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