-//! FIXME: write short doc here
-
use super::*;
// test expr_literals
// let _ = b"e";
// let _ = br"f";
// }
-pub(crate) const LITERAL_FIRST: TokenSet =
- TokenSet::new(&[TRUE_KW, FALSE_KW, INT_NUMBER, FLOAT_NUMBER, BYTE, CHAR, STRING, BYTE_STRING]);
+pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[
+ T![true],
+ T![false],
+ INT_NUMBER,
+ FLOAT_NUMBER,
+ BYTE,
+ CHAR,
+ STRING,
+ BYTE_STRING,
+]);
pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
if !p.at_ts(LITERAL_FIRST) {
T!['('],
T!['{'],
T!['['],
- L_DOLLAR,
T![|],
T![move],
T![box],
T![match],
T![unsafe],
T![return],
+ T![yield],
T![break],
T![continue],
T![async],
LIFETIME_IDENT,
]));
-const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[LET_KW, R_DOLLAR]);
+const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let]]);
pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
if let Some(m) = literal(p) {
let done = match p.current() {
T!['('] => tuple_expr(p),
T!['['] => array_expr(p),
- L_DOLLAR => meta_var_expr(p),
T![|] => closure_expr(p),
- T![move] if la == T![|] => closure_expr(p),
- T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => closure_expr(p),
+ T![static] | T![async] | T![move] if la == T![|] => closure_expr(p),
+ T![static] | T![async] if la == T![move] && p.nth(2) == T![|] => closure_expr(p),
+ T![static] if la == T![async] && p.nth(2) == T![|] => closure_expr(p),
+ T![static] if la == T![async] && p.nth(2) == T![move] && p.nth(3) == T![|] => {
+ closure_expr(p)
+ }
T![if] => if_expr(p),
+ T![let] => let_expr(p),
T![loop] => loop_expr(p, None),
T![box] => box_expr(p, None),
// test labeled_block
// fn f() { 'label: {}; }
T!['{'] => {
- block_expr(p);
- m.complete(p, EFFECT_EXPR)
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
}
_ => {
// test_err misplaced_label_err
let m = p.start();
p.bump(T![async]);
p.eat(T![move]);
- block_expr(p);
- m.complete(p, EFFECT_EXPR)
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
}
T![match] => match_expr(p),
// test unsafe_block
T![unsafe] if la == T!['{'] => {
let m = p.start();
p.bump(T![unsafe]);
- block_expr(p);
- m.complete(p, EFFECT_EXPR)
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
}
// test const_block
// fn f() { const { } }
T![const] if la == T!['{'] => {
let m = p.start();
p.bump(T![const]);
- block_expr(p);
- m.complete(p, EFFECT_EXPR)
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
}
T!['{'] => {
// test for_range_from
// break;
// }
// }
- block_expr_unchecked(p)
+ let m = p.start();
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
}
T![return] => return_expr(p),
+ T![yield] => yield_expr(p),
T![continue] => continue_expr(p),
T![break] => break_expr(p, r),
_ => {
}
};
let blocklike = match done.kind() {
- IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR | EFFECT_EXPR => {
- BlockLike::Block
- }
+ IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
_ => BlockLike::NotBlock,
};
Some((done, blocklike))
// test tuple_attrs
// const A: (i64, i64) = (1, #[cfg(test)] 2);
- if !expr_with_attrs(p) {
+ if !expr(p) {
break;
}
// test array_attrs
// const A: &[i64] = &[1, #[cfg(test)] 2];
- if !expr_with_attrs(p) {
+ if !expr(p) {
break;
}
// async || {};
// move || {};
// async move || {};
+// static || {};
+// static move || {};
+// static async || {};
+// static async move || {};
// }
fn closure_expr(p: &mut Parser) -> CompletedMarker {
assert!(
|| (p.at(T![move]) && p.nth(1) == T![|])
|| (p.at(T![async]) && p.nth(1) == T![|])
|| (p.at(T![async]) && p.nth(1) == T![move] && p.nth(2) == T![|])
+ || (p.at(T![static]) && p.nth(1) == T![|])
+ || (p.at(T![static]) && p.nth(1) == T![move] && p.nth(2) == T![|])
+ || (p.at(T![static]) && p.nth(1) == T![async] && p.nth(2) == T![|])
+ || (p.at(T![static])
+ && p.nth(1) == T![async]
+ && p.nth(2) == T![move]
+ && p.nth(3) == T![|])
);
let m = p.start();
+ p.eat(T![static]);
p.eat(T![async]);
p.eat(T![move]);
params::param_list_closure(p);
// test lambda_ret_block
// fn main() { || -> i32 { 92 }(); }
block_expr(p);
+ } else if p.at_ts(EXPR_FIRST) {
+ expr(p);
} else {
- if p.at_ts(EXPR_FIRST) {
- expr(p);
- } else {
- p.error("expected expression");
- }
+ p.error("expected expression");
}
m.complete(p, CLOSURE_EXPR)
}
assert!(p.at(T![if]));
let m = p.start();
p.bump(T![if]);
- condition(p);
+ expr_no_struct(p);
block_expr(p);
if p.at(T![else]) {
p.bump(T![else]);
assert!(p.at(T![while]));
let m = m.unwrap_or_else(|| p.start());
p.bump(T![while]);
- condition(p);
+ expr_no_struct(p);
block_expr(p);
m.complete(p, WHILE_EXPR)
}
m.complete(p, FOR_EXPR)
}
-// test cond
-// fn foo() { if let Some(_) = None {} }
-// fn bar() {
-// if let Some(_) | Some(_) = None {}
-// if let | Some(_) = None {}
-// while let Some(_) | Some(_) = None {}
-// while let | Some(_) = None {}
+// test let_expr
+// fn foo() {
+// if let Some(_) = None && true {}
+// while 1 == 5 && (let None = None) {}
// }
-fn condition(p: &mut Parser) {
+fn let_expr(p: &mut Parser) -> CompletedMarker {
let m = p.start();
- if p.eat(T![let]) {
- patterns::pattern_top(p);
- p.expect(T![=]);
- }
- expr_no_struct(p);
- m.complete(p, CONDITION);
+ p.bump(T![let]);
+ patterns::pattern_top(p);
+ p.expect(T![=]);
+ expr_let(p);
+ m.complete(p, LET_EXPR)
}
// test match_expr
if p.at(T!['{']) {
match_arm_list(p);
} else {
- p.error("expected `{`")
+ p.error("expected `{`");
}
m.complete(p, MATCH_EXPR)
}
error_block(p, "expected match arm");
continue;
}
-
- // test match_arms_commas
- // fn foo() {
- // match () {
- // _ => (),
- // _ => {}
- // _ => ()
- // }
- // }
- if match_arm(p).is_block() {
- p.eat(T![,]);
- } else if !p.at(T!['}']) {
- p.expect(T![,]);
- }
+ match_arm(p);
}
p.expect(T!['}']);
m.complete(p, MATCH_ARM_LIST);
// | X => (),
// };
// }
-fn match_arm(p: &mut Parser) -> BlockLike {
+fn match_arm(p: &mut Parser) {
let m = p.start();
// test match_arms_outer_attributes
// fn foo() {
match_guard(p);
}
p.expect(T![=>]);
- let blocklike = expr_stmt(p).1;
+ let blocklike = match expr_stmt(p, None) {
+ Some((_, blocklike)) => blocklike,
+ None => BlockLike::NotBlock,
+ };
+
+ // test match_arms_commas
+ // fn foo() {
+ // match () {
+ // _ => (),
+ // _ => {}
+ // _ => ()
+ // }
+ // }
+ if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
+ p.error("expected `,`");
+ }
m.complete(p, MATCH_ARM);
- blocklike
}
// test match_guard
// fn foo() {
// match () {
// _ if foo => (),
+// _ if let foo = bar => (),
// }
// }
fn match_guard(p: &mut Parser) -> CompletedMarker {
p.error("expected a block");
return;
}
- block_expr_unchecked(p);
+ let m = p.start();
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR);
}
-fn block_expr_unchecked(p: &mut Parser) -> CompletedMarker {
+fn stmt_list(p: &mut Parser) -> CompletedMarker {
assert!(p.at(T!['{']));
let m = p.start();
p.bump(T!['{']);
expr_block_contents(p);
p.expect(T!['}']);
- m.complete(p, BLOCK_EXPR)
+ m.complete(p, STMT_LIST)
}
// test return_expr
}
m.complete(p, RETURN_EXPR)
}
+// test yield_expr
+// fn foo() {
+// yield;
+// yield 1;
+// }
+fn yield_expr(p: &mut Parser) -> CompletedMarker {
+ assert!(p.at(T![yield]));
+ let m = p.start();
+ p.bump(T![yield]);
+ if p.at_ts(EXPR_FIRST) {
+ expr(p);
+ }
+ m.complete(p, YIELD_EXPR)
+}
// test continue_expr
// fn foo() {
}
p.bump(T![try]);
- block_expr(p);
- m.complete(p, EFFECT_EXPR)
+ if p.at(T!['{']) {
+ stmt_list(p);
+ } else {
+ p.error("expected a block");
+ }
+ m.complete(p, BLOCK_EXPR)
}
// test box_expr
}
m.complete(p, BOX_EXPR)
}
-
-/// Expression from `$var` macro expansion, wrapped in dollars
-fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
- assert!(p.at(L_DOLLAR));
- let m = p.start();
- p.bump(L_DOLLAR);
- let (completed, _is_block) =
- expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
-
- match (completed, p.current()) {
- (Some(it), R_DOLLAR) => {
- p.bump(R_DOLLAR);
- m.abandon(p);
- it
- }
- _ => {
- while !p.at(R_DOLLAR) {
- p.bump_any()
- }
- p.bump(R_DOLLAR);
- m.complete(p, ERROR)
- }
- }
-}