Add possibility to execute code at any stage

This commit is contained in:
Sofia 2026-03-16 18:38:04 +02:00
parent 1091f341b9
commit 093e96f8b2
4 changed files with 94 additions and 32 deletions

View File

@ -1,4 +1,4 @@
local b = 5 global b = 5
function add(x) function add(x)
return function (y) return function (y)

View File

@ -73,8 +73,8 @@ impl LocalCounter {
} }
impl Block { impl Block {
pub fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> { pub fn find_constants(&self, scope: &mut Scope, constants: Vec<Constant>) -> HashSet<Constant> {
let mut constants = HashSet::new(); let mut constants = constants.iter().cloned().collect::<HashSet<_>>();
let mut inner_scope = scope.clone(); let mut inner_scope = scope.clone();
@ -132,7 +132,7 @@ impl Statement {
Statement::If(cond, then) => { Statement::If(cond, then) => {
let mut constants = HashSet::new(); let mut constants = HashSet::new();
constants.extend(cond.kind.find_constants(scope)); constants.extend(cond.kind.find_constants(scope));
constants.extend(then.find_constants(scope)); constants.extend(then.find_constants(scope, Vec::new()));
constants constants
} }
Statement::Expression(expr) => expr.kind.find_constants(scope), Statement::Expression(expr) => expr.kind.find_constants(scope),
@ -303,7 +303,7 @@ impl Expression {
constants constants
} }
Expression::UnOp(_, expr) => expr.kind.find_constants(scope), Expression::UnOp(_, expr) => expr.kind.find_constants(scope),
Expression::FunctionDefinition(_, block) => block.find_constants(scope), Expression::FunctionDefinition(_, block) => block.find_constants(scope, Vec::new()),
Expression::FunctionCall(expr, params) => { Expression::FunctionCall(expr, params) => {
let mut constants = HashSet::new(); let mut constants = HashSet::new();
constants.extend(expr.kind.find_constants(scope)); constants.extend(expr.kind.find_constants(scope));

View File

@ -40,40 +40,53 @@ impl RustFunction for Print {
} }
} }
fn main() { fn compile(
text: &str,
constants: Vec<vm::Constant>,
prototypes: Vec<Vec<vm::Instruction>>,
) -> (Vec<vm::Instruction>, compile::State, Vec<vm::Constant>) {
let file_path = PathBuf::from("../examples/test.lua"); let file_path = PathBuf::from("../examples/test.lua");
let tokens = tokenize(TEST).unwrap(); let tokens = tokenize(text).unwrap();
let mut stream = TokenStream::from(&file_path, &tokens); let mut stream = TokenStream::from(&file_path, &tokens);
dbg!(&tokens); // dbg!(&tokens);
let chunk = stream.parse::<Block>().unwrap(); let chunk = stream.parse::<Block>().unwrap();
stream.expect(Token::Eof).unwrap(); stream.expect(Token::Eof).unwrap();
dbg!(&chunk); // dbg!(&chunk);
let constants = chunk let constants = chunk
.find_constants(&mut Default::default()) .find_constants(&mut Default::default(), constants)
.into_iter() .into_iter()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
dbg!(&constants);
let mut state = compile::State { let mut state = compile::State {
constants: constants.clone(), constants: constants.clone(),
prototypes: Vec::new(), prototypes,
}; };
let mut scope = Default::default(); let mut scope = Default::default();
let instructions = chunk.compile(&mut state, &mut scope); let instructions = chunk.compile(&mut state, &mut scope);
(instructions, state, constants)
}
fn main() {
let (instructions, state, constants) = compile(TEST, Vec::new(), Vec::new());
dbg!(&instructions);
dbg!(&constants);
let mut vm = VirtualMachine { let mut vm = VirtualMachine {
environment: Default::default(), environment: Default::default(),
constants, constants: constants.clone(),
prototypes: Default::default(), prototypes: Default::default(),
proto_counter: 0, proto_counter: 0,
}; };
let chunk_id = vm.new_prototype(instructions); let chunk_id = vm.new_prototype(instructions);
for prototype in state.prototypes { for prototype in &state.prototypes {
vm.new_prototype(prototype); vm.new_prototype(prototype.clone());
} }
dbg!(&vm.prototypes); dbg!(&vm.prototypes);
@ -90,7 +103,24 @@ fn main() {
let mut run = closure.run(Vec::new()); let mut run = closure.run(Vec::new());
while run.next().unwrap().is_none() {} while run.next().unwrap().is_none() {
let (instructions, state, constants) =
compile("print(b)", constants.clone(), state.prototypes.clone());
// dbg!(&instructions);
let mut new_run = run.execute(instructions, state, constants);
while {
match new_run.next() {
Ok(Some(_)) => false,
Ok(None) => true,
Err(e) => {
print!("Error: {}", e);
false
}
}
} {}
}
dbg!(&vm.environment.borrow().globals); dbg!(&vm.environment.borrow().globals);
} }

View File

@ -2,7 +2,10 @@ use thiserror::Error;
use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
use crate::ast::{BinaryOperator, LuaNumber, UnaryOperator}; use crate::{
ast::{BinaryOperator, LuaNumber, UnaryOperator},
compile,
};
pub type VMNumber = u64; pub type VMNumber = u64;
@ -106,6 +109,8 @@ pub enum RuntimeError {
InvalidOperand(UnaryOperator, Value), InvalidOperand(UnaryOperator, Value),
#[error("Tried calling a non-function: {0:?}")] #[error("Tried calling a non-function: {0:?}")]
TriedCallingNonFunction(Value), TriedCallingNonFunction(Value),
#[error("Global not found: {0:?}")]
GlobalNotFound(Option<Constant>),
#[error("{0}")] #[error("{0}")]
Custom(String), Custom(String),
} }
@ -321,6 +326,44 @@ impl ClosureRunner {
} }
} }
fn close_upvalues(&self) -> HashMap<u16, Rc<RefCell<Value>>> {
let highest_upvalue = self
.closure
.upvalues
.iter()
.map(|(v, _)| *v)
.max()
.unwrap_or(0);
let mut upvalues = self.closure.upvalues.clone();
for (reg, value) in &self.stack {
upvalues.insert(reg + highest_upvalue + 1, value.clone());
}
upvalues
}
pub fn execute(
&mut self,
instructions: Vec<Instruction>,
state: compile::State,
constants: Vec<Constant>,
) -> ClosureRunner {
let mut vm = self.closure.vm.clone();
vm.constants = constants;
let proto_id = vm.new_prototype(instructions);
for prototype in state.prototypes {
vm.new_prototype(prototype);
}
let closure = Closure {
vm,
prototype: proto_id,
environment: self.closure.environment.clone(),
upvalues: self.close_upvalues(),
};
closure.run(Vec::new())
}
pub fn next(&mut self) -> Result<Option<Vec<Value>>, RuntimeError> { pub fn next(&mut self) -> Result<Option<Vec<Value>>, RuntimeError> {
if let Some(inner) = &mut self.inner { if let Some(inner) = &mut self.inner {
match inner.next() { match inner.next() {
@ -408,7 +451,9 @@ impl ClosureRunner {
if let Some(global) = glob { if let Some(global) = glob {
self.set_stack(*reg, global.clone()); self.set_stack(*reg, global.clone());
} else { } else {
todo!("Global not found: {:?}", constants.get(*global as usize)) return Err(RuntimeError::GlobalNotFound(
constants.get(*global as usize).cloned(),
));
} }
} }
Instruction::GetUpVal(reg, upvalreg) => { Instruction::GetUpVal(reg, upvalreg) => {
@ -514,26 +559,13 @@ impl ClosureRunner {
} }
Instruction::Close(_) => {} Instruction::Close(_) => {}
Instruction::Closure(reg, protok) => { Instruction::Closure(reg, protok) => {
let highest_upvalue = self
.closure
.upvalues
.iter()
.map(|(v, _)| *v)
.max()
.unwrap_or(0);
let mut upvalues = self.closure.upvalues.clone();
for (reg, value) in &self.stack {
upvalues.insert(reg + highest_upvalue + 1, value.clone());
}
self.set_stack( self.set_stack(
*reg, *reg,
Value::Function(Closure { Value::Function(Closure {
vm: self.closure.vm.clone(), vm: self.closure.vm.clone(),
prototype: *protok, prototype: *protok,
environment: self.closure.environment.clone(), environment: self.closure.environment.clone(),
upvalues, upvalues: self.close_upvalues(),
}), }),
); );
} }