diff options
-rw-r--r-- | src/grammar.ron | 25 | ||||
-rw-r--r-- | src/grammar/expressions.rs | 79 | ||||
-rw-r--r-- | src/syntax_kinds/generated.rs | 36 | ||||
-rw-r--r-- | tests/data/parser/inline/0074_expr_binding_power.rs | 3 | ||||
-rw-r--r-- | tests/data/parser/inline/0074_expr_binding_power.txt | 48 | ||||
-rw-r--r-- | tests/data/parser/inline/0075_try_expr.rs | 3 | ||||
-rw-r--r-- | tests/data/parser/inline/0075_try_expr.txt | 25 |
7 files changed, 184 insertions, 35 deletions
diff --git a/src/grammar.ron b/src/grammar.ron index 655ed2e40..8ce5ebc49 100644 --- a/src/grammar.ron +++ b/src/grammar.ron | |||
@@ -130,23 +130,32 @@ Grammar( | |||
130 | "STRUCT_PAT", | 130 | "STRUCT_PAT", |
131 | "TUPLE_PAT", | 131 | "TUPLE_PAT", |
132 | 132 | ||
133 | // atoms | ||
133 | "TUPLE_EXPR", | 134 | "TUPLE_EXPR", |
134 | "PATH_EXPR", | 135 | "PATH_EXPR", |
135 | "CALL_EXPR", | ||
136 | "METHOD_CALL_EXPR", | ||
137 | "FIELD_EXPR", | ||
138 | "REF_EXPR", | ||
139 | "DEREF_EXPR", | ||
140 | "NOT_EXPR", | ||
141 | "LAMBDA_EXPR", | 136 | "LAMBDA_EXPR", |
142 | "STRUCT_LIT", | ||
143 | "STRUCT_LIT_FIELD", | ||
144 | "IF_EXPR", | 137 | "IF_EXPR", |
145 | "BLOCK_EXPR", | 138 | "BLOCK_EXPR", |
146 | "RETURN_EXPR", | 139 | "RETURN_EXPR", |
147 | "MATCH_EXPR", | 140 | "MATCH_EXPR", |
148 | "MATCH_ARM", | 141 | "MATCH_ARM", |
149 | "MATCH_GUARD", | 142 | "MATCH_GUARD", |
143 | "STRUCT_LIT", | ||
144 | "STRUCT_LIT_FIELD", | ||
145 | |||
146 | // postfix | ||
147 | "CALL_EXPR", | ||
148 | "METHOD_CALL_EXPR", | ||
149 | "FIELD_EXPR", | ||
150 | "TRY_EXPR", | ||
151 | |||
152 | // unary | ||
153 | "REF_EXPR", | ||
154 | "DEREF_EXPR", | ||
155 | "NOT_EXPR", | ||
156 | |||
157 | "BIN_EXPR", | ||
158 | |||
150 | 159 | ||
151 | "EXTERN_BLOCK_EXPR", | 160 | "EXTERN_BLOCK_EXPR", |
152 | "ENUM_VARIANT", | 161 | "ENUM_VARIANT", |
diff --git a/src/grammar/expressions.rs b/src/grammar/expressions.rs index 6506892e1..ecca2a3f9 100644 --- a/src/grammar/expressions.rs +++ b/src/grammar/expressions.rs | |||
@@ -29,12 +29,55 @@ pub(super) fn literal(p: &mut Parser) -> Option<CompletedMarker> { | |||
29 | const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST; | 29 | const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST; |
30 | 30 | ||
31 | pub(super) fn expr(p: &mut Parser) { | 31 | pub(super) fn expr(p: &mut Parser) { |
32 | let mut lhs = match prefix_expr(p) { | 32 | expr_bp(p, 1) |
33 | } | ||
34 | |||
35 | fn bp_of(op: SyntaxKind) -> u8 { | ||
36 | match op { | ||
37 | EQEQ | NEQ => 1, | ||
38 | MINUS | PLUS => 2, | ||
39 | STAR | SLASH => 3, | ||
40 | _ => 0 | ||
41 | } | ||
42 | } | ||
43 | |||
44 | |||
45 | // test expr_binding_power | ||
46 | // fn foo() { | ||
47 | // 1 + 2 * 3 == 1 * 2 + 3 | ||
48 | // } | ||
49 | |||
50 | // Parses expression with binding power of at least bp. | ||
51 | fn expr_bp(p: &mut Parser, bp: u8) { | ||
52 | let mut lhs = match unary_expr(p) { | ||
33 | Some(lhs) => lhs, | 53 | Some(lhs) => lhs, |
34 | None => return, | 54 | None => return, |
35 | }; | 55 | }; |
36 | 56 | ||
37 | loop { | 57 | loop { |
58 | let op_bp = bp_of(p.current()); | ||
59 | if op_bp < bp { | ||
60 | break; | ||
61 | } | ||
62 | lhs = bin_expr(p, lhs, op_bp); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | fn unary_expr(p: &mut Parser) -> Option<CompletedMarker> { | ||
67 | let done = match p.current() { | ||
68 | AMPERSAND => ref_expr(p), | ||
69 | STAR => deref_expr(p), | ||
70 | EXCL => not_expr(p), | ||
71 | _ => { | ||
72 | let lhs = atom_expr(p)?; | ||
73 | postfix_expr(p, lhs) | ||
74 | } | ||
75 | }; | ||
76 | Some(done) | ||
77 | } | ||
78 | |||
79 | fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker { | ||
80 | loop { | ||
38 | lhs = match p.current() { | 81 | lhs = match p.current() { |
39 | L_PAREN => call_expr(p, lhs), | 82 | L_PAREN => call_expr(p, lhs), |
40 | DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN { | 83 | DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN { |
@@ -43,9 +86,11 @@ pub(super) fn expr(p: &mut Parser) { | |||
43 | field_expr(p, lhs) | 86 | field_expr(p, lhs) |
44 | }, | 87 | }, |
45 | DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs), | 88 | DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs), |
89 | QUESTION => try_expr(p, lhs), | ||
46 | _ => break, | 90 | _ => break, |
47 | } | 91 | } |
48 | } | 92 | } |
93 | lhs | ||
49 | } | 94 | } |
50 | 95 | ||
51 | // test block | 96 | // test block |
@@ -89,16 +134,6 @@ const PREFIX_EXPR_FIRST: TokenSet = | |||
89 | ATOM_EXPR_FIRST, | 134 | ATOM_EXPR_FIRST, |
90 | ]; | 135 | ]; |
91 | 136 | ||
92 | fn prefix_expr(p: &mut Parser) -> Option<CompletedMarker> { | ||
93 | let done = match p.current() { | ||
94 | AMPERSAND => ref_expr(p), | ||
95 | STAR => deref_expr(p), | ||
96 | EXCL => not_expr(p), | ||
97 | _ => return atom_expr(p), | ||
98 | }; | ||
99 | Some(done) | ||
100 | } | ||
101 | |||
102 | // test ref_expr | 137 | // test ref_expr |
103 | // fn foo() { | 138 | // fn foo() { |
104 | // let _ = &1; | 139 | // let _ = &1; |
@@ -369,6 +404,17 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
369 | m.complete(p, FIELD_EXPR) | 404 | m.complete(p, FIELD_EXPR) |
370 | } | 405 | } |
371 | 406 | ||
407 | // test try_expr | ||
408 | // fn foo() { | ||
409 | // x?; | ||
410 | // } | ||
411 | fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | ||
412 | assert!(p.at(QUESTION)); | ||
413 | let m = lhs.precede(p); | ||
414 | p.bump(); | ||
415 | m.complete(p, TRY_EXPR) | ||
416 | } | ||
417 | |||
372 | fn arg_list(p: &mut Parser) { | 418 | fn arg_list(p: &mut Parser) { |
373 | assert!(p.at(L_PAREN)); | 419 | assert!(p.at(L_PAREN)); |
374 | let m = p.start(); | 420 | let m = p.start(); |
@@ -432,3 +478,14 @@ fn struct_lit(p: &mut Parser) { | |||
432 | } | 478 | } |
433 | p.expect(R_CURLY); | 479 | p.expect(R_CURLY); |
434 | } | 480 | } |
481 | |||
482 | fn bin_expr(p: &mut Parser, lhs: CompletedMarker, bp: u8) -> CompletedMarker { | ||
483 | assert!(match p.current() { | ||
484 | MINUS | PLUS | STAR | SLASH | EQEQ | NEQ => true, | ||
485 | _ => false, | ||
486 | }); | ||
487 | let m = lhs.precede(p); | ||
488 | p.bump(); | ||
489 | expr_bp(p, bp); | ||
490 | m.complete(p, BIN_EXPR) | ||
491 | } | ||
diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs index d7a57f4d0..7bdd0267c 100644 --- a/src/syntax_kinds/generated.rs +++ b/src/syntax_kinds/generated.rs | |||
@@ -123,21 +123,23 @@ pub enum SyntaxKind { | |||
123 | TUPLE_PAT, | 123 | TUPLE_PAT, |
124 | TUPLE_EXPR, | 124 | TUPLE_EXPR, |
125 | PATH_EXPR, | 125 | PATH_EXPR, |
126 | CALL_EXPR, | ||
127 | METHOD_CALL_EXPR, | ||
128 | FIELD_EXPR, | ||
129 | REF_EXPR, | ||
130 | DEREF_EXPR, | ||
131 | NOT_EXPR, | ||
132 | LAMBDA_EXPR, | 126 | LAMBDA_EXPR, |
133 | STRUCT_LIT, | ||
134 | STRUCT_LIT_FIELD, | ||
135 | IF_EXPR, | 127 | IF_EXPR, |
136 | BLOCK_EXPR, | 128 | BLOCK_EXPR, |
137 | RETURN_EXPR, | 129 | RETURN_EXPR, |
138 | MATCH_EXPR, | 130 | MATCH_EXPR, |
139 | MATCH_ARM, | 131 | MATCH_ARM, |
140 | MATCH_GUARD, | 132 | MATCH_GUARD, |
133 | STRUCT_LIT, | ||
134 | STRUCT_LIT_FIELD, | ||
135 | CALL_EXPR, | ||
136 | METHOD_CALL_EXPR, | ||
137 | FIELD_EXPR, | ||
138 | TRY_EXPR, | ||
139 | REF_EXPR, | ||
140 | DEREF_EXPR, | ||
141 | NOT_EXPR, | ||
142 | BIN_EXPR, | ||
141 | EXTERN_BLOCK_EXPR, | 143 | EXTERN_BLOCK_EXPR, |
142 | ENUM_VARIANT, | 144 | ENUM_VARIANT, |
143 | NAMED_FIELD, | 145 | NAMED_FIELD, |
@@ -339,21 +341,23 @@ impl SyntaxKind { | |||
339 | TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" }, | 341 | TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" }, |
340 | TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" }, | 342 | TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" }, |
341 | PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" }, | 343 | PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" }, |
342 | CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" }, | ||
343 | METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" }, | ||
344 | FIELD_EXPR => &SyntaxInfo { name: "FIELD_EXPR" }, | ||
345 | REF_EXPR => &SyntaxInfo { name: "REF_EXPR" }, | ||
346 | DEREF_EXPR => &SyntaxInfo { name: "DEREF_EXPR" }, | ||
347 | NOT_EXPR => &SyntaxInfo { name: "NOT_EXPR" }, | ||
348 | LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" }, | 344 | LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" }, |
349 | STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, | ||
350 | STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" }, | ||
351 | IF_EXPR => &SyntaxInfo { name: "IF_EXPR" }, | 345 | IF_EXPR => &SyntaxInfo { name: "IF_EXPR" }, |
352 | BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" }, | 346 | BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" }, |
353 | RETURN_EXPR => &SyntaxInfo { name: "RETURN_EXPR" }, | 347 | RETURN_EXPR => &SyntaxInfo { name: "RETURN_EXPR" }, |
354 | MATCH_EXPR => &SyntaxInfo { name: "MATCH_EXPR" }, | 348 | MATCH_EXPR => &SyntaxInfo { name: "MATCH_EXPR" }, |
355 | MATCH_ARM => &SyntaxInfo { name: "MATCH_ARM" }, | 349 | MATCH_ARM => &SyntaxInfo { name: "MATCH_ARM" }, |
356 | MATCH_GUARD => &SyntaxInfo { name: "MATCH_GUARD" }, | 350 | MATCH_GUARD => &SyntaxInfo { name: "MATCH_GUARD" }, |
351 | STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" }, | ||
352 | STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" }, | ||
353 | CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" }, | ||
354 | METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" }, | ||
355 | FIELD_EXPR => &SyntaxInfo { name: "FIELD_EXPR" }, | ||
356 | TRY_EXPR => &SyntaxInfo { name: "TRY_EXPR" }, | ||
357 | REF_EXPR => &SyntaxInfo { name: "REF_EXPR" }, | ||
358 | DEREF_EXPR => &SyntaxInfo { name: "DEREF_EXPR" }, | ||
359 | NOT_EXPR => &SyntaxInfo { name: "NOT_EXPR" }, | ||
360 | BIN_EXPR => &SyntaxInfo { name: "BIN_EXPR" }, | ||
357 | EXTERN_BLOCK_EXPR => &SyntaxInfo { name: "EXTERN_BLOCK_EXPR" }, | 361 | EXTERN_BLOCK_EXPR => &SyntaxInfo { name: "EXTERN_BLOCK_EXPR" }, |
358 | ENUM_VARIANT => &SyntaxInfo { name: "ENUM_VARIANT" }, | 362 | ENUM_VARIANT => &SyntaxInfo { name: "ENUM_VARIANT" }, |
359 | NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" }, | 363 | NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" }, |
diff --git a/tests/data/parser/inline/0074_expr_binding_power.rs b/tests/data/parser/inline/0074_expr_binding_power.rs new file mode 100644 index 000000000..db855fd02 --- /dev/null +++ b/tests/data/parser/inline/0074_expr_binding_power.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | fn foo() { | ||
2 | 1 + 2 * 3 == 1 * 2 + 3 | ||
3 | } | ||
diff --git a/tests/data/parser/inline/0074_expr_binding_power.txt b/tests/data/parser/inline/0074_expr_binding_power.txt new file mode 100644 index 000000000..05aad25e9 --- /dev/null +++ b/tests/data/parser/inline/0074_expr_binding_power.txt | |||
@@ -0,0 +1,48 @@ | |||
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 | BIN_EXPR@[10; 38) | ||
14 | BIN_EXPR@[10; 25) | ||
15 | LITERAL@[10; 17) | ||
16 | WHITESPACE@[10; 15) | ||
17 | INT_NUMBER@[15; 16) "1" | ||
18 | WHITESPACE@[16; 17) | ||
19 | PLUS@[17; 18) | ||
20 | BIN_EXPR@[18; 25) | ||
21 | LITERAL@[18; 21) | ||
22 | WHITESPACE@[18; 19) | ||
23 | INT_NUMBER@[19; 20) "2" | ||
24 | WHITESPACE@[20; 21) | ||
25 | STAR@[21; 22) | ||
26 | LITERAL@[22; 25) | ||
27 | WHITESPACE@[22; 23) | ||
28 | INT_NUMBER@[23; 24) "3" | ||
29 | WHITESPACE@[24; 25) | ||
30 | EQEQ@[25; 27) | ||
31 | BIN_EXPR@[27; 38) | ||
32 | BIN_EXPR@[27; 34) | ||
33 | LITERAL@[27; 30) | ||
34 | WHITESPACE@[27; 28) | ||
35 | INT_NUMBER@[28; 29) "1" | ||
36 | WHITESPACE@[29; 30) | ||
37 | STAR@[30; 31) | ||
38 | LITERAL@[31; 34) | ||
39 | WHITESPACE@[31; 32) | ||
40 | INT_NUMBER@[32; 33) "2" | ||
41 | WHITESPACE@[33; 34) | ||
42 | PLUS@[34; 35) | ||
43 | LITERAL@[35; 38) | ||
44 | WHITESPACE@[35; 36) | ||
45 | INT_NUMBER@[36; 37) "3" | ||
46 | WHITESPACE@[37; 38) | ||
47 | R_CURLY@[38; 39) | ||
48 | WHITESPACE@[39; 40) | ||
diff --git a/tests/data/parser/inline/0075_try_expr.rs b/tests/data/parser/inline/0075_try_expr.rs new file mode 100644 index 000000000..8b74f7bc8 --- /dev/null +++ b/tests/data/parser/inline/0075_try_expr.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | fn foo() { | ||
2 | x?; | ||
3 | } | ||
diff --git a/tests/data/parser/inline/0075_try_expr.txt b/tests/data/parser/inline/0075_try_expr.txt new file mode 100644 index 000000000..49edce956 --- /dev/null +++ b/tests/data/parser/inline/0075_try_expr.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | FILE@[0; 21) | ||
2 | FN_ITEM@[0; 21) | ||
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; 21) | ||
12 | L_CURLY@[9; 10) | ||
13 | EXPR_STMT@[10; 19) | ||
14 | TRY_EXPR@[10; 17) | ||
15 | PATH_EXPR@[10; 16) | ||
16 | PATH@[10; 16) | ||
17 | PATH_SEGMENT@[10; 16) | ||
18 | NAME_REF@[10; 16) | ||
19 | WHITESPACE@[10; 15) | ||
20 | IDENT@[15; 16) "x" | ||
21 | QUESTION@[16; 17) | ||
22 | SEMI@[17; 18) | ||
23 | WHITESPACE@[18; 19) | ||
24 | R_CURLY@[19; 20) | ||
25 | WHITESPACE@[20; 21) | ||