use Value

This commit is contained in:
numzero 2025-04-20 13:42:57 +03:00
parent 61c42ae790
commit 8559220aa3

View File

@ -1,6 +1,9 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use crate::{ast, types}; use crate::{
ast,
types::{self, Nil, Value},
};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct OpenFunction(Function); pub struct OpenFunction(Function);
@ -273,14 +276,14 @@ pub fn build(code: &ast::Function) -> OpenFunction {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Variable(RefCell<types::Value>); struct Variable(RefCell<Value>);
impl Variable { impl Variable {
fn get(&self) -> types::Value { fn get(&self) -> Value {
self.0.borrow().clone() self.0.borrow().clone()
} }
fn set(&self, value: types::Value) { fn set(&self, value: Value) {
*self.0.borrow_mut() = value *self.0.borrow_mut() = value
} }
} }
@ -307,28 +310,28 @@ impl RunContext {
} }
trait Eval { trait Eval {
fn eval(&self, ctx: &RunContext) -> types::Value; fn eval(&self, ctx: &RunContext) -> Value;
} }
impl Eval for ast::Constant { impl Eval for ast::Constant {
fn eval(&self, _ctx: &RunContext) -> types::Value { fn eval(&self, _ctx: &RunContext) -> Value {
match self { match self {
ast::Constant::Nil => types::Value::Nil, ast::Constant::Nil => Nil,
ast::Constant::Boolean(value) => types::Value::Boolean(*value), ast::Constant::Boolean(value) => Value::Boolean(*value),
ast::Constant::Number(value) => types::Value::Number(*value), ast::Constant::Number(value) => Value::Number(*value),
ast::Constant::String(value) => types::Value::String(value.clone()), ast::Constant::String(value) => Value::String(value.clone()),
} }
} }
} }
impl Eval for Location { impl Eval for Location {
fn eval(&self, ctx: &RunContext) -> types::Value { fn eval(&self, ctx: &RunContext) -> Value {
match self { match self {
Location::Variable { id } => ctx.var(*id).get(), Location::Variable { id } => ctx.var(*id).get(),
Location::Field { table, index } => { Location::Field { table, index } => {
let table = table.eval(ctx); let table = table.eval(ctx);
let index = index.eval(ctx); let index = index.eval(ctx);
let types::Value::Table(table) = table else { let Value::Table(table) = table else {
panic!("attempt to index a non-table"); panic!("attempt to index a non-table");
}; };
table.get(index) table.get(index)
@ -338,10 +341,10 @@ impl Eval for Location {
} }
impl Eval for Call { impl Eval for Call {
fn eval(&self, ctx: &RunContext) -> types::Value { fn eval(&self, ctx: &RunContext) -> Value {
let callee = self.callee.eval(ctx); let callee = self.callee.eval(ctx);
let args: Vec<_> = self.args.iter().map(|arg| arg.eval(ctx)).collect(); let args: Vec<_> = self.args.iter().map(|arg| arg.eval(ctx)).collect();
let types::Value::Function(f) = callee else { let Value::Function(f) = callee else {
panic!("attempt to call a non-function"); panic!("attempt to call a non-function");
}; };
f.call(&args) f.call(&args)
@ -349,7 +352,7 @@ impl Eval for Call {
} }
impl Eval for Function { impl Eval for Function {
fn eval(&self, ctx: &RunContext) -> types::Value { fn eval(&self, ctx: &RunContext) -> Value {
let upvalues: Vec<_> = self let upvalues: Vec<_> = self
.upvalues .upvalues
.iter() .iter()
@ -361,7 +364,7 @@ impl Eval for Function {
} }
impl Eval for Table { impl Eval for Table {
fn eval(&self, ctx: &RunContext) -> types::Value { fn eval(&self, ctx: &RunContext) -> Value {
let table = types::Table::default(); let table = types::Table::default();
for field in &self.fields { for field in &self.fields {
let key = field.key.eval(ctx); let key = field.key.eval(ctx);
@ -373,7 +376,7 @@ impl Eval for Table {
} }
impl Eval for Expression { impl Eval for Expression {
fn eval(&self, ctx: &RunContext) -> types::Value { fn eval(&self, ctx: &RunContext) -> Value {
match self { match self {
Expression::Constant(inner) => inner.eval(ctx), Expression::Constant(inner) => inner.eval(ctx),
Expression::Variable(inner) => inner.eval(ctx), Expression::Variable(inner) => inner.eval(ctx),
@ -385,7 +388,7 @@ impl Eval for Expression {
} }
impl Eval for Statement { impl Eval for Statement {
fn eval(&self, ctx: &RunContext) -> types::Value { fn eval(&self, ctx: &RunContext) -> Value {
match self { match self {
Statement::Assign { target, source } => { Statement::Assign { target, source } => {
let source = source.eval(ctx); let source = source.eval(ctx);
@ -394,7 +397,7 @@ impl Eval for Statement {
Location::Field { table, index } => { Location::Field { table, index } => {
let table = table.eval(ctx); let table = table.eval(ctx);
let index = index.eval(ctx); let index = index.eval(ctx);
let types::Value::Table(table) = table else { let Value::Table(table) = table else {
panic!("attempt to index a non-table"); panic!("attempt to index a non-table");
}; };
table.set(index, source) table.set(index, source)
@ -405,23 +408,21 @@ impl Eval for Statement {
call.eval(ctx); call.eval(ctx);
} }
}; };
types::Value::Nil Nil
} }
} }
fn new_var(value: &types::Value) -> VariableRef { fn new_var(value: &Value) -> VariableRef {
Rc::new(Variable(RefCell::new(value.clone()))) Rc::new(Variable(RefCell::new(value.clone())))
} }
impl Function { impl Function {
fn call(&self, upvalues: &[VariableRef], args: &[types::Value]) -> types::Value { fn call(&self, upvalues: &[VariableRef], args: &[Value]) -> Value {
assert_eq!(upvalues.len(), self.upvalues.len()); assert_eq!(upvalues.len(), self.upvalues.len());
assert_eq!(args.len(), self.args.len()); assert_eq!(args.len(), self.args.len());
let ctx = RunContext { let ctx = RunContext {
args: args.iter().map(new_var).collect(), args: args.iter().map(new_var).collect(),
locals: (0..self.locals.len()) locals: (0..self.locals.len()).map(|_| new_var(&Nil)).collect(),
.map(|_| new_var(&types::Value::Nil))
.collect(),
upvalues: upvalues.to_vec(), upvalues: upvalues.to_vec(),
}; };
for statement in &self.body { for statement in &self.body {
@ -432,7 +433,7 @@ impl Function {
} }
impl OpenFunction { impl OpenFunction {
pub fn call(&self, env: types::Value, args: &[types::Value]) -> types::Value { pub fn call(&self, env: Value, args: &[Value]) -> Value {
match self.0.upvalues.as_slice() { match self.0.upvalues.as_slice() {
[] => self.0.call(&[], args), [] => self.0.call(&[], args),
[up] if up.0 == "_ENV" => self.0.call(&[new_var(&env)], args), [up] if up.0 == "_ENV" => self.0.call(&[new_var(&env)], args),