From 89e56c364f3d0a9d5a12ae488185abc1ea69df4a Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Fri, 24 Aug 2018 11:45:14 +0300
Subject: Labeled expressions

---
 crates/libsyntax2/src/grammar.ron                  |  5 +-
 crates/libsyntax2/src/grammar/expressions/atom.rs  | 61 +++++++++++++++------
 crates/libsyntax2/src/grammar/mod.rs               |  2 +-
 crates/libsyntax2/src/syntax_kinds/generated.rs    | 10 ++--
 .../tests/data/parser/inline/0107_label.rs         |  5 ++
 .../tests/data/parser/inline/0107_label.txt        | 63 ++++++++++++++++++++++
 6 files changed, 123 insertions(+), 23 deletions(-)
 create mode 100644 crates/libsyntax2/tests/data/parser/inline/0107_label.rs
 create mode 100644 crates/libsyntax2/tests/data/parser/inline/0107_label.txt

(limited to 'crates/libsyntax2')

diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
index dff88cc4a..52764e664 100644
--- a/crates/libsyntax2/src/grammar.ron
+++ b/crates/libsyntax2/src/grammar.ron
@@ -161,11 +161,12 @@ Grammar(
         "PATH_EXPR",
         "LAMBDA_EXPR",
         "IF_EXPR",
-        "WHILE_EXPR",
         "LOOP_EXPR",
+        "FOR_EXPR",
+        "WHILE_EXPR",
         "CONTINUE_EXPR",
         "BREAK_EXPR",
-        "FOR_EXPR",
+        "LABEL",
         "BLOCK_EXPR",
         "RETURN_EXPR",
         "MATCH_EXPR",
diff --git a/crates/libsyntax2/src/grammar/expressions/atom.rs b/crates/libsyntax2/src/grammar/expressions/atom.rs
index 9f470d561..9d98340af 100644
--- a/crates/libsyntax2/src/grammar/expressions/atom.rs
+++ b/crates/libsyntax2/src/grammar/expressions/atom.rs
@@ -30,7 +30,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
     token_set_union![
         LITERAL_FIRST,
         token_set![L_PAREN, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW, L_CURLY, RETURN_KW,
-                   IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW ],
+                   IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
     ];
 
 pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
@@ -48,9 +48,24 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMark
         PIPE => lambda_expr(p),
         MOVE_KW if la == PIPE => lambda_expr(p),
         IF_KW => if_expr(p),
-        WHILE_KW => while_expr(p),
-        LOOP_KW => loop_expr(p),
-        FOR_KW => for_expr(p),
+
+        LOOP_KW => loop_expr(p, None),
+        FOR_KW => for_expr(p, None),
+        WHILE_KW => while_expr(p, None),
+        LIFETIME if la == COLON => {
+            let m = p.start();
+            label(p);
+            match p.current() {
+                LOOP_KW => loop_expr(p, Some(m)),
+                FOR_KW => for_expr(p, Some(m)),
+                WHILE_KW => while_expr(p, Some(m)),
+                _ => {
+                    p.error("expected a loop");
+                    return None;
+                }
+            }
+        }
+
         MATCH_KW => match_expr(p),
         UNSAFE_KW if la == L_CURLY => block_expr(p),
         L_CURLY => block_expr(p),
@@ -164,39 +179,53 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
     m.complete(p, IF_EXPR)
 }
 
-// test while_expr
+// test label
 // fn foo() {
-//     while true {};
-//     while let Some(x) = it.next() {};
+//     'a: loop {}
+//     'b: while true {}
+//     'c: for x in () {}
 // }
-fn while_expr(p: &mut Parser) -> CompletedMarker {
-    assert!(p.at(WHILE_KW));
+fn label(p: &mut Parser) {
+    assert!(p.at(LIFETIME) && p.nth(1) == COLON);
     let m = p.start();
     p.bump();
-    cond(p);
-    block(p);
-    m.complete(p, WHILE_EXPR)
+    p.bump();
+    m.complete(p, LABEL);
 }
 
 // test loop_expr
 // fn foo() {
 //     loop {};
 // }
-fn loop_expr(p: &mut Parser) -> CompletedMarker {
+fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     assert!(p.at(LOOP_KW));
-    let m = p.start();
+    let m = m.unwrap_or_else(|| p.start());
     p.bump();
     block(p);
     m.complete(p, LOOP_EXPR)
 }
 
+// test while_expr
+// fn foo() {
+//     while true {};
+//     while let Some(x) = it.next() {};
+// }
+fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
+    assert!(p.at(WHILE_KW));
+    let m = m.unwrap_or_else(|| p.start());
+    p.bump();
+    cond(p);
+    block(p);
+    m.complete(p, WHILE_EXPR)
+}
+
 // test for_expr
 // fn foo() {
 //     for x in [] {};
 // }
-fn for_expr(p: &mut Parser) -> CompletedMarker {
+fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
     assert!(p.at(FOR_KW));
-    let m = p.start();
+    let m = m.unwrap_or_else(|| p.start());
     p.bump();
     patterns::pattern(p);
     p.expect(IN_KW);
diff --git a/crates/libsyntax2/src/grammar/mod.rs b/crates/libsyntax2/src/grammar/mod.rs
index 0f168eb60..25887921b 100644
--- a/crates/libsyntax2/src/grammar/mod.rs
+++ b/crates/libsyntax2/src/grammar/mod.rs
@@ -32,7 +32,7 @@ mod type_params;
 mod types;
 
 use {
-    parser_api::{CompletedMarker, Parser, TokenSet},
+    parser_api::{Marker, CompletedMarker, Parser, TokenSet},
     SyntaxKind::{self, *},
 };
 
diff --git a/crates/libsyntax2/src/syntax_kinds/generated.rs b/crates/libsyntax2/src/syntax_kinds/generated.rs
index 82b6c89cf..61d527f93 100644
--- a/crates/libsyntax2/src/syntax_kinds/generated.rs
+++ b/crates/libsyntax2/src/syntax_kinds/generated.rs
@@ -157,11 +157,12 @@ pub enum SyntaxKind {
     PATH_EXPR,
     LAMBDA_EXPR,
     IF_EXPR,
-    WHILE_EXPR,
     LOOP_EXPR,
+    FOR_EXPR,
+    WHILE_EXPR,
     CONTINUE_EXPR,
     BREAK_EXPR,
-    FOR_EXPR,
+    LABEL,
     BLOCK_EXPR,
     RETURN_EXPR,
     MATCH_EXPR,
@@ -406,11 +407,12 @@ impl SyntaxKind {
             PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" },
             LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" },
             IF_EXPR => &SyntaxInfo { name: "IF_EXPR" },
-            WHILE_EXPR => &SyntaxInfo { name: "WHILE_EXPR" },
             LOOP_EXPR => &SyntaxInfo { name: "LOOP_EXPR" },
+            FOR_EXPR => &SyntaxInfo { name: "FOR_EXPR" },
+            WHILE_EXPR => &SyntaxInfo { name: "WHILE_EXPR" },
             CONTINUE_EXPR => &SyntaxInfo { name: "CONTINUE_EXPR" },
             BREAK_EXPR => &SyntaxInfo { name: "BREAK_EXPR" },
-            FOR_EXPR => &SyntaxInfo { name: "FOR_EXPR" },
+            LABEL => &SyntaxInfo { name: "LABEL" },
             BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" },
             RETURN_EXPR => &SyntaxInfo { name: "RETURN_EXPR" },
             MATCH_EXPR => &SyntaxInfo { name: "MATCH_EXPR" },
diff --git a/crates/libsyntax2/tests/data/parser/inline/0107_label.rs b/crates/libsyntax2/tests/data/parser/inline/0107_label.rs
new file mode 100644
index 000000000..48e83f263
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0107_label.rs
@@ -0,0 +1,5 @@
+fn foo() {
+    'a: loop {}
+    'b: while true {}
+    'c: for x in () {}
+}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0107_label.txt b/crates/libsyntax2/tests/data/parser/inline/0107_label.txt
new file mode 100644
index 000000000..66ba792b8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0107_label.txt
@@ -0,0 +1,63 @@
+FILE@[0; 74)
+  FN_DEF@[0; 73)
+    FN_KW@[0; 2)
+    WHITESPACE@[2; 3)
+    NAME@[3; 6)
+      IDENT@[3; 6) "foo"
+    PARAM_LIST@[6; 8)
+      L_PAREN@[6; 7)
+      R_PAREN@[7; 8)
+    WHITESPACE@[8; 9)
+    BLOCK_EXPR@[9; 73)
+      L_CURLY@[9; 10)
+      WHITESPACE@[10; 15)
+      EXPR_STMT@[15; 26)
+        LOOP_EXPR@[15; 26)
+          LABEL@[15; 18)
+            LIFETIME@[15; 17) "'a"
+            COLON@[17; 18)
+          WHITESPACE@[18; 19)
+          LOOP_KW@[19; 23)
+          WHITESPACE@[23; 24)
+          BLOCK_EXPR@[24; 26)
+            L_CURLY@[24; 25)
+            R_CURLY@[25; 26)
+      WHITESPACE@[26; 31)
+      EXPR_STMT@[31; 48)
+        WHILE_EXPR@[31; 48)
+          LABEL@[31; 34)
+            LIFETIME@[31; 33) "'b"
+            COLON@[33; 34)
+          WHITESPACE@[34; 35)
+          WHILE_KW@[35; 40)
+          WHITESPACE@[40; 41)
+          LITERAL@[41; 45)
+            TRUE_KW@[41; 45)
+          WHITESPACE@[45; 46)
+          BLOCK_EXPR@[46; 48)
+            L_CURLY@[46; 47)
+            R_CURLY@[47; 48)
+      WHITESPACE@[48; 53)
+      FOR_EXPR@[53; 71)
+        LABEL@[53; 56)
+          LIFETIME@[53; 55) "'c"
+          COLON@[55; 56)
+        WHITESPACE@[56; 57)
+        FOR_KW@[57; 60)
+        WHITESPACE@[60; 61)
+        BIND_PAT@[61; 62)
+          NAME@[61; 62)
+            IDENT@[61; 62) "x"
+        WHITESPACE@[62; 63)
+        IN_KW@[63; 65)
+        WHITESPACE@[65; 66)
+        TUPLE_EXPR@[66; 68)
+          L_PAREN@[66; 67)
+          R_PAREN@[67; 68)
+        WHITESPACE@[68; 69)
+        BLOCK_EXPR@[69; 71)
+          L_CURLY@[69; 70)
+          R_CURLY@[70; 71)
+      WHITESPACE@[71; 72)
+      R_CURLY@[72; 73)
+  WHITESPACE@[73; 74)
-- 
cgit v1.2.3