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),
LispFunction(String, Vec<String>, Vec<LispValue>),
RustFunction(String, RustFunctionType),
Var(String)
Map(HashMap<String, LispValue>),
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,7 +569,7 @@ 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) {
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() {
@ -556,7 +580,6 @@ impl LispState {
}
}
}
}
if quoted {
return Ok((list.to_vec(), false));
@ -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<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 {
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<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> {
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 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(())
}

View file

@ -195,11 +195,18 @@ fn parse_exp(tokens: Vec<Token>, 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));
},

View file

@ -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")

View file

@ -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<String>,
skipping_comment: bool,
storage: Vec<char>,
@ -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;
if char == '\n' {
self.column += 1;
self.line = 1;
if char == '\n' {
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 {
continue;
} else if char == '.' {
self.is_index = true;
self.indexing = Some(self.storage.iter().collect());
self.storage.clear();
continue;
}
self.reading_identifier = false;
tokens.push(Token::Identifier(self.storage.iter().collect()));
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 {