aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/grammar.ron25
-rw-r--r--src/grammar/expressions.rs79
-rw-r--r--src/syntax_kinds/generated.rs36
-rw-r--r--tests/data/parser/inline/0074_expr_binding_power.rs3
-rw-r--r--tests/data/parser/inline/0074_expr_binding_power.txt48
-rw-r--r--tests/data/parser/inline/0075_try_expr.rs3
-rw-r--r--tests/data/parser/inline/0075_try_expr.txt25
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> {
29const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST; 29const EXPR_FIRST: TokenSet = PREFIX_EXPR_FIRST;
30 30
31pub(super) fn expr(p: &mut Parser) { 31pub(super) fn expr(p: &mut Parser) {
32 let mut lhs = match prefix_expr(p) { 32 expr_bp(p, 1)
33}
34
35fn 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.
51fn 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
66fn 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
79fn 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
92fn 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// }
411fn 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
372fn arg_list(p: &mut Parser) { 418fn 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
482fn 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 @@
1fn 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 @@
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 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 @@
1fn 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 @@
1FILE@[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)