Skip to main content

mlua_check/
symbols.rs

1use std::collections::{HashMap, HashSet};
2
3/// Known global symbols and their fields, populated from Lua VM
4/// introspection or manual registration.
5#[derive(Debug, Clone, Default)]
6pub struct SymbolTable {
7    /// Top-level global names (e.g. `print`, `alc`, `table`).
8    globals: HashSet<String>,
9    /// First-level fields of global tables (e.g. `alc` → {`llm`, `state`}).
10    global_fields: HashMap<String, HashSet<String>>,
11    /// LuaCats `---@class` definitions: class name → known field names.
12    class_fields: HashMap<String, HashSet<String>>,
13}
14
15impl SymbolTable {
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    /// Register a top-level global name.
21    pub fn add_global(&mut self, name: &str) {
22        self.globals.insert(name.to_string());
23    }
24
25    /// Register a field of a global table.
26    pub fn add_global_field(&mut self, table: &str, field: &str) {
27        self.global_fields
28            .entry(table.to_string())
29            .or_default()
30            .insert(field.to_string());
31    }
32
33    /// Check whether a top-level global name is known.
34    pub fn has_global(&self, name: &str) -> bool {
35        self.globals.contains(name)
36    }
37
38    /// Check whether a field of a global table is known.
39    pub fn has_global_field(&self, table: &str, field: &str) -> bool {
40        self.global_fields
41            .get(table)
42            .is_some_and(|fields| fields.contains(field))
43    }
44
45    /// Get all known fields for a global table (for "did you mean?"
46    /// suggestions).
47    pub fn global_fields_for(&self, table: &str) -> Option<&HashSet<String>> {
48        self.global_fields.get(table)
49    }
50
51    /// Register a `---@class` definition (creates an empty field set if new).
52    pub fn add_class(&mut self, class_name: &str) {
53        self.class_fields.entry(class_name.to_string()).or_default();
54    }
55
56    /// Register a field on a `---@class`.
57    pub fn add_class_field(&mut self, class_name: &str, field: &str) {
58        self.class_fields
59            .entry(class_name.to_string())
60            .or_default()
61            .insert(field.to_string());
62    }
63
64    /// Check whether a class is known.
65    pub fn has_class(&self, class_name: &str) -> bool {
66        self.class_fields.contains_key(class_name)
67    }
68
69    /// Check whether a field exists on a class.
70    pub fn has_class_field(&self, class_name: &str, field: &str) -> bool {
71        self.class_fields
72            .get(class_name)
73            .is_some_and(|fields| fields.contains(field))
74    }
75
76    /// Get all known fields for a class (for "did you mean?" suggestions).
77    pub fn class_fields_for(&self, class_name: &str) -> Option<&HashSet<String>> {
78        self.class_fields.get(class_name)
79    }
80
81    /// Pre-populate with Lua 5.4 standard library globals.
82    pub fn with_lua54_stdlib(mut self) -> Self {
83        let stdlib_globals = [
84            "assert",
85            "collectgarbage",
86            "dofile",
87            "error",
88            "getmetatable",
89            "ipairs",
90            "load",
91            "loadfile",
92            "next",
93            "pairs",
94            "pcall",
95            "print",
96            "rawequal",
97            "rawget",
98            "rawlen",
99            "rawset",
100            "require",
101            "select",
102            "setmetatable",
103            "tonumber",
104            "tostring",
105            "type",
106            "warn",
107            "xpcall",
108            // standard library tables
109            "coroutine",
110            "debug",
111            "io",
112            "math",
113            "os",
114            "package",
115            "string",
116            "table",
117            "utf8",
118            // globals
119            "_G",
120            "_VERSION",
121        ];
122        for name in &stdlib_globals {
123            self.globals.insert((*name).to_string());
124        }
125        self
126    }
127}