support code generation through () blocks
This commit is contained in:
492
src/executor.rs
492
src/executor.rs
@@ -1,12 +1,12 @@
|
||||
use super::{Value, Type, Object};
|
||||
use super::parser::{ParseTree, ParseError};
|
||||
use super::tokenizer::Op;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeError {
|
||||
@@ -104,155 +104,236 @@ where
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn obj_locals(obj: &Arc<Mutex<Object>>) -> HashMap<String, Arc<Mutex<Object>>> {
|
||||
fn _obj_locals(obj: &Arc<Mutex<Object>>) -> HashMap<String, Arc<Mutex<Object>>> {
|
||||
let guard = obj.lock().unwrap();
|
||||
|
||||
let locals = guard.locals();
|
||||
let locals = guard._locals();
|
||||
|
||||
locals
|
||||
}
|
||||
|
||||
fn obj_globals(obj: &Arc<Mutex<Object>>) -> HashMap<String, Arc<Mutex<Object>>> {
|
||||
fn _obj_globals(obj: &Arc<Mutex<Object>>) -> HashMap<String, Arc<Mutex<Object>>> {
|
||||
let guard = obj.lock().unwrap();
|
||||
|
||||
let locals = guard.globals();
|
||||
let locals = guard._globals();
|
||||
|
||||
locals
|
||||
}
|
||||
|
||||
pub fn exec(&mut self, tree: Box<ParseTree>) -> Result<Value, RuntimeError> {
|
||||
match *tree {
|
||||
ParseTree::Add(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Float(x + y as f64)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 + y)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
|
||||
(Value::String(x), Value::String(y)) => Ok(Value::String(format!("{x}{y}"))),
|
||||
(Value::Array(xtype, x), Value::Array(ytype, y)) => {
|
||||
if xtype != ytype {
|
||||
return Err(RuntimeError::TypeError(xtype, ytype));
|
||||
ParseTree::Operator(op, args) => {
|
||||
let args: Vec<Value> = args.into_iter()
|
||||
.map(|x| self.exec(Box::new(x))).collect::<Result<_, _>>()?;
|
||||
|
||||
match op {
|
||||
Op::Add => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Int(x + y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Float(x + *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Float(*x as f64 + y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Float(x + y)),
|
||||
[Value::String(x), Value::String(y)] => Ok(Value::String(format!("{x}{y}"))),
|
||||
[Value::Array(xtype, x), Value::Array(ytype, y)] => {
|
||||
if xtype != ytype {
|
||||
return Err(RuntimeError::TypeError(xtype.clone(), ytype.clone()));
|
||||
}
|
||||
|
||||
Ok(Value::Array(xtype.clone(), [x.clone(), y.clone()].concat()))
|
||||
},
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
[Value::Array(t, x), y] => {
|
||||
let ytype = y.get_type();
|
||||
|
||||
if *t != ytype {
|
||||
return Err(RuntimeError::TypeError(t.clone(), ytype));
|
||||
}
|
||||
|
||||
// NOTE: use y's type instead of the arrays type.
|
||||
// an `empty` array has Any type, but any value will have a fixed type.
|
||||
// this converts the empty array into a typed array.
|
||||
Ok(Value::Array(ytype, [x.clone(), vec![y.clone()]].concat()))
|
||||
},
|
||||
[x, Value::Array(t, y)] => {
|
||||
let xtype = x.get_type();
|
||||
|
||||
if *t != xtype {
|
||||
return Err(RuntimeError::TypeError(t.clone(), xtype));
|
||||
}
|
||||
|
||||
// NOTE: read above
|
||||
Ok(Value::Array(xtype, [vec![x.clone()], y.clone()].concat()))
|
||||
},
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("+".into(), args)),
|
||||
}
|
||||
|
||||
Ok(Value::Array(xtype, [x, y].concat()))
|
||||
},
|
||||
(Value::Array(t, x), y) => {
|
||||
let ytype = y.get_type();
|
||||
|
||||
if t != ytype {
|
||||
return Err(RuntimeError::TypeError(t, ytype));
|
||||
Op::Sub => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Int(x - y)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Float(*x as f64 - y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Float(x - *y as f64)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Float(x - y)),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("-".into(), args)),
|
||||
}
|
||||
|
||||
// NOTE: use y's type instead of the arrays type.
|
||||
// an `empty` array has Any type, but any value will have a fixed type.
|
||||
// this converts the empty array into a typed array.
|
||||
Ok(Value::Array(ytype, [x, vec![y]].concat()))
|
||||
},
|
||||
(x, Value::Array(t, y)) => {
|
||||
let xtype = x.get_type();
|
||||
|
||||
if t != xtype {
|
||||
return Err(RuntimeError::TypeError(t, xtype));
|
||||
Op::Mul => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Int(x * y)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Float(*x as f64 * y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Float(x * *y as f64)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Float(x * y)),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("*".into(), args)),
|
||||
}
|
||||
|
||||
// NOTE: read above
|
||||
Ok(Value::Array(xtype, [vec![x], y].concat()))
|
||||
},
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("+".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Sub(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Float(x - y as f64)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 - y)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("-".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Mul(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * y as f64)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 * y)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
|
||||
(Value::String(x), Value::Int(y)) => Ok(Value::String(x.repeat(y as usize))),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("*".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Div(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Int(x / y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Float(x / y as f64)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 / y)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x / y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("*".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Exp(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Int(x.pow(y as u32))),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float((x as f64).powf(y))),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Float(x.powf(y as f64))),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x.powf(y))),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("**".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::Mod(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Int(x % y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Float(x % y as f64)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Float(x as f64 % y)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Float(x % y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("%".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::EqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x == y)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 == y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x == y as f64)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x == y)),
|
||||
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x == y)),
|
||||
(Value::String(x), Value::String(y)) => Ok(Value::Bool(x == y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("==".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::NotEqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x != y)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 != y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x != y as f64)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x != y)),
|
||||
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x != y)),
|
||||
(Value::String(x), Value::String(y)) => Ok(Value::Bool(x != y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("!=".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::GreaterThan(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x > y)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 > y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x > y as f64)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x > y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes(">".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::GreaterThanOrEqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x >= y)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 >= y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x >= y as f64)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x >= y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes(">=".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::LessThan(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x < y)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool((x as f64) < y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x < y as f64)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x < y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("<".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::LessThanOrEqualTo(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Int(x), Value::Int(y)) => Ok(Value::Bool(x <= y)),
|
||||
(Value::Int(x), Value::Float(y)) => Ok(Value::Bool(x as f64 <= y)),
|
||||
(Value::Float(x), Value::Int(y)) => Ok(Value::Bool(x <= y as f64)),
|
||||
(Value::Float(x), Value::Float(y)) => Ok(Value::Bool(x <= y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("<=".into(), vec![x, y])),
|
||||
},
|
||||
ParseTree::Not(x) => match self.exec(x)? {
|
||||
Value::Bool(x) => Ok(Value::Bool(!x)),
|
||||
x => Err(RuntimeError::NoOverloadForTypes("not".into(), vec![x]))
|
||||
},
|
||||
ParseTree::And(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x && y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("&&".into(), vec![x, y]))
|
||||
},
|
||||
ParseTree::Or(x, y) => match (self.exec(x)?, self.exec(y)?) {
|
||||
(Value::Bool(x), Value::Bool(y)) => Ok(Value::Bool(x || y)),
|
||||
(x, y) => Err(RuntimeError::NoOverloadForTypes("||".into(), vec![x, y]))
|
||||
},
|
||||
Op::Div => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Int(x / y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Float(x / *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Float(*x as f64 / y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Float(x / y)),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("/".into(), args)),
|
||||
}
|
||||
Op::Exp => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Float((*x as f64).powf(*y as f64))),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Float(x.powf(*y as f64))),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Float((*x as f64).powf(*y))),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Float(x.powf(*y))),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("**".into(), args)),
|
||||
}
|
||||
Op::Mod => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Int(x % y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Float(x % *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Float(*x as f64 % y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Float(x % y)),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("%".into(), args)),
|
||||
}
|
||||
Op::GreaterThan => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Bool(x > y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Bool(*x > *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Bool(*x as f64 > *y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Bool(x > y)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes(">".into(), args)),
|
||||
}
|
||||
Op::GreaterThanOrEqualTo => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Bool(x >= y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Bool(*x >= *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Bool(*x as f64 >= *y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Bool(x >= y)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes(">=".into(), args)),
|
||||
}
|
||||
Op::LessThan => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Bool(x < y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Bool(*x < *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Bool((*x as f64) < *y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Bool(x < y)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("<".into(), args)),
|
||||
}
|
||||
Op::LessThanOrEqualTo => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Bool(x <= y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Bool(*x <= *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Bool(*x as f64 <= *y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Bool(x <= y)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("<=".into(), args)),
|
||||
}
|
||||
Op::EqualTo => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Bool(x == y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Bool(*x == *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Bool(*x as f64 == *y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Bool(x == y)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("==".into(), args)),
|
||||
}
|
||||
Op::NotEqualTo => match &args[..] {
|
||||
[Value::Int(x), Value::Int(y)] => Ok(Value::Bool(x != y)),
|
||||
[Value::Float(x), Value::Int(y)] => Ok(Value::Bool(*x != *y as f64)),
|
||||
[Value::Int(x), Value::Float(y)] => Ok(Value::Bool(*x as f64 != *y)),
|
||||
[Value::Float(x), Value::Float(y)] => Ok(Value::Bool(x != y)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("!=".into(), args)),
|
||||
}
|
||||
Op::Not => match &args[0] {
|
||||
Value::Bool(b) => Ok(Value::Bool(!b)),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("!".into(), args)),
|
||||
}
|
||||
Op::Or => match &args[..] {
|
||||
[Value::Bool(x), Value::Bool(y)] => Ok(Value::Bool(*x || *y)),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("||".into(), args)),
|
||||
}
|
||||
Op::And => match &args[..] {
|
||||
[Value::Bool(x), Value::Bool(y)] => Ok(Value::Bool(*x && *y)),
|
||||
[Value::Nil, x] => Ok(x.clone()),
|
||||
[x, Value::Nil] => Ok(x.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("&&".into(), args)),
|
||||
}
|
||||
Op::Compose => match &args[..] {
|
||||
[_, v] => Ok(v.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("~".into(), args)),
|
||||
}
|
||||
Op::Head => match &args[0] {
|
||||
Value::Array(_, x) => Ok(x.first().ok_or(RuntimeError::EmptyArray)?.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("head".into(), args)),
|
||||
}
|
||||
Op::Tail => match &args[0] {
|
||||
Value::Array(t, x) => Ok(Value::Array(t.clone(), if x.len() > 0 { x[1..].to_vec() } else { vec![] })),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("head".into(), args)),
|
||||
}
|
||||
Op::Init => match &args[0] {
|
||||
Value::Array(t, x) => Ok(Value::Array(t.clone(), if x.len() > 0 { x[..x.len() - 1].to_vec() } else { vec![] })),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("head".into(), args)),
|
||||
}
|
||||
Op::Fini => match &args[0] {
|
||||
Value::Array(_, x) => Ok(x.last().ok_or(RuntimeError::EmptyArray)?.clone()),
|
||||
_ => Err(RuntimeError::NoOverloadForTypes("head".into(), args)),
|
||||
}
|
||||
Op::Id => match &args[0] {
|
||||
x => Ok(x.clone()),
|
||||
}
|
||||
Op::IntCast => match &args[0] {
|
||||
Value::Int(x) => Ok(Value::Int(*x)),
|
||||
Value::Float(x) => Ok(Value::Int(*x as i64)),
|
||||
Value::Bool(x) => Ok(Value::Int(if *x { 1 } else { 0 })),
|
||||
Value::String(x) => {
|
||||
let r: i64 = x.parse().map_err(|_| RuntimeError::ParseFail(x.clone(), Type::Int))?;
|
||||
Ok(Value::Int(r))
|
||||
}
|
||||
x => Err(RuntimeError::NoOverloadForTypes("int".into(), vec![x.clone()])),
|
||||
}
|
||||
Op::FloatCast => match &args[0] {
|
||||
Value::Int(x) => Ok(Value::Float(*x as f64)),
|
||||
Value::Float(x) => Ok(Value::Float(*x)),
|
||||
Value::Bool(x) => Ok(Value::Float(if *x { 1.0 } else { 0.0 })),
|
||||
Value::String(x) => {
|
||||
let r: f64 = x.parse().map_err(|_| RuntimeError::ParseFail(x.clone(), Type::Int))?;
|
||||
Ok(Value::Float(r))
|
||||
}
|
||||
x => Err(RuntimeError::NoOverloadForTypes("float".into(), vec![x.clone()])),
|
||||
}
|
||||
Op::BoolCast => match &args[0] {
|
||||
Value::Int(x) => Ok(Value::Bool(*x != 0)),
|
||||
Value::Float(x) => Ok(Value::Bool(*x != 0.0)),
|
||||
Value::Bool(x) => Ok(Value::Bool(*x)),
|
||||
Value::String(x) => Ok(Value::Bool(!x.is_empty())),
|
||||
Value::Array(_, vec) => Ok(Value::Bool(!vec.is_empty())),
|
||||
x => Err(RuntimeError::NoOverloadForTypes("bool".into(), vec![x.clone()])),
|
||||
}
|
||||
Op::StringCast => Ok(Value::String(format!("{}", &args[0]))),
|
||||
Op::Print => match &args[0] {
|
||||
Value::String(s) => {
|
||||
println!("{s}");
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
x => {
|
||||
println!("{x}");
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ParseTree::Equ(ident, body, scope) => {
|
||||
if self.variable_exists(&ident) {
|
||||
Err(RuntimeError::ImmutableError(ident.clone()))
|
||||
@@ -281,27 +362,46 @@ where
|
||||
let g = self.globals.clone();
|
||||
Executor::new(self.exprs, &mut self.globals)
|
||||
.locals(self.locals.clone())
|
||||
.add_local(func.name().unwrap().to_string(), Arc::new(Mutex::new(Object::function(func, g, self.locals.clone()))))
|
||||
.add_local(func.name().unwrap().to_string(),
|
||||
Arc::new(Mutex::new(Object::function(
|
||||
func
|
||||
.globals(g)
|
||||
.locals(self.locals.clone()), HashMap::new(), HashMap::new()))))
|
||||
.exec(scope)
|
||||
},
|
||||
ParseTree::Compose(x, y) => {
|
||||
self.exec(x)?;
|
||||
self.exec(y)
|
||||
ParseTree::FunctionCall(ident, args) => {
|
||||
let obj = self.get_object_mut(&ident)?;
|
||||
let v = Self::eval(obj)?;
|
||||
|
||||
match v {
|
||||
Value::Function(mut f) => {
|
||||
let mut args: Vec<_> = args.into_iter()
|
||||
.map(|x| Arc::new(Mutex::new(Object::variable(x, self.globals.clone(), self.locals.clone()))))
|
||||
.collect();
|
||||
|
||||
for arg in &mut args {
|
||||
Self::eval(arg)?;
|
||||
}
|
||||
|
||||
f.call(args)
|
||||
},
|
||||
_ => Err(RuntimeError::FunctionUndefined(ident.clone()))
|
||||
}
|
||||
},
|
||||
ParseTree::Id(x) => self.exec(x),
|
||||
ParseTree::_FunctionCallLocal(_idx, _args) => todo!(),
|
||||
ParseTree::If(cond, body) => if match self.exec(cond)? {
|
||||
Value::Float(f) => f != 0.0,
|
||||
Value::Int(i) => i != 0,
|
||||
Value::Bool(b) => b,
|
||||
Value::String(s) => !s.is_empty(),
|
||||
Value::Array(_, vec) => !vec.is_empty(),
|
||||
Value::Nil => false,
|
||||
x => return Err(RuntimeError::NoOverloadForTypes("?".into(), vec![x])),
|
||||
} {
|
||||
self.exec(body)
|
||||
} else {
|
||||
Ok(Value::Nil)
|
||||
},
|
||||
Value::Float(f) => f != 0.0,
|
||||
Value::Int(i) => i != 0,
|
||||
Value::Bool(b) => b,
|
||||
Value::String(s) => !s.is_empty(),
|
||||
Value::Array(_, vec) => !vec.is_empty(),
|
||||
Value::Nil => false,
|
||||
x => return Err(RuntimeError::NoOverloadForTypes("?".into(), vec![x])),
|
||||
} {
|
||||
self.exec(body)
|
||||
} else {
|
||||
Ok(Value::Nil)
|
||||
},
|
||||
ParseTree::IfElse(cond, istrue, isfalse) => if match self.exec(cond)? {
|
||||
Value::Float(f) => f != 0.0,
|
||||
Value::Int(i) => i != 0,
|
||||
@@ -315,23 +415,6 @@ where
|
||||
} else {
|
||||
self.exec(isfalse)
|
||||
},
|
||||
ParseTree::FunctionCall(ident, args) => {
|
||||
let obj = self.get_object_mut(&ident)?;
|
||||
let globals = Self::obj_globals(obj);
|
||||
let locals = Self::obj_locals(obj);
|
||||
let v = Self::eval(obj)?;
|
||||
|
||||
match v {
|
||||
Value::Function(mut f) => {
|
||||
let args = args.into_iter()
|
||||
.map(|x| Object::variable(x, self.globals.clone(), self.locals.clone()))
|
||||
.collect();
|
||||
|
||||
f.call(globals, locals, args)
|
||||
},
|
||||
_ => Err(RuntimeError::FunctionUndefined(ident.clone()))
|
||||
}
|
||||
},
|
||||
ParseTree::Variable(ident) => {
|
||||
let obj = self.get_object_mut(&ident)?;
|
||||
|
||||
@@ -339,70 +422,8 @@ where
|
||||
|
||||
Ok(v)
|
||||
},
|
||||
ParseTree::Constant(value) => Ok(value),
|
||||
ParseTree::IntCast(x) => match self.exec(x)? {
|
||||
Value::Int(x) => Ok(Value::Int(x)),
|
||||
Value::Float(x) => Ok(Value::Int(x as i64)),
|
||||
Value::Bool(x) => Ok(Value::Int(if x { 1 } else { 0 })),
|
||||
Value::String(x) => {
|
||||
let r: i64 = x.parse().map_err(|_| RuntimeError::ParseFail(x.clone(), Type::Int))?;
|
||||
Ok(Value::Int(r))
|
||||
}
|
||||
x => Err(RuntimeError::NoOverloadForTypes("int".into(), vec![x])),
|
||||
},
|
||||
ParseTree::FloatCast(x) => match self.exec(x)? {
|
||||
Value::Int(x) => Ok(Value::Float(x as f64)),
|
||||
Value::Float(x) => Ok(Value::Float(x)),
|
||||
Value::Bool(x) => Ok(Value::Float(if x { 1.0 } else { 0.0 })),
|
||||
Value::String(x) => {
|
||||
let r: f64 = x.parse().map_err(|_| RuntimeError::ParseFail(x.clone(), Type::Int))?;
|
||||
Ok(Value::Float(r))
|
||||
}
|
||||
x => Err(RuntimeError::NoOverloadForTypes("float".into(), vec![x])),
|
||||
},
|
||||
ParseTree::BoolCast(x) => match self.exec(x)? {
|
||||
Value::Int(x) => Ok(Value::Bool(x != 0)),
|
||||
Value::Float(x) => Ok(Value::Bool(x != 0.0)),
|
||||
Value::Bool(x) => Ok(Value::Bool(x)),
|
||||
Value::String(x) => Ok(Value::Bool(!x.is_empty())),
|
||||
Value::Array(_, vec) => Ok(Value::Bool(!vec.is_empty())),
|
||||
x => Err(RuntimeError::NoOverloadForTypes("bool".into(), vec![x])),
|
||||
},
|
||||
ParseTree::StringCast(x) => Ok(Value::String(format!("{}", self.exec(x)?))),
|
||||
ParseTree::Print(x) => match self.exec(x)? {
|
||||
Value::String(s) => {
|
||||
println!("{s}");
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
x => {
|
||||
println!("{x}");
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
}
|
||||
ParseTree::LambdaDefinition(func) => Ok(Value::Function(func)),
|
||||
ParseTree::NonCall(name) => {
|
||||
let obj = self.get_object_mut(&name)?;
|
||||
|
||||
let v = obj.lock().unwrap().eval()?;
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
ParseTree::Head(x) => match self.exec(x)? {
|
||||
Value::Array(_, x) => Ok(x.first().ok_or(RuntimeError::EmptyArray)?.clone()),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("head".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Tail(x) => match self.exec(x)? {
|
||||
Value::Array(t, x) => Ok(Value::Array(t, if x.len() > 0 { x[1..].to_vec() } else { vec![] })),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("tail".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Init(x) => match self.exec(x)? {
|
||||
Value::Array(t, x) => Ok(Value::Array(t, if x.len() > 0 { x[..x.len() - 1].to_vec() } else { vec![] })),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("init".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Fini(x) => match self.exec(x)? {
|
||||
Value::Array(_, x) => Ok(x.last().ok_or(RuntimeError::EmptyArray)?.clone()),
|
||||
t => Err(RuntimeError::NoOverloadForTypes("fini".into(), vec![t]))
|
||||
},
|
||||
ParseTree::Value(value) => Ok(value),
|
||||
ParseTree::LambdaDefinition(func) => Ok(Value::Function(func.globals(self.globals.clone()).locals(self.locals.clone()))),
|
||||
ParseTree::Nop => Ok(Value::Nil),
|
||||
ParseTree::Export(names) => {
|
||||
for name in names {
|
||||
@@ -412,6 +433,15 @@ where
|
||||
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
ParseTree::NonCall(name) => {
|
||||
let obj = self.get_object_mut(&name)?;
|
||||
|
||||
let v = obj.lock().unwrap().eval()?;
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
ParseTree::_Local(_idx) => todo!(),
|
||||
ParseTree::GeneratedFunction(function) => Ok(Value::Function(function.globals(self.globals.clone()).locals(self.locals.clone()))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user