From 93266a980e2394acee9670b49b6ebee0bd3e83b0 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 27 Dec 2021 22:19:29 +0000 Subject: [PATCH] Refractor into modules --- rust-toolchain | 2 +- src/ast.rs | 23 +++ src/eval.rs | 113 +++++++++++ src/grammar.lalrpop | 2 +- src/grammar.rs | 447 ++++++++++++-------------------------------- src/main.rs | 367 ++---------------------------------- src/prims.rs | 124 ++++++++++++ src/value.rs | 72 +++++++ 8 files changed, 466 insertions(+), 684 deletions(-) create mode 100644 src/ast.rs create mode 100644 src/eval.rs create mode 100644 src/prims.rs create mode 100644 src/value.rs diff --git a/rust-toolchain b/rust-toolchain index ee9da97..02e6a0e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2021-12-16 \ No newline at end of file +nightly-2021-12-27 \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs new file mode 100644 index 0000000..cdd9503 --- /dev/null +++ b/src/ast.rs @@ -0,0 +1,23 @@ +use std::rc::Rc; + +#[derive(Debug, debug2::Debug, PartialEq)] + +crate enum Tree { + Leaf(Literal), + Define(String, Box), + If(Box<[Tree; 3]>), + Lambda(Lambda), + Branch(Vec), +} + +#[derive(Debug, debug2::Debug, PartialEq, Clone)] + +crate struct Lambda(crate Rc<[String]>, crate Rc<[Tree]>); + +#[derive(Debug, debug2::Debug, PartialEq)] + +crate enum Literal { + Sym(String), + Num(f64), + Bool(bool), +} diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 0000000..b9dbd8d --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,113 @@ +use std::assert_matches::assert_matches; +use std::collections::HashMap; + +use crate::value::Value; +use crate::{ast, prims}; + +pub(crate) fn eval(t: &ast::Tree, env: &mut Env) -> Result { + Ok(match t { + ast::Tree::Leaf(l) => match l { + ast::Literal::Sym(s) => match env.lookup(s) { + Some(v) => v, + None => return err(format!("Undefined variable `{}`", s)), + }, + ast::Literal::Num(v) => Value::Num(*v), + ast::Literal::Bool(b) => Value::Bool(*b), + }, + ast::Tree::Lambda(l) => Value::Lambda(l.clone()), + ast::Tree::Branch(args) => { + let Some(fun) = args.get(0) else { return err("No argument given".to_owned()) }; + let fun = eval(fun, env)?; + let fun = fun.as_func()?; + let args = args + .iter() + .skip(1) + .map(|a| eval(a, env)) + .collect::, _>>()?; + // return fun(&args); + match fun { + Callable::Func(f) => f(&args)?, + Callable::Lambda(l) => { + if l.0.len() == args.len() { + let mut env = env.child(); + for (x, y) in l.0.iter().zip(args) { + env.define(x.clone(), y) + } + + let [main @ .., tail] = &l.1[..] else { unreachable!("Body has 1+ element by parser") }; + for i in main { + eval(i, &mut env)?; + } + + eval(tail, &mut env)? + } else { + return err(format!("Need {} args, got {}", l.0.len(), args.len())); + } + } + } + } + ast::Tree::Define(name, to) => { + let val = eval(to, env)?; + env.define(name.to_owned(), val); + Value::Trap + } + ast::Tree::If(box [cond, tcase, fcase]) => { + let b = eval(cond, env)?.as_bool()?; + let body = if b { tcase } else { fcase }; + eval(body, env)? + } + }) +} + +#[derive(Debug)] +crate struct RTError(crate String); + +pub(crate) fn err(s: String) -> Result { + Err(RTError(s)) +} + +pub(crate) enum Callable<'a> { + Func(prims::Func), + Lambda(&'a ast::Lambda), +} + +pub(crate) struct Env<'a> { + pub(crate) vars: HashMap, + pub(crate) enclosing: Option<&'a Env<'a>>, +} + +impl<'a> Env<'a> { + pub(crate) fn child(&'a self) -> Env<'a> { + Env { + vars: HashMap::new(), + enclosing: Some(self), + } + } + + pub(crate) fn lookup(&self, s: &str) -> Option { + if let Some(v) = self.vars.get(s) { + Some(v.clone()) + } else if let Some(parent) = self.enclosing { + parent.lookup(s) + } else { + None + } + } + + pub(crate) fn define(&mut self, name: String, val: Value) { + self.vars.insert(name, val); + } +} + +pub(crate) fn default_env() -> Env<'static> { + let mut vars = HashMap::new(); + + for (name, fun) in prims::prims() { + assert_matches!(vars.insert((*name).to_owned(), Value::Func(*fun)), None) + } + + Env { + vars, + enclosing: None, + } +} diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index f73eadf..681053d 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -1,4 +1,4 @@ -use crate::{Tree, Literal, Lambda}; +use crate::ast::*; use std::rc::Rc; grammar<'s>(); diff --git a/src/grammar.rs b/src/grammar.rs index 0ef023e..5175c41 100644 --- a/src/grammar.rs +++ b/src/grammar.rs @@ -1,19 +1,19 @@ // auto-generated: "lalrpop 0.19.6" -// sha3: 081836a45e94e7f63b8cab92d6c3fb6f3fd286189113e73ef425a1afba86 -use crate::{Tree, Literal, Lambda}; +// sha3: c1daa5330c6265bff388c19ed1642efbf9924c741dbad19b8016bd2a5a646 +use crate::ast::*; use std::rc::Rc; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; #[allow(unused_imports)] use self::__lalrpop_util::state_machine as __state_machine; -extern crate core; extern crate alloc; +extern crate core; #[cfg_attr(rustfmt, rustfmt_skip)] mod __parse__File { #![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)] - use crate::{Tree, Literal, Lambda}; + use crate::ast::*; use std::rc::Rc; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; @@ -1454,7 +1454,7 @@ pub(crate) use self::__parse__File::FileParser; mod __parse__Tree { #![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)] - use crate::{Tree, Literal, Lambda}; + use crate::ast::*; use std::rc::Rc; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; @@ -2854,7 +2854,7 @@ pub(crate) use self::__parse__Tree::TreeParser; #[cfg_attr(rustfmt, rustfmt_skip)] mod __intern_token { #![allow(unused_imports)] - use crate::{Tree, Literal, Lambda}; + use crate::ast::*; use std::rc::Rc; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; @@ -2885,89 +2885,59 @@ mod __intern_token { pub(crate) use self::__lalrpop_util::lexer::Token; #[allow(unused_variables)] -fn __action0< - 'input, - 's, ->( +fn __action0<'input, 's>( input: &'input str, (_, __0, _): (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { __0 } #[allow(unused_variables)] -fn __action1< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, Tree, usize), -) -> Tree -{ +fn __action1<'input, 's>(input: &'input str, (_, __0, _): (usize, Tree, usize)) -> Tree { __0 } #[allow(unused_variables)] -fn __action2< - 'input, - 's, ->( +fn __action2<'input, 's>( input: &'input str, (_, _, _): (usize, core::option::Option<()>, usize), (_, __0, _): (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { __0 } #[allow(unused_variables)] -fn __action3< - 'input, - 's, ->( +fn __action3<'input, 's>( input: &'input str, (_, __0, _): (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { __0 } #[allow(unused_variables)] -fn __action4< - 'input, - 's, ->( +fn __action4<'input, 's>( input: &'input str, (_, _, _): (usize, &'input str, usize), (_, __0, _): (usize, alloc::vec::Vec, usize), (_, _, _): (usize, &'input str, usize), -) -> Tree -{ +) -> Tree { Tree::Branch(__0) } #[allow(unused_variables)] -fn __action5< - 'input, - 's, ->( +fn __action5<'input, 's>( input: &'input str, (_, _, _): (usize, &'input str, usize), (_, _, _): (usize, &'input str, usize), (_, __0, _): (usize, String, usize), (_, __1, _): (usize, Box, usize), (_, _, _): (usize, &'input str, usize), -) -> Tree -{ +) -> Tree { Tree::Define(__0, __1) } #[allow(unused_variables)] -fn __action6< - 'input, - 's, ->( +fn __action6<'input, 's>( input: &'input str, (_, _, _): (usize, &'input str, usize), (_, _, _): (usize, &'input str, usize), @@ -2977,16 +2947,12 @@ fn __action6< (_, _, _): (usize, &'input str, usize), (_, body, _): (usize, Rc<[Tree]>, usize), (_, _, _): (usize, &'input str, usize), -) -> Tree -{ +) -> Tree { Tree::Define(name, Box::new(Tree::Lambda(Lambda(args, body)))) } #[allow(unused_variables)] -fn __action7< - 'input, - 's, ->( +fn __action7<'input, 's>( input: &'input str, (_, _, _): (usize, &'input str, usize), (_, _, _): (usize, &'input str, usize), @@ -2994,16 +2960,12 @@ fn __action7< (_, __1, _): (usize, Tree, usize), (_, __2, _): (usize, Tree, usize), (_, _, _): (usize, &'input str, usize), -) -> Tree -{ +) -> Tree { Tree::If(Box::new([__0, __1, __2])) } #[allow(unused_variables)] -fn __action8< - 'input, - 's, ->( +fn __action8<'input, 's>( input: &'input str, (_, _, _): (usize, &'input str, usize), (_, _, _): (usize, &'input str, usize), @@ -3011,468 +2973,295 @@ fn __action8< (_, _, _): (usize, &'input str, usize), (_, __1, _): (usize, Rc<[Tree]>, usize), (_, _, _): (usize, &'input str, usize), -) -> Tree -{ +) -> Tree { Tree::Lambda(Lambda(__0, __1)) } #[allow(unused_variables)] -fn __action9< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, Literal, usize), -) -> Tree -{ +fn __action9<'input, 's>(input: &'input str, (_, __0, _): (usize, Literal, usize)) -> Tree { Tree::Leaf(__0) } #[allow(unused_variables)] -fn __action10< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, Box, usize), -) -> Box -{ +fn __action10<'input, 's>(input: &'input str, (_, __0, _): (usize, Box, usize)) -> Box { __0 } #[allow(unused_variables)] -fn __action11< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, String, usize), -) -> Literal -{ +fn __action11<'input, 's>(input: &'input str, (_, __0, _): (usize, String, usize)) -> Literal { Literal::Sym(__0) } #[allow(unused_variables)] -fn __action12< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, f64, usize), -) -> Literal -{ +fn __action12<'input, 's>(input: &'input str, (_, __0, _): (usize, f64, usize)) -> Literal { Literal::Num(__0) } #[allow(unused_variables)] -fn __action13< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, bool, usize), -) -> Literal -{ +fn __action13<'input, 's>(input: &'input str, (_, __0, _): (usize, bool, usize)) -> Literal { Literal::Bool(__0) } #[allow(unused_variables)] -fn __action14< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, &'input str, usize), -) -> String -{ +fn __action14<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> String { __0.to_owned() } #[allow(unused_variables)] -fn __action15< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, &'input str, usize), -) -> f64 -{ +fn __action15<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> f64 { __0.parse().unwrap() } #[allow(unused_variables)] -fn __action16< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, &'input str, usize), -) -> bool -{ +fn __action16<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> bool { true } #[allow(unused_variables)] -fn __action17< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, &'input str, usize), -) -> bool -{ +fn __action17<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> bool { false } #[allow(unused_variables)] -fn __action18< - 'input, - 's, ->( +fn __action18<'input, 's>( input: &'input str, (_, __0, _): (usize, &'input str, usize), (_, __1, _): (usize, &'input str, usize), -) -> () -{ +) -> () { () } #[allow(unused_variables)] -fn __action19< - 'input, - 's, ->( +fn __action19<'input, 's>( input: &'input str, (_, __0, _): (usize, &'input str, usize), -) -> &'input str -{ +) -> &'input str { __0 } #[allow(unused_variables)] -fn __action20< - 'input, - 's, ->( +fn __action20<'input, 's>( input: &'input str, (_, __0, _): (usize, &'input str, usize), -) -> &'input str -{ +) -> &'input str { __0 } #[allow(unused_variables)] -fn __action21< - 'input, - 's, ->( - input: &'input str, - (_, __0, _): (usize, Tree, usize), -) -> Box -{ +fn __action21<'input, 's>(input: &'input str, (_, __0, _): (usize, Tree, usize)) -> Box { Box::new(__0) } #[allow(unused_variables)] -fn __action22< - 'input, - 's, ->( +fn __action22<'input, 's>( input: &'input str, (_, __0, _): (usize, alloc::vec::Vec, usize), -) -> Rc<[Tree]> -{ +) -> Rc<[Tree]> { __0.into() } #[allow(unused_variables)] -fn __action23< - 'input, - 's, ->( +fn __action23<'input, 's>( input: &'input str, (_, __0, _): (usize, alloc::vec::Vec, usize), -) -> Rc<[String]> -{ +) -> Rc<[String]> { __0.into() } #[allow(unused_variables)] -fn __action24< - 'input, - 's, ->( +fn __action24<'input, 's>( input: &'input str, (_, __0, _): (usize, Tree, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { alloc::vec![__0] } #[allow(unused_variables)] -fn __action25< - 'input, - 's, ->( +fn __action25<'input, 's>( input: &'input str, (_, v, _): (usize, alloc::vec::Vec, usize), (_, e, _): (usize, Tree, usize), -) -> alloc::vec::Vec -{ - { let mut v = v; v.push(e); v } +) -> alloc::vec::Vec { + { + let mut v = v; + v.push(e); + v + } } #[allow(unused_variables)] -fn __action26< - 'input, - 's, ->( +fn __action26<'input, 's>( input: &'input str, (_, __0, _): (usize, (), usize), -) -> core::option::Option<()> -{ +) -> core::option::Option<()> { Some(__0) } #[allow(unused_variables)] -fn __action27< - 'input, - 's, ->( +fn __action27<'input, 's>( input: &'input str, __lookbehind: &usize, __lookahead: &usize, -) -> core::option::Option<()> -{ +) -> core::option::Option<()> { None } #[allow(unused_variables)] -fn __action28< - 'input, - 's, ->( +fn __action28<'input, 's>( input: &'input str, __lookbehind: &usize, __lookahead: &usize, -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { alloc::vec![] } #[allow(unused_variables)] -fn __action29< - 'input, - 's, ->( +fn __action29<'input, 's>( input: &'input str, (_, v, _): (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { v } #[allow(unused_variables)] -fn __action30< - 'input, - 's, ->( +fn __action30<'input, 's>( input: &'input str, __lookbehind: &usize, __lookahead: &usize, -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { alloc::vec![] } #[allow(unused_variables)] -fn __action31< - 'input, - 's, ->( +fn __action31<'input, 's>( input: &'input str, (_, v, _): (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { v } #[allow(unused_variables)] -fn __action32< - 'input, - 's, ->( +fn __action32<'input, 's>( input: &'input str, (_, __0, _): (usize, String, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { alloc::vec![__0] } #[allow(unused_variables)] -fn __action33< - 'input, - 's, ->( +fn __action33<'input, 's>( input: &'input str, (_, v, _): (usize, alloc::vec::Vec, usize), (_, e, _): (usize, String, usize), -) -> alloc::vec::Vec -{ - { let mut v = v; v.push(e); v } +) -> alloc::vec::Vec { + { + let mut v = v; + v.push(e); + v + } } #[allow(unused_variables)] -fn __action34< - 'input, - 's, ->( +fn __action34<'input, 's>( input: &'input str, __0: (usize, (), usize), __1: (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); - let __temp0 = __action26( - input, - __0, - ); + let __temp0 = __action26(input, __0); let __temp0 = (__start0, __temp0, __end0); - __action2( - input, - __temp0, - __1, - ) + __action2(input, __temp0, __1) } #[allow(unused_variables)] -fn __action35< - 'input, - 's, ->( +fn __action35<'input, 's>( input: &'input str, __0: (usize, alloc::vec::Vec, usize), -) -> alloc::vec::Vec -{ +) -> alloc::vec::Vec { let __start0 = __0.0.clone(); let __end0 = __0.0.clone(); - let __temp0 = __action27( - input, - &__start0, - &__end0, - ); + let __temp0 = __action27(input, &__start0, &__end0); let __temp0 = (__start0, __temp0, __end0); - __action2( - input, - __temp0, - __0, - ) + __action2(input, __temp0, __0) } #[allow(unused_variables)] -fn __action36< - 'input, - 's, ->( +fn __action36<'input, 's>( input: &'input str, __lookbehind: &usize, __lookahead: &usize, -) -> Rc<[String]> -{ +) -> Rc<[String]> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); - let __temp0 = __action28( - input, - &__start0, - &__end0, - ); + let __temp0 = __action28(input, &__start0, &__end0); let __temp0 = (__start0, __temp0, __end0); - __action23( - input, - __temp0, - ) + __action23(input, __temp0) } #[allow(unused_variables)] -fn __action37< - 'input, - 's, ->( +fn __action37<'input, 's>( input: &'input str, __0: (usize, alloc::vec::Vec, usize), -) -> Rc<[String]> -{ +) -> Rc<[String]> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); - let __temp0 = __action29( - input, - __0, - ); + let __temp0 = __action29(input, __0); let __temp0 = (__start0, __temp0, __end0); - __action23( - input, - __temp0, - ) + __action23(input, __temp0) } #[allow(unused_variables)] -fn __action38< - 'input, - 's, ->( +fn __action38<'input, 's>( input: &'input str, __lookbehind: &usize, __lookahead: &usize, -) -> Rc<[Tree]> -{ +) -> Rc<[Tree]> { let __start0 = __lookbehind.clone(); let __end0 = __lookahead.clone(); - let __temp0 = __action30( - input, - &__start0, - &__end0, - ); + let __temp0 = __action30(input, &__start0, &__end0); let __temp0 = (__start0, __temp0, __end0); - __action22( - input, - __temp0, - ) + __action22(input, __temp0) } #[allow(unused_variables)] -fn __action39< - 'input, - 's, ->( +fn __action39<'input, 's>( input: &'input str, __0: (usize, alloc::vec::Vec, usize), -) -> Rc<[Tree]> -{ +) -> Rc<[Tree]> { let __start0 = __0.0.clone(); let __end0 = __0.2.clone(); - let __temp0 = __action31( - input, - __0, - ); + let __temp0 = __action31(input, __0); let __temp0 = (__start0, __temp0, __end0); - __action22( - input, - __temp0, - ) + __action22(input, __temp0) } -pub trait __ToTriple<'input, 's, > { - fn to_triple(value: Self) -> Result<(usize,Token<'input>,usize), __lalrpop_util::ParseError, &'static str>>; +pub trait __ToTriple<'input, 's> { + fn to_triple( + value: Self, + ) -> Result< + (usize, Token<'input>, usize), + __lalrpop_util::ParseError, &'static str>, + >; } -impl<'input, 's, > __ToTriple<'input, 's, > for (usize, Token<'input>, usize) { - fn to_triple(value: Self) -> Result<(usize,Token<'input>,usize), __lalrpop_util::ParseError, &'static str>> { +impl<'input, 's> __ToTriple<'input, 's> for (usize, Token<'input>, usize) { + fn to_triple( + value: Self, + ) -> Result< + (usize, Token<'input>, usize), + __lalrpop_util::ParseError, &'static str>, + > { Ok(value) } } -impl<'input, 's, > __ToTriple<'input, 's, > for Result<(usize, Token<'input>, usize), &'static str> { - fn to_triple(value: Self) -> Result<(usize,Token<'input>,usize), __lalrpop_util::ParseError, &'static str>> { +impl<'input, 's> __ToTriple<'input, 's> for Result<(usize, Token<'input>, usize), &'static str> { + fn to_triple( + value: Self, + ) -> Result< + (usize, Token<'input>, usize), + __lalrpop_util::ParseError, &'static str>, + > { match value { Ok(v) => Ok(v), Err(error) => Err(__lalrpop_util::ParseError::User { error }), diff --git a/src/main.rs b/src/main.rs index 987b559..1f83267 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,150 +1,25 @@ #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(crate_visibility_modifier)] #![feature(let_else)] -mod grammar; +use std::io; -#[cfg(test)] -mod tests; - -// use debug2::dbg; use rustyline::validate::{ MatchingBracketValidator, ValidationContext, ValidationResult, Validator, }; use rustyline::Editor; use rustyline_derive::{Completer, Helper, Highlighter, Hinter}; -use std::assert_matches::assert_matches; -use std::collections::HashMap; -use std::io; -use std::rc::Rc; -#[derive(Debug, debug2::Debug, PartialEq)] -enum Tree { - Leaf(Literal), - Define(String, Box), - If(Box<[Tree; 3]>), - Lambda(Lambda), - Branch(Vec), -} - -#[derive(Debug, debug2::Debug, PartialEq, Clone)] -struct Lambda(Rc<[String]>, Rc<[Tree]>); - -#[derive(Debug, debug2::Debug, PartialEq)] -enum Literal { - Sym(String), - Num(f64), - Bool(bool), -} - -#[derive(Debug)] -struct RTError(String); - -fn err(s: String) -> Result { - Err(RTError(s)) -} - -type Func = fn(&[Value]) -> Result; - -#[derive(Clone)] -enum Value { - Num(f64), - Func(Func), - Lambda(Lambda), - Bool(bool), - NotAValue, -} - -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - use Value::*; - match (self, other) { - (Num(l), Num(r)) => l == r, - (Func(l), Func(r)) => *l as usize == *r as usize, - (Bool(l), Bool(r)) => l == r, - (Lambda(l), Lambda(r)) => Rc::ptr_eq(&l.0, &r.0) && Rc::ptr_eq(&l.1, &r.1), - - (Num(_), _) => false, - (Func(_), _) => false, - (Bool(_), _) => false, - (Lambda(_), _) => false, - - (NotAValue, _) => panic!("Trap value"), - } - } -} - -impl std::fmt::Debug for Value { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Num(n) => n.fmt(f), - Self::Func(_) => f.write_str("#"), - Self::Lambda(_) => f.write_str("#"), - Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }), - Self::NotAValue => Ok(()), - } - } -} - -impl Value { - fn as_num(&self) -> Result { - if let Self::Num(n) = self { - Ok(*n) - } else { - Err(RTError("Expected a number".to_owned())) - } - } - - fn as_func(&self) -> Result { - match self { - Self::Func(f) => Ok(Callable::Func(*f)), - Self::Lambda(l) => Ok(Callable::Lambda(l)), - _ => Err(RTError(format!("Expected a function, got {:?}", self))), - } - } - - fn as_bool(&self) -> Result { - if let Self::Bool(b) = self { - Ok(*b) - } else { - Err(RTError("Expected a bool".to_owned())) - } - } -} - -enum Callable<'a> { - Func(Func), - Lambda(&'a Lambda), -} - -struct Env<'a> { - vars: HashMap, - enclosing: Option<&'a Env<'a>>, -} - -impl<'a> Env<'a> { - fn child(&'a self) -> Env<'a> { - Env { - vars: HashMap::new(), - enclosing: Some(self), - } - } - - fn lookup(&self, s: &str) -> Option { - if let Some(v) = self.vars.get(s) { - Some(v.clone()) - } else if let Some(parent) = self.enclosing { - parent.lookup(s) - } else { - None - } - } - - fn define(&mut self, name: String, val: Value) { - self.vars.insert(name, val); - } -} +mod ast; +mod eval; +#[allow(clippy::all)] +mod grammar; +mod prims; +#[cfg(test)] +mod tests; +mod value; fn main() { let args = std::env::args().collect::>(); @@ -158,9 +33,9 @@ fn main() { fn run_file(file: &str) -> io::Result<()> { let src = std::fs::read_to_string(file)?; let tree = grammar::FileParser::new().parse(&src).unwrap(); - let mut env = default_env(); + let mut env = eval::default_env(); for i in tree { - eval(&i, &mut env).unwrap(); + eval::eval(&i, &mut env).unwrap(); } Ok(()) } @@ -171,231 +46,17 @@ fn repl() { brackets: MatchingBracketValidator::new(), })); - let mut env = default_env(); + let mut env = eval::default_env(); while let Ok(line) = rl.readline("> ") { rl.add_history_entry(&line); let tree = grammar::TreeParser::new().parse(&line).unwrap(); // dbg!(&tree); - println!("< {:?}", eval(&tree, &mut env)) + println!("< {:?}", eval::eval(&tree, &mut env)) } } -fn eval(t: &Tree, env: &mut Env) -> Result { - Ok(match t { - Tree::Leaf(l) => match l { - Literal::Sym(s) => match env.lookup(s) { - Some(v) => v.clone(), - None => return err(format!("Undefined variable `{}`", s)), - }, - Literal::Num(v) => Value::Num(*v), - Literal::Bool(b) => Value::Bool(*b), - }, - Tree::Lambda(l) => Value::Lambda(l.clone()), - Tree::Branch(args) => { - let Some(fun) = args.get(0) else { return err("No argument given".to_owned()) }; - let fun = eval(fun, env)?; - let fun = fun.as_func()?; - let args = args - .iter() - .skip(1) - .map(|a| eval(a, env)) - .collect::, _>>()?; - // return fun(&args); - match fun { - Callable::Func(f) => f(&args)?, - Callable::Lambda(l) => { - if l.0.len() == args.len() { - let mut env = env.child(); - for (x, y) in l.0.iter().zip(args) { - env.define(x.clone(), y) - } - - let [main @ .., tail] = &l.1[..] else { unreachable!("Body has 1+ element by parser") }; - for i in main { - eval(i, &mut env)?; - } - - eval(tail, &mut env)? - } else { - return err(format!("Need {} args, got {}", l.0.len(), args.len())); - } - } - } - } - Tree::Define(name, to) => { - let val = eval(to, env)?; - env.define(name.to_owned(), val); - Value::NotAValue - } - Tree::If(box [cond, tcase, fcase]) => { - let b = eval(cond, env)?.as_bool()?; - let body = if b { tcase } else { fcase }; - eval(body, env)? - } - }) -} - -fn default_env() -> Env<'static> { - let mut vars = HashMap::new(); - - for (name, fun) in prims::prims() { - assert_matches!(vars.insert((*name).to_owned(), Value::Func(*fun)), None) - } - - Env { - vars, - enclosing: None, - } -} - -mod prims { - use crate::{err, Func, RTError, Value}; - - pub(crate) fn prims() -> &'static [(&'static str, Func)] { - &[ - ("*", mul), - ("+", add), - ("-", sub), - ("/", div), - // TODO: Spec compiance - ("=", equals), - ("eq?", equals), - ("eqv?", equals), - ("equal?", equals), - ("display", display), - ("newline", newline), - ("abs", abs), - ("<", lt), - ] - } - - // TODO: DRY +-/* - fn add(args: &[Value]) -> Result { - args.iter() - .map(Value::as_num) - .try_fold(0.0, |a, b| Ok(a + b?)) - .map(Value::Num) - } - - fn mul(args: &[Value]) -> Result { - args.iter() - .map(Value::as_num) - .try_fold(1.0, |a, b| Ok(a * b?)) - .map(Value::Num) - } - - fn div(args: &[Value]) -> Result { - let init = args - .get(0) - .ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))? - .as_num()?; - - Ok(Value::Num(if args.len() == 1 { - 1.0 / init - } else { - let rest = mul(&args[1..])?.as_num().unwrap(); - init / rest - })) - } - - fn sub(args: &[Value]) -> Result { - let init = args - .get(0) - .ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))? - .as_num()?; - - Ok(Value::Num(if args.len() == 1 { - -init - } else { - let rest = add(&args[1..])?.as_num().unwrap(); - init - rest - })) - } - - fn equals(args: &[Value]) -> Result { - Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r))) - } - - fn display(args: &[Value]) -> Result { - let [arg] = args else {return err("To many args to `display`".to_owned())}; - print!("{:?}", arg); - Ok(Value::NotAValue) - } - - fn newline(args: &[Value]) -> Result { - if !args.is_empty() { - return err("Newline takes no args".to_owned()); - } - println!(""); - Ok(Value::NotAValue) - } - - fn abs(args: &[Value]) -> Result { - let [v] = args else { return err("abs takes 1 arg".to_owned()) }; - let ans = v.as_num()?.abs(); - Ok(Value::Num(ans)) - } - - // TODO: gt le ge - fn lt(args: &[Value]) -> Result { - for [l, r] in args.array_windows() { - let (Value::Num(l), Value::Num(r)) = (l,r) else { return err("lt args must be numbers".to_owned()); }; - if !(l < r) { - return Ok(Value::Bool(false)); - }; - } - - Ok(Value::Bool(true)) - } -} - -// #[cfg(test)] -// mod tests { -// use super::*; - -// #[test] -// fn simple_math_space() { -// let t = grammar::TreeParser::new() -// .parse("( + 1 2 ( / 2 3 4 5) )") -// .unwrap(); -// assert_eq!( -// t, -// Tree::Add(vec![ -// Tree::Val(1.0), -// Tree::Val(2.0), -// Tree::Div(vec![ -// Tree::Val(2.0), -// Tree::Val(3.0), -// Tree::Val(4.0), -// Tree::Val(5.0), -// ]) -// ]) -// ); -// } - -// #[test] -// fn simple_math_dence() { -// let t = grammar::TreeParser::new() -// .parse("(+ 1 2 (/ 2 3 4 5))") -// .unwrap(); -// assert_eq!( -// t, -// Tree::Add(vec![ -// Tree::Val(1.0), -// Tree::Val(2.0), -// Tree::Div(vec![ -// Tree::Val(2.0), -// Tree::Val(3.0), -// Tree::Val(4.0), -// Tree::Val(5.0), -// ]) -// ]) -// ); -// } -// } - #[derive(Completer, Helper, Highlighter, Hinter)] struct InputValidator { brackets: MatchingBracketValidator, diff --git a/src/prims.rs b/src/prims.rs new file mode 100644 index 0000000..62e67ff --- /dev/null +++ b/src/prims.rs @@ -0,0 +1,124 @@ +use crate::eval::{err, RTError}; +use crate::value::Value; + +crate type Func = fn(&[Value]) -> Result; + +crate fn prims() -> &'static [(&'static str, Func)] { + &[ + ("*", mul), + ("+", add), + ("-", sub), + ("/", div), + // TODO: Spec compiance + ("=", equals), + ("eq?", equals), + ("eqv?", equals), + ("equal?", equals), + ("display", display), + ("newline", newline), + ("abs", abs), + ("<", lt), + (">", gt), + ("<=", le), + (">=", ge), + ] +} + +// TODO: DRY +-/* +fn add(args: &[Value]) -> Result { + args.iter() + .map(Value::as_num) + .try_fold(0.0, |a, b| Ok(a + b?)) + .map(Value::Num) +} + +fn mul(args: &[Value]) -> Result { + args.iter() + .map(Value::as_num) + .try_fold(1.0, |a, b| Ok(a * b?)) + .map(Value::Num) +} + +fn div(args: &[Value]) -> Result { + let init = args + .get(0) + .ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))? + .as_num()?; + + Ok(Value::Num(if args.len() == 1 { + 1.0 / init + } else { + let rest = mul(&args[1..])?.as_num().unwrap(); + init / rest + })) +} + +fn sub(args: &[Value]) -> Result { + let init = args + .get(0) + .ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))? + .as_num()?; + + Ok(Value::Num(if args.len() == 1 { + -init + } else { + let rest = add(&args[1..])?.as_num().unwrap(); + init - rest + })) +} + +fn equals(args: &[Value]) -> Result { + Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r))) +} + +fn display(args: &[Value]) -> Result { + let [arg] = args else {return err("To many args to `display`".to_owned())}; + print!("{:?}", arg); + Ok(Value::Trap) +} + +fn newline(args: &[Value]) -> Result { + if !args.is_empty() { + return err("Newline takes no args".to_owned()); + } + println!(); + Ok(Value::Trap) +} + +fn abs(args: &[Value]) -> Result { + let [v] = args else { return err("abs takes 1 arg".to_owned()) }; + let ans = v.as_num()?.abs(); + Ok(Value::Num(ans)) +} + +crate fn compare_core( + args: &[Value], + f: fn(f64, f64) -> bool, + name: &'static str, +) -> Result { + for [l, r] in args.array_windows() { + let (Value::Num(l), Value::Num(r)) = (l,r) else + { + return err(format!("`{}` args must be numbers", name)); + }; + + // TODO: Ensure this is correct wrt NaN + if !f(*l, *r) { + return Ok(Value::Bool(false)); + }; + } + + Ok(Value::Bool(true)) +} + +macro_rules! cmps { + ($(($name:ident $op:tt))*) => { + $( + fn $name(args: &[Value]) -> Result { + compare_core(args, |l, r| l $op r, stringify!($op)) + } + )* + }; +} + +cmps! { (lt <) (gt >) (le <=) (ge >=) } \ No newline at end of file diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..09f309a --- /dev/null +++ b/src/value.rs @@ -0,0 +1,72 @@ +use crate::{ast, eval, prims}; +use std::rc::Rc; + +#[derive(Clone)] +crate enum Value { + Num(f64), + Func(prims::Func), + Lambda(ast::Lambda), + Bool(bool), + /// Result of things that shouldnt have values, like (define x 3) + Trap, +} + +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + use Value::*; + match (self, other) { + (Num(l), Num(r)) => l == r, + (Func(l), Func(r)) => *l as usize == *r as usize, + (Bool(l), Bool(r)) => l == r, + (Lambda(l), Lambda(r)) => Rc::ptr_eq(&l.0, &r.0) && Rc::ptr_eq(&l.1, &r.1), + + (Num(_), _) => false, + (Func(_), _) => false, + (Bool(_), _) => false, + (Lambda(_), _) => false, + + (Trap, _) => panic!("Trap value"), + } + } +} + +impl std::fmt::Debug for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Num(n) => n.fmt(f), + Self::Func(_) => f.write_str("#"), + Self::Lambda(_) => f.write_str("#"), + Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }), + Self::Trap => Ok(()), + } + } +} + +impl Value { + crate fn as_num(&self) -> Result { + if let Self::Num(n) = self { + Ok(*n) + } else { + Err(eval::RTError("Expected a number".to_owned())) + } + } + + crate fn as_func(&self) -> Result { + match self { + Self::Func(f) => Ok(eval::Callable::Func(*f)), + Self::Lambda(l) => Ok(eval::Callable::Lambda(l)), + _ => Err(eval::RTError(format!( + "Expected a function, got {:?}", + self + ))), + } + } + + crate fn as_bool(&self) -> Result { + if let Self::Bool(b) = self { + Ok(*b) + } else { + Err(eval::RTError("Expected a bool".to_owned())) + } + } +}