Refactoring, some pipes, exponents

This commit is contained in:
TriMill 2022-09-16 16:05:28 -04:00
parent ccbc6c32f3
commit 8dd7d5607c
7 changed files with 298 additions and 159 deletions

View File

@ -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);
}

View File

@ -25,6 +25,7 @@ fn panic_hook(info: &PanicInfo) {
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("{}", std::mem::size_of::<Value>());
panic::set_hook(Box::new(panic_hook));
let args: Vec<String> = std::env::args().collect();
if args.len() == 2 {

View File

@ -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<Value, RuntimeError> {
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<Value, RuntimeError> {
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<Value, RuntimeError> {
pub fn eval_arith(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
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<Va
TokenType::Star => &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<Valu
}
}
fn pipecolon_inner(_: Vec<Value>, data: Rc<RefCell<Vec<Value>>>, iter_data: Rc<RefCell<Vec<CIterator>>>) -> Result<Value, RuntimeError> {
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<Value>, data: Rc<RefCell<Vec<Value>>>, iter_data: Rc<RefCell<Vec<CIterator>>>) -> Result<Value, RuntimeError> {
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<Value, RuntimeError> {
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<Value, RuntimeError> {
let a = eval_expr(arg, env)?;
match op.ty {

View File

@ -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<Rc<str>>, 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<String> 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 {

View File

@ -45,19 +45,19 @@ impl Parser {
pub fn parse(&mut self) -> Result<Vec<Stmt>, 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<Stmt, ParserError> {
fn statement(&mut self, req_semicolon: bool) -> Result<Stmt, ParserError> {
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<Stmt, ParserError> {
fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result<Stmt, ParserError> {
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<Stmt, ParserError> {
fn letstmt(&mut self, req_semicolon: bool) -> Result<Stmt, ParserError> {
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<Stmt, ParserError> {
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)))

View File

@ -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<str>;
@ -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<Value>) -> Result<Value, String> {
fn fn_str(args: Vec<Value>) -> Result<Value, RuntimeError> {
Ok(Value::String(args[0].to_string()))
}
fn fn_repr(args: Vec<Value>) -> Result<Value, String> {
fn fn_repr(args: Vec<Value>) -> Result<Value, RuntimeError> {
Ok(Value::String(args[0].repr()))
}
fn fn_print(args: Vec<Value>) -> Result<Value, String> {
fn fn_print(args: Vec<Value>) -> Result<Value, RuntimeError> {
print!("{}", args[0].to_string());
std::io::stdout().flush().map_err(|e| e.to_string())?;
Ok(Value::Nil)
}
fn fn_println(args: Vec<Value>) -> Result<Value, String> {
fn fn_println(args: Vec<Value>) -> Result<Value, RuntimeError> {
println!("{}", args[0].to_string());
Ok(Value::Nil)
}
fn fn_input(_: Vec<Value>) -> Result<Value, String> {
fn fn_input(_: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, String> {
Ok(Value::from(buffer))
}
fn fn_ord(args: Vec<Value>) -> Result<Value, String> {
fn fn_ord(args: Vec<Value>) -> Result<Value, RuntimeError> {
if let Value::Char(c) = args[0] {
Ok(Value::from(c as u32))
} else {
@ -71,7 +73,7 @@ fn fn_ord(args: Vec<Value>) -> Result<Value, String> {
}
}
fn fn_chr(args: Vec<Value>) -> Result<Value, String> {
fn fn_chr(args: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, String> {
}
}
fn fn_range(args: Vec<Value>) -> Result<Value, String> {
let min = &args[0];
let max = &args[1];
match (min, max) {
fn range_inner(_: Vec<Value>, data: Rc<RefCell<Vec<Value>>>, _: Rc<RefCell<Vec<CIterator>>>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, RuntimeError> {
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::<Vec<Value>>())),
Ordering::Greater =>
Ok(Value::from(((*b+1)..(*a+1)).rev().map(Value::Int).collect::<Vec<Value>>()))
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<Value>) -> Result<Value, String> {
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<Value>) -> Result<Value, RuntimeError> {
Ok(Value::Int(args[0].len().map_err(|e| RuntimeError::new_incomplete(e))? as i64))
}
fn fn_has(args: Vec<Value>) -> Result<Value, String> {
fn fn_has(args: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, String> {
fn fn_re(args: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, String> {
fn fn_im(args: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, String> {
fn fn_time(_: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value>) -> Result<Value, RuntimeError> {
let a = args[0].iter()?;
let mut res = Vec::new();
for v in a { res.push(v?); }
Ok(Value::from(res))
}

View File

@ -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<i64>;
pub type Complex = num_complex::Complex64;
@ -13,12 +13,18 @@ pub enum Func {
name: Option<Rc<str>>,
args: Vec<Rc<str>>,
env: EnvRef,
func: Stmt
func: Stmt,
},
Builtin {
name: Rc<str>,
func: fn(Vec<Value>) -> Result<Value, String>,
arg_count: usize
func: fn(Vec<Value>) -> Result<Value, RuntimeError>,
arg_count: usize,
},
BuiltinClosure {
func: fn(Vec<Value>, Rc<RefCell<Vec<Value>>>, Rc<RefCell<Vec<CIterator>>>) -> Result<Value, RuntimeError>,
data: Rc<RefCell<Vec<Value>>>,
iter_data: Rc<RefCell<Vec<CIterator>>>,
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<Value>, pos: &Position) -> Result<Value, RuntimeError> {
pub fn call(&self, arg_values: Vec<Value>) -> Result<Value, RuntimeError> {
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<Value, RuntimeError>;
impl From<String> for EitherRteOrString {
fn from(s: String) -> Self {
Self::String(s)
}
}
impl From<RuntimeError> for EitherRteOrString {
fn from(e: RuntimeError) -> Self {
Self::Rte(e)
}
}
impl Iterator for Func {
type Item = Result<Value, EitherRteOrString>;
fn next(&mut self) -> Option<Self::Item> {
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<Box<dyn Iterator<Item=Result<Value, RuntimeError>> + '_>, String> {
pub fn iter<'a>(&'a self) -> Result<CIterator, String> {
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<Value>, pos: &Position) -> Result<Value, RuntimeError> {
pub fn call(&self, args: Vec<Value>) -> Result<Value, RuntimeError> {
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!("<builtin fn {} at {:?}>", name, *func as *const ())),
Self::Func(Func::BuiltinClosure { func, .. }) => Rc::from(format!("<builtin anonymous fn at {:?}>", *func as *const ())),
Self::Func(Func::Func { name, .. }) => match name {
Some(name) => Rc::from(format!("<fn {}>", name)),
None => Rc::from("<anonymous fn>"),
@ -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!("<builtin fn {} at {:?}>", name, *func as *const ())),
Self::Func(Func::BuiltinClosure { func, .. }) => Rc::from(format!("<builtin anonymous fn at {:?}>", *func as *const ())),
Self::Func(Func::Func { name, .. }) => match name {
Some(name) => Rc::from(format!("<fn {}>", name)),
None => Rc::from("<anonymous fn>"),
@ -289,6 +291,15 @@ impl Value {
v => Err(format!("Cannot assign to index in {:?}", v))
}
}
pub fn len(&self) -> Result<usize, String> {
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<Value, String>;
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::<Vec<Value>>())),
});
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<Value, String>;
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))
}
}
}