Skip to content

Commit 7728ee1

Browse files
committed
Minor change to keyword arguments in function call
1 parent 2f424eb commit 7728ee1

File tree

5 files changed

+86
-57
lines changed

5 files changed

+86
-57
lines changed

parser/src/ast.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ pub enum Statement {
9696
name: String,
9797
body: Vec<LocatedStatement>,
9898
args: Vec<(String, Option<Expression>)>,
99+
// TODO: bases: Vec<Expression>,
100+
// TODO: keywords: Vec<Keyword>,
99101
decorator_list: Vec<Expression>,
100102
// TODO: docstring: String,
101103
},
@@ -148,8 +150,8 @@ pub enum Expression {
148150
},
149151
Call {
150152
function: Box<Expression>,
151-
// parameters are (None, value), kwargs are (keyword name, value)
152-
args: Vec<(Option<String>, Expression)>,
153+
args: Vec<Expression>,
154+
keywords: Vec<Keyword>,
153155
},
154156
Number {
155157
value: Number,
@@ -181,6 +183,12 @@ pub enum Expression {
181183
None,
182184
}
183185

186+
#[derive(Debug, PartialEq, Clone)]
187+
pub struct Keyword {
188+
pub name: Option<String>,
189+
pub value: Expression,
190+
}
191+
184192
#[derive(Debug, PartialEq)]
185193
pub struct ExceptHandler {
186194
pub typ: Option<Expression>,

parser/src/parser.rs

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,10 @@ mod tests {
9595
function: Box::new(ast::Expression::Identifier {
9696
name: String::from("print"),
9797
}),
98-
args: vec![(
99-
None,
100-
ast::Expression::String {
101-
value: String::from("Hello world"),
102-
}
103-
),],
98+
args: vec![ast::Expression::String {
99+
value: String::from("Hello world"),
100+
}],
101+
keywords: vec![],
104102
},
105103
},
106104
},],
@@ -123,19 +121,14 @@ mod tests {
123121
name: String::from("print"),
124122
}),
125123
args: vec![
126-
(
127-
None,
128-
ast::Expression::String {
129-
value: String::from("Hello world"),
130-
}
131-
),
132-
(
133-
None,
134-
ast::Expression::Number {
135-
value: ast::Number::Integer { value: 2 },
136-
}
137-
),
124+
ast::Expression::String {
125+
value: String::from("Hello world"),
126+
},
127+
ast::Expression::Number {
128+
value: ast::Number::Integer { value: 2 },
129+
}
138130
],
131+
keywords: vec![],
139132
},
140133
},
141134
},],
@@ -157,20 +150,15 @@ mod tests {
157150
function: Box::new(ast::Expression::Identifier {
158151
name: String::from("my_func"),
159152
}),
160-
args: vec![
161-
(
162-
None,
163-
ast::Expression::String {
164-
value: String::from("positional"),
165-
}
166-
),
167-
(
168-
Some("keyword".to_string()),
169-
ast::Expression::Number {
170-
value: ast::Number::Integer { value: 2 },
171-
}
172-
),
173-
],
153+
args: vec![ast::Expression::String {
154+
value: String::from("positional"),
155+
}],
156+
keywords: vec![ast::Keyword {
157+
name: Some("keyword".to_string()),
158+
value: ast::Expression::Number {
159+
value: ast::Number::Integer { value: 2 },
160+
}
161+
}],
174162
},
175163
},
176164
},],

parser/src/python.lalrpop

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
// See also: file:///usr/share/doc/python/html/reference/grammar.html?highlight=grammar
2+
// See also: https://github.com/antlr/grammars-v4/blob/master/python3/Python3.g4
3+
// See also: file:///usr/share/doc/python/html/reference/compound_stmts.html#function-definitions
4+
// See also: https://greentreesnakes.readthedocs.io/en/latest/nodes.html#keyword
25
#![allow(unknown_lints,clippy)]
36

47
use super::ast;
@@ -408,12 +411,13 @@ ClassDef: ast::LocatedStatement = {
408411

409412
// Decorators:
410413
Decorator: ast::Expression = {
411-
"@" <n:DottedName> <a: ("(" FunctionArguments ")")?> "\n" => {
414+
"@" <n:DottedName> <a: ("(" ArgumentList ")")?> "\n" => {
412415
let name = ast::Expression::Identifier { name: n };
413416
match a {
414417
Some((_, args, _)) => ast::Expression::Call {
415418
function: Box::new(name),
416-
args: args,
419+
args: args.0,
420+
keywords: args.1,
417421
},
418422
None => name,
419423
}
@@ -529,7 +533,7 @@ Power: ast::Expression = {
529533

530534
AtomExpr: ast::Expression = {
531535
<e:Atom> => e,
532-
<f:AtomExpr> "(" <a:FunctionArguments> ")" => ast::Expression::Call { function: Box::new(f), args: a },
536+
<f:AtomExpr> "(" <a:ArgumentList> ")" => ast::Expression::Call { function: Box::new(f), args: a.0, keywords: a.1 },
533537
<e:AtomExpr> "[" <s:Subscript> "]" => ast::Expression::Subscript { a: Box::new(e), b: Box::new(s) },
534538
<e:AtomExpr> "." <n:Identifier> => ast::Expression::Attribute { value: Box::new(e), name: n },
535539
};
@@ -602,8 +606,25 @@ TestList: Vec<ast::Expression> = {
602606
}
603607
};
604608

605-
FunctionArguments: Vec<(Option<String>, ast::Expression)> = {
606-
<e: Comma<FunctionArgument>> => e,
609+
ArgumentList: (Vec<ast::Expression>, Vec<ast::Keyword>) = {
610+
<e: Comma<FunctionArgument>> => {
611+
let mut args = vec![];
612+
let mut keywords = vec![];
613+
for (name, value) in e {
614+
match name {
615+
Some(n) => {
616+
keywords.push(ast::Keyword { name: Some(n), value: value });
617+
},
618+
None => {
619+
if keywords.len() > 0 {
620+
panic!("positional argument follows keyword argument");
621+
};
622+
args.push(value);
623+
},
624+
}
625+
}
626+
(args, keywords)
627+
}
607628
};
608629

609630
FunctionArgument: (Option<String>, ast::Expression) = {

vm/src/compile.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -700,21 +700,33 @@ impl Compiler {
700700
fn compile_expression(&mut self, expression: &ast::Expression) {
701701
trace!("Compiling {:?}", expression);
702702
match expression {
703-
ast::Expression::Call { function, args } => {
703+
ast::Expression::Call {
704+
function,
705+
args,
706+
keywords,
707+
} => {
704708
self.compile_expression(&*function);
705-
let count = args.len();
706-
let mut kwarg_names = vec![];
707-
for (kwarg, value) in args {
708-
if let Some(kwarg) = kwarg {
709-
kwarg_names.push(bytecode::Constant::String {
710-
value: kwarg.to_string(),
711-
});
712-
} else if kwarg_names.len() > 0 {
713-
panic!("positional argument follows keyword argument");
714-
};
709+
let count = args.len() + keywords.len();
710+
711+
// Normal arguments:
712+
for value in args {
715713
self.compile_expression(value);
716714
}
717-
if kwarg_names.len() > 0 {
715+
716+
// Keyword arguments:
717+
if keywords.len() > 0 {
718+
let mut kwarg_names = vec![];
719+
for keyword in keywords {
720+
if let Some(name) = &keyword.name {
721+
kwarg_names.push(bytecode::Constant::String {
722+
value: name.to_string(),
723+
});
724+
} else {
725+
panic!("name must be set");
726+
}
727+
self.compile_expression(&keyword.value);
728+
}
729+
718730
self.emit(Instruction::LoadConst {
719731
value: bytecode::Constant::Tuple {
720732
elements: kwarg_names,

vm/src/stdlib/ast.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,17 +235,17 @@ fn expressions_to_ast(ctx: &PyContext, expressions: &Vec<ast::Expression>) -> Py
235235

236236
fn expression_to_ast(ctx: &PyContext, expression: &ast::Expression) -> PyObjectRef {
237237
let node = match &expression {
238-
ast::Expression::Call { function, args } => {
238+
ast::Expression::Call {
239+
function,
240+
args,
241+
keywords: _,
242+
} => {
239243
let node = create_node(ctx, "Call");
240244

241245
let py_func_ast = expression_to_ast(ctx, function);
242246
node.set_attr("func", py_func_ast);
243247

244-
let mut py_args = vec![];
245-
for arg in args {
246-
py_args.push(expression_to_ast(ctx, &arg.1));
247-
}
248-
let py_args = ctx.new_list(py_args);
248+
let py_args = expressions_to_ast(ctx, args);
249249
node.set_attr("args", py_args);
250250

251251
node

0 commit comments

Comments
 (0)