From 240aca36313016df68f03954c54c2bc21910344e Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 24 Mar 2021 18:16:52 +0530 Subject: rename env to eval, add div operator --- src/lisp/env.rs | 266 -------------------------------------------------------- 1 file changed, 266 deletions(-) delete mode 100644 src/lisp/env.rs (limited to 'src/lisp/env.rs') diff --git a/src/lisp/env.rs b/src/lisp/env.rs deleted file mode 100644 index c5ff6d3..0000000 --- a/src/lisp/env.rs +++ /dev/null @@ -1,266 +0,0 @@ -use crate::{ - app::AppState, - lisp::{ - error::LispError, - expr::{LispExpr, LispFunction}, - number::LispNumber, - Environment, - }, - primitive, -}; - -use std::collections::HashMap; - -use log::{error, info}; - -pub fn with_prelude() -> Environment { - let mut env = Environment::new(); - primitive!(env, Some(2), "+", |args, _| { - if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { - Err(LispError::EvalError) - } else { - Ok(LispExpr::Number( - args.iter() - .map(|arg| unwrap_number(arg)) - .fold(LispNumber::Integer(0), |acc, x| acc + *x), - )) - } - }); - primitive!(env, Some(2), "-", |args, _| { - if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { - Err(LispError::EvalError) - } else { - let mut acc = unwrap_number(&args[0]).clone(); - for arg in args.into_iter().skip(1) { - acc = acc - *unwrap_number(&arg); - } - Ok(LispExpr::Number(acc)) - } - }); - primitive!(env, Some(2), "*", |args, _| { - if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { - Err(LispError::EvalError) - } else { - Ok(LispExpr::Number( - args.iter() - .map(|arg| unwrap_number(arg)) - .fold(LispNumber::Integer(1), |acc, x| acc * *x), - )) - } - }); - primitive!(env, Some(0), "toggle-grid", |_, app| { - app.toggle_grid(); - Ok(LispExpr::Unit) - }); - primitive!(env, Some(3), "if", |args, _| { - match args { - [predicate, then, else_] => { - if matches!(predicate, LispExpr::BoolLit(false)) { - Ok(else_.clone()) - } else { - Ok(then.clone()) - } - } - _ => { - error!("invalid args for `if` primitive"); - Err(LispError::EvalError) - } - } - }); - primitive!(env, Some(2), "and", |args, _| { - if args - .iter() - .any(|arg| matches!(arg, LispExpr::BoolLit(false))) - { - Ok(LispExpr::BoolLit(false)) - } else { - Ok(LispExpr::BoolLit(true)) - } - }); - primitive!(env, Some(2), "or", |args, _| { - if args - .iter() - .any(|arg| matches!(arg, LispExpr::BoolLit(true))) - { - Ok(LispExpr::BoolLit(true)) - } else { - Ok(LispExpr::BoolLit(false)) - } - }); - primitive!(env, Some(1), "not", |args, _| { - match args { - [val] => { - if matches!(val, LispExpr::BoolLit(false)) { - Ok(LispExpr::BoolLit(true)) - } else { - Ok(LispExpr::BoolLit(false)) - } - } - _ => Err(LispError::EvalError), - } - }); - primitive!(env, None, "begin", |args, _| { - if args.is_empty() { - Err(LispError::EvalError) - } else { - Ok(args.into_iter().last().unwrap().clone()) - } - }); - env -} - -pub fn eval( - expr: &LispExpr, - app: &mut AppState, - extra_env: Option<&Environment>, -) -> Result { - match expr { - LispExpr::Unit => Ok(expr.clone()), - LispExpr::StringLit(_) => Ok(expr.clone()), - LispExpr::Number(_) => Ok(expr.clone()), - LispExpr::BoolLit(_) => Ok(expr.clone()), - LispExpr::Ident(ref id) => { - lookup_extended(extra_env.unwrap_or(&Environment::new()), &app.lisp_env, id) - } - LispExpr::List(li) => { - let func_expr = &li[0]; - match func_expr { - LispExpr::Ident(s) => match s.as_ref() { - "define" => define_var(&li[1..], app), - "set!" => set_var(&li[1..], app), - "lambda" => create_lambda(&li[1..]), - _ => { - let func_expr = eval(&func_expr, app, extra_env)?; - match func_expr { - LispExpr::PrimitiveFunc(f) => { - let mut args = Vec::new(); - for item in li[1..].iter() { - args.push(eval(item, app, extra_env)?); - } - f.call(&args, app) - } - LispExpr::Function(f) => { - info!("eval custom func"); - let mut args = Vec::new(); - for item in li[1..].iter() { - args.push(eval(item, app, extra_env)?); - } - if f.params.len() != args.len() { - info!("too many or too little number of args"); - Err(LispError::EvalError) // too many or too little number of args - } else { - let mut local_env: Environment = - f.params.into_iter().zip(args).collect(); - local_env.extend(app.lisp_env.clone()); - if let Some(env) = extra_env { - local_env.extend(env.clone()); - } - if f.body.is_empty() { - return Ok(LispExpr::Unit); - } else { - eval(&LispExpr::List(f.body), app, Some(&local_env)) - } - } - } - _ => Err(LispError::EvalError), - } - } - }, - _ => Err(LispError::EvalError), - } - } - _ => Err(LispError::ParseError), - } -} - -pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result { - if args.len() != 2 { - error!("Invalid arity for `define`"); - return Err(LispError::EvalError); - } - match args { - [LispExpr::Ident(id), expr] => { - let value = eval(&expr, app, None)?; - app.lisp_env.insert(id.into(), value); - return Ok(LispExpr::Unit); - } - _ => { - error!("Invalid usage of `define`"); - return Err(LispError::EvalError); - } - } -} - -pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result { - if args.len() != 2 { - error!("Invalid arity for `define`"); - return Err(LispError::EvalError); - } - match args { - [LispExpr::Ident(id), expr] => { - let value = eval(&expr, app, None)?; - return app - .lisp_env - .insert(id.into(), value) - .ok_or(LispError::EvalError); - } - _ => { - error!("Invalid usage of `define`"); - return Err(LispError::EvalError); - } - } -} - -pub fn create_lambda(cdr: &[LispExpr]) -> Result { - if cdr.len() != 2 { - // needs params and body - error!("needs params and body"); - return Err(LispError::EvalError); - } - info!("creating lambda"); - match cdr { - [LispExpr::List(params), LispExpr::List(body)] - if params.iter().all(|p| matches!(p, LispExpr::Ident(_))) => - { - return Ok(LispExpr::Function(LispFunction { - params: params - .into_iter() - .map(|p| unwrap_ident(p.clone())) - .collect::>(), - body: body.clone(), - })); - } - _ => { - error!("Invalid usage of `define`"); - return Err(LispError::EvalError); - } - } -} - -pub fn lookup_extended( - local: &Environment, - super_: &Environment, - key: &str, -) -> Result { - if let Some(e) = local.get(key) { - Ok(e.clone()) - } else if let Some(e) = super_.get(key) { - Ok(e.clone()) - } else { - Err(LispError::EvalError) - } -} - -pub fn unwrap_number(n: &LispExpr) -> &LispNumber { - match n { - LispExpr::Number(i) => i, - _ => panic!("unwrap_number expected number"), - } -} - -pub fn unwrap_ident(i: LispExpr) -> String { - match i { - LispExpr::Ident(i) => i, - _ => panic!("unwrap_ident expected string"), - } -} -- cgit v1.2.3