Add the __future__.annotations feature

This commit is contained in:
Noa 2021-08-30 00:50:44 -05:00
parent 42af29c79c
commit 4c3c5c5ed1
2 changed files with 39 additions and 7 deletions

View file

@ -67,6 +67,7 @@ struct Compiler {
current_source_location: ast::Location, current_source_location: ast::Location,
qualified_path: Vec<String>, qualified_path: Vec<String>,
done_with_future_stmts: bool, done_with_future_stmts: bool,
future_annotations: bool,
ctx: CompileContext, ctx: CompileContext,
class_name: Option<String>, class_name: Option<String>,
opts: CompileOpts, opts: CompileOpts,
@ -196,6 +197,7 @@ impl Compiler {
current_source_location: ast::Location::default(), current_source_location: ast::Location::default(),
qualified_path: Vec::new(), qualified_path: Vec::new(),
done_with_future_stmts: false, done_with_future_stmts: false,
future_annotations: false,
ctx: CompileContext { ctx: CompileContext {
loop_data: None, loop_data: None,
in_class: false, in_class: false,
@ -1081,7 +1083,7 @@ impl Compiler {
value: "return".to_owned(), value: "return".to_owned(),
}); });
// value: // value:
self.compile_expression(annotation)?; self.compile_annotation(annotation)?;
num_annotations += 1; num_annotations += 1;
} }
@ -1096,7 +1098,7 @@ impl Compiler {
self.emit_constant(ConstantData::Str { self.emit_constant(ConstantData::Str {
value: self.mangle(&arg.node.arg).into_owned(), value: self.mangle(&arg.node.arg).into_owned(),
}); });
self.compile_expression(annotation)?; self.compile_annotation(annotation)?;
num_annotations += 1; num_annotations += 1;
} }
} }
@ -1538,6 +1540,17 @@ impl Compiler {
Ok(()) Ok(())
} }
fn compile_annotation(&mut self, annotation: &ast::Expr) -> CompileResult<()> {
if self.future_annotations {
self.emit_constant(ConstantData::Str {
value: annotation.to_string(),
});
} else {
self.compile_expression(annotation)?;
}
Ok(())
}
fn compile_annotated_assign( fn compile_annotated_assign(
&mut self, &mut self,
target: &ast::Expr, target: &ast::Expr,
@ -1555,7 +1568,7 @@ impl Compiler {
} }
// Compile annotation: // Compile annotation:
self.compile_expression(annotation)?; self.compile_annotation(annotation)?;
if let ast::ExprKind::Name { id, .. } = &target.node { if let ast::ExprKind::Name { id, .. } = &target.node {
// Store as dict entry in __annotations__ dict: // Store as dict entry in __annotations__ dict:
@ -2423,7 +2436,7 @@ impl Compiler {
"nested_scopes" | "generators" | "division" | "absolute_import" "nested_scopes" | "generators" | "division" | "absolute_import"
| "with_statement" | "print_function" | "unicode_literals" => {} | "with_statement" | "print_function" | "unicode_literals" => {}
// "generator_stop" => {} // "generator_stop" => {}
// "annotations" => {} "annotations" => self.future_annotations = true,
other => { other => {
return Err(self.error(CompileErrorType::InvalidFutureFeature(other.to_owned()))) return Err(self.error(CompileErrorType::InvalidFutureFeature(other.to_owned())))
} }

View file

@ -537,6 +537,7 @@ struct SymbolTableBuilder {
class_name: Option<String>, class_name: Option<String>,
// Scope stack. // Scope stack.
tables: Vec<SymbolTable>, tables: Vec<SymbolTable>,
future_annotations: bool,
} }
/// Enum to indicate in what mode an expression /// Enum to indicate in what mode an expression
@ -557,6 +558,7 @@ impl SymbolTableBuilder {
let mut this = Self { let mut this = Self {
class_name: None, class_name: None,
tables: vec![], tables: vec![],
future_annotations: false,
}; };
this.enter_scope("top", SymbolTableType::Module, 0); this.enter_scope("top", SymbolTableType::Module, 0);
this this
@ -617,14 +619,31 @@ impl SymbolTableBuilder {
fn scan_parameter_annotation(&mut self, parameter: &ast::Arg) -> SymbolTableResult { fn scan_parameter_annotation(&mut self, parameter: &ast::Arg) -> SymbolTableResult {
if let Some(annotation) = &parameter.node.annotation { if let Some(annotation) = &parameter.node.annotation {
self.scan_expression(annotation, ExpressionContext::Load)?; self.scan_annotation(annotation)?;
} }
Ok(()) Ok(())
} }
fn scan_annotation(&mut self, annotation: &ast::Expr) -> SymbolTableResult {
if self.future_annotations {
Ok(())
} else {
self.scan_expression(annotation, ExpressionContext::Load)
}
}
fn scan_statement(&mut self, statement: &ast::Stmt) -> SymbolTableResult { fn scan_statement(&mut self, statement: &ast::Stmt) -> SymbolTableResult {
use ast::StmtKind::*; use ast::StmtKind::*;
let location = statement.location; let location = statement.location;
if let ImportFrom { module, names, .. } = &statement.node {
if module.as_deref() == Some("__future__") {
for feature in names {
if feature.name == "annotations" {
self.future_annotations = true;
}
}
}
}
match &statement.node { match &statement.node {
Global { names } => { Global { names } => {
for name in names { for name in names {
@ -655,7 +674,7 @@ impl SymbolTableBuilder {
self.scan_expressions(decorator_list, ExpressionContext::Load)?; self.scan_expressions(decorator_list, ExpressionContext::Load)?;
self.register_name(name, SymbolUsage::Assigned, location)?; self.register_name(name, SymbolUsage::Assigned, location)?;
if let Some(expression) = returns { if let Some(expression) = returns {
self.scan_expression(expression, ExpressionContext::Load)?; self.scan_annotation(expression)?;
} }
self.enter_function(name, args, location.row())?; self.enter_function(name, args, location.row())?;
self.scan_statements(body)?; self.scan_statements(body)?;
@ -769,7 +788,7 @@ impl SymbolTableBuilder {
self.scan_expression(target, ExpressionContext::Store)?; self.scan_expression(target, ExpressionContext::Store)?;
} }
} }
self.scan_expression(annotation, ExpressionContext::Load)?; self.scan_annotation(annotation)?;
if let Some(value) = value { if let Some(value) = value {
self.scan_expression(value, ExpressionContext::Load)?; self.scan_expression(value, ExpressionContext::Load)?;
} }