diff --git a/parser/src/ast.rs b/parser/src/ast.rs index ee85faa90..b4757271e 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -124,6 +124,9 @@ pub enum Expression { Tuple { elements: Vec, }, + Dict { + elements: Vec<(Expression, Expression)>, + }, Slice { elements: Vec, }, diff --git a/parser/src/python.lalrpop b/parser/src/python.lalrpop index 3105f77f2..fd4d7bdc5 100644 --- a/parser/src/python.lalrpop +++ b/parser/src/python.lalrpop @@ -323,11 +323,24 @@ Atom: ast::Expression = { } } }, + "{" "}" => ast::Expression::Dict { elements: e.unwrap_or(Vec::new()) }, "True" => ast::Expression::True, "False" => ast::Expression::False, "None" => ast::Expression::None, }; +TestDict: Vec<(ast::Expression, ast::Expression)> = { + => { + let mut d = vec![e1]; + d.extend(e2.into_iter().map(|x| x.1)); + d + } +}; + +DictEntry: (ast::Expression, ast::Expression) = { + ":" => (e1, e2), +}; + ExpressionList: Vec = { > => e, }; @@ -385,6 +398,8 @@ extern { ")" => lexer::Tok::Rpar, "[" => lexer::Tok::Lsqb, "]" => lexer::Tok::Rsqb, + "{" => lexer::Tok::Lbrace, + "}" => lexer::Tok::Rbrace, "=" => lexer::Tok::Equal, "+=" => lexer::Tok::PlusEqual, "-=" => lexer::Tok::MinusEqual, diff --git a/tests/snippets/builtin_dict.py b/tests/snippets/builtin_dict.py index 8fe70d51a..d401aabca 100644 --- a/tests/snippets/builtin_dict.py +++ b/tests/snippets/builtin_dict.py @@ -1 +1,6 @@ assert len(dict()) == 0 + +assert len({}) == 0 +assert len({"a": "b"}) == 1 +assert len({"a": "b", "b": 1}) == 2 +assert len({"a": "b", "b": 1, "a" + "b": 2*2}) == 3 diff --git a/vm/src/compile.rs b/vm/src/compile.rs index b4af32964..9162f9fab 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -465,6 +465,14 @@ impl Compiler { } self.emit(Instruction::BuildTuple { size: size }); } + ast::Expression::Dict { elements } => { + let size = elements.len(); + for (key, value) in elements { + self.compile_expression(key); + self.compile_expression(value); + } + self.emit(Instruction::BuildMap { size: size }); + } ast::Expression::Slice { elements } => { let size = elements.len(); for element in elements { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 3b11cbdd9..98dd1dffa 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -5,6 +5,7 @@ */ use std::cell::RefMut; +use std::collections::hash_map::HashMap; use std::ops::Deref; use super::builtins; @@ -562,15 +563,25 @@ impl VirtualMachine { None } bytecode::Instruction::BuildMap { size } => { - let mut elements = Vec::new(); + let mut elements = HashMap::new(); for _x in 0..*size { - let key = self.pop_value(); let obj = self.pop_value(); - elements.push((key, obj)); + // XXX: Currently, we only support String keys, so we have to unwrap the + // PyObject (and ensure it is a String). + let key_pyobj = self.pop_value(); + let key = match key_pyobj.borrow().kind { + PyObjectKind::String { ref value } => value.clone(), + ref kind => unimplemented!( + "Only strings can be used as dict keys, we saw: {:?}", + kind + ), + }; + elements.insert(key, obj); } - panic!("To be implemented!") - //let list_obj = PyObject::Tuple { elements: elements }.into_ref(); - //frame.stack.push(list_obj); + let map_obj = + PyObject::new(PyObjectKind::Dict { elements: elements }, self.get_type()); + self.push_value(map_obj); + None } bytecode::Instruction::BuildSlice { size } => { assert!(*size == 2 || *size == 3);