Added environment with basic math functions

Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
teo3300
2023-06-11 03:03:25 +02:00
parent fe6fbf061c
commit d03f43a94c
7 changed files with 76 additions and 55 deletions

View File

@ -1,6 +1,7 @@
use std::collections::HashMap; 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 { pub struct Env {
map: HashMap<String, MalType>, map: HashMap<String, MalType>,
@ -8,16 +9,29 @@ pub struct Env {
impl Env { impl Env {
pub fn new() -> Self { pub fn new() -> Self {
Env { let mut env = Env {
map: HashMap::new(), 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 { fn define(&mut self, sym: &str, f: fn(MalArgs) -> MalRet) {
let v = sym.val; self.map.insert(sym.to_string(), Fun(f));
match self.map.get(&v) { }
Some(val) => Ok(val.clone()),
None => Err(format!("symbol {:?} not defined", v)), 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));
} }
} }

View File

@ -40,8 +40,8 @@ fn main() {
println!("; [{}]> Error {}", num, err); println!("; [{}]> Error {}", num, err);
} }
} }
num += 1;
} }
num += 1;
break; break;
} }
} }

View File

@ -1,17 +1,24 @@
use crate::envs::Env; use crate::envs::Env;
use crate::types::MalType::*; 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 { match list {
List(list) => { List(list) => {
let _func = &list[0]; let func = &list[0];
if list.len() > 1 { let args = if list.len() > 1 {
let _ast = &list[1..list.len() - 1]; &list[1..]
todo!("call: func(args)");
} else { } else {
todo!("call: func()"); &list[0..0]
} };
call_func(func, args.to_vec())
} }
_ => Err("YOU SHOULD NOT BE HERE".to_string()), _ => Err("YOU SHOULD NOT BE HERE".to_string()),
} }
@ -21,10 +28,10 @@ pub fn eval(ast: MalType, env: &Env) -> MalRet {
match &ast { match &ast {
List(list) => { List(list) => {
if list.is_empty() { if list.is_empty() {
Ok(ast) Ok(Nil)
// Previously Ok(ast)
} else { } else {
let ev = eval_ast(ast, env)?; eval_func(eval_ast(ast, env)?)
function_call(ev)
} }
} }
_ => eval_ast(ast, env), _ => eval_ast(ast, env),
@ -42,10 +49,10 @@ fn eval_list(list: Vec<MalType>, env: &Env) -> MalRet {
Ok(List(ret)) Ok(List(ret))
} }
pub fn eval_ast(ast: MalType, env: &Env) -> MalRet { fn eval_ast(ast: MalType, env: &Env) -> MalRet {
match ast { match ast {
Sym(sym) => env.solve(sym), // resolve Sym(sym) => env.solve(sym),
List(list) => eval_list(list, env), List(list) => eval_list(list, env),
_ => Ok(ast), // Default behavior, do not resolve _ => Ok(ast),
} }
} }

View File

@ -5,14 +5,15 @@ use crate::types::MalType::*;
pub fn pr_str(ast: &MalType, print_readably: bool) -> String { pub fn pr_str(ast: &MalType, print_readably: bool) -> String {
match ast { match ast {
Nil => "nil".to_string(), 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(), Int(val) => val.to_string(),
Bool(val) => val.to_string(), Bool(val) => val.to_string(),
Str(str) => { Str(str) => {
if print_readably { if print_readably {
escape_str(&str.val) escape_str(str)
} else { } else {
str.val.to_string() str.to_string()
} }
} }
List(el) => format!( List(el) => format!(
@ -33,9 +34,10 @@ pub fn pr_str(ast: &MalType, print_readably: bool) -> String {
Map(el) => format!( Map(el) => format!(
"{{{}}}", "{{{}}}",
el.iter() 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::<Vec<String>>() .collect::<Vec<String>>()
.join(" ") .join(" ")
), ),
Fun(func) => format!("{:?}", func),
} }
} }

View File

@ -1,7 +1,6 @@
// Specyfy components in "types" // Specyfy components in "types"
use crate::types::*; use crate::types::*;
// By specifying enum variants it's possible to omit namespace // By specifying enum variants it's possible to omit namespace
use crate::types::KeyVar;
use crate::types::MalType::*; use crate::types::MalType::*;
use regex::Regex; use regex::Regex;
@ -72,11 +71,11 @@ impl Reader {
if Regex::new(r"^-?[0-9]+$").unwrap().is_match(tk) { if Regex::new(r"^-?[0-9]+$").unwrap().is_match(tk) {
Ok(Int(tk.parse::<isize>().unwrap())) Ok(Int(tk.parse::<isize>().unwrap()))
} else if tk.starts_with('\"') { } else if tk.starts_with('\"') {
Ok(Str(map_key(KeyVar::Str, &unescape_str(tk)))) Ok(Str(unescape_str(tk)))
} else if tk.starts_with(':') { } else if tk.starts_with(':') {
Ok(Key(map_key(KeyVar::Key, tk))) Ok(Key(format!("ʞ{}", tk)))
} else { } else {
Ok(Sym(map_key(KeyVar::Sym, tk))) Ok(Sym(tk.to_string()))
} }
} }
} }

View File

@ -36,6 +36,7 @@ fn PRINT(output: MalType) -> String {
pub fn rep(input: &str, env: &Env) -> Result<String, String> { pub fn rep(input: &str, env: &Env) -> Result<String, String> {
let ast = READ(input)?; let ast = READ(input)?;
// println!("{:#?}", ast);
let out = EVAL(ast, env)?; let out = EVAL(ast, env)?;
Ok(PRINT(out)) Ok(PRINT(out))
} }

View File

@ -2,35 +2,16 @@
use std::collections::HashMap; 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 // All Mal types should inherit from this
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum MalType { pub enum MalType {
List(Vec<MalType>), List(Vec<MalType>),
Vector(Vec<MalType>), Vector(Vec<MalType>),
Map(HashMap<KeyType, MalType>), Map(HashMap<String, MalType>),
Sym(KeyType), Fun(fn(MalArgs) -> MalRet),
Key(KeyType), Sym(String),
Str(KeyType), Key(String),
Str(String),
Int(isize), Int(isize),
Bool(bool), Bool(bool),
Nil, Nil,
@ -87,3 +68,20 @@ pub fn unescape_str(s: &str) -> String {
.replace("\\n", "\n") .replace("\\n", "\n")
.replace("\\\"", "\"") .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))
}