From f2cfb03fa13abed81b38254c763ceff2bdc634b5 Mon Sep 17 00:00:00 2001 From: minneelyyyy Date: Fri, 18 Oct 2024 02:21:31 -0400 Subject: [PATCH] function, object, parser, and executer rewrites --- src/executor.rs | 248 +++++++++++++------------------ src/function.rs | 79 ++++++++++ src/lib.rs | 130 +++++++++-------- src/main.rs | 2 +- src/parser.rs | 370 +++++++++++++++++++---------------------------- src/tokenizer.rs | 26 +--- 6 files changed, 401 insertions(+), 454 deletions(-) create mode 100644 src/function.rs diff --git a/src/executor.rs b/src/executor.rs index 0c22c1a..0e4f4ee 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,11 +1,10 @@ -use super::{Value, Type, Object, Evaluation, Function}; +use super::{Value, Type, Object}; use super::parser::{ParseTree, ParseError}; use std::collections::HashMap; -use std::borrow::Cow; use std::fmt::Display; use std::error::Error; -use std::io::{self, Read, Write}; +use std::io; #[derive(Debug)] pub enum RuntimeError { @@ -47,52 +46,62 @@ impl Error for RuntimeError {} /// Executes an input of ParseTrees pub struct Executor<'a, I> where - I: Iterator>, + I: Iterator> { - exprs: I, + exprs: &'a mut I, globals: HashMap, - stdout: Box, - stdin: Box, + locals: HashMap, } impl<'a, I> Executor<'a, I> where I: Iterator>, { - pub fn new(exprs: I) -> Self { + pub fn new(exprs: &'a mut I) -> Self { Self { exprs, globals: HashMap::new(), - stdout: Box::new(io::stdout()), - stdin: Box::new(io::stdin()), + locals: HashMap::new(), } } - pub fn stdout(self, writer: impl Write + 'a) -> Self { - Self { - exprs: self.exprs, - globals: self.globals, - stdout: Box::new(writer), - stdin: self.stdin, - } + pub fn globals(mut self, globals: HashMap) -> Self { + self.globals = globals; + self } - pub fn stdin(self, reader: impl Read + 'a) -> Self { - Self { - exprs: self.exprs, - globals: self.globals, - stdout: self.stdout, - stdin: Box::new(reader), - } + pub fn _add_global(mut self, k: String, v: Object) -> Self { + self.globals.insert(k, v); + self } - fn exec( - &mut self, - tree: Box, - locals: &mut Cow>>) -> Result - { + pub fn locals(mut self, locals: HashMap) -> Self { + self.locals = locals; + self + } + + pub fn add_local(mut self, k: String, v: Object) -> Self { + self.locals.insert(k, v); + self + } + + fn _get_object(&self, ident: &String) -> Result<&Object, RuntimeError> { + self.locals.get(ident).or(self.globals.get(ident)) + .ok_or(RuntimeError::VariableUndefined(ident.clone())) + } + + fn get_object_mut(&mut self, ident: &String) -> Result<&mut Object, RuntimeError> { + self.locals.get_mut(ident).or(self.globals.get_mut(ident)) + .ok_or(RuntimeError::VariableUndefined(ident.clone())) + } + + fn variable_exists(&self, ident: &String) -> bool { + self.locals.contains_key(ident) || self.globals.contains_key(ident) + } + + pub fn exec(&mut self, tree: Box) -> Result { match *tree { - ParseTree::Add(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Add(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x + y as f64)), (Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 + y)), @@ -129,14 +138,14 @@ where }, (x, y) => Err(RuntimeError::NoOverloadForTypes("+".into(), vec![x, y])) }, - ParseTree::Sub(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Sub(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x - y as f64)), (Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 - y)), (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("-".into(), vec![x, y])) }, - ParseTree::Mul(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Mul(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * y as f64)), (Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 * y)), @@ -144,28 +153,28 @@ where (Value::String(x), Value::Int(y)) => Ok(Value::String(x.repeat(y as usize))), (x, y) => Err(RuntimeError::NoOverloadForTypes("*".into(), vec![x, y])) }, - ParseTree::Div(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Div(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x / y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x / y as f64)), (Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 / y)), (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x / y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("*".into(), vec![x, y])) }, - ParseTree::Exp(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Exp(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x.pow(y as u32))), (Value::Int(x), Value::Float(y)) => Ok(Value::Float((x as f64).powf(y))), (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x.powf(y as f64))), (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x.powf(y))), (x, y) => Err(RuntimeError::NoOverloadForTypes("**".into(), vec![x, y])), }, - ParseTree::Mod(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Mod(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x % y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x % y as f64)), (Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 % y)), (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x % y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("%".into(), vec![x, y])), }, - ParseTree::EqualTo(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::EqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x == y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 == y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x == y as f64)), @@ -174,7 +183,7 @@ where (Value::String(x), Value::String(y)) => Ok(Value::Bool(x == y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("==".into(), vec![x, y])), }, - ParseTree::NotEqualTo(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::NotEqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x != y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 != y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x != y as f64)), @@ -183,80 +192,83 @@ where (Value::String(x), Value::String(y)) => Ok(Value::Bool(x != y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("!=".into(), vec![x, y])), }, - ParseTree::GreaterThan(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::GreaterThan(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x > y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 > y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x > y as f64)), (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x > y)), (x, y) => Err(RuntimeError::NoOverloadForTypes(">".into(), vec![x, y])), }, - ParseTree::GreaterThanOrEqualTo(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::GreaterThanOrEqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x >= y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 >= y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x >= y as f64)), (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x >= y)), (x, y) => Err(RuntimeError::NoOverloadForTypes(">=".into(), vec![x, y])), }, - ParseTree::LessThan(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::LessThan(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x < y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool((x as f64) < y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x < y as f64)), (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x < y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("<".into(), vec![x, y])), }, - ParseTree::LessThanOrEqualTo(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::LessThanOrEqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x <= y)), (Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 <= y)), (Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x <= y as f64)), (Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x <= y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("<=".into(), vec![x, y])), }, - ParseTree::Not(x) => match self.exec(x, locals)? { + ParseTree::Not(x) => match self.exec(x)? { Value::Bool(x) => Ok(Value::Bool(!x)), x => Err(RuntimeError::NoOverloadForTypes("not".into(), vec![x])) }, - ParseTree::And(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::And(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x && y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("&&".into(), vec![x, y])) }, - ParseTree::Or(x, y) => match (self.exec(x, locals)?, self.exec(y, locals)?) { + ParseTree::Or(x, y) => match (self.exec(x)?, self.exec(y)?) { (Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x || y)), (x, y) => Err(RuntimeError::NoOverloadForTypes("||".into(), vec![x, y])) }, ParseTree::Equ(ident, body, scope) => { - if self.globals.contains_key(&ident) || locals.contains_key(&ident) { + if self.variable_exists(&ident) { Err(RuntimeError::ImmutableError(ident.clone())) } else { - let locals = locals.to_mut(); - let value = self.exec(body, &mut Cow::Borrowed(&locals))?; - locals.insert(ident.clone(), Object::Variable(Evaluation::Computed(value))); + let value = self.exec(body)?; - self.exec(scope, &mut Cow::Borrowed(&locals)) + Executor::new(self.exprs) + .globals(self.globals.clone()) + .locals(self.locals.clone()) + .add_local(ident, Object::value(value, self.globals.to_owned(), self.locals.to_owned())) + .exec(scope) } }, ParseTree::LazyEqu(ident, body, scope) => { - if self.globals.contains_key(&ident) || locals.contains_key(&ident) { + if self.variable_exists(&ident) { Err(RuntimeError::ImmutableError(ident.clone())) } else { - let locals = locals.to_mut(); - locals.insert(ident.clone(), Object::Variable(Evaluation::Uncomputed(body))); - - self.exec(scope, &mut Cow::Borrowed(&locals)) + Executor::new(self.exprs) + .globals(self.globals.clone()) + .locals(self.locals.clone()) + .add_local(ident, Object::variable(*body, self.globals.to_owned(), self.locals.to_owned())) + .exec(scope) } }, ParseTree::FunctionDefinition(func, scope) => { - let locals = locals.to_mut(); - - locals.insert(func.name.clone().unwrap(), Object::Function(func)); - - self.exec(scope, &mut Cow::Borrowed(&locals)) + Executor::new(self.exprs) + .globals(self.globals.clone()) + .locals(self.locals.clone()) + .add_local(func.name().unwrap().to_string(), Object::function(func, self.globals.clone(), self.locals.clone())) + .exec(scope) }, ParseTree::Compose(x, y) => { - self.exec(x, locals)?; - self.exec(y, locals) + self.exec(x)?; + self.exec(y) }, - ParseTree::Id(x) => self.exec(x, locals), - ParseTree::If(cond, body) => if match self.exec(cond, locals)? { + ParseTree::Id(x) => self.exec(x), + ParseTree::If(cond, body) => if match self.exec(cond)? { Value::Float(f) => f != 0.0, Value::Int(i) => i != 0, Value::Bool(b) => b, @@ -265,85 +277,42 @@ where Value::Nil => false, x => return Err(RuntimeError::NoOverloadForTypes("?".into(), vec![x])), } { - self.exec(body, locals) + self.exec(body) } else { Ok(Value::Nil) }, - ParseTree::IfElse(cond, istrue, isfalse) => if match self.exec(cond, locals)? { + ParseTree::IfElse(cond, istrue, isfalse) => if match self.exec(cond)? { Value::Float(f) => f != 0.0, Value::Int(i) => i != 0, Value::Bool(b) => b, Value::String(s) => !s.is_empty(), Value::Array(_, vec) => !vec.is_empty(), Value::Nil => false, - x => return Err(RuntimeError::NoOverloadForTypes("?".into(), vec![x])), + x => return Err(RuntimeError::NoOverloadForTypes("??".into(), vec![x])), } { - self.exec(istrue, locals) + self.exec(istrue) } else { - self.exec(isfalse, locals) + self.exec(isfalse) }, ParseTree::FunctionCall(ident, args) => { - let obj = locals.get(&ident).or(self.globals.get(&ident)).cloned(); + let args = args.into_iter().map(|x| Object::variable(x, self.globals.clone(), self.locals.clone())).collect(); + let obj = self.get_object_mut(&ident)?; + let v = obj.eval()?; - match obj { - Some(Object::Function(f)) => { - assert!(f.arg_names.is_some()); - - let loc = std::iter::zip(std::iter::zip(f.t.1.clone(), f.arg_names.clone().unwrap()), args) - .map(|((t, name), tree)| { - let v = self.exec(Box::new(tree), locals)?; - - if t != v.get_type() { - return Err(RuntimeError::TypeError(t, v.get_type())); - } - - match v { - Value::Function(f) => Ok((Object::Function(f), name)), - v => Ok((Object::Variable(Evaluation::Computed(v)), name)), - } - }).collect::, RuntimeError>>()?; - - let mut locals = f.locals.clone(); - - for (obj, name) in loc.into_iter() { - locals.insert(name, obj); - } - - // the parser previously placed a copy of this function with the same name and type - // into it's locals, however it doesn't have a body. This would cause a - // panic later when attempting to execute the function during recursive calls. - // we fix this by replacing it with a *complete* copy of the function. - // also only do this if the function has a name in the first place, otherwise it panics with lambdas. - if let Some(name) = f.name.clone() { - locals.insert(name, Object::Function(f.clone())); - } - - self.exec(f.body.unwrap(), &mut Cow::Borrowed(&Box::new(locals))) - } + match v { + Value::Function(mut f) => f.call(obj.globals(), obj.locals(), args), _ => Err(RuntimeError::FunctionUndefined(ident.clone())) } }, ParseTree::Variable(ident) => { - let locals = locals.to_mut(); + let obj = self.get_object_mut(&ident)?; - let obj = locals.get(&ident).or(self.globals.get(&ident)).cloned(); + let v = obj.eval()?; - if let Some(Object::Variable(eval)) = obj { - match eval { - Evaluation::Computed(v) => Ok(v), - Evaluation::Uncomputed(tree) => { - let v = self.exec(tree, &mut Cow::Borrowed(&locals))?; - locals.insert(ident, Object::Variable(Evaluation::Computed(v.clone()))); - - Ok(v) - } - } - } else { - Err(RuntimeError::VariableUndefined(ident.clone())) - } + Ok(v) }, ParseTree::Constant(value) => Ok(value), - ParseTree::IntCast(x) => match self.exec(x, locals)? { + ParseTree::IntCast(x) => match self.exec(x)? { Value::Int(x) => Ok(Value::Int(x)), Value::Float(x) => Ok(Value::Int(x as i64)), Value::Bool(x) => Ok(Value::Int(if x { 1 } else { 0 })), @@ -353,7 +322,7 @@ where } x => Err(RuntimeError::NoOverloadForTypes("int".into(), vec![x])), }, - ParseTree::FloatCast(x) => match self.exec(x, locals)? { + ParseTree::FloatCast(x) => match self.exec(x)? { Value::Int(x) => Ok(Value::Float(x as f64)), Value::Float(x) => Ok(Value::Float(x)), Value::Bool(x) => Ok(Value::Float(if x { 1.0 } else { 0.0 })), @@ -363,7 +332,7 @@ where } x => Err(RuntimeError::NoOverloadForTypes("float".into(), vec![x])), }, - ParseTree::BoolCast(x) => match self.exec(x, locals)? { + ParseTree::BoolCast(x) => match self.exec(x)? { Value::Int(x) => Ok(Value::Bool(x != 0)), Value::Float(x) => Ok(Value::Bool(x != 0.0)), Value::Bool(x) => Ok(Value::Bool(x)), @@ -371,49 +340,38 @@ where Value::Array(_, vec) => Ok(Value::Bool(!vec.is_empty())), x => Err(RuntimeError::NoOverloadForTypes("bool".into(), vec![x])), }, - ParseTree::StringCast(x) => Ok(Value::String(format!("{}", self.exec(x, locals)?))), - ParseTree::Print(x) => match self.exec(x, locals)? { + ParseTree::StringCast(x) => Ok(Value::String(format!("{}", self.exec(x)?))), + ParseTree::Print(x) => match self.exec(x)? { Value::String(s) => { - writeln!(self.stdout, "{s}").map_err(|e| RuntimeError::IO(e))?; + println!("{s}"); Ok(Value::Nil) } x => { - writeln!(self.stdout, "{x}").map_err(|e| RuntimeError::IO(e))?; + println!("{x}"); Ok(Value::Nil) } } ParseTree::LambdaDefinition(func) => Ok(Value::Function(func)), ParseTree::NonCall(name) => { - let locals = locals.to_mut(); + let obj = self.get_object_mut(&name)?; - let func = locals.get(&name).ok_or(RuntimeError::FunctionUndefined(name.clone())).cloned()?; + let v = obj.eval()?; - match func { - Object::Function(func) => Ok(Value::Function(func.clone())), - Object::Variable(var) => match var { - Evaluation::Computed(value) => Ok(value.clone()), - Evaluation::Uncomputed(tree) => { - let v = self.exec(tree, &mut Cow::Borrowed(&locals))?; - locals.insert(name, Object::Variable(Evaluation::Computed(v.clone()))); - - Ok(v) - } - } - } + Ok(v) } - ParseTree::Head(x) => match self.exec(x, locals)? { + ParseTree::Head(x) => match self.exec(x)? { Value::Array(_, x) => Ok(x.first().ok_or(RuntimeError::EmptyArray)?.clone()), t => Err(RuntimeError::NoOverloadForTypes("head".into(), vec![t])) }, - ParseTree::Tail(x) => match self.exec(x, locals)? { + ParseTree::Tail(x) => match self.exec(x)? { Value::Array(t, x) => Ok(Value::Array(t, if x.len() > 0 { x[1..].to_vec() } else { vec![] })), t => Err(RuntimeError::NoOverloadForTypes("tail".into(), vec![t])) }, - ParseTree::Init(x) => match self.exec(x, locals)? { + ParseTree::Init(x) => match self.exec(x)? { Value::Array(t, x) => Ok(Value::Array(t, if x.len() > 0 { x[..x.len() - 1].to_vec() } else { vec![] })), t => Err(RuntimeError::NoOverloadForTypes("init".into(), vec![t])) }, - ParseTree::Fini(x) => match self.exec(x, locals)? { + ParseTree::Fini(x) => match self.exec(x)? { Value::Array(_, x) => Ok(x.last().ok_or(RuntimeError::EmptyArray)?.clone()), t => Err(RuntimeError::NoOverloadForTypes("fini".into(), vec![t])) }, @@ -428,7 +386,7 @@ impl<'a, I: Iterator>> Iterator for Executo let expr = self.exprs.next(); match expr { - Some(Ok(expr)) => Some(self.exec(Box::new(expr), &mut Cow::Borrowed(&Box::new(HashMap::new())))), + Some(Ok(expr)) => Some(self.exec(Box::new(expr))), Some(Err(e)) => Some(Err(RuntimeError::ParseError(e))), None => None, } diff --git a/src/function.rs b/src/function.rs new file mode 100644 index 0000000..ceebbb4 --- /dev/null +++ b/src/function.rs @@ -0,0 +1,79 @@ +use crate::parser::ParseTree; +use crate::executor::{Executor, RuntimeError}; +use crate::{Type, Object, Value}; + +use std::collections::HashMap; +use std::fmt::{self, Display}; + +#[derive(Clone, Debug, PartialEq)] +pub struct FunctionType(pub Box, pub Vec); + +impl Display for FunctionType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Function({}, {})", self.0, self.1.iter().map(|x| format!("{x}")).collect::>().join(", ")) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Function { + name: Option, + t: FunctionType, + arg_names: Vec, + body: Box, +} + +impl Function { + pub(crate) fn lambda(t: FunctionType, arg_names: Vec, body: Box) -> Self { + Self { + name: None, + t, + arg_names, + body + } + } + + pub(crate) fn named(name: &str, t: FunctionType, arg_names: Vec, body: Box) -> Self { + Self { + name: Some(name.to_string()), + t, + arg_names, + body + } + } + + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|x| x.as_str()) + } + + pub fn get_type(&self) -> FunctionType { + self.t.clone() + } + + pub(crate) fn call(&mut self, + globals: HashMap, + locals: HashMap, + args: Vec) -> Result + { + let mut tree = vec![Ok(*self.body.clone())].into_iter(); + + let mut exec = Executor::new(&mut tree) + .locals(locals.clone()) + .globals(globals.clone()); + + for (obj, name) in std::iter::zip(args.into_iter(), self.arg_names.clone().into_iter()) { + exec = exec.add_local(name.clone(), obj); + } + + if let Some(name) = self.name().map(|x| x.to_string()) { + exec = exec.add_local(name, Object::function(self.clone(), globals, locals)); + } + + exec.next().unwrap() + } +} + +impl Display for Function { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.t) + } +} diff --git a/src/lib.rs b/src/lib.rs index da3caa3..31cca04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,19 @@ mod tokenizer; mod parser; mod executor; +mod function; use executor::{Executor, RuntimeError}; use parser::{ParseTree, Parser}; use tokenizer::Tokenizer; +use function::{FunctionType, Function}; use std::collections::HashMap; use std::fmt::Display; -use std::io::{Write, Read, BufRead}; +use std::io::BufRead; use std::fmt; +use std::iter::Peekable; +use std::marker::PhantomData; #[derive(Clone, Debug)] pub enum Type { @@ -71,7 +75,7 @@ impl Value { Self::String(_) => Type::String, Self::Array(t, _) => Type::Array(Box::new(t.clone())), Self::Nil => Type::Nil, - Self::Function(f) => Type::Function(f.t.clone()), + Self::Function(f) => Type::Function(f.get_type()), } } } @@ -84,98 +88,96 @@ impl Display for Value { Self::Bool(x) => write!(f, "{}", if *x { "true" } else { "false" }), Self::String(x) => write!(f, "\"{x}\""), Self::Array(_t, v) => write!(f, "[{}]", v.iter().map(|x| format!("{x}")).collect::>().join(" ")), - Self::Function(func) => { - if let Some(name) = &func.name { - write!(f, "Function({}, {}, {})", name, func.t.0, func.t.1.iter().map(|x| format!("{x}")).collect::>().join(", ")) - } else { - write!(f, "{}", func.t) - } - } + Self::Function(func) => write!(f, "{func}"), Self::Nil => write!(f, "nil"), } } } #[derive(Clone, Debug, PartialEq)] -pub struct FunctionType(Box, Vec); - -impl Display for FunctionType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Function({}, {})", self.0, self.1.iter().map(|x| format!("{x}")).collect::>().join(", ")) - } +enum Cache { + Cached(Value), + Uncached(ParseTree), } #[derive(Clone, Debug, PartialEq)] -enum Evaluation { - // at this point, it's type is set in stone - Computed(Value), - - // at this point, it's type is unknown, and may contradict a variable's type - // or not match the expected value of the expression, this is a runtime error - Uncomputed(Box), -} - -#[derive(Clone, Debug, PartialEq)] -enum Object { - Variable(Evaluation), - Function(Function), -} - -#[derive(Clone, Debug, PartialEq)] -pub struct Function { - name: Option, - t: FunctionType, +struct Object { locals: HashMap, - arg_names: Option>, - body: Option>, + globals: HashMap, + value: Cache, } -impl Function { - fn lambda(t: FunctionType, arg_names: Vec, locals: HashMap, body: Option>) -> Self { +impl Object { + pub fn variable(tree: ParseTree, globals: HashMap, locals: HashMap) -> Self { Self { - name: None, - t, locals, - arg_names: Some(arg_names), - body + globals, + value: Cache::Uncached(tree), } } - fn named(name: &str, t: FunctionType, arg_names: Option>, locals: HashMap, body: Option>) -> Self { + pub fn value(v: Value, globals: HashMap, locals: HashMap) -> Self { Self { - name: Some(name.to_string()), - t, locals, - arg_names, - body + globals, + value: Cache::Cached(v), } } + + pub fn function(func: Function, globals: HashMap, locals: HashMap) -> Self { + Self { + locals, + globals, + value: Cache::Cached(Value::Function(func)), + } + } + + /// evaluate the tree inside of an object if it isn't evaluated yet, returns the value + pub fn eval(&mut self) -> Result { + match self.value.clone() { + Cache::Cached(v) => Ok(v), + Cache::Uncached(tree) => { + let mut tree = vec![Ok(tree)].into_iter(); + + let mut exec = Executor::new(&mut tree) + .locals(self.locals.clone()) + .globals(self.globals.clone()); + + let v = exec.next().unwrap()?; + + self.value = Cache::Cached(v.clone()); + + Ok(v) + } + } + } + + pub fn locals(&self) -> HashMap { + self.locals.clone() + } + + pub fn globals(&self) -> HashMap { + self.globals.clone() + } } pub struct Runtime<'a, R: BufRead> { - inner: executor::Executor<'a, parser::Parser>> + tokenizer: Peekable>, + parser: Option>>, + phantom: PhantomData>>>, } -impl<'a, R: BufRead + 'a> Runtime<'a, R> { +impl<'a, R: BufRead> Runtime<'a, R> { pub fn new(reader: R) -> Self { Self { - inner: Executor::new(Parser::new(Tokenizer::new(reader))) + tokenizer: Tokenizer::new(reader).peekable(), + parser: None, + phantom: PhantomData, } } - pub fn stdout(self, stdout: impl Write + 'a) -> Self { - Self { - inner: self.inner.stdout(stdout) - } - } - - pub fn stdin(self, stdin: impl Read + 'a) -> Self { - Self { - inner: self.inner.stdin(stdin) - } - } - - pub fn values(self) -> impl Iterator> + 'a { - self.inner + pub fn values(&'a mut self) -> impl Iterator> + 'a { + self.parser = Some(Parser::new(&mut self.tokenizer)); + Executor::new(self.parser.as_mut().unwrap()) } } diff --git a/src/main.rs b/src/main.rs index 88460f5..571aa6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::io::{self, BufReader}; fn main() { - let runtime = lamm::Runtime::new(BufReader::new(io::stdin())); + let mut runtime = lamm::Runtime::new(BufReader::new(io::stdin())); for value in runtime.values() { match value { diff --git a/src/parser.rs b/src/parser.rs index 5c52f30..b73ae5b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,12 +1,10 @@ -use crate::Evaluation; -use super::{Value, Type, Object, Function, FunctionType}; +use super::{Value, Type, Function, FunctionType}; use super::tokenizer::{Token, TokenizeError, Op}; use std::error; use std::collections::HashMap; use std::fmt::Display; -use std::borrow::Cow; use std::iter::Peekable; #[derive(Debug)] @@ -93,149 +91,135 @@ pub(crate) enum ParseTree { Print(Box), } -macro_rules! one_arg { - ($op:ident, $tokens:ident, $globals:ident, $locals:ident) => { - Ok(ParseTree::$op( - Box::new(ParseTree::parse($tokens, $globals, $locals)?) - ))} +/// Parses input tokens and produces ParseTrees for an Executor +pub(crate) struct Parser<'a, I: Iterator>> { + tokens: &'a mut Peekable, + globals: HashMap, + locals: HashMap, } -macro_rules! two_arg { - ($op:ident, $tokens:ident, $globals:ident, $locals:ident) => { - Ok(ParseTree::$op( - Box::new(ParseTree::parse($tokens, $globals, $locals)?), - Box::new(ParseTree::parse($tokens, $globals, $locals)?) - ))} -} +impl<'a, I: Iterator>> Parser<'a, I> { + pub fn new(tokens: &'a mut Peekable) -> Self { + Self { + tokens: tokens, + globals: HashMap::new(), + locals: HashMap::new() + } + } -macro_rules! three_arg { - ($op:ident, $tokens:ident, $globals:ident, $locals:ident) => { - Ok(ParseTree::$op( - Box::new(ParseTree::parse($tokens, $globals, $locals)?), - Box::new(ParseTree::parse($tokens, $globals, $locals)?), - Box::new(ParseTree::parse($tokens, $globals, $locals)?) - ))} -} + pub fn globals(mut self, globals: HashMap) -> Self { + self.globals = globals; + self + } -impl ParseTree { - fn parse( - tokens: &mut Peekable, - globals: &HashMap, - locals: &mut Cow>) -> Result - where - I: Iterator>, - { - match tokens.next() { + pub fn _add_global(mut self, k: String, v: Type) -> Self { + self.globals.insert(k, v); + self + } + + pub fn locals(mut self, locals: HashMap) -> Self { + self.locals = locals; + self + } + + pub fn add_local(mut self, k: String, v: Type) -> Self { + self.locals.insert(k, v); + self + } + + fn get_object_type(&self, ident: &String) -> Result<&Type, ParseError> { + self.locals.get(ident).or(self.globals.get(ident)) + .ok_or(ParseError::IdentifierUndefined(ident.clone())) + } + + fn parse(&mut self) -> Result { + match self.tokens.next() { Some(Ok(token)) => { match token { - Token::Constant(c) => Ok(Self::Constant(c)), + Token::Constant(c) => Ok(ParseTree::Constant(c)), Token::Identifier(ident) => { - if let Some(obj) = locals.clone().get(&ident).or(globals.clone().get(&ident)) { - match obj { - Object::Function(f) => { - let args = f.t.1.iter() - .map(|_| ParseTree::parse(tokens, globals, locals)).collect::, ParseError>>()?; - - Ok(ParseTree::FunctionCall(ident, args)) - } - Object::Variable(e) => Ok(ParseTree::Variable(ident)), + match self.get_object_type(&ident)? { + Type::Function(f) => { + let args = f.1.clone().iter() + .map(|_| self.parse()).collect::, ParseError>>()?; + + Ok(ParseTree::FunctionCall(ident, args)) } - } else { - Err(ParseError::IdentifierUndefined(ident)) + _ => Ok(ParseTree::Variable(ident)), } } Token::Operator(op) => { match op { - Op::Add => two_arg!(Add, tokens, globals, locals), - Op::Sub => two_arg!(Sub, tokens, globals, locals), - Op::Mul => two_arg!(Mul, tokens, globals, locals), - Op::Div => two_arg!(Div, tokens, globals, locals), - Op::Exp => two_arg!(Exp, tokens, globals, locals), - Op::Mod => two_arg!(Mod, tokens, globals, locals), + Op::Add => Ok(ParseTree::Add(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Sub => Ok(ParseTree::Sub(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Mul => Ok(ParseTree::Mul(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Div => Ok(ParseTree::Div(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Exp => Ok(ParseTree::Exp(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Mod => Ok(ParseTree::Mod(Box::new(self.parse()?), Box::new(self.parse()?))), Op::Equ | Op::LazyEqu => { - let token = tokens.next() + let token = self.tokens.next() .ok_or(ParseError::UnexpectedEndInput)? .map_err(|e| ParseError::TokenizeError(e))?; - let body = Box::new(ParseTree::parse(tokens, globals, locals)?); + let body = Box::new(self.parse()?); if let Token::Identifier(ident) = token { - let locals = locals.to_mut(); - - locals.insert(ident.clone(), Object::Variable(Evaluation::Computed(Value::Nil))); - match op { - Op::Equ => Ok(ParseTree::Equ(ident, - body, - Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&locals))?) - )), - Op::LazyEqu => Ok(ParseTree::LazyEqu(ident, - body, - Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&locals))?) - )), - _ => panic!("Operator literally changed under your nose"), + Op::Equ => Ok(ParseTree::Equ(ident.clone(), + body.clone(), + Box::new(Parser::new(self.tokens.by_ref()) + .locals(self.locals.clone()) + .globals(self.globals.clone()) + .add_local(ident, Type::Any) + .parse()?)) + ), + Op::LazyEqu => Ok(ParseTree::LazyEqu(ident.clone(), + body.clone(), + Box::new(Parser::new(self.tokens.by_ref()) + .locals(self.locals.clone()) + .globals(self.globals.clone()) + .add_local(ident, Type::Any) + .parse()?)) + ), + _ => unreachable!(), } } else { Err(ParseError::InvalidIdentifier(token)) } } Op::FunctionDefine(arg_count) => { - let f = { - let mut f = ParseTree::parse_function(tokens, arg_count)?; + let f = self.parse_function(arg_count)?; - if locals.contains_key(&f.name.clone().unwrap()) { - return Err(ParseError::ImmutableError(f.name.unwrap())); - } - - f.locals = locals.to_mut().clone(); - - // recursion requires that f's prototype is present in locals - f.locals.insert(f.name.clone().unwrap(), Object::Function(f.clone())); - - // we also need any function parameters in local scope - for (name, t) in std::iter::zip(f.arg_names.clone().unwrap(), f.t.1.clone()) { - match t { - Type::Function(t) => { - f.locals.insert(name.clone(), Object::Function(Function::named(&name, t, None, HashMap::new(), None))); - } - _ => { - // the value isn't important, just that the identifier is there - f.locals.insert(name.clone(), Object::Variable(Evaluation::Computed(Value::Nil))); - } - } - } - - f.body = Some(Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&f.locals))?)); - - f - }; - - let locals = locals.to_mut(); - locals.insert(f.name.clone().unwrap(), Object::Function(f.clone())); - - Ok(ParseTree::FunctionDefinition(f, Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&locals))?))) + Ok(ParseTree::FunctionDefinition(f.clone(), + Box::new( + Parser::new(self.tokens) + .globals(self.globals.clone()) + .locals(self.locals.clone()) + .add_local(f.name().unwrap().to_string(), Type::Function(f.get_type())) + .parse()? + ))) }, - Op::Compose => two_arg!(Compose, tokens, globals, locals), - Op::Id => one_arg!(Id, tokens, globals, locals), - Op::If => two_arg!(If, tokens, globals, locals), - Op::IfElse => three_arg!(IfElse, tokens, globals, locals), - Op::EqualTo => two_arg!(EqualTo, tokens, globals, locals), - Op::GreaterThan => two_arg!(GreaterThan, tokens, globals, locals), - Op::LessThan => two_arg!(LessThan, tokens, globals, locals), - Op::GreaterThanOrEqualTo => two_arg!(GreaterThanOrEqualTo, tokens, globals, locals), - Op::LessThanOrEqualTo => two_arg!(LessThanOrEqualTo, tokens, globals, locals), - Op::Not => one_arg!(Not, tokens, globals, locals), - Op::IntCast => one_arg!(IntCast, tokens, globals, locals), - Op::FloatCast => one_arg!(FloatCast, tokens, globals, locals), - Op::BoolCast => one_arg!(BoolCast, tokens, globals, locals), - Op::StringCast => one_arg!(StringCast, tokens, globals, locals), - Op::Print => one_arg!(Print, tokens, globals, locals), + Op::Compose => Ok(ParseTree::Compose(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Id => Ok(ParseTree::Id(Box::new(self.parse()?))), + Op::IfElse => Ok(ParseTree::IfElse(Box::new(self.parse()?), Box::new(self.parse()?), Box::new(self.parse()?))), + Op::If => Ok(ParseTree::If(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::EqualTo => Ok(ParseTree::EqualTo(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::GreaterThan => Ok(ParseTree::GreaterThan(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::LessThan => Ok(ParseTree::LessThan(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::GreaterThanOrEqualTo => Ok(ParseTree::GreaterThanOrEqualTo(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::LessThanOrEqualTo => Ok(ParseTree::LessThanOrEqualTo(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Not => Ok(ParseTree::Not(Box::new(self.parse()?))), + Op::IntCast => Ok(ParseTree::IntCast(Box::new(self.parse()?))), + Op::FloatCast => Ok(ParseTree::FloatCast(Box::new(self.parse()?))), + Op::BoolCast => Ok(ParseTree::BoolCast(Box::new(self.parse()?))), + Op::StringCast => Ok(ParseTree::StringCast(Box::new(self.parse()?))), + Op::Print => Ok(ParseTree::Print(Box::new(self.parse()?))), Op::OpenArray => { let mut depth = 1; // take tokens until we reach the end of this array // if we don't collect them here it causes rust to overflow computing the types - let array_tokens = tokens.by_ref().take_while(|t| match t { + let array_tokens = self.tokens.by_ref().take_while(|t| match t { Ok(Token::Operator(Op::OpenArray)) => { depth += 1; true @@ -247,11 +231,16 @@ impl ParseTree { _ => true, }).collect::, TokenizeError>>().map_err(|e| ParseError::TokenizeError(e))?; - let array_tokens: Vec> = array_tokens.into_iter().map(|t| Ok(t)).collect(); + let mut array_tokens = array_tokens + .into_iter() + .map(|t| Ok(t)) + .collect::>>() + .into_iter() + .peekable(); - let trees: Vec = Parser::new(array_tokens.into_iter()) - .globals(globals.clone()) - .locals(locals.to_mut().to_owned()) + let trees: Vec = Parser::new(&mut array_tokens) + .globals(self.globals.to_owned()) + .locals(self.locals.to_owned()) .collect::>()?; let tree = trees.into_iter().fold( @@ -263,44 +252,21 @@ impl ParseTree { } Op::Empty => Ok(ParseTree::Constant(Value::Array(Type::Any, vec![]))), Op::CloseArray => Err(ParseError::UnmatchedArrayClose), - Op::NotEqualTo => two_arg!(NotEqualTo, tokens, globals, locals), - Op::And => two_arg!(And, tokens, globals, locals), - Op::Or => two_arg!(Or, tokens, globals, locals), + Op::NotEqualTo => Ok(ParseTree::NotEqualTo(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::And => Ok(ParseTree::And(Box::new(self.parse()?), Box::new(self.parse()?))), + Op::Or => Ok(ParseTree::Or(Box::new(self.parse()?), Box::new(self.parse()?))), Op::LambdaDefine(arg_count) => { - let f = { - let mut f = ParseTree::parse_lambda(tokens, arg_count)?; - - let locals = locals.to_mut(); - f.locals = locals.clone(); - - // we need any function parameters in local scope - for (name, t) in std::iter::zip(f.arg_names.clone().unwrap(), f.t.1.clone()) { - match t { - Type::Function(t) => { - f.locals.insert(name.clone(), Object::Function(Function::named(&name, t, None, HashMap::new(), None))); - } - _ => { - // the value isn't important, just that the identifier is there - f.locals.insert(name.clone(), Object::Variable(Evaluation::Computed(Value::Nil))); - } - } - } - - f.body = Some(Box::new(ParseTree::parse(tokens, globals, &mut Cow::Borrowed(&f.locals))?)); - - f - }; - + let f = self.parse_lambda(arg_count)?; Ok(ParseTree::LambdaDefinition(f)) } Op::NonCall => { - let name = Self::get_identifier(tokens.next())?; + let name = Self::get_identifier(self.tokens.next())?; Ok(ParseTree::NonCall(name)) }, - Op::Head => one_arg!(Head, tokens, globals, locals), - Op::Tail => one_arg!(Tail, tokens, globals, locals), - Op::Init => one_arg!(Init, tokens, globals, locals), - Op::Fini => one_arg!(Fini, tokens, globals, locals), + Op::Head => Ok(ParseTree::Head(Box::new(self.parse()?))), + Op::Tail => Ok(ParseTree::Tail(Box::new(self.parse()?))), + Op::Init => Ok(ParseTree::Init(Box::new(self.parse()?))), + Op::Fini => Ok(ParseTree::Fini(Box::new(self.parse()?))), op => Err(ParseError::UnwantedToken(Token::Operator(op))), } } @@ -312,28 +278,40 @@ impl ParseTree { } } - fn parse_lambda(tokens: &mut Peekable, arg_count: usize) -> Result - where - I: Iterator>, - { - let (t, args) = Self::parse_function_declaration(tokens, arg_count)?; - Ok(Function::lambda(t, args, HashMap::new(), None)) + fn parse_lambda(&mut self, arg_count: usize) -> Result { + let (t, args) = Self::parse_function_declaration(self.tokens, arg_count)?; + + let mut locals = self.locals.clone(); + + for (name, t) in std::iter::zip(args.iter(), t.1.iter()) { + locals.insert(name.clone(), t.clone()); + } + + Ok(Function::lambda(t, args, Box::new( + Parser::new(self.tokens) + .globals(self.globals.clone()) + .locals(locals).parse()?))) } - fn parse_function(tokens: &mut Peekable, arg_count: usize) -> Result - where - I: Iterator>, - { - let name = Self::get_identifier(tokens.next())?; - let (t, args) = Self::parse_function_declaration(tokens, arg_count)?; + fn parse_function(&mut self, arg_count: usize) -> Result { + let name = Self::get_identifier(self.tokens.next())?; + let (t, args) = Self::parse_function_declaration(self.tokens, arg_count)?; - Ok(Function::named(&name, t, Some(args), HashMap::new(), None)) + let mut locals = self.locals.clone(); + + for (name, t) in std::iter::zip(args.iter(), t.1.iter()) { + locals.insert(name.clone(), t.clone()); + } + + locals.insert(name.clone(), Type::Function(t.clone())); + + Ok(Function::named(&name, t, args, Box::new( + Parser::new(self.tokens) + .globals(self.globals.clone()) + .locals(locals).parse()?))) } - fn parse_function_declaration(tokens: &mut Peekable, arg_count: usize) -> Result<(FunctionType, Vec), ParseError> - where - I: Iterator> - { + fn parse_function_declaration(tokens: &mut Peekable, arg_count: usize) -> Result<(FunctionType, Vec), ParseError> { let args: Vec<(Type, String)> = (0..arg_count) .map(|_| Self::parse_function_declaration_parameter(tokens)) .collect::>()?; @@ -342,22 +320,14 @@ impl ParseTree { let (types, names): (Vec<_>, Vec<_>) = args.into_iter().unzip(); let mut ret = Type::Any; - if let Some(t) = tokens.next_if(|x| matches!(x, Ok(Token::Operator(Op::Arrow)))) - { - if let Err(e) = t { - return Err(ParseError::TokenizeError(e)); - } - + if tokens.next_if(|x| matches!(x, Ok(Token::Operator(Op::Arrow)))).is_some() { ret = Self::parse_type(tokens)?; } Ok((FunctionType(Box::new(ret), types), names)) } - fn parse_function_declaration_parameter(mut tokens: &mut Peekable) -> Result<(Type, String), ParseError> - where - I: Iterator> - { + fn parse_function_declaration_parameter(mut tokens: &mut Peekable) -> Result<(Type, String), ParseError> { match tokens.next() { // untyped variable Some(Ok(Token::Identifier(x))) => Ok((Type::Any, x)), @@ -406,10 +376,7 @@ impl ParseTree { } } - fn parse_type(tokens: &mut I) -> Result - where - I: Iterator>, - { + fn parse_type(tokens: &mut Peekable) -> Result { match tokens.next() { Some(Ok(Token::Type(t))) => Ok(t), Some(Ok(Token::Operator(Op::FunctionDefine(n)))) => { @@ -447,48 +414,11 @@ impl ParseTree { } } -/// Parses input tokens and produces ParseTrees for an Executor -pub(crate) struct Parser>> { - tokens: I, - - // These are used to keep track of functions in the current context - // by the parser. otherwise the parser would have no way to tell - // if the program `* a b 12` is supposed to be ((* a b) (12)) or (* (a b) 12) - globals: HashMap, - locals: HashMap, -} - -impl>> Parser { - pub fn new(tokens: I) -> Self { - Self { - tokens, - globals: HashMap::new(), - locals: HashMap::new() - } - } - - pub fn globals(self, globals: HashMap) -> Self { - Self { - tokens: self.tokens, - globals, - locals: self.locals, - } - } - - pub fn locals(self, locals: HashMap) -> Self { - Self { - tokens: self.tokens, - globals: self.globals, - locals, - } - } -} - -impl>> Iterator for Parser { +impl<'a, I: Iterator>> Iterator for Parser<'a, I> { type Item = Result; fn next(&mut self) -> Option { - let tree = ParseTree::parse(&mut self.tokens.by_ref().peekable(), &self.globals, &mut Cow::Borrowed(&self.locals)); + let tree = self.parse(); match tree { Ok(tree) => Some(Ok(tree)), diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 00a0353..0b43e64 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -42,7 +42,7 @@ impl Display for TokenizeError { impl error::Error for TokenizeError {} #[derive(Debug, Clone, PartialEq)] -pub(crate) enum Op { +pub enum Op { Add, Sub, Mul, @@ -85,7 +85,7 @@ pub(crate) enum Op { } #[derive(Debug, Clone)] -pub(crate) enum Token { +pub enum Token { Identifier(String), Operator(Op), Constant(Value), @@ -408,26 +408,4 @@ impl std::iter::Iterator for Tokenizer { Err(e) => Some(Err(TokenizeError::IO(e))), } } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use crate::parser::{Parser, ParseTree, ParseError}; - - use super::*; - - #[test] - fn uwu() { - let program = ":. map ?: f Any -> Any ?. x [Any] -> [Any] ?? bool x + f head x map 'f tail x empty map ;x ** x 2 [1 2 3 4 5]"; - - let tokens: Vec = Tokenizer::from_str(program).unwrap().collect::>().unwrap(); - - println!("{tokens:?}"); - - let trees: Result, ParseError> = Parser::new(tokens.into_iter().map(|x| Ok(x))).collect(); - - println!("{trees:?}"); - } } \ No newline at end of file