tower_vm/builder/
builder.rs

1use std::collections::HashMap;
2
3use super::chunk::Chunk;
4
5use crate::{Instruction, TypeFlag, Value, Machine};
6
7macro_rules! simple_instr {
8    ($fn_name:ident, $instr:ident) => {
9        pub fn $fn_name(&mut self) {
10            self.push_instr(Instruction::$instr);
11        }
12    };
13}
14
15
16
17pub struct Builder {
18    chunks: Vec<Chunk>,
19    funcs: HashMap<String, u64>,// store the start point of a function with its identifier
20}   
21
22impl Builder {
23    pub fn new() -> Self {
24        Self {
25            chunks: vec![],
26            funcs: HashMap::new(),
27        }
28    }
29
30    pub fn debug_chunks(&self) {
31        println!("{:?}", self.chunks)
32    }
33    fn get_func(&self, ident: &str) -> Option<u64> {
34        self.funcs.get(ident).copied()
35    }
36
37    fn push_instr(&mut self, instr: Instruction) {
38        self.chunks.push(Chunk::Instr(instr))
39    }
40
41    pub fn push(&mut self, value: Value) {
42        self.push_instr(Instruction::Push);
43        self.chunks.push(Chunk::Literal(value));
44    }
45
46    // a utility to handle the pushing of a collection putting the first element at the top of the stack
47    pub fn push_collect(&mut self, values: &mut Vec<Value>) {
48        while values.len() > 0 {
49            self.push(values.pop().unwrap());
50        }        
51    }
52
53    // set the start point of a new function to the next index in code
54    // if the function is already defined, return Err with the index of the existing function
55    pub fn start_fn(&mut self, id: &str) -> Result<(), u64> {
56        let ident = id.to_string();
57
58        match self.get_func(id) {
59            Some(_) => Err(self.funcs[&ident]),
60            None => {
61                self.funcs.insert(ident, self.chunks.len() as u64);
62                Ok(())
63            },
64        }
65    }
66
67    // mark the stop of a function by pushing the return instruction
68    simple_instr!(ret_fn, Ret);
69
70    // mark the end of the program
71    simple_instr!(halt, Halt);
72
73    // set the type alignment
74    pub fn set_type(&mut self, ty_flag: TypeFlag) {
75        self.push_instr(Instruction::SetType);
76        self.chunks.push(Chunk::Type(ty_flag));
77    }
78
79    simple_instr!(get_type, GetType);
80
81    simple_instr!(add, Add);
82
83    simple_instr!(sub, Sub);
84
85    simple_instr!(div, Div);
86
87    simple_instr!(rem, Rem);
88
89    simple_instr!(neg, Neg);
90
91    simple_instr!(incr, Incr);
92
93    simple_instr!(decr, Decr);
94
95    simple_instr!(eq, Eq);
96
97    simple_instr!(neq, Neq);
98
99    simple_instr!(lt, Lt);
100
101    simple_instr!(gt, Gt);
102
103    simple_instr!(lte, Lte);
104
105    simple_instr!(gte, Gte);
106
107    simple_instr!(and, And);
108
109    simple_instr!(or, Or);
110
111    simple_instr!(xor, Xor);
112
113    simple_instr!(shl, Shl);
114
115    simple_instr!(shr, Shr);
116
117    simple_instr!(not, Not);
118
119    // optionally give the address to be jumped to
120    pub fn jmp(&mut self, addr: Option<u64>) {
121        if let Some(idx) = addr {
122            self.push(idx.into());
123        }
124        self.push_instr(Instruction::Jmp);
125    }
126
127    simple_instr!(jmp_if, JmpIf);
128
129    simple_instr!(jmp_if_not, JmpIfNot);
130
131    pub fn call(&mut self, ident: &str) -> Result<(), String> {
132        match self.get_func(ident) {
133            Some(idx) => {
134                self.push(idx.into());
135                Ok(self.push_instr(Instruction::Call))
136            }
137            None => Err(format!("Error: fn {} is undefined", ident)),
138        }
139    }
140
141    simple_instr!(ret, Ret);
142
143    simple_instr!(dup, Dup);
144
145    simple_instr!(drop, Drop);
146
147    simple_instr!(swap, Swap);
148
149    // optionally provide the ptr to the heap address
150    pub fn load(&mut self, ptr: Option<u64>) {
151        if let Some(idx) = ptr {
152            self.push(idx.into());
153        }
154        self.push_instr(Instruction::Load);
155    }
156
157    simple_instr!(store, Store);
158
159    simple_instr!(alloc, Alloc);
160
161    simple_instr!(free, Free);
162
163    simple_instr!(heap_size, HeapSize);
164
165    simple_instr!(stack_size, StackSize);
166
167    simple_instr!(load_code, LoadCode);
168
169    simple_instr!(save_code, SaveCode);
170
171    pub fn write(&mut self, out: Option<&str>) {
172        // optionally push a string to stack and write the whole thing to stream
173        // otherwise push one write instruction
174        if let Some(s) = out {
175            let mut values: Vec<Value> = s.chars().into_iter().map(|ch| ch.into()).collect();
176            self.push_collect(&mut values);
177            for _ in 0..(s.len()) {
178                self.push_instr(Instruction::Write);
179            }
180        }else{
181            self.push_instr(Instruction::Write);
182        }
183    }
184
185    simple_instr!(read, Read);
186
187    pub fn print(&mut self, out: Option<&str>) {
188        if let Some(s) = out {
189            self.write(Some(s));
190        }
191        self.push_instr(Instruction::Print);
192    }
193
194    fn to_code(&mut self) -> Vec<u8> {
195        let mut code = vec![];
196        
197        for chunk in self.chunks.iter_mut() {
198            code.append(&mut chunk.to_code());
199        }
200
201        code
202    }
203
204    // there will be optional optimization passes here in the distant future
205    pub fn build_code(&mut self) -> Vec<u8> {
206        self.to_code()
207    }
208
209    pub fn build_machine(&mut self) -> Machine {
210        let mut machine = Machine::new();
211        machine.push_code(&self.build_code());
212        return machine;
213    }
214}