Added maps and map indexing syntax

This commit is contained in:
Apache 2024-06-25 00:00:37 -05:00
parent 43a6e4c1fd
commit bc32c26164
Signed by: apache
GPG key ID: 6B10F3EAF14F4C77
5 changed files with 108 additions and 31 deletions

View file

@ -104,7 +104,8 @@ pub enum LispValue {
List(Vec<LispValue>, bool), List(Vec<LispValue>, bool),
LispFunction(String, Vec<String>, Vec<LispValue>), LispFunction(String, Vec<String>, Vec<LispValue>),
RustFunction(String, RustFunctionType), RustFunction(String, RustFunctionType),
Var(String) Map(HashMap<String, LispValue>),
Var(String),
} }
impl fmt::Display for LispValue { impl fmt::Display for LispValue {
@ -174,7 +175,8 @@ fn get_type(v: &LispValue) -> String {
LispValue::List(_, _) => String::from("list"), LispValue::List(_, _) => String::from("list"),
LispValue::LispFunction(_, _, _) => String::from("function"), LispValue::LispFunction(_, _, _) => String::from("function"),
LispValue::RustFunction(_, _) => 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()]) 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| { add_function(&mut table, "print", |_, args| {
let mut strings = Vec::new(); let mut strings = Vec::new();
for val in args { 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(); 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 LispValue::List(elements, quoted) = &list[i] {
if let Ok((elems, astuple)) = self.eval_list(env, elements, *quoted) { let (elems, astuple) = self.eval_list(env, elements, *quoted)?;
if astuple { if astuple {
list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned(); list[i] = elems.get(0).unwrap_or(&LispValue::Nil).to_owned();
for j in 1..elems.len() { for j in 1..elems.len() {
list.insert(i, elems[j].to_owned()); list.insert(i, elems[j].to_owned());
}
} else {
list[i] = LispValue::List(elems, *quoted);
} }
} else {
list[i] = LispValue::List(elems, *quoted);
} }
} }
} }
@ -565,19 +588,19 @@ impl LispState {
if let LispValue::RustFunction(_name, f) = &list[0] { if let LispValue::RustFunction(_name, f) = &list[0] {
Ok((f(self, list[1..].to_vec())?, true)) Ok((f(self, list[1..].to_vec())?, true))
} else if let LispValue::LispFunction(_name, _, _) = &list[0] { } 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 { } else {
Ok((list.to_vec(), false)) Ok((list.to_vec(), false))
} }
} }
fn call_lisp_func(&mut self, env: &mut HashMap<String, LispValue>, f: &LispValue, args: Vec<LispValue>) -> Result<Vec<LispValue>, RuntimeError> { fn call_lisp_func_internal(&mut self, env: &mut HashMap<String, LispValue>, f: &LispValue, args: Vec<LispValue>) -> Result<Vec<LispValue>, RuntimeError> {
let (arg_names, instructions) = match f { let (arg_names, instructions) = match f {
LispValue::LispFunction(_, arg_names, i) => { LispValue::LispFunction(_, arg_names, i) => {
(arg_names, i) (arg_names, i)
}, },
_ => return Err(RuntimeError { _ => 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) Ok(out)
} }
pub fn call_lisp_func(&mut self, f: &LispValue, args: Vec<impl Into<LispValue>>) -> Result<Vec<LispValue>, 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<String>) -> Option<LispValue> {
if let Some(v) = self.table.get(&name.into()) {
Some(v.to_owned())
} else {
None
}
}
pub fn execute(&mut self, instructions: Vec<PreLispValue>) -> Result<Vec<LispValue>, RuntimeError> { pub fn execute(&mut self, instructions: Vec<PreLispValue>) -> Result<Vec<LispValue>, RuntimeError> {
let instructions = Self::handle_prevalues(self, instructions); let instructions = Self::handle_prevalues(self, instructions);

View file

@ -17,7 +17,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut state = LispState::new(); 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)?; state.execute(instructions)?;
let f = state.get_func("takevalue").unwrap();
state.call_lisp_func(&f, vec![LispValue::Map(some_map)])?;
Ok(()) Ok(())
} }

View file

@ -195,11 +195,18 @@ fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue {
}, },
Token::Identifier(name) => { Token::Identifier(name) => {
if name == &String::from("nil") { if name == &String::from("nil") {
values.push(PreLispValue::Nil) values.push(PreLispValue::Nil);
} else { } else {
values.push(PreLispValue::Var(name.to_owned())); 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) => { Token::Integer(num) => {
values.push(PreLispValue::Integer(*num)); values.push(PreLispValue::Integer(*num));
}, },

View file

@ -1,11 +1,4 @@
(fn hi (name) ( (fn takevalue(origin) (
(print (concat "Hello, " name "!")) (print (concat "Origin: (" origin.x ", " origin.y ")"))
(print origin)
)) ))
(hi "Joe")
(hi (fn(x) (
(print x)
)))
(name "Balls")

View file

@ -93,6 +93,7 @@ pub enum Token {
Quote, Quote,
Unquote, Unquote,
Identifier(String), Identifier(String),
Index(String, String),
String(String), String(String),
Integer(i32), Integer(i32),
Float(f32) Float(f32)
@ -132,6 +133,9 @@ pub struct Tokenizer {
is_float: bool, is_float: bool,
reading_identifier: bool, reading_identifier: bool,
is_index: bool,
indexing: Option<String>,
skipping_comment: bool, skipping_comment: bool,
storage: Vec<char>, storage: Vec<char>,
@ -151,6 +155,9 @@ impl Tokenizer {
escape_next_char: false, escape_next_char: false,
reading_identifier: false, reading_identifier: false,
is_index: false,
indexing: None,
skipping_comment: false, skipping_comment: false,
storage: Vec::new() storage: Vec::new()
@ -164,10 +171,10 @@ impl Tokenizer {
let line = self.line; let line = self.line;
let column = self.column; let column = self.column;
self.line += 1; self.column += 1;
if char == '\n' { if char == '\n' {
self.column += 1; self.line += 1;
self.line = 1; self.column = 1;
} }
if self.skipping_comment { if self.skipping_comment {
@ -182,12 +189,28 @@ impl Tokenizer {
if self.reading_identifier { if self.reading_identifier {
if char.is_alphabetic() { if char.is_alphabetic() {
self.storage.push(char); self.storage.push(char);
} else { continue;
self.reading_identifier = false; } else if char == '.' {
self.is_index = true;
tokens.push(Token::Identifier(self.storage.iter().collect())); self.indexing = Some(self.storage.iter().collect());
self.storage.clear(); 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 { if self.reading_num {