2022-09-06 13:52:29 +00:00
|
|
|
use std::{collections::HashMap, rc::Rc, cell::RefCell};
|
|
|
|
|
2022-09-12 20:53:04 +00:00
|
|
|
use crate::{value::{Value, Complex, Func}, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError, Position};
|
2022-09-06 13:52:29 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Environment {
|
2022-09-07 20:11:51 +00:00
|
|
|
parent: Option<EnvRef>,
|
2022-09-09 20:08:40 +00:00
|
|
|
map: HashMap<Rc<str>, Value>,
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|
|
|
|
|
2022-09-09 20:08:40 +00:00
|
|
|
pub type EnvRef = Rc<RefCell<Environment>>;
|
2022-09-07 20:11:51 +00:00
|
|
|
|
2022-09-06 13:52:29 +00:00
|
|
|
impl Environment {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self { parent: None, map: HashMap::new() }
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
pub fn wrap(self) -> EnvRef {
|
|
|
|
Rc::new(RefCell::new(self))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn extend(parent: EnvRef) -> Self {
|
2022-09-06 13:52:29 +00:00
|
|
|
Self { parent: Some(parent), map: HashMap::new() }
|
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
pub fn get(&self, name: &str) -> Option<Value> {
|
2022-09-09 20:08:40 +00:00
|
|
|
match self.map.get(name) {
|
2022-09-11 17:02:18 +00:00
|
|
|
Some(v) => Some(v.clone()),
|
2022-09-06 13:52:29 +00:00
|
|
|
None => match self.parent {
|
|
|
|
Some(ref p) => p.borrow().get(name),
|
2022-09-11 17:02:18 +00:00
|
|
|
None => None
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|
2022-09-09 20:08:40 +00:00
|
|
|
}
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn declare(&mut self, name: Rc<str>, value: Value) {
|
|
|
|
self.map.insert(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(&mut self, name: Rc<str>, value: Value) -> Result<(),()> {
|
|
|
|
match self.map.contains_key(&name) {
|
|
|
|
true => { self.map.insert(name, value); Ok(()) },
|
|
|
|
false => match self.parent {
|
|
|
|
Some(ref mut p) => p.borrow_mut().set(name, value),
|
|
|
|
None => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
impl Default for Environment {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-12 20:53:04 +00:00
|
|
|
#[derive(Debug)]
|
2022-09-11 05:01:53 +00:00
|
|
|
pub enum Unwind {
|
2022-09-12 20:53:04 +00:00
|
|
|
Continue{pos: Position},
|
|
|
|
Break{pos: Position},
|
|
|
|
Return{pos: Position, value: Value},
|
|
|
|
Error(RuntimeError)
|
2022-09-11 05:01:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Unwind {
|
|
|
|
pub fn as_error(self) -> RuntimeError {
|
|
|
|
match self {
|
|
|
|
Self::Error(e) => e,
|
2022-09-12 20:53:04 +00:00
|
|
|
Self::Continue { pos } => RuntimeError::new("continue statement outside of loop", pos),
|
|
|
|
Self::Break { pos } => RuntimeError::new("break statement outside of loop", pos),
|
|
|
|
Self::Return { pos, .. } => RuntimeError::new("return statement outside of function", pos),
|
2022-09-11 05:01:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<RuntimeError> for Unwind {
|
|
|
|
fn from(e: RuntimeError) -> Self {
|
|
|
|
Self::Error(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
fn unwrap_ident_token(tok: &Token) -> &Rc<str> {
|
2022-09-07 22:10:43 +00:00
|
|
|
if let Token { ty: TokenType::Ident(s),.. } = tok {
|
|
|
|
s
|
|
|
|
} else {
|
|
|
|
unreachable!("precondition failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 05:01:53 +00:00
|
|
|
pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), Unwind> {
|
2022-09-06 13:52:29 +00:00
|
|
|
match stmt {
|
|
|
|
Stmt::Expr{ expr }
|
2022-09-12 20:53:04 +00:00
|
|
|
=> drop(eval_expr(expr, env)?),
|
2022-09-07 22:10:43 +00:00
|
|
|
Stmt::Let { lhs, rhs: None }
|
|
|
|
=> env.borrow_mut().declare(unwrap_ident_token(lhs).clone(), Value::Nil),
|
|
|
|
Stmt::Let { lhs, rhs: Some(rhs) } => {
|
2022-09-06 13:52:29 +00:00
|
|
|
let r = eval_expr(rhs, env.clone())?;
|
2022-09-07 22:10:43 +00:00
|
|
|
env.borrow_mut().declare(unwrap_ident_token(lhs).clone(), r)
|
2022-09-06 13:52:29 +00:00
|
|
|
},
|
2022-09-07 20:11:51 +00:00
|
|
|
Stmt::Block { stmts } => {
|
|
|
|
let block_env = Environment::extend(env).wrap();
|
2022-09-12 20:53:04 +00:00
|
|
|
for stmt in stmts {
|
|
|
|
eval_stmt(stmt, block_env.clone())?;
|
2022-09-07 20:11:51 +00:00
|
|
|
}
|
2022-09-07 22:10:43 +00:00
|
|
|
},
|
2022-09-07 20:11:51 +00:00
|
|
|
Stmt::If { if_clauses, else_clause } => {
|
|
|
|
for ic in if_clauses {
|
|
|
|
let cond = eval_expr(&ic.0, env.clone())?;
|
|
|
|
if cond.truthy() {
|
2022-09-11 17:02:18 +00:00
|
|
|
return eval_stmt(&ic.1, env)
|
2022-09-07 20:11:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(ec) = else_clause {
|
2022-09-11 17:02:18 +00:00
|
|
|
return eval_stmt(ec, env)
|
2022-09-07 20:11:51 +00:00
|
|
|
}
|
2022-09-07 22:10:43 +00:00
|
|
|
},
|
2022-09-13 17:31:29 +00:00
|
|
|
Stmt::For { var, expr, stmt, iter_pos } => {
|
2022-09-07 22:10:43 +00:00
|
|
|
let name = unwrap_ident_token(var);
|
|
|
|
let iter = eval_expr(expr, env.clone())?;
|
|
|
|
env.borrow_mut().declare(name.clone(), Value::Nil);
|
2022-09-13 17:31:29 +00:00
|
|
|
let iterator = iter.iter(iter_pos);
|
2022-09-11 17:02:18 +00:00
|
|
|
if let Err(e) = iterator {
|
2022-09-12 20:53:04 +00:00
|
|
|
return Err(RuntimeError::new(e, var.pos.clone()).into())
|
2022-09-11 17:02:18 +00:00
|
|
|
}
|
|
|
|
if let Ok(i) = iterator {
|
2022-09-07 22:10:43 +00:00
|
|
|
for v in i {
|
2022-09-13 17:31:29 +00:00
|
|
|
let v = v?;
|
2022-09-07 22:10:43 +00:00
|
|
|
let env = env.clone();
|
|
|
|
env.borrow_mut().set(name.clone(), v).expect("unreachable");
|
2022-09-11 17:02:18 +00:00
|
|
|
match eval_stmt(stmt, env) {
|
2022-09-11 05:01:53 +00:00
|
|
|
Ok(_) => (),
|
|
|
|
Err(Unwind::Break{..}) => break,
|
|
|
|
Err(Unwind::Continue{..}) => continue,
|
|
|
|
Err(e) => return Err(e)
|
|
|
|
}
|
2022-09-07 22:10:43 +00:00
|
|
|
}
|
2022-09-11 17:02:18 +00:00
|
|
|
}
|
2022-09-07 22:10:43 +00:00
|
|
|
},
|
2022-09-09 20:08:40 +00:00
|
|
|
Stmt::While { expr, stmt } => {
|
|
|
|
loop {
|
|
|
|
let cond = eval_expr(expr, env.clone())?;
|
|
|
|
if !cond.truthy() {
|
|
|
|
break
|
|
|
|
}
|
2022-09-11 17:02:18 +00:00
|
|
|
match eval_stmt(stmt, env.clone()) {
|
2022-09-11 05:01:53 +00:00
|
|
|
Ok(_) => (),
|
|
|
|
Err(Unwind::Break{..}) => break,
|
|
|
|
Err(Unwind::Continue{..}) => continue,
|
|
|
|
Err(e) => return Err(e)
|
|
|
|
}
|
2022-09-09 20:08:40 +00:00
|
|
|
}
|
|
|
|
},
|
2022-09-12 20:53:04 +00:00
|
|
|
Stmt::Fn { name, args, body } => {
|
|
|
|
let name = name.ty.clone().as_ident().unwrap();
|
2022-09-14 15:16:53 +00:00
|
|
|
let func = Func::Func {
|
2022-09-12 20:53:04 +00:00
|
|
|
name: Some(name.clone()),
|
|
|
|
args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(),
|
|
|
|
env: env.clone(),
|
|
|
|
func: body.as_ref().clone()
|
|
|
|
};
|
|
|
|
env.borrow_mut().declare(name, Value::Func(func));
|
|
|
|
},
|
2022-09-13 17:31:29 +00:00
|
|
|
Stmt::Break { pos } => return Err(Unwind::Break { pos: pos.clone() }),
|
|
|
|
Stmt::Continue { pos } => return Err(Unwind::Continue { pos: pos.clone() }),
|
|
|
|
Stmt::Return { pos, expr } => {
|
2022-09-12 20:53:04 +00:00
|
|
|
let value = eval_expr(expr, env)?;
|
2022-09-13 17:31:29 +00:00
|
|
|
return Err(Unwind::Return { pos: pos.clone(), value })
|
2022-09-12 20:53:04 +00:00
|
|
|
}
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-06 13:52:29 +00:00
|
|
|
match expr {
|
2022-09-07 20:11:51 +00:00
|
|
|
Expr::Literal { value } => Ok(eval_literal(value)),
|
|
|
|
Expr::Ident { value } => eval_ident(value, env),
|
2022-09-06 13:52:29 +00:00
|
|
|
Expr::Binary { lhs, rhs, op } => match op.ty.get_op_type() {
|
2022-09-07 20:11:51 +00:00
|
|
|
Some(OpType::Assignment)
|
|
|
|
=> eval_assignment(lhs, rhs, op, env),
|
2022-09-11 05:14:54 +00:00
|
|
|
Some(OpType::Additive) | Some(OpType::Multiplicative)
|
2022-09-07 20:11:51 +00:00
|
|
|
=> eval_binary(lhs, rhs, op, env),
|
2022-09-11 05:14:54 +00:00
|
|
|
Some(OpType::Boolean)
|
|
|
|
=> eval_boolean(lhs, rhs, op, env),
|
2022-09-09 20:08:40 +00:00
|
|
|
Some(OpType::Comparison)
|
|
|
|
=> eval_comp(lhs, rhs, op, env),
|
2022-09-06 13:52:29 +00:00
|
|
|
o => todo!("{:?}", o) // TODO other operations
|
|
|
|
},
|
2022-09-10 21:19:23 +00:00
|
|
|
Expr::Unary { arg, op } => eval_unary(arg, op, env),
|
2022-09-09 20:08:40 +00:00
|
|
|
Expr::List { items } => {
|
|
|
|
let mut list = Vec::with_capacity(items.len());
|
|
|
|
for item in items {
|
|
|
|
list.push(eval_expr(item, env.clone())?);
|
|
|
|
}
|
2022-09-10 21:19:23 +00:00
|
|
|
Ok(Value::from(list))
|
2022-09-09 20:08:40 +00:00
|
|
|
},
|
2022-09-15 04:01:57 +00:00
|
|
|
Expr::Map { items } => {
|
|
|
|
let mut map = HashMap::with_capacity(items.len());
|
|
|
|
for (k, v) in items {
|
|
|
|
let key = eval_expr(k, env.clone())?;
|
|
|
|
let value = eval_expr(v, env.clone())?;
|
|
|
|
map.insert(key, value);
|
|
|
|
}
|
|
|
|
Ok(Value::from(map))
|
|
|
|
},
|
2022-09-09 20:08:40 +00:00
|
|
|
Expr::FuncCall { func, args, pos } => {
|
2022-09-10 21:19:23 +00:00
|
|
|
let func = eval_expr(func, env.clone())?;
|
2022-09-09 20:08:40 +00:00
|
|
|
let mut arg_values = Vec::with_capacity(args.len());
|
|
|
|
for arg in args {
|
|
|
|
let result = eval_expr(arg, env.clone())?;
|
|
|
|
arg_values.push(result);
|
|
|
|
}
|
|
|
|
func.call(arg_values, pos)
|
2022-09-10 21:19:23 +00:00
|
|
|
},
|
|
|
|
Expr::Index { lhs, index, pos } => {
|
|
|
|
let l = eval_expr(lhs, env.clone())?;
|
|
|
|
let idx = eval_expr(index, env)?;
|
2022-09-12 20:53:04 +00:00
|
|
|
l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))
|
|
|
|
},
|
|
|
|
Expr::Fn { args, body } => {
|
2022-09-14 15:16:53 +00:00
|
|
|
let func = Func::Func {
|
2022-09-12 20:53:04 +00:00
|
|
|
name: None,
|
|
|
|
args: args.into_iter().map(|a| a.ty.clone().as_ident().unwrap()).collect(),
|
|
|
|
env: env.clone(),
|
|
|
|
func: body.as_ref().clone()
|
|
|
|
};
|
|
|
|
Ok(Value::Func(func))
|
2022-09-10 21:19:23 +00:00
|
|
|
},
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|
2022-09-07 20:11:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval_literal(token: &Token) -> Value {
|
|
|
|
match &token.ty {
|
|
|
|
TokenType::Nil => Value::Nil,
|
|
|
|
TokenType::True => Value::Bool(true),
|
|
|
|
TokenType::False => Value::Bool(false),
|
|
|
|
TokenType::Int(n) => Value::Int(*n),
|
|
|
|
TokenType::Float(f) => Value::Float(*f),
|
2022-09-09 20:08:40 +00:00
|
|
|
TokenType::ImFloat(f) => Value::Complex(Complex::new(0.0, *f)),
|
2022-09-07 20:11:51 +00:00
|
|
|
TokenType::String(s) => Value::String(s.clone()),
|
2022-09-07 22:10:43 +00:00
|
|
|
TokenType::Char(c) => Value::Char(*c),
|
2022-09-07 20:11:51 +00:00
|
|
|
_ => todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval_ident(token: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
|
|
|
if let Token { ty: TokenType::Ident(name), ..} = token {
|
|
|
|
env.borrow_mut()
|
|
|
|
.get(name)
|
2022-09-12 20:53:04 +00:00
|
|
|
.ok_or_else(|| RuntimeError::new("Variable not defined in scope", token.pos.clone()))
|
2022-09-07 20:11:51 +00:00
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-07 20:11:51 +00:00
|
|
|
// lhs must be an identifier (checked in parser)
|
2022-09-11 17:02:18 +00:00
|
|
|
if let Expr::Ident{value: Token{ty: TokenType::Ident(name),..}} = lhs {
|
2022-09-07 20:11:51 +00:00
|
|
|
if op.ty == TokenType::Equal {
|
|
|
|
// plain assignment
|
|
|
|
let r = eval_expr(rhs, env.clone())?;
|
|
|
|
env.borrow_mut()
|
|
|
|
.set(name.clone(), r)
|
2022-09-12 20:53:04 +00:00
|
|
|
.map_err(|_| RuntimeError::new("Variable not declared before assignment", op.pos.clone()))?;
|
2022-09-07 20:11:51 +00:00
|
|
|
Ok(Value::Nil)
|
|
|
|
} else {
|
|
|
|
// compound assignment
|
|
|
|
let prev_value = env.borrow_mut()
|
|
|
|
.get(name)
|
2022-09-12 20:53:04 +00:00
|
|
|
.ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?;
|
2022-09-07 20:11:51 +00:00
|
|
|
let r = eval_expr(rhs, env.clone())?;
|
|
|
|
|
|
|
|
let result = match op.ty {
|
|
|
|
TokenType::PlusEqual => &prev_value + &r,
|
|
|
|
TokenType::MinusEqual => &prev_value - &r,
|
|
|
|
TokenType::StarEqual => &prev_value * &r,
|
|
|
|
TokenType::SlashEqual => &prev_value / &r,
|
2022-09-07 22:10:43 +00:00
|
|
|
TokenType::PercentEqual => &prev_value % &r,
|
2022-09-07 20:11:51 +00:00
|
|
|
_ => todo!() // TODO more operations
|
2022-09-12 20:53:04 +00:00
|
|
|
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))?;
|
2022-09-07 20:11:51 +00:00
|
|
|
|
|
|
|
env.borrow_mut()
|
|
|
|
.set(name.clone(), result.clone()).expect("unreachable");
|
|
|
|
Ok(result)
|
|
|
|
}
|
2022-09-11 17:02:18 +00:00
|
|
|
} else if let Expr::Index { lhs, index, pos } = lhs {
|
2022-09-10 21:19:23 +00:00
|
|
|
let l = eval_expr(lhs, env.clone())?;
|
|
|
|
let idx = eval_expr(index, env.clone())?;
|
|
|
|
if op.ty == TokenType::Equal {
|
|
|
|
let r = eval_expr(rhs, env)?;
|
2022-09-12 20:53:04 +00:00
|
|
|
l.assign_index(&idx, r.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
2022-09-10 21:19:23 +00:00
|
|
|
Ok(r)
|
|
|
|
} else {
|
2022-09-12 20:53:04 +00:00
|
|
|
let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
2022-09-10 21:19:23 +00:00
|
|
|
let r = eval_expr(rhs, env)?;
|
|
|
|
let result = match op.ty {
|
|
|
|
TokenType::PlusEqual => &prev_value + &r,
|
|
|
|
TokenType::MinusEqual => &prev_value - &r,
|
|
|
|
TokenType::StarEqual => &prev_value * &r,
|
|
|
|
TokenType::SlashEqual => &prev_value / &r,
|
|
|
|
TokenType::PercentEqual => &prev_value % &r,
|
|
|
|
_ => todo!() // TODO more operations
|
2022-09-12 20:53:04 +00:00
|
|
|
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))?;
|
|
|
|
l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
2022-09-10 21:19:23 +00:00
|
|
|
Ok(result)
|
|
|
|
}
|
2022-09-07 20:11:51 +00:00
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
pub fn eval_binary(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-07 20:11:51 +00:00
|
|
|
let l = eval_expr(lhs, env.clone())?;
|
|
|
|
let r = eval_expr(rhs, env)?;
|
|
|
|
match op.ty {
|
|
|
|
TokenType::Plus => &l + &r,
|
|
|
|
TokenType::Minus => &l - &r,
|
|
|
|
TokenType::Star => &l * &r,
|
|
|
|
TokenType::Slash => &l / &r,
|
2022-09-07 22:10:43 +00:00
|
|
|
TokenType::Percent => &l % &r,
|
2022-09-07 20:11:51 +00:00
|
|
|
_ => todo!() // TODO other operations
|
2022-09-12 20:53:04 +00:00
|
|
|
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
2022-09-09 20:08:40 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
pub fn eval_boolean(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-11 05:14:54 +00:00
|
|
|
let l = eval_expr(lhs, env.clone())?;
|
|
|
|
match op.ty {
|
|
|
|
TokenType::DoubleAmper => if l.truthy() {
|
|
|
|
eval_expr(rhs, env)
|
|
|
|
} else {
|
|
|
|
Ok(l)
|
|
|
|
},
|
|
|
|
TokenType::DoublePipe => if !l.truthy() {
|
|
|
|
eval_expr(rhs, env)
|
|
|
|
} else {
|
|
|
|
Ok(l)
|
|
|
|
},
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
pub fn eval_comp(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-09 20:08:40 +00:00
|
|
|
let l = eval_expr(lhs, env.clone())?;
|
|
|
|
let r = eval_expr(rhs, env)?;
|
2022-09-12 20:53:04 +00:00
|
|
|
let mk_err = || RuntimeError::new(
|
|
|
|
format!("Cannot compare {:?} with {:?}", l, r),
|
|
|
|
op.pos.clone()
|
|
|
|
);
|
2022-09-09 20:08:40 +00:00
|
|
|
match op.ty {
|
|
|
|
TokenType::DoubleEqual => Ok(Value::Bool(l == r)),
|
|
|
|
TokenType::BangEqual => Ok(Value::Bool(l != r)),
|
|
|
|
TokenType::Greater => l.partial_cmp(&r)
|
|
|
|
.ok_or_else(mk_err)
|
|
|
|
.map(|o| Value::from(o.is_gt())),
|
|
|
|
TokenType::Less => l.partial_cmp(&r)
|
|
|
|
.ok_or_else(mk_err)
|
|
|
|
.map(|o| Value::from(o.is_lt())),
|
|
|
|
TokenType::GreaterEqual => l.partial_cmp(&r)
|
|
|
|
.ok_or_else(mk_err)
|
|
|
|
.map(|o| Value::from(o.is_ge())),
|
|
|
|
TokenType::LessEqual => l.partial_cmp(&r)
|
|
|
|
.ok_or_else(mk_err)
|
|
|
|
.map(|o| Value::from(o.is_le())),
|
|
|
|
TokenType::Spaceship => l.partial_cmp(&r)
|
|
|
|
.ok_or_else(mk_err)
|
|
|
|
.map(|o| Value::from(o as i8)),
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
2022-09-10 21:19:23 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 17:02:18 +00:00
|
|
|
pub fn eval_unary(arg: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-10 21:19:23 +00:00
|
|
|
let a = eval_expr(arg, env)?;
|
|
|
|
match op.ty {
|
|
|
|
TokenType::Minus => -a,
|
2022-09-11 05:14:54 +00:00
|
|
|
TokenType::Bang => Ok(Value::Bool(!a.truthy())),
|
2022-09-10 21:19:23 +00:00
|
|
|
_ => todo!(),
|
2022-09-12 20:53:04 +00:00
|
|
|
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
2022-09-11 17:02:18 +00:00
|
|
|
}
|