mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 17:25:33 +01:00
Eval cycle implemented
Yet to be implement: - Environment - Function calls Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
23
src/envs.rs
Normal file
23
src/envs.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::types::{KeyType, MalRet, MalType};
|
||||||
|
|
||||||
|
pub struct Env {
|
||||||
|
map: HashMap<String, MalType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main.rs
41
src/main.rs
@ -1,15 +1,21 @@
|
|||||||
// io lib to read input and print output
|
// io lib to read input and print output
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
mod envs;
|
||||||
|
mod mal_core;
|
||||||
mod printer;
|
mod printer;
|
||||||
mod reader;
|
mod reader;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
mod step1_read_print;
|
use envs::Env;
|
||||||
use step1_read_print::rep;
|
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
mod step2_eval;
|
||||||
|
use step2_eval::rep;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
|
let env = Env::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
loop {
|
loop {
|
||||||
@ -19,28 +25,23 @@ fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
// Read line to compose program inpug
|
// Read line to compose program inpug
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
io::stdin().read_line(&mut line)?;
|
io::stdin().read_line(&mut line).unwrap();
|
||||||
|
|
||||||
input.push_str(&line);
|
input.push_str(&line);
|
||||||
if input == "\n" {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform rep on whole available input
|
if input != "\n" {
|
||||||
match rep(&input) {
|
// Perform rep on whole available input
|
||||||
Ok(output) => {
|
match rep(&input, &env) {
|
||||||
num += 1;
|
Ok(output) => println!("[{}]> {}", num, output),
|
||||||
println!("[{}]> {}", num, output);
|
Err(err) => {
|
||||||
}
|
if line != "\n" {
|
||||||
Err(err) => {
|
continue;
|
||||||
if line == "\n" {
|
}
|
||||||
num += 1;
|
println!("; [{}]> Error {}", num, err);
|
||||||
println!("; [{}]> {}", num, err);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
num += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/mal_core.rs
Normal file
51
src/mal_core.rs
Normal file
@ -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<MalType>, 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
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/step2_eval.rs
Normal file
41
src/step2_eval.rs
Normal file
@ -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<String, String> {
|
||||||
|
let ast = READ(input)?;
|
||||||
|
let out = EVAL(ast, env)?;
|
||||||
|
Ok(PRINT(out))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user