diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 4d0b00b0c..d8d4212db 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -153,4 +153,8 @@ pub enum Comparison { LessOrEqual, Greater, GreaterOrEqual, + In, + NotIn, + Is, + IsNot, } diff --git a/parser/src/python.lalrpop b/parser/src/python.lalrpop index d899fc070..9dc16f458 100644 --- a/parser/src/python.lalrpop +++ b/parser/src/python.lalrpop @@ -133,6 +133,10 @@ CompOp: ast::Comparison = { "<=" => ast::Comparison::LessOrEqual, ">" => ast::Comparison::Greater, ">=" => ast::Comparison::GreaterOrEqual, + "in" => ast::Comparison::In, + "not" "in" => ast::Comparison::NotIn, + "is" => ast::Comparison::Is, + "is" "not" => ast::Comparison::IsNot, }; Expression: ast::Expression = { @@ -280,20 +284,22 @@ extern { "<=" => lexer::Tok::LessEqual, ">" => lexer::Tok::Greater, ">=" => lexer::Tok::GreaterEqual, - "assert" => lexer::Tok::Assert, - "import" => lexer::Tok::Import, - "break" => lexer::Tok::Break, - "continue" => lexer::Tok::Break, - "return" => lexer::Tok::Return, - "pass" => lexer::Tok::Pass, - "if" => lexer::Tok::If, - "while" => lexer::Tok::While, - "for" => lexer::Tok::For, - "in" => lexer::Tok::In, - "with" => lexer::Tok::With, "as" => lexer::Tok::As, - "def" => lexer::Tok::Def, + "assert" => lexer::Tok::Assert, + "break" => lexer::Tok::Break, "class" => lexer::Tok::Class, + "continue" => lexer::Tok::Break, + "def" => lexer::Tok::Def, + "for" => lexer::Tok::For, + "if" => lexer::Tok::If, + "in" => lexer::Tok::In, + "is" => lexer::Tok::Is, + "import" => lexer::Tok::Import, + "not" => lexer::Tok::Not, + "pass" => lexer::Tok::Pass, + "return" => lexer::Tok::Return, + "while" => lexer::Tok::While, + "with" => lexer::Tok::With, "True" => lexer::Tok::True, "False" => lexer::Tok::False, "None" => lexer::Tok::None, diff --git a/src/main.rs b/src/main.rs index 0643788a5..2ac826cfe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,7 +48,7 @@ fn run_script(script_file: &String) { match parse(filepath) { Ok(program) => { debug!("Got ast: {:?}", program); - let bytecode = compile::compile(program); + let bytecode = compile::compile(program, compile::Mode::Exec); debug!("Code object: {:?}", bytecode); vm.evaluate(bytecode); } diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index a9458c2e0..b2378b2fb 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -37,7 +37,7 @@ pub fn print(args: Vec>) -> NativeType { } */ -pub fn print(rt: &mut Executor, args: Vec) -> Result { +pub fn print(rt: &mut Executor, args: Vec) -> PyResult { // println!("Woot: {:?}", args); trace!("print called with {:?}", args); for a in args { @@ -48,6 +48,16 @@ pub fn print(rt: &mut Executor, args: Vec) -> Result) -> PyResult { + // TODO + Ok(rt.new_bool(true)) +} + +pub fn locals(rt: &mut Executor, args: Vec) -> PyResult { + // TODO + Ok(rt.new_bool(true)) +} + /* * TODO pub fn len(args: Vec>) -> NativeType { @@ -66,7 +76,7 @@ pub fn len(args: Vec>) -> NativeType { pub fn make_module(ctx: &PyContext) -> PyObjectRef { // scope[String::from("print")] = print; - let obj = PyObject::new(PyObjectKind::Module, ctx.type_type.clone()); + let obj = PyObject::new(PyObjectKind::Module { name: "__builtins__".to_string() }, ctx.type_type.clone()); obj.borrow_mut().dict.insert( String::from("print"), PyObject::new(PyObjectKind::RustFunction { function: print }, ctx.type_type.clone()), diff --git a/vm/src/bytecode.rs b/vm/src/bytecode.rs index 6852a7502..cec2f496f 100644 --- a/vm/src/bytecode.rs +++ b/vm/src/bytecode.rs @@ -81,7 +81,7 @@ pub enum ComparisonOperator { In, NotIn, Is, - NotIs, + IsNot, } #[derive(Debug, Clone)] diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 766b5710f..4fbbe69a3 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -12,11 +12,16 @@ struct Compiler { nxt_label: usize, } -pub fn compile(p: ast::Program) -> CodeObject { +pub fn compile(p: ast::Program, mode: Mode) -> CodeObject { let mut compiler = Compiler::new(); compiler.compile_program(p) } +pub enum Mode { + Exec, + Eval, +} + type Label = usize; impl Compiler { @@ -279,6 +284,10 @@ impl Compiler { ast::Comparison::LessOrEqual => bytecode::ComparisonOperator::LessOrEqual, ast::Comparison::Greater => bytecode::ComparisonOperator::Greater, ast::Comparison::GreaterOrEqual => bytecode::ComparisonOperator::GreaterOrEqual, + ast::Comparison::In => bytecode::ComparisonOperator::In, + ast::Comparison::NotIn => bytecode::ComparisonOperator::NotIn, + ast::Comparison::Is => bytecode::ComparisonOperator::Is, + ast::Comparison::IsNot => bytecode::ComparisonOperator::IsNot, }; let i = Instruction::CompareOperation { op: i }; self.emit(i); diff --git a/vm/src/eval.rs b/vm/src/eval.rs index 4ab9234cc..fb33d5cb1 100644 --- a/vm/src/eval.rs +++ b/vm/src/eval.rs @@ -9,7 +9,7 @@ pub fn eval(vm: &mut VirtualMachine, source: &String) -> Result { debug!("Got ast: {:?}", program); - let bytecode = compile::compile(program); + let bytecode = compile::compile(program, compile::Mode::Eval); debug!("Code object: {:?}", bytecode); vm.evaluate(bytecode) } diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 12a19dd02..a4e3fd9ef 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -10,6 +10,7 @@ pub mod bytecode; pub mod compile; pub mod eval; mod objint; +mod objstr; mod objtype; pub mod pyobject; mod vm; diff --git a/vm/src/objint.rs b/vm/src/objint.rs index 777809e24..1096acf80 100644 --- a/vm/src/objint.rs +++ b/vm/src/objint.rs @@ -13,7 +13,7 @@ fn set_attr(a: &mut PyObjectRef, name: String, b: PyObjectRef) { */ pub fn create_type(type_type: PyObjectRef) -> PyObjectRef { - let typ = PyObject::new(PyObjectKind::Type, type_type.clone()); + let typ = PyObject::new(PyObjectKind::Class { name: "int".to_string() }, type_type.clone()); typ.borrow_mut().dict.insert( "__str__".to_string(), PyObject::new(PyObjectKind::RustFunction { function: str }, type_type.clone()), diff --git a/vm/src/objlist.rs b/vm/src/objlist.rs new file mode 100644 index 000000000..a41c50241 --- /dev/null +++ b/vm/src/objlist.rs @@ -0,0 +1,28 @@ + + +fn subscript(rt: Executor, a, b: PyObjectRef) -> PyResult { + match b.kind { + (&NativeType::List(ref l), &NativeType::Int(ref index)) => { + let pos_index = (index + l.borrow().len() as i32) % l.borrow().len() as i32; + curr_frame.stack.push(Rc::new(l.borrow()[pos_index as usize].clone())) + }, + (&NativeType::List(ref l), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => { + let start = match opt_start { + &Some(start) => ((start + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, + &None => 0, + }; + let stop = match opt_stop { + &Some(stop) => ((stop + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, + &None => l.borrow().len() as usize, + }; + let step = match opt_step { + //Some(step) => step as usize, + &None => 1 as usize, + _ => unimplemented!(), + }; + // TODO: we could potentially avoid this copy and use slice + curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(l.borrow()[start..stop].to_vec())))); + }, + } +} + diff --git a/vm/src/objstr.rs b/vm/src/objstr.rs new file mode 100644 index 000000000..7bee4d604 --- /dev/null +++ b/vm/src/objstr.rs @@ -0,0 +1,47 @@ +use super::pyobject::{PyObject, PyObjectKind, PyObjectRef, Executor, PyResult}; + +fn str_pos(s: &String, p: i32) -> usize { + if p < 0 { + s.len() - ((-p) as usize) + } else if p as usize > s.len() { + s.len() + } else { + p as usize + } +} + +pub fn subscript(rt: &mut Executor, value: &String, b: PyObjectRef) -> PyResult { + // let value = a + match &(*b.borrow()).kind { + &PyObjectKind::Integer { value: ref pos } => { + let idx = str_pos(value, *pos); + Ok(rt.new_str(value[idx..idx+1].to_string())) + }, + &PyObjectKind::Slice { + ref start, + ref stop, + ref step, + } => { + let start2: usize = match start { + // &Some(_) => panic!("Bad start index for string slicing {:?}", start), + &Some(start) => str_pos(value, start), + &None => 0, + }; + let stop2: usize = match stop { + &Some(stop) => str_pos(value, stop), + // &Some(_) => panic!("Bad stop index for string slicing"), + &None => value.len() as usize, + }; + let step2: usize = match step { + //Some(step) => step as usize, + &None => 1 as usize, + _ => unimplemented!(), + }; + Ok(rt.new_str(value[start2..stop2].to_string())) + }, + _ => panic!( + "TypeError: indexing type {:?} with index {:?} is not supported (yet?)", + value, b + ), + } +} diff --git a/vm/src/objtype.rs b/vm/src/objtype.rs index 97e67b3b2..084a5ada9 100644 --- a/vm/src/objtype.rs +++ b/vm/src/objtype.rs @@ -9,7 +9,7 @@ use super::pyobject::{PyObject, PyObjectKind, PyObjectRef}; pub fn create_type() -> PyObjectRef { let typ = PyObject::default().into_ref(); - (*typ.borrow_mut()).kind = PyObjectKind::Type; + (*typ.borrow_mut()).kind = PyObjectKind::Class { name: "type".to_string() }; (*typ.borrow_mut()).typ = Some(typ.clone()); // typ.borrow_mut().dict.insert("__str__".to_string(), PyObject::new(PyObjectKind::RustFunction { function: str })); typ diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 9e6d47608..c83d1baab 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -65,6 +65,16 @@ impl PyContext { pub fn new_bool(&self, b: bool) -> PyObjectRef { PyObject::new(PyObjectKind::Boolean { value: b }, self.type_type.clone()) } + + pub fn new_class(&self, name: String) -> PyObjectRef { + PyObject::new(PyObjectKind::Class { name: name }, self.type_type.clone()) + } + + /* TODO: something like this? + pub fn new_instance(&self, name: String) -> PyObjectRef { + PyObject::new(PyObjectKind::Class { name: name }, self.type_type.clone()) + } + */ } pub trait Executor { @@ -76,7 +86,6 @@ pub trait Executor { fn context(&self) -> &PyContext; } -#[derive(Debug)] pub struct PyObject { pub kind: PyObjectKind, pub typ: Option, @@ -93,6 +102,12 @@ impl Default for PyObject { } } +impl fmt::Debug for PyObject { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[PyObj {:?}]", self.kind) + } +} + type RustPyFunc = fn(rt: &mut Executor, Vec) -> PyResult; // #[derive(Debug)] @@ -132,9 +147,9 @@ pub enum PyObjectKind { Function { code: bytecode::CodeObject, }, - Module, + Module { name: String }, None, - Type, + Class { name: String }, RustFunction { function: RustPyFunc, }, @@ -142,7 +157,10 @@ pub enum PyObjectKind { impl fmt::Debug for PyObjectKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Some kind of python obj") + match self { + &PyObjectKind::String { ref value } => write!(f, "str[{}]", value), + _ => write!(f, "Some kind of python obj"), + } } } @@ -169,6 +187,7 @@ impl PyObject { match self.kind { PyObjectKind::String { ref value } => value.clone(), PyObjectKind::Integer { ref value } => format!("{:?}", value), + PyObjectKind::Boolean { ref value } => format!("{:?}", value), PyObjectKind::List { ref elements } => format!( "[{}]", elements @@ -186,6 +205,11 @@ impl PyObject { .join(", ") ), PyObjectKind::None => String::from("None"), + PyObjectKind::Class { ref name } => format!("", name), + PyObjectKind::Code { code: _ } => format!(""), + PyObjectKind::Function { code: _ } => format!(""), + PyObjectKind::RustFunction { function: _ } => format!(""), + PyObjectKind::Module { ref name }=> format!("", name), _ => { println!("Not impl {:?}", self); panic!("Not impl"); diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 979666570..30b3f31f9 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -15,8 +15,9 @@ use std::rc::Rc; use self::rustpython_parser::parse; use super::builtins; use super::bytecode; -use super::compile::compile; +use super::compile; use super::pyobject::{PyObject, PyObjectKind, PyObjectRef, PyResult, PyContext, Executor}; +use super::objstr; // use objects::objects; @@ -47,16 +48,6 @@ pub struct VirtualMachine { ctx: PyContext, } -fn str_pos(s: &String, p: i32) -> usize { - if p < 0 { - s.len() - ((-p) as usize) - } else if p as usize > s.len() { - s.len() - } else { - p as usize - } -} - impl Frame { pub fn new( code: Rc, @@ -165,8 +156,28 @@ impl VirtualMachine { self.current_frame().pop_multiple(count) } - fn store_name(&mut self, name: String, obj: PyObjectRef) { + fn store_name(&mut self, name: String) -> Option { + let obj = self.pop_value(); self.current_frame().locals.insert(name, obj); + None + } + + fn load_name(&mut self, name: &String) -> Option { + // Lookup name in scope and put it onto the stack! + if self.current_frame().locals.contains_key(name) { + let obj = self.current_frame().locals[name].clone(); + self.push_value(obj); + None + } else if self.builtins.borrow().dict.contains_key(name) { + let obj = self.builtins.borrow().dict[name].clone(); + self.push_value(obj); + None + } else { + let name_error = PyObject::new(PyObjectKind::NameError { + name: name.to_string(), + }, self.get_type()); + Some(Err(name_error)) + } } fn run(&mut self, code: Rc) -> PyResult { @@ -174,7 +185,6 @@ impl VirtualMachine { self.run_frame(frame).0 } - // TODO: read the op codes directly from the internal code object fn run_frame(&mut self, frame: Frame) -> (PyResult, Frame) { self.frames.push(frame); @@ -191,13 +201,6 @@ impl VirtualMachine { break Err(value); } } - /*if curr_frame.blocks.len() > 0 { - self.manage_block_stack(&why); - } - */ - //if let Some(_) = why { - // break; - //} }; let frame2 = self.pop_frame(); @@ -207,63 +210,15 @@ impl VirtualMachine { fn run_code(&mut self, code: i32) -> Result { }*/ - fn subscript(&mut self, a: &PyObject, b: &PyObject) -> PyObjectRef { + fn subscript(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { // debug!("tos: {:?}, tos1: {:?}", tos, tos1); // Subscript implementation: a[b] - match (&a.kind, &b.kind) { + let a2 = &*a.borrow(); + match &a2.kind { /* - (&NativeType::List(ref l), &NativeType::Int(ref index)) => { - let pos_index = (index + l.borrow().len() as i32) % l.borrow().len() as i32; - curr_frame.stack.push(Rc::new(l.borrow()[pos_index as usize].clone())) - }, - (&NativeType::List(ref l), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => { - let start = match opt_start { - &Some(start) => ((start + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, - &None => 0, - }; - let stop = match opt_stop { - &Some(stop) => ((stop + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, - &None => l.borrow().len() as usize, - }; - let step = match opt_step { - //Some(step) => step as usize, - &None => 1 as usize, - _ => unimplemented!(), - }; - // TODO: we could potentially avoid this copy and use slice - curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(l.borrow()[start..stop].to_vec())))); - }, (&NativeType::Tuple(ref t), &NativeType::Int(ref index)) => curr_frame.stack.push(Rc::new(t[*index as usize].clone())), - (&NativeType::Str(ref s), &NativeType::Int(ref index)) => { - let idx = (index + s.len() as i32) % s.len() as i32; - curr_frame.stack.push(Rc::new(NativeType::Str(s.chars().nth(idx as usize).unwrap().to_string()))); - }, */ - ( - PyObjectKind::String { ref value }, - PyObjectKind::Slice { - ref start, - ref stop, - ref step, - }, - ) => { - let start2: usize = match start { - // &Some(_) => panic!("Bad start index for string slicing {:?}", start), - &Some(start) => str_pos(value, start), - &None => 0, - }; - let stop2: usize = match stop { - &Some(stop) => str_pos(value, stop), - // &Some(_) => panic!("Bad stop index for string slicing"), - &None => value.len() as usize, - }; - let step2: usize = match step { - //Some(step) => step as usize, - &None => 1 as usize, - _ => unimplemented!(), - }; - self.ctx.new_str(value[start2..stop2].to_string()) - } + PyObjectKind::String { ref value } => objstr::subscript(self, value, b.clone()), // TODO: implement other Slice possibilities _ => panic!( "TypeError: indexing type {:?} with index {:?} is not supported (yet?)", @@ -272,25 +227,47 @@ impl VirtualMachine { } } - fn execute_binop(&mut self, op: &bytecode::BinaryOperator) { + fn _sub(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + let b2 = &*b.borrow(); + let a2 = &*a.borrow(); + Ok(PyObject::new(a2 - b2, self.get_type())) + } + + fn _add(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + let b2 = &*b.borrow(); + let a2 = &*a.borrow(); + Ok(PyObject::new(a2 + b2, self.get_type())) + } + + fn _mul(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + let b2 = &*b.borrow(); + let a2 = &*a.borrow(); + Ok(PyObject::new(a2 * b2, self.get_type())) + } + + fn execute_binop(&mut self, op: &bytecode::BinaryOperator) -> Option { let b_ref = self.pop_value(); let a_ref = self.pop_value(); - let b = &*b_ref.borrow(); - let a = &*a_ref.borrow(); // TODO: if the left hand side provides __add__, invoke that function. // let result = match op { - &bytecode::BinaryOperator::Subtract => PyObject::new(a - b, self.get_type()), - &bytecode::BinaryOperator::Add => PyObject::new(a + b, self.get_type()), - &bytecode::BinaryOperator::Multiply => PyObject::new(a * b, self.get_type()), + &bytecode::BinaryOperator::Subtract => self._sub(a_ref, b_ref), + &bytecode::BinaryOperator::Add => self._add(a_ref, b_ref), + &bytecode::BinaryOperator::Multiply => self._mul(a_ref, b_ref), // &bytecode::BinaryOperator::Div => a / b, - &bytecode::BinaryOperator::Subscript => self.subscript(a, b), + &bytecode::BinaryOperator::Subscript => self.subscript(a_ref, b_ref), _ => panic!("NOT IMPL {:?}", op), }; - self.push_value(result); + match result { + Ok(value) => { + self.push_value(value); + None + } + Err(value) => Some(Err(value)), + } } - fn execute_unop(&mut self, op: &bytecode::UnaryOperator) { + fn execute_unop(&mut self, op: &bytecode::UnaryOperator) -> Option { let a_ref = self.pop_value(); let a = &*a_ref.borrow(); let result = match op { @@ -299,28 +276,75 @@ impl VirtualMachine { // self.invoke('__neg__' match a.kind { PyObjectKind::Integer { value: ref value1 } => { - self.ctx.new_int(-*value1) + Ok(self.ctx.new_int(-*value1)) } _ => panic!("Not impl {:?}", a), } } _ => panic!("Not impl {:?}", op), }; - self.push_value(result); + match result { + Ok(value) => { + self.push_value(value); + None + }, + Err(value) => Some(Err(value)), + } } - fn execute_compare(&mut self, op: &bytecode::ComparisonOperator) { - let b_ref = self.pop_value(); - let a_ref = self.pop_value(); - let b = &*b_ref.borrow(); - let a = &*a_ref.borrow(); - let result_bool = match op { - &bytecode::ComparisonOperator::Equal => (a == b), - &bytecode::ComparisonOperator::NotEqual => (a != b), + fn _eq(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + let b2 = &*b.borrow(); + let a2 = &*a.borrow(); + let result_bool = a == b; + let result = self.ctx.new_bool(result_bool); + Ok(result) + } + + fn _ne(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + let b2 = &*b.borrow(); + let a2 = &*a.borrow(); + let result_bool = a != b; + let result = self.ctx.new_bool(result_bool); + Ok(result) + } + + fn _is(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + // Pointer equal: + let result_bool = true; // TODO: *a.as_ptr() == *b.as_ptr(); + let result = self.ctx.new_bool(result_bool); + Ok(result) + } + + fn _is_not(&mut self, a: PyObjectRef, b: PyObjectRef) -> PyResult { + // Pointer equal: + let result_bool = true; // TODO: *a.as_ptr() != *b.as_ptr(); + let result = self.ctx.new_bool(result_bool); + Ok(result) + } + + fn execute_compare(&mut self, op: &bytecode::ComparisonOperator) -> Option { + let b = self.pop_value(); + let a = self.pop_value(); + let result = match op { + &bytecode::ComparisonOperator::Equal => self._eq(a, b), + &bytecode::ComparisonOperator::NotEqual => self._ne(a, b), + &bytecode::ComparisonOperator::Is => self._is(a, b), + &bytecode::ComparisonOperator::IsNot => self._is_not(a, b), _ => panic!("NOT IMPL {:?}", op), }; - let result = self.ctx.new_bool(result_bool); - self.push_value(result); + match result { + Ok(value) => { + self.push_value(value); + None + }, + Err(value) => Some(Err(value)), + } + } + + fn new_instance(&mut self, type_ref: PyObjectRef, args: Vec) -> PyResult { + // more or less __new__ operator + let obj = PyObject::new(PyObjectKind::None, type_ref.clone()); + Ok(obj) } fn invoke(&mut self, func_ref: PyObjectRef, args: Vec) -> PyResult { @@ -331,7 +355,10 @@ impl VirtualMachine { PyObjectKind::Function { ref code } => { let frame = Frame::new(Rc::new(code.clone()), HashMap::new(), None); self.run_frame(frame).0 - } + }, + PyObjectKind::Class { name: _ } => { + self.new_instance(func_ref.clone(), args) + }, _ => { println!("Not impl {:?}", f); panic!("Not impl"); @@ -347,9 +374,9 @@ impl VirtualMachine { match parse(filepath) { Ok(program) => { debug!("Got ast: {:?}", program); - let bytecode = compile(program); + let bytecode = compile::compile(program, compile::Mode::Exec); debug!("Code object: {:?}", bytecode); - let obj = PyObject::new(PyObjectKind::Module, self.get_type()); + let obj = PyObject::new(PyObjectKind::Module { name: name.clone() }, self.get_type()); // As a sort of hack, create a frame and run code in it let frame = Frame::new(Rc::new(bytecode), HashMap::new(), None); @@ -372,11 +399,12 @@ impl VirtualMachine { } } - fn load_attr(&mut self, name: String) { + fn load_attr(&mut self, name: String) -> Option { let parent = self.pop_value(); // Lookup name in obj let obj = parent.borrow().dict[&name].clone(); self.push_value(obj); + None } fn fetch_instruction(&mut self) -> bytecode::Instruction { @@ -389,12 +417,20 @@ impl VirtualMachine { } // Execute a single instruction: - fn execute_instruction(&mut self) -> Option> { + fn execute_instruction(&mut self) -> Option { let instruction = self.fetch_instruction(); { - trace!("Executing op code: {:?}", instruction); - trace!(" stack:{:?}", self.current_frame().stack); + trace!("======="); + trace!( + " stack:{:?}", + self.current_frame().stack + .iter() + .map(|elem| elem.borrow_mut().str()) + .collect::>() + .join(", ") + ); trace!(" env :{:?}", self.current_frame().locals); + trace!(" Executing op code: {:?}", instruction); } match &instruction { &bytecode::Instruction::LoadConst { ref value } => { @@ -417,27 +453,11 @@ impl VirtualMachine { None } &bytecode::Instruction::LoadName { ref name } => { - // Lookup name in scope and put it onto the stack! - if self.current_frame().locals.contains_key(name) { - let obj = self.current_frame().locals[name].clone(); - self.push_value(obj); - None - } else if self.builtins.borrow().dict.contains_key(name) { - let obj = self.builtins.borrow().dict[name].clone(); - self.push_value(obj); - None - } else { - let name_error = PyObject::new(PyObjectKind::NameError { - name: name.to_string(), - }, self.get_type()); - Some(Err(name_error)) - } + self.load_name(name) } &bytecode::Instruction::StoreName { ref name } => { // take top of stack and assign in scope: - let obj = self.pop_value(); - self.store_name(name.clone(), obj); - None + self.store_name(name.clone()) } &bytecode::Instruction::Pop => { // Pop value from stack and ignore. @@ -489,20 +509,16 @@ impl VirtualMachine { None } &bytecode::Instruction::BinaryOperation { ref op } => { - self.execute_binop(op); - None + self.execute_binop(op) } &bytecode::Instruction::LoadAttr { ref name } => { - self.load_attr(name.to_string()); - None + self.load_attr(name.to_string()) } &bytecode::Instruction::UnaryOperation { ref op } => { - self.execute_unop(op); - None + self.execute_unop(op) } &bytecode::Instruction::CompareOperation { ref op } => { - self.execute_compare(op); - None + self.execute_compare(op) } &bytecode::Instruction::ReturnValue => { let value = self.pop_value();