Skip to main content

lust/bytecode/compiler/
mod.rs

1pub(super) use super::{Chunk, Function, Instruction, Register, Value};
2pub(super) use crate::ast::{
3    BinaryOp, ExprKind, ExternItem, Item, ItemKind, Literal, Span, Stmt, StmtKind, Type, TypeKind,
4    UnaryOp,
5};
6use crate::config::LustConfig;
7pub(super) use crate::number::LustInt;
8use crate::typechecker::FunctionSignature;
9pub(super) use crate::{Expr, LustError, Result};
10pub(super) use alloc::{
11    format,
12    string::{String, ToString},
13    vec,
14    vec::Vec,
15};
16pub(super) use hashbrown::{HashMap, HashSet};
17mod closures;
18mod expressions;
19mod methods;
20mod module;
21mod patterns;
22mod registers;
23mod statements;
24pub struct Compiler {
25    pub(super) functions: Vec<Function>,
26    pub(super) function_table: HashMap<String, usize>,
27    pub(super) trait_impls: Vec<(String, String)>,
28    pub(super) trait_names: HashSet<String>,
29    pub(super) current_function: usize,
30    pub(super) scopes: Vec<Scope>,
31    pub(super) loop_contexts: Vec<LoopContext>,
32    pub(super) next_register: Register,
33    pub(super) max_register: Register,
34    pub(super) current_line: usize,
35    pub(super) imports_by_module: HashMap<String, crate::modules::ModuleImports>,
36    pub(super) current_module: Option<String>,
37    pub(super) entry_module: Option<String>,
38    pub(super) module_locals: HashMap<String, HashSet<String>>,
39    pub(super) current_function_name: Option<String>,
40    pub(super) extern_value_aliases: HashMap<String, String>,
41    pub(super) stdlib_symbols: HashSet<String>,
42    option_coercions: HashMap<String, HashSet<Span>>,
43    function_signatures: HashMap<String, FunctionSignature>,
44}
45
46#[derive(Debug, Clone)]
47pub(super) struct Scope {
48    pub(super) locals: HashMap<String, (Register, bool)>,
49    pub(super) depth: usize,
50}
51
52#[derive(Debug, Clone)]
53pub(super) struct LoopContext {
54    pub(super) continue_target: Option<usize>,
55    pub(super) continue_jumps: Vec<usize>,
56    pub(super) break_jumps: Vec<usize>,
57}
58
59impl Compiler {
60    pub fn new() -> Self {
61        let mut compiler = Self {
62            functions: Vec::new(),
63            function_table: HashMap::new(),
64            trait_impls: Vec::new(),
65            trait_names: HashSet::new(),
66            current_function: 0,
67            scopes: Vec::new(),
68            loop_contexts: Vec::new(),
69            next_register: 0,
70            max_register: 0,
71            current_line: 0,
72            imports_by_module: HashMap::new(),
73            current_module: None,
74            entry_module: None,
75            module_locals: HashMap::new(),
76            current_function_name: None,
77            extern_value_aliases: HashMap::new(),
78            stdlib_symbols: HashSet::new(),
79            option_coercions: HashMap::new(),
80            function_signatures: HashMap::new(),
81        };
82        compiler.configure_stdlib(&LustConfig::default());
83        compiler
84    }
85
86    pub fn set_imports_by_module(&mut self, map: HashMap<String, crate::modules::ModuleImports>) {
87        self.imports_by_module = map;
88    }
89
90    pub fn set_entry_module(&mut self, module: impl Into<String>) {
91        self.entry_module = Some(module.into());
92    }
93
94    pub fn get_trait_impls(&self) -> &[(String, String)] {
95        &self.trait_impls
96    }
97
98    pub fn configure_stdlib(&mut self, config: &LustConfig) {
99        self.stdlib_symbols.clear();
100        self.stdlib_symbols.extend(
101            [
102                "print",
103                "println",
104                "type",
105                "tostring",
106                "unpack",
107                "select",
108                "task",
109                "lua",
110                "error",
111                "assert",
112                "tonumber",
113                "pairs",
114                "ipairs",
115                "setmetatable",
116            ]
117                .into_iter()
118                .map(String::from),
119        );
120        for module in config.enabled_modules() {
121            match module {
122                "io" | "os" | "string" | "math" | "table" => {
123                    self.stdlib_symbols.insert(module.to_string());
124                }
125
126                _ => {}
127            }
128        }
129    }
130
131    pub fn set_option_coercions(&mut self, map: HashMap<String, HashSet<Span>>) {
132        self.option_coercions = map;
133    }
134
135    pub fn set_function_signatures(&mut self, signatures: HashMap<String, FunctionSignature>) {
136        self.function_signatures = signatures;
137    }
138
139    pub(super) fn is_stdlib_symbol(&self, name: &str) -> bool {
140        self.stdlib_symbols.contains(name)
141    }
142
143    pub(super) fn should_wrap_option(&self, span: Span) -> bool {
144        let module = self.current_module.as_deref().unwrap_or("");
145        self.option_coercions
146            .get(module)
147            .map_or(false, |set| set.contains(&span))
148    }
149
150    fn assign_signature_by_name(&mut self, func_idx: usize, name: &str) {
151        if let Some(signature) = self.function_signatures.get(name).cloned() {
152            self.functions[func_idx].set_signature(signature);
153        }
154    }
155
156    fn try_set_lambda_signature(
157        &mut self,
158        func_idx: usize,
159        params: &[(String, Option<Type>)],
160        return_type: &Option<Type>,
161    ) {
162        if let Some(signature) = Self::lambda_signature(params, return_type) {
163            self.functions[func_idx].set_signature(signature);
164        }
165    }
166
167    fn lambda_signature(
168        params: &[(String, Option<Type>)],
169        return_type: &Option<Type>,
170    ) -> Option<FunctionSignature> {
171        let mut param_types = Vec::with_capacity(params.len());
172        for (_, ty) in params {
173            if let Some(ty) = ty {
174                param_types.push(ty.clone());
175            } else {
176                return None;
177            }
178        }
179
180        let return_type = return_type
181            .clone()
182            .unwrap_or_else(|| Type::new(TypeKind::Unit, Span::dummy()));
183        Some(FunctionSignature {
184            params: param_types,
185            return_type,
186            is_method: false,
187        })
188    }
189
190    pub(super) fn record_extern_value(&mut self, name: &str) {
191        let runtime_name = name.to_string();
192        self.extern_value_aliases
193            .entry(runtime_name.clone())
194            .or_insert(runtime_name.clone());
195        let module_name = self
196            .current_module
197            .clone()
198            .or_else(|| self.entry_module.clone());
199        if let Some(module) = module_name {
200            if !name.contains('.') {
201                let qualified = format!("{}.{}", module, name);
202                self.extern_value_aliases
203                    .entry(qualified)
204                    .or_insert(runtime_name);
205            }
206        }
207    }
208
209    pub(super) fn describe_expr_kind(kind: &ExprKind) -> &'static str {
210        match kind {
211            ExprKind::Literal(_) => "literal expression",
212            ExprKind::Identifier(_) => "identifier expression",
213            ExprKind::Binary { .. } => "binary expression",
214            ExprKind::Unary { .. } => "unary expression",
215            ExprKind::Call { .. } => "function call",
216            ExprKind::MethodCall { .. } => "method call",
217            ExprKind::FieldAccess { .. } => "field access",
218            ExprKind::Index { .. } => "index access",
219            ExprKind::Array(_) => "array literal",
220            ExprKind::Map(_) => "map literal",
221            ExprKind::Tuple(_) => "tuple literal",
222            ExprKind::StructLiteral { .. } => "struct literal",
223            ExprKind::EnumConstructor { .. } => "enum constructor",
224            ExprKind::Lambda { .. } => "lambda expression",
225            ExprKind::Paren(_) => "parenthesized expression",
226            ExprKind::Cast { .. } => "cast expression",
227            ExprKind::TypeCheck { .. } => "`is` type check",
228            ExprKind::IsPattern { .. } => "`is` pattern expression",
229            ExprKind::If { .. } => "`if` expression",
230            ExprKind::Block(_) => "block expression",
231            ExprKind::Return(_) => "return expression",
232            ExprKind::Range { .. } => "range expression",
233        }
234    }
235
236    pub(super) fn type_to_string(type_kind: &crate::ast::TypeKind) -> String {
237        use crate::ast::TypeKind;
238        match type_kind {
239            TypeKind::Int => "int".to_string(),
240            TypeKind::Float => "float".to_string(),
241            TypeKind::String => "string".to_string(),
242            TypeKind::Bool => "bool".to_string(),
243            TypeKind::Named(name) => name.clone(),
244            TypeKind::Array(inner) => format!("Array<{}>", Self::type_to_string(&inner.kind)),
245            TypeKind::Map(key, val) => format!(
246                "Map<{}, {}>",
247                Self::type_to_string(&key.kind),
248                Self::type_to_string(&val.kind)
249            ),
250            TypeKind::Option(inner) => format!("Option<{}>", Self::type_to_string(&inner.kind)),
251            TypeKind::Result(ok, err) => format!(
252                "Result<{}, {}>",
253                Self::type_to_string(&ok.kind),
254                Self::type_to_string(&err.kind)
255            ),
256            TypeKind::Function {
257                params,
258                return_type,
259            } => {
260                let param_strs: Vec<String> = params
261                    .iter()
262                    .map(|p| Self::type_to_string(&p.kind))
263                    .collect();
264                format!(
265                    "function({}) -> {}",
266                    param_strs.join(", "),
267                    Self::type_to_string(&return_type.kind)
268                )
269            }
270
271            TypeKind::Tuple(elements) => {
272                let element_strs: Vec<String> = elements
273                    .iter()
274                    .map(|t| Self::type_to_string(&t.kind))
275                    .collect();
276                format!("Tuple<{}>", element_strs.join(", "))
277            }
278
279            TypeKind::Generic(name) => name.clone(),
280            TypeKind::GenericInstance { name, type_args } => {
281                let arg_strs: Vec<String> = type_args
282                    .iter()
283                    .map(|t| Self::type_to_string(&t.kind))
284                    .collect();
285                format!("{}<{}>", name, arg_strs.join(", "))
286            }
287
288            TypeKind::Unknown => "unknown".to_string(),
289            TypeKind::Union(types) => {
290                let type_strs: Vec<String> = types
291                    .iter()
292                    .map(|t| Self::type_to_string(&t.kind))
293                    .collect();
294                format!("{}", type_strs.join(" | "))
295            }
296
297            TypeKind::Unit => "()".to_string(),
298            TypeKind::Infer => "_".to_string(),
299            TypeKind::Ref(inner) => format!("&{}", Self::type_to_string(&inner.kind)),
300            TypeKind::MutRef(inner) => format!("&mut {}", Self::type_to_string(&inner.kind)),
301            TypeKind::Pointer { mutable, pointee } => {
302                if *mutable {
303                    format!("*mut {}", Self::type_to_string(&pointee.kind))
304                } else {
305                    format!("*{}", Self::type_to_string(&pointee.kind))
306                }
307            }
308
309            TypeKind::Trait(name) => name.clone(),
310            TypeKind::TraitBound(traits) => traits.join(" + "),
311        }
312    }
313
314    fn module_context_name(&self) -> Option<&str> {
315        self.current_module
316            .as_deref()
317            .or_else(|| self.entry_module.as_deref())
318    }
319
320    fn is_builtin_type_name(name: &str) -> bool {
321        matches!(
322            name,
323            "int"
324                | "float"
325                | "string"
326                | "bool"
327                | "unknown"
328                | "Array"
329                | "Map"
330                | "Option"
331                | "Result"
332                | "Iterator"
333                | "Task"
334                | "TaskStatus"
335                | "TaskInfo"
336                | "LuaValue"
337                | "LuaTable"
338                | "LuaFunction"
339                | "LuaUserdata"
340                | "LuaThread"
341        )
342    }
343
344    pub(super) fn resolve_type_name(&self, name: &str) -> String {
345        if let Some((head, tail)) = name.split_once('.') {
346            if let Some(module) = self.module_context_name() {
347                if let Some(imports) = self.imports_by_module.get(module) {
348                    if let Some(real_module) = imports.module_aliases.get(head) {
349                        if tail.is_empty() {
350                            return real_module.clone();
351                        } else {
352                            return format!("{}.{}", real_module, tail);
353                        }
354                    }
355                }
356            }
357
358            return name.to_string();
359        }
360
361        if Self::is_builtin_type_name(name) {
362            return name.to_string();
363        }
364
365        if let Some(module) = self.module_context_name() {
366            if let Some(imports) = self.imports_by_module.get(module) {
367                if let Some(fq) = imports.type_aliases.get(name) {
368                    return fq.clone();
369                }
370            }
371
372            return format!("{}.{}", module, name);
373        }
374
375        name.to_string()
376    }
377}
378
379impl Default for Compiler {
380    fn default() -> Self {
381        Self::new()
382    }
383}