diff --git a/readme.md b/readme.md index a555d29..5b0cb3d 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,5 @@ # Monkey Interpreter This project is my attempt at writing an interpreter while working through the book, [Writing an Interpreter in Go](https://interpreterbook.com/). -It supports all the features from the book. + +This language supports integers, strings, hashtables, functions, closures, arrays, if/else and more! diff --git a/src/evaluator/builtins.rs b/src/evaluator/builtins.rs index e0415a7..e4ed7dd 100644 --- a/src/evaluator/builtins.rs +++ b/src/evaluator/builtins.rs @@ -19,6 +19,7 @@ pub const BUILTINS: LazyCell> = LazyCell::new(|| { match &args[0] { Object::String(s) => Object::Integer(s.len() as i64), Object::Array(s) => Object::Integer(s.elements.len() as i64), + Object::Hash(h) => Object::Integer(h.pairs.len() as i64), v => Object::Error(format!("argument to `len` not supported, got {}", v)), } }), @@ -110,5 +111,17 @@ pub const BUILTINS: LazyCell> = LazyCell::new(|| { }), }), ); + + map.insert( + "puts", + Object::Builtin(BuiltinFunction { + func: Box::new(|args: Vec| { + for arg in args { + println!("{}", arg.inspect()); + } + Object::Null + }), + }), + ); map }); diff --git a/src/evaluator/mod.rs b/src/evaluator/mod.rs index 3ad277e..7572dd2 100644 --- a/src/evaluator/mod.rs +++ b/src/evaluator/mod.rs @@ -517,6 +517,7 @@ mod tests { elements: vec![Object::Integer(1), Object::Integer(5)], })), ), + ("len({\"foo\": \"bar\"})", Some(Object::Integer(1))), ]; run_test_cases(&test_cases); diff --git a/src/evaluator/tree_walker.rs b/src/evaluator/tree_walker.rs index beab588..d1cc680 100644 --- a/src/evaluator/tree_walker.rs +++ b/src/evaluator/tree_walker.rs @@ -318,10 +318,14 @@ impl TreeWalker { } fn eval_hash_index_expression(&self, left: &HashObject, index: Object) -> Option { - Some(Object::Error(format!( - "index operator not supported: {:?}", - left - ))) + if let Object::Function(_) = index { + return Some(Object::Error(format!("unusable as hash key: {}", index))); + } + + match left.pairs.get(&index) { + Some(v) => Some(v.clone()), + None => Some(Object::Null), + } } fn eval_array_index_expression(array: &Array, index: i64) -> Object { let max = array.elements.len() as i64;