mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-19 11:05:45 +00:00
Make from __future__
imports a syntactic construct in the compiler
This commit is contained in:
parent
330fdce246
commit
a499fb775a
2 changed files with 52 additions and 0 deletions
|
@ -29,6 +29,7 @@ struct Compiler<O: OutputStream = BasicOutputStream> {
|
|||
source_path: Option<String>,
|
||||
current_source_location: ast::Location,
|
||||
current_qualified_path: Option<String>,
|
||||
done_with_future_stmts: bool,
|
||||
ctx: CompileContext,
|
||||
opts: CompileOpts,
|
||||
}
|
||||
|
@ -166,6 +167,7 @@ impl<O: OutputStream> Compiler<O> {
|
|||
source_path: None,
|
||||
current_source_location: ast::Location::default(),
|
||||
current_qualified_path: None,
|
||||
done_with_future_stmts: false,
|
||||
ctx: CompileContext {
|
||||
in_loop: false,
|
||||
func: FunctionContext::NoFunction,
|
||||
|
@ -334,6 +336,16 @@ impl<O: OutputStream> Compiler<O> {
|
|||
self.set_source_location(statement.location);
|
||||
use ast::StatementType::*;
|
||||
|
||||
match &statement.node {
|
||||
// we do this here because `from __future__` still executes that `from` statement at runtime,
|
||||
// we still need to compile the ImportFrom down below
|
||||
ImportFrom { module, names, .. } if module.as_deref() == Some("__future__") => {
|
||||
self.compile_future_features(&names)?
|
||||
}
|
||||
// if we find any other statement, stop accepting future statements
|
||||
_ => self.done_with_future_stmts = true,
|
||||
}
|
||||
|
||||
match &statement.node {
|
||||
Import { names } => {
|
||||
// import a, b, c as d
|
||||
|
@ -2132,6 +2144,38 @@ impl<O: OutputStream> Compiler<O> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_future_features(
|
||||
&mut self,
|
||||
features: &[ast::ImportSymbol],
|
||||
) -> Result<(), CompileError> {
|
||||
if self.done_with_future_stmts {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::InvalidFuturePlacement,
|
||||
location: self.current_source_location.clone(),
|
||||
source_path: self.source_path.clone(),
|
||||
statement: None,
|
||||
});
|
||||
}
|
||||
for feature in features {
|
||||
match &*feature.symbol {
|
||||
// Python 3 features; we've already implemented them by default
|
||||
"nested_scopes" | "generators" | "division" | "absolute_import"
|
||||
| "with_statement" | "print_function" | "unicode_literals" => {}
|
||||
// "generator_stop" => {}
|
||||
// "annotations" => {}
|
||||
other => {
|
||||
return Err(CompileError {
|
||||
error: CompileErrorType::InvalidFutureFeature(other.to_owned()),
|
||||
location: self.current_source_location.clone(),
|
||||
source_path: self.source_path.clone(),
|
||||
statement: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Scope helpers:
|
||||
fn enter_scope(&mut self) {
|
||||
// println!("Enter scope {:?}", self.symbol_table_stack);
|
||||
|
|
|
@ -58,6 +58,8 @@ pub enum CompileErrorType {
|
|||
InvalidAwait,
|
||||
AsyncYieldFrom,
|
||||
AsyncReturnValue,
|
||||
InvalidFuturePlacement,
|
||||
InvalidFutureFeature(String),
|
||||
}
|
||||
|
||||
impl CompileError {
|
||||
|
@ -106,6 +108,12 @@ impl fmt::Display for CompileError {
|
|||
CompileErrorType::AsyncReturnValue => {
|
||||
"'return' with value inside async generator".to_owned()
|
||||
}
|
||||
CompileErrorType::InvalidFuturePlacement => {
|
||||
"from __future__ imports must occur at the beginning of the file".to_owned()
|
||||
}
|
||||
CompileErrorType::InvalidFutureFeature(feat) => {
|
||||
format!("future feature {} is not defined", feat)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(statement) = &self.statement {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue