1use crate::scheme::arena::{Arena, ProcedureData, ValueData, ValueId, NIL_ID, TRUE_ID, FALSE_ID};
22use crate::scheme::instruction::Instruction;
23use std::collections::HashMap;
24
25#[derive(Debug, Clone)]
27struct Frame {
28 return_ip: usize,
30 frame_pointer: usize,
32 display: Vec<Vec<ValueId>>,
34}
35
36pub struct VM<'a> {
38 stack: Vec<ValueId>,
40 frames: Vec<Frame>,
42 arena: &'a mut Arena,
44 globals: HashMap<String, ValueId>,
46 primitive_names: std::collections::HashSet<String>,
48}
49
50impl<'a> VM<'a> {
51 pub fn new(arena: &'a mut Arena) -> Self {
53 VM {
54 stack: Vec::with_capacity(1024),
55 frames: Vec::with_capacity(256),
56 arena,
57 globals: HashMap::new(),
58 primitive_names: std::collections::HashSet::new(),
59 }
60 }
61
62 pub fn with_primitives(arena: &'a mut Arena) -> Self {
64 let mut vm = Self::new(arena);
65 vm.register_primitives();
66 vm
67 }
68
69 pub fn register_primitives(&mut self) {
71 use crate::scheme::primitives;
72
73 self.register_primitive_immut("car", primitives::car);
75 self.register_primitive_immut("cdr", primitives::cdr);
76 self.register_primitive("cons", primitives::cons);
77 self.register_primitive_immut("null?", primitives::null);
78 self.register_primitive("list", primitives::list);
79 self.register_primitive("length", primitives::length);
80 self.register_primitive("reverse", primitives::reverse);
81 self.register_primitive("append", primitives::append);
82 self.register_primitive_immut("list?", primitives::list_p);
83 self.register_primitive_immut("pair?", primitives::pair_p);
84 self.register_primitive_immut("list-ref", primitives::list_ref);
85 self.register_primitive_immut("list-tail", primitives::list_tail);
86
87 self.register_primitive_immut("cadr", primitives::cadr);
89 self.register_primitive_immut("caddr", primitives::caddr);
90 self.register_primitive_immut("cadddr", primitives::cadddr);
91 self.register_primitive_immut("caar", primitives::caar);
92 self.register_primitive_immut("cdar", primitives::cdar);
93 self.register_primitive_immut("cddr", primitives::cddr);
94 self.register_primitive_immut("caaar", primitives::caaar);
95 self.register_primitive_immut("caadr", primitives::caadr);
96 self.register_primitive_immut("cadar", primitives::cadar);
97 self.register_primitive_immut("cdaar", primitives::cdaar);
98 self.register_primitive_immut("cdadr", primitives::cdadr);
99 self.register_primitive_immut("cddar", primitives::cddar);
100 self.register_primitive_immut("cdddr", primitives::cdddr);
101
102 self.register_primitive_immut("memq", primitives::memq);
104 self.register_primitive_immut("memv", primitives::memv);
105 self.register_primitive_immut("member", primitives::member);
106 self.register_primitive_immut("assq", primitives::assq);
107 self.register_primitive_immut("assv", primitives::assv);
108 self.register_primitive_immut("assoc", primitives::assoc);
109 self.register_primitive_immut("last", primitives::last);
110 self.register_primitive_immut("last-pair", primitives::last_pair);
111
112 self.register_primitive("list-copy", primitives::list_copy);
114 self.register_primitive("append!", primitives::append_bang);
115 self.register_primitive("reverse!", primitives::reverse_bang);
116 self.register_primitive("iota", primitives::iota);
117 self.register_primitive("take", primitives::take);
118 self.register_primitive_immut("drop", primitives::drop);
119 self.register_primitive("split-at", primitives::split_at);
120 self.register_primitive_immut("filter", primitives::filter);
121 self.register_primitive_immut("remove", primitives::remove);
122 self.register_primitive_immut("list?", primitives::list_p_improved);
123 self.register_primitive_immut("null-list?", primitives::null_list_p);
124 self.register_primitive_immut("improper-list?", primitives::improper_list_p);
125 self.register_primitive_immut("circular-list?", primitives::circular_list_p);
126
127 self.register_primitive("set-car!", primitives::set_car);
129 self.register_primitive("set-cdr!", primitives::set_cdr);
130
131 self.register_primitive("+", primitives::add);
133 self.register_primitive("-", primitives::subtract);
134 self.register_primitive("*", primitives::multiply);
135 self.register_primitive("/", primitives::divide);
136 self.register_primitive("quotient", primitives::quotient);
137 self.register_primitive("remainder", primitives::remainder);
138 self.register_primitive("modulo", primitives::modulo);
139 self.register_primitive("abs", primitives::abs);
140 self.register_primitive("min", primitives::min);
141 self.register_primitive("max", primitives::max);
142 self.register_primitive("gcd", primitives::gcd);
143 self.register_primitive("lcm", primitives::lcm);
144
145 self.register_primitive_immut("=", primitives::num_eq);
147 self.register_primitive_immut("<", primitives::num_lt);
148 self.register_primitive_immut(">", primitives::num_gt);
149 self.register_primitive_immut("<=", primitives::num_le);
150 self.register_primitive_immut(">=", primitives::num_ge);
151
152 self.register_primitive_immut("zero?", primitives::zero_p);
154 self.register_primitive_immut("positive?", primitives::positive_p);
155 self.register_primitive_immut("negative?", primitives::negative_p);
156 self.register_primitive_immut("odd?", primitives::odd_p);
157 self.register_primitive_immut("even?", primitives::even_p);
158 self.register_primitive_immut("exact?", primitives::exact_p);
159 self.register_primitive_immut("inexact?", primitives::inexact_p);
160
161 self.register_primitive("floor", primitives::floor);
163 self.register_primitive("ceiling", primitives::ceiling);
164 self.register_primitive("truncate", primitives::truncate);
165 self.register_primitive("round", primitives::round);
166 self.register_primitive("sqrt", primitives::sqrt);
167 self.register_primitive("sin", primitives::sin);
168 self.register_primitive("cos", primitives::cos);
169 self.register_primitive("tan", primitives::tan);
170 self.register_primitive("asin", primitives::asin);
171 self.register_primitive("acos", primitives::acos);
172 self.register_primitive("atan", primitives::atan);
173 self.register_primitive("exp", primitives::exp);
174 self.register_primitive("log", primitives::log);
175 self.register_primitive("expt", primitives::expt);
176
177 self.register_primitive("exact->inexact", primitives::exact_to_inexact);
179 self.register_primitive("inexact->exact", primitives::inexact_to_exact);
180 self.register_primitive("numerator", primitives::numerator);
181 self.register_primitive("denominator", primitives::denominator);
182 self.register_primitive_immut("rationalize", primitives::rationalize);
183 self.register_primitive("angle", primitives::angle);
184 self.register_primitive("magnitude", primitives::magnitude);
185
186 self.register_primitive_immut("number?", primitives::number_p);
188 self.register_primitive_immut("integer?", primitives::integer_p);
189 self.register_primitive_immut("real?", primitives::real_p);
190 self.register_primitive_immut("string?", primitives::string_p);
191 self.register_primitive_immut("symbol?", primitives::symbol_p);
192 self.register_primitive_immut("char?", primitives::char_p);
193 self.register_primitive_immut("boolean?", primitives::boolean_p);
194 self.register_primitive_immut("vector?", primitives::vector_p);
195 self.register_primitive_immut("procedure?", primitives::procedure_p);
196
197 self.register_primitive_immut("equal?", primitives::equal);
199 self.register_primitive_immut("eqv?", primitives::eqv_p);
200 self.register_primitive_immut("eq?", primitives::eq_p);
201 self.register_primitive_immut("not", primitives::not);
202
203 self.register_primitive("string-length", primitives::string_length);
205 self.register_primitive("string-ref", primitives::string_ref);
206 self.register_primitive("substring", primitives::substring);
207 self.register_primitive("string-append", primitives::string_append);
208 self.register_primitive_immut("string=?", primitives::string_eq);
209 self.register_primitive_immut("string<?", primitives::string_lt);
210 self.register_primitive_immut("string>?", primitives::string_gt);
211 self.register_primitive_immut("string<=?", primitives::string_le);
212 self.register_primitive_immut("string>=?", primitives::string_ge);
213 self.register_primitive_immut("string-ci=?", primitives::string_ci_eq);
214 self.register_primitive_immut("string-ci<?", primitives::string_ci_lt);
215 self.register_primitive_immut("string-ci>?", primitives::string_ci_gt);
216 self.register_primitive_immut("string-ci<=?", primitives::string_ci_le);
217 self.register_primitive_immut("string-ci>=?", primitives::string_ci_ge);
218 self.register_primitive("string-upcase", primitives::string_upcase);
219 self.register_primitive("string-downcase", primitives::string_downcase);
220 self.register_primitive("case-fold-down", primitives::case_fold_down);
221 self.register_primitive("string-index", primitives::string_index);
222 self.register_primitive("make-string", primitives::make_string);
223 self.register_primitive("string", primitives::string);
224 self.register_primitive("string-set!", primitives::string_set);
225 self.register_primitive("string-copy", primitives::string_copy);
226 self.register_primitive("string-fill!", primitives::string_fill);
227
228 self.register_primitive("string->number", primitives::string_to_number);
230 self.register_primitive("number->string", primitives::number_to_string);
231 self.register_primitive("string->list", primitives::string_to_list);
232 self.register_primitive("list->string", primitives::list_to_string);
233 self.register_primitive("string->number", primitives::string_to_number_radix);
234 self.register_primitive("number->string", primitives::number_to_string_radix);
235
236 self.register_primitive_immut("char=?", primitives::char_eq);
238 self.register_primitive_immut("char<?", primitives::char_lt);
239 self.register_primitive_immut("char>?", primitives::char_gt);
240 self.register_primitive_immut("char<=?", primitives::char_le);
241 self.register_primitive_immut("char>=?", primitives::char_ge);
242 self.register_primitive_immut("char-ci=?", primitives::char_ci_eq);
243 self.register_primitive_immut("char-ci<?", primitives::char_ci_lt);
244 self.register_primitive_immut("char-ci>?", primitives::char_ci_gt);
245 self.register_primitive_immut("char-ci<=?", primitives::char_ci_le);
246 self.register_primitive_immut("char-ci>=?", primitives::char_ci_ge);
247 self.register_primitive("char-upcase", primitives::char_upcase);
248 self.register_primitive("char-downcase", primitives::char_downcase);
249 self.register_primitive_immut("char-alphabetic?", primitives::char_alphabetic_p);
250 self.register_primitive_immut("char-numeric?", primitives::char_numeric_p);
251 self.register_primitive_immut("char-whitespace?", primitives::char_whitespace_p);
252 self.register_primitive_immut("char-lower-case?", primitives::char_lower_case_p);
253 self.register_primitive_immut("char-upper-case?", primitives::char_upper_case_p);
254 self.register_primitive("char->integer", primitives::char_to_integer);
255 self.register_primitive("integer->char", primitives::integer_to_char);
256 self.register_primitive("char-property", primitives::char_property);
257 self.register_primitive("char-script-case", primitives::char_script_case);
258
259 self.register_primitive("symbol->string", primitives::symbol_to_string);
261 self.register_primitive("string->symbol", primitives::string_to_symbol);
262 self.register_primitive_immut("keyword?", primitives::keyword_p);
263 self.register_primitive("keyword->string", primitives::keyword_to_string);
264 self.register_primitive("string->keyword", primitives::string_to_keyword);
265
266 self.register_primitive("vector", primitives::vector);
268 self.register_primitive("make-vector", primitives::make_vector);
269 self.register_primitive("vector-length", primitives::vector_length);
270 self.register_primitive_immut("vector-ref", primitives::vector_ref);
271 self.register_primitive("vector-set!", primitives::vector_set);
272 self.register_primitive("vector->list", primitives::vector_to_list);
273 self.register_primitive("list->vector", primitives::list_to_vector);
274 self.register_primitive("vector-fill!", primitives::vector_fill);
275
276 self.register_primitive("bitwise-and", primitives::bitwise_and);
278 self.register_primitive("bitwise-ior", primitives::bitwise_ior);
279 self.register_primitive("bitwise-xor", primitives::bitwise_xor);
280 self.register_primitive("bitwise-not", primitives::bitwise_not);
281 self.register_primitive("arithmetic-shift", primitives::arithmetic_shift);
282 self.register_primitive("bit-extract", primitives::bit_extract);
283 self.register_primitive_immut("bitwise-bit-set?", primitives::bitwise_bit_set_p);
284 self.register_primitive("bitwise-bit-count", primitives::bitwise_bit_count);
285
286 self.register_primitive_immut("display", primitives::display);
288 self.register_primitive_immut("newline", primitives::newline);
289 self.register_primitive_immut("write", primitives::write);
290 self.register_primitive_immut("write-char", primitives::write_char);
291 self.register_primitive_immut("read-char", primitives::read_char);
292 self.register_primitive_immut("eof-object?", primitives::eof_object_p);
293
294 self.register_primitive("format-number", primitives::format_number);
296 self.register_primitive("format-number-list", primitives::format_number_list);
297
298 self.register_primitive("empty-sosofo", primitives::empty_sosofo);
300 self.register_primitive("sosofo-append", primitives::sosofo_append);
301 self.register_primitive("if-first-page", primitives::if_first_page);
302 self.register_primitive("if-front-page", primitives::if_front_page);
303 self.register_primitive_immut("sosofo?", primitives::sosofo_p);
304
305 self.register_primitive("current-node", primitives::current_node);
307 self.register_primitive("gi", primitives::gi);
308 self.register_primitive("data", primitives::data);
309 self.register_primitive("id", primitives::id);
310 self.register_primitive("children", primitives::children);
311 self.register_primitive("parent", primitives::parent);
312 self.register_primitive("attributes", primitives::attributes);
313 self.register_primitive("ancestor", primitives::ancestor);
314 self.register_primitive("ancestors", primitives::ancestors);
315 self.register_primitive("descendants", primitives::descendants);
316 self.register_primitive("follow", primitives::follow);
317 self.register_primitive("preced", primitives::preced);
318 self.register_primitive("ipreced", primitives::ipreced);
319 self.register_primitive("document-element", primitives::document_element);
320
321 self.register_primitive_immut("node-list?", primitives::node_list_p);
323 self.register_primitive("empty-node-list", primitives::empty_node_list);
324 self.register_primitive_immut("node-list-empty?", primitives::node_list_empty_p);
325 self.register_primitive("node-list-length", primitives::node_list_length);
326 self.register_primitive("node-list-first", primitives::node_list_first);
327 self.register_primitive("node-list-rest", primitives::node_list_rest);
328 self.register_primitive("node-list-ref", primitives::node_list_ref);
329 self.register_primitive("node-list-last", primitives::node_list_last);
330 self.register_primitive("node-list-reverse", primitives::node_list_reverse);
331 self.register_primitive("node-list-union", primitives::node_list_union);
332 self.register_primitive("node-list-intersection", primitives::node_list_intersection);
333 self.register_primitive("node-list-difference", primitives::node_list_difference);
334 self.register_primitive("node-list-remove-duplicates", primitives::node_list_remove_duplicates);
335 self.register_primitive("node-list->list", primitives::node_list_to_list);
336 self.register_primitive("node-list-contains?", primitives::node_list_contains_p);
337 self.register_primitive("node-list-map", primitives::node_list_map);
338
339 self.register_primitive_immut("node?", primitives::node_p);
341 self.register_primitive("first-sibling?", primitives::first_sibling_p);
342 self.register_primitive("last-sibling?", primitives::last_sibling_p);
343 self.register_primitive("absolute-first-sibling?", primitives::absolute_first_sibling_p);
344 self.register_primitive("absolute-last-sibling?", primitives::absolute_last_sibling_p);
345 self.register_primitive("have-ancestor?", primitives::have_ancestor_p);
346 self.register_primitive("match-element?", primitives::match_element_p);
347
348 self.register_primitive("attribute-string", primitives::attribute_string);
350 self.register_primitive("node-property", primitives::node_property);
351 self.register_primitive("select-elements", primitives::select_elements);
352 self.register_primitive("element-with-id", primitives::element_with_id);
353 self.register_primitive("child-number", primitives::child_number);
354 self.register_primitive("element-number", primitives::element_number);
355 self.register_primitive("hierarchical-number", primitives::hierarchical_number);
356 self.register_primitive("hierarchical-number-recursive", primitives::hierarchical_number_recursive);
357
358 self.register_primitive("entity-system-id", primitives::entity_system_id);
360 self.register_primitive("entity-public-id", primitives::entity_public_id);
361 self.register_primitive("entity-type", primitives::entity_type);
362 self.register_primitive("notation-system-id", primitives::notation_system_id);
363 self.register_primitive("notation-public-id", primitives::notation_public_id);
364
365 self.register_primitive_immut("quantity?", primitives::quantity_p);
367 self.register_primitive_immut("color?", primitives::color_p);
368 self.register_primitive("color", primitives::color);
369 self.register_primitive_immut("display-space?", primitives::display_space_p);
370 self.register_primitive_immut("inline-space?", primitives::inline_space_p);
371 self.register_primitive("quantity->number", primitives::quantity_to_number);
372 self.register_primitive("number->quantity", primitives::number_to_quantity);
373 self.register_primitive("quantity-convert", primitives::quantity_convert);
374 self.register_primitive("device-length", primitives::device_length);
375 self.register_primitive("label-distance", primitives::label_distance);
376 self.register_primitive_immut("address?", primitives::address_p);
377 self.register_primitive_immut("address-local?", primitives::address_local_p);
378 self.register_primitive_immut("address-visited?", primitives::address_visited_p);
379 self.register_primitive_immut("color-space?", primitives::color_space_p);
380 self.register_primitive_immut("color-space", primitives::color_space);
381 self.register_primitive("display-space", primitives::display_space);
382 self.register_primitive("inline-space", primitives::inline_space);
383 self.register_primitive_immut("glyph-id?", primitives::glyph_id_p);
384 self.register_primitive_immut("glyph-id", primitives::glyph_id);
385
386 self.register_primitive_immut("current-language", primitives::current_language);
388 self.register_primitive_immut("current-mode", primitives::current_mode);
389 self.register_primitive_immut("current-node-address", primitives::current_node_address);
390 self.register_primitive("current-node-page-number-sosofo", primitives::current_node_page_number_sosofo);
391 self.register_primitive_immut("debug", primitives::debug);
392 self.register_primitive("error", primitives::error);
393 }
394
395 fn register_primitive(
397 &mut self,
398 name: &'static str,
399 func: fn(&mut Arena, &[ValueId]) -> Result<ValueId, String>,
400 ) {
401 let proc = ProcedureData::Primitive { name, func };
402 let proc_id = self.arena.alloc(ValueData::Procedure(proc));
403 self.globals.insert(name.to_string(), proc_id);
404 self.primitive_names.insert(name.to_string());
405 }
406
407 fn register_primitive_immut(
410 &mut self,
411 name: &'static str,
412 immut_func: fn(&Arena, &[ValueId]) -> Result<ValueId, String>,
413 ) {
414 let wrapper: fn(&mut Arena, &[ValueId]) -> Result<ValueId, String> = unsafe {
418 std::mem::transmute(immut_func)
419 };
420
421 let proc = ProcedureData::Primitive { name, func: wrapper };
422 let proc_id = self.arena.alloc(ValueData::Procedure(proc));
423 self.globals.insert(name.to_string(), proc_id);
424 self.primitive_names.insert(name.to_string());
425 }
426
427 pub fn define_global(&mut self, name: String, value_id: ValueId) {
429 self.globals.insert(name, value_id);
430 }
431
432 pub fn lookup_global(&self, name: &str) -> Option<ValueId> {
434 self.globals.get(name).copied()
435 }
436
437 pub fn get_globals(&self) -> HashMap<String, ValueId> {
439 self.globals.clone()
440 }
441
442 pub fn set_globals(&mut self, globals: HashMap<String, ValueId>) {
444 self.globals = globals;
445 }
446
447 pub fn extend_globals(&mut self, additional: HashMap<String, ValueId>) {
449 for (name, value_id) in additional {
450 self.globals.insert(name, value_id);
451 }
452 }
453
454 pub fn get_user_globals(&self) -> HashMap<String, ValueId> {
456 self.globals
457 .iter()
458 .filter(|(name, _)| !self.primitive_names.contains(*name))
459 .map(|(name, value_id)| (name.clone(), *value_id))
460 .collect()
461 }
462
463 pub fn run(&mut self, instructions: &[Instruction], start_ip: usize) -> Result<ValueId, String> {
465 let mut ip = start_ip;
466
467 loop {
469 if ip >= instructions.len() {
470 return Err(format!("Instruction pointer {} out of bounds", ip));
471 }
472
473 match &instructions[ip] {
474 Instruction::Constant { value_id } => {
475 self.stack.push(*value_id);
476 ip += 1;
477 }
478
479 Instruction::Variable { depth, offset } => {
480 if let Some(frame) = self.frames.last() {
482 if *depth < frame.display.len() {
483 if *offset < frame.display[*depth].len() {
484 let value_id = frame.display[*depth][*offset];
485 self.stack.push(value_id);
486 ip += 1;
487 continue;
488 }
489 }
490 }
491 return Err(format!("Variable not found at depth {} offset {}", depth, offset));
492 }
493
494 Instruction::GlobalVariable { name } => {
495 if let Some(value_id) = self.lookup_global(name) {
496 self.stack.push(value_id);
497 ip += 1;
498 } else {
499 return Err(format!("Undefined variable: {} (globals: {:?})", name, self.globals.keys().collect::<Vec<_>>()));
500 }
501 }
502
503 Instruction::Apply { n_args } => {
504 if self.stack.len() < n_args + 1 {
506 return Err("Stack underflow in Apply".to_string());
507 }
508
509 let proc_id = self.stack.pop().unwrap();
511
512 let args_start = self.stack.len() - n_args;
514 let args: Vec<ValueId> = self.stack.drain(args_start..).collect();
515
516 let proc_data = self.arena.get(proc_id);
518
519 match proc_data {
520 ValueData::Procedure(ProcedureData::Primitive { name: _, func }) => {
521 let result = func(self.arena, &args)?;
523 self.stack.push(result);
524 ip += 1;
525 }
526 ValueData::Procedure(ProcedureData::CompiledLambda {
527 params,
528 required_count,
529 optional_defaults,
530 body_ip,
531 env,
532 ..
533 }) => {
534 if args.len() < *required_count {
536 return Err(format!(
537 "Lambda: expected at least {} arguments, got {}",
538 required_count,
539 args.len()
540 ));
541 }
542
543 let mut display = Vec::new();
545
546 let mut frame_values = args;
548
549 for i in frame_values.len()..params.len() {
551 if i - required_count < optional_defaults.len() {
552 frame_values.push(optional_defaults[i - required_count]);
553 } else {
554 frame_values.push(NIL_ID);
555 }
556 }
557
558 display.push(frame_values);
559
560 if *env != NIL_ID {
562 let env_data = self.arena.get(*env);
563 match env_data {
564 ValueData::Vector(free_vars) => {
565 display.push(free_vars.clone());
567 }
568 _ => {}
569 }
570 }
571
572 self.frames.push(Frame {
574 return_ip: ip + 1,
575 frame_pointer: self.stack.len(),
576 display,
577 });
578
579 ip = *body_ip;
581 }
582 ValueData::Procedure(ProcedureData::Lambda { .. }) => {
583 return Err("Interpreted lambda not supported in VM (must be compiled first)".to_string());
584 }
585 _ => return Err("Apply: not a procedure".to_string()),
586 }
587 }
588
589 Instruction::Test { else_ip } => {
590 let test_id = self.stack.pop().ok_or("Stack underflow in Test")?;
591 let test_data = self.arena.get(test_id);
592
593 if matches!(test_data, ValueData::Bool(false)) {
595 ip = *else_ip;
596 } else {
597 ip += 1;
598 }
599 }
600
601 Instruction::Jump { target_ip } => {
602 ip = *target_ip;
603 }
604
605 Instruction::MakeClosure {
606 params,
607 required_count,
608 body_ip,
609 n_free,
610 } => {
611 let mut free_vars = Vec::new();
613 for _ in 0..*n_free {
614 if let Some(var_id) = self.stack.pop() {
615 free_vars.push(var_id);
616 } else {
617 return Err("Stack underflow in MakeClosure".to_string());
618 }
619 }
620 free_vars.reverse();
622
623 let env_id = if free_vars.is_empty() {
625 NIL_ID
626 } else {
627 self.arena.vector(free_vars)
628 };
629
630 let lambda = ProcedureData::CompiledLambda {
631 params: params.clone(),
632 required_count: *required_count,
633 optional_defaults: vec![],
634 body_ip: *body_ip,
635 env: env_id,
636 source: None,
637 name: None,
638 };
639
640 let closure_id = self.arena.alloc(ValueData::Procedure(lambda));
641 self.stack.push(closure_id);
642 ip += 1;
643 }
644
645 Instruction::Return => {
646 let result_id = self.stack.pop().ok_or("Stack underflow in Return")?;
648
649 if let Some(frame) = self.frames.pop() {
651 self.stack.truncate(frame.frame_pointer);
653 self.stack.push(result_id);
654 ip = frame.return_ip;
655 } else {
656 return Ok(result_id);
658 }
659 }
660
661 Instruction::Cons => {
663 let cdr_id = self.stack.pop().ok_or("Stack underflow in Cons")?;
664 let car_id = self.stack.pop().ok_or("Stack underflow in Cons")?;
665 let pair_id = self.arena.cons(car_id, cdr_id);
666 self.stack.push(pair_id);
667 ip += 1;
668 }
669
670 Instruction::Car => {
671 let pair_id = self.stack.pop().ok_or("Stack underflow in Car")?;
672 let pair_data = self.arena.get(pair_id);
673 match pair_data {
674 ValueData::Pair { car, .. } => {
675 self.stack.push(*car);
676 ip += 1;
677 }
678 _ => return Err("car: not a pair".to_string()),
679 }
680 }
681
682 Instruction::Cdr => {
683 let pair_id = self.stack.pop().ok_or("Stack underflow in Cdr")?;
684 let pair_data = self.arena.get(pair_id);
685 match pair_data {
686 ValueData::Pair { cdr, .. } => {
687 self.stack.push(*cdr);
688 ip += 1;
689 }
690 _ => return Err("cdr: not a pair".to_string()),
691 }
692 }
693
694 Instruction::IsNull => {
695 let value_id = self.stack.pop().ok_or("Stack underflow in IsNull")?;
696 let value_data = self.arena.get(value_id);
697 let result = matches!(value_data, ValueData::Nil);
698 self.stack.push(if result { TRUE_ID } else { FALSE_ID });
699 ip += 1;
700 }
701
702 Instruction::Add => {
703 let b_id = self.stack.pop().ok_or("Stack underflow in Add")?;
704 let a_id = self.stack.pop().ok_or("Stack underflow in Add")?;
705 let a = self.arena.get(a_id);
706 let b = self.arena.get(b_id);
707
708 let result = match (a, b) {
709 (ValueData::Integer(x), ValueData::Integer(y)) => {
710 self.arena.int(x + y)
711 }
712 (ValueData::Real(x), ValueData::Real(y)) => {
713 self.arena.real(x + y)
714 }
715 (ValueData::Integer(x), ValueData::Real(y)) => {
716 self.arena.real(*x as f64 + y)
717 }
718 (ValueData::Real(x), ValueData::Integer(y)) => {
719 self.arena.real(x + *y as f64)
720 }
721 _ => return Err("+: expected numbers".to_string()),
722 };
723 self.stack.push(result);
724 ip += 1;
725 }
726
727 Instruction::Subtract => {
728 let b_id = self.stack.pop().ok_or("Stack underflow in Subtract")?;
729 let a_id = self.stack.pop().ok_or("Stack underflow in Subtract")?;
730 let a = self.arena.get(a_id);
731 let b = self.arena.get(b_id);
732
733 let result = match (a, b) {
734 (ValueData::Integer(x), ValueData::Integer(y)) => {
735 self.arena.int(x - y)
736 }
737 (ValueData::Real(x), ValueData::Real(y)) => {
738 self.arena.real(x - y)
739 }
740 (ValueData::Integer(x), ValueData::Real(y)) => {
741 self.arena.real(*x as f64 - y)
742 }
743 (ValueData::Real(x), ValueData::Integer(y)) => {
744 self.arena.real(x - *y as f64)
745 }
746 _ => return Err("-: expected numbers".to_string()),
747 };
748 self.stack.push(result);
749 ip += 1;
750 }
751
752 Instruction::Multiply => {
753 let b_id = self.stack.pop().ok_or("Stack underflow in Multiply")?;
754 let a_id = self.stack.pop().ok_or("Stack underflow in Multiply")?;
755 let a = self.arena.get(a_id);
756 let b = self.arena.get(b_id);
757
758 let result = match (a, b) {
759 (ValueData::Integer(x), ValueData::Integer(y)) => {
760 self.arena.int(x * y)
761 }
762 (ValueData::Real(x), ValueData::Real(y)) => {
763 self.arena.real(x * y)
764 }
765 (ValueData::Integer(x), ValueData::Real(y)) => {
766 self.arena.real(*x as f64 * y)
767 }
768 (ValueData::Real(x), ValueData::Integer(y)) => {
769 self.arena.real(x * *y as f64)
770 }
771 _ => return Err("*: expected numbers".to_string()),
772 };
773 self.stack.push(result);
774 ip += 1;
775 }
776
777 Instruction::Divide => {
778 let b_id = self.stack.pop().ok_or("Stack underflow in Divide")?;
779 let a_id = self.stack.pop().ok_or("Stack underflow in Divide")?;
780 let a = self.arena.get(a_id);
781 let b = self.arena.get(b_id);
782
783 let result = match (a, b) {
784 (ValueData::Integer(x), ValueData::Integer(y)) => {
785 if *y == 0 {
786 return Err("/: division by zero".to_string());
787 }
788 self.arena.int(x / y)
789 }
790 (ValueData::Real(x), ValueData::Real(y)) => {
791 if *y == 0.0 {
792 return Err("/: division by zero".to_string());
793 }
794 self.arena.real(x / y)
795 }
796 (ValueData::Integer(x), ValueData::Real(y)) => {
797 if *y == 0.0 {
798 return Err("/: division by zero".to_string());
799 }
800 self.arena.real(*x as f64 / y)
801 }
802 (ValueData::Real(x), ValueData::Integer(y)) => {
803 if *y == 0 {
804 return Err("/: division by zero".to_string());
805 }
806 self.arena.real(x / *y as f64)
807 }
808 _ => return Err("/: expected numbers".to_string()),
809 };
810 self.stack.push(result);
811 ip += 1;
812 }
813
814 Instruction::Equal => {
815 let b_id = self.stack.pop().ok_or("Stack underflow in Equal")?;
816 let a_id = self.stack.pop().ok_or("Stack underflow in Equal")?;
817 let result = self.values_equal(a_id, b_id);
818 self.stack.push(if result { TRUE_ID } else { FALSE_ID });
819 ip += 1;
820 }
821
822 Instruction::NumLt => {
823 let b_id = self.stack.pop().ok_or("Stack underflow in NumLt")?;
824 let a_id = self.stack.pop().ok_or("Stack underflow in NumLt")?;
825 let a = self.arena.get(a_id);
826 let b = self.arena.get(b_id);
827
828 let result = match (a, b) {
829 (ValueData::Integer(x), ValueData::Integer(y)) => x < y,
830 (ValueData::Real(x), ValueData::Real(y)) => x < y,
831 (ValueData::Integer(x), ValueData::Real(y)) => (*x as f64) < *y,
832 (ValueData::Real(x), ValueData::Integer(y)) => *x < (*y as f64),
833 _ => return Err("<: expected numbers".to_string()),
834 };
835 self.stack.push(if result { TRUE_ID } else { FALSE_ID });
836 ip += 1;
837 }
838
839 Instruction::NumGt => {
840 let b_id = self.stack.pop().ok_or("Stack underflow in NumGt")?;
841 let a_id = self.stack.pop().ok_or("Stack underflow in NumGt")?;
842 let a = self.arena.get(a_id);
843 let b = self.arena.get(b_id);
844
845 let result = match (a, b) {
846 (ValueData::Integer(x), ValueData::Integer(y)) => x > y,
847 (ValueData::Real(x), ValueData::Real(y)) => x > y,
848 (ValueData::Integer(x), ValueData::Real(y)) => (*x as f64) > *y,
849 (ValueData::Real(x), ValueData::Integer(y)) => *x > (*y as f64),
850 _ => return Err(">: expected numbers".to_string()),
851 };
852 self.stack.push(if result { TRUE_ID } else { FALSE_ID });
853 ip += 1;
854 }
855
856 Instruction::MakeList { n } => {
857 if self.stack.len() < *n {
858 return Err("Stack underflow in MakeList".to_string());
859 }
860
861 let start = self.stack.len() - n;
862 let items: Vec<ValueId> = self.stack.drain(start..).collect();
863
864 let mut list_id = NIL_ID;
865 for &item_id in items.iter().rev() {
866 list_id = self.arena.cons(item_id, list_id);
867 }
868
869 self.stack.push(list_id);
870 ip += 1;
871 }
872
873 Instruction::Pop => {
874 self.stack.pop().ok_or("Stack underflow in Pop")?;
875 ip += 1;
876 }
877
878 Instruction::Dup => {
879 let value_id = self.stack.last().copied().ok_or("Stack underflow in Dup")?;
880 self.stack.push(value_id);
881 ip += 1;
882 }
883
884 Instruction::SetVariable { depth, offset } => {
885 let value_id = self.stack.pop().ok_or("Stack underflow in SetVariable")?;
887
888 if let Some(frame) = self.frames.last_mut() {
890 if *depth < frame.display.len() {
891 if *offset < frame.display[*depth].len() {
892 frame.display[*depth][*offset] = value_id;
893 self.stack.push(value_id); ip += 1;
895 continue;
896 }
897 }
898 }
899 return Err(format!("set!: variable not found at depth {} offset {}", depth, offset));
900 }
901
902 Instruction::SetGlobalVariable { name } => {
903 let value_id = self.stack.pop().ok_or("Stack underflow in SetGlobalVariable")?;
905
906 if self.globals.contains_key(name) {
908 self.globals.insert(name.clone(), value_id);
909 self.stack.push(value_id); ip += 1;
911 } else {
912 return Err(format!("set!: undefined variable: {}", name));
913 }
914 }
915
916 Instruction::DefineGlobal { name } => {
917 let value_id = self.stack.pop().ok_or("Stack underflow in DefineGlobal")?;
919
920 if std::env::var("DAZZLE_DEBUG").is_ok() && name.starts_with('%') {
922 eprintln!("VM: Defining {} = {:?}", name, self.arena.get(value_id));
923 }
924
925 self.globals.insert(name.clone(), value_id);
927
928 use crate::scheme::arena::UNSPECIFIED_ID;
930 self.stack.push(UNSPECIFIED_ID);
931 ip += 1;
932 }
933 }
934 }
935 }
936
937 fn values_equal(&self, a_id: ValueId, b_id: ValueId) -> bool {
939 let a = self.arena.get(a_id);
940 let b = self.arena.get(b_id);
941
942 match (a, b) {
943 (ValueData::Nil, ValueData::Nil) => true,
944 (ValueData::Bool(x), ValueData::Bool(y)) => x == y,
945 (ValueData::Integer(x), ValueData::Integer(y)) => x == y,
946 (ValueData::Real(x), ValueData::Real(y)) => (x - y).abs() < f64::EPSILON,
947 (ValueData::Char(x), ValueData::Char(y)) => x == y,
948 (ValueData::String(x), ValueData::String(y)) => x == y,
949 (ValueData::Symbol(x), ValueData::Symbol(y)) => x == y,
950 (ValueData::Pair { car: car1, cdr: cdr1, .. }, ValueData::Pair { car: car2, cdr: cdr2, .. }) => {
951 self.values_equal(*car1, *car2) && self.values_equal(*cdr1, *cdr2)
952 }
953 _ => false,
954 }
955 }
956}
957
958#[cfg(test)]
959mod tests {
960 use super::*;
961 use crate::scheme::compiler::Compiler;
962 use crate::scheme::instruction::Program;
963 use std::rc::Rc;
964
965 #[test]
966 fn test_vm_constant() {
967 let mut arena = Arena::new();
968 let value_id = arena.int(42);
969
970 let mut program = Program::new();
971 program.emit(Instruction::Constant { value_id });
972 program.emit(Instruction::Return);
973
974 let mut vm = VM::new(&mut arena);
975 let result_id = vm.run(&program.instructions, 0).unwrap();
976 let result = arena.get(result_id);
977
978 assert!(matches!(result, ValueData::Integer(42)));
979 }
980
981 #[test]
982 fn test_vm_arithmetic() {
983 let mut arena = Arena::new();
984
985 let mut program = Program::new();
986
987 let a_id = arena.int(2);
989 let b_id = arena.int(3);
990
991 program.emit(Instruction::Constant { value_id: a_id });
992 program.emit(Instruction::Constant { value_id: b_id });
993 program.emit(Instruction::Add);
994 program.emit(Instruction::Return);
995
996 let mut vm = VM::new(&mut arena);
997 let result_id = vm.run(&program.instructions, 0).unwrap();
998 let result = arena.get(result_id);
999
1000 assert!(matches!(result, ValueData::Integer(5)));
1001 }
1002
1003 #[test]
1004 fn test_vm_list_ops() {
1005 let mut arena = Arena::new();
1006
1007 let mut program = Program::new();
1008
1009 let a_id = arena.int(1);
1011 let b_id = arena.int(2);
1012
1013 program.emit(Instruction::Constant { value_id: a_id });
1014 program.emit(Instruction::Constant { value_id: b_id });
1015 program.emit(Instruction::Cons);
1016 program.emit(Instruction::Car); program.emit(Instruction::Return);
1018
1019 let mut vm = VM::new(&mut arena);
1020 let result_id = vm.run(&program.instructions, 0).unwrap();
1021 let result = arena.get(result_id);
1022
1023 assert!(matches!(result, ValueData::Integer(1)));
1024 }
1025
1026 #[test]
1027 fn test_vm_with_primitive_call() {
1028 let mut arena = Arena::new();
1030 let mut program = Program::new();
1031
1032 let ten = arena.int(10);
1034 let thirty_two = arena.int(32);
1035 let arg_list = arena.cons(thirty_two, NIL_ID);
1036 let args = arena.cons(ten, arg_list);
1037 let plus = arena.symbol(Rc::from("+"));
1038 let expr = arena.cons(plus, args);
1039
1040 let mut compiler = Compiler::new(&arena);
1042 let start_ip = compiler.compile(expr).unwrap();
1043
1044 let compiled_program = compiler.into_program();
1046 program.instructions = compiled_program.instructions;
1047 program.emit(Instruction::Return); let mut vm = VM::with_primitives(&mut arena);
1051 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1052 let result = arena.get(result_id);
1053
1054 assert!(matches!(result, ValueData::Integer(42)));
1055 }
1056
1057 #[test]
1058 fn test_compile_and_run_if() {
1059 let mut arena = Arena::new();
1061 let mut program = Program::new();
1062
1063 let test = TRUE_ID;
1065 let consequent = arena.int(100);
1066 let alternative = arena.int(200);
1067
1068 let alt_list = arena.cons(alternative, NIL_ID);
1070 let cons_list = arena.cons(consequent, alt_list);
1071 let args = arena.cons(test, cons_list);
1072 let if_sym = arena.symbol(Rc::from("if"));
1073 let expr = arena.cons(if_sym, args);
1074
1075 let mut compiler = Compiler::new(&arena);
1077 let start_ip = compiler.compile(expr).unwrap();
1078 let compiled_program = compiler.into_program();
1079 program.instructions = compiled_program.instructions;
1080 program.emit(Instruction::Return); let mut vm = VM::new(&mut arena);
1084 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1085 let result = arena.get(result_id);
1086
1087 assert!(matches!(result, ValueData::Integer(100)));
1088 }
1089
1090 #[test]
1091 fn test_vm_let() {
1092 let mut arena = Arena::new();
1094 let mut program = Program::new();
1095
1096 let x_sym = arena.symbol(Rc::from("x"));
1097 let y_sym = arena.symbol(Rc::from("y"));
1098 let plus_sym = arena.symbol(Rc::from("+"));
1099 let ten = arena.int(10);
1100 let twenty = arena.int(20);
1101
1102 let x_val_list = arena.cons(ten, NIL_ID);
1104 let x_binding = arena.cons(x_sym, x_val_list);
1105
1106 let y_val_list = arena.cons(twenty, NIL_ID);
1108 let y_binding = arena.cons(y_sym, y_val_list);
1109
1110 let y_binding_list = arena.cons(y_binding, NIL_ID);
1112 let bindings = arena.cons(x_binding, y_binding_list);
1113
1114 let y_list = arena.cons(y_sym, NIL_ID);
1116 let x_list = arena.cons(x_sym, y_list);
1117 let body = arena.cons(plus_sym, x_list);
1118
1119 let body_list = arena.cons(body, NIL_ID);
1121 let args = arena.cons(bindings, body_list);
1122 let let_sym = arena.symbol(Rc::from("let"));
1123 let expr = arena.cons(let_sym, args);
1124
1125 let mut compiler = Compiler::new(&arena);
1127 let start_ip = compiler.compile(expr).unwrap();
1128 let compiled_program = compiler.into_program();
1129 program.instructions = compiled_program.instructions;
1130 program.emit(Instruction::Return);
1131
1132 let mut vm = VM::with_primitives(&mut arena);
1134 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1135 let result = arena.get(result_id);
1136
1137 assert!(matches!(result, ValueData::Integer(30)));
1138 }
1139
1140 #[test]
1141 fn test_vm_let_star() {
1142 let mut arena = Arena::new();
1145 let mut program = Program::new();
1146
1147 let x_sym = arena.symbol(Rc::from("x"));
1148 let y_sym = arena.symbol(Rc::from("y"));
1149 let plus_sym = arena.symbol(Rc::from("+"));
1150 let ten = arena.int(10);
1151 let five = arena.int(5);
1152
1153 let x_val_list = arena.cons(ten, NIL_ID);
1155 let x_binding = arena.cons(x_sym, x_val_list);
1156
1157 let five_list = arena.cons(five, NIL_ID);
1159 let x_plus_list = arena.cons(x_sym, five_list);
1160 let y_val = arena.cons(plus_sym, x_plus_list);
1161
1162 let y_val_list = arena.cons(y_val, NIL_ID);
1164 let y_binding = arena.cons(y_sym, y_val_list);
1165
1166 let y_binding_list = arena.cons(y_binding, NIL_ID);
1168 let bindings = arena.cons(x_binding, y_binding_list);
1169
1170 let body_list = arena.cons(y_sym, NIL_ID);
1172
1173 let args = arena.cons(bindings, body_list);
1175 let let_star_sym = arena.symbol(Rc::from("let*"));
1176 let expr = arena.cons(let_star_sym, args);
1177
1178 let mut compiler = Compiler::new(&arena);
1180 let start_ip = compiler.compile(expr).unwrap();
1181 let compiled_program = compiler.into_program();
1182 program.instructions = compiled_program.instructions;
1183 program.emit(Instruction::Return);
1184
1185 let mut vm = VM::with_primitives(&mut arena);
1187 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1188 let result = arena.get(result_id);
1189
1190 assert!(matches!(result, ValueData::Integer(15)));
1191 }
1192
1193 #[test]
1194 fn test_vm_cond() {
1195 let mut arena = Arena::new();
1198 let mut program = Program::new();
1199
1200 let one = arena.int(1);
1201 let forty_two = arena.int(42);
1202 let ninety_nine = arena.int(99);
1203
1204 let clause1_body = arena.cons(one, NIL_ID);
1206 let clause1 = arena.cons(FALSE_ID, clause1_body);
1207
1208 let clause2_body = arena.cons(forty_two, NIL_ID);
1210 let clause2 = arena.cons(TRUE_ID, clause2_body);
1211
1212 let else_sym = arena.symbol(Rc::from("else"));
1214 let clause3_body = arena.cons(ninety_nine, NIL_ID);
1215 let clause3 = arena.cons(else_sym, clause3_body);
1216
1217 let clause3_list = arena.cons(clause3, NIL_ID);
1219 let clause2_list = arena.cons(clause2, clause3_list);
1220 let clauses = arena.cons(clause1, clause2_list);
1221
1222 let cond_sym = arena.symbol(Rc::from("cond"));
1224 let expr = arena.cons(cond_sym, clauses);
1225
1226 let mut compiler = Compiler::new(&arena);
1228 let start_ip = compiler.compile(expr).unwrap();
1229 let compiled_program = compiler.into_program();
1230 program.instructions = compiled_program.instructions;
1231 program.emit(Instruction::Return);
1232
1233 let mut vm = VM::new(&mut arena);
1235 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1236 let result = arena.get(result_id);
1237
1238 assert!(matches!(result, ValueData::Integer(42)));
1239 }
1240
1241 #[test]
1242 fn test_vm_define_and_call() {
1243 let mut arena = Arena::new();
1246 let mut program = Program::new();
1247
1248 let x_sym = arena.symbol(Rc::from("x"));
1249 let forty_two = arena.int(42);
1250
1251 let val_list = arena.cons(forty_two, NIL_ID);
1253 let define_args = arena.cons(x_sym, val_list);
1254 let define_sym = arena.symbol(Rc::from("define"));
1255 let define_expr = arena.cons(define_sym, define_args);
1256
1257 let mut compiler = Compiler::new(&arena);
1259 let start_ip = compiler.compile(define_expr).unwrap();
1260 let compiled_program = compiler.into_program();
1261 program.instructions = compiled_program.instructions;
1262
1263 let mut compiler2 = Compiler::new(&arena);
1265 compiler2.compile(x_sym).unwrap();
1266 let compiled_program2 = compiler2.into_program();
1267 program.instructions.extend(compiled_program2.instructions);
1268 program.emit(Instruction::Return);
1269
1270 let mut vm = VM::new(&mut arena);
1272 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1273 let result = arena.get(result_id);
1274
1275 assert!(matches!(result, ValueData::Integer(42)));
1276 }
1277
1278 #[test]
1279 fn test_vm_lambda_call() {
1280 let mut arena = Arena::new();
1283 let mut program = Program::new();
1284
1285 let x_sym = arena.symbol(Rc::from("x"));
1286 let y_sym = arena.symbol(Rc::from("y"));
1287 let plus_sym = arena.symbol(Rc::from("+"));
1288 let ten = arena.int(10);
1289 let twenty = arena.int(20);
1290
1291 let y_param_list = arena.cons(y_sym, NIL_ID);
1293 let params = arena.cons(x_sym, y_param_list);
1294
1295 let y_arg_list = arena.cons(y_sym, NIL_ID);
1297 let x_arg_list = arena.cons(x_sym, y_arg_list);
1298 let body = arena.cons(plus_sym, x_arg_list);
1299
1300 let body_list = arena.cons(body, NIL_ID);
1302 let lambda_args = arena.cons(params, body_list);
1303 let lambda_sym = arena.symbol(Rc::from("lambda"));
1304 let lambda_expr = arena.cons(lambda_sym, lambda_args);
1305
1306 let twenty_list = arena.cons(twenty, NIL_ID);
1308 let args = arena.cons(ten, twenty_list);
1309
1310 let app_args = arena.cons(lambda_expr, args);
1312 let expr = app_args;
1313
1314 let mut compiler = Compiler::new(&arena);
1316 let start_ip = compiler.compile(expr).unwrap();
1317 let compiled_program = compiler.into_program();
1318 program.instructions = compiled_program.instructions;
1319 program.emit(Instruction::Return);
1320
1321 let mut vm = VM::with_primitives(&mut arena);
1323 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1324 let result = arena.get(result_id);
1325
1326 assert!(matches!(result, ValueData::Integer(30)));
1327 }
1328
1329 #[test]
1330 fn test_vm_closure_capture() {
1331 let mut arena = Arena::new();
1335 let mut program = Program::new();
1336
1337 let x_sym = arena.symbol(Rc::from("x"));
1338 let y_sym = arena.symbol(Rc::from("y"));
1339 let plus_sym = arena.symbol(Rc::from("+"));
1340 let ten = arena.int(10);
1341 let twenty = arena.int(20);
1342
1343 let y_list = arena.cons(y_sym, NIL_ID);
1345 let x_list = arena.cons(x_sym, y_list);
1346 let inner_body = arena.cons(plus_sym, x_list);
1347
1348 let y_params = arena.cons(y_sym, NIL_ID);
1350 let inner_body_list = arena.cons(inner_body, NIL_ID);
1351 let inner_lambda_args = arena.cons(y_params, inner_body_list);
1352 let lambda_sym = arena.symbol(Rc::from("lambda"));
1353 let inner_lambda = arena.cons(lambda_sym, inner_lambda_args);
1354
1355 let x_params = arena.cons(x_sym, NIL_ID);
1357 let outer_body_list = arena.cons(inner_lambda, NIL_ID);
1358 let outer_lambda_args = arena.cons(x_params, outer_body_list);
1359 let outer_lambda = arena.cons(lambda_sym, outer_lambda_args);
1360
1361 let ten_list = arena.cons(ten, NIL_ID);
1363 let app1 = arena.cons(outer_lambda, ten_list);
1364
1365 let closure_sym = arena.symbol(Rc::from("my-closure"));
1367 let twenty_list = arena.cons(twenty, NIL_ID);
1368 let app2 = arena.cons(closure_sym, twenty_list);
1369
1370 let mut compiler = Compiler::new(&arena);
1372 let start_ip = compiler.compile(app1).unwrap();
1373 let compiled_program = compiler.into_program();
1374 program.instructions = compiled_program.instructions;
1375 program.emit(Instruction::Return);
1376
1377 let mut compiler2 = Compiler::new(&arena);
1379 let start_ip2 = compiler2.compile(app2).unwrap();
1380 let compiled_program2 = compiler2.into_program();
1381
1382 let offset = program.instructions.len();
1384 program.instructions.extend(compiled_program2.instructions);
1385 program.emit(Instruction::Return);
1386
1387 let adjusted_start_ip2 = offset + start_ip2;
1389
1390 let mut vm = VM::with_primitives(&mut arena);
1392 let closure_id = vm.run(&program.instructions, start_ip).unwrap();
1393
1394 vm.define_global("my-closure".to_string(), closure_id);
1396
1397 let result_id = vm.run(&program.instructions, adjusted_start_ip2).unwrap();
1399 let result = arena.get(result_id);
1400
1401 assert!(matches!(result, ValueData::Integer(30)));
1402 }
1403
1404 #[test]
1405 fn test_vm_case_multiple_datums() {
1406 let mut arena = Arena::new();
1409 let mut program = Program::new();
1410
1411 let a_sym = arena.symbol(Rc::from("a"));
1412 let b_sym = arena.symbol(Rc::from("b"));
1413 let c_sym = arena.symbol(Rc::from("c"));
1414 let one = arena.int(1);
1415 let forty_two = arena.int(42);
1416 let ninety_nine = arena.int(99);
1417
1418 let key_list = arena.cons(b_sym, NIL_ID);
1420 let quote_sym = arena.symbol(Rc::from("quote"));
1421 let key = arena.cons(quote_sym, key_list);
1422
1423 let clause1_datums = arena.cons(a_sym, NIL_ID);
1425 let clause1_body = arena.cons(one, NIL_ID);
1426 let clause1 = arena.cons(clause1_datums, clause1_body);
1427
1428 let c_list = arena.cons(c_sym, NIL_ID);
1430 let bc_list = arena.cons(b_sym, c_list);
1431 let clause2_datums = bc_list;
1432 let clause2_body = arena.cons(forty_two, NIL_ID);
1433 let clause2 = arena.cons(clause2_datums, clause2_body);
1434
1435 let else_sym = arena.symbol(Rc::from("else"));
1437 let clause3_body = arena.cons(ninety_nine, NIL_ID);
1438 let clause3 = arena.cons(else_sym, clause3_body);
1439
1440 let clause3_list = arena.cons(clause3, NIL_ID);
1442 let clause2_list = arena.cons(clause2, clause3_list);
1443 let clauses = arena.cons(clause1, clause2_list);
1444
1445 let args = arena.cons(key, clauses);
1447 let case_sym = arena.symbol(Rc::from("case"));
1448 let expr = arena.cons(case_sym, args);
1449
1450 let mut compiler = Compiler::new(&arena);
1452 let start_ip = compiler.compile(expr).unwrap();
1453 let compiled_program = compiler.into_program();
1454 program.instructions = compiled_program.instructions;
1455 program.emit(Instruction::Return);
1456
1457 let mut vm = VM::new(&mut arena);
1459 let result_id = vm.run(&program.instructions, start_ip).unwrap();
1460 let result = arena.get(result_id);
1461
1462 assert!(matches!(result, ValueData::Integer(42)));
1463 }
1464}