3 pub(crate) use self::atom::{block_expr, match_arm_list};
4 pub(super) use self::atom::{literal, LITERAL_FIRST};
7 pub(super) enum StmtWithSemi {
13 const EXPR_FIRST: TokenSet = LHS_FIRST;
15 pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
16 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
20 pub(super) fn expr_with_attrs(p: &mut Parser) -> bool {
22 let has_attrs = p.at(T![#]);
23 attributes::outer_attrs(p);
25 let (cm, _block_like) = expr(p);
26 let success = cm.is_some();
28 match (has_attrs, cm) {
31 cm.undo_completion(p).abandon(p);
40 pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
41 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
45 fn expr_no_struct(p: &mut Parser) {
46 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
50 fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
51 let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR);
55 pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
57 // test attr_on_expr_stmt
64 let has_attrs = p.at(T![#]);
65 attributes::outer_attrs(p);
68 let_stmt(p, m, with_semi);
73 // fn a() { fn b() {} }
74 let m = match items::maybe_item(p, m) {
79 let (cm, blocklike) = expr_stmt(p);
80 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
82 if has_attrs && !is_expr_stmt_attr_allowed(kind) {
83 // test_err attr_on_expr_not_allowed
88 p.error(format!("attributes are not allowed on {:?}", kind));
91 if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
92 // test attr_on_last_expr_in_block
97 if let Some(cm) = cm {
98 cm.undo_completion(p).abandon(p);
104 // test no_semi_after_block
113 // macro_rules! test {
120 StmtWithSemi::Yes => {
121 if blocklike.is_block() {
127 StmtWithSemi::No => {}
128 StmtWithSemi::Optional => {
135 m.complete(p, EXPR_STMT);
146 // let f = #[attr]||{};
148 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
149 assert!(p.at(T![let]));
151 patterns::pattern(p);
153 types::ascription(p);
156 expressions::expr_with_attrs(p);
160 StmtWithSemi::Yes => {
163 StmtWithSemi::No => {}
164 StmtWithSemi::Optional => {
170 m.complete(p, LET_STMT);
174 pub(super) fn expr_block_contents(p: &mut Parser) {
175 // This is checked by a validator
176 attributes::inner_attrs(p);
178 while !p.at(EOF) && !p.at(T!['}']) {
179 // test nocontentexpr
181 // ;;;some_expr();;;;{;;;};;;;Ok(())
184 // test nocontentexpr_after_item
185 // fn simple_function() {
199 stmt(p, StmtWithSemi::Yes, false)
203 #[derive(Clone, Copy)]
204 struct Restrictions {
205 forbid_structs: bool,
209 /// Binding powers of operators for a Pratt parser.
211 /// See https://www.oilshell.org/blog/2016/11/03.html
213 fn current_op(p: &Parser) -> (u8, SyntaxKind) {
214 const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]);
216 T![|] if p.at(T![||]) => (3, T![||]),
217 T![|] if p.at(T![|=]) => (1, T![|=]),
219 T![>] if p.at(T![>>=]) => (1, T![>>=]),
220 T![>] if p.at(T![>>]) => (9, T![>>]),
221 T![>] if p.at(T![>=]) => (5, T![>=]),
223 T![=] if p.at(T![=>]) => NOT_AN_OP,
224 T![=] if p.at(T![==]) => (5, T![==]),
226 T![<] if p.at(T![<=]) => (5, T![<=]),
227 T![<] if p.at(T![<<=]) => (1, T![<<=]),
228 T![<] if p.at(T![<<]) => (9, T![<<]),
230 T![+] if p.at(T![+=]) => (1, T![+=]),
231 T![+] => (10, T![+]),
232 T![^] if p.at(T![^=]) => (1, T![^=]),
234 T![%] if p.at(T![%=]) => (1, T![%=]),
235 T![%] => (11, T![%]),
236 T![&] if p.at(T![&=]) => (1, T![&=]),
237 T![&] if p.at(T![&&]) => (4, T![&&]),
239 T![/] if p.at(T![/=]) => (1, T![/=]),
240 T![/] => (11, T![/]),
241 T![*] if p.at(T![*=]) => (1, T![*=]),
242 T![*] => (11, T![*]),
243 T![.] if p.at(T![..=]) => (2, T![..=]),
244 T![.] if p.at(T![..]) => (2, T![..]),
245 T![!] if p.at(T![!=]) => (5, T![!=]),
246 T![-] if p.at(T![-=]) => (1, T![-=]),
247 T![-] => (10, T![-]),
248 T![as] => (12, T![as]),
254 // Parses expression with binding power of at least bp.
255 fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
256 let mut lhs = match lhs(p, r) {
257 Some((lhs, blocklike)) => {
258 // test stmt_bin_expr_ambiguity
263 if r.prefer_stmt && blocklike.is_block() {
264 return (Some(lhs), BlockLike::Block);
268 None => return (None, BlockLike::NotBlock),
272 let is_range = p.at(T![..]) || p.at(T![..=]);
273 let (op_bp, op) = current_op(p);
277 // test as_precedence
279 // let _ = &1 as *const i32;
282 lhs = cast_expr(p, lhs);
285 let m = lhs.precede(p);
288 // test binop_resets_statementness
292 r = Restrictions { prefer_stmt: false, ..r };
295 // test postfix_range
298 // match 1.. { _ => () };
299 // match a.b()..S { _ => () };
301 let has_trailing_expression =
302 p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
303 if !has_trailing_expression {
305 lhs = m.complete(p, RANGE_EXPR);
310 expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
311 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
313 (Some(lhs), BlockLike::NotBlock)
316 const LHS_FIRST: TokenSet =
317 atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-]]));
319 fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
321 let kind = match p.current() {
324 // // reference operator
326 // let _ = &mut &f();
329 // // raw reference operator
330 // let _ = &raw mut foo;
331 // let _ = &raw const foo;
337 && p.at_contextual_kw("raw")
338 && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const]))
340 p.bump_remap(T![raw]);
353 T![*] | T![!] | T![-] => {
359 // test full_range_expr
360 // fn foo() { xs[..]; }
361 for &op in [T![..=], T![..]].iter() {
365 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
368 return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
372 // test expression_after_block
374 // let mut p = F{x: 5};
378 let (lhs, blocklike) = atom::atom_expr(p, r)?;
379 return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
382 // parse the interior of the unary expression
384 Some((m.complete(p, kind), BlockLike::NotBlock))
389 mut lhs: CompletedMarker,
390 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
391 // E.g. `while true {break}();` is parsed as
392 // `while true {break}; ();`
393 mut block_like: BlockLike,
394 mut allow_calls: bool,
395 ) -> (CompletedMarker, BlockLike) {
397 lhs = match p.current() {
398 // test stmt_postfix_expr_ambiguity
406 T!['('] if allow_calls => call_expr(p, lhs),
407 T!['['] if allow_calls => index_expr(p, lhs),
408 T![.] => match postfix_dot_expr(p, lhs) {
415 T![?] => try_expr(p, lhs),
419 block_like = BlockLike::NotBlock;
421 return (lhs, block_like);
425 lhs: CompletedMarker,
426 ) -> Result<CompletedMarker, CompletedMarker> {
427 assert!(p.at(T![.]));
428 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
429 return Ok(method_call_expr(p, lhs));
436 // x.0().await?.hello();
438 if p.nth(1) == T![await] {
439 let m = lhs.precede(p);
442 return Ok(m.complete(p, AWAIT_EXPR));
445 if p.at(T![..=]) || p.at(T![..]) {
449 Ok(field_expr(p, lhs))
456 // let _ = f()(1)(1, 2,);
457 // let _ = f(<Foo>::func());
458 // f(<Foo as Trait>::func());
460 fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
461 assert!(p.at(T!['(']));
462 let m = lhs.precede(p);
464 m.complete(p, CALL_EXPR)
471 fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
472 assert!(p.at(T!['[']));
473 let m = lhs.precede(p);
477 m.complete(p, INDEX_EXPR)
480 // test method_call_expr
483 // y.bar::<T>(1, 2,);
485 fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
486 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
487 let m = lhs.precede(p);
490 type_args::opt_generic_arg_list(p, true);
494 m.complete(p, METHOD_CALL_EXPR)
504 // test_err bad_tuple_index_expr
510 fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
511 assert!(p.at(T![.]));
512 let m = lhs.precede(p);
514 if p.at(IDENT) || p.at(INT_NUMBER) {
516 } else if p.at(FLOAT_NUMBER) {
517 // FIXME: How to recover and instead parse INT + T![.]?
520 p.error("expected field name or number")
522 m.complete(p, FIELD_EXPR)
529 fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
530 assert!(p.at(T![?]));
531 let m = lhs.precede(p);
533 m.complete(p, TRY_EXPR)
541 // 0x36 as u8 <= 0x37;
543 fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
544 assert!(p.at(T![as]));
545 let m = lhs.precede(p);
547 // Use type_no_bounds(), because cast expressions are not
548 // allowed to have bounds.
549 types::type_no_bounds(p);
550 m.complete(p, CAST_EXPR)
553 fn arg_list(p: &mut Parser) {
554 assert!(p.at(T!['(']));
557 while !p.at(T![')']) && !p.at(EOF) {
558 // test arg_with_attr
562 if !expr_with_attrs(p) {
565 if !p.at(T![')']) && !p.expect(T![,]) {
570 m.complete(p, ARG_LIST);
578 // let _ = format!();
580 fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
581 assert!(paths::is_path_start(p));
585 T!['{'] if !r.forbid_structs => {
586 record_expr_field_list(p);
587 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
589 T![!] if !p.at(T![!=]) => {
590 let block_like = items::macro_call_after_excl(p);
591 (m.complete(p, MACRO_CALL), block_like)
593 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
601 // S { x, y: 32, ..Default::default() };
602 // TupleStruct { 0: 1 };
604 pub(crate) fn record_expr_field_list(p: &mut Parser) {
605 assert!(p.at(T!['{']));
608 while !p.at(EOF) && !p.at(T!['}']) {
610 // test record_literal_field_with_attr
612 // S { #[cfg(test)] field: 1 }
614 attributes::outer_attrs(p);
617 IDENT | INT_NUMBER => {
618 // test_err record_literal_before_ellipsis_recovery
620 // S { field ..S::default() }
622 if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
623 name_ref_or_index(p);
627 m.complete(p, RECORD_EXPR_FIELD);
629 T![.] if p.at(T![..]) => {
635 error_block(p, "expected a field");
639 p.err_and_bump("expected identifier");
648 m.complete(p, RECORD_EXPR_FIELD_LIST);