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),
|
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,7 +569,7 @@ 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() {
|
||||||
|
@ -556,7 +580,6 @@ impl LispState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if quoted {
|
if quoted {
|
||||||
return Ok((list.to_vec(), false));
|
return Ok((list.to_vec(), false));
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
},
|
},
|
||||||
|
|
|
@ -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")
|
|
|
@ -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;
|
|
||||||
if char == '\n' {
|
|
||||||
self.column += 1;
|
self.column += 1;
|
||||||
self.line = 1;
|
if char == '\n' {
|
||||||
|
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;
|
||||||
|
} else if char == '.' {
|
||||||
|
self.is_index = true;
|
||||||
|
self.indexing = Some(self.storage.iter().collect());
|
||||||
|
self.storage.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
self.reading_identifier = false;
|
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.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 {
|
||||||
|
|
Reference in a new issue