swamp_script_vm_test/
util.rs

1use 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}