mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-13 08:05:17 +00:00
Merge pull request #1215 from RustPython/syntax-fixes
Add variable annotation syntax.
This commit is contained in:
commit
dd53fe8f89
2 changed files with 90 additions and 27 deletions
106
src/compile.rs
106
src/compile.rs
|
@ -368,33 +368,7 @@ impl<O: OutputStream> Compiler<O> {
|
||||||
}
|
}
|
||||||
self.set_label(end_label);
|
self.set_label(end_label);
|
||||||
}
|
}
|
||||||
While { test, body, orelse } => {
|
While { test, body, orelse } => self.compile_while(test, body, orelse)?,
|
||||||
let start_label = self.new_label();
|
|
||||||
let else_label = self.new_label();
|
|
||||||
let end_label = self.new_label();
|
|
||||||
self.emit(Instruction::SetupLoop {
|
|
||||||
start: start_label,
|
|
||||||
end: end_label,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.set_label(start_label);
|
|
||||||
|
|
||||||
self.compile_test(test, None, Some(else_label), EvalContext::Statement)?;
|
|
||||||
|
|
||||||
let was_in_loop = self.in_loop;
|
|
||||||
self.in_loop = true;
|
|
||||||
self.compile_statements(body)?;
|
|
||||||
self.in_loop = was_in_loop;
|
|
||||||
self.emit(Instruction::Jump {
|
|
||||||
target: start_label,
|
|
||||||
});
|
|
||||||
self.set_label(else_label);
|
|
||||||
self.emit(Instruction::PopBlock);
|
|
||||||
if let Some(orelse) = orelse {
|
|
||||||
self.compile_statements(orelse)?;
|
|
||||||
}
|
|
||||||
self.set_label(end_label);
|
|
||||||
}
|
|
||||||
With {
|
With {
|
||||||
is_async,
|
is_async,
|
||||||
items,
|
items,
|
||||||
|
@ -563,6 +537,11 @@ impl<O: OutputStream> Compiler<O> {
|
||||||
self.compile_op(op, true);
|
self.compile_op(op, true);
|
||||||
self.compile_store(target)?;
|
self.compile_store(target)?;
|
||||||
}
|
}
|
||||||
|
AnnAssign {
|
||||||
|
target,
|
||||||
|
annotation,
|
||||||
|
value,
|
||||||
|
} => self.compile_annotated_assign(target, annotation, value)?,
|
||||||
Delete { targets } => {
|
Delete { targets } => {
|
||||||
for target in targets {
|
for target in targets {
|
||||||
self.compile_delete(target)?;
|
self.compile_delete(target)?;
|
||||||
|
@ -1011,6 +990,40 @@ impl<O: OutputStream> Compiler<O> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_while(
|
||||||
|
&mut self,
|
||||||
|
test: &ast::Expression,
|
||||||
|
body: &[ast::Statement],
|
||||||
|
orelse: &Option<Vec<ast::Statement>>,
|
||||||
|
) -> Result<(), CompileError> {
|
||||||
|
let start_label = self.new_label();
|
||||||
|
let else_label = self.new_label();
|
||||||
|
let end_label = self.new_label();
|
||||||
|
self.emit(Instruction::SetupLoop {
|
||||||
|
start: start_label,
|
||||||
|
end: end_label,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.set_label(start_label);
|
||||||
|
|
||||||
|
self.compile_test(test, None, Some(else_label), EvalContext::Statement)?;
|
||||||
|
|
||||||
|
let was_in_loop = self.in_loop;
|
||||||
|
self.in_loop = true;
|
||||||
|
self.compile_statements(body)?;
|
||||||
|
self.in_loop = was_in_loop;
|
||||||
|
self.emit(Instruction::Jump {
|
||||||
|
target: start_label,
|
||||||
|
});
|
||||||
|
self.set_label(else_label);
|
||||||
|
self.emit(Instruction::PopBlock);
|
||||||
|
if let Some(orelse) = orelse {
|
||||||
|
self.compile_statements(orelse)?;
|
||||||
|
}
|
||||||
|
self.set_label(end_label);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_for(
|
fn compile_for(
|
||||||
&mut self,
|
&mut self,
|
||||||
target: &ast::Expression,
|
target: &ast::Expression,
|
||||||
|
@ -1129,6 +1142,39 @@ impl<O: OutputStream> Compiler<O> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_annotated_assign(
|
||||||
|
&mut self,
|
||||||
|
target: &ast::Expression,
|
||||||
|
annotation: &ast::Expression,
|
||||||
|
value: &Option<ast::Expression>,
|
||||||
|
) -> Result<(), CompileError> {
|
||||||
|
if let Some(value) = value {
|
||||||
|
self.compile_expression(value)?;
|
||||||
|
self.compile_store(target)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile annotation:
|
||||||
|
self.compile_expression(annotation)?;
|
||||||
|
|
||||||
|
if let ast::ExpressionType::Identifier { name } = &target.node {
|
||||||
|
// Store as dict entry in __annotations__ dict:
|
||||||
|
self.emit(Instruction::LoadName {
|
||||||
|
name: String::from("__annotations__"),
|
||||||
|
scope: bytecode::NameScope::Local,
|
||||||
|
});
|
||||||
|
self.emit(Instruction::LoadConst {
|
||||||
|
value: bytecode::Constant::String {
|
||||||
|
value: name.to_string(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
self.emit(Instruction::StoreSubscript);
|
||||||
|
} else {
|
||||||
|
// Drop annotation if not assigned to simple identifier.
|
||||||
|
self.emit(Instruction::Pop);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_store(&mut self, target: &ast::Expression) -> Result<(), CompileError> {
|
fn compile_store(&mut self, target: &ast::Expression) -> Result<(), CompileError> {
|
||||||
match &target.node {
|
match &target.node {
|
||||||
ast::ExpressionType::Identifier { name } => {
|
ast::ExpressionType::Identifier { name } => {
|
||||||
|
@ -1272,6 +1318,8 @@ impl<O: OutputStream> Compiler<O> {
|
||||||
|
|
||||||
fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), CompileError> {
|
fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), CompileError> {
|
||||||
trace!("Compiling {:?}", expression);
|
trace!("Compiling {:?}", expression);
|
||||||
|
self.set_source_location(&expression.location);
|
||||||
|
|
||||||
use ast::ExpressionType::*;
|
use ast::ExpressionType::*;
|
||||||
match &expression.node {
|
match &expression.node {
|
||||||
Call {
|
Call {
|
||||||
|
@ -1664,6 +1712,10 @@ impl<O: OutputStream> Compiler<O> {
|
||||||
|
|
||||||
let mut loop_labels = vec![];
|
let mut loop_labels = vec![];
|
||||||
for generator in generators {
|
for generator in generators {
|
||||||
|
if generator.is_async {
|
||||||
|
unimplemented!("async for comprehensions");
|
||||||
|
}
|
||||||
|
|
||||||
if loop_labels.is_empty() {
|
if loop_labels.is_empty() {
|
||||||
// Load iterator onto stack (passed as first argument):
|
// Load iterator onto stack (passed as first argument):
|
||||||
self.emit(Instruction::LoadName {
|
self.emit(Instruction::LoadName {
|
||||||
|
|
|
@ -335,6 +335,17 @@ impl SymbolTableBuilder {
|
||||||
self.scan_expression(target)?;
|
self.scan_expression(target)?;
|
||||||
self.scan_expression(value)?;
|
self.scan_expression(value)?;
|
||||||
}
|
}
|
||||||
|
AnnAssign {
|
||||||
|
target,
|
||||||
|
annotation,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
self.scan_expression(target)?;
|
||||||
|
self.scan_expression(annotation)?;
|
||||||
|
if let Some(value) = value {
|
||||||
|
self.scan_expression(value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
With { items, body, .. } => {
|
With { items, body, .. } => {
|
||||||
for item in items {
|
for item in items {
|
||||||
self.scan_expression(&item.context_expr)?;
|
self.scan_expression(&item.context_expr)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue