Add SETTABLE

This commit is contained in:
Sofia 2026-03-17 18:33:52 +02:00
parent 8e57def387
commit 83bccbbf4d
2 changed files with 70 additions and 1 deletions

View File

@ -30,6 +30,10 @@ impl RustFunction for Max {
_ => Ok(vec![vm::Value::Nil]), _ => Ok(vec![vm::Value::Nil]),
} }
} }
fn as_indexable(&self) -> String {
"std::max".to_owned()
}
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct Print; pub struct Print;
@ -38,6 +42,10 @@ impl RustFunction for Print {
println!("{:?}", parameters); println!("{:?}", parameters);
Ok(Vec::new()) Ok(Vec::new())
} }
fn as_indexable(&self) -> String {
"std::print".to_owned()
}
} }
fn compile( fn compile(

View File

@ -1,6 +1,12 @@
use thiserror::Error; use thiserror::Error;
use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, rc::Rc}; use std::{
cell::{RefCell, RefMut},
collections::HashMap,
fmt::Debug,
hash::Hash,
rc::Rc,
};
use crate::{ use crate::{
ast::{BinaryOperator, LuaNumber, UnaryOperator}, ast::{BinaryOperator, LuaNumber, UnaryOperator},
@ -43,6 +49,8 @@ pub enum Instruction {
GetUpVal(u16, u16), GetUpVal(u16, u16),
/// U[B] := R(A) /// U[B] := R(A)
SetUpVal(u16, u16), SetUpVal(u16, u16),
/// R(A)[R(B)] := R(C)
SetTable(u16, u16, u16),
/// R(A) := {} /// R(A) := {}
NewTable(u16), NewTable(u16),
/// R(A) := R(B) + R(C) /// R(A) := R(B) + R(C)
@ -83,6 +91,9 @@ impl Debug for Instruction {
Instruction::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1), Instruction::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1),
Instruction::GetUpVal(arg0, arg1) => write!(f, "GETUPVAL {} {}", arg0, arg1), Instruction::GetUpVal(arg0, arg1) => write!(f, "GETUPVAL {} {}", arg0, arg1),
Instruction::SetUpVal(arg0, arg1) => write!(f, "SETUPVAL {} {}", arg0, arg1), Instruction::SetUpVal(arg0, arg1) => write!(f, "SETUPVAL {} {}", arg0, arg1),
Instruction::SetTable(arg0, arg1, arg2) => {
write!(f, "SETTABLE {} {} {}", arg0, arg1, arg2)
}
Instruction::NewTable(arg0) => write!(f, "NEWTABLE {}", arg0), Instruction::NewTable(arg0) => write!(f, "NEWTABLE {}", arg0),
Instruction::Jmp(arg0) => write!(f, "JMP {}", arg0), Instruction::Jmp(arg0) => write!(f, "JMP {}", arg0),
Instruction::Test(arg0, arg1, arg2) => write!(f, "TEST {} {} {}", arg0, arg1, arg2), Instruction::Test(arg0, arg1, arg2) => write!(f, "TEST {} {} {}", arg0, arg1, arg2),
@ -114,6 +125,8 @@ pub enum RuntimeError {
TriedCallingNonFunction(Value), TriedCallingNonFunction(Value),
#[error("Global not found: {0:?}")] #[error("Global not found: {0:?}")]
GlobalNotFound(Option<Constant>), GlobalNotFound(Option<Constant>),
#[error("Unable to index tables with {0:?}")]
InvalidTableIndex(Value),
#[error("{0}")] #[error("{0}")]
Custom(String), Custom(String),
} }
@ -133,6 +146,21 @@ pub enum Value {
Table(HashMap<IndexableValue, Value>), Table(HashMap<IndexableValue, Value>),
} }
impl Value {
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError> {
match self {
Value::String(value) => Ok(IndexableValue::String(value)),
Value::Number(value) => Ok(IndexableValue::Number(value)),
Value::RustFunction(value) => {
Ok(IndexableValue::RustFunction(value.borrow().as_indexable()))
}
Value::Function(closure) => Ok(IndexableValue::Function(closure.prototype)),
Value::Nil => Err(RuntimeError::InvalidTableIndex(self)),
Value::Table(_) => Err(RuntimeError::InvalidTableIndex(self)),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)] #[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum IndexableValue { pub enum IndexableValue {
String(String), String(String),
@ -272,6 +300,7 @@ impl Debug for Value {
pub trait RustFunction: Debug { pub trait RustFunction: Debug {
fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError>; fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError>;
fn as_indexable(&self) -> String;
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -494,6 +523,38 @@ impl ClosureRunner {
.map(|v| v.borrow().clone()) .map(|v| v.borrow().clone())
.unwrap_or(Value::Nil); .unwrap_or(Value::Nil);
} }
Instruction::SetTable(tablereg, indexreg, valuereg) => {
let table = self.stack.get(tablereg);
match table {
Some(value) => {
let mut table = value.borrow_mut();
if let Value::Table(table) = &mut *table {
let index_value = self
.stack
.get(indexreg)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
.as_indexable()?;
let value = self
.stack
.get(valuereg)
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil);
match value {
Value::Nil => {
table.remove(&index_value);
}
_ => {
table.insert(index_value, value);
}
}
} else {
todo!()
}
}
None => todo!(),
}
}
Instruction::NewTable(reg) => { Instruction::NewTable(reg) => {
self.set_stack(*reg, Value::Table(HashMap::new())); self.set_stack(*reg, Value::Table(HashMap::new()));
} }