mirror of
https://github.com/RustPython/Parser.git
synced 2025-08-01 01:12:55 +00:00
Update the compiler to use the new asdl ast types
This commit is contained in:
parent
7c2c787404
commit
dc8b93a417
4 changed files with 745 additions and 746 deletions
|
@ -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()))
|
||||||
|
|
1093
src/compile.rs
1093
src/compile.rs
File diff suppressed because it is too large
Load diff
|
@ -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")
|
||||||
|
|
|
@ -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(¶meter.arg, usage, parameter.location)
|
self.register_name(¶meter.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) = ¶meter.annotation {
|
if let Some(annotation) = ¶meter.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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue