mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
@@ -72,6 +72,7 @@ pub enum Statement {
|
||||
},
|
||||
ClassDef {
|
||||
name: String,
|
||||
body: Vec<Statement>,
|
||||
// TODO: docstring: String,
|
||||
},
|
||||
FunctionDef {
|
||||
|
||||
@@ -190,4 +190,22 @@ mod tests {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_class() {
|
||||
let source = String::from("class Foo:\n def __init__(self):\n pass\n");
|
||||
assert_eq!(
|
||||
parse_statement(&source),
|
||||
Ok(ast::Statement::ClassDef {
|
||||
name: String::from("Foo"),
|
||||
body: vec![
|
||||
ast::Statement::FunctionDef {
|
||||
name: String::from("__init__"),
|
||||
args: vec![String::from("self")],
|
||||
body: vec![ast::Statement::Pass],
|
||||
}
|
||||
],
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,9 @@ TypedArgsList: Vec<String> = {
|
||||
};
|
||||
|
||||
ClassDef: ast::Statement = {
|
||||
"class" <n:Identifier> <_a:("(" ")")?> ":" <_s:Suite> => ast::Statement::ClassDef { name: n },
|
||||
"class" <n:Identifier> <_a:("(" ")")?> ":" <s:Suite> => ast::Statement::ClassDef {
|
||||
name: n,
|
||||
body: s},
|
||||
};
|
||||
|
||||
Test: ast::Expression = {
|
||||
|
||||
14
tests/snippets/class.py
Normal file
14
tests/snippets/class.py
Normal file
@@ -0,0 +1,14 @@
|
||||
class Foo:
|
||||
print("Defining class")
|
||||
def __init__(self):
|
||||
print("initing: ", self)
|
||||
self.x = 5
|
||||
|
||||
y = 7
|
||||
|
||||
print("Done defining: ", Foo)
|
||||
print("Init: ", Foo.__init__)
|
||||
print("y = ", Foo.y)
|
||||
foo = Foo()
|
||||
print("Done initting: ", foo)
|
||||
print("Foo's x: ", foo.x)
|
||||
@@ -269,3 +269,15 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
|
||||
obj
|
||||
}
|
||||
|
||||
pub fn builtin_build_class_(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let function = args.args[0].clone();
|
||||
let a1 = &*args.args[1].borrow();
|
||||
let name = match &a1.kind {
|
||||
PyObjectKind::String { value: name } => name,
|
||||
_ => panic!("Class name must be a string."),
|
||||
};
|
||||
|
||||
let new_dict = vm.new_dict();
|
||||
&vm.invoke(function, PyFuncArgs { args: vec![ new_dict.clone() ] });
|
||||
Ok(vm.new_class(name.to_string(), new_dict))
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ pub enum Instruction {
|
||||
LoadName { name: String },
|
||||
StoreName { name: String },
|
||||
StoreSubscript,
|
||||
StoreAttr { name: String },
|
||||
LoadConst { value: Constant },
|
||||
UnaryOperation { op: UnaryOperator },
|
||||
BinaryOperation { op: BinaryOperator },
|
||||
@@ -64,6 +65,8 @@ pub enum Instruction {
|
||||
BuildMap { size: usize },
|
||||
BuildSlice { size: usize },
|
||||
PrintExpr,
|
||||
LoadBuildClass,
|
||||
StoreLocals,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -229,8 +229,41 @@ impl Compiler {
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
ast::Statement::ClassDef { name } => {
|
||||
// TODO?
|
||||
ast::Statement::ClassDef { name, body } => {
|
||||
self.emit(Instruction::LoadBuildClass);
|
||||
self.code_object_stack.push(
|
||||
CodeObject::new(vec![String::from("__locals__")]));
|
||||
self.emit(Instruction::LoadName {
|
||||
name: String::from("__locals__")});
|
||||
self.emit(Instruction::StoreLocals);
|
||||
self.compile_statements(body);
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::None,
|
||||
});
|
||||
self.emit(Instruction::ReturnValue);
|
||||
|
||||
let code = self.code_object_stack.pop().unwrap();
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Code { code: code },
|
||||
});
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::String {
|
||||
value: name.clone(),
|
||||
},
|
||||
});
|
||||
// Turn code object into function object:
|
||||
self.emit(Instruction::MakeFunction);
|
||||
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::String {
|
||||
value: name.clone(),
|
||||
},
|
||||
});
|
||||
self.emit(Instruction::CallFunction { count: 2 });
|
||||
|
||||
self.emit(Instruction::StoreName {
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
ast::Statement::Assert { test, msg } => {
|
||||
// TODO: if some flag, ignore all assert statements!
|
||||
@@ -318,8 +351,14 @@ impl Compiler {
|
||||
self.compile_expression(b);
|
||||
self.emit(Instruction::StoreSubscript);
|
||||
}
|
||||
ast::Expression::Attribute { value, name } => {
|
||||
self.compile_expression(value);
|
||||
self.emit(Instruction::StoreAttr {
|
||||
name: name.to_string()
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
panic!("WTF");
|
||||
panic!("WTF: {:?}", target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn create_type(type_type: PyObjectRef) -> PyObjectRef {
|
||||
let typ = PyObject::new(
|
||||
PyObjectKind::Class {
|
||||
name: "int".to_string(),
|
||||
// dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone() ),
|
||||
dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone() ),
|
||||
},
|
||||
type_type.clone(),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// use std::rc::Rc;
|
||||
// use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/*
|
||||
* The magical type type
|
||||
@@ -9,11 +8,14 @@ use super::pyobject::{PyObject, PyObjectKind, PyObjectRef};
|
||||
|
||||
pub fn create_type() -> PyObjectRef {
|
||||
let typ = PyObject::default().into_ref();
|
||||
let dict = PyObject::new(
|
||||
PyObjectKind::Dict {
|
||||
elements: HashMap::new(),
|
||||
}, typ.clone());
|
||||
(*typ.borrow_mut()).kind = PyObjectKind::Class {
|
||||
name: "type".to_string(),
|
||||
// dict: dict,
|
||||
};
|
||||
name: String::from("type"),
|
||||
dict: dict,
|
||||
};
|
||||
(*typ.borrow_mut()).typ = Some(typ.clone());
|
||||
// typ.borrow_mut().dict.insert("__str__".to_string(), PyObject::new(PyObjectKind::RustFunction { function: str }));
|
||||
typ
|
||||
}
|
||||
|
||||
@@ -141,8 +141,11 @@ impl PyContext {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_class(&self, name: String) -> PyObjectRef {
|
||||
PyObject::new(PyObjectKind::Class { name: name }, self.type_type.clone())
|
||||
pub fn new_class(&self, name: String, namespace: PyObjectRef) -> PyObjectRef {
|
||||
PyObject::new(PyObjectKind::Class {
|
||||
name: name,
|
||||
dict: namespace.clone()
|
||||
}, self.type_type.clone())
|
||||
}
|
||||
|
||||
/* TODO: something like this?
|
||||
@@ -205,6 +208,30 @@ impl ParentProtocol for PyObjectRef {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AttributeProtocol {
|
||||
fn get_attr(&self, attr_name: &String) -> PyObjectRef;
|
||||
fn set_attr(&self, attr_name: &String, value: PyObjectRef);
|
||||
}
|
||||
|
||||
impl AttributeProtocol for PyObjectRef {
|
||||
fn get_attr(&self, attr_name: &String) -> PyObjectRef {
|
||||
match self.borrow().kind {
|
||||
PyObjectKind::Module { name: _, ref dict } => dict.get_item(attr_name),
|
||||
PyObjectKind::Class { name: _, ref dict } => dict.get_item(attr_name),
|
||||
PyObjectKind::Instance { ref dict } => dict.get_item(attr_name),
|
||||
ref kind => unimplemented!("load_attr unimplemented for: {:?}", kind),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_attr(&self, attr_name: &String, value: PyObjectRef) {
|
||||
match self.borrow_mut().kind {
|
||||
PyObjectKind::Instance { ref mut dict } =>
|
||||
dict.set_item(attr_name, value),
|
||||
ref kind => unimplemented!("load_attr unimplemented for: {:?}", kind),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DictProtocol {
|
||||
fn contains_key(&self, k: &String) -> bool;
|
||||
fn get_item(&self, k: &String) -> PyObjectRef;
|
||||
@@ -312,7 +339,10 @@ pub enum PyObjectKind {
|
||||
None,
|
||||
Class {
|
||||
name: String,
|
||||
// dict: PyObjectRef,
|
||||
dict: PyObjectRef,
|
||||
},
|
||||
Instance {
|
||||
dict: PyObjectRef
|
||||
},
|
||||
RustFunction {
|
||||
function: RustPyFunc,
|
||||
@@ -337,7 +367,8 @@ impl fmt::Debug for PyObjectKind {
|
||||
&PyObjectKind::Module { name: _, dict: _ } => write!(f, "module"),
|
||||
&PyObjectKind::Scope { scope: _ } => write!(f, "scope"),
|
||||
&PyObjectKind::None => write!(f, "None"),
|
||||
&PyObjectKind::Class { name: _ } => write!(f, "class"),
|
||||
&PyObjectKind::Class { name: _, dict: _ } => write!(f, "class"),
|
||||
&PyObjectKind::Instance { dict: _ } => write!(f, "instance"),
|
||||
&PyObjectKind::RustFunction { function: _ } => write!(f, "rust function"),
|
||||
}
|
||||
}
|
||||
@@ -396,7 +427,10 @@ impl PyObject {
|
||||
.join(", ")
|
||||
),
|
||||
PyObjectKind::None => String::from("None"),
|
||||
PyObjectKind::Class { ref name } => format!("<class '{}'>", name),
|
||||
PyObjectKind::Class { ref name, dict: ref _dict } =>
|
||||
format!("<class '{}'>", name),
|
||||
PyObjectKind::Instance { dict: _ } =>
|
||||
format!("<instance>"),
|
||||
PyObjectKind::Code { code: _ } => format!("<code>"),
|
||||
PyObjectKind::Function { code: _, scope: _ } => format!("<func>"),
|
||||
PyObjectKind::RustFunction { function: _ } => format!("<rustfunc>"),
|
||||
|
||||
72
vm/src/vm.rs
72
vm/src/vm.rs
@@ -14,11 +14,20 @@ use super::frame::{Block, Frame, copy_code};
|
||||
use super::import::import;
|
||||
use super::objlist;
|
||||
use super::objstr;
|
||||
use super::objtype;
|
||||
use super::pyobject::{
|
||||
DictProtocol, IdProtocol, ParentProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind,
|
||||
PyObjectRef, PyResult,
|
||||
AttributeProtocol,
|
||||
DictProtocol,
|
||||
IdProtocol,
|
||||
ParentProtocol,
|
||||
PyContext,
|
||||
PyFuncArgs,
|
||||
PyObject,
|
||||
PyObjectKind,
|
||||
PyObjectRef,
|
||||
PyResult,
|
||||
Scope,
|
||||
};
|
||||
|
||||
use super::sysmodule;
|
||||
|
||||
// use objects::objects;
|
||||
@@ -57,10 +66,19 @@ impl VirtualMachine {
|
||||
self.ctx.new_dict()
|
||||
}
|
||||
|
||||
pub fn new_class(&self, name: String, namespace: PyObjectRef) -> PyObjectRef {
|
||||
self.ctx.new_class(name, namespace)
|
||||
}
|
||||
|
||||
pub fn new_exception(&self, msg: String) -> PyObjectRef {
|
||||
self.new_str(msg)
|
||||
}
|
||||
|
||||
pub fn new_scope(&mut self) -> PyObjectRef {
|
||||
let parent_scope = self.current_frame().locals.clone();
|
||||
self.ctx.new_scope(Some(parent_scope))
|
||||
}
|
||||
|
||||
pub fn get_none(&self) -> PyObjectRef {
|
||||
// TODO
|
||||
self.ctx.new_bool(false)
|
||||
@@ -460,11 +478,16 @@ impl VirtualMachine {
|
||||
|
||||
fn new_instance(&mut self, type_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
// more or less __new__ operator
|
||||
let obj = PyObject::new(PyObjectKind::None, type_ref.clone());
|
||||
let dict = self.new_dict();
|
||||
let obj = PyObject::new(PyObjectKind::Instance{dict: dict}, type_ref.clone());
|
||||
let init = type_ref.get_attr(&String::from("__init__"));
|
||||
let mut self_args = PyFuncArgs { args: args.args };
|
||||
self_args.args.insert(0, obj.clone());
|
||||
self.invoke(init, self_args).unwrap();
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
fn invoke(&mut self, func_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
pub fn invoke(&mut self, func_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
let f = func_ref.borrow();
|
||||
|
||||
match f.kind {
|
||||
@@ -478,7 +501,8 @@ impl VirtualMachine {
|
||||
let frame = Frame::new(code.clone(), scope);
|
||||
self.run_frame(frame)
|
||||
}
|
||||
PyObjectKind::Class { name: _ } => self.new_instance(func_ref.clone(), args),
|
||||
PyObjectKind::Class { name: _, dict: _ } =>
|
||||
self.new_instance(func_ref.clone(), args),
|
||||
ref kind => {
|
||||
unimplemented!("invoke unimplemented for: {:?}", kind);
|
||||
}
|
||||
@@ -498,15 +522,18 @@ impl VirtualMachine {
|
||||
|
||||
fn load_attr(&mut self, attr_name: &String) -> Option<PyResult> {
|
||||
let parent = self.pop_value();
|
||||
// Lookup name in obj
|
||||
let obj = match parent.borrow().kind {
|
||||
PyObjectKind::Module { name: _, ref dict } => dict.get_item(attr_name),
|
||||
ref kind => unimplemented!("load_attr unimplemented for: {:?}", kind),
|
||||
};
|
||||
let obj = parent.get_attr(attr_name);
|
||||
self.push_value(obj);
|
||||
None
|
||||
}
|
||||
|
||||
fn store_attr(&mut self, attr_name: &String) -> Option<PyResult> {
|
||||
let parent = self.pop_value();
|
||||
let value = self.pop_value();
|
||||
parent.set_attr(attr_name, value);
|
||||
None
|
||||
}
|
||||
|
||||
// Execute a single instruction:
|
||||
fn execute_instruction(&mut self) -> Option<PyResult> {
|
||||
let instruction = self.current_frame().fetch_instruction();
|
||||
@@ -609,6 +636,7 @@ impl VirtualMachine {
|
||||
}
|
||||
bytecode::Instruction::BinaryOperation { ref op } => self.execute_binop(op),
|
||||
bytecode::Instruction::LoadAttr { ref name } => self.load_attr(name),
|
||||
bytecode::Instruction::StoreAttr { ref name } => self.store_attr(name),
|
||||
bytecode::Instruction::UnaryOperation { ref op } => self.execute_unop(op),
|
||||
bytecode::Instruction::CompareOperation { ref op } => self.execute_compare(op),
|
||||
bytecode::Instruction::ReturnValue => {
|
||||
@@ -770,6 +798,28 @@ impl VirtualMachine {
|
||||
}
|
||||
None
|
||||
}
|
||||
bytecode::Instruction::LoadBuildClass => {
|
||||
let rustfunc = PyObject::new(
|
||||
PyObjectKind::RustFunction {
|
||||
function: builtins::builtin_build_class_
|
||||
},
|
||||
objtype::create_type()
|
||||
);
|
||||
self.push_value(rustfunc);
|
||||
None
|
||||
}
|
||||
bytecode::Instruction::StoreLocals => {
|
||||
let locals = self.pop_value();
|
||||
let ref mut frame = self.current_frame();
|
||||
match frame.locals.borrow_mut().kind {
|
||||
PyObjectKind::Scope { ref mut scope } => {
|
||||
scope.locals = locals;
|
||||
}
|
||||
_ =>
|
||||
panic!("We really expect our scope to be a scope!")
|
||||
}
|
||||
None
|
||||
},
|
||||
_ => panic!("NOT IMPL {:?}", instruction),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user