Add parsing for star arg parameters.

This commit is contained in:
Windel Bouwman
2018-10-20 11:47:23 +02:00
parent e92ba94c61
commit ae768c7fe6
5 changed files with 117 additions and 11 deletions

View File

@@ -198,11 +198,14 @@ pub enum Expression {
* In cpython this is called arguments, but we choose parameters to
* distuingish between function parameters and actual call arguments.
*/
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Default)]
pub struct Parameters {
pub args: Vec<String>,
pub kwonlyargs: Vec<String>,
pub vararg: Option<String>,
pub kwarg: Option<String>,
pub defaults: Vec<Expression>,
pub kw_defaults: Vec<Option<Expression>>,
}
#[derive(Debug, PartialEq)]

View File

@@ -228,8 +228,11 @@ mod tests {
expression: ast::Expression::Lambda {
args: ast::Parameters {
args: vec![String::from("x"), String::from("y")],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
defaults: vec![],
kw_defaults: vec![],
},
body: Box::new(ast::Expression::Binop {
a: Box::new(ast::Expression::Identifier {
@@ -305,8 +308,11 @@ mod tests {
name: String::from("__init__"),
args: ast::Parameters {
args: vec![String::from("self")],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
defaults: vec![],
kw_defaults: vec![],
},
body: vec![ast::LocatedStatement {
location: ast::Location::new(3, 3),
@@ -321,10 +327,13 @@ mod tests {
name: String::from("method_with_default"),
args: ast::Parameters {
args: vec![String::from("self"), String::from("arg"),],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
defaults: vec![ast::Expression::String {
value: "default".to_string()
}]
}],
kw_defaults: vec![],
},
body: vec![ast::LocatedStatement {
location: ast::Location::new(5, 3),

View File

@@ -407,13 +407,22 @@ FuncDef: ast::LocatedStatement = {
};
Parameters: ast::Parameters = {
"(" <a: TypedArgsList> ")" => a,
"(" <a: (TypedArgsList)?> ")" => {
match a {
Some(a) => a,
None => Default::default(),
}
},
};
// parameters are (String, None), kwargs are (String, Some(Test)) where Test is
// the default
TypedArgsList: ast::Parameters = {
<args: Comma<Parameter>> => {
<param1:TypedParameterDef> <param2:("," TypedParameterDef)*> <args2:("," ParameterListStarArgs)?> => {
// Combine first parameters:
let mut args = vec![param1];
args.extend(param2.into_iter().map(|x| x.1));
let mut names = vec![];
let mut default_elements = vec![];
@@ -433,17 +442,71 @@ TypedArgsList: ast::Parameters = {
}
}
// Now gather rest of parameters:
let (vararg, kwonlyargs, kw_defaults, kwarg) = match args2 {
Some((_, x)) => x,
None => (None, vec![], vec![], None),
};
ast::Parameters {
args: names,
vararg: None,
kwonlyargs: kwonlyargs,
vararg: vararg,
kwarg: kwarg,
defaults: default_elements,
kw_defaults: kw_defaults,
}
}
},
<params:ParameterListStarArgs> => {
let (vararg, kwonlyargs, kw_defaults, kwarg) = params;
ast::Parameters {
args: vec![],
kwonlyargs: kwonlyargs,
vararg: vararg,
kwarg: kwarg,
defaults: vec![],
kw_defaults: kw_defaults,
}
},
"**" <kw:Identifier> => {
ast::Parameters {
args: vec![],
kwonlyargs: vec![],
vararg: None,
kwarg: Some(kw),
defaults: vec![],
kw_defaults: vec![],
}
},
};
Parameter: (String, Option<ast::Expression>) = {
<i:Identifier> => (i.clone(), None),
<i:Identifier> "=" <e:Test> => (i.clone(), Some(e)),
TypedParameterDef: (String, Option<ast::Expression>) = {
<i:TypedParameter> => (i, None),
<i:TypedParameter> "=" <e:Test> => (i, Some(e)),
};
// TODO: add type annotations here:
TypedParameter: String = {
Identifier,
};
ParameterListStarArgs: (Option<String>, Vec<String>, Vec<Option<ast::Expression>>, Option<String>) = {
"*" <va:Identifier> <kw:("," TypedParameterDef)*> <kwarg:("," "**" Identifier)?> => {
// Extract keyword arguments:
let mut kwonlyargs = vec![];
let mut kw_defaults = vec![];
for (name, value) in kw.into_iter().map(|x| x.1) {
kwonlyargs.push(name);
kw_defaults.push(value);
}
let kwarg = match kwarg {
Some((_, _, name)) => Some(name),
None => None,
};
(Some(va), kwonlyargs, kw_defaults, kwarg)
}
};
ClassDef: ast::LocatedStatement = {
@@ -505,9 +568,9 @@ Test: ast::Expression = {
};
LambdaDef: ast::Expression = {
"lambda" <p:TypedArgsList> ":" <b:Expression> =>
"lambda" <p:TypedArgsList?> ":" <b:Expression> =>
ast::Expression::Lambda {
args:p,
args: p.unwrap_or(Default::default()),
body:Box::new(b)
}
}

View File

@@ -2,3 +2,11 @@
a = 1
del a
class MyObject: pass
foo = MyObject()
foo.bar = 2
assert hasattr(foo, 'bar')
del foo.bar
assert not hasattr(foo, 'bar')

View File

@@ -49,6 +49,28 @@ fn object_ne(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
objbool::not(vm, &eq)
}
// TODO: is object the right place for delattr?
fn object_delattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [
(zelf, Some(vm.ctx.object())),
(attr, Some(vm.ctx.str_type()))
]
);
// Get dict:
let dict = match zelf.borrow().kind {
PyObjectKind::Class { ref dict, .. } => dict.clone(),
PyObjectKind::Instance { ref dict, .. } => dict.clone(),
_ => return Err(vm.new_type_error("TypeError: no dictionary.".to_string())),
};
// Delete attr from dict:
vm.call_method(&dict, "__delitem__", vec![attr.clone()])
}
fn object_str(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.object()))]);
vm.call_method(zelf, "__repr__", vec![])
@@ -67,6 +89,7 @@ pub fn init(context: &PyContext) {
object.set_attr("__init__", context.new_rustfunc(object_init));
object.set_attr("__eq__", context.new_rustfunc(object_eq));
object.set_attr("__ne__", context.new_rustfunc(object_ne));
object.set_attr("__delattr__", context.new_rustfunc(object_delattr));
object.set_attr("__dict__", context.new_member_descriptor(object_dict));
object.set_attr("__str__", context.new_rustfunc(object_str));
object.set_attr("__repr__", context.new_rustfunc(object_repr));