From fe6fbf061c0a17c838d61b98db7a455b9c042e3c Mon Sep 17 00:00:00 2001 From: teo3300 Date: Sat, 10 Jun 2023 23:19:29 +0200 Subject: [PATCH] Eval cycle implemented Yet to be implement: - Environment - Function calls Signed-off-by: teo3300 --- src/envs.rs | 23 +++++++++++++++++++++ src/main.rs | 41 ++++++++++++++++++------------------- src/mal_core.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/step2_eval.rs | 41 +++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 src/envs.rs create mode 100644 src/mal_core.rs create mode 100644 src/step2_eval.rs diff --git a/src/envs.rs b/src/envs.rs new file mode 100644 index 0000000..e33c670 --- /dev/null +++ b/src/envs.rs @@ -0,0 +1,23 @@ +use std::collections::HashMap; + +use crate::types::{KeyType, MalRet, MalType}; + +pub struct Env { + map: HashMap, +} + +impl Env { + pub fn new() -> Self { + Env { + map: HashMap::new(), + } + } + + 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)), + } + } +} diff --git a/src/main.rs b/src/main.rs index 9daa0d1..3abe439 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,21 @@ // io lib to read input and print output use std::io::{self, Write}; +mod envs; +mod mal_core; mod printer; mod reader; mod types; -mod step1_read_print; -use step1_read_print::rep; +use envs::Env; -fn main() -> io::Result<()> { +mod step2_eval; +use step2_eval::rep; + +fn main() { let mut num = 0; + let env = Env::new(); + loop { let mut input = String::new(); loop { @@ -19,28 +25,23 @@ fn main() -> io::Result<()> { // Read line to compose program inpug let mut line = String::new(); - io::stdin().read_line(&mut line)?; + io::stdin().read_line(&mut line).unwrap(); input.push_str(&line); - if input == "\n" { - break; - } - // Perform rep on whole available input - match rep(&input) { - Ok(output) => { - num += 1; - println!("[{}]> {}", num, output); - } - Err(err) => { - if line == "\n" { - num += 1; - println!("; [{}]> {}", num, err); - } else { - continue; + if input != "\n" { + // Perform rep on whole available input + match rep(&input, &env) { + Ok(output) => println!("[{}]> {}", num, output), + Err(err) => { + if line != "\n" { + continue; + } + println!("; [{}]> Error {}", num, err); } } - }; + } + num += 1; break; } } diff --git a/src/mal_core.rs b/src/mal_core.rs new file mode 100644 index 0000000..f362255 --- /dev/null +++ b/src/mal_core.rs @@ -0,0 +1,51 @@ +use crate::envs::Env; +use crate::types::MalType::*; +use crate::types::{MalRet, MalType}; + +fn function_call(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)"); + } else { + todo!("call: func()"); + } + } + _ => Err("YOU SHOULD NOT BE HERE".to_string()), + } +} + +pub fn eval(ast: MalType, env: &Env) -> MalRet { + match &ast { + List(list) => { + if list.is_empty() { + Ok(ast) + } else { + let ev = eval_ast(ast, env)?; + function_call(ev) + } + } + _ => eval_ast(ast, env), + } +} + +fn eval_list(list: Vec, env: &Env) -> MalRet { + let mut ret = Vec::new(); + for el in list { + match eval(el, env) { + Ok(val) => ret.push(val), + Err(err) => return Err(err), + } + } + Ok(List(ret)) +} + +pub fn eval_ast(ast: MalType, env: &Env) -> MalRet { + match ast { + Sym(sym) => env.solve(sym), // resolve + List(list) => eval_list(list, env), + _ => Ok(ast), // Default behavior, do not resolve + } +} diff --git a/src/step2_eval.rs b/src/step2_eval.rs new file mode 100644 index 0000000..9b2771d --- /dev/null +++ b/src/step2_eval.rs @@ -0,0 +1,41 @@ +// Structure the main functions of the interpreter +// +// For now just act as an echo, note that each function should not modify the +// input, thus this can be referenced by the previous step without the need +// to allocate more memory + +use crate::envs::Env; +use crate::mal_core::eval; +use crate::printer::pr_str; +use crate::reader::read_str; +use crate::types::{MalRet, MalType}; + +#[allow(non_snake_case)] +/// Read input and generate an ast +fn READ(input: &str) -> MalRet { + match read_str(input) { + Ok(ast) => Ok(ast), + Err(err) => Err(format!("@ READ: {}", err)), + } +} + +#[allow(non_snake_case)] +/// Evaluate the generated ast +fn EVAL(ast: MalType, env: &Env) -> MalRet { + match eval(ast, env) { + Ok(ast) => Ok(ast), + Err(err) => Err(format!("@ EVAL: {}", err)), + } +} + +#[allow(non_snake_case)] +/// Print out the result of the evaluation +fn PRINT(output: MalType) -> String { + pr_str(&output, true) +} + +pub fn rep(input: &str, env: &Env) -> Result { + let ast = READ(input)?; + let out = EVAL(ast, env)?; + Ok(PRINT(out)) +}