1use sema_core::{intern, SemaError, Spur, Value};
2
3use crate::chunk::{Chunk, ExceptionEntry, Function, UpvalueDesc};
4use crate::core_expr::{
5 ResolvedDoLoop, ResolvedExpr, ResolvedLambda, ResolvedPromptEntry, VarRef, VarResolution,
6};
7use crate::emit::Emitter;
8use crate::opcodes::Op;
9
10pub struct CompileResult {
12 pub chunk: Chunk,
14 pub functions: Vec<Function>,
16}
17
18pub fn compile(expr: &ResolvedExpr) -> Result<CompileResult, SemaError> {
20 compile_with_locals(expr, 0)
21}
22
23pub fn compile_with_locals(expr: &ResolvedExpr, n_locals: u16) -> Result<CompileResult, SemaError> {
25 let mut compiler = Compiler::new();
26 compiler.n_locals = n_locals;
27 compiler.compile_expr(expr)?;
28 compiler.emit.emit_op(Op::Return);
29 let (chunk, functions) = compiler.finish();
30 Ok(CompileResult { chunk, functions })
31}
32
33pub fn compile_many(exprs: &[ResolvedExpr]) -> Result<CompileResult, SemaError> {
35 compile_many_with_locals(exprs, 0)
36}
37
38pub fn compile_many_with_locals(
40 exprs: &[ResolvedExpr],
41 n_locals: u16,
42) -> Result<CompileResult, SemaError> {
43 let mut compiler = Compiler::new();
44 compiler.n_locals = n_locals;
45 for (i, expr) in exprs.iter().enumerate() {
46 compiler.compile_expr(expr)?;
47 if i < exprs.len() - 1 {
48 compiler.emit.emit_op(Op::Pop);
49 }
50 }
51 if exprs.is_empty() {
52 compiler.emit.emit_op(Op::Nil);
53 }
54 compiler.emit.emit_op(Op::Return);
55 let (chunk, functions) = compiler.finish();
56 Ok(CompileResult { chunk, functions })
57}
58
59fn patch_closure_func_ids(chunk: &mut Chunk, offset: u16) {
61 let code = &mut chunk.code;
62 let mut pc = 0;
63 while pc < code.len() {
64 let Some(op) = Op::from_u8(code[pc]) else {
65 break;
66 };
67 match op {
68 Op::MakeClosure => {
69 let old = u16::from_le_bytes([code[pc + 1], code[pc + 2]]);
71 let new = old + offset;
72 let bytes = new.to_le_bytes();
73 code[pc + 1] = bytes[0];
74 code[pc + 2] = bytes[1];
75 let n_upvalues = u16::from_le_bytes([code[pc + 3], code[pc + 4]]) as usize;
77 pc += 1 + 2 + 2 + n_upvalues * 4;
79 }
80 Op::Const
82 | Op::LoadLocal
83 | Op::StoreLocal
84 | Op::LoadUpvalue
85 | Op::StoreUpvalue
86 | Op::Call
87 | Op::TailCall
88 | Op::MakeList
89 | Op::MakeVector
90 | Op::MakeMap
91 | Op::MakeHashMap => {
92 pc += 1 + 2; }
94 Op::CallNative => {
95 pc += 1 + 2 + 2; }
97 Op::LoadGlobal | Op::StoreGlobal | Op::DefineGlobal => {
98 pc += 1 + 4; }
100 Op::Jump | Op::JumpIfFalse | Op::JumpIfTrue => {
101 pc += 1 + 4; }
103 _ => {
105 pc += 1;
106 }
107 }
108 }
109}
110
111struct Compiler {
112 emit: Emitter,
113 functions: Vec<Function>,
114 exception_entries: Vec<ExceptionEntry>,
115 n_locals: u16,
116}
117
118impl Compiler {
119 fn new() -> Self {
120 Compiler {
121 emit: Emitter::new(),
122 functions: Vec::new(),
123 exception_entries: Vec::new(),
124 n_locals: 0,
125 }
126 }
127
128 fn finish(self) -> (Chunk, Vec<Function>) {
129 let mut chunk = self.emit.into_chunk();
130 chunk.n_locals = self.n_locals;
131 chunk.exception_table = self.exception_entries;
132 (chunk, self.functions)
133 }
134
135 fn compile_expr(&mut self, expr: &ResolvedExpr) -> Result<(), SemaError> {
136 match expr {
137 ResolvedExpr::Const(val) => self.compile_const(val),
138 ResolvedExpr::Var(vr) => self.compile_var_load(vr),
139 ResolvedExpr::If { test, then, else_ } => self.compile_if(test, then, else_),
140 ResolvedExpr::Begin(exprs) => self.compile_begin(exprs),
141 ResolvedExpr::Set(vr, val) => self.compile_set(vr, val),
142 ResolvedExpr::Lambda(def) => self.compile_lambda(def),
143 ResolvedExpr::Call { func, args, tail } => self.compile_call(func, args, *tail),
144 ResolvedExpr::Define(spur, val) => self.compile_define(*spur, val),
145 ResolvedExpr::Let { bindings, body } => self.compile_let(bindings, body),
146 ResolvedExpr::LetStar { bindings, body } => self.compile_let_star(bindings, body),
147 ResolvedExpr::Letrec { bindings, body } => self.compile_letrec(bindings, body),
148 ResolvedExpr::NamedLet {
149 name,
150 bindings,
151 body,
152 } => self.compile_named_let(name, bindings, body),
153 ResolvedExpr::Do(do_loop) => self.compile_do(do_loop),
154 ResolvedExpr::Try {
155 body,
156 catch_var,
157 handler,
158 } => self.compile_try(body, catch_var, handler),
159 ResolvedExpr::Throw(val) => self.compile_throw(val),
160 ResolvedExpr::And(exprs) => self.compile_and(exprs),
161 ResolvedExpr::Or(exprs) => self.compile_or(exprs),
162 ResolvedExpr::Quote(val) => self.compile_const(val),
163 ResolvedExpr::MakeList(exprs) => self.compile_make_list(exprs),
164 ResolvedExpr::MakeVector(exprs) => self.compile_make_vector(exprs),
165 ResolvedExpr::MakeMap(pairs) => self.compile_make_map(pairs),
166 ResolvedExpr::Defmacro {
167 name,
168 params,
169 rest,
170 body,
171 } => self.compile_defmacro(*name, params, rest, body),
172 ResolvedExpr::DefineRecordType {
173 type_name,
174 ctor_name,
175 pred_name,
176 field_names,
177 field_specs,
178 } => self.compile_define_record_type(
179 *type_name,
180 *ctor_name,
181 *pred_name,
182 field_names,
183 field_specs,
184 ),
185 ResolvedExpr::Module {
186 name,
187 exports,
188 body,
189 } => self.compile_module(*name, exports, body),
190 ResolvedExpr::Import { path, selective } => self.compile_import(path, selective),
191 ResolvedExpr::Load(path) => self.compile_load(path),
192 ResolvedExpr::Eval(expr) => self.compile_eval(expr),
193 ResolvedExpr::Prompt(entries) => self.compile_prompt(entries),
194 ResolvedExpr::Message { role, parts } => self.compile_message(role, parts),
195 ResolvedExpr::Deftool {
196 name,
197 description,
198 parameters,
199 handler,
200 } => self.compile_deftool(*name, description, parameters, handler),
201 ResolvedExpr::Defagent { name, options } => self.compile_defagent(*name, options),
202 ResolvedExpr::Delay(expr) => self.compile_delay(expr),
203 ResolvedExpr::Force(expr) => self.compile_force(expr),
204 ResolvedExpr::Macroexpand(expr) => self.compile_macroexpand(expr),
205 }
206 }
207
208 fn compile_const(&mut self, val: &Value) -> Result<(), SemaError> {
211 if val.is_nil() {
212 self.emit.emit_op(Op::Nil);
213 } else if val.as_bool() == Some(true) {
214 self.emit.emit_op(Op::True);
215 } else if val.as_bool() == Some(false) {
216 self.emit.emit_op(Op::False);
217 } else {
218 self.emit.emit_const(val.clone());
219 }
220 Ok(())
221 }
222
223 fn compile_var_load(&mut self, vr: &VarRef) -> Result<(), SemaError> {
226 match vr.resolution {
227 VarResolution::Local { slot } => match slot {
228 0 => self.emit.emit_op(Op::LoadLocal0),
229 1 => self.emit.emit_op(Op::LoadLocal1),
230 2 => self.emit.emit_op(Op::LoadLocal2),
231 3 => self.emit.emit_op(Op::LoadLocal3),
232 _ => {
233 self.emit.emit_op(Op::LoadLocal);
234 self.emit.emit_u16(slot);
235 }
236 },
237 VarResolution::Upvalue { index } => {
238 self.emit.emit_op(Op::LoadUpvalue);
239 self.emit.emit_u16(index);
240 }
241 VarResolution::Global { spur } => {
242 self.emit.emit_op(Op::LoadGlobal);
243 self.emit.emit_u32(spur_to_u32(spur));
244 }
245 }
246 Ok(())
247 }
248
249 fn compile_var_store(&mut self, vr: &VarRef) {
250 match vr.resolution {
251 VarResolution::Local { slot } => {
252 self.emit.emit_op(Op::StoreLocal);
253 self.emit.emit_u16(slot);
254 }
255 VarResolution::Upvalue { index } => {
256 self.emit.emit_op(Op::StoreUpvalue);
257 self.emit.emit_u16(index);
258 }
259 VarResolution::Global { spur } => {
260 self.emit.emit_op(Op::StoreGlobal);
261 self.emit.emit_u32(spur_to_u32(spur));
262 }
263 }
264 }
265
266 fn compile_if(
269 &mut self,
270 test: &ResolvedExpr,
271 then: &ResolvedExpr,
272 else_: &ResolvedExpr,
273 ) -> Result<(), SemaError> {
274 self.compile_expr(test)?;
275 let else_jump = self.emit.emit_jump(Op::JumpIfFalse);
276 self.compile_expr(then)?;
277 let end_jump = self.emit.emit_jump(Op::Jump);
278 self.emit.patch_jump(else_jump);
279 self.compile_expr(else_)?;
280 self.emit.patch_jump(end_jump);
281 Ok(())
282 }
283
284 fn compile_begin(&mut self, exprs: &[ResolvedExpr]) -> Result<(), SemaError> {
285 if exprs.is_empty() {
286 self.emit.emit_op(Op::Nil);
287 return Ok(());
288 }
289 for (i, expr) in exprs.iter().enumerate() {
290 self.compile_expr(expr)?;
291 if i < exprs.len() - 1 {
292 self.emit.emit_op(Op::Pop);
293 }
294 }
295 Ok(())
296 }
297
298 fn compile_set(&mut self, vr: &VarRef, val: &ResolvedExpr) -> Result<(), SemaError> {
301 self.compile_expr(val)?;
302 self.emit.emit_op(Op::Dup); self.compile_var_store(vr);
304 Ok(())
305 }
306
307 fn compile_define(&mut self, spur: Spur, val: &ResolvedExpr) -> Result<(), SemaError> {
308 self.compile_expr(val)?;
309 self.emit.emit_op(Op::DefineGlobal);
310 self.emit.emit_u32(spur_to_u32(spur));
311 self.emit.emit_op(Op::Nil); Ok(())
313 }
314
315 fn compile_lambda(&mut self, def: &ResolvedLambda) -> Result<(), SemaError> {
318 let mut inner = Compiler::new();
320 inner.n_locals = def.n_locals;
321
322 if def.body.is_empty() {
324 inner.emit.emit_op(Op::Nil);
325 } else {
326 for (i, expr) in def.body.iter().enumerate() {
327 inner.compile_expr(expr)?;
328 if i < def.body.len() - 1 {
329 inner.emit.emit_op(Op::Pop);
330 }
331 }
332 }
333 inner.emit.emit_op(Op::Return);
334
335 let func_id = self.functions.len() as u16;
336 let (mut chunk, mut child_functions) = inner.finish();
337
338 let offset = func_id + 1;
342 if offset > 0 && !child_functions.is_empty() {
343 patch_closure_func_ids(&mut chunk, offset);
344 for f in &mut child_functions {
345 patch_closure_func_ids(&mut f.chunk, offset);
346 }
347 }
348
349 let func = Function {
350 name: def.name,
351 chunk,
352 upvalue_descs: def.upvalues.clone(),
353 arity: def.params.len() as u16,
354 has_rest: def.rest.is_some(),
355 local_names: Vec::new(),
356 };
357 self.functions.push(func);
358 self.functions.extend(child_functions);
359
360 let n_upvalues = def.upvalues.len() as u16;
362 self.emit.emit_op(Op::MakeClosure);
363 self.emit.emit_u16(func_id);
364 self.emit.emit_u16(n_upvalues);
365
366 for uv in &def.upvalues {
368 match uv {
369 UpvalueDesc::ParentLocal(slot) => {
370 self.emit.emit_u16(1); self.emit.emit_u16(*slot);
372 }
373 UpvalueDesc::ParentUpvalue(idx) => {
374 self.emit.emit_u16(0); self.emit.emit_u16(*idx);
376 }
377 }
378 }
379
380 Ok(())
381 }
382
383 fn compile_call(
386 &mut self,
387 func: &ResolvedExpr,
388 args: &[ResolvedExpr],
389 tail: bool,
390 ) -> Result<(), SemaError> {
391 self.compile_expr(func)?;
393 for arg in args {
395 self.compile_expr(arg)?;
396 }
397 let argc = args.len() as u16;
398 if tail {
399 self.emit.emit_op(Op::TailCall);
400 } else {
401 self.emit.emit_op(Op::Call);
402 }
403 self.emit.emit_u16(argc);
404 Ok(())
405 }
406
407 fn compile_let(
410 &mut self,
411 bindings: &[(VarRef, ResolvedExpr)],
412 body: &[ResolvedExpr],
413 ) -> Result<(), SemaError> {
414 for (_, init) in bindings {
416 self.compile_expr(init)?;
417 }
418 for (vr, _) in bindings.iter().rev() {
420 self.compile_var_store(vr);
421 }
422 self.compile_begin(body)
424 }
425
426 fn compile_let_star(
427 &mut self,
428 bindings: &[(VarRef, ResolvedExpr)],
429 body: &[ResolvedExpr],
430 ) -> Result<(), SemaError> {
431 for (vr, init) in bindings {
433 self.compile_expr(init)?;
434 self.compile_var_store(vr);
435 }
436 self.compile_begin(body)
437 }
438
439 fn compile_letrec(
440 &mut self,
441 bindings: &[(VarRef, ResolvedExpr)],
442 body: &[ResolvedExpr],
443 ) -> Result<(), SemaError> {
444 for (vr, _) in bindings {
446 self.emit.emit_op(Op::Nil);
447 self.compile_var_store(vr);
448 }
449 for (vr, init) in bindings {
451 self.compile_expr(init)?;
452 self.compile_var_store(vr);
453 }
454 self.compile_begin(body)
455 }
456
457 fn compile_named_let(
458 &mut self,
459 name: &VarRef,
460 bindings: &[(VarRef, ResolvedExpr)],
461 body: &[ResolvedExpr],
462 ) -> Result<(), SemaError> {
463 let params: Vec<Spur> = bindings.iter().map(|(vr, _)| vr.name).collect();
471
472 let mut inner = Compiler::new();
474 let max_slot = bindings
477 .iter()
478 .map(|(vr, _)| match vr.resolution {
479 VarResolution::Local { slot } => slot + 1,
480 _ => 0,
481 })
482 .max()
483 .unwrap_or(0);
484 let name_slot = match name.resolution {
485 VarResolution::Local { slot } => slot + 1,
486 _ => 0,
487 };
488 inner.n_locals = max_slot.max(name_slot);
489
490 if body.is_empty() {
492 inner.emit.emit_op(Op::Nil);
493 } else {
494 for (i, expr) in body.iter().enumerate() {
495 inner.compile_expr(expr)?;
496 if i < body.len() - 1 {
497 inner.emit.emit_op(Op::Pop);
498 }
499 }
500 }
501 inner.emit.emit_op(Op::Return);
502
503 let func_id = self.functions.len() as u16;
504 let (chunk, child_functions) = inner.finish();
505
506 let func = Function {
507 name: Some(name.name),
508 chunk,
509 upvalue_descs: Vec::new(),
510 arity: params.len() as u16,
511 has_rest: false,
512 local_names: Vec::new(),
513 };
514 self.functions.push(func);
515 self.functions.extend(child_functions);
516
517 self.emit.emit_op(Op::MakeClosure);
519 self.emit.emit_u16(func_id);
520 self.emit.emit_u16(0);
522
523 self.compile_var_store(name);
525
526 self.compile_var_load(name)?;
528 for (_, init) in bindings {
529 self.compile_expr(init)?;
530 }
531 let argc = bindings.len() as u16;
532 self.emit.emit_op(Op::Call);
533 self.emit.emit_u16(argc);
534
535 Ok(())
536 }
537
538 fn compile_do(&mut self, do_loop: &ResolvedDoLoop) -> Result<(), SemaError> {
541 for var in &do_loop.vars {
543 self.compile_expr(&var.init)?;
544 self.compile_var_store(&var.name);
545 }
546
547 let loop_top = self.emit.current_pc();
549
550 self.compile_expr(&do_loop.test)?;
552 let exit_jump = self.emit.emit_jump(Op::JumpIfTrue);
553
554 for expr in &do_loop.body {
556 self.compile_expr(expr)?;
557 self.emit.emit_op(Op::Pop);
558 }
559
560 let mut step_vars = Vec::new();
563 for var in &do_loop.vars {
564 if let Some(step) = &var.step {
565 self.compile_expr(step)?;
566 step_vars.push(&var.name);
567 }
568 }
569 for vr in step_vars.iter().rev() {
571 self.compile_var_store(vr);
572 }
573
574 self.emit.emit_op(Op::Jump);
576 let jump_end_pc = self.emit.current_pc();
577 let offset = loop_top as i32 - (jump_end_pc as i32 + 4);
578 self.emit.emit_i32(offset);
579
580 self.emit.patch_jump(exit_jump);
582 if do_loop.result.is_empty() {
583 self.emit.emit_op(Op::Nil);
584 } else {
585 for (i, expr) in do_loop.result.iter().enumerate() {
586 self.compile_expr(expr)?;
587 if i < do_loop.result.len() - 1 {
588 self.emit.emit_op(Op::Pop);
589 }
590 }
591 }
592
593 Ok(())
594 }
595
596 fn compile_try(
599 &mut self,
600 body: &[ResolvedExpr],
601 catch_var: &VarRef,
602 handler: &[ResolvedExpr],
603 ) -> Result<(), SemaError> {
604 let try_start = self.emit.current_pc();
605
606 self.compile_begin(body)?;
608 let try_end = self.emit.current_pc();
609
610 let success_jump = self.emit.emit_jump(Op::Jump);
612
613 let handler_pc = self.emit.current_pc();
614
615 let catch_slot = match catch_var.resolution {
618 VarResolution::Local { slot } => slot,
619 _ => 0,
620 };
621 self.emit.emit_op(Op::StoreLocal);
622 self.emit.emit_u16(catch_slot);
623
624 self.compile_begin(handler)?;
626
627 self.emit.patch_jump(success_jump);
628
629 self.add_exception_entry(ExceptionEntry {
637 try_start,
638 try_end,
639 handler_pc,
640 stack_depth: self.n_locals,
641 catch_slot,
642 });
643
644 Ok(())
645 }
646
647 fn add_exception_entry(&mut self, entry: ExceptionEntry) {
648 self.exception_entries.push(entry);
653 }
654
655 fn compile_throw(&mut self, val: &ResolvedExpr) -> Result<(), SemaError> {
656 self.compile_expr(val)?;
657 self.emit.emit_op(Op::Throw);
658 Ok(())
659 }
660
661 fn compile_and(&mut self, exprs: &[ResolvedExpr]) -> Result<(), SemaError> {
664 if exprs.is_empty() {
665 self.emit.emit_op(Op::True);
666 return Ok(());
667 }
668
669 let mut jumps = Vec::new();
670 for (i, expr) in exprs.iter().enumerate() {
671 self.compile_expr(expr)?;
672 if i < exprs.len() - 1 {
673 self.emit.emit_op(Op::Dup);
675 let jump = self.emit.emit_jump(Op::JumpIfFalse);
676 jumps.push(jump);
677 self.emit.emit_op(Op::Pop); }
679 }
680 let end_jump = self.emit.emit_jump(Op::Jump);
681 for jump in jumps {
683 self.emit.patch_jump(jump);
684 }
685 self.emit.patch_jump(end_jump);
686 Ok(())
687 }
688
689 fn compile_or(&mut self, exprs: &[ResolvedExpr]) -> Result<(), SemaError> {
690 if exprs.is_empty() {
691 self.emit.emit_op(Op::False);
692 return Ok(());
693 }
694
695 let mut jumps = Vec::new();
696 for (i, expr) in exprs.iter().enumerate() {
697 self.compile_expr(expr)?;
698 if i < exprs.len() - 1 {
699 self.emit.emit_op(Op::Dup);
700 let jump = self.emit.emit_jump(Op::JumpIfTrue);
701 jumps.push(jump);
702 self.emit.emit_op(Op::Pop);
703 }
704 }
705 let end_jump = self.emit.emit_jump(Op::Jump);
706 for jump in jumps {
707 self.emit.patch_jump(jump);
708 }
709 self.emit.patch_jump(end_jump);
710 Ok(())
711 }
712
713 fn compile_make_list(&mut self, exprs: &[ResolvedExpr]) -> Result<(), SemaError> {
716 for expr in exprs {
717 self.compile_expr(expr)?;
718 }
719 self.emit.emit_op(Op::MakeList);
720 self.emit.emit_u16(exprs.len() as u16);
721 Ok(())
722 }
723
724 fn compile_make_vector(&mut self, exprs: &[ResolvedExpr]) -> Result<(), SemaError> {
725 for expr in exprs {
726 self.compile_expr(expr)?;
727 }
728 self.emit.emit_op(Op::MakeVector);
729 self.emit.emit_u16(exprs.len() as u16);
730 Ok(())
731 }
732
733 fn compile_make_map(
734 &mut self,
735 pairs: &[(ResolvedExpr, ResolvedExpr)],
736 ) -> Result<(), SemaError> {
737 for (key, val) in pairs {
738 self.compile_expr(key)?;
739 self.compile_expr(val)?;
740 }
741 self.emit.emit_op(Op::MakeMap);
742 self.emit.emit_u16(pairs.len() as u16);
743 Ok(())
744 }
745
746 fn compile_eval(&mut self, expr: &ResolvedExpr) -> Result<(), SemaError> {
753 self.emit_runtime_call("__vm-eval", &[expr])
754 }
755
756 fn compile_load(&mut self, path: &ResolvedExpr) -> Result<(), SemaError> {
757 self.emit_runtime_call("__vm-load", &[path])
758 }
759
760 fn compile_import(&mut self, path: &ResolvedExpr, selective: &[Spur]) -> Result<(), SemaError> {
761 let sel_list: Vec<Value> = selective
762 .iter()
763 .map(|s| Value::symbol_from_spur(*s))
764 .collect();
765 self.emit_runtime_call_with_const("__vm-import", path, &Value::list(sel_list))
766 }
767
768 fn compile_module(
769 &mut self,
770 _name: Spur,
771 _exports: &[Spur],
772 body: &[ResolvedExpr],
773 ) -> Result<(), SemaError> {
774 for (i, expr) in body.iter().enumerate() {
776 self.compile_expr(expr)?;
777 if i < body.len() - 1 {
778 self.emit.emit_op(Op::Pop);
779 }
780 }
781 if body.is_empty() {
782 self.emit.emit_op(Op::Nil);
783 }
784 Ok(())
787 }
788
789 fn compile_defmacro(
790 &mut self,
791 name: Spur,
792 params: &[Spur],
793 rest: &Option<Spur>,
794 body: &[ResolvedExpr],
795 ) -> Result<(), SemaError> {
796 let param_vals: Vec<Value> = params.iter().map(|s| Value::symbol_from_spur(*s)).collect();
799 self.emit.emit_op(Op::LoadGlobal);
800 self.emit.emit_u32(spur_to_u32(intern("__vm-defmacro")));
801 self.emit.emit_const(Value::symbol_from_spur(name));
802 self.emit.emit_const(Value::list(param_vals));
803 if let Some(r) = rest {
804 self.emit.emit_const(Value::symbol_from_spur(*r));
805 } else {
806 self.emit.emit_op(Op::Nil);
807 }
808 self.compile_begin(body)?;
810 self.emit.emit_op(Op::Call);
811 self.emit.emit_u16(4);
812 Ok(())
813 }
814
815 fn compile_define_record_type(
816 &mut self,
817 type_name: Spur,
818 ctor_name: Spur,
819 pred_name: Spur,
820 field_names: &[Spur],
821 field_specs: &[(Spur, Spur)],
822 ) -> Result<(), SemaError> {
823 self.emit.emit_op(Op::LoadGlobal);
826 self.emit
827 .emit_u32(spur_to_u32(intern("__vm-define-record-type")));
828 self.emit.emit_const(Value::symbol_from_spur(type_name));
829 self.emit.emit_const(Value::symbol_from_spur(ctor_name));
830 self.emit.emit_const(Value::symbol_from_spur(pred_name));
831 let fields: Vec<Value> = field_names
832 .iter()
833 .map(|s| Value::symbol_from_spur(*s))
834 .collect();
835 self.emit.emit_const(Value::list(fields));
836 let specs: Vec<Value> = field_specs
837 .iter()
838 .map(|(f, a)| {
839 Value::list(vec![
840 Value::symbol_from_spur(*f),
841 Value::symbol_from_spur(*a),
842 ])
843 })
844 .collect();
845 self.emit.emit_const(Value::list(specs));
846 self.emit.emit_op(Op::Call);
847 self.emit.emit_u16(5);
848 Ok(())
849 }
850
851 fn compile_prompt(&mut self, entries: &[ResolvedPromptEntry]) -> Result<(), SemaError> {
852 self.emit.emit_op(Op::LoadGlobal);
854 self.emit.emit_u32(spur_to_u32(intern("__vm-prompt")));
855 for entry in entries {
857 match entry {
858 ResolvedPromptEntry::RoleContent { role, parts } => {
859 self.emit.emit_const(Value::string(role));
860 for part in parts {
861 self.compile_expr(part)?;
862 }
863 self.emit.emit_op(Op::MakeList);
864 self.emit.emit_u16(parts.len() as u16);
865 self.emit.emit_op(Op::MakeList);
867 self.emit.emit_u16(2);
868 }
869 ResolvedPromptEntry::Expr(expr) => {
870 self.compile_expr(expr)?;
871 }
872 }
873 }
874 self.emit.emit_op(Op::MakeList);
875 self.emit.emit_u16(entries.len() as u16);
876 self.emit.emit_op(Op::Call);
877 self.emit.emit_u16(1);
878 Ok(())
879 }
880
881 fn compile_message(
882 &mut self,
883 role: &ResolvedExpr,
884 parts: &[ResolvedExpr],
885 ) -> Result<(), SemaError> {
886 self.emit.emit_op(Op::LoadGlobal);
887 self.emit.emit_u32(spur_to_u32(intern("__vm-message")));
888 self.compile_expr(role)?;
889 for part in parts {
890 self.compile_expr(part)?;
891 }
892 self.emit.emit_op(Op::MakeList);
893 self.emit.emit_u16(parts.len() as u16);
894 self.emit.emit_op(Op::Call);
895 self.emit.emit_u16(2);
896 Ok(())
897 }
898
899 fn compile_deftool(
900 &mut self,
901 name: Spur,
902 description: &ResolvedExpr,
903 parameters: &ResolvedExpr,
904 handler: &ResolvedExpr,
905 ) -> Result<(), SemaError> {
906 self.emit.emit_op(Op::LoadGlobal);
907 self.emit.emit_u32(spur_to_u32(intern("__vm-deftool")));
908 self.emit.emit_const(Value::symbol_from_spur(name));
909 self.compile_expr(description)?;
910 self.compile_expr(parameters)?;
911 self.compile_expr(handler)?;
912 self.emit.emit_op(Op::Call);
913 self.emit.emit_u16(4);
914 Ok(())
915 }
916
917 fn compile_defagent(&mut self, name: Spur, options: &ResolvedExpr) -> Result<(), SemaError> {
918 self.emit.emit_op(Op::LoadGlobal);
919 self.emit.emit_u32(spur_to_u32(intern("__vm-defagent")));
920 self.emit.emit_const(Value::symbol_from_spur(name));
921 self.compile_expr(options)?;
922 self.emit.emit_op(Op::Call);
923 self.emit.emit_u16(2);
924 Ok(())
925 }
926
927 fn compile_delay(&mut self, expr: &ResolvedExpr) -> Result<(), SemaError> {
928 self.emit.emit_op(Op::LoadGlobal);
932 self.emit.emit_u32(spur_to_u32(intern("__vm-delay")));
933 self.compile_expr(expr)?;
934 self.emit.emit_op(Op::Call);
935 self.emit.emit_u16(1);
936 Ok(())
937 }
938
939 fn compile_force(&mut self, expr: &ResolvedExpr) -> Result<(), SemaError> {
940 self.emit.emit_op(Op::LoadGlobal);
941 self.emit.emit_u32(spur_to_u32(intern("__vm-force")));
942 self.compile_expr(expr)?;
943 self.emit.emit_op(Op::Call);
944 self.emit.emit_u16(1);
945 Ok(())
946 }
947
948 fn compile_macroexpand(&mut self, expr: &ResolvedExpr) -> Result<(), SemaError> {
949 self.emit.emit_op(Op::LoadGlobal);
950 self.emit.emit_u32(spur_to_u32(intern("__vm-macroexpand")));
951 self.compile_expr(expr)?;
952 self.emit.emit_op(Op::Call);
953 self.emit.emit_u16(1);
954 Ok(())
955 }
956
957 fn emit_runtime_call(&mut self, name: &str, args: &[&ResolvedExpr]) -> Result<(), SemaError> {
960 self.emit.emit_op(Op::LoadGlobal);
961 self.emit.emit_u32(spur_to_u32(intern(name)));
962 for arg in args {
963 self.compile_expr(arg)?;
964 }
965 self.emit.emit_op(Op::Call);
966 self.emit.emit_u16(args.len() as u16);
967 Ok(())
968 }
969
970 fn emit_runtime_call_with_const(
971 &mut self,
972 name: &str,
973 arg1: &ResolvedExpr,
974 arg2: &Value,
975 ) -> Result<(), SemaError> {
976 self.emit.emit_op(Op::LoadGlobal);
977 self.emit.emit_u32(spur_to_u32(intern(name)));
978 self.compile_expr(arg1)?;
979 self.emit.emit_const(arg2.clone());
980 self.emit.emit_op(Op::Call);
981 self.emit.emit_u16(2);
982 Ok(())
983 }
984}
985
986fn spur_to_u32(spur: Spur) -> u32 {
987 spur.into_inner().get()
988}
989
990#[cfg(test)]
991mod tests {
992 use super::*;
993 use crate::lower::lower;
994 use crate::resolve::resolve;
995
996 fn compile_str(input: &str) -> CompileResult {
997 let val = sema_reader::read(input).unwrap();
998 let core = lower(&val).unwrap();
999 let resolved = resolve(&core).unwrap();
1000 compile(&resolved).unwrap()
1001 }
1002
1003 fn compile_many_str(input: &str) -> CompileResult {
1004 let vals = sema_reader::read_many(input).unwrap();
1005 let mut resolved = Vec::new();
1006 for val in &vals {
1007 let core = lower(val).unwrap();
1008 resolved.push(resolve(&core).unwrap());
1009 }
1010 compile_many(&resolved).unwrap()
1011 }
1012
1013 fn extract_ops(chunk: &Chunk) -> Vec<Op> {
1015 let code = &chunk.code;
1016 let mut ops = Vec::new();
1017 let mut pc = 0;
1018 while pc < code.len() {
1019 let op = unsafe { std::mem::transmute::<u8, Op>(code[pc]) };
1020 ops.push(op);
1021 pc += 1;
1022 match op {
1024 Op::Const
1025 | Op::LoadLocal
1026 | Op::StoreLocal
1027 | Op::LoadUpvalue
1028 | Op::StoreUpvalue
1029 | Op::Call
1030 | Op::TailCall
1031 | Op::MakeList
1032 | Op::MakeVector
1033 | Op::MakeMap
1034 | Op::MakeHashMap => pc += 2,
1035 Op::LoadGlobal | Op::StoreGlobal | Op::DefineGlobal => pc += 4,
1036 Op::Jump | Op::JumpIfFalse | Op::JumpIfTrue => pc += 4,
1037 Op::CallNative => pc += 4,
1038 Op::MakeClosure => {
1039 let func_id = u16::from_le_bytes([code[pc], code[pc + 1]]);
1040 let n_upvalues = u16::from_le_bytes([code[pc + 2], code[pc + 3]]);
1041 pc += 4;
1042 pc += n_upvalues as usize * 4; let _ = func_id;
1044 }
1045 _ => {} }
1047 }
1048 ops
1049 }
1050
1051 fn read_jump_offset(chunk: &Chunk, op_pc: usize) -> i32 {
1053 i32::from_le_bytes([
1054 chunk.code[op_pc + 1],
1055 chunk.code[op_pc + 2],
1056 chunk.code[op_pc + 3],
1057 chunk.code[op_pc + 4],
1058 ])
1059 }
1060
1061 #[test]
1064 fn test_compile_int_literal() {
1065 let result = compile_str("42");
1066 let ops = extract_ops(&result.chunk);
1067 assert_eq!(ops, vec![Op::Const, Op::Return]);
1068 assert_eq!(result.chunk.consts[0], Value::int(42));
1069 }
1070
1071 #[test]
1072 fn test_compile_nil() {
1073 let result = compile_str("()");
1074 let ops = extract_ops(&result.chunk);
1075 assert_eq!(ops, vec![Op::Nil, Op::Return]);
1076 }
1077
1078 #[test]
1079 fn test_compile_true_false() {
1080 let t = compile_str("#t");
1081 assert_eq!(extract_ops(&t.chunk), vec![Op::True, Op::Return]);
1082
1083 let f = compile_str("#f");
1084 assert_eq!(extract_ops(&f.chunk), vec![Op::False, Op::Return]);
1085 }
1086
1087 #[test]
1088 fn test_compile_string_literal() {
1089 let result = compile_str("\"hello\"");
1090 let ops = extract_ops(&result.chunk);
1091 assert_eq!(ops, vec![Op::Const, Op::Return]);
1092 assert_eq!(result.chunk.consts[0].as_str(), Some("hello"));
1093 }
1094
1095 #[test]
1098 fn test_compile_global_var() {
1099 let result = compile_str("x");
1100 let ops = extract_ops(&result.chunk);
1101 assert_eq!(ops, vec![Op::LoadGlobal, Op::Return]);
1102 }
1103
1104 #[test]
1107 fn test_compile_if() {
1108 let result = compile_str("(if #t 1 2)");
1109 let ops = extract_ops(&result.chunk);
1110 assert_eq!(
1112 ops,
1113 vec![
1114 Op::True,
1115 Op::JumpIfFalse,
1116 Op::Const,
1117 Op::Jump,
1118 Op::Const,
1119 Op::Return
1120 ]
1121 );
1122 }
1123
1124 #[test]
1125 fn test_compile_nested_if() {
1126 let result = compile_str("(if #t (if #f 1 2) 3)");
1127 let ops = extract_ops(&result.chunk);
1128 let jif_count = ops.iter().filter(|&&op| op == Op::JumpIfFalse).count();
1129 assert_eq!(jif_count, 2);
1130 }
1131
1132 #[test]
1133 fn test_compile_begin() {
1134 let result = compile_str("(begin 1 2 3)");
1135 let ops = extract_ops(&result.chunk);
1136 assert_eq!(
1138 ops,
1139 vec![
1140 Op::Const,
1141 Op::Pop,
1142 Op::Const,
1143 Op::Pop,
1144 Op::Const,
1145 Op::Return
1146 ]
1147 );
1148 }
1149
1150 #[test]
1153 fn test_compile_define() {
1154 let result = compile_str("(define x 42)");
1155 let ops = extract_ops(&result.chunk);
1156 assert_eq!(ops, vec![Op::Const, Op::DefineGlobal, Op::Nil, Op::Return]);
1158 }
1159
1160 #[test]
1163 fn test_compile_lambda() {
1164 let result = compile_str("(lambda (x) x)");
1165 assert_eq!(result.functions.len(), 1);
1166 let func = &result.functions[0];
1167 assert_eq!(func.arity, 1);
1168 assert!(!func.has_rest);
1169
1170 let inner_ops = extract_ops(&func.chunk);
1172 assert_eq!(inner_ops, vec![Op::LoadLocal0, Op::Return]);
1173
1174 let top_ops = extract_ops(&result.chunk);
1176 assert_eq!(top_ops, vec![Op::MakeClosure, Op::Return]);
1177 }
1178
1179 #[test]
1180 fn test_compile_lambda_rest_param() {
1181 let result = compile_str("(lambda (x . rest) x)");
1182 assert_eq!(result.functions.len(), 1);
1183 let func = &result.functions[0];
1184 assert_eq!(func.arity, 1);
1185 assert!(func.has_rest);
1186 }
1187
1188 #[test]
1191 fn test_compile_non_tail_call() {
1192 let result = compile_str("(+ 1 2)");
1194 let ops = extract_ops(&result.chunk);
1195 assert_eq!(
1197 ops,
1198 vec![Op::LoadGlobal, Op::Const, Op::Const, Op::Call, Op::Return]
1199 );
1200 assert!(!ops.contains(&Op::TailCall));
1202 }
1203
1204 #[test]
1205 fn test_compile_tail_call() {
1206 let result = compile_str("(lambda () (f 1))");
1207 assert_eq!(result.functions.len(), 1);
1208 let inner_ops = extract_ops(&result.functions[0].chunk);
1209 assert_eq!(
1211 inner_ops,
1212 vec![Op::LoadGlobal, Op::Const, Op::TailCall, Op::Return]
1213 );
1214 assert!(!inner_ops.contains(&Op::Call));
1216 }
1217
1218 #[test]
1219 fn test_compile_non_tail_in_begin() {
1220 let result = compile_str("(lambda () (f 1) (g 2))");
1222 let inner_ops = extract_ops(&result.functions[0].chunk);
1223 assert_eq!(
1226 inner_ops,
1227 vec![
1228 Op::LoadGlobal,
1229 Op::Const,
1230 Op::Call,
1231 Op::Pop,
1232 Op::LoadGlobal,
1233 Op::Const,
1234 Op::TailCall,
1235 Op::Return
1236 ]
1237 );
1238 }
1239
1240 #[test]
1243 fn test_compile_let() {
1244 let result = compile_str("(lambda () (let ((x 1) (y 2)) x))");
1245 let inner_ops = extract_ops(&result.functions[0].chunk);
1246 assert_eq!(
1248 inner_ops,
1249 vec![
1250 Op::Const,
1251 Op::Const,
1252 Op::StoreLocal,
1253 Op::StoreLocal,
1254 Op::LoadLocal0,
1255 Op::Return
1256 ]
1257 );
1258 }
1259
1260 #[test]
1261 fn test_compile_let_star() {
1262 let result = compile_str("(lambda () (let* ((x 1) (y x)) y))");
1264 let inner_ops = extract_ops(&result.functions[0].chunk);
1265 assert_eq!(
1267 inner_ops,
1268 vec![
1269 Op::Const,
1270 Op::StoreLocal,
1271 Op::LoadLocal0,
1272 Op::StoreLocal,
1273 Op::LoadLocal1,
1274 Op::Return
1275 ]
1276 );
1277 }
1278
1279 #[test]
1280 fn test_compile_letrec() {
1281 let result = compile_str("(lambda () (letrec ((x 1)) x))");
1282 let inner_ops = extract_ops(&result.functions[0].chunk);
1283 assert_eq!(
1285 inner_ops,
1286 vec![
1287 Op::Nil,
1288 Op::StoreLocal,
1289 Op::Const,
1290 Op::StoreLocal,
1291 Op::LoadLocal0,
1292 Op::Return
1293 ]
1294 );
1295 }
1296
1297 #[test]
1300 fn test_compile_set_local() {
1301 let result = compile_str("(lambda (x) (set! x 42))");
1302 let inner_ops = extract_ops(&result.functions[0].chunk);
1303 assert_eq!(
1305 inner_ops,
1306 vec![Op::Const, Op::Dup, Op::StoreLocal, Op::Return]
1307 );
1308 }
1309
1310 #[test]
1311 fn test_compile_set_global() {
1312 let result = compile_str("(set! x 42)");
1313 let ops = extract_ops(&result.chunk);
1314 assert_eq!(ops, vec![Op::Const, Op::Dup, Op::StoreGlobal, Op::Return]);
1316 }
1317
1318 #[test]
1319 fn test_compile_set_upvalue() {
1320 let result = compile_str("(lambda (x) (lambda () (set! x 1)))");
1322 assert_eq!(result.functions.len(), 2);
1323 let inner_ops = extract_ops(&result.functions[1].chunk);
1324 assert_eq!(
1326 inner_ops,
1327 vec![Op::Const, Op::Dup, Op::StoreUpvalue, Op::Return]
1328 );
1329 }
1330
1331 #[test]
1334 fn test_compile_and_empty() {
1335 let result = compile_str("(and)");
1336 let ops = extract_ops(&result.chunk);
1337 assert_eq!(ops, vec![Op::True, Op::Return]);
1338 }
1339
1340 #[test]
1341 fn test_compile_or_empty() {
1342 let result = compile_str("(or)");
1343 let ops = extract_ops(&result.chunk);
1344 assert_eq!(ops, vec![Op::False, Op::Return]);
1345 }
1346
1347 #[test]
1348 fn test_compile_and_short_circuit() {
1349 let result = compile_str("(and 1 2)");
1350 let ops = extract_ops(&result.chunk);
1351 assert_eq!(
1353 ops,
1354 vec![
1355 Op::Const,
1356 Op::Dup,
1357 Op::JumpIfFalse,
1358 Op::Pop,
1359 Op::Const,
1360 Op::Jump,
1361 Op::Return
1362 ]
1363 );
1364 }
1365
1366 #[test]
1367 fn test_compile_or_short_circuit() {
1368 let result = compile_str("(or 1 2)");
1369 let ops = extract_ops(&result.chunk);
1370 assert_eq!(
1372 ops,
1373 vec![
1374 Op::Const,
1375 Op::Dup,
1376 Op::JumpIfTrue,
1377 Op::Pop,
1378 Op::Const,
1379 Op::Jump,
1380 Op::Return
1381 ]
1382 );
1383 }
1384
1385 #[test]
1388 fn test_compile_vector_literal() {
1389 let result = compile_str("[1 2 3]");
1390 let ops = extract_ops(&result.chunk);
1391 assert_eq!(
1392 ops,
1393 vec![Op::Const, Op::Const, Op::Const, Op::MakeVector, Op::Return]
1394 );
1395 }
1396
1397 #[test]
1398 fn test_compile_quote() {
1399 let result = compile_str("'(1 2 3)");
1400 let ops = extract_ops(&result.chunk);
1401 assert_eq!(ops, vec![Op::Const, Op::Return]);
1402 }
1403
1404 #[test]
1407 fn test_compile_throw() {
1408 let result = compile_str("(throw 42)");
1409 let ops = extract_ops(&result.chunk);
1410 assert_eq!(ops, vec![Op::Const, Op::Throw, Op::Return]);
1411 }
1412
1413 #[test]
1414 fn test_compile_try_catch() {
1415 let result = compile_str("(lambda () (try (/ 1 0) (catch e e)))");
1416 let func = &result.functions[0];
1417 assert_eq!(func.chunk.exception_table.len(), 1);
1419 let entry = &func.chunk.exception_table[0];
1420 assert!(entry.try_start < entry.try_end);
1421 assert!(entry.handler_pc > entry.try_end);
1422 assert!((entry.handler_pc as usize) < func.chunk.code.len());
1423 let ops = extract_ops(&func.chunk);
1425 assert!(ops.contains(&Op::StoreLocal)); assert!(ops.contains(&Op::Jump));
1428 }
1429
1430 #[test]
1433 fn test_compile_closure_with_upvalue() {
1434 let result = compile_str("(lambda (x) (lambda () x))");
1435 assert_eq!(result.functions.len(), 2);
1436 let outer = &result.functions[0];
1438 let outer_ops = extract_ops(&outer.chunk);
1439 assert!(outer_ops.contains(&Op::MakeClosure));
1440 let inner = &result.functions[1];
1442 let inner_ops = extract_ops(&inner.chunk);
1443 assert_eq!(inner_ops, vec![Op::LoadUpvalue, Op::Return]);
1444 assert_eq!(inner.upvalue_descs.len(), 1);
1446 assert!(matches!(
1447 inner.upvalue_descs[0],
1448 UpvalueDesc::ParentLocal(0)
1449 ));
1450 }
1451
1452 #[test]
1453 fn test_compile_nested_lambda_func_ids() {
1454 let result = compile_str("(lambda () (lambda () 1) (lambda () 2))");
1457 assert_eq!(result.functions.len(), 3);
1458 let f1 = &result.functions[1];
1460 let f1_ops = extract_ops(&f1.chunk);
1461 assert_eq!(f1_ops, vec![Op::Const, Op::Return]);
1462 assert_eq!(f1.chunk.consts[0], Value::int(1));
1463
1464 let f2 = &result.functions[2];
1465 let f2_ops = extract_ops(&f2.chunk);
1466 assert_eq!(f2_ops, vec![Op::Const, Op::Return]);
1467 assert_eq!(f2.chunk.consts[0], Value::int(2));
1468
1469 let outer = &result.functions[0];
1472 let outer_ops = extract_ops(&outer.chunk);
1473 let mc_count = outer_ops
1474 .iter()
1475 .filter(|&&op| op == Op::MakeClosure)
1476 .count();
1477 assert_eq!(mc_count, 2);
1478 }
1479
1480 #[test]
1483 fn test_compile_do_loop() {
1484 let result = compile_str("(lambda () (do ((i 0 (+ i 1))) ((= i 10) i) (display i)))");
1485 let func = &result.functions[0];
1486 let ops = extract_ops(&func.chunk);
1487 let jump_pcs: Vec<usize> = (0..func.chunk.code.len())
1489 .filter(|&pc| func.chunk.code[pc] == Op::Jump as u8)
1490 .collect();
1491 let has_back_edge = jump_pcs
1493 .iter()
1494 .any(|&pc| read_jump_offset(&func.chunk, pc) < 0);
1495 assert!(has_back_edge, "do loop must have a backward jump");
1496 assert!(ops.contains(&Op::JumpIfTrue));
1498 }
1499
1500 #[test]
1503 fn test_compile_named_let() {
1504 let result = compile_str("(lambda () (let loop ((n 10)) (if (= n 0) n (loop (- n 1)))))");
1506 assert!(result.functions.len() >= 2);
1508 let outer = &result.functions[0];
1510 let outer_ops = extract_ops(&outer.chunk);
1511 assert!(outer_ops.contains(&Op::MakeClosure));
1512 assert!(outer_ops.contains(&Op::TailCall) || outer_ops.contains(&Op::Call));
1513 }
1514
1515 #[test]
1518 fn test_compile_many_empty() {
1519 let result = compile_many(&[]).unwrap();
1520 let ops = extract_ops(&result.chunk);
1521 assert_eq!(ops, vec![Op::Nil, Op::Return]);
1522 }
1523
1524 #[test]
1525 fn test_compile_many_multiple() {
1526 let result = compile_many_str("1 2 3");
1527 let ops = extract_ops(&result.chunk);
1528 assert_eq!(
1530 ops,
1531 vec![
1532 Op::Const,
1533 Op::Pop,
1534 Op::Const,
1535 Op::Pop,
1536 Op::Const,
1537 Op::Return
1538 ]
1539 );
1540 }
1541
1542 #[test]
1543 fn test_compile_many_single() {
1544 let result = compile_many_str("42");
1545 let ops = extract_ops(&result.chunk);
1546 assert_eq!(ops, vec![Op::Const, Op::Return]);
1548 }
1549
1550 #[test]
1553 fn test_calling_convention_runtime_call() {
1554 let result = compile_str("(eval 42)");
1556 let ops = extract_ops(&result.chunk);
1557 assert_eq!(ops, vec![Op::LoadGlobal, Op::Const, Op::Call, Op::Return]);
1558 assert_eq!(ops[0], Op::LoadGlobal);
1560 }
1561
1562 #[test]
1565 fn test_compile_map_literal() {
1566 let result = compile_str("{:a 1 :b 2}");
1567 let ops = extract_ops(&result.chunk);
1568 assert_eq!(
1570 ops,
1571 vec![
1572 Op::Const,
1573 Op::Const,
1574 Op::Const,
1575 Op::Const,
1576 Op::MakeMap,
1577 Op::Return
1578 ]
1579 );
1580 }
1581}