aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grammar.ron4
-rw-r--r--src/grammar/expressions.rs44
-rw-r--r--src/parser_api.rs23
-rw-r--r--src/syntax_kinds/generated.rs11
-rw-r--r--tests/data/lexer/0011_keywords.rs2
-rw-r--r--tests/data/lexer/0011_keywords.txt2
-rw-r--r--tests/data/parser/inline/0068_return_expr.rs4
-rw-r--r--tests/data/parser/inline/0068_return_expr.txt28
8 files changed, 100 insertions, 18 deletions
diff --git a/src/grammar.ron b/src/grammar.ron
index 109556561..8e8a71010 100644
--- a/src/grammar.ron
+++ b/src/grammar.ron
@@ -70,6 +70,7 @@ Grammar(
70 "ref", 70 "ref",
71 "let", 71 "let",
72 "move", 72 "move",
73 "return",
73 ], 74 ],
74 contextual_keywords: [ 75 contextual_keywords: [
75 "auto", 76 "auto",
@@ -138,6 +139,8 @@ Grammar(
138 "STRUCT_LIT", 139 "STRUCT_LIT",
139 "STRUCT_LIT_FIELD", 140 "STRUCT_LIT_FIELD",
140 "IF_EXPR", 141 "IF_EXPR",
142 "BLOCK_EXPR",
143 "RETURN_EXPR",
141 144
142 "EXTERN_BLOCK_EXPR", 145 "EXTERN_BLOCK_EXPR",
143 "ENUM_VARIANT", 146 "ENUM_VARIANT",
@@ -155,7 +158,6 @@ Grammar(
155 "ABI", 158 "ABI",
156 "NAME", 159 "NAME",
157 "NAME_REF", 160 "NAME_REF",
158 "BLOCK_EXPR",
159 161
160 "LET_STMT", 162 "LET_STMT",
161 "EXPR_STMT", 163 "EXPR_STMT",
diff --git a/src/grammar/expressions.rs b/src/grammar/expressions.rs
index 5c59843a4..423e1a95a 100644
--- a/src/grammar/expressions.rs
+++ b/src/grammar/expressions.rs
@@ -13,18 +13,20 @@ use super::*;
13// let _ = b"e"; 13// let _ = b"e";
14// let _ = br"f"; 14// let _ = br"f";
15// } 15// }
16const LITERAL_FIRST: TokenSet =
17 token_set![TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR,
18 STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
19
16pub(super) fn literal(p: &mut Parser) -> Option<CompletedMarker> { 20pub(super) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
17 match p.current() { 21 if !LITERAL_FIRST.contains(p.current()) {
18 TRUE_KW | FALSE_KW | INT_NUMBER | FLOAT_NUMBER | BYTE | CHAR | STRING | RAW_STRING 22 return None;
19 | BYTE_STRING | RAW_BYTE_STRING => {
20 let m = p.start();
21 p.bump();
22 Some(m.complete(p, LITERAL))
23 }
24 _ => None,
25 } 23 }
24 let m = p.start();
25 p.bump();
26 Some(m.complete(p, LITERAL))
26} 27}
27 28
29const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST;
28pub(super) fn expr(p: &mut Parser) { 30pub(super) fn expr(p: &mut Parser) {
29 let mut lhs = match prefix_expr(p) { 31 let mut lhs = match prefix_expr(p) {
30 Some(lhs) => lhs, 32 Some(lhs) => lhs,
@@ -80,6 +82,11 @@ fn let_stmt(p: &mut Parser) {
80 m.complete(p, LET_STMT); 82 m.complete(p, LET_STMT);
81} 83}
82 84
85const PREFIX_EXPR_FIRST: TokenSet =
86 token_set_union![
87 token_set![AMPERSAND, STAR, EXCL],
88 ATOM_EXPR_FIRST,
89 ];
83fn prefix_expr(p: &mut Parser) -> Option<CompletedMarker> { 90fn prefix_expr(p: &mut Parser) -> Option<CompletedMarker> {
84 let done = match p.current() { 91 let done = match p.current() {
85 AMPERSAND => ref_expr(p), 92 AMPERSAND => ref_expr(p),
@@ -128,6 +135,11 @@ fn not_expr(p: &mut Parser) -> CompletedMarker {
128 m.complete(p, NOT_EXPR) 135 m.complete(p, NOT_EXPR)
129} 136}
130 137
138const ATOM_EXPR_FIRST: TokenSet =
139 token_set_union![
140 LITERAL_FIRST,
141 token_set![L_PAREN, PIPE, MOVE_KW, IF_KW, UNSAFE_KW, L_CURLY, RETURN_KW],
142 ];
131fn atom_expr(p: &mut Parser) -> Option<CompletedMarker> { 143fn atom_expr(p: &mut Parser) -> Option<CompletedMarker> {
132 match literal(p) { 144 match literal(p) {
133 Some(m) => return Some(m), 145 Some(m) => return Some(m),
@@ -144,6 +156,7 @@ fn atom_expr(p: &mut Parser) -> Option<CompletedMarker> {
144 IF_KW => if_expr(p), 156 IF_KW => if_expr(p),
145 UNSAFE_KW if la == L_CURLY => block_expr(p), 157 UNSAFE_KW if la == L_CURLY => block_expr(p),
146 L_CURLY => block_expr(p), 158 L_CURLY => block_expr(p),
159 RETURN_KW => return_expr(p),
147 _ => { 160 _ => {
148 p.err_and_bump("expected expression"); 161 p.err_and_bump("expected expression");
149 return None; 162 return None;
@@ -237,6 +250,21 @@ fn block_expr(p: &mut Parser) -> CompletedMarker {
237 m.complete(p, BLOCK_EXPR) 250 m.complete(p, BLOCK_EXPR)
238} 251}
239 252
253// test return_expr
254// fn foo() {
255// return;
256// return 92;
257// }
258fn return_expr(p: &mut Parser) -> CompletedMarker {
259 assert!(p.at(RETURN_KW));
260 let m = p.start();
261 p.bump();
262 if EXPR_FIRST.contains(p.current()) {
263 expr(p);
264 }
265 m.complete(p, RETURN_EXPR)
266}
267
240// test call_expr 268// test call_expr
241// fn foo() { 269// fn foo() {
242// let _ = f(); 270// let _ = f();
diff --git a/src/parser_api.rs b/src/parser_api.rs
index 5a0da32c9..d12f773b2 100644
--- a/src/parser_api.rs
+++ b/src/parser_api.rs
@@ -3,22 +3,22 @@ use {
3 SyntaxKind::{self, ERROR}, 3 SyntaxKind::{self, ERROR},
4}; 4};
5 5
6pub(crate) struct TokenSet { 6#[derive(Clone, Copy)]
7 pub tokens: &'static [SyntaxKind], 7pub(crate) struct TokenSet(pub(crate) u128);
8fn mask(kind: SyntaxKind) -> u128 {
9 1u128 << (kind as usize)
8} 10}
9 11
10impl TokenSet { 12impl TokenSet {
11 pub fn contains(&self, kind: SyntaxKind) -> bool { 13 pub fn contains(&self, kind: SyntaxKind) -> bool {
12 self.tokens.contains(&kind) 14 self.0 & mask(kind) != 0
13 } 15 }
14} 16}
15 17
16#[macro_export] 18#[macro_export]
17macro_rules! token_set { 19macro_rules! token_set {
18 ($($t:ident),*) => { 20 ($($t:ident),*) => {
19 TokenSet { 21 TokenSet($(1u128 << ($t as usize))|*)
20 tokens: &[$($t),*],
21 }
22 }; 22 };
23 23
24 ($($t:ident),* ,) => { 24 ($($t:ident),* ,) => {
@@ -26,6 +26,17 @@ macro_rules! token_set {
26 }; 26 };
27} 27}
28 28
29#[macro_export]
30macro_rules! token_set_union {
31 ($($ts:expr),*) => {
32 TokenSet($($ts.0)|*)
33 };
34
35 ($($ts:expr),* ,) => {
36 token_set_union!($($ts),*)
37 };
38}
39
29/// `Parser` struct provides the low-level API for 40/// `Parser` struct provides the low-level API for
30/// navigating through the stream of tokens and 41/// navigating through the stream of tokens and
31/// constructing the parse tree. The actual parsing 42/// constructing the parse tree. The actual parsing
diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs
index 5f26cbf0a..50aa2b580 100644
--- a/src/syntax_kinds/generated.rs
+++ b/src/syntax_kinds/generated.rs
@@ -71,6 +71,7 @@ pub enum SyntaxKind {
71 REF_KW, 71 REF_KW,
72 LET_KW, 72 LET_KW,
73 MOVE_KW, 73 MOVE_KW,
74 RETURN_KW,
74 AUTO_KW, 75 AUTO_KW,
75 DEFAULT_KW, 76 DEFAULT_KW,
76 UNION_KW, 77 UNION_KW,
@@ -129,6 +130,8 @@ pub enum SyntaxKind {
129 STRUCT_LIT, 130 STRUCT_LIT,
130 STRUCT_LIT_FIELD, 131 STRUCT_LIT_FIELD,
131 IF_EXPR, 132 IF_EXPR,
133 BLOCK_EXPR,
134 RETURN_EXPR,
132 EXTERN_BLOCK_EXPR, 135 EXTERN_BLOCK_EXPR,
133 ENUM_VARIANT, 136 ENUM_VARIANT,
134 NAMED_FIELD, 137 NAMED_FIELD,
@@ -145,7 +148,6 @@ pub enum SyntaxKind {
145 ABI, 148 ABI,
146 NAME, 149 NAME,
147 NAME_REF, 150 NAME_REF,
148 BLOCK_EXPR,
149 LET_STMT, 151 LET_STMT,
150 EXPR_STMT, 152 EXPR_STMT,
151 TYPE_PARAM_LIST, 153 TYPE_PARAM_LIST,
@@ -202,6 +204,7 @@ impl SyntaxKind {
202 | REF_KW 204 | REF_KW
203 | LET_KW 205 | LET_KW
204 | MOVE_KW 206 | MOVE_KW
207 | RETURN_KW
205 | AUTO_KW 208 | AUTO_KW
206 | DEFAULT_KW 209 | DEFAULT_KW
207 | UNION_KW 210 | UNION_KW
@@ -278,6 +281,7 @@ impl SyntaxKind {
278 REF_KW => &SyntaxInfo { name: "REF_KW" }, 281 REF_KW => &SyntaxInfo { name: "REF_KW" },
279 LET_KW => &SyntaxInfo { name: "LET_KW" }, 282 LET_KW => &SyntaxInfo { name: "LET_KW" },
280 MOVE_KW => &SyntaxInfo { name: "MOVE_KW" }, 283 MOVE_KW => &SyntaxInfo { name: "MOVE_KW" },
284 RETURN_KW => &SyntaxInfo { name: "RETURN_KW" },
281 AUTO_KW => &SyntaxInfo { name: "AUTO_KW" }, 285 AUTO_KW => &SyntaxInfo { name: "AUTO_KW" },
282 DEFAULT_KW => &SyntaxInfo { name: "DEFAULT_KW" }, 286 DEFAULT_KW => &SyntaxInfo { name: "DEFAULT_KW" },
283 UNION_KW => &SyntaxInfo { name: "UNION_KW" }, 287 UNION_KW => &SyntaxInfo { name: "UNION_KW" },
@@ -336,6 +340,8 @@ impl SyntaxKind {
336 STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, 340 STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" },
337 STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" }, 341 STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" },
338 IF_EXPR => &SyntaxInfo { name: "IF_EXPR" }, 342 IF_EXPR => &SyntaxInfo { name: "IF_EXPR" },
343 BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" },
344 RETURN_EXPR => &SyntaxInfo { name: "RETURN_EXPR" },
339 EXTERN_BLOCK_EXPR => &SyntaxInfo { name: "EXTERN_BLOCK_EXPR" }, 345 EXTERN_BLOCK_EXPR => &SyntaxInfo { name: "EXTERN_BLOCK_EXPR" },
340 ENUM_VARIANT => &SyntaxInfo { name: "ENUM_VARIANT" }, 346 ENUM_VARIANT => &SyntaxInfo { name: "ENUM_VARIANT" },
341 NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" }, 347 NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" },
@@ -352,7 +358,6 @@ impl SyntaxKind {
352 ABI => &SyntaxInfo { name: "ABI" }, 358 ABI => &SyntaxInfo { name: "ABI" },
353 NAME => &SyntaxInfo { name: "NAME" }, 359 NAME => &SyntaxInfo { name: "NAME" },
354 NAME_REF => &SyntaxInfo { name: "NAME_REF" }, 360 NAME_REF => &SyntaxInfo { name: "NAME_REF" },
355 BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" },
356 LET_STMT => &SyntaxInfo { name: "LET_STMT" }, 361 LET_STMT => &SyntaxInfo { name: "LET_STMT" },
357 EXPR_STMT => &SyntaxInfo { name: "EXPR_STMT" }, 362 EXPR_STMT => &SyntaxInfo { name: "EXPR_STMT" },
358 TYPE_PARAM_LIST => &SyntaxInfo { name: "TYPE_PARAM_LIST" }, 363 TYPE_PARAM_LIST => &SyntaxInfo { name: "TYPE_PARAM_LIST" },
@@ -403,6 +408,7 @@ impl SyntaxKind {
403 "ref" => REF_KW, 408 "ref" => REF_KW,
404 "let" => LET_KW, 409 "let" => LET_KW,
405 "move" => MOVE_KW, 410 "move" => MOVE_KW,
411 "return" => RETURN_KW,
406 _ => return None, 412 _ => return None,
407 }; 413 };
408 Some(kw) 414 Some(kw)
@@ -506,6 +512,7 @@ impl SyntaxKind {
506 REF_KW => "ref", 512 REF_KW => "ref",
507 LET_KW => "let", 513 LET_KW => "let",
508 MOVE_KW => "move", 514 MOVE_KW => "move",
515 RETURN_KW => "return",
509 AUTO_KW => "auto", 516 AUTO_KW => "auto",
510 DEFAULT_KW => "default", 517 DEFAULT_KW => "default",
511 UNION_KW => "union", 518 UNION_KW => "union",
diff --git a/tests/data/lexer/0011_keywords.rs b/tests/data/lexer/0011_keywords.rs
index 22b063567..e6bf64d4d 100644
--- a/tests/data/lexer/0011_keywords.rs
+++ b/tests/data/lexer/0011_keywords.rs
@@ -1,3 +1,3 @@
1fn use struct trait enum impl true false as extern crate 1fn use struct trait enum impl true false as extern crate
2mod pub self super in where for loop while if match const 2mod pub self super in where for loop while if match const
3static mut type ref let else move 3static mut type ref let else move return
diff --git a/tests/data/lexer/0011_keywords.txt b/tests/data/lexer/0011_keywords.txt
index 7cfc76716..d6a1abe8a 100644
--- a/tests/data/lexer/0011_keywords.txt
+++ b/tests/data/lexer/0011_keywords.txt
@@ -57,4 +57,6 @@ WHITESPACE 1 " "
57ELSE_KW 4 "else" 57ELSE_KW 4 "else"
58WHITESPACE 1 " " 58WHITESPACE 1 " "
59MOVE_KW 4 "move" 59MOVE_KW 4 "move"
60WHITESPACE 1 " "
61RETURN_KW 6 "return"
60WHITESPACE 1 "\n" 62WHITESPACE 1 "\n"
diff --git a/tests/data/parser/inline/0068_return_expr.rs b/tests/data/parser/inline/0068_return_expr.rs
new file mode 100644
index 000000000..5733666b6
--- /dev/null
+++ b/tests/data/parser/inline/0068_return_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 return;
3 return 92;
4}
diff --git a/tests/data/parser/inline/0068_return_expr.txt b/tests/data/parser/inline/0068_return_expr.txt
new file mode 100644
index 000000000..61a075fc1
--- /dev/null
+++ b/tests/data/parser/inline/0068_return_expr.txt
@@ -0,0 +1,28 @@
1FILE@[0; 40)
2 FN_ITEM@[0; 40)
3 FN_KW@[0; 2)
4 NAME@[2; 6)
5 WHITESPACE@[2; 3)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 9)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 40)
12 L_CURLY@[9; 10)
13 EXPR_STMT@[10; 27)
14 RETURN_EXPR@[10; 21)
15 WHITESPACE@[10; 15)
16 RETURN_KW@[15; 21)
17 SEMI@[21; 22)
18 WHITESPACE@[22; 27)
19 EXPR_STMT@[27; 38)
20 RETURN_EXPR@[27; 36)
21 RETURN_KW@[27; 33)
22 LITERAL@[33; 36)
23 WHITESPACE@[33; 34)
24 INT_NUMBER@[34; 36) "92"
25 SEMI@[36; 37)
26 WHITESPACE@[37; 38)
27 R_CURLY@[38; 39)
28 WHITESPACE@[39; 40)