From 6820d09938dcb2690af2764248a0fb373ab7e2fe Mon Sep 17 00:00:00 2001 From: Ryan Chandler Date: Fri, 16 Sep 2022 23:08:38 +0100 Subject: [PATCH 1/2] parser: support empty yield expressions --- trunk_parser/src/ast.rs | 2 +- trunk_parser/src/parser/mod.rs | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/trunk_parser/src/ast.rs b/trunk_parser/src/ast.rs index d6e4f9b..d371030 100644 --- a/trunk_parser/src/ast.rs +++ b/trunk_parser/src/ast.rs @@ -557,7 +557,7 @@ pub enum Expression { value: Box, }, Yield { - value: Box, + value: Option>, }, Negate { value: Box, diff --git a/trunk_parser/src/parser/mod.rs b/trunk_parser/src/parser/mod.rs index b474ba7..f8c2dcb 100644 --- a/trunk_parser/src/parser/mod.rs +++ b/trunk_parser/src/parser/mod.rs @@ -1473,12 +1473,16 @@ impl Parser { TokenKind::Yield => { self.next(); - let value = self.expression(Precedence::Lowest)?; + if self.current.kind == TokenKind::SemiColon { + Expression::Yield { value: None } + } else { + let value = self.expression(Precedence::Lowest)?; - // FIXME: Check for presence of => here to allow yielding key and value. + // FIXME: Check for presence of => here to allow yielding key and value. - Expression::Yield { - value: Box::new(value), + Expression::Yield { + value: Some(Box::new(value)), + } } } TokenKind::Clone => { @@ -4674,6 +4678,13 @@ mod tests { ); } + #[test] + fn empty_yield() { + assert_ast(" Date: Fri, 16 Sep 2022 23:18:31 +0100 Subject: [PATCH 2/2] parser: support all forms of yield/yield from --- trunk_lexer/src/lexer.rs | 1 + trunk_lexer/src/token.rs | 2 + trunk_parser/src/ast.rs | 6 ++- trunk_parser/src/parser/mod.rs | 80 +++++++++++++++++++++++++++++----- 4 files changed, 78 insertions(+), 11 deletions(-) diff --git a/trunk_lexer/src/lexer.rs b/trunk_lexer/src/lexer.rs index 8c5bf1d..b50c1e8 100644 --- a/trunk_lexer/src/lexer.rs +++ b/trunk_lexer/src/lexer.rs @@ -815,6 +815,7 @@ impl Lexer { fn identifier_to_keyword(ident: &[u8]) -> Option { Some(match ident { + b"from" => TokenKind::From, b"and" => TokenKind::LogicalAnd, b"or" => TokenKind::LogicalOr, b"xor" => TokenKind::LogicalXor, diff --git a/trunk_lexer/src/token.rs b/trunk_lexer/src/token.rs index fe4f746..f52ef46 100644 --- a/trunk_lexer/src/token.rs +++ b/trunk_lexer/src/token.rs @@ -11,6 +11,7 @@ pub enum OpenTagKind { #[derive(Debug, PartialEq, Clone)] pub enum TokenKind { + From, Print, Dollar, HaltCompiler, @@ -194,6 +195,7 @@ impl Default for Token { impl Display for TokenKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match self { + Self::From => "from", Self::Print => "print", Self::BitwiseNot => "~", Self::Dollar => "$", diff --git a/trunk_parser/src/ast.rs b/trunk_parser/src/ast.rs index d371030..e7e03bb 100644 --- a/trunk_parser/src/ast.rs +++ b/trunk_parser/src/ast.rs @@ -557,7 +557,11 @@ pub enum Expression { value: Box, }, Yield { - value: Option>, + key: Option>, + value: Option>, + }, + YieldFrom { + value: Box, }, Negate { value: Box, diff --git a/trunk_parser/src/parser/mod.rs b/trunk_parser/src/parser/mod.rs index f8c2dcb..4b1d97e 100644 --- a/trunk_parser/src/parser/mod.rs +++ b/trunk_parser/src/parser/mod.rs @@ -1474,14 +1474,38 @@ impl Parser { self.next(); if self.current.kind == TokenKind::SemiColon { - Expression::Yield { value: None } - } else { - let value = self.expression(Precedence::Lowest)?; - - // FIXME: Check for presence of => here to allow yielding key and value. - Expression::Yield { - value: Some(Box::new(value)), + key: None, + value: None, + } + } else { + let mut from = false; + + if self.current.kind == TokenKind::From { + self.next(); + from = true; + } + + let mut key = None; + let mut value = Box::new(self.expression(if from { + Precedence::YieldFrom + } else { + Precedence::Yield + })?); + + if self.current.kind == TokenKind::DoubleArrow && !from { + self.next(); + key = Some(value.clone()); + value = Box::new(self.expression(Precedence::Yield)?); + } + + if from { + Expression::YieldFrom { value } + } else { + Expression::Yield { + key, + value: Some(value), + } } } } @@ -4680,9 +4704,45 @@ mod tests { #[test] fn empty_yield() { - assert_ast(" 1;", + &[expr!(Expression::Yield { + key: Some(Box::new(Expression::Int { i: 0 })), + value: Some(Box::new(Expression::Int { i: 1 })) + })], + ); + } + + #[test] + fn yield_from() { + assert_ast( + "