From 19b72152349223fe97a7c6f2f58bec0d437ab581 Mon Sep 17 00:00:00 2001 From: TriMill Date: Fri, 16 Sep 2022 23:06:49 -0400 Subject: [PATCH] project reorganization, general improvements --- Cargo.lock | 29 +++-- Cargo.toml | 14 +-- complexpr-bin/Cargo.toml | 11 ++ {src/bin => complexpr-bin/src}/main.rs | 3 +- complexpr/Cargo.toml | 10 ++ LICENSE => complexpr/LICENSE | 0 README.md => complexpr/README.md | 0 {examples => complexpr/examples}/bf.cxpr | 0 {examples => complexpr/examples}/cat.cxpr | 0 {examples => complexpr/examples}/collatz.cxpr | 0 .../examples}/factorial.cxpr | 0 {examples => complexpr/examples}/fib.cxpr | 0 .../examples}/fib_recur.cxpr | 0 .../examples}/helloworld.cxpr | 0 .../examples}/iterator.cxpr | 0 {examples => complexpr/examples}/mbrot.cxpr | 0 complexpr/src/env.rs | 55 ++++++++++ {src => complexpr/src}/eval.rs | 100 ++++-------------- {src => complexpr/src}/expr.rs | 0 {src => complexpr/src}/interpreter.rs | 2 +- {src => complexpr/src}/lexer.rs | 1 - {src => complexpr/src}/lib.rs | 1 + {src => complexpr/src}/parser.rs | 0 {src => complexpr/src}/stdlib/mod.rs | 2 +- {src => complexpr/src}/token.rs | 2 +- {src => complexpr/src}/value.rs | 34 +++--- 26 files changed, 139 insertions(+), 125 deletions(-) create mode 100644 complexpr-bin/Cargo.toml rename {src/bin => complexpr-bin/src}/main.rs (93%) create mode 100644 complexpr/Cargo.toml rename LICENSE => complexpr/LICENSE (100%) rename README.md => complexpr/README.md (100%) rename {examples => complexpr/examples}/bf.cxpr (100%) rename {examples => complexpr/examples}/cat.cxpr (100%) rename {examples => complexpr/examples}/collatz.cxpr (100%) rename {examples => complexpr/examples}/factorial.cxpr (100%) rename {examples => complexpr/examples}/fib.cxpr (100%) rename {examples => complexpr/examples}/fib_recur.cxpr (100%) rename {examples => complexpr/examples}/helloworld.cxpr (100%) rename {examples => complexpr/examples}/iterator.cxpr (100%) rename {examples => complexpr/examples}/mbrot.cxpr (100%) create mode 100644 complexpr/src/env.rs rename {src => complexpr/src}/eval.rs (80%) rename {src => complexpr/src}/expr.rs (100%) rename {src => complexpr/src}/interpreter.rs (88%) rename {src => complexpr/src}/lexer.rs (99%) rename {src => complexpr/src}/lib.rs (99%) rename {src => complexpr/src}/parser.rs (100%) rename {src => complexpr/src}/stdlib/mod.rs (98%) rename {src => complexpr/src}/token.rs (97%) rename {src => complexpr/src}/value.rs (95%) diff --git a/Cargo.lock b/Cargo.lock index 7718d9d..079e969 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,11 +71,18 @@ dependencies = [ name = "complexpr" version = "0.1.0" dependencies = [ - "backtrace", "lazy_static", "num-complex", "num-rational", "num-traits", +] + +[[package]] +name = "complexpr-bin" +version = "0.1.0" +dependencies = [ + "backtrace", + "complexpr", "rustyline", ] @@ -415,18 +422,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" +checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" +checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" dependencies = [ "proc-macro2", "quote", @@ -435,21 +442,21 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "utf8parse" diff --git a/Cargo.toml b/Cargo.toml index 55701a3..8d1b996 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,2 @@ -[package] -name = "complexpr" -version = "0.1.0" -edition = "2021" - -[dependencies] -lazy_static = "1.4.0" -num-complex = "0.4.2" -num-rational = "0.4.1" -num-traits = "0.2.15" -rustyline = "10.0.0" -backtrace = "0.3.66" +[workspace] +members = [ "complexpr-bin", "complexpr" ] diff --git a/complexpr-bin/Cargo.toml b/complexpr-bin/Cargo.toml new file mode 100644 index 0000000..71fd0b5 --- /dev/null +++ b/complexpr-bin/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "complexpr-bin" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +complexpr = { path = "../complexpr" } +rustyline = "10.0.0" +backtrace = "0.3.66" diff --git a/src/bin/main.rs b/complexpr-bin/src/main.rs similarity index 93% rename from src/bin/main.rs rename to complexpr-bin/src/main.rs index fbec870..dc45b14 100644 --- a/src/bin/main.rs +++ b/complexpr-bin/src/main.rs @@ -1,7 +1,7 @@ use std::{rc::Rc, cell::RefCell, fs, panic::{self, PanicInfo}}; use backtrace::Backtrace; -use complexpr::{eval::Environment, interpreter::interpret, value::Value, stdlib}; +use complexpr::{env::Environment, interpreter::interpret, value::Value, stdlib}; use rustyline::{self, error::ReadlineError}; const C_RESET: &str = "\x1b[0m"; @@ -25,7 +25,6 @@ fn panic_hook(info: &PanicInfo) { } fn main() -> Result<(), Box> { - println!("{}", std::mem::size_of::()); panic::set_hook(Box::new(panic_hook)); let args: Vec = std::env::args().collect(); if args.len() == 2 { diff --git a/complexpr/Cargo.toml b/complexpr/Cargo.toml new file mode 100644 index 0000000..6f5ee3b --- /dev/null +++ b/complexpr/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "complexpr" +version = "0.1.0" +edition = "2021" + +[dependencies] +lazy_static = "1.4.0" +num-complex = "0.4.2" +num-rational = "0.4.1" +num-traits = "0.2.15" diff --git a/LICENSE b/complexpr/LICENSE similarity index 100% rename from LICENSE rename to complexpr/LICENSE diff --git a/README.md b/complexpr/README.md similarity index 100% rename from README.md rename to complexpr/README.md diff --git a/examples/bf.cxpr b/complexpr/examples/bf.cxpr similarity index 100% rename from examples/bf.cxpr rename to complexpr/examples/bf.cxpr diff --git a/examples/cat.cxpr b/complexpr/examples/cat.cxpr similarity index 100% rename from examples/cat.cxpr rename to complexpr/examples/cat.cxpr diff --git a/examples/collatz.cxpr b/complexpr/examples/collatz.cxpr similarity index 100% rename from examples/collatz.cxpr rename to complexpr/examples/collatz.cxpr diff --git a/examples/factorial.cxpr b/complexpr/examples/factorial.cxpr similarity index 100% rename from examples/factorial.cxpr rename to complexpr/examples/factorial.cxpr diff --git a/examples/fib.cxpr b/complexpr/examples/fib.cxpr similarity index 100% rename from examples/fib.cxpr rename to complexpr/examples/fib.cxpr diff --git a/examples/fib_recur.cxpr b/complexpr/examples/fib_recur.cxpr similarity index 100% rename from examples/fib_recur.cxpr rename to complexpr/examples/fib_recur.cxpr diff --git a/examples/helloworld.cxpr b/complexpr/examples/helloworld.cxpr similarity index 100% rename from examples/helloworld.cxpr rename to complexpr/examples/helloworld.cxpr diff --git a/examples/iterator.cxpr b/complexpr/examples/iterator.cxpr similarity index 100% rename from examples/iterator.cxpr rename to complexpr/examples/iterator.cxpr diff --git a/examples/mbrot.cxpr b/complexpr/examples/mbrot.cxpr similarity index 100% rename from examples/mbrot.cxpr rename to complexpr/examples/mbrot.cxpr diff --git a/complexpr/src/env.rs b/complexpr/src/env.rs new file mode 100644 index 0000000..9b1b21c --- /dev/null +++ b/complexpr/src/env.rs @@ -0,0 +1,55 @@ +use std::{collections::HashMap, rc::Rc, cell::RefCell}; + +use crate::value::Value; + +#[derive(Debug)] +pub struct Environment { + parent: Option, + map: HashMap, Value>, +} + +pub type EnvRef = Rc>; + +impl Environment { + pub fn new() -> Self { + Self { parent: None, map: HashMap::new() } + } + + pub fn wrap(self) -> EnvRef { + Rc::new(RefCell::new(self)) + } + + pub fn extend(parent: EnvRef) -> Self { + Self { parent: Some(parent), map: HashMap::new() } + } + + pub fn get(&self, name: &str) -> Option { + match self.map.get(name) { + Some(v) => Some(v.clone()), + None => match self.parent { + Some(ref p) => p.borrow().get(name), + None => None + } + } + } + + pub fn declare(&mut self, name: Rc, value: Value) { + self.map.insert(name, value); + } + + pub fn set(&mut self, name: Rc, value: Value) -> Result<(),()> { + match self.map.contains_key(&name) { + true => { self.map.insert(name, value); Ok(()) }, + false => match self.parent { + Some(ref mut p) => p.borrow_mut().set(name, value), + None => Err(()) + } + } + } +} + +impl Default for Environment { + fn default() -> Self { + Self::new() + } +} diff --git a/src/eval.rs b/complexpr/src/eval.rs similarity index 80% rename from src/eval.rs rename to complexpr/src/eval.rs index bfafbf1..f11960d 100644 --- a/src/eval.rs +++ b/complexpr/src/eval.rs @@ -1,60 +1,9 @@ use std::{collections::HashMap, rc::Rc, cell::RefCell}; -use num_traits::{Pow, Zero}; +use num_traits::Pow; -use crate::{value::{Value, Complex, Func, Rational, CIterator}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position}; +use crate::{value::{Value, Complex, Func, CIterator}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position, env::{EnvRef, Environment}}; -#[derive(Debug)] -pub struct Environment { - parent: Option, - map: HashMap, Value>, -} - -pub type EnvRef = Rc>; - -impl Environment { - pub fn new() -> Self { - Self { parent: None, map: HashMap::new() } - } - - pub fn wrap(self) -> EnvRef { - Rc::new(RefCell::new(self)) - } - - pub fn extend(parent: EnvRef) -> Self { - Self { parent: Some(parent), map: HashMap::new() } - } - - pub fn get(&self, name: &str) -> Option { - match self.map.get(name) { - Some(v) => Some(v.clone()), - None => match self.parent { - Some(ref p) => p.borrow().get(name), - None => None - } - } - } - - pub fn declare(&mut self, name: Rc, value: Value) { - self.map.insert(name, value); - } - - pub fn set(&mut self, name: Rc, value: Value) -> Result<(),()> { - match self.map.contains_key(&name) { - true => { self.map.insert(name, value); Ok(()) }, - false => match self.parent { - Some(ref mut p) => p.borrow_mut().set(name, value), - None => Err(()) - } - } - } -} - -impl Default for Environment { - fn default() -> Self { - Self::new() - } -} #[derive(Debug)] pub enum Unwind { @@ -256,6 +205,19 @@ pub fn eval_ident(token: &Token, env: EnvRef) -> Result { } } +fn compound_assignment_inner(l: Value, r: Value, op: &Token) -> Result { + match op.ty { + TokenType::PlusEqual => &l + &r, + TokenType::MinusEqual => &l - &r, + TokenType::StarEqual => &l * &r, + TokenType::SlashEqual => &l / &r, + TokenType::PercentEqual => &l % &r, + TokenType::CaretEqual => l.pow(&r), + TokenType::DoubleSlashEqual => l.fracdiv(&r), + _ => todo!() // TODO more operations + }.map_err(|e| RuntimeError::new(e, op.pos.clone())) +} + pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result { // lhs must be an identifier (checked in parser) if let Expr::Ident{value: Token{ty: TokenType::Ident(name),..}} = lhs { @@ -273,14 +235,7 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul .ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?; let r = eval_expr(rhs, env.clone())?; - let result = match op.ty { - TokenType::PlusEqual => &prev_value + &r, - TokenType::MinusEqual => &prev_value - &r, - TokenType::StarEqual => &prev_value * &r, - TokenType::SlashEqual => &prev_value / &r, - TokenType::PercentEqual => &prev_value % &r, - _ => todo!() // TODO more operations - }.map_err(|e| RuntimeError::new(e, op.pos.clone()))?; + let result = compound_assignment_inner(prev_value, r, op)?; env.borrow_mut() .set(name.clone(), result.clone()).expect("unreachable"); @@ -296,14 +251,7 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul } else { let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?; let r = eval_expr(rhs, env)?; - let result = match op.ty { - TokenType::PlusEqual => &prev_value + &r, - TokenType::MinusEqual => &prev_value - &r, - TokenType::StarEqual => &prev_value * &r, - TokenType::SlashEqual => &prev_value / &r, - TokenType::PercentEqual => &prev_value % &r, - _ => todo!() // TODO more operations - }.map_err(|e| RuntimeError::new(e, op.pos.clone()))?; + let result = compound_assignment_inner(prev_value, r, op)?; l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?; Ok(result) } @@ -322,18 +270,8 @@ pub fn eval_arith(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result &l / &r, TokenType::Percent => &l % &r, TokenType::Caret => l.pow(&r), - TokenType::DoubleSlash => match (l, r) { - (Value::Int(_), Value::Int(b)) if b == 0 => Err("Integer division by zero".into()), - (Value::Rational(_), Value::Int(b)) if b == 0 => Err("Rational division by zero".into()), - (Value::Int(_), Value::Rational(b)) if b.is_zero() => Err("Rational division by zero".into()), - (Value::Rational(_), Value::Rational(b)) if b.is_zero() => Err("Rational division by zero".into()), - (Value::Int(a), Value::Int(b)) => Ok(Value::Rational(Rational::new(a, b))), - (Value::Rational(a), Value::Int(b)) => Ok(Value::from(a/b)), - (Value::Int(a), Value::Rational(b)) => Ok(Value::from(b.recip()*a)), - (Value::Rational(a), Value::Rational(b)) => Ok(Value::from(a/b)), - (x,y) => Err(format!("Unsupported operation 'fracdiv' between {:?} and {:?}", x, y)) - }, - _ => todo!() // TODO other operations + TokenType::DoubleSlash => l.fracdiv(&r), + _ => todo!() }.map_err(|e| RuntimeError::new(e, op.pos.clone())) } diff --git a/src/expr.rs b/complexpr/src/expr.rs similarity index 100% rename from src/expr.rs rename to complexpr/src/expr.rs diff --git a/src/interpreter.rs b/complexpr/src/interpreter.rs similarity index 88% rename from src/interpreter.rs rename to complexpr/src/interpreter.rs index 36cfefc..4f62508 100644 --- a/src/interpreter.rs +++ b/complexpr/src/interpreter.rs @@ -1,6 +1,6 @@ use std::{cell::RefCell, rc::Rc}; -use crate::{value::Value, lexer::Lexer, parser::Parser, eval::{Environment, eval_stmt, eval_expr, EnvRef}, expr::Stmt, stdlib}; +use crate::{value::Value, lexer::Lexer, parser::Parser, eval::{eval_stmt, eval_expr}, expr::Stmt, stdlib, env::{EnvRef, Environment}}; pub fn interpret(src: &str, fname: Option, env: Option, repl: bool) -> Result> { let ctx_name = if repl { "" } else { fname.as_ref().map(|s| s.as_ref()).unwrap_or("") }; diff --git a/src/lexer.rs b/complexpr/src/lexer.rs similarity index 99% rename from src/lexer.rs rename to complexpr/src/lexer.rs index ba12a20..bf79d30 100644 --- a/src/lexer.rs +++ b/complexpr/src/lexer.rs @@ -146,7 +146,6 @@ impl Lexer { }, '-' => match self.expect(&['=', '>']) { Some('=') => self.add_token(TokenType::MinusEqual, "-="), - Some('>') => self.add_token(TokenType::Arrow, "->"), _ => self.add_token(TokenType::Minus, "-"), }, '*' => match self.expect(&['=']) { diff --git a/src/lib.rs b/complexpr/src/lib.rs similarity index 99% rename from src/lib.rs rename to complexpr/src/lib.rs index 39b95cc..535eca8 100644 --- a/src/lib.rs +++ b/complexpr/src/lib.rs @@ -7,6 +7,7 @@ pub mod parser; pub mod value; pub mod eval; pub mod interpreter; +pub mod env; pub mod stdlib; #[derive(Clone, Debug)] diff --git a/src/parser.rs b/complexpr/src/parser.rs similarity index 100% rename from src/parser.rs rename to complexpr/src/parser.rs diff --git a/src/stdlib/mod.rs b/complexpr/src/stdlib/mod.rs similarity index 98% rename from src/stdlib/mod.rs rename to complexpr/src/stdlib/mod.rs index 0164e77..0f58214 100644 --- a/src/stdlib/mod.rs +++ b/complexpr/src/stdlib/mod.rs @@ -2,7 +2,7 @@ use std::{rc::Rc, io::Write, cmp::Ordering, time::{SystemTime, UNIX_EPOCH}, cell use num_traits::ToPrimitive; -use crate::{value::{Value, Func, CIterator}, eval::Environment, RuntimeError}; +use crate::{value::{Value, Func, CIterator}, RuntimeError, env::Environment}; pub fn load(env: &mut Environment) { let mut name: Rc; diff --git a/src/token.rs b/complexpr/src/token.rs similarity index 97% rename from src/token.rs rename to complexpr/src/token.rs index 771c376..85c26d0 100644 --- a/src/token.rs +++ b/complexpr/src/token.rs @@ -27,7 +27,7 @@ pub enum TokenType { Equal, PlusEqual, MinusEqual, StarEqual, SlashEqual, PercentEqual, DoubleSlashEqual, CaretEqual, DoubleEqual, BangEqual, Greater, GreaterEqual, Less, LessEqual, Spaceship, - Arrow, PipeColon, PipePoint, PipeQuestion, PipeAmper, + PipeColon, PipePoint, PipeQuestion, PipeAmper, Comma, Semicolon, Colon, diff --git a/src/value.rs b/complexpr/src/value.rs similarity index 95% rename from src/value.rs rename to complexpr/src/value.rs index bad0582..7a22427 100644 --- a/src/value.rs +++ b/complexpr/src/value.rs @@ -2,7 +2,7 @@ use std::{rc::Rc, collections::HashMap, ops::*, fmt, cmp::Ordering, cell::RefCel use num_traits::{Zero, ToPrimitive, Pow}; -use crate::{RuntimeError, eval::{EnvRef, eval_stmt, Environment, Unwind, eval_expr}, expr::Stmt}; +use crate::{RuntimeError, eval::{eval_stmt, Unwind, eval_expr}, expr::Stmt, env::{EnvRef, Environment}}; pub type Rational = num_rational::Ratio; pub type Complex = num_complex::Complex64; @@ -231,24 +231,13 @@ impl Value { pub fn repr(&self) -> Rc { match self { - Self::Nil => Rc::from("nil"), - Self::Bool(b) => Rc::from(b.to_string()), - Self::Int(n) => Rc::from(n.to_string()), - Self::Float(f) => Rc::from(f.to_string()), - Self::Rational(r) => Rc::from(r.to_string()), - Self::Complex(z) => Rc::from(z.to_string()), + Self::Float(f) => Rc::from(format!("{:?}",f)), + Self::Rational(r) => Rc::from(r.numer().to_string() + "//" + &r.denom().to_string()), Self::Char(c) => Rc::from(format!("'{}'", c)), // TODO escaping Self::String(s) => Rc::from(format!("\"{}\"", s)), // TODO escaping Self::List(l) => Rc::from(format!("{:?}", l.borrow())), // TODO fix Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix - Self::Type(_) => todo!(), - Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("", name, *func as *const ())), - Self::Func(Func::BuiltinClosure { func, .. }) => Rc::from(format!("", *func as *const ())), - Self::Func(Func::Func { name, .. }) => match name { - Some(name) => Rc::from(format!("", name)), - None => Rc::from(""), - }, - Self::Data(_) => todo!(), + _ => self.to_string(), } } @@ -300,6 +289,21 @@ impl Value { v => Err(format!("{:?} has no length", v).into()) } } + + pub fn fracdiv(&self, other: &Value) -> Result { + use Value::*; + match (self, other) { + (Int(_), Int(b)) if *b == 0 => Err("Integer division by zero".into()), + (Rational(_), Int(b)) if *b == 0 => Err("Rational division by zero".into()), + (Int(_), Rational(b)) if b.is_zero() => Err("Rational division by zero".into()), + (Rational(_), Rational(b)) if b.is_zero() => Err("Rational division by zero".into()), + (Int(a), Int(b)) => Ok(Value::from(crate::value::Rational::new(*a, *b))), + (Rational(a), Int(b)) => Ok(Value::from(a/b)), + (Int(a), Rational(b)) => Ok(Value::from(b.recip()*a)), + (Rational(a), Rational(b)) => Ok(Value::from(a/b)), + (x,y) => Err(format!("Unsupported operation 'fracdiv' between {:?} and {:?}", x, y)) + } + } } impl PartialEq for Value {