diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 8b7570b95..642230981 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -644,14 +644,10 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { let function = args.shift(); let name_arg = args.shift(); - let name_arg_ref = name_arg.borrow(); - let name = match name_arg_ref.kind { - PyObjectKind::String { ref value } => value, - _ => panic!("Class name must by a string!"), - }; let mut bases = args.args.clone(); + let metaclass = args.get_kwarg("metaclass", vm.get_type()); + bases.push(vm.context().object()); - let metaclass = vm.get_type(); let namespace = vm.new_dict(); &vm.invoke( function, @@ -660,5 +656,8 @@ pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> Py kwargs: vec![], }, ); - objtype::new(metaclass, name, bases, namespace) + + let bases = vm.context().new_tuple(bases); + + vm.call_method(&metaclass, "__new__", vec![name_arg, bases, namespace]) } diff --git a/vm/src/compile.rs b/vm/src/compile.rs index 132438fa3..c72a8ad29 100644 --- a/vm/src/compile.rs +++ b/vm/src/compile.rs @@ -436,7 +436,7 @@ impl Compiler { name, body, bases, - keywords: _, + keywords, decorator_list, } => { self.prepare_decorators(decorator_list)?; @@ -483,9 +483,34 @@ impl Compiler { for base in bases { self.compile_expression(base)?; } - self.emit(Instruction::CallFunction { - typ: CallType::Positional(2 + bases.len()), - }); + + if keywords.len() > 0 { + let mut kwarg_names = vec![]; + for keyword in keywords { + if let Some(name) = &keyword.name { + kwarg_names.push(bytecode::Constant::String { + value: name.to_string(), + }); + } else { + // This means **kwargs! + panic!("name must be set"); + } + self.compile_expression(&keyword.value)?; + } + + self.emit(Instruction::LoadConst { + value: bytecode::Constant::Tuple { + elements: kwarg_names, + }, + }); + self.emit(Instruction::CallFunction { + typ: CallType::Keyword(2 + keywords.len() + bases.len()), + }); + } else { + self.emit(Instruction::CallFunction { + typ: CallType::Positional(2 + bases.len()), + }); + } self.apply_decorators(decorator_list); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 42f350605..4dd2b7e05 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -634,6 +634,15 @@ impl PyFuncArgs { pub fn shift(&mut self) -> PyObjectRef { self.args.remove(0) } + + pub fn get_kwarg(&self, key: &str, default: PyObjectRef) -> PyObjectRef { + for (arg_name, arg_value) in self.kwargs.iter() { + if arg_name == key { + return arg_value.clone(); + } + } + default.clone() + } } type RustPyFunc = fn(vm: &mut VirtualMachine, PyFuncArgs) -> PyResult;