Added maps and map indexing syntax
This commit is contained in:
parent
43a6e4c1fd
commit
bc32c26164
5 changed files with 108 additions and 31 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
|
|
@ -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")
|
|
@ -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 {
|
||||
|
|
Reference in a new issue