Check that raise command raises exception type

This commit is contained in:
Windel Bouwman
2018-08-26 00:30:01 +02:00
parent c41370a26f
commit a0edc4203f
11 changed files with 87 additions and 59 deletions

View File

@@ -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]

View File

@@ -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()))
}
}

View File

@@ -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) => {

View File

@@ -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),
}

View File

@@ -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")))
}
}
}

View File

@@ -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()))
}
}

View File

@@ -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())),
}
}

View File

@@ -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
))),

View File

@@ -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),
))
}
}

View File

@@ -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 {

View File

@@ -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 => {