From d03f43a94c8f14d61b48773589bd33b9036165ca Mon Sep 17 00:00:00 2001 From: teo3300 Date: Sun, 11 Jun 2023 03:03:25 +0200 Subject: [PATCH] Added environment with basic math functions Signed-off-by: teo3300 --- src/envs.rs | 30 ++++++++++++++++++++++-------- src/main.rs | 2 +- src/mal_core.rs | 35 +++++++++++++++++++++-------------- src/printer.rs | 10 ++++++---- src/reader.rs | 7 +++---- src/step2_eval.rs | 1 + src/types.rs | 46 ++++++++++++++++++++++------------------------ 7 files changed, 76 insertions(+), 55 deletions(-) diff --git a/src/envs.rs b/src/envs.rs index e33c670..02ec1fd 100644 --- a/src/envs.rs +++ b/src/envs.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; -use crate::types::{KeyType, MalRet, MalType}; +use crate::types::MalType::{Fun, Str}; +use crate::types::{int_op, MalArgs, MalRet, MalType}; pub struct Env { map: HashMap, @@ -8,16 +9,29 @@ pub struct Env { impl Env { pub fn new() -> Self { - Env { + let mut env = Env { map: HashMap::new(), + }; + env.init(); + env + } + + pub fn solve(&self, sym: String) -> MalRet { + match self.map.get(&sym) { + Some(val) => Ok(val.clone()), + None => Err(format!("symbol {:?} not defined", sym)), } } - pub fn solve(&self, sym: KeyType) -> MalRet { - let v = sym.val; - match self.map.get(&v) { - Some(val) => Ok(val.clone()), - None => Err(format!("symbol {:?} not defined", v)), - } + fn define(&mut self, sym: &str, f: fn(MalArgs) -> MalRet) { + self.map.insert(sym.to_string(), Fun(f)); + } + + fn init(&mut self) { + self.define("test", |_| Ok(Str("This is a test function".to_string()))); + self.define("+", |args| int_op(0, |a, b| a + b, args)); + self.define("-", |args| int_op(0, |a, b| a - b, args)); + self.define("*", |args| int_op(1, |a, b| a * b, args)); + self.define("/", |args| int_op(1, |a, b| a / b, args)); } } diff --git a/src/main.rs b/src/main.rs index 3abe439..a711b45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,8 +40,8 @@ fn main() { println!("; [{}]> Error {}", num, err); } } + num += 1; } - num += 1; break; } } diff --git a/src/mal_core.rs b/src/mal_core.rs index f362255..2715707 100644 --- a/src/mal_core.rs +++ b/src/mal_core.rs @@ -1,17 +1,24 @@ use crate::envs::Env; use crate::types::MalType::*; -use crate::types::{MalRet, MalType}; +use crate::types::{MalArgs, MalRet, MalType}; -fn function_call(list: MalType) -> MalRet { +fn call_func(func: &MalType, args: MalArgs) -> MalRet { + match func { + Fun(func) => func(args), + _ => panic!("Calling not a function"), + } +} + +fn eval_func(list: MalType) -> MalRet { match list { List(list) => { - let _func = &list[0]; - if list.len() > 1 { - let _ast = &list[1..list.len() - 1]; - todo!("call: func(args)"); + let func = &list[0]; + let args = if list.len() > 1 { + &list[1..] } else { - todo!("call: func()"); - } + &list[0..0] + }; + call_func(func, args.to_vec()) } _ => Err("YOU SHOULD NOT BE HERE".to_string()), } @@ -21,10 +28,10 @@ pub fn eval(ast: MalType, env: &Env) -> MalRet { match &ast { List(list) => { if list.is_empty() { - Ok(ast) + Ok(Nil) + // Previously Ok(ast) } else { - let ev = eval_ast(ast, env)?; - function_call(ev) + eval_func(eval_ast(ast, env)?) } } _ => eval_ast(ast, env), @@ -42,10 +49,10 @@ fn eval_list(list: Vec, env: &Env) -> MalRet { Ok(List(ret)) } -pub fn eval_ast(ast: MalType, env: &Env) -> MalRet { +fn eval_ast(ast: MalType, env: &Env) -> MalRet { match ast { - Sym(sym) => env.solve(sym), // resolve + Sym(sym) => env.solve(sym), List(list) => eval_list(list, env), - _ => Ok(ast), // Default behavior, do not resolve + _ => Ok(ast), } } diff --git a/src/printer.rs b/src/printer.rs index 13f7c98..8878b38 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -5,14 +5,15 @@ use crate::types::MalType::*; pub fn pr_str(ast: &MalType, print_readably: bool) -> String { match ast { Nil => "nil".to_string(), - Sym(sym) | Key(sym) => sym.val.to_string(), + Sym(sym) => sym.to_string(), + Key(sym) => sym[1..sym.len() - 1].to_string(), Int(val) => val.to_string(), Bool(val) => val.to_string(), Str(str) => { if print_readably { - escape_str(&str.val) + escape_str(str) } else { - str.val.to_string() + str.to_string() } } List(el) => format!( @@ -33,9 +34,10 @@ pub fn pr_str(ast: &MalType, print_readably: bool) -> String { Map(el) => format!( "{{{}}}", el.iter() - .map(|sub| vec![sub.0.val.to_string(), pr_str(sub.1, print_readably)].join(" ")) + .map(|sub| vec![sub.0.to_string(), pr_str(sub.1, print_readably)].join(" ")) .collect::>() .join(" ") ), + Fun(func) => format!("{:?}", func), } } diff --git a/src/reader.rs b/src/reader.rs index 488d3f8..0a27cf5 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1,7 +1,6 @@ // Specyfy components in "types" use crate::types::*; // By specifying enum variants it's possible to omit namespace -use crate::types::KeyVar; use crate::types::MalType::*; use regex::Regex; @@ -72,11 +71,11 @@ impl Reader { if Regex::new(r"^-?[0-9]+$").unwrap().is_match(tk) { Ok(Int(tk.parse::().unwrap())) } else if tk.starts_with('\"') { - Ok(Str(map_key(KeyVar::Str, &unescape_str(tk)))) + Ok(Str(unescape_str(tk))) } else if tk.starts_with(':') { - Ok(Key(map_key(KeyVar::Key, tk))) + Ok(Key(format!("ʞ{}", tk))) } else { - Ok(Sym(map_key(KeyVar::Sym, tk))) + Ok(Sym(tk.to_string())) } } } diff --git a/src/step2_eval.rs b/src/step2_eval.rs index 9b2771d..cb97ab6 100644 --- a/src/step2_eval.rs +++ b/src/step2_eval.rs @@ -36,6 +36,7 @@ fn PRINT(output: MalType) -> String { pub fn rep(input: &str, env: &Env) -> Result { let ast = READ(input)?; + // println!("{:#?}", ast); let out = EVAL(ast, env)?; Ok(PRINT(out)) } diff --git a/src/types.rs b/src/types.rs index 1b67cd8..0ce9e73 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,35 +2,16 @@ use std::collections::HashMap; -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub enum KeyVar { - Key, - Sym, - Str, -} - -#[derive(Debug, Clone, Hash, Eq, PartialEq)] -pub struct KeyType { - pub val: String, - var: KeyVar, -} - -pub fn map_key(var: KeyVar, val: &str) -> KeyType { - KeyType { - val: val.to_string(), - var, - } -} - // All Mal types should inherit from this #[derive(Debug, Clone)] pub enum MalType { List(Vec), Vector(Vec), - Map(HashMap), - Sym(KeyType), - Key(KeyType), - Str(KeyType), + Map(HashMap), + Fun(fn(MalArgs) -> MalRet), + Sym(String), + Key(String), + Str(String), Int(isize), Bool(bool), Nil, @@ -87,3 +68,20 @@ pub fn unescape_str(s: &str) -> String { .replace("\\n", "\n") .replace("\\\"", "\"") } + +use MalType::Int; + +pub fn int_op(set: isize, f: fn(isize, isize) -> isize, args: MalArgs) -> MalRet { + let mut tmp: isize = set; + for el in args { + match el { + Int(val) => { + tmp = f(tmp, val); + } + _ => { + return Err(format!("{:?} is not a number", el)); + } + } + } + Ok(Int(tmp)) +}