@@ -41,6 +41,8 @@ pub struct Parser<'a> {
41
41
diagnostics : & ' a mut DiagnosticsBuilder < ParserDiagnostic > ,
42
42
/// An accumulating vector of pending skipped tokens diagnostics.
43
43
pending_skipped_token_diagnostics : Vec < PendingParserDiagnostic > ,
44
+ /// An indicator of whether to allow placeholders exprs.
45
+ allow_placeholder_exprs : bool ,
44
46
}
45
47
46
48
/// The possible results of a try_parse_* function failing to parse.
@@ -120,6 +122,7 @@ impl<'a> Parser<'a> {
120
122
last_trivia_length : Default :: default ( ) ,
121
123
diagnostics,
122
124
pending_skipped_token_diagnostics : Vec :: new ( ) ,
125
+ allow_placeholder_exprs : false ,
123
126
}
124
127
}
125
128
@@ -242,6 +245,9 @@ impl<'a> Parser<'a> {
242
245
SyntaxKind :: TerminalUse => Ok ( self . expect_item_use ( attributes, visibility) . into ( ) ) ,
243
246
SyntaxKind :: TerminalTrait => Ok ( self . expect_item_trait ( attributes, visibility) . into ( ) ) ,
244
247
SyntaxKind :: TerminalImpl => Ok ( self . expect_module_item_impl ( attributes, visibility) ) ,
248
+ SyntaxKind :: TerminalMacro => {
249
+ Ok ( self . expect_item_macro_declaration ( attributes, visibility) . into ( ) )
250
+ }
245
251
SyntaxKind :: TerminalIdentifier => {
246
252
// We take the identifier to check if the next token is a `!`. If it is, we assume
247
253
// that a macro is following and handle it similarly to any other module item. If
@@ -566,6 +572,48 @@ impl<'a> Parser<'a> {
566
572
ItemUse :: new_green ( self . db , attributes, visibility, use_kw, use_path, semicolon)
567
573
}
568
574
575
+ /// Assumes the current token is Macro.
576
+ /// Expected pattern: `macro<Identifier>{<MacroRulesList>}`
577
+ fn expect_item_macro_declaration (
578
+ & mut self ,
579
+ attributes : AttributeListGreen ,
580
+ visibility : VisibilityGreen ,
581
+ ) -> ItemMacroDeclarationGreen {
582
+ let macro_kw = self . take :: < TerminalMacro > ( ) ;
583
+ let name = self . parse_identifier ( ) ;
584
+ let lbrace = self . parse_token :: < TerminalLBrace > ( ) ;
585
+ let macro_rules = MacroRulesList :: new_green (
586
+ self . db ,
587
+ self . parse_list ( Self :: try_parse_macro_rule, is_of_kind ! ( rbrace) , "macro rule" ) ,
588
+ ) ;
589
+ let rbrace = self . parse_token :: < TerminalRBrace > ( ) ;
590
+ ItemMacroDeclaration :: new_green (
591
+ self . db ,
592
+ attributes,
593
+ visibility,
594
+ macro_kw,
595
+ name,
596
+ lbrace,
597
+ macro_rules,
598
+ rbrace,
599
+ )
600
+ }
601
+
602
+ /// Returns a GreenId of a node with a MacroRule kind or TryParseFailure if a macro rule can't
603
+ /// be parsed.
604
+ fn try_parse_macro_rule ( & mut self ) -> TryParseResult < MacroRuleGreen > {
605
+ match self . peek ( ) . kind {
606
+ SyntaxKind :: TerminalLParen => {
607
+ let lhs = self . parse_token_tree_node ( ) ;
608
+ let arrow = self . parse_token :: < TerminalMatchArrow > ( ) ;
609
+ let rhs = self . parse_block_with_placeholders ( ) ;
610
+ let semicolon = self . parse_token :: < TerminalSemicolon > ( ) ;
611
+ Ok ( MacroRule :: new_green ( self . db , lhs, arrow, rhs, semicolon) )
612
+ }
613
+ _ => Err ( TryParseFailure :: SkipToken ) ,
614
+ }
615
+ }
616
+
569
617
/// Returns a GreenId of a node with a UsePath kind or TryParseFailure if can't parse a UsePath.
570
618
fn try_parse_use_path ( & mut self ) -> TryParseResult < UsePathGreen > {
571
619
if !matches ! ( self . peek( ) . kind, SyntaxKind :: TerminalLBrace | SyntaxKind :: TerminalIdentifier )
@@ -1244,7 +1292,9 @@ impl<'a> Parser<'a> {
1244
1292
SyntaxKind :: TerminalOrOr if lbrace_allowed == LbraceAllowed :: Allow => {
1245
1293
Ok ( self . expect_closure_expr_nullary ( ) . into ( ) )
1246
1294
}
1247
-
1295
+ SyntaxKind :: TerminalDollar if self . allow_placeholder_exprs => {
1296
+ Ok ( self . expect_placeholder_expr ( ) . into ( ) )
1297
+ }
1248
1298
_ => {
1249
1299
// TODO(yuval): report to diagnostics.
1250
1300
Err ( TryParseFailure :: SkipToken )
@@ -1434,6 +1484,7 @@ impl<'a> Parser<'a> {
1434
1484
SyntaxKind :: TerminalComma => self . take :: < TerminalComma > ( ) . into ( ) ,
1435
1485
SyntaxKind :: TerminalDiv => self . take :: < TerminalDiv > ( ) . into ( ) ,
1436
1486
SyntaxKind :: TerminalDivEq => self . take :: < TerminalDivEq > ( ) . into ( ) ,
1487
+ SyntaxKind :: TerminalDollar => self . take :: < TerminalDollar > ( ) . into ( ) ,
1437
1488
SyntaxKind :: TerminalDot => self . take :: < TerminalDot > ( ) . into ( ) ,
1438
1489
SyntaxKind :: TerminalDotDot => self . take :: < TerminalDotDot > ( ) . into ( ) ,
1439
1490
SyntaxKind :: TerminalEndOfFile => self . take :: < TerminalEndOfFile > ( ) . into ( ) ,
@@ -1805,6 +1856,13 @@ impl<'a> Parser<'a> {
1805
1856
ExprBlock :: new_green ( self . db , lbrace, statements, rbrace)
1806
1857
}
1807
1858
1859
+ fn parse_block_with_placeholders ( & mut self ) -> ExprBlockGreen {
1860
+ let prev_allow_placeholder_exprs = self . allow_placeholder_exprs ;
1861
+ self . allow_placeholder_exprs = true ;
1862
+ let block = self . parse_block ( ) ;
1863
+ self . allow_placeholder_exprs = prev_allow_placeholder_exprs;
1864
+ block
1865
+ }
1808
1866
/// Assumes the current token is `Match`.
1809
1867
/// Expected pattern: `match <expr> \{<MatchArm>*\}`
1810
1868
fn expect_match_expr ( & mut self ) -> ExprMatchGreen {
@@ -1971,6 +2029,14 @@ impl<'a> Parser<'a> {
1971
2029
)
1972
2030
}
1973
2031
2032
+ /// Assumes the current token is Dollar.
2033
+ /// Expected pattern: `$<identifier>`.
2034
+ fn expect_placeholder_expr ( & mut self ) -> ExprPlaceholderGreen {
2035
+ let dollar = self . take :: < TerminalDollar > ( ) ;
2036
+ let name = self . parse_identifier ( ) ;
2037
+ ExprPlaceholder :: new_green ( self . db , dollar, name)
2038
+ }
2039
+
1974
2040
/// Returns a GreenId of a node with a MatchArm kind or TryParseFailure if a match arm can't be
1975
2041
/// parsed.
1976
2042
pub fn try_parse_match_arm ( & mut self ) -> TryParseResult < MatchArmGreen > {
@@ -2705,7 +2771,12 @@ impl<'a> Parser<'a> {
2705
2771
expected_element : & str ,
2706
2772
) -> Vec < ElementGreen > {
2707
2773
let mut children: Vec < ElementGreen > = Vec :: new ( ) ;
2774
+ let mut c = 0 ;
2708
2775
loop {
2776
+ if c > 10000 {
2777
+ break ;
2778
+ }
2779
+ c += 1 ;
2709
2780
let parse_result = try_parse_list_element ( self ) ;
2710
2781
match parse_result {
2711
2782
Ok ( element_green) => {
0 commit comments