diff options
-rw-r--r-- | src/grammar.ron | 4 | ||||
-rw-r--r-- | src/grammar/expressions.rs | 44 | ||||
-rw-r--r-- | src/parser_api.rs | 23 | ||||
-rw-r--r-- | src/syntax_kinds/generated.rs | 11 | ||||
-rw-r--r-- | tests/data/lexer/0011_keywords.rs | 2 | ||||
-rw-r--r-- | tests/data/lexer/0011_keywords.txt | 2 | ||||
-rw-r--r-- | tests/data/parser/inline/0068_return_expr.rs | 4 | ||||
-rw-r--r-- | tests/data/parser/inline/0068_return_expr.txt | 28 |
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 | // } |
16 | const 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 | |||
16 | pub(super) fn literal(p: &mut Parser) -> Option<CompletedMarker> { | 20 | pub(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 | ||
29 | const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST; | ||
28 | pub(super) fn expr(p: &mut Parser) { | 30 | pub(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 | ||
85 | const PREFIX_EXPR_FIRST: TokenSet = | ||
86 | token_set_union![ | ||
87 | token_set![AMPERSAND, STAR, EXCL], | ||
88 | ATOM_EXPR_FIRST, | ||
89 | ]; | ||
83 | fn prefix_expr(p: &mut Parser) -> Option<CompletedMarker> { | 90 | fn 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 | ||
138 | const 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 | ]; | ||
131 | fn atom_expr(p: &mut Parser) -> Option<CompletedMarker> { | 143 | fn 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 | // } | ||
258 | fn 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 | ||
6 | pub(crate) struct TokenSet { | 6 | #[derive(Clone, Copy)] |
7 | pub tokens: &'static [SyntaxKind], | 7 | pub(crate) struct TokenSet(pub(crate) u128); |
8 | fn mask(kind: SyntaxKind) -> u128 { | ||
9 | 1u128 << (kind as usize) | ||
8 | } | 10 | } |
9 | 11 | ||
10 | impl TokenSet { | 12 | impl 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] |
17 | macro_rules! token_set { | 19 | macro_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] | ||
30 | macro_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 @@ | |||
1 | fn use struct trait enum impl true false as extern crate | 1 | fn use struct trait enum impl true false as extern crate |
2 | mod pub self super in where for loop while if match const | 2 | mod pub self super in where for loop while if match const |
3 | static mut type ref let else move | 3 | static 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 " " | |||
57 | ELSE_KW 4 "else" | 57 | ELSE_KW 4 "else" |
58 | WHITESPACE 1 " " | 58 | WHITESPACE 1 " " |
59 | MOVE_KW 4 "move" | 59 | MOVE_KW 4 "move" |
60 | WHITESPACE 1 " " | ||
61 | RETURN_KW 6 "return" | ||
60 | WHITESPACE 1 "\n" | 62 | WHITESPACE 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 @@ | |||
1 | fn 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 @@ | |||
1 | FILE@[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) | ||