mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-15 09:05:25 +00:00
Merge pull request #2438 from RustPython/coolreader18/compile_call-classdef
Handle splat args in bases/kwargs for __build_class__
This commit is contained in:
commit
2b677d0124
1 changed files with 87 additions and 93 deletions
144
src/compile.rs
144
src/compile.rs
|
@ -1158,6 +1158,8 @@ impl Compiler {
|
||||||
) -> CompileResult<()> {
|
) -> CompileResult<()> {
|
||||||
self.prepare_decorators(decorator_list)?;
|
self.prepare_decorators(decorator_list)?;
|
||||||
|
|
||||||
|
self.emit(Instruction::LoadBuildClass);
|
||||||
|
|
||||||
let prev_ctx = self.ctx;
|
let prev_ctx = self.ctx;
|
||||||
self.ctx = CompileContext {
|
self.ctx = CompileContext {
|
||||||
func: FunctionContext::NoFunction,
|
func: FunctionContext::NoFunction,
|
||||||
|
@ -1173,7 +1175,6 @@ impl Compiler {
|
||||||
Some(qualified_name.clone()),
|
Some(qualified_name.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.emit(Instruction::LoadBuildClass);
|
|
||||||
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
|
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
|
||||||
|
|
||||||
let (new_body, doc_str) = get_doc(body);
|
let (new_body, doc_str) = get_doc(body);
|
||||||
|
@ -1241,35 +1242,7 @@ impl Compiler {
|
||||||
value: qualified_name,
|
value: qualified_name,
|
||||||
});
|
});
|
||||||
|
|
||||||
for base in bases {
|
self.compile_call(2, bases, keywords)?;
|
||||||
self.compile_expression(base)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !keywords.is_empty() {
|
|
||||||
let mut kwarg_names = vec![];
|
|
||||||
for keyword in keywords {
|
|
||||||
if let Some(name) = &keyword.node.arg {
|
|
||||||
kwarg_names.push(ConstantData::Str {
|
|
||||||
value: name.to_owned(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// This means **kwargs!
|
|
||||||
panic!("name must be set");
|
|
||||||
}
|
|
||||||
self.compile_expression(&keyword.node.value)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit_constant(ConstantData::Tuple {
|
|
||||||
elements: kwarg_names,
|
|
||||||
});
|
|
||||||
self.emit(Instruction::CallFunctionKeyword {
|
|
||||||
nargs: (2 + keywords.len() + bases.len()) as u32,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.emit(Instruction::CallFunctionPositional {
|
|
||||||
nargs: (2 + bases.len()) as u32,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.apply_decorators(decorator_list);
|
self.apply_decorators(decorator_list);
|
||||||
|
|
||||||
|
@ -1821,7 +1794,10 @@ impl Compiler {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
keywords,
|
keywords,
|
||||||
} => self.compile_call(func, args, keywords)?,
|
} => {
|
||||||
|
self.compile_expression(func)?;
|
||||||
|
self.compile_call(0, args, keywords)?;
|
||||||
|
}
|
||||||
BoolOp { op, values } => self.compile_bool_op(op, values)?,
|
BoolOp { op, values } => self.compile_bool_op(op, values)?,
|
||||||
BinOp { left, op, right } => {
|
BinOp { left, op, right } => {
|
||||||
self.compile_expression(left)?;
|
self.compile_expression(left)?;
|
||||||
|
@ -1864,28 +1840,16 @@ impl Compiler {
|
||||||
self.emit_constant(compile_constant(value));
|
self.emit_constant(compile_constant(value));
|
||||||
}
|
}
|
||||||
List { elts, .. } => {
|
List { elts, .. } => {
|
||||||
let size = elts.len() as u32;
|
let (size, unpack) = self.gather_elements(0, elts)?;
|
||||||
let must_unpack = self.gather_elements(elts)?;
|
self.emit(Instruction::BuildList { size, unpack });
|
||||||
self.emit(Instruction::BuildList {
|
|
||||||
size,
|
|
||||||
unpack: must_unpack,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Tuple { elts, .. } => {
|
Tuple { elts, .. } => {
|
||||||
let size = elts.len() as u32;
|
let (size, unpack) = self.gather_elements(0, elts)?;
|
||||||
let must_unpack = self.gather_elements(elts)?;
|
self.emit(Instruction::BuildTuple { size, unpack });
|
||||||
self.emit(Instruction::BuildTuple {
|
|
||||||
size,
|
|
||||||
unpack: must_unpack,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Set { elts, .. } => {
|
Set { elts, .. } => {
|
||||||
let size = elts.len() as u32;
|
let (size, unpack) = self.gather_elements(0, elts)?;
|
||||||
let must_unpack = self.gather_elements(elts)?;
|
self.emit(Instruction::BuildSet { size, unpack });
|
||||||
self.emit(Instruction::BuildSet {
|
|
||||||
size,
|
|
||||||
unpack: must_unpack,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Dict { keys, values } => {
|
Dict { keys, values } => {
|
||||||
self.compile_dict(keys, values)?;
|
self.compile_dict(keys, values)?;
|
||||||
|
@ -2139,34 +2103,27 @@ impl Compiler {
|
||||||
|
|
||||||
fn compile_call(
|
fn compile_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
function: &ast::Expr,
|
additional_positional: u32,
|
||||||
args: &[ast::Expr],
|
args: &[ast::Expr],
|
||||||
keywords: &[ast::Keyword],
|
keywords: &[ast::Keyword],
|
||||||
) -> CompileResult<()> {
|
) -> CompileResult<()> {
|
||||||
self.compile_expression(function)?;
|
let count = (args.len() + keywords.len()) as u32 + additional_positional;
|
||||||
let count = (args.len() + keywords.len()) as u32;
|
|
||||||
|
|
||||||
// Normal arguments:
|
// Normal arguments:
|
||||||
let must_unpack = self.gather_elements(args)?;
|
let (size, unpack) = self.gather_elements(additional_positional, args)?;
|
||||||
let has_double_star = keywords.iter().any(|k| k.node.arg.is_none());
|
let has_double_star = keywords.iter().any(|k| k.node.arg.is_none());
|
||||||
|
|
||||||
if must_unpack || has_double_star {
|
if unpack || has_double_star {
|
||||||
// Create a tuple with positional args:
|
// Create a tuple with positional args:
|
||||||
self.emit(Instruction::BuildTuple {
|
self.emit(Instruction::BuildTuple { size, unpack });
|
||||||
size: args.len() as u32,
|
|
||||||
unpack: must_unpack,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create an optional map with kw-args:
|
// Create an optional map with kw-args:
|
||||||
if !keywords.is_empty() {
|
let has_kwargs = !keywords.is_empty();
|
||||||
|
if has_kwargs {
|
||||||
self.compile_keywords(keywords)?;
|
self.compile_keywords(keywords)?;
|
||||||
self.emit(Instruction::CallFunctionEx { has_kwargs: true });
|
|
||||||
} else {
|
|
||||||
self.emit(Instruction::CallFunctionEx { has_kwargs: false });
|
|
||||||
}
|
}
|
||||||
} else {
|
self.emit(Instruction::CallFunctionEx { has_kwargs });
|
||||||
// Keyword arguments:
|
} else if !keywords.is_empty() {
|
||||||
if !keywords.is_empty() {
|
|
||||||
let mut kwarg_names = vec![];
|
let mut kwarg_names = vec![];
|
||||||
for keyword in keywords {
|
for keyword in keywords {
|
||||||
if let Some(name) = &keyword.node.arg {
|
if let Some(name) = &keyword.node.arg {
|
||||||
|
@ -2187,33 +2144,70 @@ impl Compiler {
|
||||||
} else {
|
} else {
|
||||||
self.emit(Instruction::CallFunctionPositional { nargs: count });
|
self.emit(Instruction::CallFunctionPositional { nargs: count });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a vector of expr / star expr generate code which gives either
|
// Given a vector of expr / star expr generate code which gives either
|
||||||
// a list of expressions on the stack, or a list of tuples.
|
// a list of expressions on the stack, or a list of tuples.
|
||||||
fn gather_elements(&mut self, elements: &[ast::Expr]) -> CompileResult<bool> {
|
fn gather_elements(
|
||||||
|
&mut self,
|
||||||
|
before: u32,
|
||||||
|
elements: &[ast::Expr],
|
||||||
|
) -> CompileResult<(u32, bool)> {
|
||||||
// First determine if we have starred elements:
|
// First determine if we have starred elements:
|
||||||
let has_stars = elements
|
let has_stars = elements
|
||||||
.iter()
|
.iter()
|
||||||
.any(|e| matches!(e.node, ast::ExprKind::Starred { .. }));
|
.any(|e| matches!(e.node, ast::ExprKind::Starred { .. }));
|
||||||
|
|
||||||
for element in elements {
|
let size = if has_stars {
|
||||||
if let ast::ExprKind::Starred { value, .. } = &element.node {
|
let mut size = 0;
|
||||||
self.compile_expression(value)?;
|
|
||||||
} else {
|
if before > 0 {
|
||||||
self.compile_expression(element)?;
|
|
||||||
if has_stars {
|
|
||||||
self.emit(Instruction::BuildTuple {
|
self.emit(Instruction::BuildTuple {
|
||||||
size: 1,
|
size: before,
|
||||||
unpack: false,
|
unpack: false,
|
||||||
});
|
});
|
||||||
|
size += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let groups = elements
|
||||||
|
.iter()
|
||||||
|
.map(|element| {
|
||||||
|
if let ast::ExprKind::Starred { value, .. } = &element.node {
|
||||||
|
(true, value.as_ref())
|
||||||
|
} else {
|
||||||
|
(false, element)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.group_by(|(starred, _)| *starred);
|
||||||
|
|
||||||
|
for (starred, run) in &groups {
|
||||||
|
let mut run_size = 0;
|
||||||
|
for (_, value) in run {
|
||||||
|
self.compile_expression(value)?;
|
||||||
|
run_size += 1
|
||||||
|
}
|
||||||
|
if starred {
|
||||||
|
size += run_size
|
||||||
|
} else {
|
||||||
|
self.emit(Instruction::BuildTuple {
|
||||||
|
size: run_size,
|
||||||
|
unpack: false,
|
||||||
|
});
|
||||||
|
size += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(has_stars)
|
size
|
||||||
|
} else {
|
||||||
|
for element in elements {
|
||||||
|
self.compile_expression(element)?;
|
||||||
|
}
|
||||||
|
before + elements.len() as u32
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((size, has_stars))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_comprehension_element(&mut self, element: &ast::Expr) -> CompileResult<()> {
|
fn compile_comprehension_element(&mut self, element: &ast::Expr) -> CompileResult<()> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue