From ca89d343c332b4759e1d71e167626a87e98736be Mon Sep 17 00:00:00 2001 From: numzero Date: Fri, 11 Apr 2025 19:33:00 +0300 Subject: [PATCH] Basic evaluation --- src/lib.rs | 1 + src/run.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/run.rs diff --git a/src/lib.rs b/src/lib.rs index 040ece4..7615628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod ast; +pub mod run; pub mod scope; pub mod types; diff --git a/src/run.rs b/src/run.rs new file mode 100644 index 0000000..d8f3b13 --- /dev/null +++ b/src/run.rs @@ -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) -> Value>, +} + +impl Function { + pub fn new(name: String, func: impl Fn(Vec) -> Value + 'static) -> Self { + Self { + name, + inner: Rc::new(func), + } + } + + pub fn call(&self, args: Vec) -> Value { + (self.inner)(args) + } +} + +impl Debug for Function { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "", self.name) + } +} + +#[derive(Debug, Clone, Default)] +pub struct Scope { + pub variables: HashMap, + pub functions: HashMap, +} + +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()) + } + } + } +}