rslua_march1917/
proto.rs

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        // TODO : optimize for duplicate LoadNil
52        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    // save result to target reg
188    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}