Skip to content

Commit 75eabfd

Browse files
authored
Merge pull request RustPython#1787 from youknowone/posonly
PEP570 - positional only parameter support
2 parents 1fd1c19 + b4f0ced commit 75eabfd

File tree

8 files changed

+1893
-28
lines changed

8 files changed

+1893
-28
lines changed

Lib/test/test_grammar.py

Lines changed: 1828 additions & 0 deletions
Large diffs are not rendered by default.

bytecode/src/bytecode.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ pub struct CodeObject {
3838
pub label_map: HashMap<Label, usize>,
3939
pub locations: Vec<Location>,
4040
pub flags: CodeFlags,
41-
pub arg_names: Vec<String>, // Names of positional arguments
42-
pub varargs: Varargs, // *args or *
41+
pub posonlyarg_count: usize, // Number of positional-only arguments
42+
pub arg_names: Vec<String>, // Names of positional arguments
43+
pub varargs: Varargs, // *args or *
4344
pub kwonlyarg_names: Vec<String>,
4445
pub varkeywords: Varargs, // **kwargs or **
4546
pub source_path: String,
@@ -370,6 +371,7 @@ impl CodeObject {
370371
#[allow(clippy::too_many_arguments)]
371372
pub fn new(
372373
flags: CodeFlags,
374+
posonlyarg_count: usize,
373375
arg_names: Vec<String>,
374376
varargs: Varargs,
375377
kwonlyarg_names: Vec<String>,
@@ -383,6 +385,7 @@ impl CodeObject {
383385
label_map: HashMap::new(),
384386
locations: Vec::new(),
385387
flags,
388+
posonlyarg_count,
386389
arg_names,
387390
varargs,
388391
kwonlyarg_names,

compiler/src/compile.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ impl<O: OutputStream> Compiler<O> {
165165
let line_number = self.get_source_line_number();
166166
self.push_output(CodeObject::new(
167167
Default::default(),
168+
0,
168169
Vec::new(),
169170
Varargs::None,
170171
Vec::new(),
@@ -695,6 +696,7 @@ impl<O: OutputStream> Compiler<O> {
695696
let line_number = self.get_source_line_number();
696697
self.push_output(CodeObject::new(
697698
flags,
699+
args.posonlyargs_count,
698700
args.args.iter().map(|a| a.arg.clone()).collect(),
699701
compile_varargs(&args.vararg),
700702
args.kwonlyargs.iter().map(|a| a.arg.clone()).collect(),
@@ -976,6 +978,7 @@ impl<O: OutputStream> Compiler<O> {
976978
let line_number = self.get_source_line_number();
977979
self.push_output(CodeObject::new(
978980
Default::default(),
981+
0,
979982
vec![],
980983
Varargs::None,
981984
vec![],
@@ -1933,6 +1936,7 @@ impl<O: OutputStream> Compiler<O> {
19331936
// Create magnificent function <listcomp>:
19341937
self.push_output(CodeObject::new(
19351938
Default::default(),
1939+
1,
19361940
vec![".0".to_owned()],
19371941
Varargs::None,
19381942
vec![],

parser/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ impl Expression {
374374
/// distinguish between function parameters and actual call arguments.
375375
#[derive(Debug, PartialEq, Default)]
376376
pub struct Parameters {
377+
pub posonlyargs_count: usize,
377378
pub args: Vec<Parameter>,
378379
pub kwonlyargs: Vec<Parameter>,
379380
pub vararg: Varargs, // Optionally we handle optionally named '*args' or '*'

parser/src/function.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ type ParameterDefs = (Vec<ast::Parameter>, Vec<ast::Expression>);
77
type ParameterDef = (ast::Parameter, Option<ast::Expression>);
88

99
#[allow(clippy::collapsible_if)]
10-
pub fn parse_params(params: Vec<ParameterDef>) -> Result<ParameterDefs, LexicalError> {
10+
pub fn parse_params(
11+
params: (Vec<ParameterDef>, Vec<ParameterDef>),
12+
) -> Result<ParameterDefs, LexicalError> {
1113
let mut names = vec![];
1214
let mut defaults = vec![];
1315

14-
for (name, default) in params {
16+
let mut try_default = |name: &ast::Parameter, default| {
1517
if let Some(default) = default {
1618
defaults.push(default);
1719
} else {
@@ -20,10 +22,20 @@ pub fn parse_params(params: Vec<ParameterDef>) -> Result<ParameterDefs, LexicalE
2022
// have defaults
2123
return Err(LexicalError {
2224
error: LexicalErrorType::DefaultArgumentError,
23-
location: name.location,
25+
location: name.location.clone(),
2426
});
2527
}
2628
}
29+
Ok(())
30+
};
31+
32+
for (name, default) in params.0 {
33+
try_default(&name, default)?;
34+
names.push(name);
35+
}
36+
37+
for (name, default) in params.1 {
38+
try_default(&name, default)?;
2739
names.push(name);
2840
}
2941

parser/src/parser.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ mod tests {
258258
location: ast::Location::new(1, 1),
259259
node: ast::ExpressionType::Lambda {
260260
args: Box::new(ast::Parameters {
261+
posonlyargs_count: 0,
261262
args: vec![
262263
ast::Parameter {
263264
location: ast::Location::new(1, 8),
@@ -335,6 +336,7 @@ mod tests {
335336
is_async: false,
336337
name: String::from("__init__"),
337338
args: Box::new(ast::Parameters {
339+
posonlyargs_count: 0,
338340
args: vec![ast::Parameter {
339341
location: ast::Location::new(2, 15),
340342
arg: String::from("self"),
@@ -360,6 +362,7 @@ mod tests {
360362
is_async: false,
361363
name: String::from("method_with_default"),
362364
args: Box::new(ast::Parameters {
365+
posonlyargs_count: 0,
363366
args: vec![
364367
ast::Parameter {
365368
location: ast::Location::new(4, 26),

parser/src/python.lalrpop

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -456,22 +456,25 @@ Parameters: ast::Parameters = {
456456
// once for lambda defs.
457457
ParameterList<ArgType>: ast::Parameters = {
458458
<param1:ParameterDefs<ArgType>> <args2:("," ParameterListStarArgs<ArgType>)?> ","? =>? {
459-
let (names, default_elements) = parse_params(param1)?;
459+
let posonlyargs_count = param1.0.len();
460+
let (names, defaults) = parse_params(param1)?;
460461

461462
// Now gather rest of parameters:
462463
let (vararg, kwonlyargs, kw_defaults, kwarg) = args2.map_or((None, vec![], vec![], None), |x| x.1);
463464

464465
Ok(ast::Parameters {
466+
posonlyargs_count,
465467
args: names,
466468
kwonlyargs,
467469
vararg: vararg.into(),
468470
kwarg: kwarg.into(),
469-
defaults: default_elements,
470-
kw_defaults: kw_defaults,
471+
defaults,
472+
kw_defaults,
471473
})
472474
},
473475
<param1:ParameterDefs<ArgType>> <kw:("," KwargParameter<ArgType>)> ","? =>? {
474-
let (names, default_elements) = parse_params(param1)?;
476+
let posonlyargs_count = param1.0.len();
477+
let (names, defaults) = parse_params(param1)?;
475478

476479
// Now gather rest of parameters:
477480
let vararg = None;
@@ -480,27 +483,30 @@ ParameterList<ArgType>: ast::Parameters = {
480483
let kwarg = Some(kw.1);
481484

482485
Ok(ast::Parameters {
486+
posonlyargs_count,
483487
args: names,
484488
kwonlyargs,
485489
vararg: vararg.into(),
486490
kwarg: kwarg.into(),
487-
defaults: default_elements,
488-
kw_defaults: kw_defaults,
491+
defaults,
492+
kw_defaults,
489493
})
490494
},
491495
<params:ParameterListStarArgs<ArgType>> ","? => {
492496
let (vararg, kwonlyargs, kw_defaults, kwarg) = params;
493497
ast::Parameters {
498+
posonlyargs_count: 0,
494499
args: vec![],
495500
kwonlyargs,
496501
vararg: vararg.into(),
497502
kwarg: kwarg.into(),
498503
defaults: vec![],
499-
kw_defaults: kw_defaults,
504+
kw_defaults,
500505
}
501506
},
502507
<kw:KwargParameter<ArgType>> ","? => {
503508
ast::Parameters {
509+
posonlyargs_count: 0,
504510
args: vec![],
505511
kwonlyargs: vec![],
506512
vararg: ast::Varargs::None,
@@ -513,10 +519,13 @@ ParameterList<ArgType>: ast::Parameters = {
513519

514520
// Use inline here to make sure the "," is not creating an ambiguity.
515521
#[inline]
516-
ParameterDefs<ArgType>: Vec<(ast::Parameter, Option<ast::Expression>)> = {
522+
ParameterDefs<ArgType>: (Vec<(ast::Parameter, Option<ast::Expression>)>, Vec<(ast::Parameter, Option<ast::Expression>)>) = {
517523
<args:OneOrMore<ParameterDef<ArgType>>> => {
518-
args
519-
}
524+
(vec![], args)
525+
},
526+
<pos_args:OneOrMore<ParameterDef<ArgType>>> "," "/" <args:("," ParameterDef<ArgType>)*> => {
527+
(pos_args, args.into_iter().map(|e| e.1).collect())
528+
},
520529
};
521530

522531
ParameterDef<ArgType>: (ast::Parameter, Option<ast::Expression>) = {

vm/src/obj/objcode.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ use std::ops::Deref;
77

88
use super::objtype::PyClassRef;
99
use crate::bytecode;
10-
use crate::pyobject::{IdProtocol, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
10+
use crate::pyobject::{IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
1111
use crate::vm::VirtualMachine;
1212

1313
pub type PyCodeRef = PyRef<PyCode>;
1414

15+
#[pyclass]
1516
pub struct PyCode {
1617
pub code: bytecode::CodeObject,
1718
}
@@ -41,12 +42,15 @@ impl PyValue for PyCode {
4142
}
4243
}
4344

45+
#[pyimpl]
4446
impl PyCodeRef {
47+
#[pyslot]
4548
#[allow(clippy::new_ret_no_self)]
4649
fn new(_cls: PyClassRef, vm: &VirtualMachine) -> PyResult {
4750
Err(vm.new_type_error("Cannot directly create code object".to_owned()))
4851
}
4952

53+
#[pymethod(magic)]
5054
fn repr(self) -> String {
5155
let code = &self.code;
5256
format!(
@@ -58,22 +62,32 @@ impl PyCodeRef {
5862
)
5963
}
6064

65+
#[pyproperty]
66+
fn co_posonlyargcount(self) -> usize {
67+
self.code.posonlyarg_count
68+
}
69+
70+
#[pyproperty]
6171
fn co_argcount(self) -> usize {
6272
self.code.arg_names.len()
6373
}
6474

75+
#[pyproperty]
6576
fn co_filename(self) -> String {
6677
self.code.source_path.clone()
6778
}
6879

80+
#[pyproperty]
6981
fn co_firstlineno(self) -> usize {
7082
self.code.first_line_number
7183
}
7284

85+
#[pyproperty]
7386
fn co_kwonlyargcount(self) -> usize {
7487
self.code.kwonlyarg_names.len()
7588
}
7689

90+
#[pyproperty]
7791
fn co_consts(self, vm: &VirtualMachine) -> PyObjectRef {
7892
let consts = self
7993
.code
@@ -83,26 +97,17 @@ impl PyCodeRef {
8397
vm.ctx.new_tuple(consts)
8498
}
8599

100+
#[pyproperty]
86101
fn co_name(self) -> String {
87102
self.code.obj_name.clone()
88103
}
89104

105+
#[pyproperty]
90106
fn co_flags(self) -> u8 {
91107
self.code.flags.bits()
92108
}
93109
}
94110

95111
pub fn init(ctx: &PyContext) {
96-
extend_class!(ctx, &ctx.types.code_type, {
97-
(slot new) => PyCodeRef::new,
98-
"__repr__" => ctx.new_method(PyCodeRef::repr),
99-
100-
"co_argcount" => ctx.new_readonly_getset("co_argcount", PyCodeRef::co_argcount),
101-
"co_consts" => ctx.new_readonly_getset("co_consts", PyCodeRef::co_consts),
102-
"co_filename" => ctx.new_readonly_getset("co_filename", PyCodeRef::co_filename),
103-
"co_firstlineno" => ctx.new_readonly_getset("co_firstlineno", PyCodeRef::co_firstlineno),
104-
"co_kwonlyargcount" => ctx.new_readonly_getset("co_kwonlyargcount", PyCodeRef::co_kwonlyargcount),
105-
"co_name" => ctx.new_readonly_getset("co_name", PyCodeRef::co_name),
106-
"co_flags" => ctx.new_readonly_getset("co_flags", PyCodeRef::co_flags),
107-
});
112+
PyCodeRef::extend_class(ctx, &ctx.types.code_type);
108113
}

0 commit comments

Comments
 (0)