forked from Rust-related/RustPython
Check that raise command raises exception type
This commit is contained in:
@@ -72,3 +72,13 @@ except NameError as ex:
|
||||
l.append(3)
|
||||
print('boom', type(ex))
|
||||
assert l == [1, 3]
|
||||
|
||||
|
||||
l = []
|
||||
try:
|
||||
l.append(1)
|
||||
raise 1
|
||||
except TypeError as ex:
|
||||
l.append(3)
|
||||
print('boom', type(ex))
|
||||
assert l == [1, 3]
|
||||
|
||||
@@ -74,7 +74,7 @@ fn builtin_any(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
fn builtin_chr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
if args.args.len() != 1 {
|
||||
return Err(vm.new_exception("Expected one arguments".to_string()));
|
||||
return Err(vm.new_type_error("Expected one arguments".to_string()));
|
||||
}
|
||||
|
||||
let code_point_obj = args.args[0].borrow();
|
||||
@@ -96,7 +96,7 @@ fn builtin_chr(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()));
|
||||
return Err(vm.new_type_error("Expected more arguments".to_string()));
|
||||
}
|
||||
// TODO:
|
||||
let mode = compile::Mode::Eval;
|
||||
@@ -104,7 +104,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
match compile::compile(vm, &source, mode) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(msg) => Err(vm.new_exception(msg)),
|
||||
Err(msg) => Err(vm.new_type_error(msg)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,11 +126,11 @@ fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
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()));
|
||||
return Err(vm.new_type_error("Expected at maximum of 3 arguments".to_string()));
|
||||
} else if args.len() > 2 {
|
||||
// TODO: handle optional global and locals
|
||||
} else {
|
||||
return Err(vm.new_exception("Expected at least one argument".to_string()));
|
||||
return Err(vm.new_type_error("Expected at least one argument".to_string()));
|
||||
}
|
||||
let source = args[0].clone();
|
||||
let _globals = args[1].clone();
|
||||
@@ -166,10 +166,10 @@ fn builtin_getattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
if let PyObjectKind::String { ref value } = attr.kind {
|
||||
vm.get_attribute(obj, value)
|
||||
} else {
|
||||
Err(vm.new_exception("Attr can only be str for now".to_string()))
|
||||
Err(vm.new_type_error("Attr can only be str for now".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("Expected 2 arguments".to_string()))
|
||||
Err(vm.new_type_error("Expected 2 arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,10 +187,10 @@ fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
};
|
||||
Ok(vm.context().new_bool(has_attr))
|
||||
} else {
|
||||
Err(vm.new_exception("Attr can only be str for now".to_string()))
|
||||
Err(vm.new_type_error("Attr can only be str for now".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("Expected 2 arguments".to_string()))
|
||||
Err(vm.new_type_error("Expected 2 arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
|
||||
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()));
|
||||
return Err(vm.new_type_error("Expected only one argument".to_string()));
|
||||
}
|
||||
|
||||
Ok(vm.context().new_int(args.args[0].get_id() as i32))
|
||||
@@ -217,7 +217,7 @@ fn builtin_isinstance(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let obj = args.args[0].clone();
|
||||
let typ = args.args[1].clone();
|
||||
|
||||
let isinstance = vm.isinstance(obj, typ);
|
||||
let isinstance = objtype::isinstance(obj, typ);
|
||||
Ok(vm.context().new_bool(isinstance))
|
||||
}
|
||||
|
||||
@@ -308,10 +308,10 @@ fn builtin_setattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
obj.set_attr(name, value);
|
||||
Ok(vm.get_none())
|
||||
} else {
|
||||
Err(vm.new_exception("Attr can only be str for now".to_string()))
|
||||
Err(vm.new_type_error("Attr can only be str for now".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("Expected 3 arguments".to_string()))
|
||||
Err(vm.new_type_error("Expected 3 arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,13 @@ fn import_module(vm: &mut VirtualMachine, module: &String) -> PyResult {
|
||||
return Ok(module);
|
||||
}
|
||||
|
||||
// TODO: introduce import error:
|
||||
let import_error = vm.context().exceptions.exception_type.clone();
|
||||
// Time to search for module in any place:
|
||||
let filepath =
|
||||
find_source(vm, module).map_err(|e| vm.new_exception(format!("Error: {:?}", e)))?;
|
||||
let filepath = find_source(vm, module)
|
||||
.map_err(|e| vm.new_exception(import_error.clone(), format!("Error: {:?}", e)))?;
|
||||
let source = parser::read_file(filepath.as_path())
|
||||
.map_err(|e| vm.new_exception(format!("Error: {:?}", e)))?;
|
||||
.map_err(|e| vm.new_exception(import_error.clone(), format!("Error: {:?}", e)))?;
|
||||
|
||||
let code_obj = match compile::compile(vm, &source, compile::Mode::Exec) {
|
||||
Ok(bytecode) => {
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
|
||||
match vm.invoke(f, PyFuncArgs::new()) {
|
||||
Ok(result) => match result.borrow().kind {
|
||||
PyObjectKind::Boolean { value } => value,
|
||||
_ => return Err(vm.new_exception(String::from("TypeError"))),
|
||||
_ => return Err(vm.new_type_error(String::from("TypeError"))),
|
||||
},
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ fn bind_method(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
fn member_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
|
||||
match args.shift().get_attr("function") {
|
||||
Some(function) => vm.invoke(function, args),
|
||||
None => Err(vm.new_exception(String::from("Attribute Error"))),
|
||||
None => {
|
||||
let attribute_error = vm.context().exceptions.attribute_error.clone();
|
||||
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ fn append(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
elements.push(o);
|
||||
Ok(vm.get_none())
|
||||
} else {
|
||||
Err(vm.new_exception("list.append is called with no list".to_string()))
|
||||
Err(vm.new_type_error("list.append is called with no list".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("list.append requires two arguments".to_string()))
|
||||
Err(vm.new_type_error("list.append requires two arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +50,10 @@ fn clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
elements.clear();
|
||||
Ok(vm.get_none())
|
||||
} else {
|
||||
Err(vm.new_exception("list.clear is called with no list".to_string()))
|
||||
Err(vm.new_type_error("list.clear is called with no list".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("list.clear requires one arguments".to_string()))
|
||||
Err(vm.new_type_error("list.clear requires one arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +66,10 @@ fn len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
if let PyObjectKind::List { ref elements } = list_obj.kind {
|
||||
Ok(vm.context().new_int(elements.len() as i32))
|
||||
} else {
|
||||
Err(vm.new_exception("list.len is called with no list".to_string()))
|
||||
Err(vm.new_type_error("list.len is called with no list".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("list.len requires one arguments".to_string()))
|
||||
Err(vm.new_type_error("list.len requires one arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +82,10 @@ fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
elements.reverse();
|
||||
Ok(vm.get_none())
|
||||
} else {
|
||||
Err(vm.new_exception("list.reverse is called with no list".to_string()))
|
||||
Err(vm.new_type_error("list.reverse is called with no list".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_exception("list.reverse requires one arguments".to_string()))
|
||||
Err(vm.new_type_error("list.reverse requires one arguments".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
match args.args[0].borrow().kind {
|
||||
PyObjectKind::Class { ref dict, .. } => Ok(dict.clone()),
|
||||
PyObjectKind::Instance { ref dict, .. } => Ok(dict.clone()),
|
||||
_ => Err(vm.new_exception("TypeError: no dictionary.".to_string())),
|
||||
_ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ pub fn get_item(
|
||||
let obj = elements[pos_index].clone();
|
||||
Ok(obj)
|
||||
} else {
|
||||
Err(vm.new_exception("Index out of bounds!".to_string()))
|
||||
let value_error = vm.context().exceptions.value_error.clone();
|
||||
Err(vm.new_exception(value_error, "Index out of bounds!".to_string()))
|
||||
}
|
||||
}
|
||||
PyObjectKind::Slice {
|
||||
@@ -91,7 +92,7 @@ pub fn get_item(
|
||||
},
|
||||
vm.get_type(),
|
||||
)),
|
||||
_ => Err(vm.new_exception(format!(
|
||||
_ => Err(vm.new_type_error(format!(
|
||||
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
|
||||
sequence, subscript
|
||||
))),
|
||||
|
||||
@@ -29,7 +29,7 @@ pub fn init(context: &PyContext) {
|
||||
fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
match _mro(args.args[0].clone()) {
|
||||
Some(mro) => Ok(vm.context().new_tuple(mro)),
|
||||
None => Err(vm.new_exception("Only classes have an MRO.".to_string())),
|
||||
None => Err(vm.new_type_error("Only classes have an MRO.".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,11 @@ fn _mro(cls: PyObjectRef) -> Option<Vec<PyObjectRef>> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isinstance(obj: PyObjectRef, cls: PyObjectRef) -> bool {
|
||||
let mro = _mro(obj.typ()).unwrap();
|
||||
mro.into_iter().any(|c| c.is(&cls))
|
||||
}
|
||||
|
||||
pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
debug!("type.__new__{:?}", args);
|
||||
if args.args.len() == 2 {
|
||||
@@ -56,7 +61,7 @@ pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
let dict = args.args[3].clone();
|
||||
new(typ, &name, bases, dict)
|
||||
} else {
|
||||
Err(vm.new_exception(format!("TypeError: type_new: {:?}", args)))
|
||||
Err(vm.new_type_error(format!(": type_new: {:?}", args)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +97,11 @@ pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &String) -
|
||||
} else if let Some(cls_attr) = cls.get_attr(name) {
|
||||
Ok(cls_attr)
|
||||
} else {
|
||||
Err(vm.new_exception(format!(
|
||||
"AttributeError: {:?} object has no attribute {}",
|
||||
cls, name
|
||||
)))
|
||||
let attribute_error = vm.context().exceptions.attribute_error.clone();
|
||||
Err(vm.new_exception(
|
||||
attribute_error,
|
||||
format!("{:?} object has no attribute {}", cls, name),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -264,12 +264,17 @@ pub struct PyObject {
|
||||
|
||||
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 TypeProtocol {
|
||||
|
||||
49
vm/src/vm.rs
49
vm/src/vm.rs
@@ -19,7 +19,7 @@ use super::objstr;
|
||||
use super::objtype;
|
||||
use super::pyobject::{
|
||||
AttributeProtocol, DictProtocol, IdProtocol, ParentProtocol, PyContext, PyFuncArgs, PyObject,
|
||||
PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
|
||||
PyObjectKind, PyObjectRef, PyResult,
|
||||
};
|
||||
use super::sysmodule;
|
||||
|
||||
@@ -52,8 +52,20 @@ impl VirtualMachine {
|
||||
self.ctx.new_dict()
|
||||
}
|
||||
|
||||
pub fn new_exception(&self, msg: String) -> PyObjectRef {
|
||||
self.new_str(msg)
|
||||
pub fn new_exception(&mut self, exc_type: PyObjectRef, msg: String) -> PyObjectRef {
|
||||
// TODO: maybe there is a clearer way to create an instance:
|
||||
info!("New exception created: {}", msg);
|
||||
let args: Vec<PyObjectRef> = Vec::new();
|
||||
let args = PyFuncArgs { args: args };
|
||||
|
||||
// Call function:
|
||||
let exception = self.invoke(exc_type, args).unwrap();
|
||||
exception
|
||||
}
|
||||
|
||||
pub fn new_type_error(&mut self, msg: String) -> PyObjectRef {
|
||||
let type_error = self.context().exceptions.type_error.clone();
|
||||
self.new_exception(type_error, msg)
|
||||
}
|
||||
|
||||
pub fn new_scope(&mut self) -> PyObjectRef {
|
||||
@@ -61,10 +73,6 @@ impl VirtualMachine {
|
||||
self.ctx.new_scope(Some(parent_scope))
|
||||
}
|
||||
|
||||
pub fn isinstance(&self, obj: PyObjectRef, typ: PyObjectRef) -> bool {
|
||||
self._is(obj.typ(), typ)
|
||||
}
|
||||
|
||||
pub fn get_none(&self) -> PyObjectRef {
|
||||
self.ctx.none.clone()
|
||||
}
|
||||
@@ -252,7 +260,7 @@ impl VirtualMachine {
|
||||
PyObjectKind::List { ref elements } | PyObjectKind::Tuple { ref elements } => {
|
||||
super::objsequence::get_item(self, &a, elements, b)
|
||||
}
|
||||
_ => Err(self.new_exception(format!(
|
||||
_ => Err(self.new_type_error(format!(
|
||||
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
|
||||
a, b
|
||||
))),
|
||||
@@ -268,7 +276,7 @@ impl VirtualMachine {
|
||||
PyObjectKind::List { ref mut elements } => {
|
||||
objlist::set_item(self, elements, idx, value)
|
||||
}
|
||||
_ => Err(self.new_exception(format!(
|
||||
_ => Err(self.new_type_error(format!(
|
||||
"TypeError: __setitem__ assign type {:?} with index {:?} is not supported (yet?)",
|
||||
obj, idx
|
||||
))),
|
||||
@@ -435,16 +443,11 @@ impl VirtualMachine {
|
||||
|
||||
fn _is(&self, a: PyObjectRef, b: PyObjectRef) -> bool {
|
||||
// Pointer equal:
|
||||
let id_a = self._id(a);
|
||||
let id_b = self._id(b);
|
||||
id_a == id_b
|
||||
a.is(&b)
|
||||
}
|
||||
|
||||
fn _is_not(&self, a: PyObjectRef, b: PyObjectRef) -> PyResult {
|
||||
// Pointer equal:
|
||||
let id_a = self._id(a);
|
||||
let id_b = self._id(b);
|
||||
let result_bool = id_a != id_b;
|
||||
let result_bool = !a.is(&b);
|
||||
let result = self.ctx.new_bool(result_bool);
|
||||
Ok(result)
|
||||
}
|
||||
@@ -800,23 +803,21 @@ impl VirtualMachine {
|
||||
0 | 2 | 3 => panic!("Not implemented!"),
|
||||
_ => panic!("Invalid paramter for RAISE_VARARGS, must be between 0 to 3"),
|
||||
};
|
||||
if self.isinstance(
|
||||
if objtype::isinstance(
|
||||
exception.clone(),
|
||||
self.context().exceptions.base_exception_type.clone(),
|
||||
) {
|
||||
info!("Exception raised: {:?}", exception);
|
||||
Some(Err(exception))
|
||||
} else {
|
||||
Some(Err(exception))
|
||||
// TODO: enable this when isinstance works properly:
|
||||
/*
|
||||
info!(
|
||||
"Can only raise BaseException derived types: {:?}",
|
||||
let msg = format!(
|
||||
"Can only raise BaseException derived types, not {:?}",
|
||||
exception
|
||||
);
|
||||
let type_error = self.context().exceptions.type_error.clone();
|
||||
let type_error_type = self.context().exceptions.type_error.clone();
|
||||
let type_error = self.new_exception(type_error_type, msg);
|
||||
Some(Err(type_error))
|
||||
*/ }
|
||||
}
|
||||
}
|
||||
|
||||
bytecode::Instruction::Break => {
|
||||
|
||||
Reference in New Issue
Block a user