diff --git a/lib/src/backend/lua/bytecode.rs b/lib/src/backend/lua/bytecode.rs index 9c0cf59..ee3d889 100644 --- a/lib/src/backend/lua/bytecode.rs +++ b/lib/src/backend/lua/bytecode.rs @@ -4,8 +4,8 @@ use std::hash::{Hash, Hasher}; use crate::parser::StString; -use super::register::{Register, RK}; -use super::{ConstantIndex, LuaType, LuaVarKind, UpValueIndex}; +use super::register::{Reg, RK}; +use super::{ConstIdx, LuaType, LuaVarKind}; macro_rules! excess_k { ($v: expr, $k: expr) => { @@ -204,34 +204,34 @@ impl Display for LuaConstants { #[derive(Debug)] pub enum LuaByteCode { /// A B: R[A] := R[B] - Move(Register, Register), + Move(Reg, Reg), /// A sBx: R[A] := sBx - LoadI(Register, i32), + LoadI(Reg, i32), /// A B: R[A] := K[Bx] - LoadK(Register, ConstantIndex), + LoadK(Reg, ConstIdx), /// A B C: R[A] := UpValue[B][K[C]:string] - GetTabUp(Register, u8, ConstantIndex), + GetTabUp(Reg, u8, ConstIdx), /// A B C: UpValue[A][K[B]:string] := RK(C) - SetTabUp(Register, UpValueIndex, RK), + SetTabUp(Reg, u8, RK), /// A B C: R[A] := R[B] + R[C] - Add(Register, Register, Register), + Add(Reg, Reg, Reg), /// A B k: if ((R[A] == R[B]) ~= k) then pc++ - Eq(Register, Register, u8), + Eq(Reg, Reg, u8), /// A sB k: if ((R[A] > sB) ~= k) then pc++ - Gti(Register, u8, u8), + Gti(Reg, u8, u8), /// A sB k: if ((R[A] >= sB) ~= k) then pc++ - Gei(Register, u8, u8), + Gei(Reg, u8, u8), /// A B C: return R[A], ... ,R[A+B-2] Return(u8, u8, u8), /// Call k, v: k is callee symbol position, v is argument count, return value not included /// A B C: R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) - Call(Register, u8, u8), + Call(Reg, u8, u8), /// A (adjust vararg parameters) VarArgPrep(u8), @@ -291,7 +291,7 @@ impl LuaByteCode { // A B RK LuaByteCode::SetTabUp(a, upv, rk) => { let c = match rk { - RK::R(Register::RealRegister(r)) => r as u32, + RK::R(Reg::R(r)) => r as u32, RK::K(k) => (k as u32) << 17 | 1u32 << 8, _ => unreachable!(), }; @@ -396,8 +396,7 @@ impl LuaCompiledCode { write!(s, " ; K[{}] = {}", bx, self.constants[*bx as usize]).unwrap(); } LuaByteCode::GetTabUp(a, b, k) => { - let (name, _upv) = self.upvalues.get_index(*k as usize).unwrap(); - write!(s, " ; _ENV \"{}\"", name).unwrap() + write!(s, " ; _ENV \"{}\"", self.constants[*k as usize]).unwrap() } LuaByteCode::Call(a, b, c) => { if *b == 0 { @@ -453,14 +452,14 @@ impl Display for LuaCompiledCode { #[cfg(test)] mod test { use super::LuaByteCode; - use super::Register; + use super::Reg; #[test] fn test_encoding() { - let code = LuaByteCode::LoadI(Register::from_raw(0), 2); + let code = LuaByteCode::LoadI(Reg::from_raw(0), 2); assert_eq!(code.encode(), 0x80008001); - let code = LuaByteCode::LoadI(Register::from_raw(3), -65535); + let code = LuaByteCode::LoadI(Reg::from_raw(3), -65535); assert_eq!(code.encode(), 0x00000181); let code = LuaByteCode::Return(0, 1, 1); diff --git a/lib/src/backend/lua/mod.rs b/lib/src/backend/lua/mod.rs index 1d69efb..4668d16 100644 --- a/lib/src/backend/lua/mod.rs +++ b/lib/src/backend/lua/mod.rs @@ -22,10 +22,9 @@ use log::*; use smallvec::{smallvec, SmallVec}; use std::mem; use std::rc::Rc; -use crate::backend::lua::register::Register::RealRegister; +use crate::backend::lua::register::Reg::R; -type ConstantIndex = u8; -type UpValueIndex = u8; +type ConstIdx = u8; bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -62,7 +61,7 @@ bitflags! { enum LuaAccessMode { None, Call(usize), - ReadUpValue, + ReadSymbol, WriteRegister, // Read value into register or literal LoadNewRegister, @@ -76,9 +75,8 @@ enum LuaAccessMode { #[derive(Clone)] pub struct LuaBackendStates { variable: Option>, - registers: SmallVec8, - constant_index: Option, - upvalue: Option<(u8, LuaUpValue)>, + registers: SmallVec8, + const_idx: Option, scope: Option, error: bool, access_mode: LuaAccessMode, @@ -91,9 +89,8 @@ impl Default for LuaBackendStates { registers: smallvec![], scope: None, error: false, - upvalue: None, access_mode: LuaAccessMode::None, - constant_index: None, + const_idx: None, } } } @@ -114,21 +111,21 @@ pub struct LuaBackend { impl LuaBackend { #[inline] - fn code_gettabup(&mut self, dst: Register, k: ConstantIndex) { + fn code_gettabup(&mut self, dst: Reg, k: ConstIdx) { self.push_code(LuaByteCode::GetTabUp(dst, 0, k)); } #[inline] fn code_settabup(&mut self, up_idx: u8, rk: RK) { - self.push_code(LuaByteCode::SetTabUp(RealRegister(0), up_idx, rk)); + self.push_code(LuaByteCode::SetTabUp(R(0), up_idx, rk)); } #[inline] - fn code_move(&mut self, from: Register, to: Register) { + fn code_move(&mut self, from: Reg, to: Reg) { self.push_code(LuaByteCode::Move(to, from)) } - fn code_load(&mut self, r: Register, v: &LiteralValue) { + fn code_load(&mut self, r: Reg, v: &LiteralValue) { // if literal can use LoadI instructions if let Some(v) = try_fit_sbx(v) { self.push_code(LuaByteCode::LoadI(r, v)); @@ -140,28 +137,18 @@ impl LuaBackend { } #[inline] - fn code_load_constant(&mut self, r: Register, k: ConstantIndex) { + fn code_load_constant(&mut self, r: Reg, k: ConstIdx) { self.push_code(LuaByteCode::LoadK(r, k)) } #[inline] fn push_code(&mut self, code: LuaByteCode) { - debug!("LuaBackend: Push Code {:?}", code); + trace!("Code-Lua: {:?}", code); self.byte_codes.push(code) } - fn lookup_symbol(&mut self, sym: &StString) -> Option<(u8, LuaUpValue)> { - if !self.upvalue_table.contains_key(sym) { - let constant = self.add_constant(&LiteralValue::String(sym.origin_string().clone())); - self.upvalue_table.insert_full(sym.clone(), LuaUpValue { stack: 0, index: constant, kind: LuaVarKind::RDKCONST }); - } - - let (idx, _key, val) = self.upvalue_table.get_full(sym).unwrap(); - Some((idx as u8, *val)) - } - #[inline] - fn add_constant(&mut self, v: &LiteralValue) -> ConstantIndex { + fn add_constant(&mut self, v: &LiteralValue) -> ConstIdx { match v { LiteralValue::String(s) => self.add_string_constant(s), LiteralValue::DInt(i) => self.add_integer_constant(*i as i64), @@ -224,24 +211,24 @@ impl LuaBackend { } #[inline] - fn add_string_constant>(&mut self, s: S) -> ConstantIndex { + fn add_string_constant>(&mut self, s: S) -> ConstIdx { let constant = LuaConstants::String(s.as_ref().to_owned()); let (idx, _inserted) = self.constants.insert_full(constant); - idx as ConstantIndex + idx as ConstIdx } #[inline] - fn add_integer_constant(&mut self, i: i64) -> ConstantIndex { + fn add_integer_constant(&mut self, i: i64) -> ConstIdx { let constant = LuaConstants::Integer(i); let (idx, _inserted) = self.constants.insert_full(constant); - idx as ConstantIndex + idx as ConstIdx } #[inline] - fn add_float_constant(&mut self, f: f64) -> ConstantIndex { + fn add_float_constant(&mut self, f: f64) -> ConstIdx { let constant = LuaConstants::Float(f); let (idx, _inserted) = self.constants.insert_full(constant); - idx as ConstantIndex + idx as ConstIdx } } @@ -356,7 +343,7 @@ impl AstVisitorMut for LuaBackend { self.code_load(r, literal.literal()); } else { - self.top_attribute().constant_index = Some(self.add_constant(literal.literal())) + self.top_attribute().const_idx = Some(self.add_constant(literal.literal())) } } @@ -378,18 +365,16 @@ impl AstVisitorMut for LuaBackend { let arg_regs = self.reg_mgr.alloc_hard_batch(arg_cnt); self.top_attribute().registers = arg_regs.into(); - self.top_attribute().upvalue = self.lookup_symbol(var_expr.name()); - // self.top_attribute().constant_index = - // Some(self.add_string_constant(var_expr.org_name())); + self.top_attribute().const_idx = Some(self.add_string_constant(var_expr.org_name())); } - // Read UpValue - LuaAccessMode::ReadUpValue => { - self.top_attribute().upvalue = self.lookup_symbol(var_expr.name()); + // Read Symbol + LuaAccessMode::ReadSymbol => { + self.top_attribute().const_idx = Some(self.add_string_constant(var_expr.org_name())); } LuaAccessMode::WriteRegister => { let dst = self.top_attribute().registers[0]; - let upv = self.lookup_symbol(var_expr.name()); - self.code_gettabup(dst, upv.unwrap().0); + let constant_index = self.add_string_constant(var_expr.org_name()); + self.code_gettabup(dst, constant_index); } // Write register into stack LuaAccessMode::Write => {} @@ -429,8 +414,8 @@ impl AstVisitorMut for LuaBackend { let arg_regs = callee_attr.registers; let callee_reg = arg_regs[0]; - // TODO: - self.push_code(LuaByteCode::GetTabUp(callee_reg, 0, callee_attr.upvalue.unwrap().0)); + // Load Callee from constant table into callee_reg + self.push_code(LuaByteCode::GetTabUp(callee_reg, 0, callee_attr.const_idx.unwrap())); // visit all arguments for (idx, arg) in call.arguments_mut().iter_mut().enumerate() { @@ -524,15 +509,15 @@ impl AstVisitorMut for LuaBackend { let rhs = self.pop_attribute(); // Get lhs register - self.push_access_attribute(LuaAccessMode::ReadUpValue); + self.push_access_attribute(LuaAccessMode::ReadSymbol); assign.left_mut().accept_mut(self); - let lhs_upv = self.pop_attribute().upvalue.unwrap(); + let lhs_constant_index = self.pop_attribute().const_idx.unwrap(); // let lhs_reg = self.pop_attribute().registers[0]; - if let Some(constant_index) = rhs.constant_index { + if let Some(constant_index) = rhs.const_idx { assert_eq!(rhs.registers.len(), 0); // self.code_load_constant(lhs_reg, constant_index) - self.code_settabup(lhs_upv.0, RK::K(constant_index)); + self.code_settabup(lhs_constant_index, RK::K(constant_index)); } else { assert_eq!(1, rhs.registers.len()); // assert_ne!(lhs_reg, rhs.registers[0]); diff --git a/lib/src/backend/lua/register.rs b/lib/src/backend/lua/register.rs index d3f4a00..cbe48d7 100644 --- a/lib/src/backend/lua/register.rs +++ b/lib/src/backend/lua/register.rs @@ -6,34 +6,36 @@ use crate::parser::StString; const MAX_REGISTER_ID: u8 = 255; +/// Register or ConstantIndex #[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)] pub enum RK { - R(Register), + R(Reg), K(u8), } +/// Register, VirtualRegister or RealRegister #[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)] -pub enum Register { - VirtualRegister(usize), - RealRegister(u8), +pub enum Reg { + VR(usize), + R(u8), } -impl Register { +impl Reg { pub fn num(&self) -> u8 { match *self { - Self::RealRegister(x) => x, - Self::VirtualRegister(..) => panic!("Can't get number for virtual register"), + Self::R(x) => x, + Self::VR(..) => panic!("Can't get number for virtual register"), } } pub fn is_virtual(&self) -> bool { - matches!(*self, Self::VirtualRegister(..)) + matches!(*self, Self::VR(..)) } // for unit test #[cfg(test)] pub fn from_raw(n: u8) -> Self { - Self::RealRegister(n) + Self::R(n) } } @@ -42,8 +44,8 @@ pub struct RegisterManager { virtual_register_cursor: usize, real_register_cursor: u8, used_real_registers: HashSet, - local_variable_register: SmallMap, - local_variable_register_reverse: SmallMap, + local_variable_register: SmallMap, + local_variable_register_reverse: SmallMap, } impl RegisterManager { @@ -59,7 +61,7 @@ impl RegisterManager { } #[inline] - pub fn alloc_local_variable(&mut self, v: &StString) -> Register { + pub fn alloc_local_variable(&mut self, v: &StString) -> Reg { match self.local_variable_register.get(v) { Some(r) => *r, None => { @@ -78,7 +80,7 @@ impl RegisterManager { pub fn check_and_reset(&mut self) -> bool { // free all local variable registers for (r, _) in self.local_variable_register_reverse.iter() { - if let Register::RealRegister(x) = r { + if let Reg::R(x) = r { self.used_real_registers.remove(x); } } @@ -97,20 +99,20 @@ impl RegisterManager { balanced } - pub fn alloc(&mut self) -> Register { + pub fn alloc(&mut self) -> Reg { let next = self.virtual_register_cursor; self.virtual_register_cursor += 1; - Register::VirtualRegister(next) + Reg::VR(next) } - pub fn alloc_hard(&mut self) -> Register { + pub fn alloc_hard(&mut self) -> Reg { // ensure has free register to allocate assert!(self.used_real_registers.len() <= MAX_REGISTER_ID as usize); loop { if self.used_real_registers.insert(self.real_register_cursor) { - return Register::RealRegister(self.real_register_cursor); + return Reg::R(self.real_register_cursor); } self.real_register_cursor += 1; @@ -118,7 +120,7 @@ impl RegisterManager { } } - pub fn alloc_hard_batch(&mut self, count: usize) -> Vec { + pub fn alloc_hard_batch(&mut self, count: usize) -> Vec { let cursor = self.real_register_cursor as usize; if cursor + count >= MAX_REGISTER_ID as usize { panic!("no more registers!") @@ -128,7 +130,7 @@ impl RegisterManager { let mut r = Vec::with_capacity(count); for x in cursor..=cursor + count { - r.push(Register::RealRegister(x as u8)); + r.push(Reg::R(x as u8)); self.used_real_registers.insert(x as u8); } @@ -136,17 +138,17 @@ impl RegisterManager { } #[inline] - pub fn free(&mut self, reg: &Register) { + pub fn free(&mut self, reg: &Reg) { // prevent free for local variable register if self.local_variable_register_reverse.contains_key(reg) { return; } match *reg { - Register::RealRegister(x) => { + Reg::R(x) => { self.used_real_registers.remove(&x); } - Register::VirtualRegister(_) => {} + Reg::VR(_) => {} } } } diff --git a/lib/src/backend/lua/test.rs b/lib/src/backend/lua/test.rs index c293068..75d2116 100644 --- a/lib/src/backend/lua/test.rs +++ b/lib/src/backend/lua/test.rs @@ -77,9 +77,24 @@ fn eval_string, S2: AsRef>(decl: S1, body: S2) -> String { #[test] fn test_print() { + // assignment let r = eval_string( "PROGRAM main: VAR a: int; END_VAR END_PROGRAM", "a := 1; print(a);", ); assert_eq!(r, "1\n"); + + // assignment twice + let r = eval_string( + "PROGRAM main: VAR a: int; END_VAR END_PROGRAM", + "a := 3; a := 2; print(a);", + ); + assert_eq!(r, "2\n"); + + // print string + let r = eval_string( + "PROGRAM main: VAR a: STRING; END_VAR END_PROGRAM", + "a := \"abc\"; print(a);", + ); + assert_eq!(r, "abc\n"); } diff --git a/viewer/test_projects/example1/test_proj.xml b/viewer/test_projects/example1/test_proj.xml index 32c6457..b6120b5 100644 --- a/viewer/test_projects/example1/test_proj.xml +++ b/viewer/test_projects/example1/test_proj.xml @@ -23,7 +23,10 @@ end_program a := 1; + + if a = 1 then print(a); + end_if