Update the compiler to use the new asdl ast types

This commit is contained in:
Noah 2021-01-10 00:46:59 -06:00
parent 7c2c787404
commit dc8b93a417
4 changed files with 745 additions and 746 deletions

View file

@ -75,29 +75,16 @@ pub fn compile(
source_path: String, source_path: String,
opts: CompileOpts, opts: CompileOpts,
) -> Result<CodeObject, CompileError> { ) -> Result<CodeObject, CompileError> {
macro_rules! try_parse { let mode = match mode {
($x:expr) => { compile::Mode::Exec => parser::Mode::Module,
match $x { compile::Mode::Eval => parser::Mode::Expression,
Ok(x) => x, compile::Mode::Single => parser::Mode::Interactive,
Err(e) => return Err(CompileError::from_parse(e, source, source_path)),
}
};
}
let res = match mode {
compile::Mode::Exec => {
let ast = try_parse!(parser::parse_program(source));
compile::compile_program(ast, source_path, opts)
}
compile::Mode::Eval => {
let statement = try_parse!(parser::parse_statement(source));
compile::compile_statement_eval(statement, source_path, opts)
}
compile::Mode::Single => {
let ast = try_parse!(parser::parse_program(source));
compile::compile_program_single(ast, source_path, opts)
}
}; };
res.map_err(|e| CompileError::from_compile(e, source)) let ast = match parser::parse(source, mode) {
Ok(x) => x,
Err(e) => return Err(CompileError::from_parse(e, source, source_path)),
};
compile::compile_top(&ast, source_path, opts).map_err(|e| CompileError::from_compile(e, source))
} }
pub fn compile_symtable( pub fn compile_symtable(
@ -119,8 +106,8 @@ pub fn compile_symtable(
symboltable::make_symbol_table(&ast) symboltable::make_symbol_table(&ast)
} }
compile::Mode::Eval => { compile::Mode::Eval => {
let statement = try_parse!(parser::parse_statement(source)); let expr = try_parse!(parser::parse_expression(source));
symboltable::statements_to_symbol_table(&statement) symboltable::make_symbol_table_expr(&expr)
} }
}; };
res.map_err(|e| CompileError::from_symtable(e, source, source_path.to_owned())) res.map_err(|e| CompileError::from_symtable(e, source, source_path.to_owned()))

File diff suppressed because it is too large Load diff

View file

@ -17,8 +17,6 @@ pub enum CompileErrorType {
Assign(&'static str), Assign(&'static str),
/// Invalid delete /// Invalid delete
Delete(&'static str), Delete(&'static str),
/// Expected an expression got a statement
ExpectExpr,
SyntaxError(String), SyntaxError(String),
/// Multiple `*` detected /// Multiple `*` detected
MultipleStarArgs, MultipleStarArgs,
@ -45,7 +43,6 @@ impl fmt::Display for CompileErrorType {
match self { match self {
CompileErrorType::Assign(target) => write!(f, "can't assign to {}", target), CompileErrorType::Assign(target) => write!(f, "can't assign to {}", target),
CompileErrorType::Delete(target) => write!(f, "can't delete {}", target), CompileErrorType::Delete(target) => write!(f, "can't delete {}", target),
CompileErrorType::ExpectExpr => write!(f, "Expecting expression, got statement"),
CompileErrorType::SyntaxError(err) => write!(f, "{}", err.as_str()), CompileErrorType::SyntaxError(err) => write!(f, "{}", err.as_str()),
CompileErrorType::MultipleStarArgs => { CompileErrorType::MultipleStarArgs => {
write!(f, "two starred expressions in assignment") write!(f, "two starred expressions in assignment")

View file

@ -12,19 +12,15 @@ use crate::IndexMap;
use rustpython_ast::{self as ast, Location}; use rustpython_ast::{self as ast, Location};
use std::fmt; use std::fmt;
pub fn make_symbol_table(program: &ast::Program) -> Result<SymbolTable, SymbolTableError> { pub fn make_symbol_table(program: &[ast::Stmt]) -> SymbolTableResult<SymbolTable> {
let mut builder = SymbolTableBuilder::default(); let mut builder = SymbolTableBuilder::new();
builder.prepare(); builder.scan_statements(program)?;
builder.scan_program(program)?;
builder.finish() builder.finish()
} }
pub fn statements_to_symbol_table( pub fn make_symbol_table_expr(expr: &ast::Expr) -> SymbolTableResult<SymbolTable> {
statements: &[ast::Statement], let mut builder = SymbolTableBuilder::new();
) -> Result<SymbolTable, SymbolTableError> { builder.scan_expression(expr, ExpressionContext::Load)?;
let mut builder = SymbolTableBuilder::default();
builder.prepare();
builder.scan_statements(statements)?;
builder.finish() builder.finish()
} }
@ -179,7 +175,7 @@ impl SymbolTableError {
} }
} }
type SymbolTableResult = Result<(), SymbolTableError>; type SymbolTableResult<T = ()> = Result<T, SymbolTableError>;
impl SymbolTable { impl SymbolTable {
pub fn lookup(&self, name: &str) -> Option<&Symbol> { pub fn lookup(&self, name: &str) -> Option<&Symbol> {
@ -540,7 +536,6 @@ enum SymbolUsage {
Iter, Iter,
} }
#[derive(Default)]
struct SymbolTableBuilder { struct SymbolTableBuilder {
// Scope stack. // Scope stack.
tables: Vec<SymbolTable>, tables: Vec<SymbolTable>,
@ -560,11 +555,13 @@ enum ExpressionContext {
} }
impl SymbolTableBuilder { impl SymbolTableBuilder {
fn prepare(&mut self) { fn new() -> Self {
self.enter_scope("top", SymbolTableType::Module, 0) let mut this = Self { tables: vec![] };
this.enter_scope("top", SymbolTableType::Module, 0);
this
} }
fn finish(&mut self) -> Result<SymbolTable, SymbolTableError> { fn finish(mut self) -> Result<SymbolTable, SymbolTableError> {
assert_eq!(self.tables.len(), 1); assert_eq!(self.tables.len(), 1);
let mut symbol_table = self.tables.pop().unwrap(); let mut symbol_table = self.tables.pop().unwrap();
analyze_symbol_table(&mut symbol_table)?; analyze_symbol_table(&mut symbol_table)?;
@ -587,50 +584,45 @@ impl SymbolTableBuilder {
self.tables.last_mut().unwrap().sub_tables.push(table); self.tables.last_mut().unwrap().sub_tables.push(table);
} }
fn scan_program(&mut self, program: &ast::Program) -> SymbolTableResult { fn scan_statements(&mut self, statements: &[ast::Stmt]) -> SymbolTableResult {
self.scan_statements(&program.statements)?;
Ok(())
}
fn scan_statements(&mut self, statements: &[ast::Statement]) -> SymbolTableResult {
for statement in statements { for statement in statements {
self.scan_statement(statement)?; self.scan_statement(statement)?;
} }
Ok(()) Ok(())
} }
fn scan_parameters(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult { fn scan_parameters(&mut self, parameters: &[ast::Arg]) -> SymbolTableResult {
for parameter in parameters { for parameter in parameters {
self.scan_parameter(parameter)?; self.scan_parameter(parameter)?;
} }
Ok(()) Ok(())
} }
fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult { fn scan_parameter(&mut self, parameter: &ast::Arg) -> SymbolTableResult {
let usage = if parameter.annotation.is_some() { let usage = if parameter.node.annotation.is_some() {
SymbolUsage::AnnotationParameter SymbolUsage::AnnotationParameter
} else { } else {
SymbolUsage::Parameter SymbolUsage::Parameter
}; };
self.register_name(&parameter.arg, usage, parameter.location) self.register_name(&parameter.node.arg, usage, parameter.location)
} }
fn scan_parameters_annotations(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult { fn scan_parameters_annotations(&mut self, parameters: &[ast::Arg]) -> SymbolTableResult {
for parameter in parameters { for parameter in parameters {
self.scan_parameter_annotation(parameter)?; self.scan_parameter_annotation(parameter)?;
} }
Ok(()) Ok(())
} }
fn scan_parameter_annotation(&mut self, parameter: &ast::Parameter) -> SymbolTableResult { fn scan_parameter_annotation(&mut self, parameter: &ast::Arg) -> SymbolTableResult {
if let Some(annotation) = &parameter.annotation { if let Some(annotation) = &parameter.node.annotation {
self.scan_expression(&annotation, ExpressionContext::Load)?; self.scan_expression(&annotation, ExpressionContext::Load)?;
} }
Ok(()) Ok(())
} }
fn scan_statement(&mut self, statement: &ast::Statement) -> SymbolTableResult { fn scan_statement(&mut self, statement: &ast::Stmt) -> SymbolTableResult {
use ast::StatementType::*; use ast::StmtKind::*;
let location = statement.location; let location = statement.location;
match &statement.node { match &statement.node {
Global { names } => { Global { names } => {
@ -650,6 +642,14 @@ impl SymbolTableBuilder {
decorator_list, decorator_list,
returns, returns,
.. ..
}
| AsyncFunctionDef {
name,
body,
args,
decorator_list,
returns,
..
} => { } => {
self.scan_expressions(decorator_list, ExpressionContext::Load)?; self.scan_expressions(decorator_list, ExpressionContext::Load)?;
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(name, SymbolUsage::Assigned, location)?;
@ -676,20 +676,16 @@ impl SymbolTableBuilder {
self.leave_scope(); self.leave_scope();
self.scan_expressions(bases, ExpressionContext::Load)?; self.scan_expressions(bases, ExpressionContext::Load)?;
for keyword in keywords { for keyword in keywords {
self.scan_expression(&keyword.value, ExpressionContext::Load)?; self.scan_expression(&keyword.node.value, ExpressionContext::Load)?;
} }
self.scan_expressions(decorator_list, ExpressionContext::Load)?; self.scan_expressions(decorator_list, ExpressionContext::Load)?;
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(name, SymbolUsage::Assigned, location)?;
} }
Expression { expression } => { Expr { value } => self.scan_expression(value, ExpressionContext::Load)?,
self.scan_expression(expression, ExpressionContext::Load)?
}
If { test, body, orelse } => { If { test, body, orelse } => {
self.scan_expression(test, ExpressionContext::Load)?; self.scan_expression(test, ExpressionContext::Load)?;
self.scan_statements(body)?; self.scan_statements(body)?;
if let Some(code) = orelse { self.scan_statements(orelse)?;
self.scan_statements(code)?;
}
} }
For { For {
target, target,
@ -697,33 +693,36 @@ impl SymbolTableBuilder {
body, body,
orelse, orelse,
.. ..
}
| AsyncFor {
target,
iter,
body,
orelse,
..
} => { } => {
self.scan_expression(target, ExpressionContext::Store)?; self.scan_expression(target, ExpressionContext::Store)?;
self.scan_expression(iter, ExpressionContext::Load)?; self.scan_expression(iter, ExpressionContext::Load)?;
self.scan_statements(body)?; self.scan_statements(body)?;
if let Some(code) = orelse { self.scan_statements(orelse)?;
self.scan_statements(code)?;
}
} }
While { test, body, orelse } => { While { test, body, orelse } => {
self.scan_expression(test, ExpressionContext::Load)?; self.scan_expression(test, ExpressionContext::Load)?;
self.scan_statements(body)?; self.scan_statements(body)?;
if let Some(code) = orelse { self.scan_statements(orelse)?;
self.scan_statements(code)?;
}
} }
Break | Continue | Pass => { Break | Continue | Pass => {
// No symbols here. // No symbols here.
} }
Import { names } | ImportFrom { names, .. } => { Import { names } | ImportFrom { names, .. } => {
for name in names { for name in names {
if let Some(alias) = &name.alias { if let Some(alias) = &name.asname {
// `import mymodule as myalias` // `import mymodule as myalias`
self.register_name(alias, SymbolUsage::Imported, location)?; self.register_name(alias, SymbolUsage::Imported, location)?;
} else { } else {
// `import module` // `import module`
self.register_name( self.register_name(
name.symbol.split('.').next().unwrap(), name.name.split('.').next().unwrap(),
SymbolUsage::Imported, SymbolUsage::Imported,
location, location,
)?; )?;
@ -744,7 +743,7 @@ impl SymbolTableBuilder {
Delete { targets } => { Delete { targets } => {
self.scan_expressions(targets, ExpressionContext::Delete)?; self.scan_expressions(targets, ExpressionContext::Delete)?;
} }
Assign { targets, value } => { Assign { targets, value, .. } => {
self.scan_expressions(targets, ExpressionContext::Store)?; self.scan_expressions(targets, ExpressionContext::Store)?;
self.scan_expression(value, ExpressionContext::Load)?; self.scan_expression(value, ExpressionContext::Load)?;
} }
@ -756,19 +755,23 @@ impl SymbolTableBuilder {
target, target,
annotation, annotation,
value, value,
simple,
} => { } => {
// https://github.com/python/cpython/blob/master/Python/symtable.c#L1233 // https://github.com/python/cpython/blob/master/Python/symtable.c#L1233
if let ast::ExpressionType::Identifier { ref name } = target.node { match &target.node {
self.register_name(name, SymbolUsage::AnnotationAssigned, location)?; ast::ExprKind::Name { id, .. } if *simple => {
} else { self.register_name(id, SymbolUsage::AnnotationAssigned, location)?;
self.scan_expression(target, ExpressionContext::Store)?; }
_ => {
self.scan_expression(target, ExpressionContext::Store)?;
}
} }
self.scan_expression(annotation, ExpressionContext::Load)?; self.scan_expression(annotation, ExpressionContext::Load)?;
if let Some(value) = value { if let Some(value) = value {
self.scan_expression(value, ExpressionContext::Load)?; self.scan_expression(value, ExpressionContext::Load)?;
} }
} }
With { items, body, .. } => { With { items, body, .. } | AsyncWith { items, body, .. } => {
for item in items { for item in items {
self.scan_expression(&item.context_expr, ExpressionContext::Load)?; self.scan_expression(&item.context_expr, ExpressionContext::Load)?;
if let Some(expression) = &item.optional_vars { if let Some(expression) = &item.optional_vars {
@ -785,23 +788,20 @@ impl SymbolTableBuilder {
} => { } => {
self.scan_statements(body)?; self.scan_statements(body)?;
for handler in handlers { for handler in handlers {
if let Some(expression) = &handler.typ { let ast::ExcepthandlerKind::ExceptHandler { type_, name, body } = &handler.node;
if let Some(expression) = type_ {
self.scan_expression(expression, ExpressionContext::Load)?; self.scan_expression(expression, ExpressionContext::Load)?;
} }
if let Some(name) = &handler.name { if let Some(name) = name {
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(name, SymbolUsage::Assigned, location)?;
} }
self.scan_statements(&handler.body)?; self.scan_statements(body)?;
}
if let Some(code) = orelse {
self.scan_statements(code)?;
}
if let Some(code) = finalbody {
self.scan_statements(code)?;
} }
self.scan_statements(orelse)?;
self.scan_statements(finalbody)?;
} }
Raise { exception, cause } => { Raise { exc, cause } => {
if let Some(expression) = exception { if let Some(expression) = exc {
self.scan_expression(expression, ExpressionContext::Load)?; self.scan_expression(expression, ExpressionContext::Load)?;
} }
if let Some(expression) = cause { if let Some(expression) = cause {
@ -814,7 +814,7 @@ impl SymbolTableBuilder {
fn scan_expressions( fn scan_expressions(
&mut self, &mut self,
expressions: &[ast::Expression], expressions: &[ast::Expr],
context: ExpressionContext, context: ExpressionContext,
) -> SymbolTableResult { ) -> SymbolTableResult {
for expression in expressions { for expression in expressions {
@ -825,31 +825,34 @@ impl SymbolTableBuilder {
fn scan_expression( fn scan_expression(
&mut self, &mut self,
expression: &ast::Expression, expression: &ast::Expr,
context: ExpressionContext, context: ExpressionContext,
) -> SymbolTableResult { ) -> SymbolTableResult {
use ast::ExpressionType::*; use ast::ExprKind::*;
let location = expression.location; let location = expression.location;
match &expression.node { match &expression.node {
Binop { a, b, .. } => { BinOp { left, right, .. } => {
self.scan_expression(a, context)?; self.scan_expression(left, context)?;
self.scan_expression(b, context)?; self.scan_expression(right, context)?;
} }
BoolOp { values, .. } => { BoolOp { values, .. } => {
self.scan_expressions(values, context)?; self.scan_expressions(values, context)?;
} }
Compare { vals, .. } => { Compare {
self.scan_expressions(vals, context)?; left, comparators, ..
} => {
self.scan_expression(left, context)?;
self.scan_expressions(comparators, context)?;
} }
Subscript { a, b } => { Subscript { value, slice, .. } => {
self.scan_expression(a, ExpressionContext::Load)?; self.scan_expression(value, ExpressionContext::Load)?;
self.scan_expression(b, ExpressionContext::Load)?; self.scan_expression(slice, ExpressionContext::Load)?;
} }
Attribute { value, .. } => { Attribute { value, .. } => {
self.scan_expression(value, ExpressionContext::Load)?; self.scan_expression(value, ExpressionContext::Load)?;
} }
Dict { elements } => { Dict { keys, values } => {
for (key, value) in elements { for (key, value) in keys.iter().zip(values) {
if let Some(key) = key { if let Some(key) = key {
self.scan_expression(key, context)?; self.scan_expression(key, context)?;
} else { } else {
@ -869,109 +872,95 @@ impl SymbolTableBuilder {
YieldFrom { value } => { YieldFrom { value } => {
self.scan_expression(value, context)?; self.scan_expression(value, context)?;
} }
Unop { a, .. } => { UnaryOp { operand, .. } => {
self.scan_expression(a, context)?; self.scan_expression(operand, context)?;
} }
True | False | None | Ellipsis => {} Constant { .. } => {}
Number { .. } => {} Starred { value, .. } => {
Starred { value } => {
self.scan_expression(value, context)?; self.scan_expression(value, context)?;
} }
Bytes { .. } => {} Tuple { elts, .. } | Set { elts, .. } | List { elts, .. } => {
Tuple { elements } | Set { elements } | List { elements } | Slice { elements } => { self.scan_expressions(elts, context)?;
self.scan_expressions(elements, context)?;
} }
Comprehension { kind, generators } => { Slice { lower, upper, step } => {
// Comprehensions are compiled as functions, so create a scope for them: if let Some(lower) = lower {
let scope_name = match **kind { self.scan_expression(lower, context)?;
ast::ComprehensionKind::GeneratorExpression { .. } => "genexpr",
ast::ComprehensionKind::List { .. } => "listcomp",
ast::ComprehensionKind::Set { .. } => "setcomp",
ast::ComprehensionKind::Dict { .. } => "dictcomp",
};
self.enter_scope(scope_name, SymbolTableType::Comprehension, location.row());
// Register the passed argument to the generator function as the name ".0"
self.register_name(".0", SymbolUsage::Parameter, location)?;
match **kind {
ast::ComprehensionKind::GeneratorExpression { ref element }
| ast::ComprehensionKind::List { ref element }
| ast::ComprehensionKind::Set { ref element } => {
self.scan_expression(element, ExpressionContext::Load)?;
}
ast::ComprehensionKind::Dict { ref key, ref value } => {
self.scan_expression(&key, ExpressionContext::Load)?;
self.scan_expression(&value, ExpressionContext::Load)?;
}
} }
if let Some(upper) = upper {
let mut is_first_generator = true; self.scan_expression(upper, context)?;
for generator in generators {
self.scan_expression(&generator.target, ExpressionContext::Iter)?;
if is_first_generator {
is_first_generator = false;
} else {
self.scan_expression(
&generator.iter,
ExpressionContext::IterDefinitionExp,
)?;
}
for if_expr in &generator.ifs {
self.scan_expression(if_expr, ExpressionContext::Load)?;
}
} }
if let Some(step) = step {
self.leave_scope(); self.scan_expression(step, context)?;
}
// The first iterable is passed as an argument into the created function: }
assert!(!generators.is_empty()); GeneratorExp { elt, generators } => {
self.scan_expression(&generators[0].iter, ExpressionContext::IterDefinitionExp)?; self.scan_comprehension("genexpr", elt, None, generators, location)?;
}
ListComp { elt, generators } => {
self.scan_comprehension("genexpr", elt, None, generators, location)?;
}
SetComp { elt, generators } => {
self.scan_comprehension("genexpr", elt, None, generators, location)?;
}
DictComp {
key,
value,
generators,
} => {
self.scan_comprehension("genexpr", key, Some(value), generators, location)?;
} }
Call { Call {
function, func,
args, args,
keywords, keywords,
} => { } => {
match context { match context {
ExpressionContext::IterDefinitionExp => { ExpressionContext::IterDefinitionExp => {
self.scan_expression(function, ExpressionContext::IterDefinitionExp)?; self.scan_expression(func, ExpressionContext::IterDefinitionExp)?;
} }
_ => { _ => {
self.scan_expression(function, ExpressionContext::Load)?; self.scan_expression(func, ExpressionContext::Load)?;
} }
} }
self.scan_expressions(args, ExpressionContext::Load)?; self.scan_expressions(args, ExpressionContext::Load)?;
for keyword in keywords { for keyword in keywords {
self.scan_expression(&keyword.value, ExpressionContext::Load)?; self.scan_expression(&keyword.node.value, ExpressionContext::Load)?;
} }
} }
String { value } => { FormattedValue {
self.scan_string_group(value)?; value, format_spec, ..
} => {
self.scan_expression(value, ExpressionContext::Load)?;
if let Some(spec) = format_spec {
self.scan_expression(spec, ExpressionContext::Load)?;
}
} }
Identifier { name } => { JoinedStr { values } => {
for value in values {
self.scan_expression(value, ExpressionContext::Load)?;
}
}
Name { id, .. } => {
// Determine the contextual usage of this symbol: // Determine the contextual usage of this symbol:
match context { match context {
ExpressionContext::Delete => { ExpressionContext::Delete => {
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(id, SymbolUsage::Assigned, location)?;
self.register_name(name, SymbolUsage::Used, location)?; self.register_name(id, SymbolUsage::Used, location)?;
} }
ExpressionContext::Load | ExpressionContext::IterDefinitionExp => { ExpressionContext::Load | ExpressionContext::IterDefinitionExp => {
self.register_name(name, SymbolUsage::Used, location)?; self.register_name(id, SymbolUsage::Used, location)?;
} }
ExpressionContext::Store => { ExpressionContext::Store => {
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(id, SymbolUsage::Assigned, location)?;
} }
ExpressionContext::Iter => { ExpressionContext::Iter => {
self.register_name(name, SymbolUsage::Iter, location)?; self.register_name(id, SymbolUsage::Iter, location)?;
} }
} }
if context == ExpressionContext::Load if context == ExpressionContext::Load
&& self.tables.last().unwrap().typ == SymbolTableType::Function && self.tables.last().unwrap().typ == SymbolTableType::Function
&& name == "super" && id == "super"
{ {
self.register_name("__class__", SymbolUsage::Used, location)?; self.register_name("__class__", SymbolUsage::Used, location)?;
} }
@ -988,13 +977,13 @@ impl SymbolTableBuilder {
} }
self.leave_scope(); self.leave_scope();
} }
IfExpression { test, body, orelse } => { IfExp { test, body, orelse } => {
self.scan_expression(test, ExpressionContext::Load)?; self.scan_expression(test, ExpressionContext::Load)?;
self.scan_expression(body, ExpressionContext::Load)?; self.scan_expression(body, ExpressionContext::Load)?;
self.scan_expression(orelse, ExpressionContext::Load)?; self.scan_expression(orelse, ExpressionContext::Load)?;
} }
NamedExpression { left, right } => { NamedExpr { target, value } => {
// named expressions are not allowed in the definiton of // named expressions are not allowed in the definiton of
// comprehension iterator definitions // comprehension iterator definitions
if let ExpressionContext::IterDefinitionExp = context { if let ExpressionContext::IterDefinitionExp = context {
@ -1005,34 +994,77 @@ impl SymbolTableBuilder {
}); });
} }
self.scan_expression(right, ExpressionContext::Load)?; self.scan_expression(value, ExpressionContext::Load)?;
// special handling for assigned identifier in named expressions // special handling for assigned identifier in named expressions
// that are used in comprehensions. This required to correctly // that are used in comprehensions. This required to correctly
// propagate the scope of the named assigned named and not to // propagate the scope of the named assigned named and not to
// propagate inner names. // propagate inner names.
if let Identifier { name } = &left.node { if let Name { id, .. } = &target.node {
let table = self.tables.last().unwrap(); let table = self.tables.last().unwrap();
if table.typ == SymbolTableType::Comprehension { if table.typ == SymbolTableType::Comprehension {
self.register_name(name, SymbolUsage::AssignedNamedExprInCompr, location)?; self.register_name(id, SymbolUsage::AssignedNamedExprInCompr, location)?;
} else { } else {
// omit one recursion. When the handling of an store changes for // omit one recursion. When the handling of an store changes for
// Identifiers this needs adapted - more forward safe would be // Identifiers this needs adapted - more forward safe would be
// calling scan_expression directly. // calling scan_expression directly.
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(id, SymbolUsage::Assigned, location)?;
} }
} else { } else {
self.scan_expression(left, ExpressionContext::Store)?; self.scan_expression(target, ExpressionContext::Store)?;
} }
} }
} }
Ok(()) Ok(())
} }
fn scan_comprehension(
&mut self,
scope_name: &str,
elt1: &ast::Expr,
elt2: Option<&ast::Expr>,
generators: &[ast::Comprehension],
location: Location,
) -> SymbolTableResult {
// Comprehensions are compiled as functions, so create a scope for them:
self.enter_scope(scope_name, SymbolTableType::Comprehension, location.row());
// Register the passed argument to the generator function as the name ".0"
self.register_name(".0", SymbolUsage::Parameter, location)?;
self.scan_expression(elt1, ExpressionContext::Load)?;
if let Some(elt2) = elt2 {
self.scan_expression(elt2, ExpressionContext::Load)?;
}
let mut is_first_generator = true;
for generator in generators {
self.scan_expression(&generator.target, ExpressionContext::Iter)?;
if is_first_generator {
is_first_generator = false;
} else {
self.scan_expression(&generator.iter, ExpressionContext::IterDefinitionExp)?;
}
for if_expr in &generator.ifs {
self.scan_expression(if_expr, ExpressionContext::Load)?;
}
}
self.leave_scope();
// The first iterable is passed as an argument into the created function:
assert!(!generators.is_empty());
self.scan_expression(&generators[0].iter, ExpressionContext::IterDefinitionExp)?;
Ok(())
}
fn enter_function( fn enter_function(
&mut self, &mut self,
name: &str, name: &str,
args: &ast::Parameters, args: &ast::Arguments,
line_number: usize, line_number: usize,
) -> SymbolTableResult { ) -> SymbolTableResult {
// Evaluate eventual default parameters: // Evaluate eventual default parameters:
@ -1044,47 +1076,31 @@ impl SymbolTableBuilder {
} }
// Annotations are scanned in outer scope: // Annotations are scanned in outer scope:
self.scan_parameters_annotations(&args.posonlyargs)?;
self.scan_parameters_annotations(&args.args)?; self.scan_parameters_annotations(&args.args)?;
self.scan_parameters_annotations(&args.kwonlyargs)?; self.scan_parameters_annotations(&args.kwonlyargs)?;
if let ast::Varargs::Named(name) = &args.vararg { if let Some(name) = &args.vararg {
self.scan_parameter_annotation(name)?; self.scan_parameter_annotation(name)?;
} }
if let ast::Varargs::Named(name) = &args.kwarg { if let Some(name) = &args.kwarg {
self.scan_parameter_annotation(name)?; self.scan_parameter_annotation(name)?;
} }
self.enter_scope(name, SymbolTableType::Function, line_number); self.enter_scope(name, SymbolTableType::Function, line_number);
// Fill scope with parameter names: // Fill scope with parameter names:
self.scan_parameters(&args.posonlyargs)?;
self.scan_parameters(&args.args)?; self.scan_parameters(&args.args)?;
self.scan_parameters(&args.kwonlyargs)?; self.scan_parameters(&args.kwonlyargs)?;
if let ast::Varargs::Named(name) = &args.vararg { if let Some(name) = &args.vararg {
self.scan_parameter(name)?; self.scan_parameter(name)?;
} }
if let ast::Varargs::Named(name) = &args.kwarg { if let Some(name) = &args.kwarg {
self.scan_parameter(name)?; self.scan_parameter(name)?;
} }
Ok(()) Ok(())
} }
fn scan_string_group(&mut self, group: &ast::StringGroup) -> SymbolTableResult {
match group {
ast::StringGroup::Constant { .. } => {}
ast::StringGroup::FormattedValue { value, spec, .. } => {
self.scan_expression(value, ExpressionContext::Load)?;
if let Some(spec) = spec {
self.scan_string_group(spec)?;
}
}
ast::StringGroup::Joined { values } => {
for subgroup in values {
self.scan_string_group(subgroup)?;
}
}
}
Ok(())
}
fn register_name( fn register_name(
&mut self, &mut self,
name: &str, name: &str,