mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
870 lines
26 KiB
Rust
870 lines
26 KiB
Rust
use super::bytecode;
|
|
use super::exceptions;
|
|
use super::obj::objbool;
|
|
use super::obj::objbytes;
|
|
use super::obj::objdict;
|
|
use super::obj::objfloat;
|
|
use super::obj::objfunction;
|
|
use super::obj::objint;
|
|
use super::obj::objiter;
|
|
use super::obj::objlist;
|
|
use super::obj::objobject;
|
|
use super::obj::objset;
|
|
use super::obj::objstr;
|
|
use super::obj::objtuple;
|
|
use super::obj::objtype;
|
|
use super::vm::VirtualMachine;
|
|
use std::cell::RefCell;
|
|
use std::cmp::Ordering;
|
|
use std::collections::HashMap;
|
|
use std::fmt;
|
|
use std::rc::Rc;
|
|
|
|
/* Python objects and references.
|
|
|
|
Okay, so each python object itself is an class itself (PyObject). Each
|
|
python object can have several references to it (PyObjectRef). These
|
|
references are Rc (reference counting) rust smart pointers. So when
|
|
all references are destroyed, the object itself also can be cleaned up.
|
|
Basically reference counting, but then done by rust.
|
|
|
|
*/
|
|
|
|
/*
|
|
* Good reference: https://github.com/ProgVal/pythonvm-rust/blob/master/src/objects/mod.rs
|
|
*/
|
|
|
|
/*
|
|
The PyRef type implements
|
|
https://doc.rust-lang.org/std/cell/index.html#introducing-mutability-inside-of-something-immutable
|
|
*/
|
|
pub type PyRef<T> = Rc<RefCell<T>>;
|
|
pub type PyObjectRef = PyRef<PyObject>;
|
|
pub type PyResult = Result<PyObjectRef, PyObjectRef>; // A valid value, or an exception
|
|
|
|
/*
|
|
impl fmt::Display for PyObjectRef {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "Obj {:?}", self)
|
|
}
|
|
}*/
|
|
|
|
#[derive(Debug)]
|
|
pub struct PyContext {
|
|
pub type_type: PyObjectRef,
|
|
pub none: PyObjectRef,
|
|
pub dict_type: PyObjectRef,
|
|
pub int_type: PyObjectRef,
|
|
pub float_type: PyObjectRef,
|
|
pub bytes_type: PyObjectRef,
|
|
pub bool_type: PyObjectRef,
|
|
pub true_value: PyObjectRef,
|
|
pub false_value: PyObjectRef,
|
|
pub list_type: PyObjectRef,
|
|
pub tuple_type: PyObjectRef,
|
|
pub set_type: PyObjectRef,
|
|
pub iter_type: PyObjectRef,
|
|
pub str_type: PyObjectRef,
|
|
pub function_type: PyObjectRef,
|
|
pub module_type: PyObjectRef,
|
|
pub bound_method_type: PyObjectRef,
|
|
pub member_descriptor_type: PyObjectRef,
|
|
pub object: PyObjectRef,
|
|
pub exceptions: exceptions::ExceptionZoo,
|
|
}
|
|
|
|
/*
|
|
* So a scope is a linked list of scopes.
|
|
* When a name is looked up, it is check in its scope.
|
|
*/
|
|
#[derive(Debug)]
|
|
pub struct Scope {
|
|
pub locals: PyObjectRef, // Variables
|
|
pub parent: Option<PyObjectRef>, // Parent scope
|
|
}
|
|
|
|
fn _nothing() -> PyObjectRef {
|
|
PyObject {
|
|
kind: PyObjectKind::None,
|
|
typ: None,
|
|
}
|
|
.into_ref()
|
|
}
|
|
|
|
pub fn create_type(
|
|
name: &str,
|
|
type_type: &PyObjectRef,
|
|
base: &PyObjectRef,
|
|
dict_type: &PyObjectRef,
|
|
) -> PyObjectRef {
|
|
let dict = PyObject::new(
|
|
PyObjectKind::Dict {
|
|
elements: HashMap::new(),
|
|
},
|
|
dict_type.clone(),
|
|
);
|
|
objtype::new(type_type.clone(), name, vec![base.clone()], dict).unwrap()
|
|
}
|
|
|
|
// Basic objects:
|
|
impl PyContext {
|
|
pub fn new() -> Self {
|
|
let type_type = _nothing();
|
|
let object_type = _nothing();
|
|
let dict_type = _nothing();
|
|
|
|
objtype::create_type(type_type.clone(), object_type.clone(), dict_type.clone());
|
|
objobject::create_object(type_type.clone(), object_type.clone(), dict_type.clone());
|
|
objdict::create_type(type_type.clone(), object_type.clone(), dict_type.clone());
|
|
|
|
let module_type = create_type("module", &type_type, &object_type, &dict_type);
|
|
let function_type = create_type("function", &type_type, &object_type, &dict_type);
|
|
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
|
|
let member_descriptor_type =
|
|
create_type("member_descriptor", &type_type, &object_type, &dict_type);
|
|
let str_type = create_type("str", &type_type, &object_type, &dict_type);
|
|
let list_type = create_type("list", &type_type, &object_type, &dict_type);
|
|
let set_type = create_type("set", &type_type, &object_type, &dict_type);
|
|
let int_type = create_type("int", &type_type, &object_type, &dict_type);
|
|
let float_type = create_type("float", &type_type, &object_type, &dict_type);
|
|
let bytes_type = create_type("bytes", &type_type, &object_type, &dict_type);
|
|
let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type);
|
|
let iter_type = create_type("iter", &type_type, &object_type, &dict_type);
|
|
let bool_type = create_type("bool", &type_type, &int_type, &dict_type);
|
|
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type);
|
|
|
|
let none = PyObject::new(
|
|
PyObjectKind::None,
|
|
create_type("NoneType", &type_type, &object_type, &dict_type),
|
|
);
|
|
|
|
let true_value = PyObject::new(PyObjectKind::Integer { value: 1 }, bool_type.clone());
|
|
let false_value = PyObject::new(PyObjectKind::Integer { value: 0 }, bool_type.clone());
|
|
let context = PyContext {
|
|
int_type: int_type,
|
|
float_type: float_type,
|
|
bytes_type: bytes_type,
|
|
list_type: list_type,
|
|
set_type: set_type,
|
|
bool_type: bool_type,
|
|
true_value: true_value,
|
|
false_value: false_value,
|
|
tuple_type: tuple_type,
|
|
iter_type: iter_type,
|
|
dict_type: dict_type,
|
|
none: none,
|
|
str_type: str_type,
|
|
object: object_type,
|
|
function_type: function_type,
|
|
module_type: module_type,
|
|
bound_method_type: bound_method_type,
|
|
member_descriptor_type: member_descriptor_type,
|
|
type_type: type_type,
|
|
exceptions: exceptions,
|
|
};
|
|
objtype::init(&context);
|
|
objlist::init(&context);
|
|
objset::init(&context);
|
|
objtuple::init(&context);
|
|
objobject::init(&context);
|
|
objdict::init(&context);
|
|
objfunction::init(&context);
|
|
objint::init(&context);
|
|
objfloat::init(&context);
|
|
objbytes::init(&context);
|
|
objstr::init(&context);
|
|
objtuple::init(&context);
|
|
objiter::init(&context);
|
|
objbool::init(&context);
|
|
exceptions::init(&context);
|
|
context
|
|
}
|
|
|
|
pub fn int_type(&self) -> PyObjectRef {
|
|
self.int_type.clone()
|
|
}
|
|
|
|
pub fn float_type(&self) -> PyObjectRef {
|
|
self.float_type.clone()
|
|
}
|
|
|
|
pub fn bytes_type(&self) -> PyObjectRef {
|
|
self.bytes_type.clone()
|
|
}
|
|
|
|
pub fn list_type(&self) -> PyObjectRef {
|
|
self.list_type.clone()
|
|
}
|
|
|
|
pub fn set_type(&self) -> PyObjectRef {
|
|
self.set_type.clone()
|
|
}
|
|
|
|
pub fn bool_type(&self) -> PyObjectRef {
|
|
self.bool_type.clone()
|
|
}
|
|
pub fn tuple_type(&self) -> PyObjectRef {
|
|
self.tuple_type.clone()
|
|
}
|
|
pub fn iter_type(&self) -> PyObjectRef {
|
|
self.iter_type.clone()
|
|
}
|
|
pub fn dict_type(&self) -> PyObjectRef {
|
|
self.dict_type.clone()
|
|
}
|
|
pub fn str_type(&self) -> PyObjectRef {
|
|
self.str_type.clone()
|
|
}
|
|
pub fn function_type(&self) -> PyObjectRef {
|
|
self.function_type.clone()
|
|
}
|
|
pub fn bound_method_type(&self) -> PyObjectRef {
|
|
self.bound_method_type.clone()
|
|
}
|
|
pub fn member_descriptor_type(&self) -> PyObjectRef {
|
|
self.member_descriptor_type.clone()
|
|
}
|
|
pub fn type_type(&self) -> PyObjectRef {
|
|
self.type_type.clone()
|
|
}
|
|
|
|
pub fn none(&self) -> PyObjectRef {
|
|
self.none.clone()
|
|
}
|
|
pub fn object(&self) -> PyObjectRef {
|
|
self.object.clone()
|
|
}
|
|
|
|
pub fn new_object(&self) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::Instance {
|
|
dict: self.new_dict(),
|
|
},
|
|
self.object(),
|
|
)
|
|
}
|
|
|
|
pub fn new_int(&self, i: i32) -> PyObjectRef {
|
|
PyObject::new(PyObjectKind::Integer { value: i }, self.int_type())
|
|
}
|
|
|
|
pub fn new_float(&self, i: f64) -> PyObjectRef {
|
|
PyObject::new(PyObjectKind::Float { value: i }, self.float_type())
|
|
}
|
|
|
|
pub fn new_str(&self, s: String) -> PyObjectRef {
|
|
PyObject::new(PyObjectKind::String { value: s }, self.str_type())
|
|
}
|
|
|
|
pub fn new_bytes(&self, data: Vec<u8>) -> PyObjectRef {
|
|
PyObject::new(PyObjectKind::Bytes { value: data }, self.bytes_type())
|
|
}
|
|
|
|
pub fn new_bool(&self, b: bool) -> PyObjectRef {
|
|
if b {
|
|
self.true_value.clone()
|
|
} else {
|
|
self.false_value.clone()
|
|
}
|
|
}
|
|
|
|
pub fn new_tuple(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::Tuple { elements: elements },
|
|
self.tuple_type(),
|
|
)
|
|
}
|
|
|
|
pub fn new_list(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
|
|
PyObject::new(PyObjectKind::List { elements: elements }, self.list_type())
|
|
}
|
|
|
|
pub fn new_set(&self, elements: Vec<PyObjectRef>) -> PyObjectRef {
|
|
let elements = objset::sequence_to_hashmap(&elements);
|
|
PyObject::new(PyObjectKind::Set { elements: elements }, self.set_type())
|
|
}
|
|
|
|
pub fn new_dict(&self) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::Dict {
|
|
elements: HashMap::new(),
|
|
},
|
|
self.dict_type(),
|
|
)
|
|
}
|
|
|
|
pub fn new_class(&self, name: &str, base: PyObjectRef) -> PyObjectRef {
|
|
objtype::new(self.type_type(), name, vec![base], self.new_dict()).unwrap()
|
|
}
|
|
|
|
pub fn new_scope(&self, parent: Option<PyObjectRef>) -> PyObjectRef {
|
|
let locals = self.new_dict();
|
|
let scope = Scope {
|
|
locals: locals,
|
|
parent: parent,
|
|
};
|
|
PyObject {
|
|
kind: PyObjectKind::Scope { scope: scope },
|
|
typ: None,
|
|
}
|
|
.into_ref()
|
|
}
|
|
|
|
pub fn new_module(&self, name: &str, scope: PyObjectRef) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::Module {
|
|
name: name.to_string(),
|
|
dict: scope.clone(),
|
|
},
|
|
self.module_type.clone(),
|
|
)
|
|
}
|
|
|
|
pub fn new_rustfunc(&self, function: RustPyFunc) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::RustFunction { function: function },
|
|
self.function_type(),
|
|
)
|
|
}
|
|
|
|
pub fn new_function(
|
|
&self,
|
|
code_obj: PyObjectRef,
|
|
scope: PyObjectRef,
|
|
defaults: PyObjectRef,
|
|
) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::Function {
|
|
code: code_obj,
|
|
scope: scope,
|
|
defaults: defaults,
|
|
},
|
|
self.function_type(),
|
|
)
|
|
}
|
|
|
|
pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef {
|
|
PyObject::new(
|
|
PyObjectKind::BoundMethod {
|
|
function: function,
|
|
object: object,
|
|
},
|
|
self.bound_method_type(),
|
|
)
|
|
}
|
|
|
|
pub fn new_member_descriptor(&self, function: RustPyFunc) -> PyObjectRef {
|
|
let dict = self.new_dict();
|
|
dict.set_item(&String::from("function"), self.new_rustfunc(function));
|
|
self.new_instance(dict, self.member_descriptor_type())
|
|
}
|
|
|
|
pub fn new_instance(&self, dict: PyObjectRef, class: PyObjectRef) -> PyObjectRef {
|
|
PyObject::new(PyObjectKind::Instance { dict: dict }, class)
|
|
}
|
|
}
|
|
|
|
pub struct PyObject {
|
|
pub kind: PyObjectKind,
|
|
pub typ: Option<PyObjectRef>,
|
|
// pub dict: HashMap<String, PyObjectRef>, // __dict__ member
|
|
}
|
|
|
|
pub trait IdProtocol {
|
|
fn get_id(&self) -> usize;
|
|
fn is(&self, other: &PyObjectRef) -> bool;
|
|
}
|
|
|
|
impl IdProtocol for PyObjectRef {
|
|
fn get_id(&self) -> usize {
|
|
self.as_ptr() as usize
|
|
}
|
|
|
|
fn is(&self, other: &PyObjectRef) -> bool {
|
|
self.get_id() == other.get_id()
|
|
}
|
|
}
|
|
|
|
pub trait FromPyObjectRef {
|
|
fn from_pyobj(obj: &PyObjectRef) -> Self;
|
|
}
|
|
|
|
pub trait TypeProtocol {
|
|
fn typ(&self) -> PyObjectRef;
|
|
}
|
|
|
|
impl TypeProtocol for PyObjectRef {
|
|
fn typ(&self) -> PyObjectRef {
|
|
match self.borrow().typ {
|
|
Some(ref typ) => typ.clone(),
|
|
None => panic!("Object {:?} doesn't have a type!", self),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait ParentProtocol {
|
|
fn has_parent(&self) -> bool;
|
|
fn get_parent(&self) -> PyObjectRef;
|
|
}
|
|
|
|
impl ParentProtocol for PyObjectRef {
|
|
fn has_parent(&self) -> bool {
|
|
match self.borrow().kind {
|
|
PyObjectKind::Scope { ref scope } => match scope.parent {
|
|
Some(_) => true,
|
|
None => false,
|
|
},
|
|
_ => panic!("Only scopes have parent (not {:?}", self),
|
|
}
|
|
}
|
|
|
|
fn get_parent(&self) -> PyObjectRef {
|
|
match self.borrow().kind {
|
|
PyObjectKind::Scope { ref scope } => match scope.parent {
|
|
Some(ref value) => value.clone(),
|
|
None => panic!("OMG"),
|
|
},
|
|
_ => panic!("TODO"),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait AttributeProtocol {
|
|
fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef>;
|
|
fn set_attr(&self, attr_name: &str, value: PyObjectRef);
|
|
fn has_attr(&self, attr_name: &str) -> bool;
|
|
}
|
|
|
|
fn class_get_item(class: &PyObjectRef, attr_name: &str) -> Option<PyObjectRef> {
|
|
let class = class.borrow();
|
|
match class.kind {
|
|
PyObjectKind::Class { ref dict, .. } => dict.get_item(attr_name),
|
|
_ => panic!("Only classes should be in MRO!"),
|
|
}
|
|
}
|
|
|
|
fn class_has_item(class: &PyObjectRef, attr_name: &str) -> bool {
|
|
let class = class.borrow();
|
|
match class.kind {
|
|
PyObjectKind::Class { ref dict, .. } => dict.contains_key(attr_name),
|
|
_ => panic!("Only classes should be in MRO!"),
|
|
}
|
|
}
|
|
|
|
impl AttributeProtocol for PyObjectRef {
|
|
fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
|
|
let obj = self.borrow();
|
|
match obj.kind {
|
|
PyObjectKind::Module { ref dict, .. } => dict.get_item(attr_name),
|
|
PyObjectKind::Class { ref mro, .. } => {
|
|
if let Some(item) = class_get_item(self, attr_name) {
|
|
return Some(item);
|
|
}
|
|
for ref class in mro {
|
|
if let Some(item) = class_get_item(class, attr_name) {
|
|
return Some(item);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
PyObjectKind::Instance { ref dict } => dict.get_item(attr_name),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn has_attr(&self, attr_name: &str) -> bool {
|
|
let obj = self.borrow();
|
|
match obj.kind {
|
|
PyObjectKind::Module { name: _, ref dict } => dict.contains_key(attr_name),
|
|
PyObjectKind::Class { ref mro, .. } => {
|
|
class_has_item(self, attr_name)
|
|
|| mro.into_iter().any(|d| class_has_item(d, attr_name))
|
|
}
|
|
PyObjectKind::Instance { ref dict } => dict.contains_key(attr_name),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
fn set_attr(&self, attr_name: &str, value: PyObjectRef) {
|
|
match self.borrow().kind {
|
|
PyObjectKind::Instance { ref dict } => dict.set_item(attr_name, value),
|
|
PyObjectKind::Class {
|
|
name: _,
|
|
ref dict,
|
|
mro: _,
|
|
} => dict.set_item(attr_name, value),
|
|
ref kind => unimplemented!("set_attr unimplemented for: {:?}", kind),
|
|
};
|
|
}
|
|
}
|
|
|
|
pub trait DictProtocol {
|
|
fn contains_key(&self, k: &str) -> bool;
|
|
fn get_item(&self, k: &str) -> Option<PyObjectRef>;
|
|
fn set_item(&self, k: &str, v: PyObjectRef);
|
|
}
|
|
|
|
impl DictProtocol for PyObjectRef {
|
|
fn contains_key(&self, k: &str) -> bool {
|
|
match self.borrow().kind {
|
|
PyObjectKind::Dict { ref elements } => elements.contains_key(k),
|
|
PyObjectKind::Module { name: _, ref dict } => dict.contains_key(k),
|
|
PyObjectKind::Scope { ref scope } => scope.locals.contains_key(k),
|
|
ref kind => unimplemented!("TODO {:?}", kind),
|
|
}
|
|
}
|
|
|
|
fn get_item(&self, k: &str) -> Option<PyObjectRef> {
|
|
match self.borrow().kind {
|
|
PyObjectKind::Dict { ref elements } => match elements.get(k) {
|
|
Some(v) => Some(v.clone()),
|
|
None => None,
|
|
},
|
|
PyObjectKind::Module { name: _, ref dict } => dict.get_item(k),
|
|
PyObjectKind::Scope { ref scope } => scope.locals.get_item(k),
|
|
_ => panic!("TODO"),
|
|
}
|
|
}
|
|
|
|
fn set_item(&self, k: &str, v: PyObjectRef) {
|
|
match self.borrow_mut().kind {
|
|
PyObjectKind::Dict {
|
|
elements: ref mut el,
|
|
} => {
|
|
el.insert(k.to_string(), v);
|
|
}
|
|
PyObjectKind::Module {
|
|
name: _,
|
|
ref mut dict,
|
|
} => dict.set_item(k, v),
|
|
PyObjectKind::Scope { ref mut scope } => {
|
|
scope.locals.set_item(k, v);
|
|
}
|
|
_ => panic!("TODO"),
|
|
};
|
|
}
|
|
}
|
|
|
|
pub trait ToRust {
|
|
fn to_vec(&self) -> Option<Vec<PyObjectRef>>;
|
|
fn to_str(&self) -> Option<String>;
|
|
}
|
|
|
|
impl ToRust for PyObjectRef {
|
|
fn to_vec(&self) -> Option<Vec<PyObjectRef>> {
|
|
match self.borrow().kind {
|
|
PyObjectKind::Tuple { ref elements } => Some(elements.clone()),
|
|
PyObjectKind::List { ref elements } => Some(elements.clone()),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn to_str(&self) -> Option<String> {
|
|
Some(self.borrow().str())
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for PyObject {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "[PyObj {:?}]", self.kind)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone)]
|
|
pub struct PyFuncArgs {
|
|
pub args: Vec<PyObjectRef>,
|
|
pub kwargs: Vec<(String, PyObjectRef)>,
|
|
}
|
|
|
|
impl PyFuncArgs {
|
|
pub fn new(mut args: Vec<PyObjectRef>, kwarg_names: Vec<String>) -> PyFuncArgs {
|
|
let mut kwargs = vec![];
|
|
for name in kwarg_names.iter().rev() {
|
|
kwargs.push((name.clone(), args.pop().unwrap()));
|
|
}
|
|
PyFuncArgs {
|
|
args: args,
|
|
kwargs: kwargs,
|
|
}
|
|
}
|
|
|
|
pub fn insert(&self, item: PyObjectRef) -> PyFuncArgs {
|
|
let mut args = PyFuncArgs {
|
|
args: self.args.clone(),
|
|
kwargs: self.kwargs.clone(),
|
|
};
|
|
args.args.insert(0, item);
|
|
return args;
|
|
}
|
|
|
|
pub fn shift(&mut self) -> PyObjectRef {
|
|
self.args.remove(0)
|
|
}
|
|
}
|
|
|
|
type RustPyFunc = fn(vm: &mut VirtualMachine, PyFuncArgs) -> PyResult;
|
|
|
|
pub enum PyObjectKind {
|
|
String {
|
|
value: String,
|
|
},
|
|
Integer {
|
|
value: i32,
|
|
},
|
|
Float {
|
|
value: f64,
|
|
},
|
|
Bytes {
|
|
value: Vec<u8>,
|
|
},
|
|
List {
|
|
elements: Vec<PyObjectRef>,
|
|
},
|
|
Tuple {
|
|
elements: Vec<PyObjectRef>,
|
|
},
|
|
Dict {
|
|
elements: HashMap<String, PyObjectRef>,
|
|
},
|
|
Set {
|
|
elements: HashMap<usize, PyObjectRef>,
|
|
},
|
|
Iterator {
|
|
position: usize,
|
|
iterated_obj: PyObjectRef,
|
|
},
|
|
Slice {
|
|
start: Option<i32>,
|
|
stop: Option<i32>,
|
|
step: Option<i32>,
|
|
},
|
|
Code {
|
|
code: bytecode::CodeObject,
|
|
},
|
|
Function {
|
|
code: PyObjectRef,
|
|
scope: PyObjectRef,
|
|
defaults: PyObjectRef,
|
|
},
|
|
BoundMethod {
|
|
function: PyObjectRef,
|
|
object: PyObjectRef,
|
|
},
|
|
Scope {
|
|
scope: Scope,
|
|
},
|
|
Module {
|
|
name: String,
|
|
dict: PyObjectRef,
|
|
},
|
|
None,
|
|
Class {
|
|
name: String,
|
|
dict: PyObjectRef,
|
|
mro: Vec<PyObjectRef>,
|
|
},
|
|
Instance {
|
|
dict: PyObjectRef,
|
|
},
|
|
RustFunction {
|
|
function: RustPyFunc,
|
|
},
|
|
}
|
|
|
|
impl fmt::Debug for PyObjectKind {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
&PyObjectKind::String { ref value } => write!(f, "str \"{}\"", value),
|
|
&PyObjectKind::Integer { ref value } => write!(f, "int {}", value),
|
|
&PyObjectKind::Float { ref value } => write!(f, "float {}", value),
|
|
&PyObjectKind::Bytes { ref value } => write!(f, "bytes {:?}", value),
|
|
&PyObjectKind::List { elements: _ } => write!(f, "list"),
|
|
&PyObjectKind::Tuple { elements: _ } => write!(f, "tuple"),
|
|
&PyObjectKind::Dict { elements: _ } => write!(f, "dict"),
|
|
&PyObjectKind::Set { elements: _ } => write!(f, "set"),
|
|
&PyObjectKind::Iterator {
|
|
position: _,
|
|
iterated_obj: _,
|
|
} => write!(f, "iterator"),
|
|
&PyObjectKind::Slice {
|
|
start: _,
|
|
stop: _,
|
|
step: _,
|
|
} => write!(f, "slice"),
|
|
&PyObjectKind::Code { ref code } => write!(f, "code: {:?}", code),
|
|
&PyObjectKind::Function { .. } => write!(f, "function"),
|
|
&PyObjectKind::BoundMethod {
|
|
ref function,
|
|
ref object,
|
|
} => write!(f, "bound-method: {:?} of {:?}", function, object),
|
|
&PyObjectKind::Module { name: _, dict: _ } => write!(f, "module"),
|
|
&PyObjectKind::Scope { scope: _ } => write!(f, "scope"),
|
|
&PyObjectKind::None => write!(f, "None"),
|
|
&PyObjectKind::Class {
|
|
ref name,
|
|
dict: _,
|
|
mro: _,
|
|
} => write!(f, "class {:?}", name),
|
|
&PyObjectKind::Instance { dict: _ } => write!(f, "instance"),
|
|
&PyObjectKind::RustFunction { function: _ } => write!(f, "rust function"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PyObject {
|
|
pub fn new(kind: PyObjectKind, /* dict: PyObjectRef,*/ typ: PyObjectRef) -> PyObjectRef {
|
|
PyObject {
|
|
kind: kind,
|
|
typ: Some(typ),
|
|
// dict: HashMap::new(), // dict,
|
|
}
|
|
.into_ref()
|
|
}
|
|
|
|
pub fn str(&self) -> String {
|
|
match self.kind {
|
|
PyObjectKind::String { ref value } => value.clone(),
|
|
PyObjectKind::Integer { ref value } => format!("{:?}", value),
|
|
PyObjectKind::Float { ref value } => format!("{:?}", value),
|
|
PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value),
|
|
PyObjectKind::List { ref elements } => format!(
|
|
"[{}]",
|
|
elements
|
|
.iter()
|
|
.map(|elem| elem.borrow().str())
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
PyObjectKind::Tuple { ref elements } => {
|
|
if elements.len() == 1 {
|
|
format!("({},)", elements[0].borrow().str())
|
|
} else {
|
|
format!(
|
|
"({})",
|
|
elements
|
|
.iter()
|
|
.map(|elem| elem.borrow().str())
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
)
|
|
}
|
|
}
|
|
PyObjectKind::Dict { ref elements } => format!(
|
|
"{{ {} }}",
|
|
elements
|
|
.iter()
|
|
.map(|elem| format!("{}: {}", elem.0, elem.1.borrow().str()))
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
PyObjectKind::Set { ref elements } => format!(
|
|
"{{ {} }}",
|
|
elements
|
|
.iter()
|
|
.map(|elem| elem.1.borrow().str())
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
PyObjectKind::None => String::from("None"),
|
|
PyObjectKind::Class {
|
|
ref name,
|
|
dict: ref _dict,
|
|
mro: _,
|
|
} => format!("<class '{}'>", name),
|
|
PyObjectKind::Instance { dict: _ } => format!("<instance>"),
|
|
PyObjectKind::Code { code: _ } => format!("<code>"),
|
|
PyObjectKind::Function { .. } => format!("<func>"),
|
|
PyObjectKind::BoundMethod { .. } => format!("<bound-method>"),
|
|
PyObjectKind::RustFunction { function: _ } => format!("<rustfunc>"),
|
|
PyObjectKind::Module { ref name, dict: _ } => format!("<module '{}'>", name),
|
|
PyObjectKind::Scope { ref scope } => format!("<scope '{:?}'>", scope),
|
|
PyObjectKind::Slice {
|
|
ref start,
|
|
ref stop,
|
|
ref step,
|
|
} => format!("<slice '{:?}:{:?}:{:?}'>", start, stop, step),
|
|
PyObjectKind::Iterator {
|
|
ref position,
|
|
ref iterated_obj,
|
|
} => format!(
|
|
"<iter pos {} in {}>",
|
|
position,
|
|
iterated_obj.borrow_mut().str()
|
|
),
|
|
}
|
|
}
|
|
|
|
// Move this object into a reference object, transferring ownership.
|
|
pub fn into_ref(self) -> PyObjectRef {
|
|
Rc::new(RefCell::new(self))
|
|
}
|
|
}
|
|
|
|
// impl<'a> PartialEq<&'a PyObject> for &'a PyObject {
|
|
impl PartialEq for PyObject {
|
|
fn eq(&self, other: &PyObject) -> bool {
|
|
match (&self.kind, &other.kind) {
|
|
(
|
|
PyObjectKind::Integer { value: ref v1i },
|
|
PyObjectKind::Integer { value: ref v2i },
|
|
) => v2i == v1i,
|
|
(PyObjectKind::Float { value: a }, PyObjectKind::Float { value: b }) => a == b,
|
|
(PyObjectKind::Integer { value: a }, PyObjectKind::Float { value: b }) => {
|
|
*a as f64 == *b
|
|
}
|
|
(PyObjectKind::Float { value: a }, PyObjectKind::Integer { value: b }) => {
|
|
*a == *b as f64
|
|
}
|
|
(PyObjectKind::String { value: ref v1i }, PyObjectKind::String { value: ref v2i }) => {
|
|
*v2i == *v1i
|
|
}
|
|
(PyObjectKind::List { elements: ref l1 }, PyObjectKind::List { elements: ref l2 })
|
|
| (
|
|
PyObjectKind::Tuple { elements: ref l1 },
|
|
PyObjectKind::Tuple { elements: ref l2 },
|
|
) => {
|
|
if l1.len() == l2.len() {
|
|
Iterator::zip(l1.iter(), l2.iter()).all(|elem| elem.0 == elem.1)
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
(PyObjectKind::None, PyObjectKind::None) => true,
|
|
_ => panic!(
|
|
"TypeError in COMPARE_OP: can't compare {:?} with {:?}",
|
|
self, other
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for PyObject {}
|
|
|
|
impl PartialOrd for PyObject {
|
|
fn partial_cmp(&self, other: &PyObject) -> Option<Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for PyObject {
|
|
fn cmp(&self, other: &PyObject) -> Ordering {
|
|
match (&self.kind, &other.kind) {
|
|
(PyObjectKind::Integer { value: v1 }, PyObjectKind::Integer { value: ref v2 }) => {
|
|
v1.cmp(v2)
|
|
}
|
|
_ => panic!("Not impl"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::PyContext;
|
|
|
|
#[test]
|
|
fn test_type_type() {
|
|
// TODO: Write this test
|
|
PyContext::new();
|
|
}
|
|
}
|