diff --git a/Cargo.toml b/Cargo.toml index d968cb1..6846c43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] indexmap = "1.0" -itertools = "0.8.0" +itertools = "0.9" rustpython-bytecode = { path = "../bytecode", version = "0.1.1" } rustpython-parser = { path = "../parser", version = "0.1.1" } num-complex = { version = "0.2", features = ["serde"] } diff --git a/src/symboltable.rs b/src/symboltable.rs index 1b9707d..d121fa1 100644 --- a/src/symboltable.rs +++ b/src/symboltable.rs @@ -97,10 +97,13 @@ pub struct Symbol { pub name: String, // pub table: SymbolTableRef, pub scope: SymbolScope, + // TODO: Use bitflags replace pub is_referenced: bool, pub is_assigned: bool, pub is_parameter: bool, pub is_free: bool, + pub is_annotated: bool, + pub is_imported: bool, // indicates if the symbol gets a value assigned by a named expression in a comprehension // this is required to correct the scope in the analysis. @@ -121,6 +124,8 @@ impl Symbol { is_assigned: false, is_parameter: false, is_free: false, + is_annotated: false, + is_imported: false, is_assign_namedexpr_in_comprehension: false, is_iter: false, } @@ -396,7 +401,10 @@ enum SymbolUsage { Nonlocal, Used, Assigned, + Imported, + AnnotationAssigned, Parameter, + AnnotationParameter, AssignedNamedExprInCompr, Iter, } @@ -462,7 +470,12 @@ impl SymbolTableBuilder { } fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult { - self.register_name(¶meter.arg, SymbolUsage::Parameter) + let usage = if parameter.annotation.is_some() { + SymbolUsage::AnnotationParameter + } else { + SymbolUsage::Parameter + }; + self.register_name(¶meter.arg, usage) } fn scan_parameters_annotations(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult { @@ -566,12 +579,12 @@ impl SymbolTableBuilder { for name in names { if let Some(alias) = &name.alias { // `import mymodule as myalias` - self.register_name(alias, SymbolUsage::Assigned)?; + self.register_name(alias, SymbolUsage::Imported)?; } else { // `import module` self.register_name( name.symbol.split('.').next().unwrap(), - SymbolUsage::Assigned, + SymbolUsage::Imported, )?; } } @@ -603,7 +616,12 @@ impl SymbolTableBuilder { annotation, value, } => { - self.scan_expression(target, &ExpressionContext::Store)?; + // https://github.com/python/cpython/blob/master/Python/symtable.c#L1233 + if let ast::ExpressionType::Identifier { ref name } = target.node { + self.register_name(name, SymbolUsage::AnnotationAssigned)?; + } else { + self.scan_expression(target, &ExpressionContext::Store)?; + } self.scan_expression(annotation, &ExpressionContext::Load)?; if let Some(value) = value { self.scan_expression(value, &ExpressionContext::Load)?; @@ -986,9 +1004,21 @@ impl SymbolTableBuilder { }); } } + SymbolUsage::Imported => { + symbol.is_assigned = true; + symbol.is_imported = true; + } SymbolUsage::Parameter => { symbol.is_parameter = true; } + SymbolUsage::AnnotationParameter => { + symbol.is_parameter = true; + symbol.is_annotated = true; + } + SymbolUsage::AnnotationAssigned => { + symbol.is_assigned = true; + symbol.is_annotated = true; + } SymbolUsage::Assigned => { symbol.is_assigned = true; }