Introduce symtable test and add is_annotation for symbol

This commit is contained in:
lynskylate 2020-07-31 02:11:00 +08:00
parent f6e25fc0cb
commit 66731121ab

View file

@ -97,10 +97,13 @@ pub struct Symbol {
pub name: String, pub name: String,
// pub table: SymbolTableRef, // pub table: SymbolTableRef,
pub scope: SymbolScope, pub scope: SymbolScope,
// TODO(lynskylate@gmail.com): Use bitflags replace
pub is_referenced: bool, pub is_referenced: bool,
pub is_assigned: bool, pub is_assigned: bool,
pub is_parameter: bool, pub is_parameter: bool,
pub is_free: 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 // 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. // this is required to correct the scope in the analysis.
@ -121,6 +124,8 @@ impl Symbol {
is_assigned: false, is_assigned: false,
is_parameter: false, is_parameter: false,
is_free: false, is_free: false,
is_annotated: false,
is_imported: false,
is_assign_namedexpr_in_comprehension: false, is_assign_namedexpr_in_comprehension: false,
is_iter: false, is_iter: false,
} }
@ -276,6 +281,11 @@ impl<'a> SymbolTableAnalyzer<'a> {
fn analyze_unknown_symbol(&self, symbol: &mut Symbol) { fn analyze_unknown_symbol(&self, symbol: &mut Symbol) {
if symbol.is_assigned || symbol.is_parameter { if symbol.is_assigned || symbol.is_parameter {
symbol.scope = SymbolScope::Local; symbol.scope = SymbolScope::Local;
} else if !symbol.is_assigned && symbol.is_referenced {
// if symbol is referenced in its block, but not assigned to.
// https://docs.python.org/3/library/symtable.html?highlight=symtable#symtable.Symbol.is_free
symbol.scope = SymbolScope::Unknown;
symbol.is_free = true;
} else { } else {
// Interesting stuff about the __class__ variable: // Interesting stuff about the __class__ variable:
// https://docs.python.org/3/reference/datamodel.html?highlight=__class__#creating-the-class-object // https://docs.python.org/3/reference/datamodel.html?highlight=__class__#creating-the-class-object
@ -394,7 +404,10 @@ enum SymbolUsage {
Nonlocal, Nonlocal,
Used, Used,
Assigned, Assigned,
Imported,
AnnotationAssigned,
Parameter, Parameter,
AnnotationParameter,
AssignedNamedExprInCompr, AssignedNamedExprInCompr,
Iter, Iter,
} }
@ -460,7 +473,11 @@ impl SymbolTableBuilder {
} }
fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult { fn scan_parameter(&mut self, parameter: &ast::Parameter) -> SymbolTableResult {
self.register_name(&parameter.arg, SymbolUsage::Parameter) if let Some(_annotation) = &parameter.annotation {
self.register_name(&parameter.arg, SymbolUsage::AnnotationParameter)
} else {
self.register_name(&parameter.arg, SymbolUsage::Parameter)
}
} }
fn scan_parameters_annotations(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult { fn scan_parameters_annotations(&mut self, parameters: &[ast::Parameter]) -> SymbolTableResult {
@ -564,12 +581,12 @@ impl SymbolTableBuilder {
for name in names { for name in names {
if let Some(alias) = &name.alias { if let Some(alias) = &name.alias {
// `import mymodule as myalias` // `import mymodule as myalias`
self.register_name(alias, SymbolUsage::Assigned)?; self.register_name(alias, SymbolUsage::Imported)?;
} else { } else {
// `import module` // `import module`
self.register_name( self.register_name(
name.symbol.split('.').next().unwrap(), name.symbol.split('.').next().unwrap(),
SymbolUsage::Assigned, SymbolUsage::Imported,
)?; )?;
} }
} }
@ -601,7 +618,12 @@ impl SymbolTableBuilder {
annotation, annotation,
value, 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)?; self.scan_expression(annotation, &ExpressionContext::Load)?;
if let Some(value) = value { if let Some(value) = value {
self.scan_expression(value, &ExpressionContext::Load)?; self.scan_expression(value, &ExpressionContext::Load)?;
@ -984,9 +1006,21 @@ impl SymbolTableBuilder {
}); });
} }
} }
SymbolUsage::Imported => {
symbol.is_assigned = true;
symbol.is_imported = true;
}
SymbolUsage::Parameter => { SymbolUsage::Parameter => {
symbol.is_parameter = true; 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 => { SymbolUsage::Assigned => {
symbol.is_assigned = true; symbol.is_assigned = true;
} }