Skip to content

Commit 162a91b

Browse files
committed
Add named expressions / assignment expressions
Aka "walrus operator". https://www.python.org/dev/peps/pep-0572/
1 parent c07e932 commit 162a91b

File tree

8 files changed

+55
-2
lines changed

8 files changed

+55
-2
lines changed

compiler/src/compile.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,17 @@ impl<O: OutputStream> Compiler<O> {
15651565
Ok(())
15661566
}
15671567

1568+
fn compile_named_expression(
1569+
&mut self,
1570+
target: &ast::Expression,
1571+
value: &ast::Expression,
1572+
) -> Result<(), CompileError> {
1573+
1574+
// evaluate value
1575+
// store into target
1576+
Ok(())
1577+
}
1578+
15681579
fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), CompileError> {
15691580
trace!("Compiling {:?}", expression);
15701581
self.set_source_location(&expression.location);
@@ -1577,6 +1588,7 @@ impl<O: OutputStream> Compiler<O> {
15771588
keywords,
15781589
} => self.compile_call(function, args, keywords)?,
15791590
BoolOp { op, values } => self.compile_bool_op(op, values)?,
1591+
NamedExpression { target, value} => self.compile_named_expression(target, value)?,
15801592
Binop { a, op, b } => {
15811593
self.compile_expression(a)?;
15821594
self.compile_expression(b)?;
@@ -1913,6 +1925,7 @@ impl<O: OutputStream> Compiler<O> {
19131925
Ok(has_stars)
19141926
}
19151927

1928+
19161929
fn compile_comprehension(
19171930
&mut self,
19181931
kind: &ast::ComprehensionKind,

compiler/src/symboltable.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,10 @@ impl SymbolTableBuilder {
547547
self.scan_expression(a, context)?;
548548
self.scan_expression(b, context)?;
549549
}
550+
NamedExpression {target, value} => {
551+
self.scan_expression(target, &ExpressionContext::Store)?;
552+
self.scan_expression(value, &ExpressionContext::Load)?;
553+
},
550554
BoolOp { values, .. } => {
551555
self.scan_expressions(values, context)?;
552556
}

parser/src/ast.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ pub enum ExpressionType {
186186
values: Vec<Expression>,
187187
},
188188

189+
/// A named expression aka. assignment expression aka. "Walrus operator"
190+
NamedExpression {
191+
target: Box<Expression>,
192+
value: Box<Expression>,
193+
},
194+
189195
/// A binary operation on two operands.
190196
Binop {
191197
a: Box<Expression>,
@@ -330,6 +336,7 @@ impl Expression {
330336

331337
match &self.node {
332338
BoolOp { .. } | Binop { .. } | Unop { .. } => "operator",
339+
NamedExpression { .. } => "named expression",
333340
Subscript { .. } => "subscript",
334341
Await { .. } => "await expression",
335342
Yield { .. } | YieldFrom { .. } => "yield expression",
@@ -359,7 +366,7 @@ impl Expression {
359366
| String {
360367
value: FormattedValue { .. },
361368
} => "f-string expression",
362-
Identifier { .. } => "named expression",
369+
Identifier { .. } => "identifier",
363370
Lambda { .. } => "lambda",
364371
IfExpression { .. } => "conditional expression",
365372
True | False | None => "keyword",

parser/src/lexer.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,16 @@ where
10951095
self.nesting -= 1;
10961096
}
10971097
':' => {
1098-
self.eat_single_char(Tok::Colon);
1098+
let tok_start = self.get_pos();
1099+
self.next_char();
1100+
if let Some('=') = self.chr0 {
1101+
self.next_char();
1102+
let tok_end = self.get_pos();
1103+
self.emit((tok_start, Tok::ColonEqual, tok_end));
1104+
} else {
1105+
let tok_end = self.get_pos();
1106+
self.emit((tok_start, Tok::Colon, tok_end));
1107+
}
10991108
}
11001109
';' => {
11011110
self.eat_single_char(Tok::Semi);

parser/src/python.lalrpop

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,14 @@ MulOp: ast::Operator = {
787787
"@" => ast::Operator::MatMult,
788788
};
789789

790+
NamedExpression: ast::Expression = {
791+
<e1:Expression> <location:@L> ":=" <e2:Expression> => ast::Expression {
792+
location,
793+
node: ast::ExpressionType::NamedExpression { target: Box::new(e1), value: Box::new(e2) }
794+
},
795+
NamedExpression,
796+
};
797+
790798
Factor: ast::Expression = {
791799
<location:@L> <op:UnOp> <e:Factor> => ast::Expression {
792800
location,
@@ -1169,6 +1177,7 @@ extern {
11691177
"//=" => lexer::Tok::DoubleSlashEqual,
11701178
"==" => lexer::Tok::EqEqual,
11711179
"!=" => lexer::Tok::NotEqual,
1180+
":=" => lexer::Tok::ColonEqual,
11721181
"<" => lexer::Tok::Less,
11731182
"<=" => lexer::Tok::LessEqual,
11741183
">" => lexer::Tok::Greater,

parser/src/token.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub enum Tok {
5959
CircumflexEqual, // '^='
6060
LeftShiftEqual,
6161
RightShiftEqual,
62+
ColonEqual,
6263
DoubleSlash, // '//'
6364
DoubleSlashEqual,
6465
At,
@@ -181,6 +182,7 @@ impl fmt::Display for Tok {
181182
CircumflexEqual => f.write_str("'^='"),
182183
LeftShiftEqual => f.write_str("'<<='"),
183184
RightShiftEqual => f.write_str("'>>='"),
185+
ColonEqual => f.write_str("':='"),
184186
DoubleSlash => f.write_str("'//'"),
185187
DoubleSlashEqual => f.write_str("'//='"),
186188
At => f.write_str("'@'"),

vm/src/exceptions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ pub struct ExceptionZoo {
404404
pub syntax_error: PyClassRef,
405405
pub indentation_error: PyClassRef,
406406
pub tab_error: PyClassRef,
407+
pub target_scope_error: PyClassRef,
407408
pub system_error: PyClassRef,
408409
pub type_error: PyClassRef,
409410
pub value_error: PyClassRef,
@@ -473,6 +474,7 @@ impl ExceptionZoo {
473474
let eof_error = create_type("EOFError", &type_type, &exception_type);
474475
let indentation_error = create_type("IndentationError", &type_type, &syntax_error);
475476
let tab_error = create_type("TabError", &type_type, &indentation_error);
477+
let target_scope_error = create_type("TargetScopeError", &type_type, &syntax_error);
476478
let unicode_error = create_type("UnicodeError", &type_type, &value_error);
477479
let unicode_decode_error = create_type("UnicodeDecodeError", &type_type, &unicode_error);
478480
let unicode_encode_error = create_type("UnicodeEncodeError", &type_type, &unicode_error);
@@ -571,6 +573,7 @@ impl ExceptionZoo {
571573
keyboard_interrupt,
572574
generator_exit,
573575
system_exit,
576+
target_scope_error,
574577
}
575578
}
576579
}

vm/src/stdlib/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,12 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
328328
args => expressions_to_ast(vm, args)?,
329329
keywords => map_ast(keyword_to_ast, vm, keywords)?,
330330
}),
331+
NamedExpression {target, value} => {
332+
node!(vm, NamedExpression, {
333+
target => expression_to_ast(vm, target)?,
334+
value => expression_to_ast(vm, value)?,
335+
})
336+
},
331337
Binop { a, op, b } => {
332338
// Operator:
333339
node!(vm, BinOp, {

0 commit comments

Comments
 (0)