From bc32c2616434c0abcb289f389b17dc4005065f0eebcf731fd4be12b34a70cb90 Mon Sep 17 00:00:00 2001 From: Apache Date: Tue, 25 Jun 2024 00:00:37 -0500 Subject: [PATCH] Added maps and map indexing syntax --- src/executor.rs | 72 +++++++++++++++++++++++++++++++++++++++--------- src/main.rs | 8 ++++++ src/parser.rs | 9 +++++- src/test.lisp | 13 ++------- src/tokenizer.rs | 37 ++++++++++++++++++++----- 5 files changed, 108 insertions(+), 31 deletions(-) diff --git a/src/executor.rs b/src/executor.rs index adc7ccb..b199986 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -104,7 +104,8 @@ pub enum LispValue { List(Vec, bool), LispFunction(String, Vec, Vec), RustFunction(String, RustFunctionType), - Var(String) + Map(HashMap), + Var(String), } impl fmt::Display for LispValue { @@ -174,7 +175,8 @@ fn get_type(v: &LispValue) -> String { LispValue::List(_, _) => String::from("list"), LispValue::LispFunction(_, _, _) => String::from("function"), LispValue::RustFunction(_, _) => String::from("function"), - LispValue::Var(_) => String::from("symbol") + LispValue::Map(_) => String::from("map"), + LispValue::Var(_) => String::from("symbol"), } } @@ -234,6 +236,28 @@ impl LispState { Ok(vec![args[1].clone()]) }); + add_function(&mut table, "get", |_,args| { + if args.len() != 2 { + return Err(RuntimeError { + message: format!("Bad arguments to get (expected 2, got {})", args.len()) + }) + } + + if let LispValue::Map(map) = &args[0] { + if let LispValue::String(str) = &args[1] { + return Ok(vec![map.get(str).unwrap_or(&LispValue::Nil).to_owned()]); + } else { + return Err(RuntimeError { + message: format!("Bad argument 2 to get (expected string, got {})", get_type(&args[0])) + }) + } + } else { + return Err(RuntimeError { + message: format!("Bad argument 1 to get (expected map, got {})", get_type(&args[0])) + }) + } + }); + add_function(&mut table, "print", |_, args| { let mut strings = Vec::new(); for val in args { @@ -545,15 +569,14 @@ impl LispState { list[i] = env.get(name).unwrap_or_else(|| self.table.get(name).unwrap_or(&LispValue::Nil)).to_owned(); } if let LispValue::List(elements, quoted) = &list[i] { - if let Ok((elems, astuple)) = self.eval_list(env, elements, *quoted) { - if astuple { - list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned(); - for j in 1..elems.len() { - list.insert(i, elems[j].to_owned()); - } - } else { - list[i] = LispValue::List(elems, *quoted); + let (elems, astuple) = self.eval_list(env, elements, *quoted)?; + if astuple { + list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned(); + for j in 1..elems.len() { + list.insert(i, elems[j].to_owned()); } + } else { + list[i] = LispValue::List(elems, *quoted); } } } @@ -565,19 +588,19 @@ impl LispState { if let LispValue::RustFunction(_name, f) = &list[0] { Ok((f(self, list[1..].to_vec())?, true)) } else if let LispValue::LispFunction(_name, _, _) = &list[0] { - Ok((self.call_lisp_func(env, &list[0], list[1..].to_vec())?, true)) + Ok((self.call_lisp_func_internal(env, &list[0], list[1..].to_vec())?, true)) } else { Ok((list.to_vec(), false)) } } - fn call_lisp_func(&mut self, env: &mut HashMap, f: &LispValue, args: Vec) -> Result, RuntimeError> { + fn call_lisp_func_internal(&mut self, env: &mut HashMap, f: &LispValue, args: Vec) -> Result, RuntimeError> { let (arg_names, instructions) = match f { LispValue::LispFunction(_, arg_names, i) => { (arg_names, i) }, _ => return Err(RuntimeError { - message: format!("Invalid argument to call_lisp_func (expected function, got {})", get_type(f)) + message: format!("Invalid argument to call_lisp_func_internal (expected function, got {})", get_type(f)) }) }; @@ -603,6 +626,29 @@ impl LispState { Ok(out) } + pub fn call_lisp_func(&mut self, f: &LispValue, args: Vec>) -> Result, RuntimeError> { + if !matches!(f, LispValue::LispFunction(_, _, _)) { + return Err(RuntimeError { + message: format!("Invalid argument to call_lisp_func_internal (expected function, got {})", get_type(&f)) + }) + } + + let mut vargs = Vec::new(); + for v in args { + vargs.push(v.into()); + } + + self.call_lisp_func_internal(&mut HashMap::new(), &f, vargs) + } + + pub fn get_func(&mut self, name: impl Into) -> Option { + if let Some(v) = self.table.get(&name.into()) { + Some(v.to_owned()) + } else { + None + } + } + pub fn execute(&mut self, instructions: Vec) -> Result, RuntimeError> { let instructions = Self::handle_prevalues(self, instructions); diff --git a/src/main.rs b/src/main.rs index 17dafaa..3e54dea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,15 @@ fn main() -> Result<(), Box> { let mut state = LispState::new(); + let mut some_map = std::collections::HashMap::new(); + some_map.insert(String::from("x"), LispValue::Float(0.0)); + some_map.insert(String::from("y"), LispValue::Float(0.0)); + state.execute(instructions)?; + let f = state.get_func("takevalue").unwrap(); + + state.call_lisp_func(&f, vec![LispValue::Map(some_map)])?; + Ok(()) } diff --git a/src/parser.rs b/src/parser.rs index e397464..3554951 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -195,11 +195,18 @@ fn parse_exp(tokens: Vec, quoted: bool) -> PreLispValue { }, Token::Identifier(name) => { if name == &String::from("nil") { - values.push(PreLispValue::Nil) + values.push(PreLispValue::Nil); } else { values.push(PreLispValue::Var(name.to_owned())); } }, + Token::Index(map, idx) => { + values.push(PreLispValue::List(vec![ + PreLispValue::Var(String::from("get")), + PreLispValue::Var(map.to_owned()), + PreLispValue::String(idx.to_owned()) + ], false)); + } Token::Integer(num) => { values.push(PreLispValue::Integer(*num)); }, diff --git a/src/test.lisp b/src/test.lisp index 0347f2d..d09e17e 100644 --- a/src/test.lisp +++ b/src/test.lisp @@ -1,11 +1,4 @@ -(fn hi (name) ( - (print (concat "Hello, " name "!")) +(fn takevalue(origin) ( + (print (concat "Origin: (" origin.x ", " origin.y ")")) + (print origin) )) - -(hi "Joe") - -(hi (fn(x) ( - (print x) -))) - -(name "Balls") \ No newline at end of file diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 692221f..57ae74b 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -93,6 +93,7 @@ pub enum Token { Quote, Unquote, Identifier(String), + Index(String, String), String(String), Integer(i32), Float(f32) @@ -132,6 +133,9 @@ pub struct Tokenizer { is_float: bool, reading_identifier: bool, + is_index: bool, + indexing: Option, + skipping_comment: bool, storage: Vec, @@ -151,6 +155,9 @@ impl Tokenizer { escape_next_char: false, reading_identifier: false, + is_index: false, + indexing: None, + skipping_comment: false, storage: Vec::new() @@ -164,10 +171,10 @@ impl Tokenizer { let line = self.line; let column = self.column; - self.line += 1; + self.column += 1; if char == '\n' { - self.column += 1; - self.line = 1; + self.line += 1; + self.column = 1; } if self.skipping_comment { @@ -182,12 +189,28 @@ impl Tokenizer { if self.reading_identifier { if char.is_alphabetic() { self.storage.push(char); - } else { - self.reading_identifier = false; - - tokens.push(Token::Identifier(self.storage.iter().collect())); + continue; + } else if char == '.' { + self.is_index = true; + self.indexing = Some(self.storage.iter().collect()); self.storage.clear(); + continue; } + + self.reading_identifier = false; + + if self.is_index { + self.is_index = false; + + tokens.push(Token::Index(self.indexing.as_ref().unwrap().to_string(), self.storage.iter().collect())); + + self.storage.clear(); + self.indexing = None; + } else { + tokens.push(Token::Identifier(self.storage.iter().collect())); + } + + self.storage.clear(); } if self.reading_num {