mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 17:25:33 +01:00
Added environment with basic math functions
Signed-off-by: teo3300 <matteo.rogora@live.it>
This commit is contained in:
30
src/envs.rs
30
src/envs.rs
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,8 +40,8 @@ fn main() {
|
|||||||
println!("; [{}]> Error {}", num, err);
|
println!("; [{}]> Error {}", num, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
num += 1;
|
||||||
}
|
}
|
||||||
num += 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
46
src/types.rs
46
src/types.rs
@ -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))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user