Use evaluation error type
This commit is contained in:
parent
5b4bb6606e
commit
009095f771
@ -9,7 +9,7 @@ use std::convert::From;
|
|||||||
|
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
type EvalResult<T> = Result<T, String>;
|
type EvalResult<T> = Result<T, RuntimeError>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
@ -49,6 +49,14 @@ impl From<String> for RuntimeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&str> for RuntimeError {
|
||||||
|
fn from(msg: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
msg: msg.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RuntimeError {
|
impl RuntimeError {
|
||||||
fn get_msg(&self) -> String {
|
fn get_msg(&self) -> String {
|
||||||
format!("Runtime error: {}", self.msg)
|
format!("Runtime error: {}", self.msg)
|
||||||
@ -160,7 +168,7 @@ impl<'a> State<'a> {
|
|||||||
},
|
},
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
acc.push(Err(error.into()));
|
acc.push(Err(error.msg));
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,21 +218,21 @@ impl<'a> State<'a> {
|
|||||||
// This just checks that the function exists in "memory" by ID, we don't
|
// This just checks that the function exists in "memory" by ID, we don't
|
||||||
// actually retrieve it until `apply_function()`
|
// actually retrieve it until `apply_function()`
|
||||||
Some(RuntimeValue::Function(_)) => Primitive::Callable(Function::UserDefined(id.clone())),
|
Some(RuntimeValue::Function(_)) => Primitive::Callable(Function::UserDefined(id.clone())),
|
||||||
x => return Err(format!("Function not found for id: {} : {:?}", id, x)),
|
x => return Err(format!("Function not found for id: {} : {:?}", id, x).into()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Lookup::Param(n) => {
|
Lookup::Param(n) => {
|
||||||
let mem = n.into();
|
let mem = n.into();
|
||||||
match self.environments.lookup(&mem) {
|
match self.environments.lookup(&mem) {
|
||||||
Some(RuntimeValue::Primitive(prim)) => prim.clone(),
|
Some(RuntimeValue::Primitive(prim)) => prim.clone(),
|
||||||
e => return Err(format!("Param lookup error, got {:?}", e)),
|
e => return Err(format!("Param lookup error, got {:?}", e).into()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
kind @ Lookup::LocalVar | kind @ Lookup::GlobalVar => {
|
kind @ Lookup::LocalVar | kind @ Lookup::GlobalVar => {
|
||||||
let mem = id.into();
|
let mem = id.into();
|
||||||
match self.environments.lookup(&mem) {
|
match self.environments.lookup(&mem) {
|
||||||
Some(RuntimeValue::Primitive(expr)) => expr.clone(),
|
Some(RuntimeValue::Primitive(expr)) => expr.clone(),
|
||||||
_ => return Err(format!("Nothing found for variable lookup {} of kind {:?}", id, kind)),
|
_ => return Err(format!("Nothing found for variable lookup {} of kind {:?}", id, kind).into()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -232,19 +240,18 @@ impl<'a> State<'a> {
|
|||||||
Expression::Assign { ref lval, box rval } => {
|
Expression::Assign { ref lval, box rval } => {
|
||||||
let mem = lval.into();
|
let mem = lval.into();
|
||||||
let mut env = self.environments.lookup(&mem);
|
let mut env = self.environments.lookup(&mem);
|
||||||
return Err("Assign not implemented".to_string());
|
return Err("Assign not implemented".into());
|
||||||
},
|
},
|
||||||
Expression::Call { box f, args } => self.call_expression(f, args)?,
|
Expression::Call { box f, args } => self.call_expression(f, args)?,
|
||||||
Expression::Callable(func) => Primitive::Callable(func),
|
Expression::Callable(func) => Primitive::Callable(func),
|
||||||
Expression::ReductionError(e) => return Err(e.into()),
|
Expression::ReductionError(e) => return Err(e.into()),
|
||||||
e => return Err(format!("Can't yet handle {:?}", e)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Primitive> {
|
fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Primitive> {
|
||||||
let func = match self.expression(f)? {
|
let func = match self.expression(f)? {
|
||||||
Primitive::Callable(func) => func,
|
Primitive::Callable(func) => func,
|
||||||
other => return Err(format!("Trying to call non-function value: {:?}", other)),
|
other => return Err(format!("Trying to call non-function value: {:?}", other).into()),
|
||||||
};
|
};
|
||||||
match func {
|
match func {
|
||||||
Function::Builtin(builtin) => self.apply_builtin(builtin, args),
|
Function::Builtin(builtin) => self.apply_builtin(builtin, args),
|
||||||
@ -255,12 +262,12 @@ impl<'a> State<'a> {
|
|||||||
let body = body.clone(); //TODO ideally this clone would not happen
|
let body = body.clone(); //TODO ideally this clone would not happen
|
||||||
self.apply_function(body, args)
|
self.apply_function(body, args)
|
||||||
},
|
},
|
||||||
e => Err(format!("Error looking up function with id {}: {:?}", def_id, e))
|
e => Err(format!("Error looking up function with id {}: {:?}", def_id, e).into())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Function::Lambda { arity, body } => {
|
Function::Lambda { arity, body } => {
|
||||||
if arity as usize != args.len() {
|
if arity as usize != args.len() {
|
||||||
return Err(format!("Lambda expression requries {} arguments, only {} provided", arity, args.len()));
|
return Err(format!("Lambda expression requries {} arguments, only {} provided", arity, args.len()).into());
|
||||||
}
|
}
|
||||||
let body = body.clone(); //TODO again ideally, no cloning here
|
let body = body.clone(); //TODO again ideally, no cloning here
|
||||||
self.apply_function(body, args)
|
self.apply_function(body, args)
|
||||||
@ -279,7 +286,7 @@ impl<'a> State<'a> {
|
|||||||
|
|
||||||
Ok(match (builtin, evaled_args.as_slice()) {
|
Ok(match (builtin, evaled_args.as_slice()) {
|
||||||
(FieldAccess, /*&[Node::PrimObject { .. }]*/ _) => {
|
(FieldAccess, /*&[Node::PrimObject { .. }]*/ _) => {
|
||||||
return Err("Field access unimplemented".to_string());
|
return Err("Field access unimplemented".into());
|
||||||
}
|
}
|
||||||
(binop, &[ref lhs, ref rhs]) => match (binop, lhs, rhs) {
|
(binop, &[ref lhs, ref rhs]) => match (binop, lhs, rhs) {
|
||||||
(Add, Lit(Nat(l)), Lit(Nat(r))) => Nat(l + r).into(),
|
(Add, Lit(Nat(l)), Lit(Nat(r))) => Nat(l + r).into(),
|
||||||
@ -288,7 +295,7 @@ impl<'a> State<'a> {
|
|||||||
(Multiply, Lit(Nat(l)), Lit(Nat(r))) => Nat(l * r).into(),
|
(Multiply, Lit(Nat(l)), Lit(Nat(r))) => Nat(l * r).into(),
|
||||||
(Divide, Lit(Nat(l)), Lit(Nat(r))) => Float((*l as f64)/ (*r as f64)).into(),
|
(Divide, Lit(Nat(l)), Lit(Nat(r))) => Float((*l as f64)/ (*r as f64)).into(),
|
||||||
(Quotient, Lit(Nat(l)), Lit(Nat(r))) => if *r == 0 {
|
(Quotient, Lit(Nat(l)), Lit(Nat(r))) => if *r == 0 {
|
||||||
return Err("Divide-by-zero error".to_string());
|
return Err("Divide-by-zero error".into());
|
||||||
} else {
|
} else {
|
||||||
Nat(l / r).into()
|
Nat(l / r).into()
|
||||||
},
|
},
|
||||||
@ -320,7 +327,7 @@ impl<'a> State<'a> {
|
|||||||
(GreaterThanOrEqual, Lit(Int(l)), Lit(Int(r))) => Bool(l >= r).into(),
|
(GreaterThanOrEqual, Lit(Int(l)), Lit(Int(r))) => Bool(l >= r).into(),
|
||||||
(GreaterThanOrEqual, Lit(Float(l)), Lit(Float(r))) => Bool(l >= r).into(),
|
(GreaterThanOrEqual, Lit(Float(l)), Lit(Float(r))) => Bool(l >= r).into(),
|
||||||
|
|
||||||
(binop, lhs, rhs) => return Err(format!("Invalid binop expression {:?} {:?} {:?}", lhs, binop, rhs)),
|
(binop, lhs, rhs) => return Err(format!("Invalid binop expression {:?} {:?} {:?}", lhs, binop, rhs).into()),
|
||||||
},
|
},
|
||||||
(prefix, &[ref arg]) => match (prefix, arg) {
|
(prefix, &[ref arg]) => match (prefix, arg) {
|
||||||
(BooleanNot, Lit(Bool(true))) => Bool(false),
|
(BooleanNot, Lit(Bool(true))) => Bool(false),
|
||||||
@ -329,7 +336,7 @@ impl<'a> State<'a> {
|
|||||||
(Negate, Lit(Int(n))) => Int(-(*n as i64)),
|
(Negate, Lit(Int(n))) => Int(-(*n as i64)),
|
||||||
(Increment, Lit(Int(n))) => Int(*n),
|
(Increment, Lit(Int(n))) => Int(*n),
|
||||||
(Increment, Lit(Nat(n))) => Nat(*n),
|
(Increment, Lit(Nat(n))) => Nat(*n),
|
||||||
_ => return Err("No valid prefix op".to_string())
|
_ => return Err("No valid prefix op".into())
|
||||||
}.into(),
|
}.into(),
|
||||||
/* builtin functions */
|
/* builtin functions */
|
||||||
(IOPrint, &[ref anything]) => {
|
(IOPrint, &[ref anything]) => {
|
||||||
@ -345,7 +352,7 @@ impl<'a> State<'a> {
|
|||||||
std::io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'");
|
std::io::stdin().read_line(&mut buf).expect("Error readling line in 'getline'");
|
||||||
StringLit(Rc::new(buf.trim().to_string())).into()
|
StringLit(Rc::new(buf.trim().to_string())).into()
|
||||||
},
|
},
|
||||||
(x, args) => return Err(format!("bad or unimplemented builtin {:?} | {:?}", x, args)),
|
(x, args) => return Err(format!("bad or unimplemented builtin {:?} | {:?}", x, args).into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user