remove obsolete code

This commit is contained in:
numzero 2025-04-19 15:07:07 +03:00
parent 843c65ca16
commit 5138ada816
3 changed files with 0 additions and 361 deletions

View File

@ -1,5 +1,3 @@
pub mod ast; pub mod ast;
pub mod run;
pub mod scope;
pub mod twopass; pub mod twopass;
pub mod types; pub mod types;

View File

@ -1,296 +0,0 @@
use std::{collections::HashMap, fmt::Debug, rc::Rc};
use crate::{
ast::{Call, Constant, Expression, Location, Statement},
types::{Value, ValueInner},
};
#[derive(Clone)]
struct Function {
name: String,
inner: Rc<dyn Fn(&mut Scope, Vec<Value>) -> Value>,
}
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 {
variables: HashMap<String, ValueInner>,
functions: HashMap<String, Function>,
}
impl Scope {
pub fn get(&self, name: impl AsRef<str>) -> Value {
self.variables.get(name.as_ref()).cloned()
}
pub fn rawset(&mut self, name: String, value: Value) {
if let Some(value) = value {
self.variables.insert(name, value);
} else {
self.variables.remove(&name);
}
}
pub fn set(&mut self, name: impl AsRef<str>, value: &(impl Clone + Into<ValueInner>)) {
self.variables
.insert(name.as_ref().to_string(), value.clone().into());
}
pub fn add_fn(
&mut self,
name: impl Into<String>,
f: impl Fn(&mut Scope, Vec<Value>) -> Value + 'static,
) {
let name = name.into();
self.functions.insert(
name.clone(),
Function {
name,
inner: Rc::new(f),
},
);
}
}
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.get(name),
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 Call {
fn eval(&self, scope: &mut Scope) -> Value {
let Self { callee, args } = self;
let Some(function) = scope.functions.get(callee.as_str()).cloned() else {
panic!("attempt to call non-existent function {callee}")
};
let args = args.iter().map(|arg| arg.eval(scope)).collect();
(function.inner)(scope, args)
}
}
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(inner) => inner.eval(scope),
Expression::Function { .. } => todo!(),
}
}
}
pub trait Exec {
fn exec(&self, scope: &mut Scope);
}
impl Exec for Statement {
fn exec(&self, scope: &mut Scope) {
match self {
Statement::Assign { target, source } => {
let value = source.eval(scope);
match target {
Location::Variable { name } => {
scope.rawset(name.into(), value);
}
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.set(index, value);
}
};
}
Statement::Call(call) => {
call.eval(scope);
}
Statement::Local { .. } => todo!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{ast, types};
#[test]
fn test_consts() {
let mut scope = Scope::default();
assert_eq!(ast::Constant::Nil.eval(&mut scope), None);
assert_eq!(
ast::Constant::Boolean(true).eval(&mut scope),
Some(true.into())
);
assert_eq!(ast::Constant::Number(42).eval(&mut scope), Some(42.into()));
assert_eq!(
ast::Constant::String("foobar".into()).eval(&mut scope),
Some("foobar".into())
);
}
#[test]
fn test_vars() {
let mut scope = Scope::default();
let foo = ast::Location::Variable { name: "foo".into() };
let bar = ast::Location::Variable { name: "bar".into() };
assert_eq!(foo.eval(&mut scope), None);
assert_eq!(bar.eval(&mut scope), None);
scope.set("bar", &42);
assert_eq!(foo.eval(&mut scope), None);
assert_eq!(bar.eval(&mut scope), Some(42.into()));
}
#[test]
fn test_fields() {
let mut scope = Scope::default();
let loc = ast::Location::Field {
table: Box::new(ast::Expression::Variable(ast::Location::Variable {
name: "foo".into(),
})),
index: Box::new(ast::Expression::Constant(ast::Constant::String(
"bar".into(),
))),
};
let foo = types::Table::default();
let bar = types::Table::default();
scope.set("foo", &foo);
assert_eq!(loc.eval(&mut scope), None);
scope.set("bar", &bar);
assert_eq!(loc.eval(&mut scope), None);
bar.set("foo".into(), Some(666.into()));
assert_eq!(loc.eval(&mut scope), None);
foo.set("bar".into(), Some(42.into()));
assert_eq!(loc.eval(&mut scope), Some(42.into()));
}
#[test]
fn test_call() {
let mut scope = Scope::default();
scope.add_fn("sqr", |_, args| {
let [arg] = args.as_slice() else {
panic!("exactly one argument expected");
};
let Some(ValueInner::Number(arg)) = arg else {
panic!("number expected");
};
Some(ValueInner::Number(arg * arg))
});
assert_eq!(
ast::Expression::Call(ast::Call {
callee: "sqr".into(),
args: vec![ast::Expression::Constant(ast::Constant::Number(7))],
})
.eval(&mut scope),
Some(49.into())
);
}
#[test]
fn test_var_assign() {
let mut scope = Scope::default();
assert_eq!(scope.get("foo"), None);
assert_eq!(scope.get("bar"), None);
ast::Statement::Assign {
target: ast::Location::Variable { name: "foo".into() },
source: Box::new(ast::Expression::Constant(ast::Constant::Number(42))),
}
.exec(&mut scope);
assert_eq!(scope.get("foo"), Some(42.into()));
assert_eq!(scope.get("bar"), None);
}
#[test]
fn test_table_assign() {
let mut scope = Scope::default();
let foo = types::Table::default();
let bar = types::Table::default();
scope.set("foo", &foo);
scope.set("bar", &bar);
assert_eq!(foo.get("foo".into()), None);
assert_eq!(foo.get("bar".into()), None);
assert_eq!(bar.get("foo".into()), None);
assert_eq!(bar.get("bar".into()), None);
ast::Statement::Assign {
target: ast::Location::Field {
table: Box::new(ast::Expression::Variable(ast::Location::Variable {
name: "foo".into(),
})),
index: Box::new(ast::Expression::Constant(ast::Constant::String(
"bar".into(),
))),
},
source: Box::new(ast::Expression::Constant(ast::Constant::Number(42))),
}
.exec(&mut scope);
assert_eq!(foo.get("foo".into()), None);
assert_eq!(foo.get("bar".into()), Some(42.into()));
assert_eq!(bar.get("foo".into()), None);
assert_eq!(bar.get("bar".into()), None);
}
#[test]
fn test_call_statement() {
let mut scope = Scope::default();
scope.add_fn("set", |scope, args| {
let [key, value] = args.as_slice() else {
panic!("exactly two arguments expected");
};
let Some(ValueInner::String(key)) = key else {
panic!("string expected");
};
scope.rawset(key.clone(), value.clone());
None
});
assert_eq!(scope.get("foo"), None);
assert_eq!(scope.get("bar"), None);
ast::Statement::Call(ast::Call {
callee: "set".into(),
args: vec![
ast::Expression::Constant(ast::Constant::String("foo".into())),
ast::Expression::Constant(ast::Constant::Number(42)),
],
})
.exec(&mut scope);
assert_eq!(scope.get("foo"), Some(42.into()));
assert_eq!(scope.get("bar"), None);
}
}

View File

@ -1,63 +0,0 @@
use std::{
cell::RefCell,
collections::{hash_map::Entry, HashMap},
rc::Rc,
};
use crate::types::Value;
#[derive(Debug, Clone, Default)]
pub struct Variable(Rc<RefCell<Value>>);
impl Variable {
pub fn get(&self) -> Value {
self.0.borrow().clone()
}
pub fn set(&self, value: Value) {
*self.0.borrow_mut() = value;
}
}
#[derive(Debug, Clone, Default)]
struct ScopeInner {
parent: Option<Scope>,
locals: HashMap<String, Variable>,
}
#[derive(Debug, Clone, Default)]
pub struct Scope(Rc<RefCell<ScopeInner>>);
impl Scope {
pub fn new() -> Self {
Self::default()
}
pub fn nested(&self) -> Self {
Self(Rc::new(RefCell::new(ScopeInner {
parent: Some(self.clone()),
..Default::default()
})))
}
pub fn add(&self, name: String) {
self.0.borrow_mut().locals.insert(name, Variable::default());
}
pub fn get(&self, name: String) -> Variable {
let mut this = self.0.borrow_mut();
let parent = this.parent.clone();
match this.locals.entry(name) {
Entry::Occupied(var) => var.get().clone(),
Entry::Vacant(var) => {
if let Some(parent) = parent {
let name = var.into_key();
drop(this);
parent.get(name)
} else {
var.insert(Variable::default()).clone()
}
}
}
}
}