1use std::collections::HashMap;
2
3use crate::ast::{BinOp, UnOp};
4use crate::consts::Const;
5use crate::opcodes::{Instruction, OpCode};
6
7pub struct LocalVal {
8 name: String,
9}
10
11pub struct UpVal {}
12
13pub struct Proto {
14 pub stack_size: u32,
15 pub param_count: u32,
16 pub code: Vec<Instruction>,
17 pub consts: Vec<Const>,
18 pub const_map: HashMap<Const, u32>,
19 pub local_vars: Vec<LocalVal>,
20 pub up_vars: Vec<UpVal>,
21 pub protos: Vec<Proto>,
22}
23
24impl Proto {
25 pub fn new() -> Proto {
26 Proto {
27 stack_size: 2,
28 param_count: 0,
29 code: Vec::new(),
30 consts: Vec::new(),
31 const_map: HashMap::new(),
32 local_vars: Vec::new(),
33 up_vars: Vec::new(),
34 protos: Vec::new(),
35 }
36 }
37
38 pub fn open(&mut self) {}
39
40 pub fn close(&mut self) {
41 self.code_return(0, 0);
42 }
43
44 pub fn code_return(&mut self, first: u32, nret: u32) -> usize {
45 self.code
46 .push(Instruction::create_ABC(OpCode::Return, first, nret + 1, 0));
47 self.code.len() - 1
48 }
49
50 pub fn code_nil(&mut self, start_reg: u32, n: u32) -> usize {
51 self.code.push(Instruction::create_ABC(
53 OpCode::LoadNil,
54 start_reg,
55 n - 1,
56 0,
57 ));
58 self.code.len() - 1
59 }
60
61 pub fn code_bool(&mut self, reg: u32, v: bool, pc: u32) -> usize {
62 self.code.push(Instruction::create_ABC(
63 OpCode::LoadBool,
64 reg,
65 if v { 1 } else { 0 },
66 pc,
67 ));
68 self.code.len() - 1
69 }
70
71 pub fn code_const(&mut self, reg_index: u32, const_index: u32) -> usize {
72 self.code.push(Instruction::create_ABx(
73 OpCode::LoadK,
74 reg_index,
75 const_index,
76 ));
77 self.code.len() - 1
78 }
79
80 pub fn code_move(&mut self, reg: u32, src: u32) -> usize {
81 self.code
82 .push(Instruction::create_ABC(OpCode::Move, reg, src, 0));
83 self.code.len() - 1
84 }
85
86 pub fn code_bin_op(&mut self, op: BinOp, target: u32, left: u32, right: u32) -> usize {
87 let op_code = match op {
88 BinOp::Add => OpCode::Add,
89 BinOp::Minus => OpCode::Sub,
90 BinOp::Mul => OpCode::Mul,
91 BinOp::Mod => OpCode::Mod,
92 BinOp::Pow => OpCode::Pow,
93 BinOp::Div => OpCode::Div,
94 BinOp::IDiv => OpCode::IDiv,
95 BinOp::BAnd => OpCode::BAdd,
96 BinOp::BOr => OpCode::BOr,
97 BinOp::BXor => OpCode::BXor,
98 BinOp::Shl => OpCode::Shl,
99 BinOp::Shr => OpCode::Shr,
100 BinOp::Concat => OpCode::Concat,
101 _ => unreachable!(),
102 };
103 self.code
104 .push(Instruction::create_ABC(op_code, target, left, right));
105 self.code.len() - 1
106 }
107
108 pub fn code_comp(&mut self, op: BinOp, left: u32, right: u32) -> usize {
109 let op_code = match op {
110 BinOp::Lt | BinOp::Gt => OpCode::Lt,
111 BinOp::Ne | BinOp::Eq => OpCode::Eq,
112 BinOp::Le | BinOp::Ge => OpCode::Le,
113 _ => unreachable!(),
114 };
115 let cond = if op == BinOp::Ne { 0 } else { 1 };
116 self.code
117 .push(Instruction::create_ABC(op_code, cond, left, right));
118 self.code.len() - 1
119 }
120
121 pub fn code_un_op(&mut self, op: UnOp, target: u32, src: u32) -> usize {
122 let op_code = match op {
123 UnOp::Minus => OpCode::Unm,
124 UnOp::BNot => OpCode::BNot,
125 UnOp::Not => OpCode::Not,
126 UnOp::Len => OpCode::Len,
127 _ => unimplemented!(),
128 };
129 self.code
130 .push(Instruction::create_ABC(op_code, target, src, 0));
131 self.code.len() - 1
132 }
133
134 pub fn code_jmp(&mut self, offset: i32, upvars: u32) -> usize {
135 self.code
136 .push(Instruction::create_AsBx(OpCode::Jmp, upvars, offset));
137 self.code.len() - 1
138 }
139
140 pub fn fix_cond_jump_pos(&mut self, true_pos: usize, false_pos: usize, pc: usize) {
141 let instruction = self.get_instruction(pc);
142 let pos = if instruction.get_arg_A() == 0 {
143 true_pos
144 } else {
145 false_pos
146 };
147 instruction.set_arg_sBx(pos as i32 - pc as i32 - 1);
148 }
149
150 pub fn fix_jump_pos(&mut self, pos: usize, pc: usize) {
151 let instruction = self.get_instruction(pc);
152 instruction.set_arg_sBx(pos as i32 - pc as i32 - 1);
153 }
154
155 pub fn code_test_set(&mut self, set: u32, test: u32, to_test: u32) {
156 self.code
157 .push(Instruction::create_ABC(OpCode::TestSet, set, test, to_test));
158 }
159
160 pub fn add_local_var(&mut self, name: &str) {
161 self.local_vars.push(LocalVal {
162 name: name.to_string(),
163 });
164 }
165
166 pub fn get_local_var(&self, name: &str) -> Option<u32> {
167 for (i, var) in self.local_vars.iter().enumerate() {
168 if var.name == name {
169 return Some(i as u32);
170 }
171 }
172 None
173 }
174
175 pub fn add_const(&mut self, k: Const) -> u32 {
176 match self.const_map.get(&k) {
177 Some(index) => *index,
178 None => {
179 let index = self.consts.len();
180 self.consts.push(k.clone());
181 self.const_map.insert(k, index as u32);
182 index as u32
183 }
184 }
185 }
186
187 pub fn save(&mut self, target: u32) -> usize {
189 let last = self.code.last_mut();
190 if let Some(code) = last {
191 code.save(target);
192 }
193 self.code.len() - 1
194 }
195
196 pub fn get_instruction(&mut self, index: usize) -> &mut Instruction {
197 &mut self.code[index]
198 }
199}
200
201use std::fmt;
202impl fmt::Debug for Proto {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 writeln!(f)?;
205
206 writeln!(f, "stack size : {}", self.stack_size)?;
207
208 writeln!(f, "consts :")?;
209 for (i, k) in self.consts.iter().enumerate() {
210 writeln!(
211 f,
212 "| {:<5} | {:<10} |",
213 i,
214 match k {
215 Const::Int(i) => i.to_string(),
216 Const::Float(f) => f.to_string(),
217 Const::Str(s) => format!("\"{}\"", s.clone()),
218 }
219 )?;
220 }
221
222 writeln!(f, "locals :")?;
223 for (i, local) in self.local_vars.iter().enumerate() {
224 writeln!(f, "| {:<5} | {:<10} |", i, local.name)?;
225 }
226
227 writeln!(f, "instructions :")?;
228 writeln!(
229 f,
230 "| {:<5} | {:<10} | {:<5} | {:<5} | {:<5} |",
231 "line", "OP", "A", "B", "C"
232 )?;
233 for (i, instruction) in self.code.iter().enumerate() {
234 writeln!(f, "| {:<5} {:?}", i + 1, instruction)?;
235 }
236
237 Ok(())
238 }
239}
240
241pub struct ProtoContext {
242 pub reg_top: u32,
243 pub proto: Proto,
244}
245
246impl ProtoContext {
247 pub fn new() -> Self {
248 ProtoContext {
249 reg_top: 0,
250 proto: Proto::new(),
251 }
252 }
253
254 pub fn check_stack(&mut self, n: u32) {
255 let new_stack = self.reg_top + n;
256 if new_stack > self.proto.stack_size {
257 self.proto.stack_size = new_stack;
258 }
259 }
260
261 pub fn reserve_regs(&mut self, n: u32) -> u32 {
262 self.check_stack(n);
263 let index = self.reg_top;
264 self.reg_top += n;
265 index
266 }
267
268 pub fn get_reg_top(&self) -> u32 {
269 self.reg_top
270 }
271
272 pub fn free_reg(&mut self, n: u32) {
273 self.reg_top -= n;
274 }
275}