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,
opts: CompileOpts,
) -> Result<CodeObject, CompileError> {
macro_rules! try_parse {
($x:expr) => {
match $x {
Ok(x) => x,
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)
}
let mode = match mode {
compile::Mode::Exec => parser::Mode::Module,
compile::Mode::Eval => parser::Mode::Expression,
compile::Mode::Single => parser::Mode::Interactive,
};
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(
@ -119,8 +106,8 @@ pub fn compile_symtable(
symboltable::make_symbol_table(&ast)
}
compile::Mode::Eval => {
let statement = try_parse!(parser::parse_statement(source));
symboltable::statements_to_symbol_table(&statement)
let expr = try_parse!(parser::parse_expression(source));
symboltable::make_symbol_table_expr(&expr)
}
};
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),
/// Invalid delete
Delete(&'static str),
/// Expected an expression got a statement
ExpectExpr,
SyntaxError(String),
/// Multiple `*` detected
MultipleStarArgs,
@ -45,7 +43,6 @@ impl fmt::Display for CompileErrorType {
match self {
CompileErrorType::Assign(target) => write!(f, "can't assign to {}", 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::MultipleStarArgs => {
write!(f, "two starred expressions in assignment")

View file

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