From c59c4e4e24c8032332232910432c005a02d26044 Mon Sep 17 00:00:00 2001 From: Sofia Date: Thu, 19 Mar 2026 16:39:51 +0200 Subject: [PATCH] Add Pre-Instructions --- examples/test.lua | 2 +- src/compile.rs | 209 +++++++++++++++++++++++++++++----------------- src/lib.rs | 3 +- 3 files changed, 134 insertions(+), 80 deletions(-) diff --git a/examples/test.lua b/examples/test.lua index 7fc8bcf..2a7fe67 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -40,6 +40,6 @@ print(true or 0) global value, table = f(10, 11, 12) print("hello") -for i=#table,1,-1 do +for i=1,#table do print(table[i]) end \ No newline at end of file diff --git a/src/compile.rs b/src/compile.rs index cfe24d0..1f3ea5a 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -77,6 +77,23 @@ impl LocalCounter { } } +pub(crate) enum PreInstr { + Instr(Instruction), + Break, +} + +pub(crate) fn process_pre_instrs(pre_instructions: Vec) -> Vec { + let mut instructions = Vec::new(); + for pre_instr in pre_instructions { + match pre_instr { + PreInstr::Instr(instruction) => instructions.push(instruction), + PreInstr::Break => panic!(), + } + } + + instructions +} + impl Block { pub(crate) fn find_constants( &self, @@ -94,7 +111,7 @@ impl Block { constants } - pub(crate) fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec { + pub(crate) fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec { let mut instructions = Vec::new(); let mut inner_scope = scope.clone(); @@ -165,7 +182,7 @@ impl Statement { } } - fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec { + fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec { let mut instructions = Vec::new(); match self { @@ -173,7 +190,7 @@ impl Statement { let new_registers = if *access_modifier == Some(AccessModifier::Local) { let min_reg = scope.register_counter.0 + 1; let max_reg = scope.register_counter.0 + names.len() as u16; - instructions.push(Instruction::LoadNil(min_reg, max_reg)); + instructions.push(PreInstr::Instr(Instruction::LoadNil(min_reg, max_reg))); scope.register_counter.0 += names.len() as u16 + 1; let mut new_registers = Vec::new(); @@ -205,14 +222,14 @@ impl Statement { let mut vararg_applied = false; for (i, (name, indexes)) in names.iter().enumerate() { if let Some(expr_reg) = expr_regs.get(i) { - instructions.push(Instruction::Move( + instructions.push(PreInstr::Instr(Instruction::Move( *new_registers.get(i).unwrap(), *expr_reg, - )); + ))); } else if !vararg_applied { - instructions.push(Instruction::MoveRetValues( + instructions.push(PreInstr::Instr(Instruction::MoveRetValues( *new_registers.get(i).unwrap(), - )); + ))); vararg_applied = true; } if indexes.len() > 0 { @@ -229,10 +246,10 @@ impl Statement { todo!() } let global = state.get_constant(&Constant::String(name.kind.clone())); - instructions.push(Instruction::SetGlobal( + instructions.push(PreInstr::Instr(Instruction::SetGlobal( expr_regs.get(i).cloned().unwrap(), global, - )); + ))); } } None => { @@ -242,13 +259,17 @@ impl Statement { *reg } else if let Some(upval_reg) = scope.upvalues.get(&name.kind) { let local = scope.register_counter.next(); - instructions.push(Instruction::GetUpVal(local, *upval_reg)); + instructions.push(PreInstr::Instr(Instruction::GetUpVal( + local, *upval_reg, + ))); local } else { let global = state.get_constant(&Constant::String(name.kind.clone())); let local = scope.register_counter.next(); - instructions.push(Instruction::GetGlobal(local, global)); + instructions.push(PreInstr::Instr(Instruction::GetGlobal( + local, global, + ))); local }; @@ -261,40 +282,40 @@ impl Statement { let (instr, index_reg) = index.kind.compile(state, scope, Some(1)); instructions.extend(instr); - instructions.push(Instruction::GetTable( + instructions.push(PreInstr::Instr(Instruction::GetTable( table_reg, table_reg, *index_reg.first().unwrap(), - )); + ))); } } let (instr, index_reg) = indexes.last().unwrap().kind.compile(state, scope, Some(1)); instructions.extend(instr); - instructions.push(Instruction::SetTable( + instructions.push(PreInstr::Instr(Instruction::SetTable( table_reg, *index_reg.first().unwrap(), expr_regs.get(i).cloned().unwrap(), - )); + ))); } else { if let Some(reg) = scope.locals.get(&name.kind) { - instructions.push(Instruction::Move( + instructions.push(PreInstr::Instr(Instruction::Move( *reg, expr_regs.get(i).cloned().unwrap(), - )); + ))); } else if let Some(upval_reg) = scope.upvalues.get(&name.kind) { - instructions.push(Instruction::SetUpVal( + instructions.push(PreInstr::Instr(Instruction::SetUpVal( *upval_reg, expr_regs.get(i).cloned().unwrap(), - )); + ))); } else { let global = state.get_constant(&Constant::String(name.kind.clone())); - instructions.push(Instruction::SetGlobal( + instructions.push(PreInstr::Instr(Instruction::SetGlobal( expr_regs.get(i).cloned().unwrap(), global, - )); + ))); } } } @@ -329,35 +350,42 @@ impl Statement { for (i, ret_register) in ret_registers.iter_mut().enumerate() { let new_reg = first_ret_register + i as u16; if *ret_register != new_reg { - instructions.push(Instruction::Move(new_reg, *ret_register)); + instructions + .push(PreInstr::Instr(Instruction::Move(new_reg, *ret_register))); } *ret_register = new_reg; } if vararg { - instructions.push(Instruction::MoveRetValues( + instructions.push(PreInstr::Instr(Instruction::MoveRetValues( first_ret_register + ret_registers.len() as u16, - )); + ))); } - instructions.push(Instruction::Return( + instructions.push(PreInstr::Instr(Instruction::Return( first_ret_register, if vararg { 0 } else { *ret_registers.last().unwrap_or(&0) }, - )); + ))); } Statement::If(expr, block) => { let (instr, regs) = expr.kind.compile(state, scope, Some(1)); instructions.extend(instr); let local = scope.register_counter.next(); - instructions.push(Instruction::Test(local, *regs.first().unwrap(), 0)); + instructions.push(PreInstr::Instr(Instruction::Test( + local, + *regs.first().unwrap(), + 0, + ))); let block_instructions = block.compile(state, scope); - instructions.push(Instruction::Jmp(block_instructions.len() as i32)); + instructions.push(PreInstr::Instr(Instruction::Jmp( + block_instructions.len() as i32 + ))); instructions.extend(block_instructions); } Statement::Expression(expr) => { @@ -380,17 +408,21 @@ impl Statement { scope.locals.insert("_END".to_owned(), *end_reg); scope.locals.insert("_STEP".to_owned(), *step_reg); - instructions.push(Instruction::ForTest(*init_reg, *end_reg, *step_reg)); + instructions.push(PreInstr::Instr(Instruction::ForTest( + *init_reg, *end_reg, *step_reg, + ))); let mut inner_scope = scope.clone(); let instr = block.compile(state, &mut inner_scope); let instr_len = instr.len() as i32; - instructions.push(Instruction::Jmp(instr_len + 2)); + instructions.push(PreInstr::Instr(Instruction::Jmp(instr_len + 2))); instructions.extend(instr); - instructions.push(Instruction::Add(*init_reg, *init_reg, *step_reg)); - instructions.push(Instruction::Jmp(-(instr_len + 4))); + instructions.push(PreInstr::Instr(Instruction::Add( + *init_reg, *init_reg, *step_reg, + ))); + instructions.push(PreInstr::Instr(Instruction::Jmp(-(instr_len + 4)))); } } @@ -492,21 +524,24 @@ impl Expression { state: &mut State, scope: &mut Scope, expected_values: Option, - ) -> (Vec, Vec) { + ) -> (Vec, Vec) { match self { Expression::ValueRef(name) => { if let Some(reg) = scope.locals.get(name) { (Vec::new(), vec![*reg]) } else if let Some(upvalue) = scope.upvalues.get(name) { let local = scope.register_counter.next(); - (vec![Instruction::GetUpVal(local, *upvalue)], vec![local]) + ( + vec![PreInstr::Instr(Instruction::GetUpVal(local, *upvalue))], + vec![local], + ) } else { let mut instructions = Vec::new(); let reg = scope.register_counter.next(); - instructions.push(Instruction::GetGlobal( + instructions.push(PreInstr::Instr(Instruction::GetGlobal( reg, state.get_constant(&Constant::String(name.clone())), - )); + ))); (instructions, vec![reg]) } } @@ -519,64 +554,69 @@ impl Expression { let reg = scope.register_counter.next(); match binary_operator { BinaryOperator::Equal => { - instructions.push(Instruction::Equal( + instructions.push(PreInstr::Instr(Instruction::Equal( reg, *lhs.get(0).unwrap(), *rhs.get(0).unwrap(), - )); + ))); } BinaryOperator::LessThan => { - instructions.push(Instruction::LessThan( + instructions.push(PreInstr::Instr(Instruction::LessThan( reg, *lhs.get(0).unwrap(), *rhs.get(0).unwrap(), - )); + ))); } BinaryOperator::LessThanOrEqual => { - instructions.push(Instruction::LessThanOrEqual( + instructions.push(PreInstr::Instr(Instruction::LessThanOrEqual( reg, *lhs.get(0).unwrap(), *rhs.get(0).unwrap(), - )); + ))); } BinaryOperator::GreaterThan => { - instructions.push(Instruction::LessThan( + instructions.push(PreInstr::Instr(Instruction::LessThan( reg, *rhs.get(0).unwrap(), *lhs.get(0).unwrap(), - )); + ))); } BinaryOperator::GreaterThanOrEqual => { - instructions.push(Instruction::LessThanOrEqual( + instructions.push(PreInstr::Instr(Instruction::LessThanOrEqual( reg, *rhs.get(0).unwrap(), *lhs.get(0).unwrap(), - )); + ))); } BinaryOperator::Add => { - instructions.push(Instruction::Add( + instructions.push(PreInstr::Instr(Instruction::Add( reg, *lhs.get(0).unwrap(), *rhs.get(0).unwrap(), - )); + ))); } BinaryOperator::Sub => { - instructions.push(Instruction::Unm(reg, *rhs.get(0).unwrap())); - instructions.push(Instruction::Add(reg, *lhs.get(0).unwrap(), reg)); + instructions + .push(PreInstr::Instr(Instruction::Unm(reg, *rhs.get(0).unwrap()))); + instructions.push(PreInstr::Instr(Instruction::Add( + reg, + *lhs.get(0).unwrap(), + reg, + ))); } BinaryOperator::And => { - instructions.push(Instruction::And( + instructions.push(PreInstr::Instr(Instruction::And( reg, *lhs.get(0).unwrap(), *rhs.get(0).unwrap(), - )); + ))); } BinaryOperator::Or => { - instructions.push(Instruction::Or( + instructions.push(PreInstr::Instr(Instruction::Or( reg, *lhs.get(0).unwrap(), *rhs.get(0).unwrap(), - )); + ))); } }; (instructions, vec![reg]) @@ -587,8 +627,12 @@ impl Expression { instructions.extend(instr); for reg in ®isters { match op { - UnaryOperator::Negation => instructions.push(Instruction::Unm(*reg, *reg)), - UnaryOperator::Length => instructions.push(Instruction::Len(*reg, *reg)), + UnaryOperator::Negation => { + instructions.push(PreInstr::Instr(Instruction::Unm(*reg, *reg))) + } + UnaryOperator::Length => { + instructions.push(PreInstr::Instr(Instruction::Len(*reg, *reg))) + } } } (instructions, registers) @@ -618,7 +662,7 @@ impl Expression { let instructions = block.compile(state, &mut inner_scope); state.prototypes.push(Prototype { - instructions, + instructions: process_pre_instrs(instructions), parameters: if inner_scope.is_vararg { params.len() - 1 } else { @@ -627,9 +671,14 @@ impl Expression { }); let mut instructions = Vec::new(); - instructions.push(Instruction::Close(scope.register_counter.0)); + instructions.push(PreInstr::Instr(Instruction::Close( + scope.register_counter.0, + ))); let local = scope.register_counter.next(); - instructions.push(Instruction::Closure(local, state.prototypes.len() as u32)); + instructions.push(PreInstr::Instr(Instruction::Closure( + local, + state.prototypes.len() as u32, + ))); (instructions, vec![local]) } @@ -676,16 +725,19 @@ impl Expression { for (i, param_reg) in original_param_regs.iter().enumerate().rev() { let new_reg = param_regs.get(i).unwrap(); if param_reg != new_reg { - instructions.push(Instruction::Move(*new_reg, *param_reg)); + instructions.push(PreInstr::Instr(Instruction::Move(*new_reg, *param_reg))); } } if function_reg != *old_function_reg { - instructions.push(Instruction::Move(function_reg, *old_function_reg)); + instructions.push(PreInstr::Instr(Instruction::Move( + function_reg, + *old_function_reg, + ))); } if vararg { let last_reg = param_regs.last().unwrap_or(&function_reg) + 1; - instructions.push(Instruction::MoveRetValues(last_reg)); + instructions.push(PreInstr::Instr(Instruction::MoveRetValues(last_reg))); } let last_param_reg = param_regs.last().unwrap_or(&function_reg); @@ -702,7 +754,7 @@ impl Expression { } } - instructions.push(Instruction::Call( + instructions.push(PreInstr::Instr(Instruction::Call( *&function_reg, if vararg { 0 } else { param_regs.len() as u16 }, if return_regs.len() == 0 { @@ -710,14 +762,14 @@ impl Expression { } else { return_regs.len() as u16 + 1 }, - )); + ))); (instructions, return_regs) } Expression::Literal(literal) => { let mut instructions = Vec::new(); let reg = scope.register_counter.next(); - instructions.push(Instruction::LoadK( + instructions.push(PreInstr::Instr(Instruction::LoadK( reg, state.get_constant(&match literal { Literal::Float(value) => Constant::Float(value.vm_number()), @@ -726,13 +778,13 @@ impl Expression { Literal::Bool(value) => Constant::Bool(LuaBool(*value)), Literal::Nil => Constant::Nil, }), - )); + ))); (instructions, vec![reg]) } Expression::TableConstructor(entries) => { let mut instructions = Vec::new(); let reg = scope.register_counter.next(); - instructions.push(Instruction::NewTable(reg)); + instructions.push(PreInstr::Instr(Instruction::NewTable(reg))); let mut counter = 1; for (i, (key, value)) in entries.iter().enumerate() { @@ -741,11 +793,11 @@ impl Expression { instructions.extend(instr); let (instr, value_regs) = value.kind.compile(state, scope, Some(1)); instructions.extend(instr); - instructions.push(Instruction::SetTable( + instructions.push(PreInstr::Instr(Instruction::SetTable( reg, *key_regs.first().unwrap(), *value_regs.first().unwrap(), - )); + ))); } else { let (instr, value_regs) = value.kind.compile( state, @@ -760,18 +812,19 @@ impl Expression { if value_regs.len() > 0 { let key_reg = scope.register_counter.next(); - instructions.push(Instruction::LoadK( + instructions.push(PreInstr::Instr(Instruction::LoadK( key_reg, state.get_constant(&Constant::Integer(LuaInteger(counter))), - )); - instructions.push(Instruction::SetTable( + ))); + instructions.push(PreInstr::Instr(Instruction::SetTable( reg, key_reg, *value_regs.first().unwrap(), - )); + ))); counter += 1; } else { - instructions.push(Instruction::SetList(reg, counter as u32)); + instructions + .push(PreInstr::Instr(Instruction::SetList(reg, counter as u32))); } } } @@ -786,11 +839,11 @@ impl Expression { instructions.extend(instr); let local = scope.register_counter.next(); - instructions.push(Instruction::GetTable( + instructions.push(PreInstr::Instr(Instruction::GetTable( local, *expr_regs.first().unwrap(), *index_regs.first().unwrap(), - )); + ))); (instructions, vec![local]) } @@ -801,10 +854,10 @@ impl Expression { let mut instructions = Vec::new(); let new_reg = scope.register_counter.new(); if expected_values == None { - instructions.push(Instruction::Vararg(new_reg, 0)); + instructions.push(PreInstr::Instr(Instruction::Vararg(new_reg, 0))); (instructions, Vec::new()) } else { - instructions.push(Instruction::Vararg(new_reg, 3)); + instructions.push(PreInstr::Instr(Instruction::Vararg(new_reg, 3))); (instructions, vec![new_reg]) } } diff --git a/src/lib.rs b/src/lib.rs index 403156a..f6d5cbe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ use thiserror::Error; use crate::{ ast::Block, + compile::process_pre_instrs, token_stream::{ TokenStream, TokenStreamError, lexer::{Error as TokenizerError, Token, tokenize}, @@ -139,7 +140,7 @@ pub fn compile( // dbg!(&constants); Ok(CompilationUnit { - instructions, + instructions: process_pre_instrs(instructions), state, constants, })