Skip to content

Commit 9b29ae0

Browse files
Merge pull request RustPython#96 from OddBloke/macro
Introduce optional parameter support in arg_checks!
2 parents 9b1c44e + 970acbe commit 9b29ae0

5 files changed

Lines changed: 97 additions & 29 deletions

File tree

vm/src/builtins.rs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn builtin_any(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
7272
// builtin_callable
7373

7474
fn builtin_chr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
75-
arg_check!(vm, args, (i, Some(vm.ctx.int_type.clone())));
75+
arg_check!(vm, args, required = [(i, Some(vm.ctx.int_type.clone()))]);
7676

7777
let code_point_obj = i.borrow();
7878

@@ -95,7 +95,7 @@ fn builtin_chr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
9595
// builtin_classmethod
9696

9797
fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
98-
arg_check!(vm, args, (source, None));
98+
arg_check!(vm, args, required = [(source, None)]);
9999
// TODO:
100100
let mode = compile::Mode::Eval;
101101
let source = source.borrow().str();
@@ -125,9 +125,11 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
125125
arg_check!(
126126
vm,
127127
args,
128-
(source, None), // TODO: Use more specific type
129-
(_globals, Some(vm.ctx.dict_type.clone())),
130-
(locals, Some(vm.ctx.dict_type.clone()))
128+
required = [
129+
(source, None), // TODO: Use more specific type
130+
(_globals, Some(vm.ctx.dict_type.clone())),
131+
(locals, Some(vm.ctx.dict_type.clone()))
132+
]
131133
);
132134
// TODO: handle optional global and locals
133135

@@ -154,7 +156,11 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
154156
// builtin_frozenset
155157

156158
fn builtin_getattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
157-
arg_check!(vm, args, (obj, None), (attr, Some(vm.ctx.str_type.clone())));
159+
arg_check!(
160+
vm,
161+
args,
162+
required = [(obj, None), (attr, Some(vm.ctx.str_type.clone()))]
163+
);
158164
if let PyObjectKind::String { ref value } = attr.borrow().kind {
159165
vm.get_attribute(obj.clone(), value)
160166
} else {
@@ -165,7 +171,11 @@ fn builtin_getattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
165171
// builtin_globals
166172

167173
fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
168-
arg_check!(vm, args, (obj, None), (attr, Some(vm.ctx.str_type.clone())));
174+
arg_check!(
175+
vm,
176+
args,
177+
required = [(obj, None), (attr, Some(vm.ctx.str_type.clone()))]
178+
);
169179
if let PyObjectKind::String { ref value } = attr.borrow().kind {
170180
let has_attr = match vm.get_attribute(obj.clone(), value) {
171181
Ok(..) => true,
@@ -182,7 +192,7 @@ fn builtin_hasattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
182192
// builtin_hex
183193

184194
fn builtin_id(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
185-
arg_check!(vm, args, (obj, None));
195+
arg_check!(vm, args, required = [(obj, None)]);
186196

187197
Ok(vm.context().new_int(obj.get_id() as i32))
188198
}
@@ -191,7 +201,7 @@ fn builtin_id(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
191201
// builtin_int
192202

193203
fn builtin_isinstance(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
194-
arg_check!(vm, args, (obj, None), (typ, None));
204+
arg_check!(vm, args, required = [(obj, None), (typ, None)]);
195205

196206
let isinstance = objtype::isinstance(obj.clone(), typ.clone());
197207
Ok(vm.context().new_bool(isinstance))
@@ -211,7 +221,7 @@ fn builtin_issubclass(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
211221
// builtin_iter
212222

213223
fn builtin_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
214-
arg_check!(vm, args, (obj, None));
224+
arg_check!(vm, args, required = [(obj, None)]);
215225
match obj.borrow().kind {
216226
PyObjectKind::Dict { ref elements } => Ok(vm.context().new_int(elements.len() as i32)),
217227
PyObjectKind::Tuple { ref elements } => Ok(vm.context().new_int(elements.len() as i32)),
@@ -262,7 +272,11 @@ pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
262272
// builtin_property
263273

264274
fn builtin_range(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
265-
arg_check!(vm, args, (range, Some(vm.ctx.int_type.clone())));
275+
arg_check!(
276+
vm,
277+
args,
278+
required = [(range, Some(vm.ctx.int_type.clone()))]
279+
);
266280
match range.borrow().kind {
267281
PyObjectKind::Integer { ref value } => {
268282
let range_elements: Vec<PyObjectRef> =
@@ -282,9 +296,11 @@ fn builtin_setattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
282296
arg_check!(
283297
vm,
284298
args,
285-
(obj, None),
286-
(attr, Some(vm.ctx.str_type.clone())),
287-
(value, None)
299+
required = [
300+
(obj, None),
301+
(attr, Some(vm.ctx.str_type.clone())),
302+
(value, None)
303+
]
288304
);
289305
if let PyObjectKind::String { value: ref name } = attr.borrow().kind {
290306
obj.clone().set_attr(name, value.clone());

vm/src/macros.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ macro_rules! arg_check {
66
"Expected no arguments (got: {})", $args.args.len())));
77
}
88
};
9-
( $vm: ident, $args:ident, $( ($arg_name:ident, $arg_type:expr) ),* ) => {
9+
( $vm: ident, $args:ident, required=[$( ($arg_name:ident, $arg_type:expr) ),*] ) => {
10+
arg_check!($vm, $args, required=[$( ($arg_name, $arg_type) ),*], optional=[]);
11+
};
12+
( $vm: ident, $args:ident, required=[$( ($arg_name:ident, $arg_type:expr) ),*], optional=[$( ($optional_arg_name:ident, $optional_arg_type:expr) ),*] ) => {
1013
let mut expected_args: Vec<(usize, &str, Option<PyObjectRef>)> = vec![];
1114
let mut arg_count = 0;
1215

@@ -26,10 +29,31 @@ macro_rules! arg_check {
2629
}
2730
)*
2831

29-
if $args.args.len() != expected_args.len() {
32+
let minimum_arg_count = arg_count;
33+
34+
$(
35+
let $optional_arg_name = if arg_count < $args.args.len() {
36+
expected_args.push((arg_count, stringify!($optional_arg_name), $optional_arg_type));
37+
let ret = Some(&$args.args[arg_count]);
38+
#[allow(unused_assignments)]
39+
{
40+
arg_count += 1;
41+
}
42+
ret
43+
} else {
44+
None
45+
};
46+
)*
47+
48+
if $args.args.len() < minimum_arg_count || $args.args.len() > expected_args.len() {
49+
let expected_str = if minimum_arg_count == arg_count {
50+
format!("{}", arg_count)
51+
} else {
52+
format!("{}-{}", minimum_arg_count, arg_count)
53+
};
3054
return Err($vm.new_type_error(format!(
3155
"Expected {} arguments (got: {})",
32-
expected_args.len(),
56+
expected_str,
3357
$args.args.len()
3458
)));
3559
};

vm/src/objbool.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::objtype;
22
use super::pyobject::{
3-
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult,
3+
AttributeProtocol, PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
44
};
55
use super::vm::VirtualMachine;
66

@@ -37,9 +37,17 @@ pub fn init(context: &PyContext) {
3737
}
3838

3939
fn bool_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
40-
if args.args.len() == 1 {
41-
return Ok(vm.context().new_bool(false));
42-
}
43-
let ref value = boolval(vm, args.args[1].clone())?;
44-
Ok(vm.new_bool(value.clone()))
40+
arg_check!(
41+
vm,
42+
args,
43+
required = [(_zelf, Some(vm.ctx.type_type.clone()))],
44+
optional = [(val, None)]
45+
);
46+
Ok(match val {
47+
Some(val) => {
48+
let bv = boolval(vm, val.clone())?;
49+
vm.new_bool(bv.clone())
50+
}
51+
None => vm.context().new_bool(false),
52+
})
4553
}

vm/src/objlist.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ pub fn set_item(
2727

2828
pub fn append(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
2929
trace!("list.append called with: {:?}", args);
30-
arg_check!(vm, args, (list, Some(vm.ctx.list_type.clone())), (x, None));
30+
arg_check!(
31+
vm,
32+
args,
33+
required = [(list, Some(vm.ctx.list_type.clone())), (x, None)]
34+
);
3135
let mut list_obj = list.borrow_mut();
3236
if let PyObjectKind::List { ref mut elements } = list_obj.kind {
3337
elements.push(x.clone());
@@ -39,7 +43,11 @@ pub fn append(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
3943

4044
fn clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
4145
trace!("list.clear called with: {:?}", args);
42-
arg_check!(vm, args, (list, Some(vm.ctx.list_type.clone())));
46+
arg_check!(
47+
vm,
48+
args,
49+
required = [(list, Some(vm.ctx.list_type.clone()))]
50+
);
4351
let mut list_obj = list.borrow_mut();
4452
if let PyObjectKind::List { ref mut elements } = list_obj.kind {
4553
elements.clear();
@@ -51,7 +59,11 @@ fn clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5159

5260
fn len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
5361
trace!("list.len called with: {:?}", args);
54-
arg_check!(vm, args, (list, Some(vm.ctx.list_type.clone())));
62+
arg_check!(
63+
vm,
64+
args,
65+
required = [(list, Some(vm.ctx.list_type.clone()))]
66+
);
5567
let list_obj = list.borrow();
5668
if let PyObjectKind::List { ref elements } = list_obj.kind {
5769
Ok(vm.context().new_int(elements.len() as i32))
@@ -62,7 +74,11 @@ fn len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6274

6375
fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
6476
trace!("list.reverse called with: {:?}", args);
65-
arg_check!(vm, args, (list, Some(vm.ctx.list_type.clone())));
77+
arg_check!(
78+
vm,
79+
args,
80+
required = [(list, Some(vm.ctx.list_type.clone()))]
81+
);
6682
let mut list_obj = list.borrow_mut();
6783
if let PyObjectKind::List { ref mut elements } = list_obj.kind {
6884
elements.reverse();

vm/src/stdlib/json.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,19 @@ impl<'de> serde::Deserialize<'de> for PyObjectKind {
170170

171171
fn dumps(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
172172
// TODO: Implement non-trivial serialisation case
173-
arg_check!(vm, args, (obj, None));
173+
arg_check!(vm, args, required = [(obj, None)]);
174174
// TODO: Raise an exception for serialisation errors
175175
let string = serde_json::to_string(&obj.borrow().kind).unwrap();
176176
Ok(vm.context().new_str(string))
177177
}
178178

179179
fn loads(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
180180
// TODO: Implement non-trivial deserialisation case
181-
arg_check!(vm, args, (string, Some(vm.ctx.str_type.clone())));
181+
arg_check!(
182+
vm,
183+
args,
184+
required = [(string, Some(vm.ctx.str_type.clone()))]
185+
);
182186
// TODO: Raise an exception for deserialisation errors
183187
let kind: PyObjectKind = match string.borrow().kind {
184188
PyObjectKind::String { ref value } => serde_json::from_str(&value).unwrap(),

0 commit comments

Comments
 (0)