From 8dd7d5607c9151b38aad43784b3e0b826df941af Mon Sep 17 00:00:00 2001 From: TriMill Date: Fri, 16 Sep 2022 16:05:28 -0400 Subject: [PATCH] Refactoring, some pipes, exponents --- idea.cxpr | 6 +- src/bin/main.rs | 1 + src/eval.rs | 81 +++++++++++++++++-- src/lib.rs | 18 +++++ src/parser.rs | 67 ++++++---------- src/stdlib/mod.rs | 90 +++++++++++++-------- src/value.rs | 194 +++++++++++++++++++++++++++++----------------- 7 files changed, 298 insertions(+), 159 deletions(-) diff --git a/idea.cxpr b/idea.cxpr index 3026100..23704ca 100644 --- a/idea.cxpr +++ b/idea.cxpr @@ -3,7 +3,7 @@ let also_square(x) = x^2; let primes = range(100) |: filter(is_prime); let prime_squares = range(100) |: map(square); -let also_prime_squares = range(100) |? is_prime |> square; +let also_prime_squares = range(100) |? is_prime |: square; # let primes_and_prime_squares = primes |& prime_squares; @@ -27,6 +27,6 @@ for p : primes { let D = x -> { let facts = factors(x); - let product = facts |: foldl(1, mul); - return facts |> (n -> product / n) |: foldl(0, add); + let product = facts |> foldl(1, mul); + return facts |: (n -> product / n) |> foldl(0, add); } diff --git a/src/bin/main.rs b/src/bin/main.rs index 84347b1..fbec870 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -25,6 +25,7 @@ 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/src/eval.rs b/src/eval.rs index 1fd803a..a2f7a79 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,8 @@ use std::{collections::HashMap, rc::Rc, cell::RefCell}; -use crate::{value::{Value, Complex, Func}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position}; +use num_traits::{Pow, Zero}; + +use crate::{value::{Value, Complex, Func, Rational, CIterator}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position}; #[derive(Debug)] pub struct Environment { @@ -118,13 +120,13 @@ pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), Unwind> { let name = unwrap_ident_token(var); let iter = eval_expr(expr, env.clone())?; env.borrow_mut().declare(name.clone(), Value::Nil); - let iterator = iter.iter(iter_pos); + let iterator = iter.iter(); if let Err(e) = iterator { - return Err(RuntimeError::new(e, var.pos.clone()).into()) + return Err(RuntimeError::new(e, iter_pos.clone()).into()) } if let Ok(i) = iterator { for v in i { - let v = v?; + let v = v.map_err(|e| e.complete(iter_pos.clone()))?; let env = env.clone(); env.borrow_mut().set(name.clone(), v).expect("unreachable"); match eval_stmt(stmt, env) { @@ -177,12 +179,14 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result { Expr::Binary { lhs, rhs, op } => match op.ty.get_op_type() { Some(OpType::Assignment) => eval_assignment(lhs, rhs, op, env), - Some(OpType::Additive) | Some(OpType::Multiplicative) - => eval_binary(lhs, rhs, op, env), + Some(OpType::Additive) | Some(OpType::Multiplicative) | Some(OpType::Exponential) + => eval_arith(lhs, rhs, op, env), Some(OpType::Boolean) => eval_boolean(lhs, rhs, op, env), Some(OpType::Comparison) => eval_comp(lhs, rhs, op, env), + Some(OpType::Pipeline) + => eval_pipeline(lhs, rhs, op, env), o => todo!("{:?}", o) // TODO other operations }, Expr::Unary { arg, op } => eval_unary(arg, op, env), @@ -209,7 +213,7 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result { let result = eval_expr(arg, env.clone())?; arg_values.push(result); } - func.call(arg_values, pos) + func.call(arg_values).map_err(|e| e.complete(pos.clone())) }, Expr::Index { lhs, index, pos } => { let l = eval_expr(lhs, env.clone())?; @@ -308,7 +312,7 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul } } -pub fn eval_binary(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result { +pub fn eval_arith(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result { let l = eval_expr(lhs, env.clone())?; let r = eval_expr(rhs, env)?; match op.ty { @@ -317,6 +321,18 @@ pub fn eval_binary(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result &l * &r, TokenType::Slash => &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 }.map_err(|e| RuntimeError::new(e, op.pos.clone())) } @@ -367,6 +383,55 @@ pub fn eval_comp(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result, data: Rc>>, iter_data: Rc>>) -> Result { + let f = &data.borrow()[0]; + if let Some(next) = iter_data.borrow_mut()[0].next() { + f.call(vec![next?]) + } else { + Ok(Value::Nil) + } +} + +fn pipequestion_inner(_: Vec, data: Rc>>, iter_data: Rc>>) -> Result { + let f = &data.borrow()[0]; + loop { + let next = iter_data.borrow_mut()[0].next(); + if let Some(next) = next { + let next = next?; + let success = f.call(vec![next.clone()])?.truthy(); + if success { + return Ok(next) + } + } else { + return Ok(Value::Nil) + } + } +} + +pub fn eval_pipeline(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result { + let l = eval_expr(lhs, env.clone())?; + let r = eval_expr(rhs, env)?; + match op.ty { + TokenType::PipeColon => { + Ok(Value::Func(Func::BuiltinClosure { + arg_count: 0, + data: Rc::new(RefCell::new(vec![r])), + iter_data: Rc::new(RefCell::new(vec![l.iter()?])), + func: pipecolon_inner, + })) + }, + TokenType::PipeQuestion => { + Ok(Value::Func(Func::BuiltinClosure { + arg_count: 0, + data: Rc::new(RefCell::new(vec![r])), + iter_data: Rc::new(RefCell::new(vec![l.iter()?])), + func: pipequestion_inner, + })) + }, + _ => todo!() + } +} + pub fn eval_unary(arg: &Expr, op: &Token, env: EnvRef) -> Result { let a = eval_expr(arg, env)?; match op.ty { diff --git a/src/lib.rs b/src/lib.rs index 342f84f..39b95cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,13 @@ impl RuntimeError { } } + pub fn complete(mut self, last_pos: Position) -> Self { + if self.last_pos.is_none() { + self.last_pos = Some(last_pos); + } + self + } + pub fn exit_fn(mut self, fn_name: Option>, pos: Position) -> Self { self.stacktrace.push(Stackframe { pos: self.last_pos.expect("RuntimeError never completed after construction"), fn_name }); self.last_pos = Some(pos); @@ -69,6 +76,17 @@ impl RuntimeError { } } +impl From for RuntimeError { + fn from(s: String) -> Self { + Self::new_incomplete(s) + } +} + +impl From<&str> for RuntimeError { + fn from(s: &str) -> Self { + Self::new_incomplete(s) + } +} impl fmt::Display for ParserError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/parser.rs b/src/parser.rs index fe2d146..2a2278e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -45,19 +45,19 @@ impl Parser { pub fn parse(&mut self) -> Result, ParserError> { let mut stmts = vec![]; while !self.at_end() { - stmts.push(self.statement()?); + stmts.push(self.statement(!self.repl)?); } Ok(stmts) } - fn statement(&mut self) -> Result { + fn statement(&mut self, req_semicolon: bool) -> Result { let next_ty = &self.peek().ty; match next_ty { TokenType::Let => { // let statement self.next(); - self.letstmt() + self.letstmt(req_semicolon) }, TokenType::LBrace => { // block @@ -81,16 +81,16 @@ impl Parser { }, TokenType::Break => { let tok = self.next(); - self.terminate_stmt(Stmt::Break{ pos: tok.pos }) + self.terminate_stmt(Stmt::Break{ pos: tok.pos }, req_semicolon) }, TokenType::Continue => { let tok = self.next(); - self.terminate_stmt(Stmt::Continue{ pos: tok.pos }) + self.terminate_stmt(Stmt::Continue{ pos: tok.pos }, req_semicolon) }, TokenType::Return => { let tok = self.next(); let expr = self.assignment()?; - self.terminate_stmt(Stmt::Return{ pos: tok.pos, expr }) + self.terminate_stmt(Stmt::Return{ pos: tok.pos, expr }, req_semicolon) }, TokenType::Fn => { self.next(); @@ -99,18 +99,17 @@ impl Parser { _ => { // fallback to an expression terminated with a semicolon let expr = self.assignment()?; - self.terminate_stmt(Stmt::Expr{ expr }) + self.terminate_stmt(Stmt::Expr{ expr }, req_semicolon) } } } - fn terminate_stmt(&mut self, stmt: Stmt) -> Result { + fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result { + if !req_semicolon { + return Ok(stmt) + } if self.at_end() { - if self.repl { - return Ok(stmt) - } else { - self.err_on_eof()?; - } + self.err_on_eof()?; } let next = self.next(); @@ -122,39 +121,17 @@ impl Parser { } - fn letstmt(&mut self) -> Result { + fn letstmt(&mut self, req_semicolon: bool) -> Result { let expr = self.assignment()?; // must be followed by an assignment expression if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr { if let Expr::Ident{value: tok} = *lhs { - if self.at_end() { - if self.repl { - return Ok(Stmt::Let{lhs: tok, rhs: Some(*rhs)}) - } else { - self.err_on_eof()?; - } - } - let next = self.next(); - match next.ty { - TokenType::Semicolon => Ok(Stmt::Let{lhs: tok, rhs: Some(*rhs)}), - _ => Err(self.mk_error("Missing semicolon after 'let' statement".to_owned())) - } + self.terminate_stmt(Stmt::Let{lhs: tok, rhs: Some(*rhs)}, req_semicolon) } else { Err(self.mk_error("Invalid expression after 'let'".to_owned())) } } else if let Expr::Ident{value: tok} = expr { - if self.at_end() { - if self.repl { - return Ok(Stmt::Let{lhs: tok, rhs: None}) - } else { - self.err_on_eof()?; - } - } - let next = self.next(); - match next.ty { - TokenType::Semicolon => Ok(Stmt::Let{lhs: tok, rhs: None}), - _ => Err(self.mk_error("Missing semicolon after 'let' statement".to_owned())) - } + self.terminate_stmt(Stmt::Let{lhs: tok, rhs: None}, req_semicolon) } else { Err(self.mk_error("Invalid expression after 'let'".to_owned())) } @@ -165,7 +142,7 @@ impl Parser { let mut ec = false; loop { let condition = self.assignment()?; - let body = self.statement()?; + let body = self.statement(true)?; if_clauses.push((condition, body)); match self.peek().ty { TokenType::Elif => { self.next(); continue }, @@ -174,7 +151,7 @@ impl Parser { } } let else_clause = if ec { - Some(Box::new(self.statement()?)) + Some(Box::new(self.statement(true)?)) } else { None }; @@ -195,7 +172,7 @@ impl Parser { self.err_on_eof()?; let expr = self.assignment()?; self.err_on_eof()?; - let stmt = self.statement()?; + let stmt = self.statement(true)?; Ok(Stmt::For{ var, expr, stmt: Box::new(stmt), iter_pos: colon.pos }) } else { Err(self.mk_error("Expected identifier after for")) @@ -206,7 +183,7 @@ impl Parser { self.err_on_eof()?; let expr = self.assignment()?; self.err_on_eof()?; - let stmt = self.statement()?; + let stmt = self.statement(true)?; Ok(Stmt::While{ expr, stmt: Box::new(stmt) }) } @@ -225,7 +202,7 @@ impl Parser { } let args = self.commalist(TokenType::RParen, Self::ident)?; self.err_on_eof()?; - let body = self.statement()?; + let body = self.statement(false)?; Ok(Stmt::Fn { name, args, body: Box::new(body) }) } @@ -240,7 +217,7 @@ impl Parser { fn block(&mut self) -> Result { let mut stmts = vec![]; while !self.at_end() && self.peek().ty != TokenType::RBrace { - stmts.push(self.statement()?) + stmts.push(self.statement(true)?) } self.err_on_eof()?; self.next(); @@ -411,7 +388,7 @@ impl Parser { } let args = self.commalist(TokenType::RParen, Self::ident)?; self.err_on_eof()?; - let body = self.statement()?; + let body = self.statement(false)?; Ok(Expr::Fn { args, body: Box::new(body) }) } else { Err(self.mk_error(format!("Unexpected token: {:?}", next.ty))) diff --git a/src/stdlib/mod.rs b/src/stdlib/mod.rs index e8156fb..0164e77 100644 --- a/src/stdlib/mod.rs +++ b/src/stdlib/mod.rs @@ -1,8 +1,8 @@ -use std::{rc::Rc, io::Write, cmp::Ordering, time::{SystemTime, UNIX_EPOCH}}; +use std::{rc::Rc, io::Write, cmp::Ordering, time::{SystemTime, UNIX_EPOCH}, cell::RefCell}; use num_traits::ToPrimitive; -use crate::{value::{Value, Func}, eval::Environment}; +use crate::{value::{Value, Func, CIterator}, eval::Environment, RuntimeError}; pub fn load(env: &mut Environment) { let mut name: Rc; @@ -32,28 +32,30 @@ pub fn load(env: &mut Environment) { env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_im, arg_count: 1, name })); name = Rc::from("time"); env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_time, arg_count: 0, name })); + name = Rc::from("list"); + env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_list, arg_count: 1, name })); } -fn fn_str(args: Vec) -> Result { +fn fn_str(args: Vec) -> Result { Ok(Value::String(args[0].to_string())) } -fn fn_repr(args: Vec) -> Result { +fn fn_repr(args: Vec) -> Result { Ok(Value::String(args[0].repr())) } -fn fn_print(args: Vec) -> Result { +fn fn_print(args: Vec) -> Result { print!("{}", args[0].to_string()); std::io::stdout().flush().map_err(|e| e.to_string())?; Ok(Value::Nil) } -fn fn_println(args: Vec) -> Result { +fn fn_println(args: Vec) -> Result { println!("{}", args[0].to_string()); Ok(Value::Nil) } -fn fn_input(_: Vec) -> Result { +fn fn_input(_: Vec) -> Result { let mut buffer = String::new(); let stdin = std::io::stdin(); stdin.read_line(&mut buffer).map_err(|e| e.to_string())?; @@ -63,7 +65,7 @@ fn fn_input(_: Vec) -> Result { Ok(Value::from(buffer)) } -fn fn_ord(args: Vec) -> Result { +fn fn_ord(args: Vec) -> Result { if let Value::Char(c) = args[0] { Ok(Value::from(c as u32)) } else { @@ -71,7 +73,7 @@ fn fn_ord(args: Vec) -> Result { } } -fn fn_chr(args: Vec) -> Result { +fn fn_chr(args: Vec) -> Result { if let Value::Int(i) = args[0] { if i >= 0 && i < (u32::MAX as i64) { if let Some(c) = char::from_u32(i as u32) { @@ -84,57 +86,77 @@ fn fn_chr(args: Vec) -> Result { } } -fn fn_range(args: Vec) -> Result { - let min = &args[0]; - let max = &args[1]; - match (min, max) { +fn range_inner(_: Vec, data: Rc>>, _: Rc>>) -> Result { + const ZERO: Value = Value::Int(0); + let mut d = data.borrow_mut(); + if d[2] >= ZERO && d[0] >= d[1] { + Ok(Value::Nil) + } else if d[2] <= ZERO && d[0] <= d[1] { + Ok(Value::Nil) + } else { + let res = d[0].clone(); + d[0] = (&d[0] + &d[2])?; + Ok(res) + } +} + +fn fn_range(args: Vec) -> Result { + let start = &args[0]; + let end = &args[1]; + let delta = match (start, end) { (Value::Int(a), Value::Int(b)) => match a.cmp(b) { - Ordering::Equal => Ok(Value::from(vec![])), - Ordering::Less => - Ok(Value::from((*a..*b).map(Value::Int).collect::>())), - Ordering::Greater => - Ok(Value::from(((*b+1)..(*a+1)).rev().map(Value::Int).collect::>())) + Ordering::Equal => 0, + Ordering::Less => 1, + Ordering::Greater => -1, }, - _ => Err("Both arguments to range must be integers".into()) - } + _ => return Err("Both arguments to range must be integers".into()) + }; + return Ok(Value::Func(Func::BuiltinClosure { + arg_count: 0, + data: Rc::new(RefCell::new(vec![start.clone(), end.clone(), Value::Int(delta)])), + iter_data: Rc::new(RefCell::new(vec![])), + func: range_inner + })) } -fn fn_len(args: Vec) -> Result { - match &args[0] { - Value::String(s) => Ok(Value::Int(s.len() as i64)), - Value::List(l) => Ok(Value::Int(l.borrow().len() as i64)), - Value::Map(m) => Ok(Value::Int(m.borrow().len() as i64)), - v => Err(format!("{:?} has no length", v)) - } +fn fn_len(args: Vec) -> Result { + Ok(Value::Int(args[0].len().map_err(|e| RuntimeError::new_incomplete(e))? as i64)) } -fn fn_has(args: Vec) -> Result { +fn fn_has(args: Vec) -> Result { match &args[0] { Value::Map(m) => Ok(Value::from(m.borrow().contains_key(&args[1]))), - v => Err(format!("Argument to has must be a map, got {:?} ", v)) + v => Err(format!("Argument to has must be a map, got {:?} ", v).into()) } } -fn fn_re(args: Vec) -> Result { +fn fn_re(args: Vec) -> Result { match &args[0] { Value::Int(x) => Ok(Value::Float(*x as f64)), Value::Float(x) => Ok(Value::Float(*x)), Value::Rational(x) => Ok(Value::Float(x.to_f64().unwrap())), Value::Complex(x) => Ok(Value::Float(x.re)), - x => Err(format!("Cannot get real part of {:?}", x)) + x => Err(format!("Cannot get real part of {:?}", x).into()) } } -fn fn_im(args: Vec) -> Result { +fn fn_im(args: Vec) -> Result { match &args[0] { Value::Int(_) | Value::Float(_) | Value::Rational(_) => Ok(Value::Float(0.0)), Value::Complex(x) => Ok(Value::Float(x.im)), - x => Err(format!("Cannot get real part of {:?}", x)) + x => Err(format!("Cannot get real part of {:?}", x).into()) } } -fn fn_time(_: Vec) -> Result { +fn fn_time(_: Vec) -> Result { let time = SystemTime::now().duration_since(UNIX_EPOCH).map_err(|e| e.to_string())?; Ok(Value::from(time.as_secs_f64())) } + +fn fn_list(args: Vec) -> Result { + let a = args[0].iter()?; + let mut res = Vec::new(); + for v in a { res.push(v?); } + Ok(Value::from(res)) +} diff --git a/src/value.rs b/src/value.rs index 2168eff..bad0582 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,8 +1,8 @@ use std::{rc::Rc, collections::HashMap, ops::*, fmt, cmp::Ordering, cell::RefCell, hash::Hash}; -use num_traits::{Zero, ToPrimitive}; +use num_traits::{Zero, ToPrimitive, Pow}; -use crate::{RuntimeError, Position, eval::{EnvRef, eval_stmt, Environment, Unwind}, expr::Stmt}; +use crate::{RuntimeError, eval::{EnvRef, eval_stmt, Environment, Unwind, eval_expr}, expr::Stmt}; pub type Rational = num_rational::Ratio; pub type Complex = num_complex::Complex64; @@ -13,12 +13,18 @@ pub enum Func { name: Option>, args: Vec>, env: EnvRef, - func: Stmt + func: Stmt, }, Builtin { name: Rc, - func: fn(Vec) -> Result, - arg_count: usize + func: fn(Vec) -> Result, + arg_count: usize, + }, + BuiltinClosure { + func: fn(Vec, Rc>>, Rc>>) -> Result, + data: Rc>>, + iter_data: Rc>>, + arg_count: usize, } } @@ -35,6 +41,11 @@ impl fmt::Debug for Func { .field("name", name) .field("arg_count", arg_count) .finish_non_exhaustive(), + Self::BuiltinClosure { arg_count, data, .. } + => f.debug_struct("Func::BuiltinClosure") + .field("arg_count", arg_count) + .field("data", data) + .finish_non_exhaustive(), } } @@ -44,34 +55,39 @@ impl Func { pub fn arg_count(&self) -> usize { match self { Self::Builtin { arg_count, .. } => *arg_count, - Self::Func { args, .. } => args.len() + Self::BuiltinClosure { arg_count, .. } => *arg_count, + Self::Func { args, .. } => args.len(), } } - pub fn call(&self, arg_values: Vec, pos: &Position) -> Result { + pub fn call(&self, arg_values: Vec) -> Result { match arg_values.len().cmp(&self.arg_count()) { Ordering::Equal => match self { Self::Builtin { func, .. } - => func(arg_values).map_err(|e| RuntimeError::new(e, pos.clone())), - Self::Func { name, args, func, env } => { + => func(arg_values), + Self::BuiltinClosure { func, data, iter_data, .. } + => func(arg_values, data.clone(), iter_data.clone()), + Self::Func { args, func, env, .. } => { let mut env = Environment::extend(env.clone()); for (k, v) in args.iter().zip(arg_values.iter()) { env.declare(k.clone(), v.clone()); } - match eval_stmt(func, env.wrap()) { - Ok(()) => Ok(Value::Nil), - Err(Unwind::Return{ value, .. }) => Ok(value), - Err(e) => Err(e.as_error().exit_fn(name.clone(), pos.clone())) + match func { + Stmt::Expr { expr } => eval_expr(expr, env.wrap()), + stmt => match eval_stmt(stmt, env.wrap()) { + Ok(()) => Ok(Value::Nil), + Err(Unwind::Return{ value, .. }) => Ok(value), + Err(e) => Err(e.as_error()), + } + } } } - Ordering::Less => Err(RuntimeError::new( - format!("Not enough arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()), - pos.clone() + Ordering::Less => Err(RuntimeError::new_incomplete( + format!("Not enough arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()) )), - Ordering::Greater => Err(RuntimeError::new( - format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()), - pos.clone() + Ordering::Greater => Err(RuntimeError::new_incomplete( + format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()) )) } } @@ -88,53 +104,39 @@ impl Hash for Func { Self::Func { name, args, .. } => { name.hash(state); args.hash(state); + }, + Self::BuiltinClosure { arg_count, data, .. } => { + arg_count.hash(state); + data.borrow().hash(state); } } } } -pub enum EitherRteOrString { - Rte(RuntimeError), String(String) +pub enum CIterator { + // precondition: value must be len()able + Indexable{ value: Value, idx: i64 }, + Func(Func) } -impl EitherRteOrString { - pub fn to_rte(self, pos: &Position) -> RuntimeError { - match self { - Self::Rte(e) => e, - Self::String(s) => RuntimeError::new(s, pos.clone()) - } - } -} +impl Iterator for CIterator { + type Item = Result; -impl From for EitherRteOrString { - fn from(s: String) -> Self { - Self::String(s) - } -} - -impl From for EitherRteOrString { - fn from(e: RuntimeError) -> Self { - Self::Rte(e) - } -} - -impl Iterator for Func { - type Item = Result; fn next(&mut self) -> Option { match self { - Self::Builtin { func, .. } => match (func)(vec![]) { - Ok(Value::Nil) => None, - r => Some(r.map_err(|e| e.into())), - }, - Self::Func { func, env, .. } => { - let env = Environment::extend(env.clone()).wrap(); - match eval_stmt(&func, env) { - Ok(_) => None, - Err(Unwind::Return{ value: Value::Nil, .. }) => None, - Err(Unwind::Return{ value, .. }) => Some(Ok(value)), - Err(e) => Some(Err(e.as_error().into())) + Self::Indexable{ value, ref mut idx } => { + if *idx >= value.len().unwrap() as i64 { + None + } else { + let result = value.index(&Value::Int(*idx)).unwrap(); + *idx += 1; + Some(Ok(result)) } - } + }, + Self::Func(f) => match f.call(vec![]) { + Ok(Value::Nil) => None, + x => Some(x) + }, } } } @@ -152,7 +154,6 @@ pub struct Type { } #[derive(Clone, Debug)] -#[repr(u8)] pub enum Value { Nil, Type(usize), @@ -177,19 +178,18 @@ impl Value { String(s) => !s.len() == 0, List(l) => !l.borrow().len() == 0, Map(m) => !m.borrow().len() == 0, + Char(c) => *c != '\0', _ => true } } - pub fn iter<'a>(&'a self, pos: &'a Position) -> Result> + '_>, String> { + pub fn iter<'a>(&'a self) -> Result { match self { - Value::String(s) - => Ok(Box::new(s.chars() - .map(Value::Char).map(Ok))), - Value::List(l) => Ok(Box::new(l.borrow().clone().into_iter().map(Ok))), + Value::String(_) | Value::List(_) + => Ok(CIterator::Indexable { value: self.clone(), idx: 0 }), Value::Func(f) => { if f.arg_count() == 0 { - Ok(Box::new(f.clone().map(|e| e.map_err(|e| e.to_rte(pos))))) + Ok(CIterator::Func(f.clone())) } else { Err("Only zero-argument functions can be used as iterators".into()) } @@ -198,11 +198,11 @@ impl Value { } } - pub fn call(&self, args: Vec, pos: &Position) -> Result { + pub fn call(&self, args: Vec) -> Result { if let Value::Func(f) = self { - f.call(args, pos) + f.call(args) } else { - Err(RuntimeError::new("Cannot call", pos.clone())) + Err(RuntimeError::new_incomplete("Cannot call")) } } @@ -220,6 +220,7 @@ impl Value { 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(""), @@ -242,6 +243,7 @@ impl Value { 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(""), @@ -289,6 +291,15 @@ impl Value { v => Err(format!("Cannot assign to index in {:?}", v)) } } + + pub fn len(&self) -> Result { + match self { + Value::String(s) => Ok(s.len()), + Value::List(l) => Ok(l.borrow().len()), + Value::Map(m) => Ok(m.borrow().len()), + v => Err(format!("{:?} has no length", v).into()) + } + } } impl PartialEq for Value { @@ -449,9 +460,9 @@ macro_rules! impl_numeric_op { type Output = Result; fn $fnname(self, other: Self) -> Self::Output { use Value::*; - use num_traits::ToPrimitive; const RATIO_CAST_FAIL: &'static str = "Failed to cast Rational to Float"; match (self, other) { + $($bonus)* (Int(a), Int(b)) => Ok(a.$fnname(b).into()), (Rational(a), Int(b)) => Ok(a.$fnname(b).into()), (Int(a), Rational(b)) => Ok(self::Rational::from(*a).$fnname(b).into()), @@ -468,7 +479,6 @@ macro_rules! impl_numeric_op { (Rational(a), Complex(b)) => Ok(self::Complex::from(a.to_f64().ok_or(RATIO_CAST_FAIL)?).$fnname(b).into()), (Complex(a), Rational(b)) => Ok(a.$fnname(self::Complex::from(b.to_f64().ok_or(RATIO_CAST_FAIL)?)).into()), (Complex(a), Complex(b)) => Ok(a.$fnname(b).into()), - $($bonus)* (lhs, rhs) => Err(format!("Unsupported operation '{}' between {:?} and {:?}", stringify!($fnname), lhs, rhs)) } } @@ -515,5 +525,51 @@ impl_numeric_op!(Mul, mul, { (List(a), Int(b)) | (Int(b), List(a)) => Ok(Value::from(a.borrow().iter().cycle().take(a.borrow().len()*(*b as usize)).cloned().collect::>())), }); -impl_numeric_op!(Div, div, {}); -impl_numeric_op!(Rem, rem, {}); +impl_numeric_op!(Div, div, { + (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()), +}); +impl_numeric_op!(Rem, rem, { + (Int(_), Int(b)) if *b == 0 => Err("Integer modulo by zero".into()), + (Rational(_), Int(b)) if *b == 0 => Err("Rational modulo by zero".into()), + (Int(_), Rational(b)) if b.is_zero() => Err("Rational modulo by zero".into()), + (Rational(_), Rational(b)) if b.is_zero() => Err("Rational modulo by zero".into()), +}); + +impl Pow<&Value> for &Value { + type Output = Result; + + fn pow(self, other: &Value) -> Self::Output { + use Value::*; + const RATIO_CAST_FAIL: &'static str = "Failed to convert rational to float"; + match (self, other) { + (Int(a), Int(b)) => match b { + x if *x < 0 => Err(format!("Cannot raise integer {:?} to negative integer exponent {:?}", a, b)), + x if *x > (u32::MAX as i64) => Err(format!("Integer exponent {:?} too large", x)), + _ => Ok(Value::from(a.pow(*b as u32))) + }, + (Rational(a), Int(b)) => match b { + x if *x > (i32::MAX as i64) => Err(format!("Integer exponent {:?} too large", x)), + x if *x < (i32::MIN as i64) => Err(format!("Integer exponent {:?} too small", x)), + _ => Ok(Value::from(a.pow(*b as i32))) + }, + (Int(_), Rational(_)) => Err("Cannot raise integer to rational exponent".into()), + (Rational(_), Rational(_)) => Err("Cannot raise rational to rational exponent".into()), + (Float(a), Int(b)) => Ok(a.pow(*b as f64).into()), + (Int(a), Float(b)) => Ok((*a as f64).pow(b).into()), + (Float(a), Rational(b)) => Ok(a.pow(b.to_f64().ok_or(RATIO_CAST_FAIL)?).into()), + (Rational(a), Float(b)) => Ok(a.to_f64().ok_or(RATIO_CAST_FAIL)?.pow(b).into()), + (Float(a), Float(b)) => Ok(a.pow(b).into()), + (Int(a), Complex(b)) => Ok(self::Complex::from(*a as f64).pow(b).into()), + (Complex(a), Int(b)) => Ok(a.pow(self::Complex::from(*b as f64)).into()), + (Float(a), Complex(b)) => Ok(self::Complex::from(a).pow(b).into()), + (Complex(a), Float(b)) => Ok(a.pow(self::Complex::from(b)).into()), + (Rational(a), Complex(b)) => Ok(self::Complex::from(a.to_f64().ok_or(RATIO_CAST_FAIL)?).pow(b).into()), + (Complex(a), Rational(b)) => Ok(a.pow(self::Complex::from(b.to_f64().ok_or(RATIO_CAST_FAIL)?)).into()), + (Complex(a), Complex(b)) => Ok(a.pow(b).into()), + (lhs, rhs) => Err(format!("Unsupported operation 'pow' between {:?} and {:?}", lhs, rhs)) + } + } +}