Move max function test cases to snippet dir. Implement key and default argument on max function.

This commit is contained in:
Windel Bouwman committed 2018-11-07 17:26:18 +01:00
1 parent 4acea45f78
commit 99af466a88
13 files changed
+192 -42

No files matched your search

+3
View File
@@ -197,6 +197,9 @@ where
// Skip backslash and newline
self.shift();
self.shift();
// Idea: insert trailing newline here:
// } else if self.chr0 != Some('\n') && self.chr1.is_none() {
// self.chr1 = Some('\n');
} else {
break;
}
File renamed without changes.
+4
View File
@@ -17,3 +17,7 @@ assert list(zip(['a', 'b', 'c'], range(3), [9, 8, 7, 99])) == [('a', 0, 9), ('b'
assert list(filter(lambda x: ((x % 2) == 0), [0, 1, 2])) == [0, 2]
assert 3 == eval('1+2')
code = compile('5+3', 'x.py', 'eval')
assert eval(code) == 8
+88 -16
View File
@@ -132,6 +132,8 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
]
);
let source = objstr::get_value(source);
// TODO: fix this newline bug:
let source = format!("{}\n", source);
let mode = {
let mode = objstr::get_value(mode);
@@ -206,19 +208,36 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [
(source, None), // TODO: Use more specific type
required = [(source, None)],
optional = [
(_globals, Some(vm.ctx.dict_type())),
(locals, Some(vm.ctx.dict_type()))
]
);
// TODO: handle optional global and locals
let code_obj = source; // if source.borrow().kind
// Determine code object:
let code_obj = if objtype::isinstance(source, &vm.ctx.code_type()) {
source.clone()
} else if objtype::isinstance(source, &vm.ctx.str_type()) {
let mode = compile::Mode::Eval;
let source = objstr::get_value(source);
// TODO: fix this newline bug:
let source = format!("{}\n", source);
compile::compile(vm, &source, mode, None)?
} else {
return Err(vm.new_type_error("code argument must be str or code object".to_string()));
};
let locals = if let Some(locals) = locals {
locals.clone()
} else {
vm.new_dict()
};
// TODO: handle optional globals
// Construct new scope:
let scope_inner = Scope {
locals: locals.clone(),
locals: locals,
parent: None,
};
let scope = PyObject {
@@ -235,26 +254,38 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [
(source, None),
required = [(source, None)],
optional = [
(_globals, Some(vm.ctx.dict_type())),
(locals, Some(vm.ctx.dict_type()))
]
);
// TODO: handle optional global and locals
// Determine code object:
let code_obj = if objtype::isinstance(source, &vm.ctx.str_type()) {
let mode = compile::Mode::Exec;
let source = objstr::get_value(source);
// TODO: fix this newline bug:
let source = format!("{}\n", source);
compile::compile(vm, &source, mode, None)?
} else {
} else if objtype::isinstance(source, &vm.ctx.code_type()) {
source.clone()
} else {
return Err(vm.new_type_error("source argument must be str or code object".to_string()));
};
// handle optional global and locals
let locals = if let Some(locals) = locals {
locals.clone()
} else {
vm.new_dict()
};
// TODO: use globals
// Construct new scope:
let scope_inner = Scope {
locals: locals.clone(),
locals: locals,
parent: None,
};
let scope = PyObject {
@@ -416,15 +447,56 @@ fn builtin_map(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
}
fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(x, None), (y, None)]);
// arg_check!(vm, args, required = [(x, None), (y, None)]);
let order = vm.call_method(x, "__gt__", vec![y.clone()])?;
if objbool::get_value(&order) {
Ok(x.clone())
let candidates = if args.args.len() > 1 {
args.args.clone()
} else if args.args.len() == 1 {
vm.extract_elements(&args.args[0])?
} else {
Ok(y.clone())
// zero arguments means type error:
return Err(vm.new_type_error("Expected 1 or more arguments".to_string()));
};
if candidates.len() == 0 {
let default = args.get_optional_kwarg("default");
if default.is_none() {
return Err(vm.new_value_error("max() arg is an empty sequence".to_string()));
} else {
return Ok(default.unwrap());
}
}
let key_func = args.get_optional_kwarg("key");
// Start with first assumption:
let mut candidates_iter = candidates.into_iter();
let mut x = candidates_iter.next().unwrap();
// TODO: this key function looks pretty duplicate. Maybe we can create
// a local function?
let mut x_key = if let Some(f) = &key_func {
let args = PyFuncArgs::new(vec![x.clone()], vec![]);
vm.invoke(f.clone(), args)?
} else {
x.clone()
};
for y in candidates_iter {
let y_key = if let Some(f) = &key_func {
let args = PyFuncArgs::new(vec![y.clone()], vec![]);
vm.invoke(f.clone(), args)?
} else {
y.clone()
};
let order = vm.call_method(&x_key, "__gt__", vec![y_key.clone()])?;
if !objbool::get_value(&order) {
x = y.clone();
x_key = y_key;
}
}
Ok(x)
}
// builtin_memoryview
+6
View File
@@ -11,6 +11,7 @@ use super::objtype;
pub fn init(context: &PyContext) {
let ref code_type = context.code_type;
code_type.set_attr("__new__", context.new_rustfunc(code_new));
code_type.set_attr("__repr__", context.new_rustfunc(code_repr));
}
@@ -24,6 +25,11 @@ pub fn copy_code(code_obj: &PyObjectRef) -> bytecode::CodeObject {
}
}
fn code_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(_cls, None)]);
Err(vm.new_type_error(format!("Cannot directly create code object")))
}
fn code_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(o, Some(vm.ctx.code_type()))]);
+22
View File
@@ -109,6 +109,27 @@ fn dict_delitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
}
}
/// When iterating over a dictionary, we iterate over the keys of it.
fn dict_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(dict, Some(vm.ctx.dict_type()))]);
let keys = get_elements(dict)
.keys()
.map(|k| vm.ctx.new_str(k.to_string()))
.collect();
let key_list = vm.ctx.new_list(keys);
let iter_obj = PyObject::new(
PyObjectKind::Iterator {
position: 0,
iterated_obj: key_list,
},
vm.ctx.iter_type(),
);
Ok(iter_obj)
}
fn dict_setitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
@@ -165,6 +186,7 @@ pub fn init(context: &PyContext) {
dict_type.set_attr("__contains__", context.new_rustfunc(dict_contains));
dict_type.set_attr("__delitem__", context.new_rustfunc(dict_delitem));
dict_type.set_attr("__getitem__", context.new_rustfunc(dict_getitem));
dict_type.set_attr("__iter__", context.new_rustfunc(dict_iter));
dict_type.set_attr("__new__", context.new_rustfunc(dict_new));
dict_type.set_attr("__repr__", context.new_rustfunc(dict_repr));
dict_type.set_attr("__setitem__", context.new_rustfunc(dict_setitem));
+6
View File
@@ -10,9 +10,15 @@ use super::objtype;
pub fn init(context: &PyContext) {
let ref frame_type = context.frame_type;
frame_type.set_attr("__new__", context.new_rustfunc(frame_new));
frame_type.set_attr("__repr__", context.new_rustfunc(frame_repr));
}
fn frame_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(_cls, None)]);
Err(vm.new_type_error(format!("Cannot directly create frame object")))
}
fn frame_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(_frame, Some(vm.ctx.frame_type()))]);
let repr = format!("<frame object at .. >");
+5 -26
View File
@@ -3,8 +3,7 @@
*/
use super::super::pyobject::{
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
TypeProtocol,
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objbool;
@@ -17,30 +16,10 @@ use super::objtype; // Required for arg_check! to use isinstance
* function 'iter' is called.
*/
pub fn get_iter(vm: &mut VirtualMachine, iter_target: &PyObjectRef) -> PyResult {
// Check what we are going to iterate over:
let iterated_obj = if objtype::isinstance(iter_target, &vm.ctx.iter_type()) {
// If object is already an iterator, return that one.
return Ok(iter_target.clone());
} else if objtype::isinstance(iter_target, &vm.ctx.list_type()) {
iter_target.clone()
// } else if hasattr(iter_target, "__iter__") {
} else {
return vm.call_method(iter_target, "__iter__", vec![]);
// let type_str = objstr::get_value(&vm.to_str(iter_target.typ()).unwrap());
// let type_error = vm.new_type_error(format!("Cannot iterate over {}", type_str));
// return Err(type_error);
};
let iter_obj = PyObject::new(
PyObjectKind::Iterator {
position: 0,
iterated_obj: iterated_obj,
},
vm.ctx.iter_type(),
);
// We are all good here:
Ok(iter_obj)
vm.call_method(iter_target, "__iter__", vec![])
// let type_str = objstr::get_value(&vm.to_str(iter_target.typ()).unwrap());
// let type_error = vm.new_type_error(format!("Cannot iterate over {}", type_str));
// return Err(type_error);
}
/*
+16
View File
@@ -183,6 +183,21 @@ fn list_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
get_item(vm, list, &get_elements(list), needle.clone())
}
fn list_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(list, Some(vm.ctx.list_type()))]);
let iter_obj = PyObject::new(
PyObjectKind::Iterator {
position: 0,
iterated_obj: list.clone(),
},
vm.ctx.iter_type(),
);
// We are all good here:
Ok(iter_obj)
}
fn list_setitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
@@ -199,6 +214,7 @@ pub fn init(context: &PyContext) {
list_type.set_attr("__contains__", context.new_rustfunc(list_contains));
list_type.set_attr("__eq__", context.new_rustfunc(list_eq));
list_type.set_attr("__getitem__", context.new_rustfunc(list_getitem));
list_type.set_attr("__iter__", context.new_rustfunc(list_iter));
list_type.set_attr("__setitem__", context.new_rustfunc(list_setitem));
list_type.set_attr("__len__", context.new_rustfunc(list_len));
list_type.set_attr("__new__", context.new_rustfunc(list_new));
+16
View File
@@ -14,6 +14,7 @@ pub fn init(context: &PyContext) {
str_type.set_attr("__eq__", context.new_rustfunc(str_eq));
str_type.set_attr("__contains__", context.new_rustfunc(str_contains));
str_type.set_attr("__getitem__", context.new_rustfunc(str_getitem));
str_type.set_attr("__gt__", context.new_rustfunc(str_gt));
str_type.set_attr("__len__", context.new_rustfunc(str_len));
str_type.set_attr("__mul__", context.new_rustfunc(str_mul));
str_type.set_attr("__new__", context.new_rustfunc(str_new));
@@ -53,6 +54,21 @@ fn str_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(vm.ctx.new_bool(result))
}
fn str_gt(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [
(zelf, Some(vm.ctx.str_type())),
(other, Some(vm.ctx.str_type()))
]
);
let zelf = get_value(zelf);
let other = get_value(other);
let result = zelf > other;
Ok(vm.ctx.new_bool(result))
}
fn str_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
Ok(s.clone())
+15
View File
@@ -48,6 +48,20 @@ fn tuple_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(vm.ctx.new_int(x.to_bigint().unwrap()))
}
fn tuple_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(tuple, Some(vm.ctx.tuple_type()))]);
let iter_obj = PyObject::new(
PyObjectKind::Iterator {
position: 0,
iterated_obj: tuple.clone(),
},
vm.ctx.iter_type(),
);
Ok(iter_obj)
}
fn tuple_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.tuple_type()))]);
let elements = get_elements(zelf);
@@ -132,6 +146,7 @@ pub fn init(context: &PyContext) {
tuple_type.set_attr("__contains__", context.new_rustfunc(tuple_contains));
tuple_type.set_attr("__getitem__", context.new_rustfunc(tuple_getitem));
tuple_type.set_attr("__hash__", context.new_rustfunc(tuple_hash));
tuple_type.set_attr("__iter__", context.new_rustfunc(tuple_iter));
tuple_type.set_attr("__len__", context.new_rustfunc(tuple_len));
tuple_type.set_attr("__new__", context.new_rustfunc(tuple_new));
tuple_type.set_attr("__repr__", context.new_rustfunc(tuple_repr));
+9
View File
@@ -728,6 +728,15 @@ impl PyFuncArgs {
}
default.clone()
}
pub fn get_optional_kwarg(&self, key: &str) -> Option<PyObjectRef> {
for (arg_name, arg_value) in self.kwargs.iter() {
if arg_name == key {
return Some(arg_value.clone());
}
}
None
}
}
type RustPyFunc = fn(vm: &mut VirtualMachine, PyFuncArgs) -> PyResult;
+2
View File
@@ -35,6 +35,7 @@ pub struct VirtualMachine {
pub sys_module: PyObjectRef,
pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc>,
pub ctx: PyContext,
pub current_frame: Option<PyObjectRef>,
}
impl VirtualMachine {
@@ -51,6 +52,7 @@ impl VirtualMachine {
sys_module: sysmod,
stdlib_inits,
ctx: ctx,
current_frame: None,
}
}