Refactoring, some pipes, exponents
This commit is contained in:
parent
ccbc6c32f3
commit
8dd7d5607c
7 changed files with 298 additions and 159 deletions
|
@ -3,7 +3,7 @@ let also_square(x) = x^2;
|
||||||
|
|
||||||
let primes = range(100) |: filter(is_prime);
|
let primes = range(100) |: filter(is_prime);
|
||||||
let prime_squares = range(100) |: map(square);
|
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;
|
let primes_and_prime_squares = primes |& prime_squares;
|
||||||
|
@ -27,6 +27,6 @@ for p : primes {
|
||||||
|
|
||||||
let D = x -> {
|
let D = x -> {
|
||||||
let facts = factors(x);
|
let facts = factors(x);
|
||||||
let product = facts |: foldl(1, mul);
|
let product = facts |> foldl(1, mul);
|
||||||
return facts |> (n -> product / n) |: foldl(0, add);
|
return facts |: (n -> product / n) |> foldl(0, add);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ fn panic_hook(info: &PanicInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("{}", std::mem::size_of::<Value>());
|
||||||
panic::set_hook(Box::new(panic_hook));
|
panic::set_hook(Box::new(panic_hook));
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
if args.len() == 2 {
|
if args.len() == 2 {
|
||||||
|
|
81
src/eval.rs
81
src/eval.rs
|
@ -1,6 +1,8 @@
|
||||||
use std::{collections::HashMap, rc::Rc, cell::RefCell};
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
|
@ -118,13 +120,13 @@ pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), Unwind> {
|
||||||
let name = unwrap_ident_token(var);
|
let name = unwrap_ident_token(var);
|
||||||
let iter = eval_expr(expr, env.clone())?;
|
let iter = eval_expr(expr, env.clone())?;
|
||||||
env.borrow_mut().declare(name.clone(), Value::Nil);
|
env.borrow_mut().declare(name.clone(), Value::Nil);
|
||||||
let iterator = iter.iter(iter_pos);
|
let iterator = iter.iter();
|
||||||
if let Err(e) = iterator {
|
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 {
|
if let Ok(i) = iterator {
|
||||||
for v in i {
|
for v in i {
|
||||||
let v = v?;
|
let v = v.map_err(|e| e.complete(iter_pos.clone()))?;
|
||||||
let env = env.clone();
|
let env = env.clone();
|
||||||
env.borrow_mut().set(name.clone(), v).expect("unreachable");
|
env.borrow_mut().set(name.clone(), v).expect("unreachable");
|
||||||
match eval_stmt(stmt, env) {
|
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() {
|
Expr::Binary { lhs, rhs, op } => match op.ty.get_op_type() {
|
||||||
Some(OpType::Assignment)
|
Some(OpType::Assignment)
|
||||||
=> eval_assignment(lhs, rhs, op, env),
|
=> eval_assignment(lhs, rhs, op, env),
|
||||||
Some(OpType::Additive) | Some(OpType::Multiplicative)
|
Some(OpType::Additive) | Some(OpType::Multiplicative) | Some(OpType::Exponential)
|
||||||
=> eval_binary(lhs, rhs, op, env),
|
=> eval_arith(lhs, rhs, op, env),
|
||||||
Some(OpType::Boolean)
|
Some(OpType::Boolean)
|
||||||
=> eval_boolean(lhs, rhs, op, env),
|
=> eval_boolean(lhs, rhs, op, env),
|
||||||
Some(OpType::Comparison)
|
Some(OpType::Comparison)
|
||||||
=> eval_comp(lhs, rhs, op, env),
|
=> eval_comp(lhs, rhs, op, env),
|
||||||
|
Some(OpType::Pipeline)
|
||||||
|
=> eval_pipeline(lhs, rhs, op, env),
|
||||||
o => todo!("{:?}", o) // TODO other operations
|
o => todo!("{:?}", o) // TODO other operations
|
||||||
},
|
},
|
||||||
Expr::Unary { arg, op } => eval_unary(arg, op, env),
|
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())?;
|
let result = eval_expr(arg, env.clone())?;
|
||||||
arg_values.push(result);
|
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 } => {
|
Expr::Index { lhs, index, pos } => {
|
||||||
let l = eval_expr(lhs, env.clone())?;
|
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 l = eval_expr(lhs, env.clone())?;
|
||||||
let r = eval_expr(rhs, env)?;
|
let r = eval_expr(rhs, env)?;
|
||||||
match op.ty {
|
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::Star => &l * &r,
|
||||||
TokenType::Slash => &l / &r,
|
TokenType::Slash => &l / &r,
|
||||||
TokenType::Percent => &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
|
_ => todo!() // TODO other operations
|
||||||
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
}.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> {
|
pub fn eval_unary(arg: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
let a = eval_expr(arg, env)?;
|
let a = eval_expr(arg, env)?;
|
||||||
match op.ty {
|
match op.ty {
|
||||||
|
|
18
src/lib.rs
18
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<Rc<str>>, pos: Position) -> 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.stacktrace.push(Stackframe { pos: self.last_pos.expect("RuntimeError never completed after construction"), fn_name });
|
||||||
self.last_pos = Some(pos);
|
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 {
|
impl fmt::Display for ParserError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
|
|
@ -45,19 +45,19 @@ impl Parser {
|
||||||
pub fn parse(&mut self) -> Result<Vec<Stmt>, ParserError> {
|
pub fn parse(&mut self) -> Result<Vec<Stmt>, ParserError> {
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
while !self.at_end() {
|
while !self.at_end() {
|
||||||
stmts.push(self.statement()?);
|
stmts.push(self.statement(!self.repl)?);
|
||||||
}
|
}
|
||||||
Ok(stmts)
|
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;
|
let next_ty = &self.peek().ty;
|
||||||
|
|
||||||
match next_ty {
|
match next_ty {
|
||||||
TokenType::Let => {
|
TokenType::Let => {
|
||||||
// let statement
|
// let statement
|
||||||
self.next();
|
self.next();
|
||||||
self.letstmt()
|
self.letstmt(req_semicolon)
|
||||||
},
|
},
|
||||||
TokenType::LBrace => {
|
TokenType::LBrace => {
|
||||||
// block
|
// block
|
||||||
|
@ -81,16 +81,16 @@ impl Parser {
|
||||||
},
|
},
|
||||||
TokenType::Break => {
|
TokenType::Break => {
|
||||||
let tok = self.next();
|
let tok = self.next();
|
||||||
self.terminate_stmt(Stmt::Break{ pos: tok.pos })
|
self.terminate_stmt(Stmt::Break{ pos: tok.pos }, req_semicolon)
|
||||||
},
|
},
|
||||||
TokenType::Continue => {
|
TokenType::Continue => {
|
||||||
let tok = self.next();
|
let tok = self.next();
|
||||||
self.terminate_stmt(Stmt::Continue{ pos: tok.pos })
|
self.terminate_stmt(Stmt::Continue{ pos: tok.pos }, req_semicolon)
|
||||||
},
|
},
|
||||||
TokenType::Return => {
|
TokenType::Return => {
|
||||||
let tok = self.next();
|
let tok = self.next();
|
||||||
let expr = self.assignment()?;
|
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 => {
|
TokenType::Fn => {
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -99,18 +99,17 @@ impl Parser {
|
||||||
_ => {
|
_ => {
|
||||||
// fallback to an expression terminated with a semicolon
|
// fallback to an expression terminated with a semicolon
|
||||||
let expr = self.assignment()?;
|
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 self.at_end() {
|
if !req_semicolon {
|
||||||
if self.repl {
|
|
||||||
return Ok(stmt)
|
return Ok(stmt)
|
||||||
} else {
|
|
||||||
self.err_on_eof()?;
|
|
||||||
}
|
}
|
||||||
|
if self.at_end() {
|
||||||
|
self.err_on_eof()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = self.next();
|
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()?;
|
let expr = self.assignment()?;
|
||||||
// must be followed by an assignment expression
|
// must be followed by an assignment expression
|
||||||
if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr {
|
if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr {
|
||||||
if let Expr::Ident{value: tok} = *lhs {
|
if let Expr::Ident{value: tok} = *lhs {
|
||||||
if self.at_end() {
|
self.terminate_stmt(Stmt::Let{lhs: tok, rhs: Some(*rhs)}, req_semicolon)
|
||||||
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()))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
||||||
}
|
}
|
||||||
} else if let Expr::Ident{value: tok} = expr {
|
} else if let Expr::Ident{value: tok} = expr {
|
||||||
if self.at_end() {
|
self.terminate_stmt(Stmt::Let{lhs: tok, rhs: None}, req_semicolon)
|
||||||
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()))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
||||||
}
|
}
|
||||||
|
@ -165,7 +142,7 @@ impl Parser {
|
||||||
let mut ec = false;
|
let mut ec = false;
|
||||||
loop {
|
loop {
|
||||||
let condition = self.assignment()?;
|
let condition = self.assignment()?;
|
||||||
let body = self.statement()?;
|
let body = self.statement(true)?;
|
||||||
if_clauses.push((condition, body));
|
if_clauses.push((condition, body));
|
||||||
match self.peek().ty {
|
match self.peek().ty {
|
||||||
TokenType::Elif => { self.next(); continue },
|
TokenType::Elif => { self.next(); continue },
|
||||||
|
@ -174,7 +151,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let else_clause = if ec {
|
let else_clause = if ec {
|
||||||
Some(Box::new(self.statement()?))
|
Some(Box::new(self.statement(true)?))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -195,7 +172,7 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
self.err_on_eof()?;
|
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 })
|
Ok(Stmt::For{ var, expr, stmt: Box::new(stmt), iter_pos: colon.pos })
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error("Expected identifier after for"))
|
Err(self.mk_error("Expected identifier after for"))
|
||||||
|
@ -206,7 +183,7 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let stmt = self.statement()?;
|
let stmt = self.statement(true)?;
|
||||||
Ok(Stmt::While{ expr, stmt: Box::new(stmt) })
|
Ok(Stmt::While{ expr, stmt: Box::new(stmt) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +202,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let body = self.statement()?;
|
let body = self.statement(false)?;
|
||||||
Ok(Stmt::Fn { name, args, body: Box::new(body) })
|
Ok(Stmt::Fn { name, args, body: Box::new(body) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +217,7 @@ impl Parser {
|
||||||
fn block(&mut self) -> Result<Stmt, ParserError> {
|
fn block(&mut self) -> Result<Stmt, ParserError> {
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
while !self.at_end() && self.peek().ty != TokenType::RBrace {
|
while !self.at_end() && self.peek().ty != TokenType::RBrace {
|
||||||
stmts.push(self.statement()?)
|
stmts.push(self.statement(true)?)
|
||||||
}
|
}
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -411,7 +388,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let body = self.statement()?;
|
let body = self.statement(false)?;
|
||||||
Ok(Expr::Fn { args, body: Box::new(body) })
|
Ok(Expr::Fn { args, body: Box::new(body) })
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
||||||
|
|
|
@ -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 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) {
|
pub fn load(env: &mut Environment) {
|
||||||
let mut name: Rc<str>;
|
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 }));
|
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_im, arg_count: 1, name }));
|
||||||
name = Rc::from("time");
|
name = Rc::from("time");
|
||||||
env.declare(name.clone(), Value::Func(Func::Builtin { func: fn_time, arg_count: 0, name }));
|
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()))
|
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()))
|
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());
|
print!("{}", args[0].to_string());
|
||||||
std::io::stdout().flush().map_err(|e| e.to_string())?;
|
std::io::stdout().flush().map_err(|e| e.to_string())?;
|
||||||
Ok(Value::Nil)
|
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());
|
println!("{}", args[0].to_string());
|
||||||
Ok(Value::Nil)
|
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 mut buffer = String::new();
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
stdin.read_line(&mut buffer).map_err(|e| e.to_string())?;
|
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))
|
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] {
|
if let Value::Char(c) = args[0] {
|
||||||
Ok(Value::from(c as u32))
|
Ok(Value::from(c as u32))
|
||||||
} else {
|
} 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 let Value::Int(i) = args[0] {
|
||||||
if i >= 0 && i < (u32::MAX as i64) {
|
if i >= 0 && i < (u32::MAX as i64) {
|
||||||
if let Some(c) = char::from_u32(i as u32) {
|
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> {
|
fn range_inner(_: Vec<Value>, data: Rc<RefCell<Vec<Value>>>, _: Rc<RefCell<Vec<CIterator>>>) -> Result<Value, RuntimeError> {
|
||||||
let min = &args[0];
|
const ZERO: Value = Value::Int(0);
|
||||||
let max = &args[1];
|
let mut d = data.borrow_mut();
|
||||||
match (min, max) {
|
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) {
|
(Value::Int(a), Value::Int(b)) => match a.cmp(b) {
|
||||||
Ordering::Equal => Ok(Value::from(vec![])),
|
Ordering::Equal => 0,
|
||||||
Ordering::Less =>
|
Ordering::Less => 1,
|
||||||
Ok(Value::from((*a..*b).map(Value::Int).collect::<Vec<Value>>())),
|
Ordering::Greater => -1,
|
||||||
Ordering::Greater =>
|
|
||||||
Ok(Value::from(((*b+1)..(*a+1)).rev().map(Value::Int).collect::<Vec<Value>>()))
|
|
||||||
},
|
},
|
||||||
_ => 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> {
|
fn fn_len(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
match &args[0] {
|
Ok(Value::Int(args[0].len().map_err(|e| RuntimeError::new_incomplete(e))? as i64))
|
||||||
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_has(args: Vec<Value>) -> Result<Value, String> {
|
fn fn_has(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
match &args[0] {
|
match &args[0] {
|
||||||
Value::Map(m) => Ok(Value::from(m.borrow().contains_key(&args[1]))),
|
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] {
|
match &args[0] {
|
||||||
Value::Int(x) => Ok(Value::Float(*x as f64)),
|
Value::Int(x) => Ok(Value::Float(*x as f64)),
|
||||||
Value::Float(x) => Ok(Value::Float(*x)),
|
Value::Float(x) => Ok(Value::Float(*x)),
|
||||||
Value::Rational(x) => Ok(Value::Float(x.to_f64().unwrap())),
|
Value::Rational(x) => Ok(Value::Float(x.to_f64().unwrap())),
|
||||||
Value::Complex(x) => Ok(Value::Float(x.re)),
|
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] {
|
match &args[0] {
|
||||||
Value::Int(_) | Value::Float(_) | Value::Rational(_)
|
Value::Int(_) | Value::Float(_) | Value::Rational(_)
|
||||||
=> Ok(Value::Float(0.0)),
|
=> Ok(Value::Float(0.0)),
|
||||||
Value::Complex(x) => Ok(Value::Float(x.im)),
|
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())?;
|
let time = SystemTime::now().duration_since(UNIX_EPOCH).map_err(|e| e.to_string())?;
|
||||||
Ok(Value::from(time.as_secs_f64()))
|
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))
|
||||||
|
}
|
||||||
|
|
190
src/value.rs
190
src/value.rs
|
@ -1,8 +1,8 @@
|
||||||
use std::{rc::Rc, collections::HashMap, ops::*, fmt, cmp::Ordering, cell::RefCell, hash::Hash};
|
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 Rational = num_rational::Ratio<i64>;
|
||||||
pub type Complex = num_complex::Complex64;
|
pub type Complex = num_complex::Complex64;
|
||||||
|
@ -13,12 +13,18 @@ pub enum Func {
|
||||||
name: Option<Rc<str>>,
|
name: Option<Rc<str>>,
|
||||||
args: Vec<Rc<str>>,
|
args: Vec<Rc<str>>,
|
||||||
env: EnvRef,
|
env: EnvRef,
|
||||||
func: Stmt
|
func: Stmt,
|
||||||
},
|
},
|
||||||
Builtin {
|
Builtin {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
func: fn(Vec<Value>) -> Result<Value, String>,
|
func: fn(Vec<Value>) -> Result<Value, RuntimeError>,
|
||||||
arg_count: usize
|
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("name", name)
|
||||||
.field("arg_count", arg_count)
|
.field("arg_count", arg_count)
|
||||||
.finish_non_exhaustive(),
|
.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 {
|
pub fn arg_count(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Builtin { arg_count, .. } => *arg_count,
|
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()) {
|
match arg_values.len().cmp(&self.arg_count()) {
|
||||||
Ordering::Equal => match self {
|
Ordering::Equal => match self {
|
||||||
Self::Builtin { func, .. }
|
Self::Builtin { func, .. }
|
||||||
=> func(arg_values).map_err(|e| RuntimeError::new(e, pos.clone())),
|
=> func(arg_values),
|
||||||
Self::Func { name, args, func, env } => {
|
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());
|
let mut env = Environment::extend(env.clone());
|
||||||
for (k, v) in args.iter().zip(arg_values.iter()) {
|
for (k, v) in args.iter().zip(arg_values.iter()) {
|
||||||
env.declare(k.clone(), v.clone());
|
env.declare(k.clone(), v.clone());
|
||||||
}
|
}
|
||||||
match eval_stmt(func, env.wrap()) {
|
match func {
|
||||||
|
Stmt::Expr { expr } => eval_expr(expr, env.wrap()),
|
||||||
|
stmt => match eval_stmt(stmt, env.wrap()) {
|
||||||
Ok(()) => Ok(Value::Nil),
|
Ok(()) => Ok(Value::Nil),
|
||||||
Err(Unwind::Return{ value, .. }) => Ok(value),
|
Err(Unwind::Return{ value, .. }) => Ok(value),
|
||||||
Err(e) => Err(e.as_error().exit_fn(name.clone(), pos.clone()))
|
Err(e) => Err(e.as_error()),
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ordering::Less => Err(RuntimeError::new(
|
Ordering::Less => Err(RuntimeError::new_incomplete(
|
||||||
format!("Not enough arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()),
|
format!("Not enough arguments for function: expected {}, got {}", self.arg_count(), arg_values.len())
|
||||||
pos.clone()
|
|
||||||
)),
|
)),
|
||||||
Ordering::Greater => Err(RuntimeError::new(
|
Ordering::Greater => Err(RuntimeError::new_incomplete(
|
||||||
format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len()),
|
format!("Too many arguments for function: expected {}, got {}", self.arg_count(), arg_values.len())
|
||||||
pos.clone()
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,53 +104,39 @@ impl Hash for Func {
|
||||||
Self::Func { name, args, .. } => {
|
Self::Func { name, args, .. } => {
|
||||||
name.hash(state);
|
name.hash(state);
|
||||||
args.hash(state);
|
args.hash(state);
|
||||||
|
},
|
||||||
|
Self::BuiltinClosure { arg_count, data, .. } => {
|
||||||
|
arg_count.hash(state);
|
||||||
|
data.borrow().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EitherRteOrString {
|
pub enum CIterator {
|
||||||
Rte(RuntimeError), String(String)
|
// precondition: value must be len()able
|
||||||
|
Indexable{ value: Value, idx: i64 },
|
||||||
|
Func(Func)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EitherRteOrString {
|
impl Iterator for CIterator {
|
||||||
pub fn to_rte(self, pos: &Position) -> RuntimeError {
|
type Item = Result<Value, RuntimeError>;
|
||||||
match self {
|
|
||||||
Self::Rte(e) => e,
|
|
||||||
Self::String(s) => RuntimeError::new(s, pos.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self {
|
match self {
|
||||||
Self::Builtin { func, .. } => match (func)(vec![]) {
|
Self::Indexable{ value, ref mut idx } => {
|
||||||
Ok(Value::Nil) => None,
|
if *idx >= value.len().unwrap() as i64 {
|
||||||
r => Some(r.map_err(|e| e.into())),
|
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)
|
||||||
},
|
},
|
||||||
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()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +154,6 @@ pub struct Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[repr(u8)]
|
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Nil,
|
Nil,
|
||||||
Type(usize),
|
Type(usize),
|
||||||
|
@ -177,19 +178,18 @@ impl Value {
|
||||||
String(s) => !s.len() == 0,
|
String(s) => !s.len() == 0,
|
||||||
List(l) => !l.borrow().len() == 0,
|
List(l) => !l.borrow().len() == 0,
|
||||||
Map(m) => !m.borrow().len() == 0,
|
Map(m) => !m.borrow().len() == 0,
|
||||||
|
Char(c) => *c != '\0',
|
||||||
_ => true
|
_ => 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 {
|
match self {
|
||||||
Value::String(s)
|
Value::String(_) | Value::List(_)
|
||||||
=> Ok(Box::new(s.chars()
|
=> Ok(CIterator::Indexable { value: self.clone(), idx: 0 }),
|
||||||
.map(Value::Char).map(Ok))),
|
|
||||||
Value::List(l) => Ok(Box::new(l.borrow().clone().into_iter().map(Ok))),
|
|
||||||
Value::Func(f) => {
|
Value::Func(f) => {
|
||||||
if f.arg_count() == 0 {
|
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 {
|
} else {
|
||||||
Err("Only zero-argument functions can be used as iterators".into())
|
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 {
|
if let Value::Func(f) = self {
|
||||||
f.call(args, pos)
|
f.call(args)
|
||||||
} else {
|
} 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::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
|
||||||
Self::Type(_) => todo!(),
|
Self::Type(_) => todo!(),
|
||||||
Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
|
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 {
|
Self::Func(Func::Func { name, .. }) => match name {
|
||||||
Some(name) => Rc::from(format!("<fn {}>", name)),
|
Some(name) => Rc::from(format!("<fn {}>", name)),
|
||||||
None => Rc::from("<anonymous fn>"),
|
None => Rc::from("<anonymous fn>"),
|
||||||
|
@ -242,6 +243,7 @@ impl Value {
|
||||||
Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
|
Self::Map(m) => Rc::from(format!("{:?}", m)), // TODO fix
|
||||||
Self::Type(_) => todo!(),
|
Self::Type(_) => todo!(),
|
||||||
Self::Func(Func::Builtin { name, func, .. }) => Rc::from(format!("<builtin fn {} at {:?}>", name, *func as *const ())),
|
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 {
|
Self::Func(Func::Func { name, .. }) => match name {
|
||||||
Some(name) => Rc::from(format!("<fn {}>", name)),
|
Some(name) => Rc::from(format!("<fn {}>", name)),
|
||||||
None => Rc::from("<anonymous fn>"),
|
None => Rc::from("<anonymous fn>"),
|
||||||
|
@ -289,6 +291,15 @@ impl Value {
|
||||||
v => Err(format!("Cannot assign to index in {:?}", v))
|
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 {
|
impl PartialEq for Value {
|
||||||
|
@ -449,9 +460,9 @@ macro_rules! impl_numeric_op {
|
||||||
type Output = Result<Value, String>;
|
type Output = Result<Value, String>;
|
||||||
fn $fnname(self, other: Self) -> Self::Output {
|
fn $fnname(self, other: Self) -> Self::Output {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
use num_traits::ToPrimitive;
|
|
||||||
const RATIO_CAST_FAIL: &'static str = "Failed to cast Rational to Float";
|
const RATIO_CAST_FAIL: &'static str = "Failed to cast Rational to Float";
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
$($bonus)*
|
||||||
(Int(a), Int(b)) => Ok(a.$fnname(b).into()),
|
(Int(a), Int(b)) => Ok(a.$fnname(b).into()),
|
||||||
(Rational(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()),
|
(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()),
|
(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), 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()),
|
(Complex(a), Complex(b)) => Ok(a.$fnname(b).into()),
|
||||||
$($bonus)*
|
|
||||||
(lhs, rhs) => Err(format!("Unsupported operation '{}' between {:?} and {:?}", stringify!($fnname), lhs, rhs))
|
(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))
|
(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>>())),
|
=> 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!(Div, div, {
|
||||||
impl_numeric_op!(Rem, rem, {});
|
(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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue