1use crate::ast::{BinOp, Expr, Import, Literal, MatchArm, ModuleDef, ModuleItem, Pattern, Program};
42use crate::modules::ModuleRegistry;
43use crate::types::{Type, TypeEnv};
44use fusabi_vm::chunk::Chunk;
45use fusabi_vm::closure::Closure;
46use fusabi_vm::instruction::Instruction;
47use fusabi_vm::value::Value;
48use std::collections::HashMap;
49use std::fmt;
50use std::sync::Arc;
51
52#[derive(Debug, Clone, PartialEq)]
54pub enum CompileError {
55 UndefinedVariable(String),
57 TooManyConstants,
59 TooManyLocals,
61 InvalidJumpOffset,
63 UnsupportedFloat,
65 TupleTooLarge,
67 TypeError(String),
69 CodeGenError(String),
71 ModuleNotFound(String),
73 NoModuleContext,
75 BreakOutsideLoop,
77 ContinueOutsideLoop,
79}
80
81impl fmt::Display for CompileError {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 CompileError::UndefinedVariable(name) => {
85 write!(f, "Undefined variable: {}", name)
86 }
87 CompileError::TooManyConstants => {
88 write!(f, "Too many constants (max {})", u16::MAX)
89 }
90 CompileError::TooManyLocals => {
91 write!(f, "Too many local variables (max {})", u8::MAX)
92 }
93 CompileError::InvalidJumpOffset => {
94 write!(f, "Jump offset too large")
95 }
96 CompileError::UnsupportedFloat => {
97 write!(f, "Float operations not supported in Phase 1")
98 }
99 CompileError::TupleTooLarge => {
100 write!(f, "Tuple too large (max {} elements)", u16::MAX)
101 }
102 CompileError::TypeError(msg) => {
103 write!(f, "Type error: {}", msg)
104 }
105 CompileError::CodeGenError(msg) => {
106 write!(f, "Code generation error: {}", msg)
107 }
108 CompileError::ModuleNotFound(name) => {
109 write!(f, "Module not found: {}", name)
110 }
111 CompileError::NoModuleContext => {
112 write!(f, "No module context available for qualified name lookup")
113 }
114 CompileError::BreakOutsideLoop => {
115 write!(f, "Break statement used outside of loop")
116 }
117 CompileError::ContinueOutsideLoop => {
118 write!(f, "Continue statement used outside of loop")
119 }
120 }
121 }
122}
123
124impl std::error::Error for CompileError {}
125
126pub type CompileResult<T> = Result<T, CompileError>;
128
129#[derive(Debug, Clone)]
134pub struct CompileOptions {
135 pub enable_type_checking: bool,
137 pub strict_mode: bool,
139 pub allow_warnings: bool,
141}
142
143impl Default for CompileOptions {
144 fn default() -> Self {
145 CompileOptions {
146 enable_type_checking: false, strict_mode: false,
148 allow_warnings: true,
149 }
150 }
151}
152
153#[derive(Debug, Clone)]
155struct Local {
156 name: String,
157 depth: usize,
158}
159
160#[derive(Debug, Clone)]
162struct LoopState {
163 start_offset: usize,
165 break_jumps: Vec<usize>,
167 continue_jumps: Vec<usize>,
169}
170
171pub struct Compiler {
173 chunk: Chunk,
174 locals: Vec<Local>,
175 scope_depth: usize,
176 options: CompileOptions,
177 type_env: Option<TypeEnv>,
178
179 module_registry: Option<ModuleRegistry>,
181 imported_bindings: HashMap<String, Expr>,
182
183 loop_stack: Vec<LoopState>,
185}
186
187impl Compiler {
188 fn new() -> Self {
190 Compiler {
191 chunk: Chunk::new(),
192 locals: Vec::new(),
193 scope_depth: 0,
194 options: CompileOptions::default(),
195 type_env: None,
196 module_registry: None,
197 imported_bindings: HashMap::new(),
198 loop_stack: Vec::new(),
199 }
200 }
201
202 fn new_with_options(options: CompileOptions) -> Self {
204 Compiler {
205 chunk: Chunk::new(),
206 locals: Vec::new(),
207 scope_depth: 0,
208 options,
209 type_env: None,
210 module_registry: None,
211 imported_bindings: HashMap::new(),
212 loop_stack: Vec::new(),
213 }
214 }
215
216 fn expr_references_var(expr: &Expr, name: &str) -> bool {
224 match expr {
225 Expr::Var(var_name) => var_name == name,
226 Expr::Lambda { param, body } => {
227 if param == name {
229 false
230 } else {
231 Self::expr_references_var(body, name)
232 }
233 }
234 Expr::App { func, arg } => {
235 Self::expr_references_var(func, name) || Self::expr_references_var(arg, name)
236 }
237 Expr::Let {
238 name: let_name,
239 value,
240 body,
241 } => {
242 Self::expr_references_var(value, name)
244 || (let_name != name && Self::expr_references_var(body, name))
245 }
246 Expr::LetRec {
247 name: rec_name,
248 value,
249 body,
250 } => {
251 Self::expr_references_var(value, name)
253 || (rec_name != name && Self::expr_references_var(body, name))
254 }
255 Expr::LetRecMutual { bindings, body } => {
256 bindings
258 .iter()
259 .any(|(_, expr)| Self::expr_references_var(expr, name))
260 || (!bindings.iter().any(|(n, _)| n == name)
262 && Self::expr_references_var(body, name))
263 }
264 Expr::If {
265 cond,
266 then_branch,
267 else_branch,
268 } => {
269 Self::expr_references_var(cond, name)
270 || Self::expr_references_var(then_branch, name)
271 || Self::expr_references_var(else_branch, name)
272 }
273 Expr::BinOp { left, right, .. } => {
274 Self::expr_references_var(left, name) || Self::expr_references_var(right, name)
275 }
276 Expr::Tuple(elements) | Expr::List(elements) | Expr::Array(elements) => {
277 elements.iter().any(|e| Self::expr_references_var(e, name))
278 }
279 Expr::Cons { head, tail } => {
280 Self::expr_references_var(head, name) || Self::expr_references_var(tail, name)
281 }
282 Expr::ArrayIndex { array, index } => {
283 Self::expr_references_var(array, name) || Self::expr_references_var(index, name)
284 }
285 Expr::ArrayUpdate {
286 array,
287 index,
288 value,
289 } => {
290 Self::expr_references_var(array, name)
291 || Self::expr_references_var(index, name)
292 || Self::expr_references_var(value, name)
293 }
294 Expr::ArrayLength(array) => Self::expr_references_var(array, name),
295 Expr::RecordLiteral { fields, .. } => fields
296 .iter()
297 .any(|(_, expr)| Self::expr_references_var(expr, name)),
298 Expr::RecordAccess { record, .. } => Self::expr_references_var(record, name),
299 Expr::RecordUpdate { record, fields } => {
300 Self::expr_references_var(record, name)
301 || fields
302 .iter()
303 .any(|(_, expr)| Self::expr_references_var(expr, name))
304 }
305 Expr::VariantConstruct { fields, .. } => fields
306 .iter()
307 .any(|expr| Self::expr_references_var(expr, name)),
308 Expr::Match { scrutinee, arms } => {
309 Self::expr_references_var(scrutinee, name)
310 || arms.iter().any(|arm| {
311 Self::expr_references_var(&arm.body, name)
315 })
316 }
317 Expr::MethodCall { receiver, args, .. } => {
318 Self::expr_references_var(receiver, name)
319 || args.iter().any(|e| Self::expr_references_var(e, name))
320 }
321 Expr::While { cond, body } => {
322 Self::expr_references_var(cond, name) || Self::expr_references_var(body, name)
323 }
324 Expr::ComputationExpr { body, .. } => {
325 body.iter().any(|stmt| {
327 use crate::ast::CEStatement;
328 match stmt {
329 CEStatement::Let { value, .. }
330 | CEStatement::LetBang { value, .. }
331 | CEStatement::DoBang { value }
332 | CEStatement::Return { value }
333 | CEStatement::ReturnBang { value }
334 | CEStatement::Yield { value }
335 | CEStatement::YieldBang { value }
336 | CEStatement::Expr { value } => Self::expr_references_var(value, name),
337 }
338 })
339 }
340 Expr::Lit(_) | Expr::Break | Expr::Continue => false,
342 }
343 }
344
345 pub fn compile(expr: &Expr) -> CompileResult<Chunk> {
347 Self::compile_with_options(expr, CompileOptions::default())
348 }
349
350 pub fn compile_checked(expr: &Expr) -> CompileResult<Chunk> {
352 let options = CompileOptions {
353 enable_type_checking: true,
354 ..Default::default()
355 };
356 Self::compile_with_options(expr, options)
357 }
358
359 pub fn compile_with_options(expr: &Expr, options: CompileOptions) -> CompileResult<Chunk> {
361 let mut compiler = Compiler::new_with_options(options);
362
363 if compiler.options.enable_type_checking {
365 compiler.type_check(expr)?;
366 }
367
368 compiler.compile_expr(expr)?;
370 compiler.emit(Instruction::Return);
371 Ok(compiler.chunk)
372 }
373
374 pub fn compile_program(program: &Program) -> CompileResult<Chunk> {
382 let mut compiler = Compiler::new();
383 let mut registry = ModuleRegistry::with_stdlib();
384
385 for module in &program.modules {
387 compiler.register_module(&mut registry, module)?;
388 }
389
390 compiler.module_registry = Some(registry);
392
393 for import in &program.imports {
395 compiler.apply_import(import)?;
396 }
397
398 compiler.compile_top_level_items(&program.items, &program.main_expr)?;
400
401 compiler.emit(Instruction::Return);
402 Ok(compiler.chunk)
403 }
404
405 #[allow(clippy::only_used_in_recursion)]
410 fn register_module(
411 &mut self,
412 registry: &mut ModuleRegistry,
413 module: &ModuleDef,
414 ) -> CompileResult<()> {
415 let mut bindings = HashMap::new();
416 let mut types = HashMap::new();
417
418 for item in &module.items {
419 match item {
420 ModuleItem::Let(name, expr) => {
421 if let Some(name) = name {
423 bindings.insert(name.clone(), expr.clone());
424 }
425 }
426 ModuleItem::LetRec(rec_bindings) => {
427 for (name, expr) in rec_bindings {
429 bindings.insert(name.clone(), expr.clone());
430 }
431 }
432 ModuleItem::TypeDef(type_def) => {
433 let module_type_def = match type_def {
435 crate::ast::TypeDefinition::Record(r) => {
436 crate::modules::TypeDefinition::Record(r.clone())
437 }
438 crate::ast::TypeDefinition::Du(du) => {
439 crate::modules::TypeDefinition::Du(du.clone())
440 }
441 };
442
443 let type_name = match type_def {
445 crate::ast::TypeDefinition::Record(r) => r.name.clone(),
446 crate::ast::TypeDefinition::Du(du) => du.name.clone(),
447 };
448
449 types.insert(type_name, module_type_def);
450 }
451 ModuleItem::Module(nested) => {
452 self.register_module(registry, nested)?;
454 }
455 }
456 }
457
458 registry.register_module(module.name.clone(), bindings, types);
460
461 Ok(())
462 }
463
464 fn apply_import(&mut self, import: &Import) -> CompileResult<()> {
469 let module_name = import
471 .module_path
472 .first()
473 .ok_or_else(|| CompileError::ModuleNotFound("empty module path".to_string()))?;
474
475 let registry = self
476 .module_registry
477 .as_ref()
478 .ok_or(CompileError::NoModuleContext)?;
479
480 let module_bindings = registry
481 .get_module_bindings(module_name)
482 .ok_or_else(|| CompileError::ModuleNotFound(module_name.clone()))?;
483
484 for (name, expr) in module_bindings {
486 self.imported_bindings.insert(name.clone(), expr.clone());
487 }
488
489 Ok(())
490 }
491
492 fn type_check(&mut self, _expr: &Expr) -> CompileResult<Type> {
498 self.type_env = Some(TypeEnv::new());
514 Ok(Type::Unit)
515 }
516
517 fn compile_expr(&mut self, expr: &Expr) -> CompileResult<()> {
519 match expr {
520 Expr::Lit(lit) => self.compile_literal(lit),
521 Expr::Var(name) => self.compile_var(name),
522 Expr::BinOp { op, left, right } => self.compile_binop(*op, left, right),
523 Expr::Let { name, value, body } => self.compile_let(name, value, body),
524 Expr::LetRec { name, value, body } => self.compile_let_rec(name, value, body),
525 Expr::LetRecMutual { bindings, body } => self.compile_let_rec_mutual(bindings, body),
526 Expr::Lambda { param, body } => self.compile_lambda(param, body),
527 Expr::App { func, arg } => self.compile_app(func, arg),
528 Expr::If {
529 cond,
530 then_branch,
531 else_branch,
532 } => self.compile_if(cond, then_branch, else_branch),
533 Expr::Tuple(elements) => self.compile_tuple(elements),
534 Expr::List(elements) => self.compile_list(elements),
535 Expr::Cons { head, tail } => self.compile_cons(head, tail),
536 Expr::Array(elements) => self.compile_array(elements),
537 Expr::ArrayIndex { array, index } => self.compile_array_index(array, index),
538 Expr::ArrayUpdate {
539 array,
540 index,
541 value,
542 } => self.compile_array_update(array, index, value),
543 Expr::ArrayLength(array) => self.compile_array_length(array),
544 Expr::RecordLiteral { fields, .. } => self.compile_record_literal(fields),
545 Expr::RecordAccess { record, field } => self.compile_record_access(record, field),
546 Expr::RecordUpdate { record, fields } => self.compile_record_update(record, fields),
547 Expr::Match { scrutinee, arms } => self.compile_match(scrutinee, arms),
548 Expr::VariantConstruct {
549 type_name,
550 variant,
551 fields,
552 } => self.compile_variant_construct(type_name, variant, fields),
553 Expr::MethodCall {
554 receiver,
555 method_name,
556 args,
557 } => self.compile_method_call(receiver, method_name, args),
558 Expr::While { cond, body } => self.compile_while(cond, body),
559 Expr::Break => self.compile_break(),
560 Expr::Continue => self.compile_continue(),
561 Expr::ComputationExpr { builder, body } => self.compile_computation_expr(builder, body),
562 }
563 }
564
565 fn compile_literal(&mut self, lit: &Literal) -> CompileResult<()> {
567 let value = match lit {
568 Literal::Int(n) => Value::Int(*n),
569 Literal::Bool(b) => Value::Bool(*b),
570 Literal::Str(s) => Value::Str(s.clone()),
571 Literal::Unit => Value::Unit,
572 Literal::Float(f) => Value::Float(*f),
573 };
574
575 let idx = self.add_constant(value)?;
576 self.emit(Instruction::LoadConst(idx));
577 Ok(())
578 }
579 fn compile_var(&mut self, name: &str) -> CompileResult<()> {
586 if let Some((module_path, binding_name)) = parse_qualified_name(name) {
588 return self.compile_qualified_var(&module_path, &binding_name);
589 }
590
591 for (i, local) in self.locals.iter().enumerate().rev() {
593 if local.name == name {
594 let idx = i as u8;
595 self.emit(Instruction::LoadLocal(idx));
596 return Ok(());
597 }
598 }
599
600 if let Some(expr) = self.imported_bindings.get(name) {
602 if let Expr::Var(ref global_name) = expr {
606 let idx = self.add_constant(Value::Str(global_name.clone()))?;
607 self.emit(Instruction::LoadGlobal(idx));
608 return Ok(());
609 }
610 return self.compile_expr(&expr.clone());
612 }
613
614 let idx = self.add_constant(Value::Str(name.to_string()))?;
616 self.emit(Instruction::LoadGlobal(idx));
617 Ok(())
618 }
619
620 fn compile_qualified_var(&mut self, module_path: &[String], name: &str) -> CompileResult<()> {
622 if module_path.len() != 1 {
624 return Err(CompileError::CodeGenError(
625 "Nested module paths not yet supported in compilation".to_string(),
626 ));
627 }
628
629 let module_name = &module_path[0];
630
631 if let Some(registry) = self.module_registry.as_ref() {
633 if let Some(expr) = registry.resolve_qualified(module_name, name) {
634 if let Expr::Var(ref global_name) = expr {
638 let idx = self.add_constant(Value::Str(global_name.clone()))?;
639 self.emit(Instruction::LoadGlobal(idx));
640 return Ok(());
641 }
642
643 return self.compile_expr(&expr.clone());
645 }
646 }
647
648 let qualified_name = format!("{}.{}", module_name, name);
651 let idx = self.add_constant(Value::Str(qualified_name))?;
652 self.emit(Instruction::LoadGlobal(idx));
653 Ok(())
654 }
655 fn compile_binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> CompileResult<()> {
657 self.compile_expr(left)?;
659 self.compile_expr(right)?;
660
661 let instr = match op {
663 BinOp::Add => Instruction::Add,
664 BinOp::Sub => Instruction::Sub,
665 BinOp::Mul => Instruction::Mul,
666 BinOp::Div => Instruction::Div,
667 BinOp::Concat => Instruction::Concat,
668 BinOp::Eq => Instruction::Eq,
669 BinOp::Neq => Instruction::Neq,
670 BinOp::Lt => Instruction::Lt,
671 BinOp::Lte => Instruction::Lte,
672 BinOp::Gt => Instruction::Gt,
673 BinOp::Gte => Instruction::Gte,
674 BinOp::And => Instruction::And,
675 BinOp::Or => Instruction::Or,
676 };
677 self.emit(instr);
678 Ok(())
679 }
680
681 fn compile_tuple(&mut self, elements: &[Expr]) -> CompileResult<()> {
683 if elements.len() > u16::MAX as usize {
685 return Err(CompileError::TupleTooLarge);
686 }
687
688 for element in elements {
690 self.compile_expr(element)?;
691 }
692
693 let element_count = elements.len() as u16;
695 self.emit(Instruction::MakeTuple(element_count));
696
697 Ok(())
698 }
699
700 fn compile_list(&mut self, elements: &[Expr]) -> CompileResult<()> {
705 if elements.is_empty() {
707 let idx = self.add_constant(Value::Nil)?;
708 self.emit(Instruction::LoadConst(idx));
709 return Ok(());
710 }
711
712 if elements.len() > u16::MAX as usize {
714 return Err(CompileError::TupleTooLarge); }
716
717 for element in elements {
719 self.compile_expr(element)?;
720 }
721
722 let element_count = elements.len() as u16;
724 self.emit(Instruction::MakeList(element_count));
725
726 Ok(())
727 }
728
729 fn compile_cons(&mut self, head: &Expr, tail: &Expr) -> CompileResult<()> {
731 self.compile_expr(head)?;
733 self.compile_expr(tail)?;
735 self.emit(Instruction::Cons);
737 Ok(())
738 }
739
740 fn compile_array(&mut self, elements: &[Expr]) -> CompileResult<()> {
742 if elements.len() > u16::MAX as usize {
744 return Err(CompileError::TupleTooLarge); }
746
747 for element in elements {
749 self.compile_expr(element)?;
750 }
751
752 let element_count = elements.len() as u16;
754 self.emit(Instruction::MakeArray(element_count));
755
756 Ok(())
757 }
758
759 fn compile_array_index(&mut self, array: &Expr, index: &Expr) -> CompileResult<()> {
761 self.compile_expr(array)?;
763 self.compile_expr(index)?;
765 self.emit(Instruction::ArrayGet);
767 Ok(())
768 }
769
770 fn compile_array_update(
772 &mut self,
773 array: &Expr,
774 index: &Expr,
775 value: &Expr,
776 ) -> CompileResult<()> {
777 self.compile_expr(array)?;
779 self.compile_expr(index)?;
781 self.compile_expr(value)?;
783 self.emit(Instruction::ArrayUpdate);
785 Ok(())
786 }
787
788 fn compile_array_length(&mut self, array: &Expr) -> CompileResult<()> {
790 self.compile_expr(array)?;
792 self.emit(Instruction::ArrayLength);
794 Ok(())
795 }
796
797 fn compile_top_level_items(
798 &mut self,
799 items: &[ModuleItem],
800 main_expr: &Option<Expr>,
801 ) -> CompileResult<()> {
802 if let Some((first, rest)) = items.split_first() {
803 match first {
804 ModuleItem::Let(name, value) => {
805 self.compile_expr(value)?;
807
808 if let Some(name) = name {
809 self.begin_scope();
811 self.add_local(name.to_string())?;
812
813 let local_idx = (self.locals.len() - 1) as u8;
815 self.emit(Instruction::StoreLocal(local_idx));
816
817 self.compile_top_level_items(rest, main_expr)?;
819
820 let locals_to_remove = self.end_scope_count();
822 for _ in 0..locals_to_remove {
823 self.locals.pop();
824 }
825 self.scope_depth -= 1;
826 } else {
827 self.emit(Instruction::Pop);
829 self.compile_top_level_items(rest, main_expr)?;
830 }
831 }
832 ModuleItem::LetRec(bindings) => {
833 if bindings.len() == 1 {
834 let (name, value) = &bindings[0];
836 let placeholder_idx = self.add_constant(Value::Unit)?;
837 self.emit(Instruction::LoadConst(placeholder_idx));
838
839 self.begin_scope();
840 self.add_local(name.to_string())?;
841 let local_idx = (self.locals.len() - 1) as u8;
842 self.emit(Instruction::StoreLocal(local_idx));
843
844 self.compile_expr(value)?;
845 self.emit(Instruction::StoreLocal(local_idx));
846
847 self.compile_top_level_items(rest, main_expr)?;
848
849 let locals_to_remove = self.end_scope_count();
850 for _ in 0..locals_to_remove {
851 self.locals.pop();
852 }
853 self.scope_depth -= 1;
854 } else {
855 let placeholder_idx = self.add_constant(Value::Unit)?;
857 let mut local_indices = Vec::new();
858
859 self.begin_scope();
860
861 for (name, _) in bindings {
862 self.emit(Instruction::LoadConst(placeholder_idx));
863 self.add_local(name.to_string())?;
864 local_indices.push((self.locals.len() - 1) as u8);
865 self.emit(Instruction::StoreLocal(*local_indices.last().unwrap()));
866 }
867
868 for ((_, value), local_idx) in bindings.iter().zip(local_indices.iter()) {
869 self.compile_expr(value)?;
870 self.emit(Instruction::StoreLocal(*local_idx));
871 }
872
873 self.compile_top_level_items(rest, main_expr)?;
874
875 let locals_to_remove = self.end_scope_count();
876 for _ in 0..locals_to_remove {
877 self.locals.pop();
878 }
879 self.scope_depth -= 1;
880 }
881 }
882 ModuleItem::TypeDef(_) | ModuleItem::Module(_) => {
883 self.compile_top_level_items(rest, main_expr)?;
885 }
886 }
887 } else {
888 if let Some(expr) = main_expr {
890 self.compile_expr(expr)?;
891 } else {
892 let unit_idx = self.add_constant(Value::Unit)?;
893 self.emit(Instruction::LoadConst(unit_idx));
894 }
895 }
896 Ok(())
897 }
898
899 fn compile_let(&mut self, name: &str, value: &Expr, body: &Expr) -> CompileResult<()> {
900 let auto_recursive = Self::expr_references_var(value, name);
902
903 if auto_recursive {
904 self.compile_let_rec(name, value, body)
906 } else {
907 self.compile_expr(value)?;
910
911 self.begin_scope();
913
914 self.add_local(name.to_string())?;
916
917 let local_idx = (self.locals.len() - 1) as u8;
919 self.emit(Instruction::StoreLocal(local_idx));
920
921 self.compile_expr(body)?;
923
924 let locals_to_remove = self.end_scope_count();
927
928 for _ in 0..locals_to_remove {
932 self.locals.pop();
933 }
934 self.scope_depth -= 1;
935
936 Ok(())
937 }
938 }
939
940 fn compile_lambda(&mut self, param: &str, body: &Expr) -> CompileResult<()> {
942 let mut lambda_compiler = Compiler::new();
944
945 lambda_compiler.begin_scope();
947 lambda_compiler.add_local(param.to_string())?;
948
949 lambda_compiler.compile_expr(body)?;
951 lambda_compiler.emit(Instruction::Return);
952
953 let _locals_to_remove = lambda_compiler.end_scope_count();
955 lambda_compiler.scope_depth -= 1;
956
957 let closure = Closure::with_arity(lambda_compiler.chunk, 1);
961 let closure_val = Value::Closure(Arc::new(closure));
962
963 let const_idx = self.add_constant(closure_val)?;
965
966 self.emit(Instruction::MakeClosure(const_idx, 0));
968 Ok(())
969 }
970
971 fn compile_let_rec(&mut self, name: &str, value: &Expr, body: &Expr) -> CompileResult<()> {
973 let placeholder_idx = self.add_constant(Value::Unit)?;
978 self.emit(Instruction::LoadConst(placeholder_idx));
979
980 self.begin_scope();
982 self.add_local(name.to_string())?;
983 let local_idx = (self.locals.len() - 1) as u8;
984
985 self.emit(Instruction::StoreLocal(local_idx));
987
988 self.compile_expr(value)?;
991
992 self.emit(Instruction::StoreLocal(local_idx));
994
995 self.compile_expr(body)?;
997
998 let locals_to_remove = self.end_scope_count();
1000 for _ in 0..locals_to_remove {
1001 self.locals.pop();
1002 }
1003 self.scope_depth -= 1;
1004
1005 Ok(())
1006 }
1007
1008 fn compile_let_rec_mutual(
1010 &mut self,
1011 bindings: &[(String, Expr)],
1012 body: &Expr,
1013 ) -> CompileResult<()> {
1014 self.begin_scope();
1018
1019 let placeholder_idx = self.add_constant(Value::Unit)?;
1021 let mut local_indices = Vec::new();
1022
1023 for (name, _) in bindings {
1024 self.emit(Instruction::LoadConst(placeholder_idx));
1026
1027 self.add_local(name.clone())?;
1029 let local_idx = (self.locals.len() - 1) as u8;
1030 local_indices.push(local_idx);
1031
1032 self.emit(Instruction::StoreLocal(local_idx));
1034 }
1035
1036 for (i, (_name, value)) in bindings.iter().enumerate() {
1038 self.compile_expr(value)?;
1039 self.emit(Instruction::StoreLocal(local_indices[i]));
1040 }
1041
1042 self.compile_expr(body)?;
1044
1045 let locals_to_remove = self.end_scope_count();
1047 for _ in 0..locals_to_remove {
1048 self.locals.pop();
1049 }
1050 self.scope_depth -= 1;
1051
1052 Ok(())
1053 }
1054
1055 fn compile_app(&mut self, func: &Expr, arg: &Expr) -> CompileResult<()> {
1057 self.compile_expr(func)?;
1059
1060 self.compile_expr(arg)?;
1062
1063 self.emit(Instruction::Call(1));
1065
1066 Ok(())
1067 }
1068
1069 fn compile_if(
1071 &mut self,
1072 cond: &Expr,
1073 then_branch: &Expr,
1074 else_branch: &Expr,
1075 ) -> CompileResult<()> {
1076 self.compile_expr(cond)?;
1078
1079 let jump_to_else = self.emit_jump(Instruction::JumpIfFalse(0));
1081
1082 self.compile_expr(then_branch)?;
1086
1087 let jump_to_end = self.emit_jump(Instruction::Jump(0));
1089
1090 self.patch_jump(jump_to_else)?;
1092
1093 self.compile_expr(else_branch)?;
1095
1096 self.patch_jump(jump_to_end)?;
1098
1099 Ok(())
1100 }
1101
1102 fn compile_while(&mut self, cond: &Expr, body: &Expr) -> CompileResult<()> {
1104 let start_offset = self.chunk.current_offset();
1106
1107 self.compile_expr(cond)?;
1109
1110 let jump_to_end = self.emit_jump(Instruction::JumpIfFalse(0));
1112
1113 self.loop_stack.push(LoopState {
1115 start_offset,
1116 break_jumps: Vec::new(),
1117 continue_jumps: Vec::new(),
1118 });
1119
1120 self.compile_expr(body)?;
1122
1123 self.emit(Instruction::Pop);
1125
1126 let offset_to_start = self.chunk.current_offset() as i32 - start_offset as i32 + 1;
1128 if offset_to_start > i16::MAX as i32 || -offset_to_start > i16::MAX as i32 {
1129 return Err(CompileError::InvalidJumpOffset);
1130 }
1131 self.emit(Instruction::Jump(-offset_to_start as i16));
1132
1133 self.patch_jump(jump_to_end)?;
1135
1136 let loop_state = self.loop_stack.pop().unwrap();
1138
1139 for break_jump in loop_state.break_jumps {
1141 self.patch_jump(break_jump)?;
1142 }
1143
1144 for continue_jump in loop_state.continue_jumps {
1146 let target = start_offset;
1147 let offset = target as i32 - continue_jump as i32 - 1;
1148 if offset > i16::MAX as i32 || offset < i16::MIN as i32 {
1149 return Err(CompileError::InvalidJumpOffset);
1150 }
1151 match self.chunk.instructions[continue_jump] {
1152 Instruction::Jump(_) => {
1153 self.chunk.instructions[continue_jump] = Instruction::Jump(offset as i16);
1154 }
1155 _ => unreachable!("Expected Jump instruction for continue"),
1156 }
1157 }
1158
1159 let unit_idx = self.add_constant(Value::Unit)?;
1161 self.emit(Instruction::LoadConst(unit_idx));
1162
1163 Ok(())
1164 }
1165
1166 fn compile_break(&mut self) -> CompileResult<()> {
1168 if self.loop_stack.is_empty() {
1169 return Err(CompileError::BreakOutsideLoop);
1170 }
1171
1172 let jump_idx = self.emit_jump(Instruction::Jump(0));
1174
1175 self.loop_stack
1177 .last_mut()
1178 .unwrap()
1179 .break_jumps
1180 .push(jump_idx);
1181
1182 Ok(())
1183 }
1184
1185 fn compile_continue(&mut self) -> CompileResult<()> {
1187 if self.loop_stack.is_empty() {
1188 return Err(CompileError::ContinueOutsideLoop);
1189 }
1190
1191 let jump_idx = self.emit_jump(Instruction::Jump(0));
1193
1194 self.loop_stack
1196 .last_mut()
1197 .unwrap()
1198 .continue_jumps
1199 .push(jump_idx);
1200
1201 Ok(())
1202 }
1203
1204 fn compile_computation_expr(
1206 &mut self,
1207 builder: &str,
1208 body: &[crate::ast::CEStatement],
1209 ) -> CompileResult<()> {
1210 let desugared = self.desugar_ce_statements(builder, body)?;
1212
1213 self.compile_expr(&desugared)
1215 }
1216
1217 fn desugar_ce_statements(
1219 &self,
1220 builder: &str,
1221 statements: &[crate::ast::CEStatement],
1222 ) -> CompileResult<Expr> {
1223 if statements.is_empty() {
1224 let builder_expr = Box::new(Expr::Var(builder.to_string()));
1227 let unit_expr = Expr::Lit(Literal::Unit);
1228
1229 return Ok(Expr::MethodCall {
1230 receiver: builder_expr,
1231 method_name: "Return".to_string(),
1232 args: vec![unit_expr],
1233 });
1234 }
1235
1236 let first = &statements[0];
1237 let rest = &statements[1..];
1238 let builder_expr = Box::new(Expr::Var(builder.to_string()));
1239
1240 match first {
1241 crate::ast::CEStatement::Let { name, value } => {
1242 let rest_expr = self.desugar_ce_statements(builder, rest)?;
1246 Ok(Expr::Let {
1247 name: name.clone(),
1248 value: value.clone(),
1249 body: Box::new(rest_expr),
1250 })
1251 }
1252 crate::ast::CEStatement::LetBang { name, value } => {
1253 let rest_expr = self.desugar_ce_statements(builder, rest)?;
1258
1259 let continuation = Expr::Lambda {
1260 param: name.clone(),
1261 body: Box::new(rest_expr),
1262 };
1263
1264 Ok(Expr::MethodCall {
1265 receiver: builder_expr,
1266 method_name: "Bind".to_string(),
1267 args: vec![*value.clone(), continuation],
1268 })
1269 }
1270 crate::ast::CEStatement::DoBang { value } => {
1271 let rest_expr = self.desugar_ce_statements(builder, rest)?;
1275
1276 let continuation = Expr::Lambda {
1278 param: "_".to_string(),
1279 body: Box::new(rest_expr),
1280 };
1281
1282 Ok(Expr::MethodCall {
1283 receiver: builder_expr,
1284 method_name: "Bind".to_string(),
1285 args: vec![*value.clone(), continuation],
1286 })
1287 }
1288 crate::ast::CEStatement::Return { value } => {
1289 Ok(Expr::MethodCall {
1293 receiver: builder_expr,
1294 method_name: "Return".to_string(),
1295 args: vec![*value.clone()],
1296 })
1297 }
1298 crate::ast::CEStatement::ReturnBang { value } => {
1299 Ok(Expr::MethodCall {
1302 receiver: builder_expr,
1303 method_name: "ReturnFrom".to_string(),
1304 args: vec![*value.clone()],
1305 })
1306 }
1307 crate::ast::CEStatement::Yield { value } => {
1308 let yield_expr = Expr::MethodCall {
1311 receiver: builder_expr.clone(),
1312 method_name: "Yield".to_string(),
1313 args: vec![*value.clone()],
1314 };
1315
1316 if rest.is_empty() {
1317 Ok(yield_expr)
1318 } else {
1319 let rest_expr = self.desugar_ce_statements(builder, rest)?;
1321
1322 let delay_lambda = Expr::Lambda {
1323 param: "_".to_string(),
1324 body: Box::new(rest_expr),
1325 };
1326
1327 let delay_expr = Expr::MethodCall {
1328 receiver: builder_expr.clone(),
1329 method_name: "Delay".to_string(),
1330 args: vec![delay_lambda],
1331 };
1332
1333 Ok(Expr::MethodCall {
1334 receiver: builder_expr,
1335 method_name: "Combine".to_string(),
1336 args: vec![yield_expr, delay_expr],
1337 })
1338 }
1339 }
1340 crate::ast::CEStatement::YieldBang { value } => {
1341 let yield_from_expr = Expr::MethodCall {
1344 receiver: builder_expr.clone(),
1345 method_name: "YieldFrom".to_string(),
1346 args: vec![*value.clone()],
1347 };
1348
1349 if rest.is_empty() {
1350 Ok(yield_from_expr)
1351 } else {
1352 let rest_expr = self.desugar_ce_statements(builder, rest)?;
1353
1354 let delay_lambda = Expr::Lambda {
1355 param: "_".to_string(),
1356 body: Box::new(rest_expr),
1357 };
1358
1359 let delay_expr = Expr::MethodCall {
1360 receiver: builder_expr.clone(),
1361 method_name: "Delay".to_string(),
1362 args: vec![delay_lambda],
1363 };
1364
1365 Ok(Expr::MethodCall {
1366 receiver: builder_expr,
1367 method_name: "Combine".to_string(),
1368 args: vec![yield_from_expr, delay_expr],
1369 })
1370 }
1371 }
1372 crate::ast::CEStatement::Expr { value } => {
1373 if rest.is_empty() {
1375 Ok(*value.clone())
1377 } else {
1378 let rest_expr = self.desugar_ce_statements(builder, rest)?;
1382
1383 Ok(Expr::Let {
1384 name: "_".to_string(),
1385 value: value.clone(),
1386 body: Box::new(rest_expr),
1387 })
1388 }
1389 }
1390 }
1391 }
1392
1393 fn compile_match(&mut self, scrutinee: &Expr, arms: &[MatchArm]) -> CompileResult<()> {
1395 self.compile_expr(scrutinee)?;
1397
1398 let _end_label = self.chunk.current_offset();
1399 let mut end_jumps = Vec::new();
1400
1401 for (i, arm) in arms.iter().enumerate() {
1402 let is_last_arm = i == arms.len() - 1;
1403
1404 if !is_last_arm {
1406 self.emit(Instruction::Dup);
1407 }
1408
1409 let _next_arm_offset = if !is_last_arm {
1411 self.chunk.current_offset()
1412 } else {
1413 0 };
1415
1416 self.compile_pattern_test(&arm.pattern)?;
1418
1419 let jump_to_next = if !is_last_arm {
1421 self.emit_jump(Instruction::JumpIfFalse(0))
1422 } else {
1423 self.emit(Instruction::Pop);
1425 0
1426 };
1427
1428 if !is_last_arm {
1431 self.emit(Instruction::Dup); }
1433
1434 self.begin_scope();
1436
1437 self.compile_pattern_bindings(&arm.pattern)?;
1439
1440 self.compile_expr(&arm.body)?;
1442
1443 let locals_to_remove = self.end_scope_count();
1445 for _ in 0..locals_to_remove {
1446 self.locals.pop();
1447 }
1448 self.scope_depth -= 1;
1449
1450 let jump_to_end = self.emit_jump(Instruction::Jump(0));
1452 end_jumps.push(jump_to_end);
1453
1454 if !is_last_arm {
1456 self.patch_jump(jump_to_next)?;
1457 self.emit(Instruction::Pop);
1459 }
1460 }
1461
1462 for jump_idx in end_jumps {
1464 self.patch_jump(jump_idx)?;
1465 }
1466
1467 Ok(())
1468 }
1469
1470 fn compile_pattern_test(&mut self, pattern: &Pattern) -> CompileResult<()> {
1473 match pattern {
1474 Pattern::Wildcard | Pattern::Var(_) => {
1475 let true_idx = self.add_constant(Value::Bool(true))?;
1477 self.emit(Instruction::LoadConst(true_idx));
1478 Ok(())
1479 }
1480 Pattern::Literal(Literal::Int(n)) => {
1481 self.emit(Instruction::CheckInt(*n));
1482 Ok(())
1483 }
1484 Pattern::Literal(Literal::Bool(b)) => {
1485 self.emit(Instruction::CheckBool(*b));
1486 Ok(())
1487 }
1488 Pattern::Literal(Literal::Str(s)) => {
1489 self.emit(Instruction::CheckString(s.clone()));
1490 Ok(())
1491 }
1492 Pattern::Literal(Literal::Unit) => {
1493 let unit_idx = self.add_constant(Value::Unit)?;
1495 self.emit(Instruction::LoadConst(unit_idx));
1496 self.emit(Instruction::Eq);
1497 Ok(())
1498 }
1499 Pattern::Literal(Literal::Float(f)) => {
1500 let float_idx = self.add_constant(Value::Float(*f))?;
1502 self.emit(Instruction::LoadConst(float_idx));
1503 self.emit(Instruction::Eq);
1504 Ok(())
1505 }
1506 Pattern::Tuple(patterns) => {
1507 self.emit(Instruction::Dup);
1509 self.emit(Instruction::CheckTupleLen(patterns.len() as u8));
1510
1511 if !patterns.is_empty() {
1514 }
1518
1519 Ok(())
1520 }
1521 Pattern::Variant {
1522 variant,
1523 patterns: _,
1524 } => {
1525 self.emit(Instruction::Dup);
1527 self.emit(Instruction::CheckVariantTag(variant.clone()));
1528 Ok(())
1529 }
1530 }
1531 }
1532
1533 fn compile_pattern_bindings(&mut self, pattern: &Pattern) -> CompileResult<()> {
1536 match pattern {
1537 Pattern::Wildcard | Pattern::Literal(_) => {
1538 self.emit(Instruction::Pop);
1540 Ok(())
1541 }
1542 Pattern::Var(name) => {
1543 self.add_local(name.clone())?;
1545 let local_idx = (self.locals.len() - 1) as u8;
1546 self.emit(Instruction::StoreLocal(local_idx));
1547 Ok(())
1548 }
1549 Pattern::Tuple(patterns) => {
1550 for (i, pat) in patterns.iter().enumerate() {
1552 self.emit(Instruction::Dup); self.emit(Instruction::GetTupleElem(i as u8)); self.compile_pattern_bindings(pat)?; }
1556 self.emit(Instruction::Pop);
1558 Ok(())
1559 }
1560 Pattern::Variant {
1561 variant: _,
1562 patterns,
1563 } => {
1564 for (i, pat) in patterns.iter().enumerate() {
1566 self.emit(Instruction::Dup); self.emit(Instruction::GetVariantField(i as u8)); self.compile_pattern_bindings(pat)?; }
1570 self.emit(Instruction::Pop);
1572 Ok(())
1573 }
1574 }
1575 }
1576
1577 fn compile_variant_construct(
1581 &mut self,
1582 type_name: &str,
1583 variant_name: &str,
1584 fields: &[Box<Expr>],
1585 ) -> CompileResult<()> {
1586 if fields.len() > u16::MAX as usize {
1588 return Err(CompileError::TupleTooLarge); }
1590
1591 let type_name_idx = self.add_constant(Value::Str(type_name.to_string()))?;
1593 self.emit(Instruction::LoadConst(type_name_idx));
1594
1595 let variant_name_idx = self.add_constant(Value::Str(variant_name.to_string()))?;
1597 self.emit(Instruction::LoadConst(variant_name_idx));
1598
1599 for field in fields {
1601 self.compile_expr(field)?;
1602 }
1603
1604 let field_count = fields.len() as u16;
1606 self.emit(Instruction::MakeVariant(field_count));
1607
1608 Ok(())
1609 }
1610
1611 fn emit(&mut self, instruction: Instruction) {
1612 self.chunk.emit(instruction);
1613 }
1614
1615 fn emit_jump(&mut self, instruction: Instruction) -> usize {
1617 self.emit(instruction);
1618 self.chunk.current_offset() - 1
1619 }
1620
1621 fn patch_jump(&mut self, jump_index: usize) -> CompileResult<()> {
1623 let jump_offset = self.chunk.current_offset() - jump_index - 1;
1625
1626 if jump_offset > i16::MAX as usize {
1628 return Err(CompileError::InvalidJumpOffset);
1629 }
1630
1631 match self.chunk.instructions[jump_index] {
1633 Instruction::Jump(_) => {
1634 self.chunk.instructions[jump_index] = Instruction::Jump(jump_offset as i16);
1635 }
1636 Instruction::JumpIfFalse(_) => {
1637 self.chunk.instructions[jump_index] = Instruction::JumpIfFalse(jump_offset as i16);
1638 }
1639 _ => unreachable!("patch_jump called on non-jump instruction"),
1640 }
1641
1642 Ok(())
1643 }
1644
1645 fn add_constant(&mut self, value: Value) -> CompileResult<u16> {
1647 let count = self.chunk.constants.len();
1648 if count >= u16::MAX as usize {
1649 return Err(CompileError::TooManyConstants);
1650 }
1651 let idx = self.chunk.add_constant(value);
1652 Ok(idx)
1653 }
1654 fn begin_scope(&mut self) {
1656 self.scope_depth += 1;
1657 }
1658
1659 fn end_scope_count(&self) -> usize {
1661 self.locals
1662 .iter()
1663 .rev()
1664 .take_while(|local| local.depth > self.scope_depth - 1)
1665 .count()
1666 }
1667
1668 fn add_local(&mut self, name: String) -> CompileResult<()> {
1670 if self.locals.len() >= u8::MAX as usize {
1671 return Err(CompileError::TooManyLocals);
1672 }
1673
1674 self.locals.push(Local {
1675 name,
1676 depth: self.scope_depth,
1677 });
1678
1679 Ok(())
1680 }
1681 fn compile_record_literal(&mut self, fields: &[(String, Box<Expr>)]) -> CompileResult<()> {
1684 if fields.len() > u16::MAX as usize {
1686 return Err(CompileError::TupleTooLarge); }
1688
1689 for (field_name, field_value) in fields {
1692 let field_name_idx = self.add_constant(Value::Str(field_name.clone()))?;
1694 self.emit(Instruction::LoadConst(field_name_idx));
1695
1696 self.compile_expr(field_value)?;
1698 }
1699
1700 let field_count = fields.len() as u16;
1702 self.emit(Instruction::MakeRecord(field_count));
1703
1704 Ok(())
1705 }
1706
1707 fn compile_record_access(&mut self, record: &Expr, field: &str) -> CompileResult<()> {
1710 self.compile_expr(record)?;
1712
1713 let field_name_idx = self.add_constant(Value::Str(field.to_string()))?;
1715 self.emit(Instruction::LoadConst(field_name_idx));
1716
1717 self.emit(Instruction::GetRecordField);
1719
1720 Ok(())
1721 }
1722
1723 fn compile_record_update(
1726 &mut self,
1727 record: &Expr,
1728 fields: &[(String, Box<Expr>)],
1729 ) -> CompileResult<()> {
1730 if fields.len() > u16::MAX as usize {
1732 return Err(CompileError::TupleTooLarge); }
1734
1735 self.compile_expr(record)?;
1737
1738 for (field_name, field_value) in fields {
1741 let field_name_idx = self.add_constant(Value::Str(field_name.clone()))?;
1743 self.emit(Instruction::LoadConst(field_name_idx));
1744
1745 self.compile_expr(field_value)?;
1747 }
1748
1749 let update_count = fields.len() as u16;
1751 self.emit(Instruction::UpdateRecord(update_count));
1752
1753 Ok(())
1754 }
1755
1756 fn compile_method_call(
1759 &mut self,
1760 receiver: &Expr,
1761 method_name: &str,
1762 args: &[Expr],
1763 ) -> CompileResult<()> {
1764 if args.len() > u8::MAX as usize {
1766 return Err(CompileError::CodeGenError(
1767 "Too many method arguments (max 255)".to_string(),
1768 ));
1769 }
1770
1771 if let Expr::Var(module_name) = receiver {
1775 let qualified_name = format!("{}.{}", module_name, method_name);
1776
1777 let has_module_binding = self
1779 .module_registry
1780 .as_ref()
1781 .and_then(|r| r.resolve_qualified(module_name, method_name))
1782 .is_some();
1783
1784 if !has_module_binding {
1787 let name_idx = self.add_constant(Value::Str(qualified_name))?;
1789 self.emit(Instruction::LoadGlobal(name_idx));
1790
1791 for arg in args {
1793 self.compile_expr(arg)?;
1794 }
1795
1796 let arg_count = args.len() as u8;
1798 self.emit(Instruction::Call(arg_count));
1799
1800 return Ok(());
1801 }
1802 }
1803
1804 self.compile_expr(receiver)?;
1807
1808 for arg in args {
1810 self.compile_expr(arg)?;
1811 }
1812
1813 let method_name_idx = self.add_constant(Value::Str(method_name.to_string()))?;
1815
1816 let arg_count = args.len() as u8;
1818 self.emit(Instruction::CallMethod(method_name_idx, arg_count));
1819
1820 Ok(())
1821 }
1822}
1823
1824fn parse_qualified_name(name: &str) -> Option<(Vec<String>, String)> {
1830 if name.contains('.') {
1831 let parts: Vec<&str> = name.split('.').collect();
1832 if parts.len() >= 2 {
1833 let module_path: Vec<String> = parts[..parts.len() - 1]
1834 .iter()
1835 .map(|s| s.to_string())
1836 .collect();
1837 let binding_name = parts[parts.len() - 1].to_string();
1838 return Some((module_path, binding_name));
1839 }
1840 }
1841 None
1842}
1843
1844#[cfg(test)]
1847mod tests {
1848 use super::*;
1849
1850 #[test]
1852 fn test_compile_options_default() {
1853 let options = CompileOptions::default();
1854 assert!(!options.enable_type_checking);
1855 assert!(!options.strict_mode);
1856 assert!(options.allow_warnings);
1857 }
1858
1859 #[test]
1860 fn test_compile_with_type_checking() {
1861 let expr = Expr::Lit(Literal::Int(42));
1862 let result = Compiler::compile_checked(&expr);
1863 assert!(result.is_ok());
1864 }
1865
1866 #[test]
1867 fn test_compile_backwards_compatible() {
1868 let expr = Expr::Lit(Literal::Int(42));
1869 let chunk = Compiler::compile(&expr).unwrap();
1870 assert_eq!(chunk.constants.len(), 1);
1871 assert_eq!(chunk.constants[0], Value::Int(42));
1872 }
1873
1874 #[test]
1875 fn test_parse_qualified_name_simple() {
1876 let result = parse_qualified_name("Math.add");
1877 assert!(result.is_some());
1878 let (path, name) = result.unwrap();
1879 assert_eq!(path, vec!["Math".to_string()]);
1880 assert_eq!(name, "add");
1881 }
1882
1883 #[test]
1884 fn test_parse_qualified_name_nested() {
1885 let result = parse_qualified_name("Geometry.Point.x");
1886 assert!(result.is_some());
1887 let (path, name) = result.unwrap();
1888 assert_eq!(path, vec!["Geometry".to_string(), "Point".to_string()]);
1889 assert_eq!(name, "x");
1890 }
1891
1892 #[test]
1893 fn test_parse_qualified_name_unqualified() {
1894 let result = parse_qualified_name("add");
1895 assert!(result.is_none());
1896 }
1897}