diff --git a/compiler/src/compile.rs b/compiler/src/compile.rs index d02d3d3878..a49c417936 100644 --- a/compiler/src/compile.rs +++ b/compiler/src/compile.rs @@ -1565,6 +1565,17 @@ impl Compiler { Ok(()) } + fn compile_named_expression( + &mut self, + target: &ast::Expression, + value: &ast::Expression, + ) -> Result<(), CompileError> { + + // evaluate value + // store into target + Ok(()) + } + fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), CompileError> { trace!("Compiling {:?}", expression); self.set_source_location(&expression.location); @@ -1577,6 +1588,7 @@ impl Compiler { keywords, } => self.compile_call(function, args, keywords)?, BoolOp { op, values } => self.compile_bool_op(op, values)?, + NamedExpression { target, value} => self.compile_named_expression(target, value)?, Binop { a, op, b } => { self.compile_expression(a)?; self.compile_expression(b)?; @@ -1913,6 +1925,7 @@ impl Compiler { Ok(has_stars) } + fn compile_comprehension( &mut self, kind: &ast::ComprehensionKind, diff --git a/compiler/src/symboltable.rs b/compiler/src/symboltable.rs index c3e2099bcf..f8791dbd8e 100644 --- a/compiler/src/symboltable.rs +++ b/compiler/src/symboltable.rs @@ -547,6 +547,10 @@ impl SymbolTableBuilder { self.scan_expression(a, context)?; self.scan_expression(b, context)?; } + NamedExpression {target, value} => { + self.scan_expression(target, &ExpressionContext::Store)?; + self.scan_expression(value, &ExpressionContext::Load)?; + }, BoolOp { values, .. } => { self.scan_expressions(values, context)?; } diff --git a/parser/src/ast.rs b/parser/src/ast.rs index f8e104757c..3452632ae4 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -186,6 +186,12 @@ pub enum ExpressionType { values: Vec, }, + /// A named expression aka. assignment expression aka. "Walrus operator" + NamedExpression { + target: Box, + value: Box, + }, + /// A binary operation on two operands. Binop { a: Box, @@ -330,6 +336,7 @@ impl Expression { match &self.node { BoolOp { .. } | Binop { .. } | Unop { .. } => "operator", + NamedExpression { .. } => "named expression", Subscript { .. } => "subscript", Await { .. } => "await expression", Yield { .. } | YieldFrom { .. } => "yield expression", @@ -359,7 +366,7 @@ impl Expression { | String { value: FormattedValue { .. }, } => "f-string expression", - Identifier { .. } => "named expression", + Identifier { .. } => "identifier", Lambda { .. } => "lambda", IfExpression { .. } => "conditional expression", True | False | None => "keyword", diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index 2a70119676..094f388994 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -1095,7 +1095,16 @@ where self.nesting -= 1; } ':' => { - self.eat_single_char(Tok::Colon); + let tok_start = self.get_pos(); + self.next_char(); + if let Some('=') = self.chr0 { + self.next_char(); + let tok_end = self.get_pos(); + self.emit((tok_start, Tok::ColonEqual, tok_end)); + } else { + let tok_end = self.get_pos(); + self.emit((tok_start, Tok::Colon, tok_end)); + } } ';' => { self.eat_single_char(Tok::Semi); diff --git a/parser/src/python.lalrpop b/parser/src/python.lalrpop index 58ea002461..91a7899bcb 100644 --- a/parser/src/python.lalrpop +++ b/parser/src/python.lalrpop @@ -787,6 +787,14 @@ MulOp: ast::Operator = { "@" => ast::Operator::MatMult, }; +NamedExpression: ast::Expression = { + ":=" => ast::Expression { + location, + node: ast::ExpressionType::NamedExpression { target: Box::new(e1), value: Box::new(e2) } + }, + NamedExpression, +}; + Factor: ast::Expression = { => ast::Expression { location, @@ -1169,6 +1177,7 @@ extern { "//=" => lexer::Tok::DoubleSlashEqual, "==" => lexer::Tok::EqEqual, "!=" => lexer::Tok::NotEqual, + ":=" => lexer::Tok::ColonEqual, "<" => lexer::Tok::Less, "<=" => lexer::Tok::LessEqual, ">" => lexer::Tok::Greater, diff --git a/parser/src/token.rs b/parser/src/token.rs index 09122bb83f..d216741749 100644 --- a/parser/src/token.rs +++ b/parser/src/token.rs @@ -59,6 +59,7 @@ pub enum Tok { CircumflexEqual, // '^=' LeftShiftEqual, RightShiftEqual, + ColonEqual, DoubleSlash, // '//' DoubleSlashEqual, At, @@ -181,6 +182,7 @@ impl fmt::Display for Tok { CircumflexEqual => f.write_str("'^='"), LeftShiftEqual => f.write_str("'<<='"), RightShiftEqual => f.write_str("'>>='"), + ColonEqual => f.write_str("':='"), DoubleSlash => f.write_str("'//'"), DoubleSlashEqual => f.write_str("'//='"), At => f.write_str("'@'"), diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 87654fb541..1fa3910fe4 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -404,6 +404,7 @@ pub struct ExceptionZoo { pub syntax_error: PyClassRef, pub indentation_error: PyClassRef, pub tab_error: PyClassRef, + pub target_scope_error: PyClassRef, pub system_error: PyClassRef, pub type_error: PyClassRef, pub value_error: PyClassRef, @@ -473,6 +474,7 @@ impl ExceptionZoo { let eof_error = create_type("EOFError", &type_type, &exception_type); let indentation_error = create_type("IndentationError", &type_type, &syntax_error); let tab_error = create_type("TabError", &type_type, &indentation_error); + let target_scope_error = create_type("TargetScopeError", &type_type, &syntax_error); let unicode_error = create_type("UnicodeError", &type_type, &value_error); let unicode_decode_error = create_type("UnicodeDecodeError", &type_type, &unicode_error); let unicode_encode_error = create_type("UnicodeEncodeError", &type_type, &unicode_error); @@ -571,6 +573,7 @@ impl ExceptionZoo { keyboard_interrupt, generator_exit, system_exit, + target_scope_error, } } } diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index d25429dcb3..387a32bb67 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -328,6 +328,12 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes args => expressions_to_ast(vm, args)?, keywords => map_ast(keyword_to_ast, vm, keywords)?, }), + NamedExpression {target, value} => { + node!(vm, NamedExpression, { + target => expression_to_ast(vm, target)?, + value => expression_to_ast(vm, value)?, + }) + }, Binop { a, op, b } => { // Operator: node!(vm, BinOp, {