diff --git a/tests/snippets/fizzbuzz.py b/tests/snippets/fizzbuzz.py new file mode 100644 index 000000000..7aafda0a8 --- /dev/null +++ b/tests/snippets/fizzbuzz.py @@ -0,0 +1,14 @@ +def fizzbuzz(n): + if n % 3 == 0 and n % 5 == 0: + return "FizzBuzz" + elif n % 3 == 0: + return "Fizz" + elif n % 5 == 0: + return "Buzz" + else: + return str(n) + +n = 1 +while n < 10: + print(fizzbuzz(n)) + n += 1 diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 8d145db73..6ad54292c 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -33,34 +33,27 @@ fn dir_object(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyObjectRef { d } -pub fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - if args.args.is_empty() { - Ok(dir_locals(vm)) - } else { - let obj = args.args.into_iter().next().unwrap(); - Ok(dir_object(vm, obj)) - } +// builtin_abs + +fn builtin_all(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + Ok(vm.new_bool(args.args.into_iter().all(|e| objbool::boolval(e)))) } -pub fn builtin_id(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - if args.args.len() != 1 { - return Err(vm.new_exception("Expected only one argument".to_string())) - } - - Ok(vm.context().new_int(args.args[0].get_id() as i32)) +fn builtin_any(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + Ok(vm.new_bool(args.args.into_iter().any(|e| objbool::boolval(e)))) } -pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - trace!("print called with {:?}", args); - for a in args.args { - print!("{} ", a.borrow().str()); - } - println!(); - io::stdout().flush().unwrap(); - Ok(vm.get_none()) -} +// builtin_ascii +// builtin_bin +// builtin_bool +// builtin_breakpoint +// builtin_bytearray +// builtin_bytes +// builtin_callable +// builtin_chr +// builtin_classmethod -pub fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { +fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if args.args.len() < 1 { return Err(vm.new_exception("Expected more arguments".to_string())) } @@ -74,7 +67,23 @@ pub fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } -pub fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { +// builtin_complex +// builtin_delattr +// builtin_dict + +fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + if args.args.is_empty() { + Ok(dir_locals(vm)) + } else { + let obj = args.args.into_iter().next().unwrap(); + Ok(dir_object(vm, obj)) + } +} + +// builtin_divmod +// builtin_enumerate + +fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let args = args.args; if args.len() > 3 { return Err(vm.new_exception("Expected at maximum of 3 arguments".to_string())) @@ -100,11 +109,33 @@ pub fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { vm.run_code_obj(code_obj, scope) } -pub fn builtin_locals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - Ok(vm.get_locals()) +// builtin_exec +// builtin_filter +// builtin_float +// builtin_format +// builtin_frozenset +// builtin_getattr +// builtin_globals +// builtin_hasattr +// builtin_hash +// builtin_help +// builtin_hex + +fn builtin_id(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + if args.args.len() != 1 { + return Err(vm.new_exception("Expected only one argument".to_string())) + } + + Ok(vm.context().new_int(args.args[0].get_id() as i32)) } -pub fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { +// builtin_input +// builtin_int +// builtin_isinstance +// builtin_issubclass +// builtin_iter + +fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if args.args.len() != 1 { panic!("len(s) expects exactly one parameter"); } @@ -120,7 +151,37 @@ pub fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.context().new_int(len as i32)) } -pub fn builtin_range(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { +// builtin_list + +fn builtin_locals(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + Ok(vm.get_locals()) +} + + +pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + trace!("print called with {:?}", args); + for a in args.args { + print!("{} ", a.borrow().str()); + } + println!(); + io::stdout().flush().unwrap(); + Ok(vm.get_none()) +} + +// builtin_map +// builtin_max +// builtin_memoryview +// builtin_min +// builtin_next +// builtin_object +// builtin_oct +// builtin_open +// builtin_ord +// builtin_pow +// builtin_print +// builtin_property + +fn builtin_range(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if args.args.len() != 1 { unimplemented!("only the single-parameter range is implemented"); } @@ -134,21 +195,56 @@ pub fn builtin_range(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } +// builtin_repr +// builtin_reversed +// builtin_round +// builtin_set +// builtin_setattr +// builtin_slice +// builtin_sorted +// builtin_staticmethod + +// TODO: should with following format +// class str(object='') +// class str(object=b'', encoding='utf-8', errors='strict') +fn builtin_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + if args.args.len() != 1 { + panic!("str expects exactly one parameter"); + }; + let s = match args.args[0].borrow().kind { + PyObjectKind::Integer { ref value } => args.args[0].borrow().str(), + PyObjectKind::String { ref value } => args.args[0].borrow().str(), + _ => { + return Err(vm.context() + .new_str("TypeError: object of this type cannot be converted to str".to_string())) + }, + }; + Ok(vm.new_str(s)) +} +// builtin_sum +// builtin_super +// builtin_tuple +// builtin_type +// builtin_vars +// builtin_zip +// builtin___import__ + pub fn make_module(ctx: &PyContext) -> PyObjectRef { // scope[String::from("print")] = print; let mut dict = HashMap::new(); - dict.insert(String::from("id"), ctx.new_rustfunc(builtin_id)); - dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print)); - dict.insert(String::from("type"), ctx.type_type.clone()); - dict.insert(String::from("int"), ctx.int_type.clone()); dict.insert(String::from("all"), ctx.new_rustfunc(builtin_all)); dict.insert(String::from("any"), ctx.new_rustfunc(builtin_any)); - dict.insert(String::from("dir"), ctx.new_rustfunc(builtin_dir)); - dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals)); dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile)); + dict.insert(String::from("dir"), ctx.new_rustfunc(builtin_dir)); dict.insert(String::from("eval"), ctx.new_rustfunc(builtin_eval)); + dict.insert(String::from("id"), ctx.new_rustfunc(builtin_id)); + dict.insert(String::from("int"), ctx.int_type.clone()); + dict.insert(String::from("len"), ctx.new_rustfunc(builtin_len)); + dict.insert(String::from("locals"), ctx.new_rustfunc(builtin_locals)); + dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print)); dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range)); - dict.insert("len".to_string(), ctx.new_rustfunc(builtin_len)); + dict.insert(String::from("str"), ctx.new_rustfunc(builtin_str)); + dict.insert(String::from("type"), ctx.type_type.clone()); let d2 = PyObject::new(PyObjectKind::Dict { elements: dict }, ctx.type_type.clone()); let scope = PyObject::new(PyObjectKind::Scope { scope: Scope { locals: d2, parent: None} }, ctx.type_type.clone()); let obj = PyObject::new( @@ -161,10 +257,3 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { obj } -fn builtin_any(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - Ok(vm.new_bool(args.args.into_iter().any(|e| objbool::boolval(e)))) -} - -fn builtin_all(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - Ok(vm.new_bool(args.args.into_iter().all(|e| objbool::boolval(e)))) -} diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 2e6a72420..cfcd8d20d 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -5,7 +5,7 @@ use std::cell::RefCell; use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; -use std::ops::{Add, Div, Mul, Sub}; +use std::ops::{Add, Div, Mul, Sub, Rem}; use std::rc::Rc; use super::vm::VirtualMachine; @@ -549,6 +549,23 @@ impl<'a> Div<&'a PyObject> for &'a PyObject { } } +impl<'a> Rem<&'a PyObject> for &'a PyObject { + type Output = PyObjectKind; + + fn rem(self, rhs: &'a PyObject) -> Self::Output { + match (&self.kind, &rhs.kind) { + (PyObjectKind::Integer { value: value1 }, PyObjectKind::Integer { value: value2 }) => { + PyObjectKind::Integer { + value: value1 % value2, + } + } + (kind1, kind2) => { + unimplemented!("% not implemented for kinds: {:?} {:?}", kind1, kind2); + } + } + } +} + // impl<'a> PartialEq<&'a PyObject> for &'a PyObject { impl PartialEq for PyObject { fn eq(&self, other: &PyObject) -> bool { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 0d45e22eb..6fef03048 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -303,6 +303,12 @@ impl VirtualMachine { } } + fn _modulo(&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(); @@ -315,6 +321,7 @@ impl VirtualMachine { &bytecode::BinaryOperator::Power => self._pow(a_ref, b_ref), &bytecode::BinaryOperator::Divide => self._div(a_ref, b_ref), &bytecode::BinaryOperator::Subscript => self.subscript(a_ref, b_ref), + &bytecode::BinaryOperator::Modulo => self._modulo(a_ref, b_ref), _ => panic!("NOT IMPL {:?}", op), }; match result {