diff --git a/complexpr-bin/src/main.rs b/complexpr-bin/src/main.rs index 01eb9db..afa404a 100644 --- a/complexpr-bin/src/main.rs +++ b/complexpr-bin/src/main.rs @@ -61,6 +61,7 @@ fn repl() -> Result<(), Box> { rl.set_helper(Some(h)); println!("Press {}Ctrl+D{} to exit.", C_BLUE, C_RESET); stdlib::load(&mut env.borrow_mut()); + stdlib::io::load(&mut env.borrow_mut()); stdlib::iter::load(&mut env.borrow_mut()); stdlib::math::load(&mut env.borrow_mut()); loop { diff --git a/complexpr/src/eval.rs b/complexpr/src/eval.rs index 8ac43c2..c8900d2 100644 --- a/complexpr/src/eval.rs +++ b/complexpr/src/eval.rs @@ -331,30 +331,38 @@ 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() { - let func = f.as_func()?; - func.call(vec![next?]) - } else { - Ok(Value::Nil) +fn mk_pipecolon_inner(f: Func, it: CIterator) -> Func { + let it = RefCell::new(it); + return Func::BuiltinClosure{ + arg_count: 0, + func: Rc::new(move |_| { + if let Some(next) = it.borrow_mut().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 func = f.as_func()?; - let success = func.call(vec![next.clone()])?.truthy(); - if success { - return Ok(next) +fn mk_pipequestion_inner(f: Func, it: CIterator) -> Func { + let it = RefCell::new(it); + return Func::BuiltinClosure { + arg_count: 0, + func: Rc::new(move |_| { + loop { + let next = it.borrow_mut().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) + } } - } else { - return Ok(Value::Nil) - } + }) } } @@ -370,22 +378,8 @@ pub fn eval_pipeline(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result< fn eval_pipeline_inner(l: Value, r: &Func, op: &Token) -> Result { match op.ty { TokenType::PipePoint => r.call(vec![l]), - TokenType::PipeColon => { - Ok(Value::Func(Func::BuiltinClosure { - arg_count: 0, - data: Rc::new(RefCell::new(vec![Value::Func(r.clone())])), - 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![Value::Func(r.clone())])), - iter_data: Rc::new(RefCell::new(vec![l.iter()?])), - func: pipequestion_inner, - })) - }, + TokenType::PipeColon => Ok(Value::Func(mk_pipecolon_inner(r.clone(), l.iter()?))), + TokenType::PipeQuestion => Ok(Value::Func(mk_pipequestion_inner(r.clone(), l.iter()?))), TokenType::PipeDoubleSlash => { let mut result = Value::Nil; let mut first_iter = true; diff --git a/complexpr/src/interpreter.rs b/complexpr/src/interpreter.rs index 2e1681d..d92ce8f 100644 --- a/complexpr/src/interpreter.rs +++ b/complexpr/src/interpreter.rs @@ -14,6 +14,7 @@ pub fn interpret(src: &str, fname: Option, env: Option, repl: bo } else { environ = Rc::new(RefCell::new(Environment::new())); stdlib::load(&mut environ.borrow_mut()); + stdlib::io::load(&mut environ.borrow_mut()); stdlib::iter::load(&mut environ.borrow_mut()); stdlib::math::load(&mut environ.borrow_mut()); } diff --git a/complexpr/src/stdlib/io.rs b/complexpr/src/stdlib/io.rs new file mode 100644 index 0000000..84f760e --- /dev/null +++ b/complexpr/src/stdlib/io.rs @@ -0,0 +1,30 @@ +use std::io::Write; + +use crate::{env::Environment, declare_fn, value::Value, RuntimeError}; + +pub fn load(env: &mut Environment) { + declare_fn!(env, print, 1); + declare_fn!(env, println, 1); + declare_fn!(env, input, 0); +} + +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 { + println!("{}", args[0].to_string()); + Ok(Value::Nil) +} + +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())?; + if buffer.ends_with('\n') { + buffer.pop(); + } + Ok(Value::from(buffer)) +} diff --git a/complexpr/src/stdlib/iter.rs b/complexpr/src/stdlib/iter.rs index fbd2f03..c052ee1 100644 --- a/complexpr/src/stdlib/iter.rs +++ b/complexpr/src/stdlib/iter.rs @@ -1,6 +1,6 @@ use std::{rc::Rc, cell::RefCell}; -use crate::{value::{Value, func::{Func, CIterator}}, RuntimeError, env::Environment, declare_fn}; +use crate::{value::{Value, func::Func}, RuntimeError, env::Environment, declare_fn}; pub fn load(env: &mut Environment) { declare_fn!(env, take, 2); @@ -9,58 +9,49 @@ pub fn load(env: &mut Environment) { declare_fn!(env, exists, 2); } - -fn take_inner(_: Vec, data: Rc>>, iter_data: Rc>>) -> Result { - // 0: current index - // 1: target index - let mut d = data.borrow_mut(); - if d[0] >= d[1] { - Ok(Value::Nil) - } else { - d[0] = (&d[0] + &Value::Int(1))?; - match iter_data.borrow_mut()[0].next() { - None => Ok(Value::Nil), - Some(x) => x - } - } -} - fn fn_take(args: Vec) -> Result { + let idx = RefCell::new(0); + let limit = match args[0] { + Value::Int(n) => n, + _ => return Err("Argument to take must be an integer".into()), + }; + let it = RefCell::new(args[1].iter()?); Ok(Value::Func(Func::BuiltinClosure { arg_count: 0, - data: Rc::new(RefCell::new(vec![Value::Int(0), args[0].clone()])), - iter_data: Rc::new(RefCell::new(vec![args[1].iter()?])), - func: take_inner + func: Rc::new(move |_| { + if *idx.borrow() >= limit { + Ok(Value::Nil) + } else { + *idx.borrow_mut() += 1; + match it.borrow_mut().next() { + None => Ok(Value::Nil), + Some(x) => x + } + } + }) })) } -fn skip_inner(_: Vec, data: Rc>>, iter_data: Rc>>) -> Result { - let mut d = if let Value::Int(d) = data.borrow()[0] { d } else { - unreachable!() // checked by fn_skip() - }; - while d > 0 { - iter_data.borrow_mut()[0].next(); - d -= 1; - } - data.borrow_mut()[0] = Value::Int(d); - match iter_data.borrow_mut()[0].next() { - None => Ok(Value::Nil), - Some(x) => x - } -} - fn fn_skip(args: Vec) -> Result { let n = match args[0] { Value::Int(n) if n <= 0 => return Err(RuntimeError::new_no_pos("First argument to skip must be nonnegative")), Value::Int(n) => n, _ => return Err(RuntimeError::new_no_pos("First argument to skip must be an integer")) }; - let it = args[1].iter()?; + let it = RefCell::new(args[1].iter()?); + let idx = RefCell::new(0); Ok(Value::Func(Func::BuiltinClosure { arg_count: 0, - data: Rc::new(RefCell::new(vec![Value::Int(n)])), - iter_data: Rc::new(RefCell::new(vec![it])), - func: skip_inner + func: Rc::new(move |_| { + while *idx.borrow() < n { + it.borrow_mut().next(); + *idx.borrow_mut() += 1; + } + match it.borrow_mut().next() { + None => Ok(Value::Nil), + Some(x) => x + } + }) })) } diff --git a/complexpr/src/stdlib/math.rs b/complexpr/src/stdlib/math.rs index cdae4cd..1343924 100644 --- a/complexpr/src/stdlib/math.rs +++ b/complexpr/src/stdlib/math.rs @@ -1,8 +1,8 @@ -use std::{rc::Rc, cmp::Ordering}; +use std::cmp::Ordering; use num_traits::{ToPrimitive, Pow}; -use crate::{value::{Value, func::Func, Complex, Rational}, RuntimeError, env::Environment, declare_fn}; +use crate::{value::{Value, Complex, Rational}, RuntimeError, env::Environment, declare_fn}; enum Floaty { Real(f64), Complex(Complex) diff --git a/complexpr/src/stdlib/mod.rs b/complexpr/src/stdlib/mod.rs index 76611b2..53a04e1 100644 --- a/complexpr/src/stdlib/mod.rs +++ b/complexpr/src/stdlib/mod.rs @@ -1,19 +1,20 @@ -pub mod math; +pub mod io; pub mod iter; +pub mod math; -use std::{rc::Rc, io::Write, cmp::Ordering, time::{SystemTime, UNIX_EPOCH}, cell::RefCell}; +use std::{rc::Rc, cmp::Ordering, time::{SystemTime, UNIX_EPOCH}, cell::RefCell}; -use crate::{value::{Value, func::{Func, CIterator}}, RuntimeError, env::Environment}; +use crate::{value::{Value, func::Func}, RuntimeError, env::Environment}; #[macro_export] macro_rules! declare_fn { - ($env:ident, $name:ident, $arg_count:literal) => {paste::paste!{{ - let s: Rc = Rc::from(stringify!($name)); - $env.declare(s.clone(), Value::Func(Func::Builtin { func: [], arg_count: $arg_count, name: s })); + ($env:ident, $name:ident, $arg_count:literal) => {::paste::paste!{{ + let s: ::std::rc::Rc = ::std::rc::Rc::from(stringify!($name)); + $env.declare(s.clone(), $crate::value::Value::Func($crate::value::func::Func::Builtin { func: [], arg_count: $arg_count, name: s })); }}}; ($env:ident, $name:literal, $rust_name:ident, $arg_count:literal) => {{ - let s: Rc = Rc::from($name); - $env.declare(s.clone(), Value::Func(Func::Builtin { func: $rust_name, arg_count: $arg_count, name: s })); + let s: ::std::rc::Rc = ::std::rc::Rc::from($name); + $env.declare(s.clone(), $crate::value::Value::Func($crate::value::func::Func::Builtin { func: $rust_name, arg_count: $arg_count, name: s })); }}; } @@ -22,9 +23,6 @@ pub fn load(env: &mut Environment) { declare_fn!(env, type_eq, 1); declare_fn!(env, str, 1); declare_fn!(env, repr, 1); - declare_fn!(env, print, 1); - declare_fn!(env, println, 1); - declare_fn!(env, input, 0); declare_fn!(env, ord, 1); declare_fn!(env, chr, 1); declare_fn!(env, range, 2); @@ -54,27 +52,6 @@ fn fn_repr(args: Vec) -> Result { Ok(Value::String(args[0].repr())) } -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 { - println!("{}", args[0].to_string()); - Ok(Value::Nil) -} - -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())?; - if buffer.ends_with('\n') { - buffer.pop(); - } - Ok(Value::from(buffer)) -} - fn fn_ord(args: Vec) -> Result { if let Value::Char(c) = args[0] { Ok(Value::from(c as u32)) @@ -96,36 +73,36 @@ fn fn_chr(args: Vec) -> Result { } } -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] - || 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 mk_range_inner(start: i64, end: i64, delta: i64) -> Func { + let counter = RefCell::new(start); + Func::BuiltinClosure { + arg_count: 0, + func: Rc::new(move |_| { + let c_value = *counter.borrow(); + if delta >= 0 && c_value >= end + || delta <= 0 && c_value <= end { + Ok(Value::Nil) + } else { + let res = *counter.borrow(); + *counter.borrow_mut() += delta; + Ok(Value::Int(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 => 0, - Ordering::Less => 1, - Ordering::Greater => -1, - }, + let (start, end, delta) = match (&args[0], &args[1]) { + (Value::Int(a), Value::Int(b)) => (a, b, + match a.cmp(&b) { + Ordering::Equal => 0, + Ordering::Less => 1, + Ordering::Greater => -1, + } + ), _ => return Err("Both arguments to range must be integers".into()) }; - 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 - })) + Ok(Value::Func(mk_range_inner(*start, *end, delta))) } fn fn_len(args: Vec) -> Result { diff --git a/complexpr/src/value/func.rs b/complexpr/src/value/func.rs index 859b555..7a1e2ab 100644 --- a/complexpr/src/value/func.rs +++ b/complexpr/src/value/func.rs @@ -21,9 +21,7 @@ pub enum Func { arg_count: usize, }, BuiltinClosure { - func: fn(Vec, ClosureData, ClosureIterData) -> Result, - data: ClosureData, - iter_data: ClosureIterData, + func: Rc) -> Result>, arg_count: usize, }, Partial { @@ -45,10 +43,9 @@ impl fmt::Debug for Func { .field("name", name) .field("arg_count", arg_count) .finish_non_exhaustive(), - Self::BuiltinClosure { arg_count, data, .. } + Self::BuiltinClosure { arg_count, .. } => f.debug_struct("Func::BuiltinClosure") .field("arg_count", arg_count) - .field("data", data) .finish_non_exhaustive(), Self::Partial { inner, filled_args } => f.debug_struct("Func::Partial") @@ -84,8 +81,8 @@ impl Func { Ordering::Equal => match self { Self::Builtin { func, .. } => func(arg_values), - Self::BuiltinClosure { func, data, iter_data, .. } - => func(arg_values, data.clone(), iter_data.clone()), + Self::BuiltinClosure { func, .. } + => func(arg_values), Self::Func { args, func, env, .. } => { let mut env = Environment::extend(env.clone()); for (k, v) in args.iter().zip(arg_values.iter()) { @@ -137,9 +134,8 @@ impl Hash for Func { name.hash(state); args.hash(state); }, - Self::BuiltinClosure { arg_count, data, .. } => { + Self::BuiltinClosure { arg_count, .. } => { arg_count.hash(state); - data.borrow().hash(state); }, Self::Partial { inner, filled_args } => { filled_args.hash(state); diff --git a/complexpr/src/value/mod.rs b/complexpr/src/value/mod.rs index 2f45225..784d417 100644 --- a/complexpr/src/value/mod.rs +++ b/complexpr/src/value/mod.rs @@ -116,7 +116,7 @@ impl Value { Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix Self::Type(t) => Rc::from(format!("", t.name)), 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::BuiltinClosure { .. }) => Rc::from(format!("")), Self::Func(f @ Func::Partial { .. }) => match f.name() { Some(name) => Rc::from(format!("", name)), None => Rc::from(""),