aboutsummaryrefslogtreecommitdiff
path: root/src/grammar/expressions
diff options
context:
space:
mode:
Diffstat (limited to 'src/grammar/expressions')
-rw-r--r--src/grammar/expressions/atom.rs239
-rw-r--r--src/grammar/expressions/mod.rs255
2 files changed, 494 insertions, 0 deletions
diff --git a/src/grammar/expressions/atom.rs b/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..95c811730
--- /dev/null
+++ b/src/grammar/expressions/atom.rs
@@ -0,0 +1,239 @@
1use super::*;
2
3// test expr_literals
4// fn foo() {
5// let _ = true;
6// let _ = false;
7// let _ = 1;
8// let _ = 2.0;
9// let _ = b'a';
10// let _ = 'b';
11// let _ = "c";
12// let _ = r"d";
13// let _ = b"e";
14// let _ = br"f";
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
20pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
21 if !LITERAL_FIRST.contains(p.current()) {
22 return None;
23 }
24 let m = p.start();
25 p.bump();
26 Some(m.complete(p, LITERAL))
27}
28
29pub(super) const ATOM_EXPR_FIRST: TokenSet =
30 token_set_union![
31 LITERAL_FIRST,
32 token_set![L_PAREN, PIPE, MOVE_KW, IF_KW, MATCH_KW, UNSAFE_KW, L_CURLY, RETURN_KW,
33 IDENT, SELF_KW, SUPER_KW, COLONCOLON ],
34 ];
35
36pub(super) fn atom_expr(p: &mut Parser) -> Option<CompletedMarker> {
37 match literal(p) {
38 Some(m) => return Some(m),
39 None => (),
40 }
41 if paths::is_path_start(p) {
42 return Some(path_expr(p));
43 }
44 let la = p.nth(1);
45 let done = match p.current() {
46 L_PAREN => tuple_expr(p),
47 PIPE => lambda_expr(p),
48 MOVE_KW if la == PIPE => lambda_expr(p),
49 IF_KW => if_expr(p),
50 MATCH_KW => match_expr(p),
51 UNSAFE_KW if la == L_CURLY => block_expr(p),
52 L_CURLY => block_expr(p),
53 RETURN_KW => return_expr(p),
54 _ => {
55 p.err_and_bump("expected expression");
56 return None;
57 }
58 };
59 Some(done)
60}
61
62fn tuple_expr(p: &mut Parser) -> CompletedMarker {
63 assert!(p.at(L_PAREN));
64 let m = p.start();
65 p.expect(L_PAREN);
66 p.expect(R_PAREN);
67 m.complete(p, TUPLE_EXPR)
68}
69
70// test lambda_expr
71// fn foo() {
72// || ();
73// || -> i32 { 92 };
74// |x| x;
75// move |x: i32,| x;
76// }
77fn lambda_expr(p: &mut Parser) -> CompletedMarker {
78 assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
79 let m = p.start();
80 p.eat(MOVE_KW);
81 params::param_list_opt_types(p);
82 if fn_ret_type(p) {
83 block(p);
84 } else {
85 expr(p)
86 }
87 m.complete(p, LAMBDA_EXPR)
88}
89
90// test if_expr
91// fn foo() {
92// if true {};
93// if true {} else {};
94// if true {} else if false {} else {}
95// }
96fn if_expr(p: &mut Parser) -> CompletedMarker {
97 assert!(p.at(IF_KW));
98 let m = p.start();
99 if_head(p);
100 block(p);
101 if p.at(ELSE_KW) {
102 p.bump();
103 if p.at(IF_KW) {
104 if_expr(p);
105 } else {
106 block(p);
107 }
108 }
109 m.complete(p, IF_EXPR)
110}
111
112fn if_head(p: &mut Parser) {
113 assert!(p.at(IF_KW));
114 p.bump();
115 expr(p);
116}
117
118// test match_expr
119// fn foo() {
120// match () { };
121// }
122fn match_expr(p: &mut Parser) -> CompletedMarker {
123 assert!(p.at(MATCH_KW));
124 let m = p.start();
125 p.bump();
126 expr(p);
127 p.eat(L_CURLY);
128 while !p.at(EOF) && !p.at(R_CURLY) {
129 match_arm(p);
130 if !p.at(R_CURLY) {
131 p.expect(COMMA);
132 }
133 }
134 p.expect(R_CURLY);
135 m.complete(p, MATCH_EXPR)
136}
137
138// test match_arm
139// fn foo() {
140// match () {
141// _ => (),
142// X | Y if Z => (),
143// };
144// }
145fn match_arm(p: &mut Parser) {
146 let m = p.start();
147 loop {
148 patterns::pattern(p);
149 if !p.eat(PIPE) {
150 break;
151 }
152 }
153 if p.at(IF_KW) {
154 if_head(p)
155 }
156 p.expect(FAT_ARROW);
157 expr(p);
158 m.complete(p, MATCH_ARM);
159}
160
161// test block_expr
162// fn foo() {
163// {};
164// unsafe {};
165// }
166pub(super) fn block_expr(p: &mut Parser) -> CompletedMarker {
167 assert!(p.at(L_CURLY) || p.at(UNSAFE_KW) && p.nth(1) == L_CURLY);
168 let m = p.start();
169 p.eat(UNSAFE_KW);
170 p.bump();
171 while !p.at(EOF) && !p.at(R_CURLY) {
172 match p.current() {
173 LET_KW => let_stmt(p),
174 _ => {
175 // test block_items
176 // fn a() { fn b() {} }
177 let m = p.start();
178 match items::maybe_item(p) {
179 items::MaybeItem::Item(kind) => {
180 m.complete(p, kind);
181 }
182 items::MaybeItem::Modifiers => {
183 m.abandon(p);
184 p.error("expected an item");
185 }
186 // test pub_expr
187 // fn foo() { pub 92; } //FIXME
188 items::MaybeItem::None => {
189 expressions::expr(p);
190 if p.eat(SEMI) {
191 m.complete(p, EXPR_STMT);
192 } else {
193 m.abandon(p);
194 }
195 }
196 }
197 }
198 }
199 }
200 p.expect(R_CURLY);
201 m.complete(p, BLOCK_EXPR)
202}
203
204// test let_stmt;
205// fn foo() {
206// let a;
207// let b: i32;
208// let c = 92;
209// let d: i32 = 92;
210// }
211fn let_stmt(p: &mut Parser) {
212 assert!(p.at(LET_KW));
213 let m = p.start();
214 p.bump();
215 patterns::pattern(p);
216 if p.at(COLON) {
217 types::ascription(p);
218 }
219 if p.eat(EQ) {
220 expressions::expr(p);
221 }
222 p.expect(SEMI);
223 m.complete(p, LET_STMT);
224}
225
226// test return_expr
227// fn foo() {
228// return;
229// return 92;
230// }
231fn return_expr(p: &mut Parser) -> CompletedMarker {
232 assert!(p.at(RETURN_KW));
233 let m = p.start();
234 p.bump();
235 if EXPR_FIRST.contains(p.current()) {
236 expr(p);
237 }
238 m.complete(p, RETURN_EXPR)
239}
diff --git a/src/grammar/expressions/mod.rs b/src/grammar/expressions/mod.rs
new file mode 100644
index 000000000..f2b0c36f5
--- /dev/null
+++ b/src/grammar/expressions/mod.rs
@@ -0,0 +1,255 @@
1mod atom;
2
3use super::*;
4pub(super) use self::atom::literal;
5
6const EXPR_FIRST: TokenSet = UNARY_EXPR_FIRST;
7
8pub(super) fn expr(p: &mut Parser) {
9 expr_bp(p, 1)
10}
11
12// test block
13// fn a() {}
14// fn b() { let _ = 1; }
15// fn c() { 1; 2; }
16// fn d() { 1; 2 }
17pub(super) fn block(p: &mut Parser) {
18 if !p.at(L_CURLY) {
19 p.error("expected block");
20 return;
21 }
22 atom::block_expr(p);
23}
24
25// test expr_binding_power
26// fn foo() {
27// 1 + 2 * 3 == 1 * 2 + 3
28// }
29fn bp_of(op: SyntaxKind) -> u8 {
30 match op {
31 EQEQ | NEQ => 1,
32 MINUS | PLUS => 2,
33 STAR | SLASH => 3,
34 _ => 0
35 }
36}
37
38// Parses expression with binding power of at least bp.
39fn expr_bp(p: &mut Parser, bp: u8) {
40 let mut lhs = match unary_expr(p) {
41 Some(lhs) => lhs,
42 None => return,
43 };
44
45 loop {
46 let op_bp = bp_of(p.current());
47 if op_bp < bp {
48 break;
49 }
50 lhs = bin_expr(p, lhs, op_bp);
51 }
52}
53
54const UNARY_EXPR_FIRST: TokenSet =
55 token_set_union![
56 token_set![AMPERSAND, STAR, EXCL],
57 atom::ATOM_EXPR_FIRST,
58 ];
59
60fn unary_expr(p: &mut Parser) -> Option<CompletedMarker> {
61 let done = match p.current() {
62 AMPERSAND => ref_expr(p),
63 STAR => deref_expr(p),
64 EXCL => not_expr(p),
65 _ => {
66 let lhs = atom::atom_expr(p)?;
67 postfix_expr(p, lhs)
68 }
69 };
70 Some(done)
71}
72
73fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker {
74 loop {
75 lhs = match p.current() {
76 L_PAREN => call_expr(p, lhs),
77 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN {
78 method_call_expr(p, lhs)
79 } else {
80 field_expr(p, lhs)
81 },
82 DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
83 QUESTION => try_expr(p, lhs),
84 _ => break,
85 }
86 }
87 lhs
88}
89
90// test ref_expr
91// fn foo() {
92// let _ = &1;
93// let _ = &mut &f();
94// }
95fn ref_expr(p: &mut Parser) -> CompletedMarker {
96 assert!(p.at(AMPERSAND));
97 let m = p.start();
98 p.bump();
99 p.eat(MUT_KW);
100 expr(p);
101 m.complete(p, REF_EXPR)
102}
103
104// test deref_expr
105// fn foo() {
106// **&1;
107// }
108fn deref_expr(p: &mut Parser) -> CompletedMarker {
109 assert!(p.at(STAR));
110 let m = p.start();
111 p.bump();
112 expr(p);
113 m.complete(p, DEREF_EXPR)
114}
115
116// test not_expr
117// fn foo() {
118// !!true;
119// }
120fn not_expr(p: &mut Parser) -> CompletedMarker {
121 assert!(p.at(EXCL));
122 let m = p.start();
123 p.bump();
124 expr(p);
125 m.complete(p, NOT_EXPR)
126}
127
128// test call_expr
129// fn foo() {
130// let _ = f();
131// let _ = f()(1)(1, 2,);
132// }
133fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
134 assert!(p.at(L_PAREN));
135 let m = lhs.precede(p);
136 arg_list(p);
137 m.complete(p, CALL_EXPR)
138}
139
140// test method_call_expr
141// fn foo() {
142// x.foo();
143// y.bar(1, 2,);
144// }
145fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
146 assert!(p.at(DOT) && p.nth(1) == IDENT && p.nth(2) == L_PAREN);
147 let m = lhs.precede(p);
148 p.bump();
149 name_ref(p);
150 arg_list(p);
151 m.complete(p, METHOD_CALL_EXPR)
152}
153
154// test field_expr
155// fn foo() {
156// x.foo;
157// x.0.bar;
158// }
159fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
160 assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
161 let m = lhs.precede(p);
162 p.bump();
163 if p.at(IDENT) {
164 name_ref(p)
165 } else {
166 p.bump()
167 }
168 m.complete(p, FIELD_EXPR)
169}
170
171// test try_expr
172// fn foo() {
173// x?;
174// }
175fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
176 assert!(p.at(QUESTION));
177 let m = lhs.precede(p);
178 p.bump();
179 m.complete(p, TRY_EXPR)
180}
181
182fn arg_list(p: &mut Parser) {
183 assert!(p.at(L_PAREN));
184 let m = p.start();
185 p.bump();
186 while !p.at(R_PAREN) && !p.at(EOF) {
187 expr(p);
188 if !p.at(R_PAREN) && !p.expect(COMMA) {
189 break;
190 }
191 }
192 p.eat(R_PAREN);
193 m.complete(p, ARG_LIST);
194}
195
196// test path_expr
197// fn foo() {
198// let _ = a;
199// let _ = a::b;
200// let _ = ::a::<b>;
201// }
202fn path_expr(p: &mut Parser) -> CompletedMarker {
203 assert!(paths::is_path_start(p));
204 let m = p.start();
205 paths::expr_path(p);
206 if p.at(L_CURLY) {
207 struct_lit(p);
208 m.complete(p, STRUCT_LIT)
209 } else {
210 m.complete(p, PATH_EXPR)
211 }
212}
213
214// test struct_lit
215// fn foo() {
216// S {};
217// S { x, y: 32, };
218// S { x, y: 32, ..Default::default() };
219// }
220fn struct_lit(p: &mut Parser) {
221 assert!(p.at(L_CURLY));
222 p.bump();
223 while !p.at(EOF) && !p.at(R_CURLY) {
224 match p.current() {
225 IDENT => {
226 let m = p.start();
227 name_ref(p);
228 if p.eat(COLON) {
229 expr(p);
230 }
231 m.complete(p, STRUCT_LIT_FIELD);
232 }
233 DOTDOT => {
234 p.bump();
235 expr(p);
236 }
237 _ => p.err_and_bump("expected identifier"),
238 }
239 if !p.at(R_CURLY) {
240 p.expect(COMMA);
241 }
242 }
243 p.expect(R_CURLY);
244}
245
246fn bin_expr(p: &mut Parser, lhs: CompletedMarker, bp: u8) -> CompletedMarker {
247 assert!(match p.current() {
248 MINUS | PLUS | STAR | SLASH | EQEQ | NEQ => true,
249 _ => false,
250 });
251 let m = lhs.precede(p);
252 p.bump();
253 expr_bp(p, bp);
254 m.complete(p, BIN_EXPR)
255}