swamp_script_vm_test/
util.rs1use swamp_script_code_gen::{CodeGenState, GenOptions};
2use swamp_script_compile::compile_string;
3use swamp_script_semantic::Function;
4use swamp_script_types::Type;
5use swamp_vm::Vm;
6use swamp_vm_disasm::{disasm_instructions_color, disasm_instructions_no_color};
7
8pub fn gen_internal(code: &str) -> CodeGenState {
9 let (program, main_module, source_map) = compile_string(code).unwrap();
10
11 let mut code_gen = CodeGenState::new();
12
13 let main_expression = main_module.main_expression.as_ref().unwrap();
14 let halt_function = GenOptions {
15 is_halt_function: true,
16 };
17
18 code_gen.gen_main_function(main_expression, &halt_function);
19
20 let normal_function = GenOptions {
21 is_halt_function: false,
22 };
23
24 for internal_function_def in &main_module.symbol_table.internal_functions() {
25 code_gen.gen_function_def(internal_function_def, &normal_function);
26 }
27
28 for (associated_on_type, impl_functions) in program.state.associated_impls.functions {
29 if !associated_on_type.is_concrete() {
30 continue;
31 }
32 if associated_on_type == Type::Int
33 || associated_on_type == Type::Float
34 || associated_on_type == Type::Bool
35 || associated_on_type == Type::String
36 {
37 continue;
38 }
39
40 for (_name, func) in impl_functions.functions {
41 match &*func {
42 Function::Internal(int_fn) => {
43 code_gen.gen_function_def(int_fn, &normal_function);
44 }
45
46 Function::External(_ext_fn) => {}
47 }
48 }
49 }
50
51 code_gen.finalize();
52
53 code_gen
54}
55
56pub fn gen_internal_debug(code: &str) -> CodeGenState {
57 let code_gen = gen_internal(code);
58 let disassembler_output = disasm_instructions_color(
59 code_gen.instructions(),
60 code_gen.comments(),
61 &code_gen.create_function_sections(),
62 );
63
64 eprintln!("{disassembler_output}");
65
66 code_gen
67}
68
69pub fn exec_internal(code: &str) -> Vm {
70 let code_gen = gen_internal_debug(code);
71
72 let (instructions, constants) = code_gen.take_instructions_and_constants();
73
74 let mut vm = Vm::new(instructions, &constants, 0x1_00_00);
75
76 vm.execute();
77
78 vm
79}
80
81pub fn exec_internal_debug(code: &str) -> Vm {
82 let vm = exec_internal(code);
83
84 vm
85}
86
87fn trim_lines(text: &str) -> String {
88 text.lines()
89 .map(str::trim)
90 .filter(|line| !line.is_empty())
91 .collect::<Vec<_>>()
92 .join("\n")
93}
94
95fn compare_line_outputs(encountered: &str, expected: &str) {
96 let encountered_trimmed = trim_lines(encountered);
97 let expected_trimmed = trim_lines(expected);
98
99 eprintln!("{encountered}");
100 assert_eq!(encountered_trimmed, expected_trimmed);
101}
102
103fn compare_hex_outputs(memory: &[u8], expected_hex: &str) {
104 let encountered_hexed = hexify::format_hex(memory);
105 let expected_hex_trimmed = expected_hex.trim();
106
107 compare_line_outputs(&encountered_hexed, expected_hex_trimmed);
108}
109
110pub fn exec(code: &str, expected_hex: &str) {
111 let vm = exec_internal_debug(code);
112
113 compare_hex_outputs(&vm.stack_base_memory()[..16], expected_hex);
114}
115
116pub fn exec_show_constants(code: &str, expected_hex: &str, expected_constants: &str) {
117 let vm = exec_internal_debug(code);
118
119 compare_hex_outputs(&vm.stack_base_memory()[..16], expected_hex);
120 compare_hex_outputs(&vm.memory()[0xFFF0..], expected_constants);
121}
122
123pub fn exec_vars(code: &str, expected_hex: &str) {
124 let vm = exec_internal_debug(code);
125
126 compare_hex_outputs(&vm.frame_memory()[..16], expected_hex);
127}
128
129pub fn gen_code(code: &str, expected_output: &str) {
130 let generator = gen_internal_debug(code);
131
132 let disassembler_output = disasm_instructions_no_color(
133 generator.instructions(),
134 generator.comments(),
135 &generator.create_function_sections(),
136 );
137
138 compare_line_outputs(&disassembler_output, expected_output);
139}