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 unsafe { std::mem::transmute::<Spur, u32>(spur) }
990}
991
992#[cfg(test)]
993mod tests {
994 use super::*;
995 use crate::lower::lower;
996 use crate::resolve::resolve;
997
998 fn compile_str(input: &str) -> CompileResult {
999 let val = sema_reader::read(input).unwrap();
1000 let core = lower(&val).unwrap();
1001 let resolved = resolve(&core).unwrap();
1002 compile(&resolved).unwrap()
1003 }
1004
1005 fn compile_many_str(input: &str) -> CompileResult {
1006 let vals = sema_reader::read_many(input).unwrap();
1007 let mut resolved = Vec::new();
1008 for val in &vals {
1009 let core = lower(val).unwrap();
1010 resolved.push(resolve(&core).unwrap());
1011 }
1012 compile_many(&resolved).unwrap()
1013 }
1014
1015 fn extract_ops(chunk: &Chunk) -> Vec<Op> {
1017 let code = &chunk.code;
1018 let mut ops = Vec::new();
1019 let mut pc = 0;
1020 while pc < code.len() {
1021 let op = unsafe { std::mem::transmute::<u8, Op>(code[pc]) };
1022 ops.push(op);
1023 pc += 1;
1024 match op {
1026 Op::Const
1027 | Op::LoadLocal
1028 | Op::StoreLocal
1029 | Op::LoadUpvalue
1030 | Op::StoreUpvalue
1031 | Op::Call
1032 | Op::TailCall
1033 | Op::MakeList
1034 | Op::MakeVector
1035 | Op::MakeMap
1036 | Op::MakeHashMap => pc += 2,
1037 Op::LoadGlobal | Op::StoreGlobal | Op::DefineGlobal => pc += 4,
1038 Op::Jump | Op::JumpIfFalse | Op::JumpIfTrue => pc += 4,
1039 Op::CallNative => pc += 4,
1040 Op::MakeClosure => {
1041 let func_id = u16::from_le_bytes([code[pc], code[pc + 1]]);
1042 let n_upvalues = u16::from_le_bytes([code[pc + 2], code[pc + 3]]);
1043 pc += 4;
1044 pc += n_upvalues as usize * 4; let _ = func_id;
1046 }
1047 _ => {} }
1049 }
1050 ops
1051 }
1052
1053 fn read_jump_offset(chunk: &Chunk, op_pc: usize) -> i32 {
1055 i32::from_le_bytes([
1056 chunk.code[op_pc + 1],
1057 chunk.code[op_pc + 2],
1058 chunk.code[op_pc + 3],
1059 chunk.code[op_pc + 4],
1060 ])
1061 }
1062
1063 #[test]
1066 fn test_compile_int_literal() {
1067 let result = compile_str("42");
1068 let ops = extract_ops(&result.chunk);
1069 assert_eq!(ops, vec![Op::Const, Op::Return]);
1070 assert_eq!(result.chunk.consts[0], Value::int(42));
1071 }
1072
1073 #[test]
1074 fn test_compile_nil() {
1075 let result = compile_str("()");
1076 let ops = extract_ops(&result.chunk);
1077 assert_eq!(ops, vec![Op::Nil, Op::Return]);
1078 }
1079
1080 #[test]
1081 fn test_compile_true_false() {
1082 let t = compile_str("#t");
1083 assert_eq!(extract_ops(&t.chunk), vec![Op::True, Op::Return]);
1084
1085 let f = compile_str("#f");
1086 assert_eq!(extract_ops(&f.chunk), vec![Op::False, Op::Return]);
1087 }
1088
1089 #[test]
1090 fn test_compile_string_literal() {
1091 let result = compile_str("\"hello\"");
1092 let ops = extract_ops(&result.chunk);
1093 assert_eq!(ops, vec![Op::Const, Op::Return]);
1094 assert_eq!(result.chunk.consts[0].as_str(), Some("hello"));
1095 }
1096
1097 #[test]
1100 fn test_compile_global_var() {
1101 let result = compile_str("x");
1102 let ops = extract_ops(&result.chunk);
1103 assert_eq!(ops, vec![Op::LoadGlobal, Op::Return]);
1104 }
1105
1106 #[test]
1109 fn test_compile_if() {
1110 let result = compile_str("(if #t 1 2)");
1111 let ops = extract_ops(&result.chunk);
1112 assert_eq!(
1114 ops,
1115 vec![
1116 Op::True,
1117 Op::JumpIfFalse,
1118 Op::Const,
1119 Op::Jump,
1120 Op::Const,
1121 Op::Return
1122 ]
1123 );
1124 }
1125
1126 #[test]
1127 fn test_compile_nested_if() {
1128 let result = compile_str("(if #t (if #f 1 2) 3)");
1129 let ops = extract_ops(&result.chunk);
1130 let jif_count = ops.iter().filter(|&&op| op == Op::JumpIfFalse).count();
1131 assert_eq!(jif_count, 2);
1132 }
1133
1134 #[test]
1135 fn test_compile_begin() {
1136 let result = compile_str("(begin 1 2 3)");
1137 let ops = extract_ops(&result.chunk);
1138 assert_eq!(
1140 ops,
1141 vec![
1142 Op::Const,
1143 Op::Pop,
1144 Op::Const,
1145 Op::Pop,
1146 Op::Const,
1147 Op::Return
1148 ]
1149 );
1150 }
1151
1152 #[test]
1155 fn test_compile_define() {
1156 let result = compile_str("(define x 42)");
1157 let ops = extract_ops(&result.chunk);
1158 assert_eq!(ops, vec![Op::Const, Op::DefineGlobal, Op::Nil, Op::Return]);
1160 }
1161
1162 #[test]
1165 fn test_compile_lambda() {
1166 let result = compile_str("(lambda (x) x)");
1167 assert_eq!(result.functions.len(), 1);
1168 let func = &result.functions[0];
1169 assert_eq!(func.arity, 1);
1170 assert!(!func.has_rest);
1171
1172 let inner_ops = extract_ops(&func.chunk);
1174 assert_eq!(inner_ops, vec![Op::LoadLocal0, Op::Return]);
1175
1176 let top_ops = extract_ops(&result.chunk);
1178 assert_eq!(top_ops, vec![Op::MakeClosure, Op::Return]);
1179 }
1180
1181 #[test]
1182 fn test_compile_lambda_rest_param() {
1183 let result = compile_str("(lambda (x . rest) x)");
1184 assert_eq!(result.functions.len(), 1);
1185 let func = &result.functions[0];
1186 assert_eq!(func.arity, 1);
1187 assert!(func.has_rest);
1188 }
1189
1190 #[test]
1193 fn test_compile_non_tail_call() {
1194 let result = compile_str("(+ 1 2)");
1196 let ops = extract_ops(&result.chunk);
1197 assert_eq!(
1199 ops,
1200 vec![Op::LoadGlobal, Op::Const, Op::Const, Op::Call, Op::Return]
1201 );
1202 assert!(!ops.contains(&Op::TailCall));
1204 }
1205
1206 #[test]
1207 fn test_compile_tail_call() {
1208 let result = compile_str("(lambda () (f 1))");
1209 assert_eq!(result.functions.len(), 1);
1210 let inner_ops = extract_ops(&result.functions[0].chunk);
1211 assert_eq!(
1213 inner_ops,
1214 vec![Op::LoadGlobal, Op::Const, Op::TailCall, Op::Return]
1215 );
1216 assert!(!inner_ops.contains(&Op::Call));
1218 }
1219
1220 #[test]
1221 fn test_compile_non_tail_in_begin() {
1222 let result = compile_str("(lambda () (f 1) (g 2))");
1224 let inner_ops = extract_ops(&result.functions[0].chunk);
1225 assert_eq!(
1228 inner_ops,
1229 vec![
1230 Op::LoadGlobal,
1231 Op::Const,
1232 Op::Call,
1233 Op::Pop,
1234 Op::LoadGlobal,
1235 Op::Const,
1236 Op::TailCall,
1237 Op::Return
1238 ]
1239 );
1240 }
1241
1242 #[test]
1245 fn test_compile_let() {
1246 let result = compile_str("(lambda () (let ((x 1) (y 2)) x))");
1247 let inner_ops = extract_ops(&result.functions[0].chunk);
1248 assert_eq!(
1250 inner_ops,
1251 vec![
1252 Op::Const,
1253 Op::Const,
1254 Op::StoreLocal,
1255 Op::StoreLocal,
1256 Op::LoadLocal0,
1257 Op::Return
1258 ]
1259 );
1260 }
1261
1262 #[test]
1263 fn test_compile_let_star() {
1264 let result = compile_str("(lambda () (let* ((x 1) (y x)) y))");
1266 let inner_ops = extract_ops(&result.functions[0].chunk);
1267 assert_eq!(
1269 inner_ops,
1270 vec![
1271 Op::Const,
1272 Op::StoreLocal,
1273 Op::LoadLocal0,
1274 Op::StoreLocal,
1275 Op::LoadLocal1,
1276 Op::Return
1277 ]
1278 );
1279 }
1280
1281 #[test]
1282 fn test_compile_letrec() {
1283 let result = compile_str("(lambda () (letrec ((x 1)) x))");
1284 let inner_ops = extract_ops(&result.functions[0].chunk);
1285 assert_eq!(
1287 inner_ops,
1288 vec![
1289 Op::Nil,
1290 Op::StoreLocal,
1291 Op::Const,
1292 Op::StoreLocal,
1293 Op::LoadLocal0,
1294 Op::Return
1295 ]
1296 );
1297 }
1298
1299 #[test]
1302 fn test_compile_set_local() {
1303 let result = compile_str("(lambda (x) (set! x 42))");
1304 let inner_ops = extract_ops(&result.functions[0].chunk);
1305 assert_eq!(
1307 inner_ops,
1308 vec![Op::Const, Op::Dup, Op::StoreLocal, Op::Return]
1309 );
1310 }
1311
1312 #[test]
1313 fn test_compile_set_global() {
1314 let result = compile_str("(set! x 42)");
1315 let ops = extract_ops(&result.chunk);
1316 assert_eq!(ops, vec![Op::Const, Op::Dup, Op::StoreGlobal, Op::Return]);
1318 }
1319
1320 #[test]
1321 fn test_compile_set_upvalue() {
1322 let result = compile_str("(lambda (x) (lambda () (set! x 1)))");
1324 assert_eq!(result.functions.len(), 2);
1325 let inner_ops = extract_ops(&result.functions[1].chunk);
1326 assert_eq!(
1328 inner_ops,
1329 vec![Op::Const, Op::Dup, Op::StoreUpvalue, Op::Return]
1330 );
1331 }
1332
1333 #[test]
1336 fn test_compile_and_empty() {
1337 let result = compile_str("(and)");
1338 let ops = extract_ops(&result.chunk);
1339 assert_eq!(ops, vec![Op::True, Op::Return]);
1340 }
1341
1342 #[test]
1343 fn test_compile_or_empty() {
1344 let result = compile_str("(or)");
1345 let ops = extract_ops(&result.chunk);
1346 assert_eq!(ops, vec![Op::False, Op::Return]);
1347 }
1348
1349 #[test]
1350 fn test_compile_and_short_circuit() {
1351 let result = compile_str("(and 1 2)");
1352 let ops = extract_ops(&result.chunk);
1353 assert_eq!(
1355 ops,
1356 vec![
1357 Op::Const,
1358 Op::Dup,
1359 Op::JumpIfFalse,
1360 Op::Pop,
1361 Op::Const,
1362 Op::Jump,
1363 Op::Return
1364 ]
1365 );
1366 }
1367
1368 #[test]
1369 fn test_compile_or_short_circuit() {
1370 let result = compile_str("(or 1 2)");
1371 let ops = extract_ops(&result.chunk);
1372 assert_eq!(
1374 ops,
1375 vec![
1376 Op::Const,
1377 Op::Dup,
1378 Op::JumpIfTrue,
1379 Op::Pop,
1380 Op::Const,
1381 Op::Jump,
1382 Op::Return
1383 ]
1384 );
1385 }
1386
1387 #[test]
1390 fn test_compile_vector_literal() {
1391 let result = compile_str("[1 2 3]");
1392 let ops = extract_ops(&result.chunk);
1393 assert_eq!(
1394 ops,
1395 vec![Op::Const, Op::Const, Op::Const, Op::MakeVector, Op::Return]
1396 );
1397 }
1398
1399 #[test]
1400 fn test_compile_quote() {
1401 let result = compile_str("'(1 2 3)");
1402 let ops = extract_ops(&result.chunk);
1403 assert_eq!(ops, vec![Op::Const, Op::Return]);
1404 }
1405
1406 #[test]
1409 fn test_compile_throw() {
1410 let result = compile_str("(throw 42)");
1411 let ops = extract_ops(&result.chunk);
1412 assert_eq!(ops, vec![Op::Const, Op::Throw, Op::Return]);
1413 }
1414
1415 #[test]
1416 fn test_compile_try_catch() {
1417 let result = compile_str("(lambda () (try (/ 1 0) (catch e e)))");
1418 let func = &result.functions[0];
1419 assert_eq!(func.chunk.exception_table.len(), 1);
1421 let entry = &func.chunk.exception_table[0];
1422 assert!(entry.try_start < entry.try_end);
1423 assert!(entry.handler_pc > entry.try_end);
1424 assert!((entry.handler_pc as usize) < func.chunk.code.len());
1425 let ops = extract_ops(&func.chunk);
1427 assert!(ops.contains(&Op::StoreLocal)); assert!(ops.contains(&Op::Jump));
1430 }
1431
1432 #[test]
1435 fn test_compile_closure_with_upvalue() {
1436 let result = compile_str("(lambda (x) (lambda () x))");
1437 assert_eq!(result.functions.len(), 2);
1438 let outer = &result.functions[0];
1440 let outer_ops = extract_ops(&outer.chunk);
1441 assert!(outer_ops.contains(&Op::MakeClosure));
1442 let inner = &result.functions[1];
1444 let inner_ops = extract_ops(&inner.chunk);
1445 assert_eq!(inner_ops, vec![Op::LoadUpvalue, Op::Return]);
1446 assert_eq!(inner.upvalue_descs.len(), 1);
1448 assert!(matches!(
1449 inner.upvalue_descs[0],
1450 UpvalueDesc::ParentLocal(0)
1451 ));
1452 }
1453
1454 #[test]
1455 fn test_compile_nested_lambda_func_ids() {
1456 let result = compile_str("(lambda () (lambda () 1) (lambda () 2))");
1459 assert_eq!(result.functions.len(), 3);
1460 let f1 = &result.functions[1];
1462 let f1_ops = extract_ops(&f1.chunk);
1463 assert_eq!(f1_ops, vec![Op::Const, Op::Return]);
1464 assert_eq!(f1.chunk.consts[0], Value::int(1));
1465
1466 let f2 = &result.functions[2];
1467 let f2_ops = extract_ops(&f2.chunk);
1468 assert_eq!(f2_ops, vec![Op::Const, Op::Return]);
1469 assert_eq!(f2.chunk.consts[0], Value::int(2));
1470
1471 let outer = &result.functions[0];
1474 let outer_ops = extract_ops(&outer.chunk);
1475 let mc_count = outer_ops
1476 .iter()
1477 .filter(|&&op| op == Op::MakeClosure)
1478 .count();
1479 assert_eq!(mc_count, 2);
1480 }
1481
1482 #[test]
1485 fn test_compile_do_loop() {
1486 let result = compile_str("(lambda () (do ((i 0 (+ i 1))) ((= i 10) i) (display i)))");
1487 let func = &result.functions[0];
1488 let ops = extract_ops(&func.chunk);
1489 let jump_pcs: Vec<usize> = (0..func.chunk.code.len())
1491 .filter(|&pc| func.chunk.code[pc] == Op::Jump as u8)
1492 .collect();
1493 let has_back_edge = jump_pcs
1495 .iter()
1496 .any(|&pc| read_jump_offset(&func.chunk, pc) < 0);
1497 assert!(has_back_edge, "do loop must have a backward jump");
1498 assert!(ops.contains(&Op::JumpIfTrue));
1500 }
1501
1502 #[test]
1505 fn test_compile_named_let() {
1506 let result = compile_str("(lambda () (let loop ((n 10)) (if (= n 0) n (loop (- n 1)))))");
1508 assert!(result.functions.len() >= 2);
1510 let outer = &result.functions[0];
1512 let outer_ops = extract_ops(&outer.chunk);
1513 assert!(outer_ops.contains(&Op::MakeClosure));
1514 assert!(outer_ops.contains(&Op::TailCall) || outer_ops.contains(&Op::Call));
1515 }
1516
1517 #[test]
1520 fn test_compile_many_empty() {
1521 let result = compile_many(&[]).unwrap();
1522 let ops = extract_ops(&result.chunk);
1523 assert_eq!(ops, vec![Op::Nil, Op::Return]);
1524 }
1525
1526 #[test]
1527 fn test_compile_many_multiple() {
1528 let result = compile_many_str("1 2 3");
1529 let ops = extract_ops(&result.chunk);
1530 assert_eq!(
1532 ops,
1533 vec![
1534 Op::Const,
1535 Op::Pop,
1536 Op::Const,
1537 Op::Pop,
1538 Op::Const,
1539 Op::Return
1540 ]
1541 );
1542 }
1543
1544 #[test]
1545 fn test_compile_many_single() {
1546 let result = compile_many_str("42");
1547 let ops = extract_ops(&result.chunk);
1548 assert_eq!(ops, vec![Op::Const, Op::Return]);
1550 }
1551
1552 #[test]
1555 fn test_calling_convention_runtime_call() {
1556 let result = compile_str("(eval 42)");
1558 let ops = extract_ops(&result.chunk);
1559 assert_eq!(ops, vec![Op::LoadGlobal, Op::Const, Op::Call, Op::Return]);
1560 assert_eq!(ops[0], Op::LoadGlobal);
1562 }
1563
1564 #[test]
1567 fn test_compile_map_literal() {
1568 let result = compile_str("{:a 1 :b 2}");
1569 let ops = extract_ops(&result.chunk);
1570 assert_eq!(
1572 ops,
1573 vec![
1574 Op::Const,
1575 Op::Const,
1576 Op::Const,
1577 Op::Const,
1578 Op::MakeMap,
1579 Op::Return
1580 ]
1581 );
1582 }
1583}