Basic evaluation
This commit is contained in:
parent
6e908ad4a2
commit
ca89d343c3
|
|
@ -1,3 +1,4 @@
|
|||
pub mod ast;
|
||||
pub mod run;
|
||||
pub mod scope;
|
||||
pub mod types;
|
||||
|
|
|
|||
86
src/run.rs
Normal file
86
src/run.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use std::{collections::HashMap, fmt::Debug, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
ast::{Constant, Expression, Location},
|
||||
types::{Value, ValueInner},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Function {
|
||||
name: String,
|
||||
inner: Rc<dyn Fn(Vec<Value>) -> Value>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(name: String, func: impl Fn(Vec<Value>) -> Value + 'static) -> Self {
|
||||
Self {
|
||||
name,
|
||||
inner: Rc::new(func),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&self, args: Vec<Value>) -> Value {
|
||||
(self.inner)(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Function {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "<function {}>", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Scope {
|
||||
pub variables: HashMap<String, Value>,
|
||||
pub functions: HashMap<String, Function>,
|
||||
}
|
||||
|
||||
pub trait Eval {
|
||||
fn eval(&self, scope: &mut Scope) -> Value;
|
||||
}
|
||||
|
||||
impl Eval for Constant {
|
||||
fn eval(&self, _scope: &mut Scope) -> Value {
|
||||
match self {
|
||||
Constant::Nil => None,
|
||||
Constant::Boolean(value) => Some(ValueInner::Boolean(*value)),
|
||||
Constant::Number(value) => Some(ValueInner::Number(*value)),
|
||||
Constant::String(value) => Some(ValueInner::String(value.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for Location {
|
||||
fn eval(&self, scope: &mut Scope) -> Value {
|
||||
match self {
|
||||
Location::Variable { name } => scope.variables.get(name).cloned().flatten(),
|
||||
Location::Field { table, index } => {
|
||||
let table = table.eval(scope);
|
||||
let Some(ValueInner::Table(table)) = table else {
|
||||
panic!("attempt to index non-table value {table:?}")
|
||||
};
|
||||
let index = index.eval(scope);
|
||||
let Some(index) = index else {
|
||||
panic!("attempt to index with a nil value")
|
||||
};
|
||||
table.get(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for Expression {
|
||||
fn eval(&self, scope: &mut Scope) -> Value {
|
||||
match self {
|
||||
Expression::Constant(inner) => inner.eval(scope),
|
||||
Expression::Variable(inner) => inner.eval(scope),
|
||||
Expression::Call { callee, args } => {
|
||||
let Some(function) = scope.functions.get(callee).cloned() else {
|
||||
panic!("attempt to call non-existent function {callee}")
|
||||
};
|
||||
function.call(args.into_iter().map(|arg| arg.eval(scope)).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user