forked from Rust-related/RustPython
positional only parameter support
This commit is contained in:
@@ -38,8 +38,9 @@ pub struct CodeObject {
|
||||
pub label_map: HashMap<Label, usize>,
|
||||
pub locations: Vec<Location>,
|
||||
pub flags: CodeFlags,
|
||||
pub arg_names: Vec<String>, // Names of positional arguments
|
||||
pub varargs: Varargs, // *args or *
|
||||
pub posonlyarg_count: usize, // Number of positional-only arguments
|
||||
pub arg_names: Vec<String>, // Names of positional arguments
|
||||
pub varargs: Varargs, // *args or *
|
||||
pub kwonlyarg_names: Vec<String>,
|
||||
pub varkeywords: Varargs, // **kwargs or **
|
||||
pub source_path: String,
|
||||
@@ -370,6 +371,7 @@ impl CodeObject {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
flags: CodeFlags,
|
||||
posonlyarg_count: usize,
|
||||
arg_names: Vec<String>,
|
||||
varargs: Varargs,
|
||||
kwonlyarg_names: Vec<String>,
|
||||
@@ -383,6 +385,7 @@ impl CodeObject {
|
||||
label_map: HashMap::new(),
|
||||
locations: Vec::new(),
|
||||
flags,
|
||||
posonlyarg_count,
|
||||
arg_names,
|
||||
varargs,
|
||||
kwonlyarg_names,
|
||||
|
||||
@@ -165,6 +165,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||
let line_number = self.get_source_line_number();
|
||||
self.push_output(CodeObject::new(
|
||||
Default::default(),
|
||||
0,
|
||||
Vec::new(),
|
||||
Varargs::None,
|
||||
Vec::new(),
|
||||
@@ -695,6 +696,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||
let line_number = self.get_source_line_number();
|
||||
self.push_output(CodeObject::new(
|
||||
flags,
|
||||
args.posonlyargs_count,
|
||||
args.args.iter().map(|a| a.arg.clone()).collect(),
|
||||
compile_varargs(&args.vararg),
|
||||
args.kwonlyargs.iter().map(|a| a.arg.clone()).collect(),
|
||||
@@ -976,6 +978,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||
let line_number = self.get_source_line_number();
|
||||
self.push_output(CodeObject::new(
|
||||
Default::default(),
|
||||
0,
|
||||
vec![],
|
||||
Varargs::None,
|
||||
vec![],
|
||||
@@ -1933,6 +1936,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||
// Create magnificent function <listcomp>:
|
||||
self.push_output(CodeObject::new(
|
||||
Default::default(),
|
||||
1,
|
||||
vec![".0".to_owned()],
|
||||
Varargs::None,
|
||||
vec![],
|
||||
|
||||
@@ -374,6 +374,7 @@ impl Expression {
|
||||
/// distinguish between function parameters and actual call arguments.
|
||||
#[derive(Debug, PartialEq, Default)]
|
||||
pub struct Parameters {
|
||||
pub posonlyargs_count: usize,
|
||||
pub args: Vec<Parameter>,
|
||||
pub kwonlyargs: Vec<Parameter>,
|
||||
pub vararg: Varargs, // Optionally we handle optionally named '*args' or '*'
|
||||
|
||||
@@ -7,11 +7,13 @@ type ParameterDefs = (Vec<ast::Parameter>, Vec<ast::Expression>);
|
||||
type ParameterDef = (ast::Parameter, Option<ast::Expression>);
|
||||
|
||||
#[allow(clippy::collapsible_if)]
|
||||
pub fn parse_params(params: Vec<ParameterDef>) -> Result<ParameterDefs, LexicalError> {
|
||||
pub fn parse_params(
|
||||
params: (Vec<ParameterDef>, Vec<ParameterDef>),
|
||||
) -> Result<ParameterDefs, LexicalError> {
|
||||
let mut names = vec![];
|
||||
let mut defaults = vec![];
|
||||
|
||||
for (name, default) in params {
|
||||
let mut try_default = |name: &ast::Parameter, default| {
|
||||
if let Some(default) = default {
|
||||
defaults.push(default);
|
||||
} else {
|
||||
@@ -20,10 +22,20 @@ pub fn parse_params(params: Vec<ParameterDef>) -> Result<ParameterDefs, LexicalE
|
||||
// have defaults
|
||||
return Err(LexicalError {
|
||||
error: LexicalErrorType::DefaultArgumentError,
|
||||
location: name.location,
|
||||
location: name.location.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
for (name, default) in params.0 {
|
||||
try_default(&name, default)?;
|
||||
names.push(name);
|
||||
}
|
||||
|
||||
for (name, default) in params.1 {
|
||||
try_default(&name, default)?;
|
||||
names.push(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -258,6 +258,7 @@ mod tests {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::ExpressionType::Lambda {
|
||||
args: Box::new(ast::Parameters {
|
||||
posonlyargs_count: 0,
|
||||
args: vec![
|
||||
ast::Parameter {
|
||||
location: ast::Location::new(1, 8),
|
||||
@@ -335,6 +336,7 @@ mod tests {
|
||||
is_async: false,
|
||||
name: String::from("__init__"),
|
||||
args: Box::new(ast::Parameters {
|
||||
posonlyargs_count: 0,
|
||||
args: vec![ast::Parameter {
|
||||
location: ast::Location::new(2, 15),
|
||||
arg: String::from("self"),
|
||||
@@ -360,6 +362,7 @@ mod tests {
|
||||
is_async: false,
|
||||
name: String::from("method_with_default"),
|
||||
args: Box::new(ast::Parameters {
|
||||
posonlyargs_count: 0,
|
||||
args: vec![
|
||||
ast::Parameter {
|
||||
location: ast::Location::new(4, 26),
|
||||
|
||||
@@ -456,22 +456,25 @@ Parameters: ast::Parameters = {
|
||||
// once for lambda defs.
|
||||
ParameterList<ArgType>: ast::Parameters = {
|
||||
<param1:ParameterDefs<ArgType>> <args2:("," ParameterListStarArgs<ArgType>)?> ","? =>? {
|
||||
let (names, default_elements) = parse_params(param1)?;
|
||||
let posonlyargs_count = param1.0.len();
|
||||
let (names, defaults) = parse_params(param1)?;
|
||||
|
||||
// Now gather rest of parameters:
|
||||
let (vararg, kwonlyargs, kw_defaults, kwarg) = args2.map_or((None, vec![], vec![], None), |x| x.1);
|
||||
|
||||
Ok(ast::Parameters {
|
||||
posonlyargs_count,
|
||||
args: names,
|
||||
kwonlyargs,
|
||||
vararg: vararg.into(),
|
||||
kwarg: kwarg.into(),
|
||||
defaults: default_elements,
|
||||
kw_defaults: kw_defaults,
|
||||
defaults,
|
||||
kw_defaults,
|
||||
})
|
||||
},
|
||||
<param1:ParameterDefs<ArgType>> <kw:("," KwargParameter<ArgType>)> ","? =>? {
|
||||
let (names, default_elements) = parse_params(param1)?;
|
||||
let posonlyargs_count = param1.0.len();
|
||||
let (names, defaults) = parse_params(param1)?;
|
||||
|
||||
// Now gather rest of parameters:
|
||||
let vararg = None;
|
||||
@@ -480,27 +483,30 @@ ParameterList<ArgType>: ast::Parameters = {
|
||||
let kwarg = Some(kw.1);
|
||||
|
||||
Ok(ast::Parameters {
|
||||
posonlyargs_count,
|
||||
args: names,
|
||||
kwonlyargs,
|
||||
vararg: vararg.into(),
|
||||
kwarg: kwarg.into(),
|
||||
defaults: default_elements,
|
||||
kw_defaults: kw_defaults,
|
||||
defaults,
|
||||
kw_defaults,
|
||||
})
|
||||
},
|
||||
<params:ParameterListStarArgs<ArgType>> ","? => {
|
||||
let (vararg, kwonlyargs, kw_defaults, kwarg) = params;
|
||||
ast::Parameters {
|
||||
posonlyargs_count: 0,
|
||||
args: vec![],
|
||||
kwonlyargs,
|
||||
vararg: vararg.into(),
|
||||
kwarg: kwarg.into(),
|
||||
defaults: vec![],
|
||||
kw_defaults: kw_defaults,
|
||||
kw_defaults,
|
||||
}
|
||||
},
|
||||
<kw:KwargParameter<ArgType>> ","? => {
|
||||
ast::Parameters {
|
||||
posonlyargs_count: 0,
|
||||
args: vec![],
|
||||
kwonlyargs: vec![],
|
||||
vararg: ast::Varargs::None,
|
||||
@@ -513,10 +519,13 @@ ParameterList<ArgType>: ast::Parameters = {
|
||||
|
||||
// Use inline here to make sure the "," is not creating an ambiguity.
|
||||
#[inline]
|
||||
ParameterDefs<ArgType>: Vec<(ast::Parameter, Option<ast::Expression>)> = {
|
||||
ParameterDefs<ArgType>: (Vec<(ast::Parameter, Option<ast::Expression>)>, Vec<(ast::Parameter, Option<ast::Expression>)>) = {
|
||||
<args:OneOrMore<ParameterDef<ArgType>>> => {
|
||||
args
|
||||
}
|
||||
(vec![], args)
|
||||
},
|
||||
<pos_args:OneOrMore<ParameterDef<ArgType>>> "," "/" <args:("," ParameterDef<ArgType>)*> => {
|
||||
(pos_args, args.into_iter().map(|e| e.1).collect())
|
||||
},
|
||||
};
|
||||
|
||||
ParameterDef<ArgType>: (ast::Parameter, Option<ast::Expression>) = {
|
||||
|
||||
@@ -7,11 +7,12 @@ use std::ops::Deref;
|
||||
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::bytecode;
|
||||
use crate::pyobject::{IdProtocol, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::pyobject::{IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
pub type PyCodeRef = PyRef<PyCode>;
|
||||
|
||||
#[pyclass]
|
||||
pub struct PyCode {
|
||||
pub code: bytecode::CodeObject,
|
||||
}
|
||||
@@ -41,12 +42,15 @@ impl PyValue for PyCode {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyCodeRef {
|
||||
#[pyslot]
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
fn new(_cls: PyClassRef, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_type_error("Cannot directly create code object".to_owned()))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(self) -> String {
|
||||
let code = &self.code;
|
||||
format!(
|
||||
@@ -58,22 +62,32 @@ impl PyCodeRef {
|
||||
)
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_posonlyargcount(self) -> usize {
|
||||
self.code.posonlyarg_count
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_argcount(self) -> usize {
|
||||
self.code.arg_names.len()
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_filename(self) -> String {
|
||||
self.code.source_path.clone()
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_firstlineno(self) -> usize {
|
||||
self.code.first_line_number
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_kwonlyargcount(self) -> usize {
|
||||
self.code.kwonlyarg_names.len()
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_consts(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let consts = self
|
||||
.code
|
||||
@@ -83,26 +97,17 @@ impl PyCodeRef {
|
||||
vm.ctx.new_tuple(consts)
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_name(self) -> String {
|
||||
self.code.obj_name.clone()
|
||||
}
|
||||
|
||||
#[pyproperty]
|
||||
fn co_flags(self) -> u8 {
|
||||
self.code.flags.bits()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(ctx: &PyContext) {
|
||||
extend_class!(ctx, &ctx.types.code_type, {
|
||||
(slot new) => PyCodeRef::new,
|
||||
"__repr__" => ctx.new_method(PyCodeRef::repr),
|
||||
|
||||
"co_argcount" => ctx.new_readonly_getset("co_argcount", PyCodeRef::co_argcount),
|
||||
"co_consts" => ctx.new_readonly_getset("co_consts", PyCodeRef::co_consts),
|
||||
"co_filename" => ctx.new_readonly_getset("co_filename", PyCodeRef::co_filename),
|
||||
"co_firstlineno" => ctx.new_readonly_getset("co_firstlineno", PyCodeRef::co_firstlineno),
|
||||
"co_kwonlyargcount" => ctx.new_readonly_getset("co_kwonlyargcount", PyCodeRef::co_kwonlyargcount),
|
||||
"co_name" => ctx.new_readonly_getset("co_name", PyCodeRef::co_name),
|
||||
"co_flags" => ctx.new_readonly_getset("co_flags", PyCodeRef::co_flags),
|
||||
});
|
||||
PyCodeRef::extend_class(ctx, &ctx.types.code_type);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user