mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Add location to expressions. Change symboltable to use flags for symbols.
This commit is contained in:
1 parent
1b48ade07b
commit
d6c19c1c6a
10 files changed
+935
-828
No files matched your search
+100
-96
@@ -6,7 +6,7 @@
|
||||
//! https://github.com/micropython/micropython/blob/master/py/compile.c
|
||||
|
||||
use crate::error::{CompileError, CompileErrorType};
|
||||
use crate::symboltable::{make_symbol_table, statements_to_symbol_table, SymbolRole, SymbolScope};
|
||||
use crate::symboltable::{make_symbol_table, statements_to_symbol_table, Symbol, SymbolScope};
|
||||
use num_complex::Complex64;
|
||||
use rustpython_bytecode::bytecode::{self, CallType, CodeObject, Instruction, Varargs};
|
||||
use rustpython_parser::{ast, parser};
|
||||
@@ -75,7 +75,7 @@ pub fn compile_program(
|
||||
|
||||
/// Compile a single Python expression to bytecode
|
||||
pub fn compile_statement_eval(
|
||||
statement: Vec<ast::LocatedStatement>,
|
||||
statement: Vec<ast::Statement>,
|
||||
source_path: String,
|
||||
optimize: u8,
|
||||
) -> Result<CodeObject, CompileError> {
|
||||
@@ -180,7 +180,7 @@ impl Compiler {
|
||||
for (i, statement) in program.statements.iter().enumerate() {
|
||||
let is_last = i == program.statements.len() - 1;
|
||||
|
||||
if let ast::Statement::Expression { ref expression } = statement.node {
|
||||
if let ast::StatementType::Expression { ref expression } = statement.node {
|
||||
self.compile_expression(expression)?;
|
||||
|
||||
if is_last {
|
||||
@@ -209,12 +209,12 @@ impl Compiler {
|
||||
// Compile statement in eval mode:
|
||||
fn compile_statement_eval(
|
||||
&mut self,
|
||||
statements: &[ast::LocatedStatement],
|
||||
statements: &[ast::Statement],
|
||||
symbol_table: SymbolScope,
|
||||
) -> Result<(), CompileError> {
|
||||
self.scope_stack.push(symbol_table);
|
||||
for statement in statements {
|
||||
if let ast::Statement::Expression { ref expression } = statement.node {
|
||||
if let ast::StatementType::Expression { ref expression } = statement.node {
|
||||
self.compile_expression(expression)?;
|
||||
} else {
|
||||
return Err(CompileError {
|
||||
@@ -227,10 +227,7 @@ impl Compiler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_statements(
|
||||
&mut self,
|
||||
statements: &[ast::LocatedStatement],
|
||||
) -> Result<(), CompileError> {
|
||||
fn compile_statements(&mut self, statements: &[ast::Statement]) -> Result<(), CompileError> {
|
||||
for statement in statements {
|
||||
self.compile_statement(statement)?
|
||||
}
|
||||
@@ -238,11 +235,13 @@ impl Compiler {
|
||||
}
|
||||
|
||||
fn scope_for_name(&self, name: &str) -> bytecode::NameScope {
|
||||
let role = self.lookup_name(name);
|
||||
match role {
|
||||
SymbolRole::Global => bytecode::NameScope::Global,
|
||||
SymbolRole::Nonlocal => bytecode::NameScope::NonLocal,
|
||||
_ => bytecode::NameScope::Local,
|
||||
let symbol = self.lookup_name(name);
|
||||
if symbol.is_global {
|
||||
bytecode::NameScope::Global
|
||||
} else if symbol.is_nonlocal {
|
||||
bytecode::NameScope::NonLocal
|
||||
} else {
|
||||
bytecode::NameScope::Local
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,12 +261,13 @@ impl Compiler {
|
||||
});
|
||||
}
|
||||
|
||||
fn compile_statement(&mut self, statement: &ast::LocatedStatement) -> Result<(), CompileError> {
|
||||
fn compile_statement(&mut self, statement: &ast::Statement) -> Result<(), CompileError> {
|
||||
trace!("Compiling {:?}", statement);
|
||||
self.set_source_location(&statement.location);
|
||||
use ast::StatementType::*;
|
||||
|
||||
match &statement.node {
|
||||
ast::Statement::Import { names } => {
|
||||
Import { names } => {
|
||||
// import a, b, c as d
|
||||
for name in names {
|
||||
self.emit(Instruction::Import {
|
||||
@@ -283,7 +283,7 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Statement::ImportFrom {
|
||||
ImportFrom {
|
||||
level,
|
||||
module,
|
||||
names,
|
||||
@@ -326,16 +326,16 @@ impl Compiler {
|
||||
self.emit(Instruction::Pop);
|
||||
}
|
||||
}
|
||||
ast::Statement::Expression { expression } => {
|
||||
Expression { expression } => {
|
||||
self.compile_expression(expression)?;
|
||||
|
||||
// Pop result of stack, since we not use it:
|
||||
self.emit(Instruction::Pop);
|
||||
}
|
||||
ast::Statement::Global { .. } | ast::Statement::Nonlocal { .. } => {
|
||||
Global { .. } | Nonlocal { .. } => {
|
||||
// Handled during symbol table construction.
|
||||
}
|
||||
ast::Statement::If { test, body, orelse } => {
|
||||
If { test, body, orelse } => {
|
||||
let end_label = self.new_label();
|
||||
match orelse {
|
||||
None => {
|
||||
@@ -358,7 +358,7 @@ impl Compiler {
|
||||
}
|
||||
self.set_label(end_label);
|
||||
}
|
||||
ast::Statement::While { test, body, orelse } => {
|
||||
While { test, body, orelse } => {
|
||||
let start_label = self.new_label();
|
||||
let else_label = self.new_label();
|
||||
let end_label = self.new_label();
|
||||
@@ -385,7 +385,7 @@ impl Compiler {
|
||||
}
|
||||
self.set_label(end_label);
|
||||
}
|
||||
ast::Statement::With { items, body } => {
|
||||
With { items, body } => {
|
||||
let end_label = self.new_label();
|
||||
for item in items {
|
||||
self.compile_expression(&item.context_expr)?;
|
||||
@@ -406,16 +406,16 @@ impl Compiler {
|
||||
}
|
||||
self.set_label(end_label);
|
||||
}
|
||||
ast::Statement::For {
|
||||
For {
|
||||
target,
|
||||
iter,
|
||||
body,
|
||||
orelse,
|
||||
} => self.compile_for(target, iter, body, orelse)?,
|
||||
ast::Statement::AsyncFor { .. } => {
|
||||
AsyncFor { .. } => {
|
||||
unimplemented!("async for");
|
||||
}
|
||||
ast::Statement::Raise { exception, cause } => match exception {
|
||||
Raise { exception, cause } => match exception {
|
||||
Some(value) => {
|
||||
self.compile_expression(value)?;
|
||||
match cause {
|
||||
@@ -432,30 +432,30 @@ impl Compiler {
|
||||
self.emit(Instruction::Raise { argc: 0 });
|
||||
}
|
||||
},
|
||||
ast::Statement::Try {
|
||||
Try {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
finalbody,
|
||||
} => self.compile_try_statement(body, handlers, orelse, finalbody)?,
|
||||
ast::Statement::FunctionDef {
|
||||
FunctionDef {
|
||||
name,
|
||||
args,
|
||||
body,
|
||||
decorator_list,
|
||||
returns,
|
||||
} => self.compile_function_def(name, args, body, decorator_list, returns)?,
|
||||
ast::Statement::AsyncFunctionDef { .. } => {
|
||||
AsyncFunctionDef { .. } => {
|
||||
unimplemented!("async def");
|
||||
}
|
||||
ast::Statement::ClassDef {
|
||||
ClassDef {
|
||||
name,
|
||||
body,
|
||||
bases,
|
||||
keywords,
|
||||
decorator_list,
|
||||
} => self.compile_class_def(name, body, bases, keywords, decorator_list)?,
|
||||
ast::Statement::Assert { test, msg } => {
|
||||
Assert { test, msg } => {
|
||||
// if some flag, ignore all assert statements!
|
||||
if self.optimize == 0 {
|
||||
let end_label = self.new_label();
|
||||
@@ -481,7 +481,7 @@ impl Compiler {
|
||||
self.set_label(end_label);
|
||||
}
|
||||
}
|
||||
ast::Statement::Break => {
|
||||
Break => {
|
||||
if !self.in_loop {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::InvalidBreak,
|
||||
@@ -490,7 +490,7 @@ impl Compiler {
|
||||
}
|
||||
self.emit(Instruction::Break);
|
||||
}
|
||||
ast::Statement::Continue => {
|
||||
Continue => {
|
||||
if !self.in_loop {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::InvalidContinue,
|
||||
@@ -499,7 +499,7 @@ impl Compiler {
|
||||
}
|
||||
self.emit(Instruction::Continue);
|
||||
}
|
||||
ast::Statement::Return { value } => {
|
||||
Return { value } => {
|
||||
if !self.in_function_def {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::InvalidReturn,
|
||||
@@ -519,7 +519,7 @@ impl Compiler {
|
||||
|
||||
self.emit(Instruction::ReturnValue);
|
||||
}
|
||||
ast::Statement::Assign { targets, value } => {
|
||||
Assign { targets, value } => {
|
||||
self.compile_expression(value)?;
|
||||
|
||||
for (i, target) in targets.iter().enumerate() {
|
||||
@@ -529,7 +529,7 @@ impl Compiler {
|
||||
self.compile_store(target)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::AugAssign { target, op, value } => {
|
||||
AugAssign { target, op, value } => {
|
||||
self.compile_expression(target)?;
|
||||
self.compile_expression(value)?;
|
||||
|
||||
@@ -537,12 +537,12 @@ impl Compiler {
|
||||
self.compile_op(op, true);
|
||||
self.compile_store(target)?;
|
||||
}
|
||||
ast::Statement::Delete { targets } => {
|
||||
Delete { targets } => {
|
||||
for target in targets {
|
||||
self.compile_delete(target)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::Pass => {
|
||||
Pass => {
|
||||
self.emit(Instruction::Pass);
|
||||
}
|
||||
}
|
||||
@@ -550,24 +550,24 @@ impl Compiler {
|
||||
}
|
||||
|
||||
fn compile_delete(&mut self, expression: &ast::Expression) -> Result<(), CompileError> {
|
||||
match expression {
|
||||
ast::Expression::Identifier { name } => {
|
||||
match &expression.node {
|
||||
ast::ExpressionType::Identifier { name } => {
|
||||
self.emit(Instruction::DeleteName {
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
ast::Expression::Attribute { value, name } => {
|
||||
ast::ExpressionType::Attribute { value, name } => {
|
||||
self.compile_expression(value)?;
|
||||
self.emit(Instruction::DeleteAttr {
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => {
|
||||
ast::ExpressionType::Subscript { a, b } => {
|
||||
self.compile_expression(a)?;
|
||||
self.compile_expression(b)?;
|
||||
self.emit(Instruction::DeleteSubscript);
|
||||
}
|
||||
ast::Expression::Tuple { elements } => {
|
||||
ast::ExpressionType::Tuple { elements } => {
|
||||
for element in elements {
|
||||
self.compile_delete(element)?;
|
||||
}
|
||||
@@ -663,10 +663,10 @@ impl Compiler {
|
||||
|
||||
fn compile_try_statement(
|
||||
&mut self,
|
||||
body: &[ast::LocatedStatement],
|
||||
body: &[ast::Statement],
|
||||
handlers: &[ast::ExceptHandler],
|
||||
orelse: &Option<Vec<ast::LocatedStatement>>,
|
||||
finalbody: &Option<Vec<ast::LocatedStatement>>,
|
||||
orelse: &Option<Vec<ast::Statement>>,
|
||||
finalbody: &Option<Vec<ast::Statement>>,
|
||||
) -> Result<(), CompileError> {
|
||||
let mut handler_label = self.new_label();
|
||||
let finally_label = self.new_label();
|
||||
@@ -764,7 +764,7 @@ impl Compiler {
|
||||
&mut self,
|
||||
name: &str,
|
||||
args: &ast::Parameters,
|
||||
body: &[ast::LocatedStatement],
|
||||
body: &[ast::Statement],
|
||||
decorator_list: &[ast::Expression],
|
||||
returns: &Option<ast::Expression>, // TODO: use type hint somehow..
|
||||
) -> Result<(), CompileError> {
|
||||
@@ -858,7 +858,7 @@ impl Compiler {
|
||||
fn compile_class_def(
|
||||
&mut self,
|
||||
name: &str,
|
||||
body: &[ast::LocatedStatement],
|
||||
body: &[ast::Statement],
|
||||
bases: &[ast::Expression],
|
||||
keywords: &[ast::Keyword],
|
||||
decorator_list: &[ast::Expression],
|
||||
@@ -989,8 +989,8 @@ impl Compiler {
|
||||
&mut self,
|
||||
target: &ast::Expression,
|
||||
iter: &ast::Expression,
|
||||
body: &[ast::LocatedStatement],
|
||||
orelse: &Option<Vec<ast::LocatedStatement>>,
|
||||
body: &[ast::Statement],
|
||||
orelse: &Option<Vec<ast::Statement>>,
|
||||
) -> Result<(), CompileError> {
|
||||
// Start loop
|
||||
let start_label = self.new_label();
|
||||
@@ -1104,27 +1104,27 @@ impl Compiler {
|
||||
}
|
||||
|
||||
fn compile_store(&mut self, target: &ast::Expression) -> Result<(), CompileError> {
|
||||
match target {
|
||||
ast::Expression::Identifier { name } => {
|
||||
match &target.node {
|
||||
ast::ExpressionType::Identifier { name } => {
|
||||
self.store_name(name);
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => {
|
||||
ast::ExpressionType::Subscript { a, b } => {
|
||||
self.compile_expression(a)?;
|
||||
self.compile_expression(b)?;
|
||||
self.emit(Instruction::StoreSubscript);
|
||||
}
|
||||
ast::Expression::Attribute { value, name } => {
|
||||
ast::ExpressionType::Attribute { value, name } => {
|
||||
self.compile_expression(value)?;
|
||||
self.emit(Instruction::StoreAttr {
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
ast::Expression::List { elements } | ast::Expression::Tuple { elements } => {
|
||||
ast::ExpressionType::List { elements } | ast::ExpressionType::Tuple { elements } => {
|
||||
let mut seen_star = false;
|
||||
|
||||
// Scan for star args:
|
||||
for (i, element) in elements.iter().enumerate() {
|
||||
if let ast::Expression::Starred { .. } = element {
|
||||
if let ast::ExpressionType::Starred { .. } = &element.node {
|
||||
if seen_star {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::StarArgs,
|
||||
@@ -1147,7 +1147,7 @@ impl Compiler {
|
||||
}
|
||||
|
||||
for element in elements {
|
||||
if let ast::Expression::Starred { value } = element {
|
||||
if let ast::ExpressionType::Starred { value } = &element.node {
|
||||
self.compile_store(value)?;
|
||||
} else {
|
||||
self.compile_store(element)?;
|
||||
@@ -1192,8 +1192,8 @@ impl Compiler {
|
||||
context: EvalContext,
|
||||
) -> Result<(), CompileError> {
|
||||
// Compile expression for test, and jump to label if false
|
||||
match expression {
|
||||
ast::Expression::BoolOp { a, op, b } => match op {
|
||||
match &expression.node {
|
||||
ast::ExpressionType::BoolOp { a, op, b } => match op {
|
||||
ast::BooleanOperator::And => {
|
||||
let f = false_label.unwrap_or_else(|| self.new_label());
|
||||
self.compile_test(a, None, Some(f), context)?;
|
||||
@@ -1246,23 +1246,27 @@ impl Compiler {
|
||||
|
||||
fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), CompileError> {
|
||||
trace!("Compiling {:?}", expression);
|
||||
match expression {
|
||||
ast::Expression::Call {
|
||||
use ast::ExpressionType::*;
|
||||
match &expression.node {
|
||||
Call {
|
||||
function,
|
||||
args,
|
||||
keywords,
|
||||
} => self.compile_call(function, args, keywords)?,
|
||||
ast::Expression::BoolOp { .. } => {
|
||||
self.compile_test(expression, None, None, EvalContext::Expression)?
|
||||
}
|
||||
ast::Expression::Binop { a, op, b } => {
|
||||
BoolOp { .. } => self.compile_test(
|
||||
expression,
|
||||
Option::None,
|
||||
Option::None,
|
||||
EvalContext::Expression,
|
||||
)?,
|
||||
Binop { a, op, b } => {
|
||||
self.compile_expression(a)?;
|
||||
self.compile_expression(b)?;
|
||||
|
||||
// Perform operation:
|
||||
self.compile_op(op, false);
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => {
|
||||
Subscript { a, b } => {
|
||||
self.compile_expression(a)?;
|
||||
self.compile_expression(b)?;
|
||||
self.emit(Instruction::BinaryOperation {
|
||||
@@ -1270,7 +1274,7 @@ impl Compiler {
|
||||
inplace: false,
|
||||
});
|
||||
}
|
||||
ast::Expression::Unop { op, a } => {
|
||||
Unop { op, a } => {
|
||||
self.compile_expression(a)?;
|
||||
|
||||
// Perform operation:
|
||||
@@ -1283,16 +1287,16 @@ impl Compiler {
|
||||
let i = Instruction::UnaryOperation { op: i };
|
||||
self.emit(i);
|
||||
}
|
||||
ast::Expression::Attribute { value, name } => {
|
||||
Attribute { value, name } => {
|
||||
self.compile_expression(value)?;
|
||||
self.emit(Instruction::LoadAttr {
|
||||
name: name.to_string(),
|
||||
});
|
||||
}
|
||||
ast::Expression::Compare { vals, ops } => {
|
||||
Compare { vals, ops } => {
|
||||
self.compile_chained_comparison(vals, ops)?;
|
||||
}
|
||||
ast::Expression::Number { value } => {
|
||||
Number { value } => {
|
||||
let const_value = match value {
|
||||
ast::Number::Integer { value } => bytecode::Constant::Integer {
|
||||
value: value.clone(),
|
||||
@@ -1304,7 +1308,7 @@ impl Compiler {
|
||||
};
|
||||
self.emit(Instruction::LoadConst { value: const_value });
|
||||
}
|
||||
ast::Expression::List { elements } => {
|
||||
List { elements } => {
|
||||
let size = elements.len();
|
||||
let must_unpack = self.gather_elements(elements)?;
|
||||
self.emit(Instruction::BuildList {
|
||||
@@ -1312,7 +1316,7 @@ impl Compiler {
|
||||
unpack: must_unpack,
|
||||
});
|
||||
}
|
||||
ast::Expression::Tuple { elements } => {
|
||||
Tuple { elements } => {
|
||||
let size = elements.len();
|
||||
let must_unpack = self.gather_elements(elements)?;
|
||||
self.emit(Instruction::BuildTuple {
|
||||
@@ -1320,7 +1324,7 @@ impl Compiler {
|
||||
unpack: must_unpack,
|
||||
});
|
||||
}
|
||||
ast::Expression::Set { elements } => {
|
||||
Set { elements } => {
|
||||
let size = elements.len();
|
||||
let must_unpack = self.gather_elements(elements)?;
|
||||
self.emit(Instruction::BuildSet {
|
||||
@@ -1328,7 +1332,7 @@ impl Compiler {
|
||||
unpack: must_unpack,
|
||||
});
|
||||
}
|
||||
ast::Expression::Dict { elements } => {
|
||||
Dict { elements } => {
|
||||
let size = elements.len();
|
||||
let has_double_star = elements.iter().any(|e| e.0.is_none());
|
||||
for (key, value) in elements {
|
||||
@@ -1351,14 +1355,14 @@ impl Compiler {
|
||||
unpack: has_double_star,
|
||||
});
|
||||
}
|
||||
ast::Expression::Slice { elements } => {
|
||||
Slice { elements } => {
|
||||
let size = elements.len();
|
||||
for element in elements {
|
||||
self.compile_expression(element)?;
|
||||
}
|
||||
self.emit(Instruction::BuildSlice { size });
|
||||
}
|
||||
ast::Expression::Yield { value } => {
|
||||
Yield { value } => {
|
||||
if !self.in_function_def {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::InvalidYield,
|
||||
@@ -1368,16 +1372,16 @@ impl Compiler {
|
||||
self.mark_generator();
|
||||
match value {
|
||||
Some(expression) => self.compile_expression(expression)?,
|
||||
None => self.emit(Instruction::LoadConst {
|
||||
Option::None => self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::None,
|
||||
}),
|
||||
};
|
||||
self.emit(Instruction::YieldValue);
|
||||
}
|
||||
ast::Expression::Await { .. } => {
|
||||
Await { .. } => {
|
||||
unimplemented!("await");
|
||||
}
|
||||
ast::Expression::YieldFrom { value } => {
|
||||
YieldFrom { value } => {
|
||||
self.mark_generator();
|
||||
self.compile_expression(value)?;
|
||||
self.emit(Instruction::GetIter);
|
||||
@@ -1386,40 +1390,40 @@ impl Compiler {
|
||||
});
|
||||
self.emit(Instruction::YieldFrom);
|
||||
}
|
||||
ast::Expression::True => {
|
||||
True => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Boolean { value: true },
|
||||
});
|
||||
}
|
||||
ast::Expression::False => {
|
||||
False => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Boolean { value: false },
|
||||
});
|
||||
}
|
||||
ast::Expression::None => {
|
||||
None => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::None,
|
||||
});
|
||||
}
|
||||
ast::Expression::Ellipsis => {
|
||||
Ellipsis => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Ellipsis,
|
||||
});
|
||||
}
|
||||
ast::Expression::String { value } => {
|
||||
String { value } => {
|
||||
self.compile_string(value)?;
|
||||
}
|
||||
ast::Expression::Bytes { value } => {
|
||||
Bytes { value } => {
|
||||
self.emit(Instruction::LoadConst {
|
||||
value: bytecode::Constant::Bytes {
|
||||
value: value.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
ast::Expression::Identifier { name } => {
|
||||
Identifier { name } => {
|
||||
self.load_name(name);
|
||||
}
|
||||
ast::Expression::Lambda { args, body } => {
|
||||
Lambda { args, body } => {
|
||||
let name = "<lambda>".to_string();
|
||||
// no need to worry about the self.loop_depth because there are no loops in lambda expressions
|
||||
let flags = self.enter_function(&name, args)?;
|
||||
@@ -1438,18 +1442,18 @@ impl Compiler {
|
||||
// Turn code object into function object:
|
||||
self.emit(Instruction::MakeFunction { flags });
|
||||
}
|
||||
ast::Expression::Comprehension { kind, generators } => {
|
||||
Comprehension { kind, generators } => {
|
||||
self.compile_comprehension(kind, generators)?;
|
||||
}
|
||||
ast::Expression::Starred { value } => {
|
||||
Starred { value } => {
|
||||
self.compile_expression(value)?;
|
||||
self.emit(Instruction::Unpack);
|
||||
panic!("We should not just unpack a starred args, since the size is unknown.");
|
||||
}
|
||||
ast::Expression::IfExpression { test, body, orelse } => {
|
||||
IfExpression { test, body, orelse } => {
|
||||
let no_label = self.new_label();
|
||||
let end_label = self.new_label();
|
||||
self.compile_test(test, None, None, EvalContext::Expression)?;
|
||||
self.compile_test(test, Option::None, Option::None, EvalContext::Expression)?;
|
||||
self.emit(Instruction::JumpIfFalse { target: no_label });
|
||||
// True case
|
||||
self.compile_expression(body)?;
|
||||
@@ -1557,7 +1561,7 @@ impl Compiler {
|
||||
fn gather_elements(&mut self, elements: &[ast::Expression]) -> Result<bool, CompileError> {
|
||||
// First determine if we have starred elements:
|
||||
let has_stars = elements.iter().any(|e| {
|
||||
if let ast::Expression::Starred { .. } = e {
|
||||
if let ast::ExpressionType::Starred { .. } = &e.node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -1565,7 +1569,7 @@ impl Compiler {
|
||||
});
|
||||
|
||||
for element in elements {
|
||||
if let ast::Expression::Starred { value } = element {
|
||||
if let ast::ExpressionType::Starred { value } = &element.node {
|
||||
self.compile_expression(value)?;
|
||||
} else {
|
||||
self.compile_expression(element)?;
|
||||
@@ -1792,7 +1796,7 @@ impl Compiler {
|
||||
assert!(scope.sub_scopes.is_empty());
|
||||
}
|
||||
|
||||
fn lookup_name(&self, name: &str) -> &SymbolRole {
|
||||
fn lookup_name(&self, name: &str) -> &Symbol {
|
||||
// println!("Looking up {:?}", name);
|
||||
let scope = self.scope_stack.last().unwrap();
|
||||
scope.lookup(name).unwrap()
|
||||
@@ -1846,10 +1850,10 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_doc(body: &[ast::LocatedStatement]) -> (&[ast::LocatedStatement], Option<String>) {
|
||||
fn get_doc(body: &[ast::Statement]) -> (&[ast::Statement], Option<String>) {
|
||||
if let Some(val) = body.get(0) {
|
||||
if let ast::Statement::Expression { ref expression } = val.node {
|
||||
if let ast::Expression::String { ref value } = expression {
|
||||
if let ast::StatementType::Expression { ref expression } = val.node {
|
||||
if let ast::ExpressionType::String { value } = &expression.node {
|
||||
if let ast::StringGroup::Constant { ref value } = value {
|
||||
if let Some((_, body_rest)) = body.split_first() {
|
||||
return (body_rest, Some(value.to_string()));
|
||||
|
||||
+152
-118
@@ -24,7 +24,7 @@ pub fn make_symbol_table(program: &ast::Program) -> Result<SymbolScope, SymbolTa
|
||||
}
|
||||
|
||||
pub fn statements_to_symbol_table(
|
||||
statements: &[ast::LocatedStatement],
|
||||
statements: &[ast::Statement],
|
||||
) -> Result<SymbolScope, SymbolTableError> {
|
||||
let mut builder: SymbolTableBuilder = Default::default();
|
||||
builder.enter_scope();
|
||||
@@ -36,25 +36,46 @@ pub fn statements_to_symbol_table(
|
||||
Ok(symbol_table)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SymbolRole {
|
||||
Global,
|
||||
Nonlocal,
|
||||
Used,
|
||||
Assigned,
|
||||
}
|
||||
|
||||
/// Captures all symbols in the current scope, and has a list of subscopes in this scope.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct SymbolScope {
|
||||
/// A set of symbols present on this scope level.
|
||||
pub symbols: IndexMap<String, SymbolRole>,
|
||||
pub symbols: IndexMap<String, Symbol>,
|
||||
|
||||
/// A list of subscopes in the order as found in the
|
||||
/// AST nodes.
|
||||
pub sub_scopes: Vec<SymbolScope>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Symbol {
|
||||
pub name: String,
|
||||
pub is_global: bool,
|
||||
pub is_local: bool,
|
||||
pub is_nonlocal: bool,
|
||||
pub is_param: bool,
|
||||
pub is_referenced: bool,
|
||||
pub is_assigned: bool,
|
||||
pub is_parameter: bool,
|
||||
pub is_free: bool,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
fn new(name: &str) -> Self {
|
||||
Symbol {
|
||||
name: name.to_string(),
|
||||
is_global: false,
|
||||
is_local: false,
|
||||
is_nonlocal: false,
|
||||
is_param: false,
|
||||
is_referenced: false,
|
||||
is_assigned: false,
|
||||
is_parameter: false,
|
||||
is_free: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SymbolTableError {
|
||||
error: String,
|
||||
@@ -73,20 +94,11 @@ impl From<SymbolTableError> for CompileError {
|
||||
type SymbolTableResult = Result<(), SymbolTableError>;
|
||||
|
||||
impl SymbolScope {
|
||||
pub fn lookup(&self, name: &str) -> Option<&SymbolRole> {
|
||||
pub fn lookup(&self, name: &str) -> Option<&Symbol> {
|
||||
self.symbols.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SymbolScope {
|
||||
fn default() -> Self {
|
||||
SymbolScope {
|
||||
symbols: Default::default(),
|
||||
sub_scopes: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SymbolScope {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
@@ -111,74 +123,73 @@ fn analyze_symbol_table(
|
||||
}
|
||||
|
||||
// Analyze symbols:
|
||||
for (symbol_name, symbol_role) in &symbol_scope.symbols {
|
||||
analyze_symbol(symbol_name, symbol_role, parent_symbol_scope)?;
|
||||
for symbol in symbol_scope.symbols.values() {
|
||||
analyze_symbol(symbol, parent_symbol_scope)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
fn analyze_symbol(
|
||||
symbol_name: &str,
|
||||
symbol_role: &SymbolRole,
|
||||
parent_symbol_scope: Option<&SymbolScope>,
|
||||
) -> SymbolTableResult {
|
||||
match symbol_role {
|
||||
SymbolRole::Nonlocal => {
|
||||
// check if name is defined in parent scope!
|
||||
if let Some(parent_symbol_scope) = parent_symbol_scope {
|
||||
if !parent_symbol_scope.symbols.contains_key(symbol_name) {
|
||||
return Err(SymbolTableError {
|
||||
error: format!("no binding for nonlocal '{}' found", symbol_name),
|
||||
location: Default::default(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
fn analyze_symbol(symbol: &Symbol, parent_symbol_scope: Option<&SymbolScope>) -> SymbolTableResult {
|
||||
if symbol.is_nonlocal {
|
||||
// check if name is defined in parent scope!
|
||||
if let Some(parent_symbol_scope) = parent_symbol_scope {
|
||||
if !parent_symbol_scope.symbols.contains_key(&symbol.name) {
|
||||
return Err(SymbolTableError {
|
||||
error: format!(
|
||||
"nonlocal {} defined at place without an enclosing scope",
|
||||
symbol_name
|
||||
),
|
||||
error: format!("no binding for nonlocal '{}' found", symbol.name),
|
||||
location: Default::default(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(SymbolTableError {
|
||||
error: format!(
|
||||
"nonlocal {} defined at place without an enclosing scope",
|
||||
symbol.name
|
||||
),
|
||||
location: Default::default(),
|
||||
});
|
||||
}
|
||||
// TODO: add more checks for globals
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// TODO: add more checks for globals
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct SymbolTableBuilder {
|
||||
// Scope stack.
|
||||
pub scopes: Vec<SymbolScope>,
|
||||
#[derive(Debug, Clone)]
|
||||
enum SymbolRole {
|
||||
Global,
|
||||
Nonlocal,
|
||||
Used,
|
||||
Assigned,
|
||||
}
|
||||
|
||||
impl Default for SymbolTableBuilder {
|
||||
fn default() -> Self {
|
||||
SymbolTableBuilder { scopes: vec![] }
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct SymbolTableBuilder {
|
||||
// Scope stack.
|
||||
scopes: Vec<SymbolScope>,
|
||||
}
|
||||
|
||||
impl SymbolTableBuilder {
|
||||
pub fn enter_scope(&mut self) {
|
||||
fn enter_scope(&mut self) {
|
||||
let scope = Default::default();
|
||||
self.scopes.push(scope);
|
||||
// self.work_scopes.push(Default::default());
|
||||
}
|
||||
|
||||
fn leave_scope(&mut self) {
|
||||
// Pop scope and add to subscopes of parent scope.
|
||||
// let work_scope = self.work_scopes.pop().unwrap();
|
||||
let scope = self.scopes.pop().unwrap();
|
||||
self.scopes.last_mut().unwrap().sub_scopes.push(scope);
|
||||
}
|
||||
|
||||
pub fn scan_program(&mut self, program: &ast::Program) -> SymbolTableResult {
|
||||
fn scan_program(&mut self, program: &ast::Program) -> SymbolTableResult {
|
||||
self.scan_statements(&program.statements)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn scan_statements(&mut self, statements: &[ast::LocatedStatement]) -> SymbolTableResult {
|
||||
fn scan_statements(&mut self, statements: &[ast::Statement]) -> SymbolTableResult {
|
||||
for statement in statements {
|
||||
self.scan_statement(statement)?;
|
||||
}
|
||||
@@ -210,26 +221,27 @@ impl SymbolTableBuilder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn scan_statement(&mut self, statement: &ast::LocatedStatement) -> SymbolTableResult {
|
||||
fn scan_statement(&mut self, statement: &ast::Statement) -> SymbolTableResult {
|
||||
use ast::StatementType::*;
|
||||
match &statement.node {
|
||||
ast::Statement::Global { names } => {
|
||||
Global { names } => {
|
||||
for name in names {
|
||||
self.register_name(name, SymbolRole::Global)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::Nonlocal { names } => {
|
||||
Nonlocal { names } => {
|
||||
for name in names {
|
||||
self.register_name(name, SymbolRole::Nonlocal)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::FunctionDef {
|
||||
FunctionDef {
|
||||
name,
|
||||
body,
|
||||
args,
|
||||
decorator_list,
|
||||
returns,
|
||||
}
|
||||
| ast::Statement::AsyncFunctionDef {
|
||||
| AsyncFunctionDef {
|
||||
name,
|
||||
body,
|
||||
args,
|
||||
@@ -247,7 +259,7 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
self.leave_scope();
|
||||
}
|
||||
ast::Statement::ClassDef {
|
||||
ClassDef {
|
||||
name,
|
||||
body,
|
||||
bases,
|
||||
@@ -264,21 +276,21 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
self.scan_expressions(decorator_list)?;
|
||||
}
|
||||
ast::Statement::Expression { expression } => self.scan_expression(expression)?,
|
||||
ast::Statement::If { test, body, orelse } => {
|
||||
Expression { expression } => self.scan_expression(expression)?,
|
||||
If { test, body, orelse } => {
|
||||
self.scan_expression(test)?;
|
||||
self.scan_statements(body)?;
|
||||
if let Some(code) = orelse {
|
||||
self.scan_statements(code)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::For {
|
||||
For {
|
||||
target,
|
||||
iter,
|
||||
body,
|
||||
orelse,
|
||||
}
|
||||
| ast::Statement::AsyncFor {
|
||||
| AsyncFor {
|
||||
target,
|
||||
iter,
|
||||
body,
|
||||
@@ -291,17 +303,17 @@ impl SymbolTableBuilder {
|
||||
self.scan_statements(code)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::While { test, body, orelse } => {
|
||||
While { test, body, orelse } => {
|
||||
self.scan_expression(test)?;
|
||||
self.scan_statements(body)?;
|
||||
if let Some(code) = orelse {
|
||||
self.scan_statements(code)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::Break | ast::Statement::Continue | ast::Statement::Pass => {
|
||||
Break | Continue | Pass => {
|
||||
// No symbols here.
|
||||
}
|
||||
ast::Statement::Import { names } | ast::Statement::ImportFrom { names, .. } => {
|
||||
Import { names } | ImportFrom { names, .. } => {
|
||||
for name in names {
|
||||
if let Some(alias) = &name.alias {
|
||||
// `import mymodule as myalias`
|
||||
@@ -312,29 +324,29 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Statement::Return { value } => {
|
||||
Return { value } => {
|
||||
if let Some(expression) = value {
|
||||
self.scan_expression(expression)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::Assert { test, msg } => {
|
||||
Assert { test, msg } => {
|
||||
self.scan_expression(test)?;
|
||||
if let Some(expression) = msg {
|
||||
self.scan_expression(expression)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::Delete { targets } => {
|
||||
Delete { targets } => {
|
||||
self.scan_expressions(targets)?;
|
||||
}
|
||||
ast::Statement::Assign { targets, value } => {
|
||||
Assign { targets, value } => {
|
||||
self.scan_expressions(targets)?;
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
ast::Statement::AugAssign { target, value, .. } => {
|
||||
AugAssign { target, value, .. } => {
|
||||
self.scan_expression(target)?;
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
ast::Statement::With { items, body } => {
|
||||
With { items, body } => {
|
||||
for item in items {
|
||||
self.scan_expression(&item.context_expr)?;
|
||||
if let Some(expression) = &item.optional_vars {
|
||||
@@ -343,7 +355,7 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
self.scan_statements(body)?;
|
||||
}
|
||||
ast::Statement::Try {
|
||||
Try {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
@@ -366,7 +378,7 @@ impl SymbolTableBuilder {
|
||||
self.scan_statements(code)?;
|
||||
}
|
||||
}
|
||||
ast::Statement::Raise { exception, cause } => {
|
||||
Raise { exception, cause } => {
|
||||
if let Some(expression) = exception {
|
||||
self.scan_expression(expression)?;
|
||||
}
|
||||
@@ -386,26 +398,27 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
|
||||
fn scan_expression(&mut self, expression: &ast::Expression) -> SymbolTableResult {
|
||||
match expression {
|
||||
ast::Expression::Binop { a, b, .. } => {
|
||||
use ast::ExpressionType::*;
|
||||
match &expression.node {
|
||||
Binop { a, b, .. } => {
|
||||
self.scan_expression(a)?;
|
||||
self.scan_expression(b)?;
|
||||
}
|
||||
ast::Expression::BoolOp { a, b, .. } => {
|
||||
BoolOp { a, b, .. } => {
|
||||
self.scan_expression(a)?;
|
||||
self.scan_expression(b)?;
|
||||
}
|
||||
ast::Expression::Compare { vals, .. } => {
|
||||
Compare { vals, .. } => {
|
||||
self.scan_expressions(vals)?;
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => {
|
||||
Subscript { a, b } => {
|
||||
self.scan_expression(a)?;
|
||||
self.scan_expression(b)?;
|
||||
}
|
||||
ast::Expression::Attribute { value, .. } => {
|
||||
Attribute { value, .. } => {
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
ast::Expression::Dict { elements } => {
|
||||
Dict { elements } => {
|
||||
for (key, value) in elements {
|
||||
if let Some(key) = key {
|
||||
self.scan_expression(key)?;
|
||||
@@ -415,36 +428,30 @@ impl SymbolTableBuilder {
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
}
|
||||
ast::Expression::Await { value } => {
|
||||
Await { value } => {
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
ast::Expression::Yield { value } => {
|
||||
Yield { value } => {
|
||||
if let Some(expression) = value {
|
||||
self.scan_expression(expression)?;
|
||||
}
|
||||
}
|
||||
ast::Expression::YieldFrom { value } => {
|
||||
YieldFrom { value } => {
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
ast::Expression::Unop { a, .. } => {
|
||||
Unop { a, .. } => {
|
||||
self.scan_expression(a)?;
|
||||
}
|
||||
ast::Expression::True
|
||||
| ast::Expression::False
|
||||
| ast::Expression::None
|
||||
| ast::Expression::Ellipsis => {}
|
||||
ast::Expression::Number { .. } => {}
|
||||
ast::Expression::Starred { value } => {
|
||||
True | False | None | Ellipsis => {}
|
||||
Number { .. } => {}
|
||||
Starred { value } => {
|
||||
self.scan_expression(value)?;
|
||||
}
|
||||
ast::Expression::Bytes { .. } => {}
|
||||
ast::Expression::Tuple { elements }
|
||||
| ast::Expression::Set { elements }
|
||||
| ast::Expression::List { elements }
|
||||
| ast::Expression::Slice { elements } => {
|
||||
Bytes { .. } => {}
|
||||
Tuple { elements } | Set { elements } | List { elements } | Slice { elements } => {
|
||||
self.scan_expressions(elements)?;
|
||||
}
|
||||
ast::Expression::Comprehension { kind, generators } => {
|
||||
Comprehension { kind, generators } => {
|
||||
match **kind {
|
||||
ast::ComprehensionKind::GeneratorExpression { ref element }
|
||||
| ast::ComprehensionKind::List { ref element }
|
||||
@@ -465,7 +472,7 @@ impl SymbolTableBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expression::Call {
|
||||
Call {
|
||||
function,
|
||||
args,
|
||||
keywords,
|
||||
@@ -476,18 +483,18 @@ impl SymbolTableBuilder {
|
||||
self.scan_expression(&keyword.value)?;
|
||||
}
|
||||
}
|
||||
ast::Expression::String { value } => {
|
||||
String { value } => {
|
||||
self.scan_string_group(value)?;
|
||||
}
|
||||
ast::Expression::Identifier { name } => {
|
||||
Identifier { name } => {
|
||||
self.register_name(name, SymbolRole::Used)?;
|
||||
}
|
||||
ast::Expression::Lambda { args, body } => {
|
||||
Lambda { args, body } => {
|
||||
self.enter_function(args)?;
|
||||
self.scan_expression(body)?;
|
||||
self.leave_scope();
|
||||
}
|
||||
ast::Expression::IfExpression { test, body, orelse } => {
|
||||
IfExpression { test, body, orelse } => {
|
||||
self.scan_expression(test)?;
|
||||
self.scan_expression(body)?;
|
||||
self.scan_expression(orelse)?;
|
||||
@@ -549,6 +556,8 @@ impl SymbolTableBuilder {
|
||||
let scope_depth = self.scopes.len();
|
||||
let current_scope = self.scopes.last_mut().unwrap();
|
||||
let location = Default::default();
|
||||
|
||||
// Some checks:
|
||||
if current_scope.symbols.contains_key(name) {
|
||||
// Role already set..
|
||||
match role {
|
||||
@@ -568,22 +577,47 @@ impl SymbolTableBuilder {
|
||||
// Ok?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match role {
|
||||
SymbolRole::Nonlocal => {
|
||||
if scope_depth < 2 {
|
||||
return Err(SymbolTableError {
|
||||
error: format!("cannot define nonlocal '{}' at top level.", name),
|
||||
location,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Ok!
|
||||
}
|
||||
|
||||
// Some more checks:
|
||||
match role {
|
||||
SymbolRole::Nonlocal => {
|
||||
if scope_depth < 2 {
|
||||
return Err(SymbolTableError {
|
||||
error: format!("cannot define nonlocal '{}' at top level.", name),
|
||||
location,
|
||||
});
|
||||
}
|
||||
}
|
||||
current_scope.symbols.insert(name.to_string(), role);
|
||||
_ => {
|
||||
// Ok!
|
||||
}
|
||||
}
|
||||
|
||||
// Insert symbol when required:
|
||||
if !current_scope.symbols.contains_key(name) {
|
||||
let symbol = Symbol::new(name);
|
||||
current_scope.symbols.insert(name.to_string(), symbol);
|
||||
}
|
||||
|
||||
// Set proper flags on symbol:
|
||||
let symbol = current_scope.symbols.get_mut(name).unwrap();
|
||||
match role {
|
||||
SymbolRole::Nonlocal => {
|
||||
symbol.is_nonlocal = true;
|
||||
}
|
||||
SymbolRole::Assigned => {
|
||||
symbol.is_assigned = true;
|
||||
// symbol.is_local = true;
|
||||
}
|
||||
SymbolRole::Global => {
|
||||
symbol.is_global = true;
|
||||
}
|
||||
SymbolRole::Used => {
|
||||
symbol.is_referenced = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+16
-2
@@ -26,7 +26,8 @@ print(t)
|
||||
shift = 3
|
||||
def print_node(node, indent=0):
|
||||
if isinstance(node, ast.AST):
|
||||
print(' '*indent, "NODE", node.__class__.__name__)
|
||||
lineno = 'row={}'.format(node.lineno) if hasattr(node, 'lineno') else ''
|
||||
print(' '*indent, "NODE", node.__class__.__name__, lineno)
|
||||
for field in node._fields:
|
||||
print(' '*indent,'-', field)
|
||||
f = getattr(node, field)
|
||||
@@ -41,12 +42,25 @@ def print_node(node, indent=0):
|
||||
print_node(t)
|
||||
|
||||
# print(ast.dump(t))
|
||||
flag_names = [
|
||||
'is_referenced',
|
||||
'is_assigned',
|
||||
'is_global',
|
||||
'is_local',
|
||||
'is_parameter',
|
||||
'is_free',
|
||||
]
|
||||
|
||||
def print_table(table, indent=0):
|
||||
print(' '*indent, 'table:', table.get_name())
|
||||
print(' '*indent, ' ', 'Syms:')
|
||||
for sym in table.get_symbols():
|
||||
print(' '*indent, ' ', sym.get_name(), 'is_referenced=', sym.is_referenced(), 'is_assigned=', sym.is_assigned())
|
||||
flags = []
|
||||
for flag_name in flag_names:
|
||||
func = getattr(sym, flag_name)
|
||||
if func():
|
||||
flags.append(flag_name)
|
||||
print(' '*indent, ' sym:', sym.get_name(), 'flags:', ' '.join(flags))
|
||||
print(' '*indent, ' ', 'Child tables:')
|
||||
for child in table.get_children():
|
||||
print_table(child, indent=indent+shift)
|
||||
|
||||
+25
-23
@@ -17,13 +17,13 @@ pub struct Node {
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Top {
|
||||
Program(Program),
|
||||
Statement(Vec<LocatedStatement>),
|
||||
Statement(Vec<Statement>),
|
||||
Expression(Expression),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Program {
|
||||
pub statements: Vec<LocatedStatement>,
|
||||
pub statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -38,12 +38,12 @@ pub struct Located<T> {
|
||||
pub node: T,
|
||||
}
|
||||
|
||||
pub type LocatedStatement = Located<Statement>;
|
||||
pub type Statement = Located<StatementType>;
|
||||
|
||||
/// Abstract syntax tree nodes for python statements.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Statement {
|
||||
pub enum StatementType {
|
||||
Break,
|
||||
Continue,
|
||||
Return {
|
||||
@@ -85,43 +85,43 @@ pub enum Statement {
|
||||
},
|
||||
If {
|
||||
test: Expression,
|
||||
body: Vec<LocatedStatement>,
|
||||
orelse: Option<Vec<LocatedStatement>>,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
},
|
||||
While {
|
||||
test: Expression,
|
||||
body: Vec<LocatedStatement>,
|
||||
orelse: Option<Vec<LocatedStatement>>,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
},
|
||||
With {
|
||||
items: Vec<WithItem>,
|
||||
body: Vec<LocatedStatement>,
|
||||
body: Vec<Statement>,
|
||||
},
|
||||
For {
|
||||
target: Expression,
|
||||
iter: Expression,
|
||||
body: Vec<LocatedStatement>,
|
||||
orelse: Option<Vec<LocatedStatement>>,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
},
|
||||
AsyncFor {
|
||||
target: Expression,
|
||||
iter: Expression,
|
||||
body: Vec<LocatedStatement>,
|
||||
orelse: Option<Vec<LocatedStatement>>,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
},
|
||||
Raise {
|
||||
exception: Option<Expression>,
|
||||
cause: Option<Expression>,
|
||||
},
|
||||
Try {
|
||||
body: Vec<LocatedStatement>,
|
||||
body: Vec<Statement>,
|
||||
handlers: Vec<ExceptHandler>,
|
||||
orelse: Option<Vec<LocatedStatement>>,
|
||||
finalbody: Option<Vec<LocatedStatement>>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
finalbody: Option<Vec<Statement>>,
|
||||
},
|
||||
ClassDef {
|
||||
name: String,
|
||||
body: Vec<LocatedStatement>,
|
||||
body: Vec<Statement>,
|
||||
bases: Vec<Expression>,
|
||||
keywords: Vec<Keyword>,
|
||||
decorator_list: Vec<Expression>,
|
||||
@@ -129,14 +129,14 @@ pub enum Statement {
|
||||
FunctionDef {
|
||||
name: String,
|
||||
args: Parameters,
|
||||
body: Vec<LocatedStatement>,
|
||||
body: Vec<Statement>,
|
||||
decorator_list: Vec<Expression>,
|
||||
returns: Option<Expression>,
|
||||
},
|
||||
AsyncFunctionDef {
|
||||
name: String,
|
||||
args: Parameters,
|
||||
body: Vec<LocatedStatement>,
|
||||
body: Vec<Statement>,
|
||||
decorator_list: Vec<Expression>,
|
||||
returns: Option<Expression>,
|
||||
},
|
||||
@@ -148,8 +148,10 @@ pub struct WithItem {
|
||||
pub optional_vars: Option<Expression>,
|
||||
}
|
||||
|
||||
pub type Expression = Located<ExpressionType>;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Expression {
|
||||
pub enum ExpressionType {
|
||||
BoolOp {
|
||||
a: Box<Expression>,
|
||||
op: BooleanOperator,
|
||||
@@ -242,10 +244,10 @@ pub enum Expression {
|
||||
impl Expression {
|
||||
/// Returns a short name for the node suitable for use in error messages.
|
||||
pub fn name(&self) -> &'static str {
|
||||
use self::Expression::*;
|
||||
use self::ExpressionType::*;
|
||||
use self::StringGroup::*;
|
||||
|
||||
match self {
|
||||
match &self.node {
|
||||
BoolOp { .. } | Binop { .. } | Unop { .. } => "operator",
|
||||
Subscript { .. } => "subscript",
|
||||
Await { .. } => "await expression",
|
||||
@@ -330,7 +332,7 @@ pub struct Keyword {
|
||||
pub struct ExceptHandler {
|
||||
pub typ: Option<Expression>,
|
||||
pub name: Option<String>,
|
||||
pub body: Vec<LocatedStatement>,
|
||||
pub body: Vec<Statement>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
||||
@@ -173,9 +173,12 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn mk_ident(name: &str) -> ast::Expression {
|
||||
ast::Expression::Identifier {
|
||||
name: name.to_owned(),
|
||||
fn mk_ident(name: &str, row: usize, col: usize) -> ast::Expression {
|
||||
ast::Expression {
|
||||
location: ast::Location::new(row, col),
|
||||
node: ast::ExpressionType::Identifier {
|
||||
name: name.to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,12 +192,12 @@ mod tests {
|
||||
Joined {
|
||||
values: vec![
|
||||
FormattedValue {
|
||||
value: Box::new(mk_ident("a")),
|
||||
value: Box::new(mk_ident("a", 1, 1)),
|
||||
conversion: None,
|
||||
spec: String::new(),
|
||||
},
|
||||
FormattedValue {
|
||||
value: Box::new(mk_ident("b")),
|
||||
value: Box::new(mk_ident("b", 1, 1)),
|
||||
conversion: None,
|
||||
spec: String::new(),
|
||||
},
|
||||
|
||||
+195
-253
@@ -35,7 +35,7 @@ pub fn parse_program(source: &str) -> Result<ast::Program, ParseError> {
|
||||
do_lalr_parsing!(source, Program, StartProgram)
|
||||
}
|
||||
|
||||
pub fn parse_statement(source: &str) -> Result<Vec<ast::LocatedStatement>, ParseError> {
|
||||
pub fn parse_statement(source: &str) -> Result<Vec<ast::Statement>, ParseError> {
|
||||
do_lalr_parsing!(source, Statement, StartStatement)
|
||||
}
|
||||
|
||||
@@ -46,16 +46,25 @@ pub fn parse_statement(source: &str) -> Result<Vec<ast::LocatedStatement>, Parse
|
||||
/// extern crate num_bigint;
|
||||
/// use num_bigint::BigInt;
|
||||
/// use rustpython_parser::{parser, ast};
|
||||
/// let expr = parser::parse_expression("1+2").unwrap();
|
||||
/// let expr = parser::parse_expression("1 + 2").unwrap();
|
||||
///
|
||||
/// assert_eq!(ast::Expression::Binop {
|
||||
/// a: Box::new(ast::Expression::Number {
|
||||
/// value: ast::Number::Integer { value: BigInt::from(1) }
|
||||
/// }),
|
||||
/// op: ast::Operator::Add,
|
||||
/// b: Box::new(ast::Expression::Number {
|
||||
/// value: ast::Number::Integer { value: BigInt::from(2) }
|
||||
/// })
|
||||
/// assert_eq!(ast::Expression {
|
||||
/// location: ast::Location::new(1, 3),
|
||||
/// node: ast::ExpressionType::Binop {
|
||||
/// a: Box::new(ast::Expression {
|
||||
/// location: ast::Location::new(1, 1),
|
||||
/// node: ast::ExpressionType::Number {
|
||||
/// value: ast::Number::Integer { value: BigInt::from(1) }
|
||||
/// }
|
||||
/// }),
|
||||
/// op: ast::Operator::Add,
|
||||
/// b: Box::new(ast::Expression {
|
||||
/// location: ast::Location::new(1, 5),
|
||||
/// node: ast::ExpressionType::Number {
|
||||
/// value: ast::Number::Integer { value: BigInt::from(2) }
|
||||
/// }
|
||||
/// })
|
||||
/// }
|
||||
/// },
|
||||
/// expr);
|
||||
///
|
||||
@@ -72,6 +81,44 @@ mod tests {
|
||||
use super::parse_statement;
|
||||
use num_bigint::BigInt;
|
||||
|
||||
fn mk_ident(name: &str, row: usize, col: usize) -> ast::Expression {
|
||||
ast::Expression {
|
||||
location: ast::Location::new(row, col),
|
||||
node: ast::ExpressionType::Identifier {
|
||||
name: name.to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn make_int(value: i32, row: usize, col: usize) -> ast::Expression {
|
||||
ast::Expression {
|
||||
location: ast::Location::new(row, col),
|
||||
node: ast::ExpressionType::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(value),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn make_string(value: &str, row: usize, col: usize) -> ast::Expression {
|
||||
ast::Expression {
|
||||
location: ast::Location::new(row, col),
|
||||
node: ast::ExpressionType::String {
|
||||
value: ast::StringGroup::Constant {
|
||||
value: String::from(value),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn as_statement(expr: ast::Expression) -> ast::Statement {
|
||||
ast::Statement {
|
||||
location: expr.location.clone(),
|
||||
node: ast::StatementType::Expression { expression: expr },
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_empty() {
|
||||
let parse_ast = parse_program(&String::from("\n"));
|
||||
@@ -85,19 +132,16 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Program {
|
||||
statements: vec![ast::LocatedStatement {
|
||||
statements: vec![ast::Statement {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("print"),
|
||||
}),
|
||||
args: vec![ast::Expression::String {
|
||||
value: ast::StringGroup::Constant {
|
||||
value: String::from("Hello world")
|
||||
}
|
||||
}],
|
||||
keywords: vec![],
|
||||
node: ast::StatementType::Expression {
|
||||
expression: ast::Expression {
|
||||
location: ast::Location::new(1, 6),
|
||||
node: ast::ExpressionType::Call {
|
||||
function: Box::new(mk_ident("print", 1, 1)),
|
||||
args: vec![make_string("Hello world", 1, 8)],
|
||||
keywords: vec![],
|
||||
}
|
||||
},
|
||||
},
|
||||
},],
|
||||
@@ -112,26 +156,16 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Program {
|
||||
statements: vec![ast::LocatedStatement {
|
||||
statements: vec![ast::Statement {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("print"),
|
||||
}),
|
||||
args: vec![
|
||||
ast::Expression::String {
|
||||
value: ast::StringGroup::Constant {
|
||||
value: String::from("Hello world"),
|
||||
}
|
||||
},
|
||||
ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(2)
|
||||
},
|
||||
}
|
||||
],
|
||||
keywords: vec![],
|
||||
node: ast::StatementType::Expression {
|
||||
expression: ast::Expression {
|
||||
location: ast::Location::new(1, 6),
|
||||
node: ast::ExpressionType::Call {
|
||||
function: Box::new(mk_ident("print", 1, 1)),
|
||||
args: vec![make_string("Hello world", 1, 8), make_int(2, 1, 22),],
|
||||
keywords: vec![],
|
||||
},
|
||||
},
|
||||
},
|
||||
},],
|
||||
@@ -146,26 +180,19 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Program {
|
||||
statements: vec![ast::LocatedStatement {
|
||||
statements: vec![ast::Statement {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Call {
|
||||
function: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("my_func"),
|
||||
}),
|
||||
args: vec![ast::Expression::String {
|
||||
value: ast::StringGroup::Constant {
|
||||
value: String::from("positional"),
|
||||
}
|
||||
}],
|
||||
keywords: vec![ast::Keyword {
|
||||
name: Some("keyword".to_string()),
|
||||
value: ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(2)
|
||||
},
|
||||
}
|
||||
}],
|
||||
node: ast::StatementType::Expression {
|
||||
expression: ast::Expression {
|
||||
location: ast::Location::new(1, 8),
|
||||
node: ast::ExpressionType::Call {
|
||||
function: Box::new(mk_ident("my_func", 1, 1)),
|
||||
args: vec![make_string("positional", 1, 10)],
|
||||
keywords: vec![ast::Keyword {
|
||||
name: Some("keyword".to_string()),
|
||||
value: make_int(2, 1, 31),
|
||||
}],
|
||||
}
|
||||
},
|
||||
},
|
||||
},],
|
||||
@@ -179,52 +206,17 @@ mod tests {
|
||||
let parse_ast = parse_statement(&source).unwrap();
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
vec![ast::LocatedStatement {
|
||||
vec![ast::Statement {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::If {
|
||||
test: ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(1)
|
||||
},
|
||||
},
|
||||
body: vec![ast::LocatedStatement {
|
||||
location: ast::Location::new(1, 7),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(10)
|
||||
},
|
||||
}
|
||||
},
|
||||
},],
|
||||
orelse: Some(vec![ast::LocatedStatement {
|
||||
node: ast::StatementType::If {
|
||||
test: make_int(1, 1, 4),
|
||||
body: vec![as_statement(make_int(10, 1, 7))],
|
||||
orelse: Some(vec![ast::Statement {
|
||||
location: ast::Location::new(2, 1),
|
||||
node: ast::Statement::If {
|
||||
test: ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(2)
|
||||
},
|
||||
},
|
||||
body: vec![ast::LocatedStatement {
|
||||
location: ast::Location::new(2, 9),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(20)
|
||||
},
|
||||
},
|
||||
},
|
||||
},],
|
||||
orelse: Some(vec![ast::LocatedStatement {
|
||||
location: ast::Location::new(3, 7),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(30)
|
||||
},
|
||||
},
|
||||
},
|
||||
},]),
|
||||
node: ast::StatementType::If {
|
||||
test: make_int(2, 2, 6),
|
||||
body: vec![as_statement(make_int(20, 2, 9))],
|
||||
orelse: Some(vec![as_statement(make_int(30, 3, 7))]),
|
||||
}
|
||||
},]),
|
||||
}
|
||||
@@ -238,39 +230,36 @@ mod tests {
|
||||
let parse_ast = parse_statement(&source);
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
Ok(vec![ast::LocatedStatement {
|
||||
Ok(vec![as_statement(ast::Expression {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::Expression {
|
||||
expression: ast::Expression::Lambda {
|
||||
args: ast::Parameters {
|
||||
args: vec![
|
||||
ast::Parameter {
|
||||
arg: String::from("x"),
|
||||
annotation: None,
|
||||
},
|
||||
ast::Parameter {
|
||||
arg: String::from("y"),
|
||||
annotation: None,
|
||||
}
|
||||
],
|
||||
kwonlyargs: vec![],
|
||||
vararg: ast::Varargs::None,
|
||||
kwarg: ast::Varargs::None,
|
||||
defaults: vec![],
|
||||
kw_defaults: vec![],
|
||||
},
|
||||
body: Box::new(ast::Expression::Binop {
|
||||
a: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("x"),
|
||||
}),
|
||||
node: ast::ExpressionType::Lambda {
|
||||
args: ast::Parameters {
|
||||
args: vec![
|
||||
ast::Parameter {
|
||||
arg: String::from("x"),
|
||||
annotation: None,
|
||||
},
|
||||
ast::Parameter {
|
||||
arg: String::from("y"),
|
||||
annotation: None,
|
||||
}
|
||||
],
|
||||
kwonlyargs: vec![],
|
||||
vararg: ast::Varargs::None,
|
||||
kwarg: ast::Varargs::None,
|
||||
defaults: vec![],
|
||||
kw_defaults: vec![],
|
||||
},
|
||||
body: Box::new(ast::Expression {
|
||||
location: ast::Location::new(1, 16),
|
||||
node: ast::ExpressionType::Binop {
|
||||
a: Box::new(mk_ident("x", 1, 14)),
|
||||
op: ast::Operator::Mult,
|
||||
b: Box::new(ast::Expression::Identifier {
|
||||
name: String::from("y"),
|
||||
})
|
||||
})
|
||||
}
|
||||
b: Box::new(mk_ident("y", 1, 18))
|
||||
}
|
||||
})
|
||||
}
|
||||
}])
|
||||
})])
|
||||
)
|
||||
}
|
||||
|
||||
@@ -280,32 +269,20 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
parse_statement(&source),
|
||||
Ok(vec![ast::LocatedStatement {
|
||||
Ok(vec![ast::Statement {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::Assign {
|
||||
targets: vec![ast::Expression::Tuple {
|
||||
elements: vec![
|
||||
ast::Expression::Identifier {
|
||||
name: "a".to_string()
|
||||
},
|
||||
ast::Expression::Identifier {
|
||||
name: "b".to_string()
|
||||
}
|
||||
]
|
||||
node: ast::StatementType::Assign {
|
||||
targets: vec![ast::Expression {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::ExpressionType::Tuple {
|
||||
elements: vec![mk_ident("a", 1, 1), mk_ident("b", 1, 4),]
|
||||
}
|
||||
}],
|
||||
value: ast::Expression::Tuple {
|
||||
elements: vec![
|
||||
ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(4)
|
||||
}
|
||||
},
|
||||
ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(5)
|
||||
}
|
||||
}
|
||||
]
|
||||
value: ast::Expression {
|
||||
location: ast::Location::new(1, 8),
|
||||
node: ast::ExpressionType::Tuple {
|
||||
elements: vec![make_int(4, 1, 8), make_int(5, 1, 11),]
|
||||
}
|
||||
}
|
||||
}
|
||||
}])
|
||||
@@ -319,23 +296,16 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
parse_statement(&source),
|
||||
Ok(vec![ast::LocatedStatement {
|
||||
Ok(vec![ast::Statement {
|
||||
location: ast::Location::new(1, 1),
|
||||
node: ast::Statement::ClassDef {
|
||||
node: ast::StatementType::ClassDef {
|
||||
name: String::from("Foo"),
|
||||
bases: vec![
|
||||
ast::Expression::Identifier {
|
||||
name: String::from("A")
|
||||
},
|
||||
ast::Expression::Identifier {
|
||||
name: String::from("B")
|
||||
}
|
||||
],
|
||||
bases: vec![mk_ident("A", 1, 11), mk_ident("B", 1, 14)],
|
||||
keywords: vec![],
|
||||
body: vec![
|
||||
ast::LocatedStatement {
|
||||
ast::Statement {
|
||||
location: ast::Location::new(2, 2),
|
||||
node: ast::Statement::FunctionDef {
|
||||
node: ast::StatementType::FunctionDef {
|
||||
name: String::from("__init__"),
|
||||
args: ast::Parameters {
|
||||
args: vec![ast::Parameter {
|
||||
@@ -348,17 +318,17 @@ mod tests {
|
||||
defaults: vec![],
|
||||
kw_defaults: vec![],
|
||||
},
|
||||
body: vec![ast::LocatedStatement {
|
||||
body: vec![ast::Statement {
|
||||
location: ast::Location::new(3, 3),
|
||||
node: ast::Statement::Pass,
|
||||
node: ast::StatementType::Pass,
|
||||
}],
|
||||
decorator_list: vec![],
|
||||
returns: None,
|
||||
}
|
||||
},
|
||||
ast::LocatedStatement {
|
||||
ast::Statement {
|
||||
location: ast::Location::new(4, 2),
|
||||
node: ast::Statement::FunctionDef {
|
||||
node: ast::StatementType::FunctionDef {
|
||||
name: String::from("method_with_default"),
|
||||
args: ast::Parameters {
|
||||
args: vec![
|
||||
@@ -374,16 +344,12 @@ mod tests {
|
||||
kwonlyargs: vec![],
|
||||
vararg: ast::Varargs::None,
|
||||
kwarg: ast::Varargs::None,
|
||||
defaults: vec![ast::Expression::String {
|
||||
value: ast::StringGroup::Constant {
|
||||
value: "default".to_string()
|
||||
}
|
||||
}],
|
||||
defaults: vec![make_string("default", 4, 37)],
|
||||
kw_defaults: vec![],
|
||||
},
|
||||
body: vec![ast::LocatedStatement {
|
||||
body: vec![ast::Statement {
|
||||
location: ast::Location::new(5, 3),
|
||||
node: ast::Statement::Pass,
|
||||
node: ast::StatementType::Pass,
|
||||
}],
|
||||
decorator_list: vec![],
|
||||
returns: None,
|
||||
@@ -402,21 +368,18 @@ mod tests {
|
||||
let parse_ast = parse_expression(&source).unwrap();
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::List {
|
||||
element: ast::Expression::Identifier {
|
||||
name: "x".to_string()
|
||||
}
|
||||
}),
|
||||
generators: vec![ast::Comprehension {
|
||||
target: ast::Expression::Identifier {
|
||||
name: "y".to_string()
|
||||
},
|
||||
iter: ast::Expression::Identifier {
|
||||
name: "z".to_string()
|
||||
},
|
||||
ifs: vec![],
|
||||
}],
|
||||
ast::Expression {
|
||||
location: ast::Location::new(1, 2),
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::List {
|
||||
element: mk_ident("x", 1, 2),
|
||||
}),
|
||||
generators: vec![ast::Comprehension {
|
||||
target: mk_ident("y", 1, 8),
|
||||
iter: mk_ident("z", 1, 13),
|
||||
ifs: vec![],
|
||||
}],
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -427,66 +390,45 @@ mod tests {
|
||||
let parse_ast = parse_expression(&source).unwrap();
|
||||
assert_eq!(
|
||||
parse_ast,
|
||||
ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::List {
|
||||
element: ast::Expression::Identifier {
|
||||
name: "x".to_string()
|
||||
}
|
||||
}),
|
||||
generators: vec![
|
||||
ast::Comprehension {
|
||||
target: ast::Expression::Tuple {
|
||||
elements: vec![
|
||||
ast::Expression::Identifier {
|
||||
name: "y".to_string()
|
||||
ast::Expression {
|
||||
location: ast::Location::new(1, 2),
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::List {
|
||||
element: mk_ident("x", 1, 2)
|
||||
}),
|
||||
generators: vec![
|
||||
ast::Comprehension {
|
||||
target: ast::Expression {
|
||||
location: ast::Location::new(1, 8),
|
||||
node: ast::ExpressionType::Tuple {
|
||||
elements: vec![mk_ident("y", 1, 8), mk_ident("y2", 1, 11),],
|
||||
}
|
||||
},
|
||||
iter: mk_ident("z", 1, 17),
|
||||
ifs: vec![],
|
||||
},
|
||||
ast::Comprehension {
|
||||
target: mk_ident("a", 1, 23),
|
||||
iter: mk_ident("b", 1, 28),
|
||||
ifs: vec![
|
||||
ast::Expression {
|
||||
location: ast::Location::new(1, 35),
|
||||
node: ast::ExpressionType::Compare {
|
||||
vals: vec![mk_ident("a", 1, 33), make_int(5, 1, 37),],
|
||||
ops: vec![ast::Comparison::Less],
|
||||
}
|
||||
},
|
||||
ast::Expression::Identifier {
|
||||
name: "y2".to_string()
|
||||
ast::Expression {
|
||||
location: ast::Location::new(1, 44),
|
||||
node: ast::ExpressionType::Compare {
|
||||
vals: vec![mk_ident("a", 1, 42), make_int(10, 1, 46),],
|
||||
ops: vec![ast::Comparison::Greater],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
iter: ast::Expression::Identifier {
|
||||
name: "z".to_string()
|
||||
},
|
||||
ifs: vec![],
|
||||
},
|
||||
ast::Comprehension {
|
||||
target: ast::Expression::Identifier {
|
||||
name: "a".to_string()
|
||||
},
|
||||
iter: ast::Expression::Identifier {
|
||||
name: "b".to_string()
|
||||
},
|
||||
ifs: vec![
|
||||
ast::Expression::Compare {
|
||||
vals: vec![
|
||||
ast::Expression::Identifier {
|
||||
name: "a".to_string()
|
||||
},
|
||||
ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(5)
|
||||
}
|
||||
}
|
||||
],
|
||||
ops: vec![ast::Comparison::Less],
|
||||
},
|
||||
ast::Expression::Compare {
|
||||
vals: vec![
|
||||
ast::Expression::Identifier {
|
||||
name: "a".to_string()
|
||||
},
|
||||
ast::Expression::Number {
|
||||
value: ast::Number::Integer {
|
||||
value: BigInt::from(10)
|
||||
}
|
||||
}
|
||||
],
|
||||
ops: vec![ast::Comparison::Greater],
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+356
-219
@@ -31,22 +31,22 @@ Program: ast::Program = {
|
||||
};
|
||||
|
||||
// A file line either has a declaration, or an empty newline:
|
||||
FileLine: Vec<ast::LocatedStatement> = {
|
||||
FileLine: Vec<ast::Statement> = {
|
||||
Statement,
|
||||
"\n" => vec![],
|
||||
};
|
||||
|
||||
Suite: Vec<ast::LocatedStatement> = {
|
||||
Suite: Vec<ast::Statement> = {
|
||||
SimpleStatement,
|
||||
"\n" indent <s:Statement+> dedent => s.into_iter().flatten().collect(),
|
||||
};
|
||||
|
||||
Statement: Vec<ast::LocatedStatement> = {
|
||||
Statement: Vec<ast::Statement> = {
|
||||
SimpleStatement,
|
||||
<s:CompoundStatement> => vec![s],
|
||||
};
|
||||
|
||||
SimpleStatement: Vec<ast::LocatedStatement> = {
|
||||
SimpleStatement: Vec<ast::Statement> = {
|
||||
<s1:SmallStatement> <s2:(";" SmallStatement)*> ";"? "\n" => {
|
||||
let mut statements = vec![s1];
|
||||
statements.extend(s2.into_iter().map(|e| e.1));
|
||||
@@ -54,7 +54,7 @@ SimpleStatement: Vec<ast::LocatedStatement> = {
|
||||
}
|
||||
};
|
||||
|
||||
SmallStatement: ast::LocatedStatement = {
|
||||
SmallStatement: ast::Statement = {
|
||||
ExpressionStatement,
|
||||
PassStatement,
|
||||
DelStatement,
|
||||
@@ -65,52 +65,52 @@ SmallStatement: ast::LocatedStatement = {
|
||||
AssertStatement,
|
||||
};
|
||||
|
||||
PassStatement: ast::LocatedStatement = {
|
||||
PassStatement: ast::Statement = {
|
||||
<loc:@L> "pass" => {
|
||||
ast::LocatedStatement {
|
||||
ast::Statement {
|
||||
location: loc,
|
||||
node: ast::Statement::Pass,
|
||||
node: ast::StatementType::Pass,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
DelStatement: ast::LocatedStatement = {
|
||||
DelStatement: ast::Statement = {
|
||||
<loc:@L> "del" <e:ExpressionList2> => {
|
||||
ast::LocatedStatement {
|
||||
ast::Statement {
|
||||
location: loc,
|
||||
node: ast::Statement::Delete { targets: e },
|
||||
node: ast::StatementType::Delete { targets: e },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ExpressionStatement: ast::LocatedStatement = {
|
||||
<loc:@L> <expr:TestOrStarExprList> <suffix:AssignSuffix*> => {
|
||||
ExpressionStatement: ast::Statement = {
|
||||
<location:@L> <expr:TestOrStarExprList> <suffix:AssignSuffix*> => {
|
||||
// Just an expression, no assignment:
|
||||
if suffix.is_empty() {
|
||||
ast::LocatedStatement {
|
||||
location: loc.clone(),
|
||||
node: ast::Statement::Expression { expression: expr }
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Expression { expression: expr }
|
||||
}
|
||||
} else {
|
||||
let mut targets = vec![expr];
|
||||
let mut values = suffix;
|
||||
let mut targets = vec![expr];
|
||||
let mut values = suffix;
|
||||
|
||||
while values.len() > 1 {
|
||||
while values.len() > 1 {
|
||||
targets.push(values.remove(0));
|
||||
}
|
||||
}
|
||||
|
||||
let value = values.into_iter().next().unwrap();
|
||||
let value = values.into_iter().next().unwrap();
|
||||
|
||||
ast::LocatedStatement {
|
||||
location: loc.clone(),
|
||||
node: ast::Statement::Assign { targets, value },
|
||||
}
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Assign { targets, value },
|
||||
}
|
||||
}
|
||||
},
|
||||
<loc:@L> <expr:TestOrStarExprList> <op:AugAssign> <rhs:TestList> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::AugAssign {
|
||||
<location:@L> <expr:TestOrStarExprList> <op:AugAssign> <rhs:TestList> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::AugAssign {
|
||||
target: Box::new(expr),
|
||||
op,
|
||||
value: Box::new(rhs)
|
||||
@@ -125,11 +125,14 @@ AssignSuffix: ast::Expression = {
|
||||
};
|
||||
|
||||
TestOrStarExprList: ast::Expression = {
|
||||
<elements:OneOrMore<TestOrStarExpr>> <comma:","?> => {
|
||||
<location:@L> <elements:OneOrMore<TestOrStarExpr>> <comma:","?> => {
|
||||
if elements.len() == 1 && comma.is_none() {
|
||||
elements.into_iter().next().unwrap()
|
||||
} else {
|
||||
ast::Expression::Tuple { elements }
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Tuple { elements }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -155,60 +158,60 @@ AugAssign: ast::Operator = {
|
||||
"//=" => ast::Operator::FloorDiv,
|
||||
};
|
||||
|
||||
FlowStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "break" => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Break,
|
||||
FlowStatement: ast::Statement = {
|
||||
<location:@L> "break" => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Break,
|
||||
}
|
||||
},
|
||||
<loc:@L> "continue" => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Continue,
|
||||
<location:@L> "continue" => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Continue,
|
||||
}
|
||||
},
|
||||
<loc:@L> "return" <value:TestList?> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Return { value },
|
||||
<location:@L> "return" <value:TestList?> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Return { value },
|
||||
}
|
||||
},
|
||||
<loc:@L> <y:YieldExpr> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Expression { expression: y },
|
||||
<location:@L> <y:YieldExpr> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Expression { expression: y },
|
||||
}
|
||||
},
|
||||
RaiseStatement,
|
||||
};
|
||||
|
||||
RaiseStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "raise" => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Raise { exception: None, cause: None },
|
||||
RaiseStatement: ast::Statement = {
|
||||
<location:@L> "raise" => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Raise { exception: None, cause: None },
|
||||
}
|
||||
},
|
||||
<loc:@L> "raise" <t:Test> <c:("from" Test)?> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Raise { exception: Some(t), cause: c.map(|x| x.1) },
|
||||
<location:@L> "raise" <t:Test> <c:("from" Test)?> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Raise { exception: Some(t), cause: c.map(|x| x.1) },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ImportStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "import" <names: Comma<ImportPart<<DottedName>>>> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Import { names },
|
||||
ImportStatement: ast::Statement = {
|
||||
<location:@L> "import" <names: Comma<ImportPart<<DottedName>>>> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Import { names },
|
||||
}
|
||||
},
|
||||
<loc:@L> "from" <n:ImportFromLocation> "import" <names: ImportAsNames> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::ImportFrom {
|
||||
<location:@L> "from" <n:ImportFromLocation> "import" <names: ImportAsNames> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::ImportFrom {
|
||||
level: n.0,
|
||||
module: n.1,
|
||||
names
|
||||
@@ -259,36 +262,36 @@ DottedName: String = {
|
||||
},
|
||||
};
|
||||
|
||||
GlobalStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "global" <names:OneOrMore<Identifier>> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Global { names }
|
||||
GlobalStatement: ast::Statement = {
|
||||
<location:@L> "global" <names:OneOrMore<Identifier>> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Global { names }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
NonlocalStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "nonlocal" <names:OneOrMore<Identifier>> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Nonlocal { names }
|
||||
NonlocalStatement: ast::Statement = {
|
||||
<location:@L> "nonlocal" <names:OneOrMore<Identifier>> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Nonlocal { names }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
AssertStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "assert" <test:Test> <msg: ("," Test)?> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Assert {
|
||||
AssertStatement: ast::Statement = {
|
||||
<location:@L> "assert" <test:Test> <msg: ("," Test)?> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Assert {
|
||||
test, msg: msg.map(|e| e.1)
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
CompoundStatement: ast::LocatedStatement = {
|
||||
CompoundStatement: ast::Statement = {
|
||||
IfStatement,
|
||||
WhileStatement,
|
||||
ForStatement,
|
||||
@@ -298,58 +301,58 @@ CompoundStatement: ast::LocatedStatement = {
|
||||
ClassDef,
|
||||
};
|
||||
|
||||
IfStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "if" <test:Test> ":" <s1:Suite> <s2:(@L "elif" Test ":" Suite)*> <s3:("else" ":" Suite)?> => {
|
||||
IfStatement: ast::Statement = {
|
||||
<location:@L> "if" <test:Test> ":" <s1:Suite> <s2:(@L "elif" Test ":" Suite)*> <s3:("else" ":" Suite)?> => {
|
||||
// Determine last else:
|
||||
let mut last = s3.map(|s| s.2);
|
||||
|
||||
// handle elif:
|
||||
for i in s2.into_iter().rev() {
|
||||
let x = ast::LocatedStatement {
|
||||
let x = ast::Statement {
|
||||
location: i.0,
|
||||
node: ast::Statement::If { test: i.2, body: i.4, orelse: last },
|
||||
node: ast::StatementType::If { test: i.2, body: i.4, orelse: last },
|
||||
};
|
||||
last = Some(vec![x]);
|
||||
}
|
||||
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::If { test, body: s1, orelse: last }
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::If { test, body: s1, orelse: last }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
WhileStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "while" <test:Test> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
|
||||
WhileStatement: ast::Statement = {
|
||||
<location:@L> "while" <test:Test> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
|
||||
let or_else = s2.map(|s| s.2);
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::While { test, body, orelse: or_else },
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::While { test, body, orelse: or_else },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ForStatement: ast::LocatedStatement = {
|
||||
<loc:@L> <is_async:"async"?> "for" <target:ExpressionList> "in" <iter:TestList> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
|
||||
ForStatement: ast::Statement = {
|
||||
<location:@L> <is_async:"async"?> "for" <target:ExpressionList> "in" <iter:TestList> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
|
||||
let orelse = s2.map(|s| s.2);
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
ast::Statement {
|
||||
location,
|
||||
node: if is_async.is_some() {
|
||||
ast::Statement::AsyncFor { target, iter, body, orelse }
|
||||
ast::StatementType::AsyncFor { target, iter, body, orelse }
|
||||
} else {
|
||||
ast::Statement::For { target, iter, body, orelse }
|
||||
ast::StatementType::For { target, iter, body, orelse }
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
TryStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "try" ":" <body:Suite> <handlers:ExceptClause*> <else_suite:("else" ":" Suite)?> <finally:("finally" ":" Suite)?> => {
|
||||
TryStatement: ast::Statement = {
|
||||
<location:@L> "try" ":" <body:Suite> <handlers:ExceptClause*> <else_suite:("else" ":" Suite)?> <finally:("finally" ":" Suite)?> => {
|
||||
let or_else = else_suite.map(|s| s.2);
|
||||
let finalbody = finally.map(|s| s.2);
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::Try {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Try {
|
||||
body: body,
|
||||
handlers: handlers,
|
||||
orelse: or_else,
|
||||
@@ -376,11 +379,11 @@ ExceptClause: ast::ExceptHandler = {
|
||||
},
|
||||
};
|
||||
|
||||
WithStatement: ast::LocatedStatement = {
|
||||
<loc:@L> "with" <items:OneOrMore<WithItem>> ":" <s:Suite> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::With { items: items, body: s },
|
||||
WithStatement: ast::Statement = {
|
||||
<location:@L> "with" <items:OneOrMore<WithItem>> ":" <s:Suite> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::With { items: items, body: s },
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -392,12 +395,12 @@ WithItem: ast::WithItem = {
|
||||
},
|
||||
};
|
||||
|
||||
FuncDef: ast::LocatedStatement = {
|
||||
<d:Decorator*> <loc:@L> <is_async:"async"?> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
FuncDef: ast::Statement = {
|
||||
<d:Decorator*> <location:@L> <is_async:"async"?> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
|
||||
ast::Statement {
|
||||
location,
|
||||
node: if is_async.is_some() {
|
||||
ast::Statement::AsyncFunctionDef {
|
||||
ast::StatementType::AsyncFunctionDef {
|
||||
name: i,
|
||||
args: a,
|
||||
body: s,
|
||||
@@ -405,7 +408,7 @@ FuncDef: ast::LocatedStatement = {
|
||||
returns: r.map(|x| x.1),
|
||||
}
|
||||
} else {
|
||||
ast::Statement::FunctionDef {
|
||||
ast::StatementType::FunctionDef {
|
||||
name: i,
|
||||
args: a,
|
||||
body: s,
|
||||
@@ -552,43 +555,55 @@ KwargParameter<ArgType>: Option<ast::Parameter> = {
|
||||
}
|
||||
};
|
||||
|
||||
ClassDef: ast::LocatedStatement = {
|
||||
<d:Decorator*> <loc:@L> "class" <n:Identifier> <a:("(" ArgumentList ")")?> ":" <s:Suite> => {
|
||||
ClassDef: ast::Statement = {
|
||||
<d:Decorator*> <location:@L> "class" <name:Identifier> <a:("(" ArgumentList ")")?> ":" <body:Suite> => {
|
||||
let (bases, keywords) = match a {
|
||||
Some((_, args, _)) => args,
|
||||
None => (vec![], vec![]),
|
||||
};
|
||||
ast::LocatedStatement {
|
||||
location: loc,
|
||||
node: ast::Statement::ClassDef {
|
||||
name: n,
|
||||
bases: bases,
|
||||
keywords: keywords,
|
||||
body: s,
|
||||
decorator_list: d,
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::ClassDef {
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
body,
|
||||
decorator_list: d,
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Path: ast::Expression = {
|
||||
<n:Identifier> => ast::Expression::Identifier { name: n },
|
||||
<p:Path> "." <n:name> => {
|
||||
ast::Expression::Attribute {
|
||||
value: Box::new(p),
|
||||
name: n,
|
||||
<location:@L> <n:Identifier> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Identifier { name: n }
|
||||
},
|
||||
<p:Path> <location:@L> "." <n:name> => {
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Attribute {
|
||||
value: Box::new(p),
|
||||
name: n,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Decorators:
|
||||
Decorator: ast::Expression = {
|
||||
"@" <p:Path> <a: ("(" ArgumentList ")")?> "\n" => {
|
||||
"@" <p:Path> <a: (@L "(" ArgumentList ")")?> "\n" => {
|
||||
match a {
|
||||
Some((_, args, _)) => ast::Expression::Call {
|
||||
function: Box::new(p),
|
||||
args: args.0,
|
||||
keywords: args.1,
|
||||
Some((location, _, args, _)) => {
|
||||
let (args, keywords) = args;
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Call {
|
||||
function: Box::new(p),
|
||||
args,
|
||||
keywords,
|
||||
}
|
||||
}
|
||||
},
|
||||
None => p,
|
||||
}
|
||||
@@ -596,17 +611,26 @@ Decorator: ast::Expression = {
|
||||
};
|
||||
|
||||
YieldExpr: ast::Expression = {
|
||||
"yield" <value:TestList?> => ast::Expression::Yield { value: value.map(Box::new) },
|
||||
"yield" "from" <e:Test> => ast::Expression::YieldFrom { value: Box::new(e) },
|
||||
<location:@L> "yield" <value:TestList?> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Yield { value: value.map(Box::new) }
|
||||
},
|
||||
<location:@L> "yield" "from" <e:Test> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::YieldFrom { value: Box::new(e) }
|
||||
},
|
||||
};
|
||||
|
||||
Test: ast::Expression = {
|
||||
<expr:OrTest> <condition: ("if" OrTest "else" Test)?> => {
|
||||
<expr:OrTest> <condition: (@L "if" OrTest "else" Test)?> => {
|
||||
if let Some(c) = condition {
|
||||
ast::Expression::IfExpression {
|
||||
test: Box::new(c.1),
|
||||
body: Box::new(expr),
|
||||
orelse: Box::new(c.3),
|
||||
ast::Expression {
|
||||
location: c.0,
|
||||
node: ast::ExpressionType::IfExpression {
|
||||
test: Box::new(c.2),
|
||||
body: Box::new(expr),
|
||||
orelse: Box::new(c.4),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expr
|
||||
@@ -616,37 +640,52 @@ Test: ast::Expression = {
|
||||
};
|
||||
|
||||
LambdaDef: ast::Expression = {
|
||||
"lambda" <p:ParameterList<UntypedParameter>?> ":" <body:Test> =>
|
||||
ast::Expression::Lambda {
|
||||
args: p.unwrap_or(Default::default()),
|
||||
body: Box::new(body)
|
||||
<location:@L> "lambda" <p:ParameterList<UntypedParameter>?> ":" <body:Test> =>
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Lambda {
|
||||
args: p.unwrap_or(Default::default()),
|
||||
body: Box::new(body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OrTest: ast::Expression = {
|
||||
AndTest,
|
||||
<e1:OrTest> "or" <e2:AndTest> => ast::Expression::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::Or, b: Box::new(e2) },
|
||||
<e1:OrTest> <location:@L> "or" <e2:AndTest> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::Or, b: Box::new(e2) }
|
||||
},
|
||||
};
|
||||
|
||||
AndTest: ast::Expression = {
|
||||
NotTest,
|
||||
<e1:AndTest> "and" <e2:NotTest> => ast::Expression::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::And, b: Box::new(e2) },
|
||||
<e1:AndTest> <location:@L> "and" <e2:NotTest> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::BoolOp { a: Box::new(e1), op: ast::BooleanOperator::And, b: Box::new(e2) }
|
||||
},
|
||||
};
|
||||
|
||||
NotTest: ast::Expression = {
|
||||
"not" <e:NotTest> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Not },
|
||||
<location:@L> "not" <e:NotTest> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Unop { a: Box::new(e), op: ast::UnaryOperator::Not }
|
||||
},
|
||||
Comparison,
|
||||
};
|
||||
|
||||
Comparison: ast::Expression = {
|
||||
<e:Expression> <comparisons:(CompOp Expression)+> => {
|
||||
<e:Expression> <location:@L> <comparisons:(CompOp Expression)+> => {
|
||||
let mut vals = vec![e];
|
||||
let mut ops = vec![];
|
||||
for x in comparisons {
|
||||
ops.push(x.0);
|
||||
vals.push(x.1);
|
||||
}
|
||||
ast::Expression::Compare { vals, ops }
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Compare { vals, ops }
|
||||
}
|
||||
},
|
||||
Expression,
|
||||
};
|
||||
@@ -665,22 +704,34 @@ CompOp: ast::Comparison = {
|
||||
};
|
||||
|
||||
Expression: ast::Expression = {
|
||||
<e1:Expression> "|" <e2:XorExpression> => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitOr, b: Box::new(e2) },
|
||||
<e1:Expression> <location:@L> "|" <e2:XorExpression> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(e1), op: ast::Operator::BitOr, b: Box::new(e2) }
|
||||
},
|
||||
XorExpression,
|
||||
};
|
||||
|
||||
XorExpression: ast::Expression = {
|
||||
<e1:XorExpression> "^" <e2:AndExpression> => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitXor, b: Box::new(e2) },
|
||||
<e1:XorExpression> <location:@L> "^" <e2:AndExpression> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(e1), op: ast::Operator::BitXor, b: Box::new(e2) }
|
||||
},
|
||||
AndExpression,
|
||||
};
|
||||
|
||||
AndExpression: ast::Expression = {
|
||||
<e1:AndExpression> "&" <e2:ShiftExpression> => ast::Expression::Binop { a: Box::new(e1), op: ast::Operator::BitAnd, b: Box::new(e2) },
|
||||
<e1:AndExpression> <location:@L> "&" <e2:ShiftExpression> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(e1), op: ast::Operator::BitAnd, b: Box::new(e2) }
|
||||
},
|
||||
ShiftExpression,
|
||||
};
|
||||
|
||||
ShiftExpression: ast::Expression = {
|
||||
<e1:ShiftExpression> <op:ShiftOp> <e2:ArithmaticExpression> => ast::Expression::Binop { a: Box::new(e1), op: op, b: Box::new(e2) },
|
||||
<e1:ShiftExpression> <location:@L> <op:ShiftOp> <e2:ArithmaticExpression> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(e1), op: op, b: Box::new(e2) }
|
||||
},
|
||||
ArithmaticExpression,
|
||||
};
|
||||
|
||||
@@ -690,7 +741,10 @@ ShiftOp: ast::Operator = {
|
||||
};
|
||||
|
||||
ArithmaticExpression: ast::Expression = {
|
||||
<a:ArithmaticExpression> <op:AddOp> <b:Term> => ast::Expression::Binop { a: Box::new(a), op: op, b: Box::new(b) },
|
||||
<a:ArithmaticExpression> <location:@L> <op:AddOp> <b:Term> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(a), op: op, b: Box::new(b) }
|
||||
},
|
||||
Term,
|
||||
};
|
||||
|
||||
@@ -700,7 +754,10 @@ AddOp: ast::Operator = {
|
||||
};
|
||||
|
||||
Term: ast::Expression = {
|
||||
<a:Term> <op:MulOp> <b:Factor> => ast::Expression::Binop { a: Box::new(a), op: op, b: Box::new(b) },
|
||||
<a:Term> <location:@L> <op:MulOp> <b:Factor> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(a), op, b: Box::new(b) }
|
||||
},
|
||||
Factor,
|
||||
};
|
||||
|
||||
@@ -713,25 +770,38 @@ MulOp: ast::Operator = {
|
||||
};
|
||||
|
||||
Factor: ast::Expression = {
|
||||
"+" <e:Factor> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Pos },
|
||||
"-" <e:Factor> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Neg },
|
||||
"~" <e:Factor> => ast::Expression::Unop { a: Box::new(e), op: ast::UnaryOperator::Inv },
|
||||
<location:@L> <op:UnOp> <e:Factor> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Unop { a: Box::new(e), op }
|
||||
},
|
||||
Power,
|
||||
};
|
||||
|
||||
UnOp: ast::UnaryOperator = {
|
||||
"+" => ast::UnaryOperator::Pos,
|
||||
"-" => ast::UnaryOperator::Neg,
|
||||
"~" => ast::UnaryOperator::Inv,
|
||||
};
|
||||
|
||||
Power: ast::Expression = {
|
||||
<e:AtomExpr> <e2:("**" Factor)?> => {
|
||||
<e:AtomExpr> <e2:(@L "**" Factor)?> => {
|
||||
match e2 {
|
||||
None => e,
|
||||
Some(x) => ast::Expression::Binop { a: Box::new(e), op: ast::Operator::Pow, b: Box::new(x.1) },
|
||||
Some((location, _, b)) => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Binop { a: Box::new(e), op: ast::Operator::Pow, b: Box::new(b) }
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AtomExpr: ast::Expression = {
|
||||
<is_await:"await"?> <atom:AtomExpr2> => {
|
||||
<location:@L> <is_await:"await"?> <atom:AtomExpr2> => {
|
||||
if is_await.is_some() {
|
||||
ast::Expression::Await { value: Box::new(atom) }
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Await { value: Box::new(atom) }
|
||||
}
|
||||
} else {
|
||||
atom
|
||||
}
|
||||
@@ -740,13 +810,25 @@ AtomExpr: ast::Expression = {
|
||||
|
||||
AtomExpr2: ast::Expression = {
|
||||
Atom,
|
||||
<f:AtomExpr2> "(" <a:ArgumentList> ")" => ast::Expression::Call { function: Box::new(f), args: a.0, keywords: a.1 },
|
||||
<e:AtomExpr2> "[" <s:SubscriptList> "]" => ast::Expression::Subscript { a: Box::new(e), b: Box::new(s) },
|
||||
<e:AtomExpr2> "." <n:Identifier> => ast::Expression::Attribute { value: Box::new(e), name: n },
|
||||
<f:AtomExpr2> <location:@L> "(" <a:ArgumentList> ")" => {
|
||||
let (args, keywords) = a;
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Call { function: Box::new(f), args, keywords }
|
||||
}
|
||||
},
|
||||
<e:AtomExpr2> <location:@L> "[" <s:SubscriptList> "]" => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Subscript { a: Box::new(e), b: Box::new(s) }
|
||||
},
|
||||
<e:AtomExpr2> <location:@L> "." <name:Identifier> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Attribute { value: Box::new(e), name }
|
||||
},
|
||||
};
|
||||
|
||||
SubscriptList: ast::Expression = {
|
||||
<s1:Subscript> <s2:("," Subscript)*> ","? => {
|
||||
<location:@L> <s1:Subscript> <s2:("," Subscript)*> ","? => {
|
||||
if s2.is_empty() {
|
||||
s1
|
||||
} else {
|
||||
@@ -754,52 +836,86 @@ SubscriptList: ast::Expression = {
|
||||
for x in s2 {
|
||||
dims.push(x.1)
|
||||
}
|
||||
ast::Expression::Tuple { elements: dims }
|
||||
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Tuple { elements: dims },
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Subscript: ast::Expression = {
|
||||
Test,
|
||||
<e1:Test?> ":" <e2:Test?> <e3:SliceOp?> => {
|
||||
let s1 = e1.unwrap_or(ast::Expression::None);
|
||||
let s2 = e2.unwrap_or(ast::Expression::None);
|
||||
let s3 = e3.unwrap_or(ast::Expression::None);
|
||||
ast::Expression::Slice { elements: vec![s1, s2, s3] }
|
||||
<e1:Test?> <location:@L> ":" <e2:Test?> <e3:SliceOp?> => {
|
||||
let s1 = e1.unwrap_or(ast::Expression { location: location.clone(), node: ast::ExpressionType::None });
|
||||
let s2 = e2.unwrap_or(ast::Expression { location: location.clone(), node: ast::ExpressionType::None });
|
||||
let s3 = e3.unwrap_or(ast::Expression { location: location.clone(), node: ast::ExpressionType::None });
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Slice { elements: vec![s1, s2, s3] }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SliceOp: ast::Expression = {
|
||||
":" <e:Test?> => e.unwrap_or(ast::Expression::None)
|
||||
<location:@L> ":" <e:Test?> => e.unwrap_or(ast::Expression {location, node: ast::ExpressionType::None})
|
||||
}
|
||||
|
||||
Atom: ast::Expression = {
|
||||
<value:StringGroup> => ast::Expression::String { value },
|
||||
<value:Bytes> => ast::Expression::Bytes { value },
|
||||
<value:Number> => ast::Expression::Number { value },
|
||||
<name:Identifier> => ast::Expression::Identifier { name },
|
||||
"[" <e:TestListComp?> "]" => {
|
||||
<location:@L> <value:StringGroup> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::String { value }
|
||||
},
|
||||
<location:@L> <value:Bytes> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Bytes { value }
|
||||
},
|
||||
<location:@L> <value:Number> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Number { value }
|
||||
},
|
||||
<location:@L> <name:Identifier> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Identifier { name }
|
||||
},
|
||||
<location:@L> "[" <e:TestListComp?> "]" => {
|
||||
let elements = e.unwrap_or(Vec::new());
|
||||
ast::Expression::List { elements }
|
||||
},
|
||||
"[" <e:TestListComp2> "]" => e,
|
||||
"(" <elements:TestList?> ")" => {
|
||||
elements.unwrap_or(ast::Expression::Tuple { elements: Vec::new() })
|
||||
},
|
||||
"(" <e:Test> <c:CompFor> ")" => {
|
||||
ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::GeneratorExpression { element: e }),
|
||||
generators: c,
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::List { elements }
|
||||
}
|
||||
},
|
||||
"{" <e:TestDict?> "}" => ast::Expression::Dict { elements: e.unwrap_or(Vec::new()) },
|
||||
"[" <e:TestListComp2> "]" => e,
|
||||
<location:@L> "(" <elements:TestList?> ")" => {
|
||||
elements.unwrap_or(ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Tuple { elements: Vec::new() }
|
||||
})
|
||||
},
|
||||
<location:@L> "(" <e:Test> <c:CompFor> ")" => {
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::GeneratorExpression { element: e }),
|
||||
generators: c,
|
||||
}
|
||||
}
|
||||
},
|
||||
<location:@L> "{" <e:TestDict?> "}" => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Dict { elements: e.unwrap_or(Vec::new()) }
|
||||
},
|
||||
"{" <e:TestDictComp> "}" => e,
|
||||
"{" <e:TestSet> "}" => ast::Expression::Set { elements: e },
|
||||
<location:@L> "{" <e:TestSet> "}" => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Set { elements: e }
|
||||
},
|
||||
"{" <e:TestSetComp> "}" => e,
|
||||
"True" => ast::Expression::True,
|
||||
"False" => ast::Expression::False,
|
||||
"None" => ast::Expression::None,
|
||||
"..." => ast::Expression::Ellipsis,
|
||||
<location:@L> "True" => ast::Expression { location, node: ast::ExpressionType::True },
|
||||
<location:@L> "False" => ast::Expression { location, node: ast::ExpressionType::False },
|
||||
<location:@L> "None" => ast::Expression { location, node: ast::ExpressionType::None },
|
||||
<location:@L> "..." => ast::Expression { location, node: ast::ExpressionType::Ellipsis },
|
||||
};
|
||||
|
||||
TestListComp: Vec<ast::Expression> = {
|
||||
@@ -807,10 +923,13 @@ TestListComp: Vec<ast::Expression> = {
|
||||
};
|
||||
|
||||
TestListComp2: ast::Expression = {
|
||||
<e:TestOrStarExpr> <c:CompFor> => {
|
||||
ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::List { element: e }),
|
||||
generators: c,
|
||||
<location:@L> <e:TestOrStarExpr> <c:CompFor> => {
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::List { element: e }),
|
||||
generators: c,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -820,10 +939,13 @@ TestDict: Vec<(Option<ast::Expression>, ast::Expression)> = {
|
||||
};
|
||||
|
||||
TestDictComp: ast::Expression = {
|
||||
<e1:DictEntry> <c:CompFor> => {
|
||||
ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::Dict { key: e1.0, value: e1.1 }),
|
||||
generators: c,
|
||||
<location:@L> <e1:DictEntry> <c:CompFor> => {
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::Dict { key: e1.0, value: e1.1 }),
|
||||
generators: c,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -842,10 +964,13 @@ TestSet: Vec<ast::Expression> = {
|
||||
};
|
||||
|
||||
TestSetComp: ast::Expression = {
|
||||
<e1:Test> <c:CompFor> => {
|
||||
ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::Set { element: e1 }),
|
||||
generators: c,
|
||||
<location:@L> <e1:Test> <c:CompFor> => {
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::Set { element: e1 }),
|
||||
generators: c,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -856,11 +981,14 @@ ExpressionOrStarExpression = {
|
||||
};
|
||||
|
||||
ExpressionList: ast::Expression = {
|
||||
<elements: OneOrMore<ExpressionOrStarExpression>> <trailing_comma:","?> => {
|
||||
<location:@L> <elements: OneOrMore<ExpressionOrStarExpression>> <trailing_comma:","?> => {
|
||||
if elements.len() == 1 && trailing_comma.is_none() {
|
||||
elements.into_iter().next().unwrap()
|
||||
} else {
|
||||
ast::Expression::Tuple { elements }
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Tuple { elements },
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -874,18 +1002,24 @@ ExpressionList2: Vec<ast::Expression> = {
|
||||
// - a single expression
|
||||
// - a single expression followed by a trailing comma
|
||||
TestList: ast::Expression = {
|
||||
<elements:OneOrMore<Test>> <trailing_comma: ","?> => {
|
||||
<location:@L> <elements:OneOrMore<Test>> <trailing_comma: ","?> => {
|
||||
if elements.len() == 1 && trailing_comma.is_none() {
|
||||
elements.into_iter().next().unwrap()
|
||||
} else {
|
||||
ast::Expression::Tuple { elements }
|
||||
ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Tuple { elements },
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Test
|
||||
StarExpr: ast::Expression = {
|
||||
"*" <e:Expression> => ast::Expression::Starred { value: Box::new(e) },
|
||||
<location:@L> "*" <e:Expression> => ast::Expression {
|
||||
location,
|
||||
node: ast::ExpressionType::Starred { value: Box::new(e) },
|
||||
}
|
||||
};
|
||||
|
||||
// Comprehensions:
|
||||
@@ -911,7 +1045,7 @@ ArgumentList: (Vec<ast::Expression>, Vec<ast::Keyword>) = {
|
||||
},
|
||||
None => {
|
||||
// Allow starred args after keyword arguments.
|
||||
let is_starred = if let ast::Expression::Starred { .. } = &value {
|
||||
let is_starred = if let ast::ExpressionType::Starred { .. } = &value.node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -931,16 +1065,19 @@ ArgumentList: (Vec<ast::Expression>, Vec<ast::Keyword>) = {
|
||||
FunctionArgument: (Option<Option<String>>, ast::Expression) = {
|
||||
<e:Test> <c:CompFor?> => {
|
||||
let expr = match c {
|
||||
Some(c) => ast::Expression::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::GeneratorExpression { element: e }),
|
||||
generators: c,
|
||||
Some(c) => ast::Expression {
|
||||
location: e.location.clone(),
|
||||
node: ast::ExpressionType::Comprehension {
|
||||
kind: Box::new(ast::ComprehensionKind::GeneratorExpression { element: e }),
|
||||
generators: c,
|
||||
}
|
||||
},
|
||||
None => e,
|
||||
};
|
||||
(None, expr)
|
||||
},
|
||||
<i:Identifier> "=" <e:Test> => (Some(Some(i.clone())), e),
|
||||
"*" <e:Test> => (None, ast::Expression::Starred { value: Box::new(e) }),
|
||||
<location:@L> "*" <e:Test> => (None, ast::Expression { location, node: ast::ExpressionType::Starred { value: Box::new(e) } }),
|
||||
"**" <e:Test> => (Some(None), e),
|
||||
};
|
||||
|
||||
|
||||
+61
-67
@@ -58,10 +58,7 @@ fn create_node(vm: &VirtualMachine, name: &str) -> PyResult<AstNodeRef> {
|
||||
AstNode.into_ref_with_type(vm, vm.class("ast", name))
|
||||
}
|
||||
|
||||
fn statements_to_ast(
|
||||
vm: &VirtualMachine,
|
||||
statements: &[ast::LocatedStatement],
|
||||
) -> PyResult<PyListRef> {
|
||||
fn statements_to_ast(vm: &VirtualMachine, statements: &[ast::Statement]) -> PyResult<PyListRef> {
|
||||
let body: PyResult<Vec<_>> = statements
|
||||
.iter()
|
||||
.map(|statement| Ok(statement_to_ast(&vm, statement)?.into_object()))
|
||||
@@ -69,12 +66,10 @@ fn statements_to_ast(
|
||||
Ok(vm.ctx.new_list(body?).downcast().unwrap())
|
||||
}
|
||||
|
||||
fn statement_to_ast(
|
||||
vm: &VirtualMachine,
|
||||
statement: &ast::LocatedStatement,
|
||||
) -> PyResult<AstNodeRef> {
|
||||
fn statement_to_ast(vm: &VirtualMachine, statement: &ast::Statement) -> PyResult<AstNodeRef> {
|
||||
use ast::StatementType::*;
|
||||
let node = match &statement.node {
|
||||
ast::Statement::ClassDef {
|
||||
ClassDef {
|
||||
name,
|
||||
body,
|
||||
keywords,
|
||||
@@ -86,7 +81,7 @@ fn statement_to_ast(
|
||||
body => statements_to_ast(vm, body)?,
|
||||
decorator_list => expressions_to_ast(vm, decorator_list)?,
|
||||
}),
|
||||
ast::Statement::FunctionDef {
|
||||
FunctionDef {
|
||||
name,
|
||||
args,
|
||||
body,
|
||||
@@ -99,7 +94,7 @@ fn statement_to_ast(
|
||||
decorator_list => expressions_to_ast(vm, decorator_list)?,
|
||||
returns => optional_expression_to_ast(vm, returns)?
|
||||
}),
|
||||
ast::Statement::AsyncFunctionDef {
|
||||
AsyncFunctionDef {
|
||||
name,
|
||||
args,
|
||||
body,
|
||||
@@ -112,14 +107,14 @@ fn statement_to_ast(
|
||||
decorator_list => expressions_to_ast(vm, decorator_list)?,
|
||||
returns => optional_expression_to_ast(vm, returns)?
|
||||
}),
|
||||
ast::Statement::Continue => node!(vm, Continue),
|
||||
ast::Statement::Break => node!(vm, Break),
|
||||
ast::Statement::Pass => node!(vm, Pass),
|
||||
ast::Statement::Assert { test, msg } => node!(vm, Assert, {
|
||||
Continue => node!(vm, Continue),
|
||||
Break => node!(vm, Break),
|
||||
Pass => node!(vm, Pass),
|
||||
Assert { test, msg } => node!(vm, Assert, {
|
||||
test => expression_to_ast(vm, test)?,
|
||||
msg => optional_expression_to_ast(vm, msg)?
|
||||
}),
|
||||
ast::Statement::Delete { targets } => {
|
||||
Delete { targets } => {
|
||||
let targets: PyResult<_> = targets
|
||||
.iter()
|
||||
.map(|v| Ok(expression_to_ast(vm, v)?.into_object()))
|
||||
@@ -127,15 +122,15 @@ fn statement_to_ast(
|
||||
let py_targets = vm.ctx.new_tuple(targets?);
|
||||
node!(vm, Delete, { targets => py_targets })
|
||||
}
|
||||
ast::Statement::Return { value } => node!(vm, Return, {
|
||||
Return { value } => node!(vm, Return, {
|
||||
value => optional_expression_to_ast(vm, value)?
|
||||
}),
|
||||
ast::Statement::If { test, body, orelse } => node!(vm, If, {
|
||||
If { test, body, orelse } => node!(vm, If, {
|
||||
test => expression_to_ast(vm, test)?,
|
||||
body => statements_to_ast(vm, body)?,
|
||||
orelse => optional_statements_to_ast(vm, orelse)?
|
||||
}),
|
||||
ast::Statement::For {
|
||||
For {
|
||||
target,
|
||||
iter,
|
||||
body,
|
||||
@@ -146,7 +141,7 @@ fn statement_to_ast(
|
||||
body => statements_to_ast(vm, body)?,
|
||||
orelse => optional_statements_to_ast(vm, orelse)?
|
||||
}),
|
||||
ast::Statement::AsyncFor {
|
||||
AsyncFor {
|
||||
target,
|
||||
iter,
|
||||
body,
|
||||
@@ -157,16 +152,16 @@ fn statement_to_ast(
|
||||
body => statements_to_ast(vm, body)?,
|
||||
orelse => optional_statements_to_ast(vm, orelse)?
|
||||
}),
|
||||
ast::Statement::While { test, body, orelse } => node!(vm, While, {
|
||||
While { test, body, orelse } => node!(vm, While, {
|
||||
test => expression_to_ast(vm, test)?,
|
||||
body => statements_to_ast(vm, body)?,
|
||||
orelse => optional_statements_to_ast(vm, orelse)?
|
||||
}),
|
||||
ast::Statement::With { items, body } => node!(vm, With, {
|
||||
With { items, body } => node!(vm, With, {
|
||||
items => map_ast(with_item_to_ast, vm, items)?,
|
||||
body => statements_to_ast(vm, body)?
|
||||
}),
|
||||
ast::Statement::Try {
|
||||
Try {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
@@ -177,13 +172,13 @@ fn statement_to_ast(
|
||||
orelse => optional_statements_to_ast(vm, orelse)?,
|
||||
finalbody => optional_statements_to_ast(vm, finalbody)?
|
||||
}),
|
||||
ast::Statement::Expression { expression } => node!(vm, Expr, {
|
||||
Expression { expression } => node!(vm, Expr, {
|
||||
value => expression_to_ast(vm, expression)?
|
||||
}),
|
||||
ast::Statement::Import { names } => node!(vm, Import, {
|
||||
Import { names } => node!(vm, Import, {
|
||||
names => map_ast(alias_to_ast, vm, names)?
|
||||
}),
|
||||
ast::Statement::ImportFrom {
|
||||
ImportFrom {
|
||||
level,
|
||||
module,
|
||||
names,
|
||||
@@ -192,22 +187,22 @@ fn statement_to_ast(
|
||||
module => optional_string_to_py_obj(vm, module),
|
||||
names => map_ast(alias_to_ast, vm, names)?
|
||||
}),
|
||||
ast::Statement::Nonlocal { names } => node!(vm, Nonlocal, {
|
||||
Nonlocal { names } => node!(vm, Nonlocal, {
|
||||
names => make_string_list(vm, names)
|
||||
}),
|
||||
ast::Statement::Global { names } => node!(vm, Global, {
|
||||
Global { names } => node!(vm, Global, {
|
||||
names => make_string_list(vm, names)
|
||||
}),
|
||||
ast::Statement::Assign { targets, value } => node!(vm, Assign, {
|
||||
Assign { targets, value } => node!(vm, Assign, {
|
||||
targets => expressions_to_ast(vm, targets)?,
|
||||
value => expression_to_ast(vm, value)?,
|
||||
}),
|
||||
ast::Statement::AugAssign { target, op, value } => node!(vm, AugAssign, {
|
||||
AugAssign { target, op, value } => node!(vm, AugAssign, {
|
||||
target => expression_to_ast(vm, target)?,
|
||||
op => vm.ctx.new_str(operator_string(op)),
|
||||
value => expression_to_ast(vm, value)?,
|
||||
}),
|
||||
ast::Statement::Raise { exception, cause } => node!(vm, Raise, {
|
||||
Raise { exception, cause } => node!(vm, Raise, {
|
||||
exc => optional_expression_to_ast(vm, exception)?,
|
||||
cause => optional_expression_to_ast(vm, cause)?,
|
||||
}),
|
||||
@@ -229,7 +224,7 @@ fn alias_to_ast(vm: &VirtualMachine, alias: &ast::ImportSymbol) -> PyResult<AstN
|
||||
|
||||
fn optional_statements_to_ast(
|
||||
vm: &VirtualMachine,
|
||||
statements: &Option<Vec<ast::LocatedStatement>>,
|
||||
statements: &Option<Vec<ast::Statement>>,
|
||||
) -> PyResult {
|
||||
let statements = if let Some(statements) = statements {
|
||||
statements_to_ast(vm, statements)?.into_object()
|
||||
@@ -283,8 +278,9 @@ fn expressions_to_ast(vm: &VirtualMachine, expressions: &[ast::Expression]) -> P
|
||||
}
|
||||
|
||||
fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyResult<AstNodeRef> {
|
||||
let node = match &expression {
|
||||
ast::Expression::Call {
|
||||
use ast::ExpressionType::*;
|
||||
let node = match &expression.node {
|
||||
Call {
|
||||
function,
|
||||
args,
|
||||
keywords,
|
||||
@@ -293,7 +289,7 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
args => expressions_to_ast(vm, args)?,
|
||||
keywords => map_ast(keyword_to_ast, vm, keywords)?,
|
||||
}),
|
||||
ast::Expression::Binop { a, op, b } => {
|
||||
Binop { a, op, b } => {
|
||||
// Operator:
|
||||
node!(vm, BinOp, {
|
||||
left => expression_to_ast(vm, a)?,
|
||||
@@ -301,7 +297,7 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
right => expression_to_ast(vm, b)?,
|
||||
})
|
||||
}
|
||||
ast::Expression::Unop { op, a } => {
|
||||
Unop { op, a } => {
|
||||
let op = match op {
|
||||
ast::UnaryOperator::Not => "Not",
|
||||
ast::UnaryOperator::Inv => "Invert",
|
||||
@@ -313,7 +309,7 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
operand => expression_to_ast(vm, a)?,
|
||||
})
|
||||
}
|
||||
ast::Expression::BoolOp { a, op, b } => {
|
||||
BoolOp { a, op, b } => {
|
||||
// Attach values:
|
||||
let py_a = expression_to_ast(vm, a)?.into_object();
|
||||
let py_b = expression_to_ast(vm, b)?.into_object();
|
||||
@@ -330,7 +326,7 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
values => py_values,
|
||||
})
|
||||
}
|
||||
ast::Expression::Compare { vals, ops } => {
|
||||
Compare { vals, ops } => {
|
||||
let left = expression_to_ast(vm, &vals[0])?;
|
||||
|
||||
// Operator:
|
||||
@@ -364,20 +360,20 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
comparators => comparators,
|
||||
})
|
||||
}
|
||||
ast::Expression::Identifier { name } => node!(vm, Name, {
|
||||
Identifier { name } => node!(vm, Name, {
|
||||
id => vm.ctx.new_str(name.clone()),
|
||||
ctx => vm.ctx.none() // TODO: add context.
|
||||
}),
|
||||
ast::Expression::Lambda { args, body } => node!(vm, Lambda, {
|
||||
Lambda { args, body } => node!(vm, Lambda, {
|
||||
args => parameters_to_ast(vm, args)?,
|
||||
body => expression_to_ast(vm, body)?,
|
||||
}),
|
||||
ast::Expression::IfExpression { test, body, orelse } => node!(vm, IfExp, {
|
||||
IfExpression { test, body, orelse } => node!(vm, IfExp, {
|
||||
text => expression_to_ast(vm, test)?,
|
||||
body => expression_to_ast(vm, body)?,
|
||||
or_else => expression_to_ast(vm, orelse)?,
|
||||
}),
|
||||
ast::Expression::Number { value } => {
|
||||
Number { value } => {
|
||||
let py_n = match value {
|
||||
ast::Number::Integer { value } => vm.ctx.new_int(value.clone()),
|
||||
ast::Number::Float { value } => vm.ctx.new_float(*value),
|
||||
@@ -389,26 +385,26 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
n => py_n
|
||||
})
|
||||
}
|
||||
ast::Expression::True => node!(vm, NameConstant, {
|
||||
True => node!(vm, NameConstant, {
|
||||
value => vm.ctx.new_bool(true)
|
||||
}),
|
||||
ast::Expression::False => node!(vm, NameConstant, {
|
||||
False => node!(vm, NameConstant, {
|
||||
value => vm.ctx.new_bool(false)
|
||||
}),
|
||||
ast::Expression::None => node!(vm, NameConstant, {
|
||||
None => node!(vm, NameConstant, {
|
||||
value => vm.ctx.none()
|
||||
}),
|
||||
ast::Expression::Ellipsis => node!(vm, Ellipsis),
|
||||
ast::Expression::List { elements } => node!(vm, List, {
|
||||
Ellipsis => node!(vm, Ellipsis),
|
||||
List { elements } => node!(vm, List, {
|
||||
elts => expressions_to_ast(vm, &elements)?
|
||||
}),
|
||||
ast::Expression::Tuple { elements } => node!(vm, Tuple, {
|
||||
Tuple { elements } => node!(vm, Tuple, {
|
||||
elts => expressions_to_ast(vm, &elements)?
|
||||
}),
|
||||
ast::Expression::Set { elements } => node!(vm, Set, {
|
||||
Set { elements } => node!(vm, Set, {
|
||||
elts => expressions_to_ast(vm, &elements)?
|
||||
}),
|
||||
ast::Expression::Dict { elements } => {
|
||||
Dict { elements } => {
|
||||
let mut keys = Vec::new();
|
||||
let mut values = Vec::new();
|
||||
for (k, v) in elements {
|
||||
@@ -425,7 +421,7 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
values => vm.ctx.new_list(values),
|
||||
})
|
||||
}
|
||||
ast::Expression::Comprehension { kind, generators } => {
|
||||
Comprehension { kind, generators } => {
|
||||
let py_generators = map_ast(comprehension_to_ast, vm, generators)?;
|
||||
|
||||
match kind.deref() {
|
||||
@@ -443,50 +439,48 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expression::Await { value } => {
|
||||
Await { value } => {
|
||||
let py_value = expression_to_ast(vm, value)?;
|
||||
node!(vm, Await, {
|
||||
value => py_value
|
||||
})
|
||||
}
|
||||
ast::Expression::Yield { value } => {
|
||||
let py_value = match value {
|
||||
Some(value) => expression_to_ast(vm, value)?.into_object(),
|
||||
None => vm.ctx.none(),
|
||||
Yield { value } => {
|
||||
let py_value = if let Some(value) = value {
|
||||
expression_to_ast(vm, value)?.into_object()
|
||||
} else {
|
||||
vm.ctx.none()
|
||||
};
|
||||
node!(vm, Yield, {
|
||||
value => py_value
|
||||
})
|
||||
}
|
||||
ast::Expression::YieldFrom { value } => {
|
||||
YieldFrom { value } => {
|
||||
let py_value = expression_to_ast(vm, value)?;
|
||||
node!(vm, YieldFrom, {
|
||||
value => py_value
|
||||
})
|
||||
}
|
||||
ast::Expression::Subscript { a, b } => node!(vm, Subscript, {
|
||||
Subscript { a, b } => node!(vm, Subscript, {
|
||||
value => expression_to_ast(vm, a)?,
|
||||
slice => expression_to_ast(vm, b)?,
|
||||
}),
|
||||
ast::Expression::Attribute { value, name } => node!(vm, Attribute, {
|
||||
Attribute { value, name } => node!(vm, Attribute, {
|
||||
value => expression_to_ast(vm, value)?,
|
||||
attr => vm.ctx.new_str(name.to_string()),
|
||||
ctx => vm.ctx.none()
|
||||
}),
|
||||
ast::Expression::Starred { value } => node!(vm, Starred, {
|
||||
Starred { value } => node!(vm, Starred, {
|
||||
value => expression_to_ast(vm, value)?
|
||||
}),
|
||||
ast::Expression::Slice { elements } => node!(vm, Slice, {
|
||||
Slice { elements } => node!(vm, Slice, {
|
||||
bounds => expressions_to_ast(vm, elements)?
|
||||
}),
|
||||
ast::Expression::String { value } => string_to_ast(vm, value)?,
|
||||
ast::Expression::Bytes { value } => {
|
||||
node!(vm, Bytes, { s => vm.ctx.new_bytes(value.clone()) })
|
||||
}
|
||||
String { value } => string_to_ast(vm, value)?,
|
||||
Bytes { value } => node!(vm, Bytes, { s => vm.ctx.new_bytes(value.clone()) }),
|
||||
};
|
||||
|
||||
// TODO: retrieve correct lineno:
|
||||
let lineno = vm.ctx.new_int(1);
|
||||
let lineno = vm.ctx.new_int(expression.location.row());
|
||||
vm.set_attr(node.as_object(), "lineno", lineno).unwrap();
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
|
||||
"random".to_string() => Box::new(random::make_module),
|
||||
"_string".to_string() => Box::new(string::make_module),
|
||||
"struct".to_string() => Box::new(pystruct::make_module),
|
||||
"symtable".to_string() => Box::new(symtable::make_module),
|
||||
"_thread".to_string() => Box::new(thread::make_module),
|
||||
"time".to_string() => Box::new(time_module::make_module),
|
||||
"_weakref".to_string() => Box::new(weakref::make_module),
|
||||
@@ -81,6 +80,12 @@ pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
|
||||
modules.insert("tokenize".to_string(), Box::new(tokenize::make_module));
|
||||
}
|
||||
|
||||
// Insert compiler related modules:
|
||||
#[cfg(feature = "rustpython-compiler")]
|
||||
{
|
||||
modules.insert("symtable".to_string(), Box::new(symtable::make_module));
|
||||
}
|
||||
|
||||
// disable some modules on WASM
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
|
||||
+16
-44
@@ -89,11 +89,9 @@ impl PySymbolTable {
|
||||
#[pymethod(name = "lookup")]
|
||||
fn lookup(&self, name: PyStringRef, vm: &VirtualMachine) -> PyResult<PySymbolRef> {
|
||||
let name = &name.value;
|
||||
if self.symtable.symbols.contains_key(name) {
|
||||
let role = self.symtable.symbols.get(name).unwrap().clone();
|
||||
if let Some(symbol) = self.symtable.symbols.get(name) {
|
||||
Ok(PySymbol {
|
||||
name: name.to_string(),
|
||||
role,
|
||||
symbol: symbol.clone(),
|
||||
}
|
||||
.into_ref(vm))
|
||||
} else {
|
||||
@@ -106,15 +104,8 @@ impl PySymbolTable {
|
||||
let symbols = self
|
||||
.symtable
|
||||
.symbols
|
||||
.iter()
|
||||
.map(|s| {
|
||||
(PySymbol {
|
||||
name: s.0.clone(),
|
||||
role: s.1.clone(),
|
||||
})
|
||||
.into_ref(vm)
|
||||
.into_object()
|
||||
})
|
||||
.values()
|
||||
.map(|s| (PySymbol { symbol: s.clone() }).into_ref(vm).into_object())
|
||||
.collect();
|
||||
Ok(vm.ctx.new_list(symbols))
|
||||
}
|
||||
@@ -137,8 +128,7 @@ impl PySymbolTable {
|
||||
|
||||
#[pyclass(name = "Symbol")]
|
||||
struct PySymbol {
|
||||
name: String,
|
||||
role: symboltable::SymbolRole,
|
||||
symbol: symboltable::Symbol,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PySymbol {
|
||||
@@ -157,55 +147,37 @@ impl PyValue for PySymbol {
|
||||
impl PySymbol {
|
||||
#[pymethod(name = "get_name")]
|
||||
fn get_name(&self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(vm.ctx.new_str(self.name.clone()))
|
||||
Ok(vm.ctx.new_str(self.symbol.name.clone()))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_global")]
|
||||
fn is_global(&self, vm: &VirtualMachine) -> PyResult {
|
||||
// TODO: figure out how this is determined.
|
||||
let is_local = if let symboltable::SymbolRole::Used = self.role {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Ok(vm.ctx.new_bool(is_local))
|
||||
Ok(vm.ctx.new_bool(self.symbol.is_global))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_local")]
|
||||
fn is_local(&self, vm: &VirtualMachine) -> PyResult {
|
||||
// TODO: figure out how this is determined.
|
||||
let is_local = if let symboltable::SymbolRole::Used = self.role {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Ok(vm.ctx.new_bool(is_local))
|
||||
Ok(vm.ctx.new_bool(self.symbol.is_local))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_referenced")]
|
||||
fn is_referenced(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let is_local = if let symboltable::SymbolRole::Used = self.role {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Ok(vm.ctx.new_bool(is_local))
|
||||
Ok(vm.ctx.new_bool(self.symbol.is_referenced))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_assigned")]
|
||||
fn is_assigned(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let is_local = if let symboltable::SymbolRole::Assigned = self.role {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Ok(vm.ctx.new_bool(is_local))
|
||||
Ok(vm.ctx.new_bool(self.symbol.is_assigned))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_parameter")]
|
||||
fn is_parameter(&self, vm: &VirtualMachine) -> PyResult {
|
||||
// TODO
|
||||
Ok(vm.ctx.new_bool(false))
|
||||
Ok(vm.ctx.new_bool(self.symbol.is_parameter))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_free")]
|
||||
fn is_free(&self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(vm.ctx.new_bool(self.symbol.is_free))
|
||||
}
|
||||
|
||||
#[pymethod(name = "is_namespace")]
|
||||
|
||||
Reference in new issue
Block a user