internal: more reasonable grammar for blocks

Consider these expples

        { 92 }
  async { 92 }
    'a: { 92 }
   #[a] { 92 }

Previously the tree for them were

  BLOCK_EXPR
    { ... }

  EFFECT_EXPR
    async
    BLOCK_EXPR
      { ... }

  EFFECT_EXPR
    'a:
    BLOCK_EXPR
      { ... }

  BLOCK_EXPR
    #[a]
    { ... }

As you see, it gets progressively worse :) The last two items are
especially odd. The last one even violates the balanced curleys
invariant we have (#10357) The new approach is to say that the stuff in
`{}` is stmt_list, and the block is stmt_list + optional modifiers

  BLOCK_EXPR
    STMT_LIST
      { ... }

  BLOCK_EXPR
    async
    STMT_LIST
      { ... }

  BLOCK_EXPR
    'a:
    STMT_LIST
      { ... }

  BLOCK_EXPR
    #[a]
    STMT_LIST
      { ... }
This commit is contained in:
Aleksey Kladov 2021-09-26 12:12:57 +03:00
parent c51a3c78cf
commit 2bf81922f7
233 changed files with 11762 additions and 11343 deletions

4
Cargo.lock generated
View file

@ -1760,9 +1760,9 @@ dependencies = [
[[package]]
name = "ungrammar"
version = "1.14.4"
version = "1.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6e36d57b143472488b1594fe25c376fa9683bccfd80d858b2180c97806835b"
checksum = "395e988af2480b8a8118ad1d5f1f790197d332e3e2585231f742949b63080ef5"
[[package]]
name = "unicase"

View file

@ -698,7 +698,7 @@ impl<'db> SemanticsImpl<'db> {
ast::ForExpr(it) => it.label(),
ast::WhileExpr(it) => it.label(),
ast::LoopExpr(it) => it.label(),
ast::EffectExpr(it) => it.label(),
ast::BlockExpr(it) => it.label(),
_ => None,
}
};

View file

@ -524,7 +524,8 @@ fn inner_attributes(
},
ast::Fn(it) => {
let body = it.body()?;
(body.attrs(), ast::CommentIter::from_syntax_node(body.syntax()))
let stmt_list = body.stmt_list()?;
(stmt_list.attrs(), ast::CommentIter::from_syntax_node(body.syntax()))
},
ast::Impl(it) => {
let assoc_item_list = it.assoc_item_list()?;

View file

@ -245,21 +245,19 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
}
ast::Expr::EffectExpr(e) => match e.effect() {
ast::Effect::Try(_) => {
let body = self.collect_block_opt(e.block_expr());
ast::Expr::BlockExpr(e) => match e.modifier() {
Some(ast::BlockModifier::Try(_)) => {
let body = self.collect_block(e);
self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
}
ast::Effect::Unsafe(_) => {
let body = self.collect_block_opt(e.block_expr());
Some(ast::BlockModifier::Unsafe(_)) => {
let body = self.collect_block(e);
self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
}
// FIXME: we need to record these effects somewhere...
ast::Effect::Label(label) => {
Some(ast::BlockModifier::Label(label)) => {
let label = self.collect_label(label);
match e.block_expr() {
Some(block) => {
let res = self.collect_block(block);
let res = self.collect_block(e);
match &mut self.body.exprs[res] {
Expr::Block { label: block_label, .. } => {
*block_label = Some(label);
@ -268,20 +266,16 @@ impl ExprCollector<'_> {
}
res
}
None => self.missing_expr(),
}
}
// FIXME: we need to record these effects somewhere...
ast::Effect::Async(_) => {
let body = self.collect_block_opt(e.block_expr());
Some(ast::BlockModifier::Async(_)) => {
let body = self.collect_block(e);
self.alloc_expr(Expr::Async { body }, syntax_ptr)
}
ast::Effect::Const(_) => {
let body = self.collect_block_opt(e.block_expr());
Some(ast::BlockModifier::Const(_)) => {
let body = self.collect_block(e);
self.alloc_expr(Expr::Const { body }, syntax_ptr)
}
None => self.collect_block(e),
},
ast::Expr::BlockExpr(e) => self.collect_block(e),
ast::Expr::LoopExpr(e) => {
let label = e.label().map(|label| self.collect_label(label));
let body = self.collect_block_opt(e.loop_body());

View file

@ -721,7 +721,7 @@ impl ExpandTo {
match parent.kind() {
MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
MACRO_STMTS | EXPR_STMT | BLOCK_EXPR => ExpandTo::Statements,
MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements,
MACRO_PAT => ExpandTo::Pattern,
MACRO_TYPE => ExpandTo::Type,

View file

@ -1083,22 +1083,22 @@ fn dyn_trait_super_trait_not_in_scope() {
fn method_resolution_foreign_opaque_type() {
check_infer(
r#"
extern "C" {
extern "C" {
type S;
fn f() -> &'static S;
}
}
impl S {
impl S {
fn foo(&self) -> bool {
true
}
}
}
fn test() {
fn test() {
let s = unsafe { f() };
s.foo();
}
"#,
}
"#,
expect![[r#"
75..79 'self': &S
89..109 '{ ... }': bool
@ -1106,7 +1106,7 @@ fn method_resolution_foreign_opaque_type() {
123..167 '{ ...o(); }': ()
133..134 's': &S
137..151 'unsafe { f() }': &S
144..151 '{ f() }': &S
137..151 'unsafe { f() }': &S
146..147 'f': fn f() -> &S
146..149 'f()': &S
157..158 's': &S

View file

@ -352,7 +352,7 @@ unsafe fn baz(u: MyUnion) {
71..89 'MyUnio...o: 0 }': MyUnion
86..87 '0': u32
95..113 'unsafe...(u); }': ()
102..113 '{ baz(u); }': ()
95..113 'unsafe...(u); }': ()
104..107 'baz': fn baz(MyUnion)
104..110 'baz(u)': ()
108..109 'u': MyUnion
@ -360,7 +360,7 @@ unsafe fn baz(u: MyUnion) {
126..146 'MyUnio... 0.0 }': MyUnion
141..144 '0.0': f32
152..170 'unsafe...(u); }': ()
159..170 '{ baz(u); }': ()
152..170 'unsafe...(u); }': ()
161..164 'baz': fn baz(MyUnion)
161..167 'baz(u)': ()
165..166 'u': MyUnion
@ -1914,41 +1914,41 @@ fn fn_pointer_return() {
}
#[test]
fn effects_smoke_test() {
fn block_modifiers_smoke_test() {
check_infer(
r#"
//- minicore: future
async fn main() {
//- minicore: future
async fn main() {
let x = unsafe { 92 };
let y = async { async { () }.await };
let z = try { () };
let w = const { 92 };
let t = 'a: { 92 };
}
}
"#,
expect![[r#"
16..162 '{ ...2 }; }': ()
26..27 'x': i32
30..43 'unsafe { 92 }': i32
37..43 '{ 92 }': i32
30..43 'unsafe { 92 }': i32
39..41 '92': i32
53..54 'y': impl Future<Output = ()>
57..85 'async ...wait }': ()
57..85 'async ...wait }': impl Future<Output = ()>
63..85 '{ asyn...wait }': ()
65..77 'async { () }': ()
65..77 'async { () }': impl Future<Output = ()>
65..83 'async ....await': ()
71..77 '{ () }': ()
73..75 '()': ()
95..96 'z': {unknown}
99..109 'try { () }': ()
99..109 'try { () }': {unknown}
103..109 '{ () }': ()
105..107 '()': ()
119..120 'w': i32
123..135 'const { 92 }': i32
129..135 '{ 92 }': i32
123..135 'const { 92 }': i32
131..133 '92': i32
145..146 't': i32
153..159 '{ 92 }': i32
149..159 ''a: { 92 }': i32
155..157 '92': i32
"#]],
)
@ -2104,8 +2104,8 @@ fn infer_labelled_break_with_val() {
fn infer_labelled_block_break_with_val() {
check_infer(
r#"
fn default<T>() -> T { loop {} }
fn foo() {
fn default<T>() -> T { loop {} }
fn foo() {
let _x = 'outer: {
let inner = 'inner: {
let i = default();
@ -2119,17 +2119,17 @@ fn infer_labelled_block_break_with_val() {
};
break 'outer inner < 8;
};
}
"#,
}
"#,
expect![[r#"
21..32 '{ loop {} }': T
23..30 'loop {}': !
28..30 '{}': ()
42..381 '{ ... }; }': ()
52..54 '_x': bool
65..378 '{ ... }': bool
57..378 ''outer... }': bool
79..84 'inner': i8
95..339 '{ ... }': i8
87..339 ''inner... }': i8
113..114 'i': bool
117..124 'default': fn default<bool>() -> bool
117..126 'default()': bool
@ -2145,7 +2145,7 @@ fn infer_labelled_block_break_with_val() {
241..255 'break 'inner 6': !
254..255 '6': i8
283..313 'break ... { 0 }': !
308..313 '{ 0 }': i8
296..313 ''inner... { 0 }': i8
310..311 '0': i8
327..329 '42': i8
349..371 'break ...er < 8': !

View file

@ -164,8 +164,8 @@ fn highlight_exit_points(
match anc {
ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)),
ast::ClosureExpr(closure) => hl(sema, closure.body()),
ast::EffectExpr(effect) => if matches!(effect.effect(), ast::Effect::Async(_) | ast::Effect::Try(_)| ast::Effect::Const(_)) {
hl(sema, effect.block_expr().map(ast::Expr::BlockExpr))
ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) {
hl(sema, Some(block_expr.into()))
} else {
continue;
},
@ -180,7 +180,7 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
fn hl(
token: Option<SyntaxToken>,
label: Option<ast::Label>,
body: Option<ast::BlockExpr>,
body: Option<ast::StmtList>,
) -> Option<Vec<HighlightedRange>> {
let mut highlights = Vec::new();
let range = cover_range(
@ -204,7 +204,7 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
ast::LoopExpr(l) => l.label().and_then(|it| it.lifetime()),
ast::ForExpr(f) => f.label().and_then(|it| it.lifetime()),
ast::WhileExpr(w) => w.label().and_then(|it| it.lifetime()),
ast::EffectExpr(b) => Some(b.label().and_then(|it| it.lifetime())?),
ast::BlockExpr(b) => Some(b.label().and_then(|it| it.lifetime())?),
_ => return None,
}
};
@ -218,16 +218,16 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
for anc in token.ancestors().flat_map(ast::Expr::cast) {
return match anc {
ast::Expr::LoopExpr(l) if label_matches(l.label()) => {
hl(l.loop_token(), l.label(), l.loop_body())
hl(l.loop_token(), l.label(), l.loop_body().and_then(|it| it.stmt_list()))
}
ast::Expr::ForExpr(f) if label_matches(f.label()) => {
hl(f.for_token(), f.label(), f.loop_body())
hl(f.for_token(), f.label(), f.loop_body().and_then(|it| it.stmt_list()))
}
ast::Expr::WhileExpr(w) if label_matches(w.label()) => {
hl(w.while_token(), w.label(), w.loop_body())
hl(w.while_token(), w.label(), w.loop_body().and_then(|it| it.stmt_list()))
}
ast::Expr::EffectExpr(e) if e.label().is_some() && label_matches(e.label()) => {
hl(None, e.label(), e.block_expr())
ast::Expr::BlockExpr(e) if e.label().is_some() && label_matches(e.label()) => {
hl(None, e.label(), e.stmt_list())
}
_ => continue,
};
@ -258,7 +258,12 @@ fn highlight_yield_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
return match_ast! {
match anc {
ast::Fn(fn_) => hl(fn_.async_token(), fn_.body().map(ast::Expr::BlockExpr)),
ast::EffectExpr(effect) => hl(effect.async_token(), effect.block_expr().map(ast::Expr::BlockExpr)),
ast::BlockExpr(block_expr) => {
if block_expr.async_token().is_none() {
continue;
}
hl(block_expr.async_token(), Some(block_expr.into()))
},
ast::ClosureExpr(closure) => hl(closure.async_token(), closure.body()),
_ => continue,
}

View file

@ -86,8 +86,8 @@ pub(super) fn try_expr(
ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db),
ast::Item(__) => return None,
ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original,
ast::EffectExpr(effect) => if matches!(effect.effect(), ast::Effect::Async(_) | ast::Effect::Try(_)| ast::Effect::Const(_)) {
sema.type_of_expr(&effect.block_expr()?.into())?.original
ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) {
sema.type_of_expr(&block_expr.into())?.original
} else {
continue;
},

View file

@ -212,7 +212,7 @@ fn remove_newline(
}
fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> {
let block_expr = ast::BlockExpr::cast(token.parent()?)?;
let block_expr = ast::BlockExpr::cast(token.ancestors().nth(1)?)?;
if !block_expr.is_standalone() {
return None;
}

View file

@ -133,6 +133,7 @@ mod tests {
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..11
STMT_LIST@9..11
L_CURLY@9..10 "{"
R_CURLY@10..11 "}"
"#]],
@ -158,6 +159,7 @@ fn test() {
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..60
STMT_LIST@10..60
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
EXPR_STMT@16..58
@ -196,6 +198,7 @@ fn test() {
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..11
STMT_LIST@9..11
L_CURLY@9..10 "{"
R_CURLY@10..11 "}"
"#]],
@ -252,6 +255,7 @@ fn bar() {
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..12
STMT_LIST@9..12
L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}"
@ -280,6 +284,7 @@ fn bar() {
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..12
STMT_LIST@9..12
L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}"
@ -307,6 +312,7 @@ fn bar() {
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..12
STMT_LIST@9..12
L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}"
@ -321,6 +327,7 @@ fn bar() {
R_PAREN@20..21 ")"
WHITESPACE@21..22 " "
BLOCK_EXPR@22..25
STMT_LIST@22..25
L_CURLY@22..23 "{"
WHITESPACE@23..24 "\n"
R_CURLY@24..25 "}"

View file

@ -100,9 +100,10 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla
let action = ret_ty_to_action(func.ret_type(), rparen_pos)?;
let body = func.body()?;
let tail_expr = body.tail_expr()?;
let stmt_list = body.stmt_list()?;
let tail_expr = stmt_list.tail_expr()?;
let ret_range_end = body.l_curly_token()?.text_range().start();
let ret_range_end = stmt_list.l_curly_token()?.text_range().start();
let ret_range = TextRange::new(rparen_pos, ret_range_end);
(FnType::Function, tail_expr, ret_range, action)
};

View file

@ -68,6 +68,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
let cond_expr = cond.expr()?;
let then_block = if_expr.then_branch()?;
let then_block = then_block.stmt_list()?;
let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
@ -75,6 +76,9 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
return None;
}
// FIXME: This relies on untyped syntax tree and casts to much. It should be
// rewritten to use strongly-typed APIs.
// check for early return and continue
let first_in_then_block = then_block.syntax().first_child()?;
if ast::ReturnExpr::can_cast(first_in_then_block.kind())

View file

@ -148,24 +148,30 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
return match stmt {
ast::Stmt::Item(_) => None,
ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => Some(FunctionBody::from_range(
node.parent().and_then(ast::BlockExpr::cast)?,
node.parent().and_then(ast::StmtList::cast)?,
node.text_range(),
)),
};
}
// Covering element returned the parent block of one or multiple statements that have been selected
if let Some(stmt_list) = ast::StmtList::cast(node.clone()) {
if let Some(block_expr) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) {
if block_expr.syntax().text_range() == selection_range {
return FunctionBody::from_expr(block_expr.into());
}
}
// Extract the full statements.
return Some(FunctionBody::from_range(stmt_list, selection_range));
}
let expr = ast::Expr::cast(node.clone())?;
// A node got selected fully
if node.text_range() == selection_range {
return FunctionBody::from_expr(expr.clone());
}
// Covering element returned the parent block of one or multiple statements that have been selected
if let ast::Expr::BlockExpr(block) = expr {
// Extract the full statements.
return Some(FunctionBody::from_range(block, selection_range));
}
node.ancestors().find_map(ast::Expr::cast).and_then(FunctionBody::from_expr)
}
@ -284,7 +290,7 @@ impl RetType {
#[derive(Debug)]
enum FunctionBody {
Expr(ast::Expr),
Span { parent: ast::BlockExpr, text_range: TextRange },
Span { parent: ast::StmtList, text_range: TextRange },
}
#[derive(Debug)]
@ -441,7 +447,7 @@ impl FunctionBody {
}
}
fn from_range(parent: ast::BlockExpr, selected: TextRange) -> FunctionBody {
fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody {
let mut text_range = parent
.statements()
.map(|stmt| stmt.syntax().text_range())
@ -643,14 +649,14 @@ impl FunctionBody {
break match_ast! {
match anc {
ast::ClosureExpr(closure) => (false, closure.body(), infer_expr_opt(closure.body())),
ast::EffectExpr(effect) => {
let (constness, block) = match effect.effect() {
ast::Effect::Const(_) => (true, effect.block_expr()),
ast::Effect::Try(_) => (false, effect.block_expr()),
ast::Effect::Label(label) if label.lifetime().is_some() => (false, effect.block_expr()),
ast::BlockExpr(block_expr) => {
let (constness, block) = match block_expr.modifier() {
Some(ast::BlockModifier::Const(_)) => (true, block_expr),
Some(ast::BlockModifier::Try(_)) => (false, block_expr),
Some(ast::BlockModifier::Label(label)) if label.lifetime().is_some() => (false, block_expr),
_ => continue,
};
let expr = block.map(ast::Expr::BlockExpr);
let expr = Some(ast::Expr::BlockExpr(block));
(constness, expr.clone(), infer_expr_opt(expr))
},
ast::Fn(fn_) => {
@ -745,7 +751,7 @@ impl FunctionBody {
ast::Expr::LoopExpr(_)
| ast::Expr::ForExpr(_)
| ast::Expr::WhileExpr(_) => loop_depth -= 1,
ast::Expr::EffectExpr(effect) if effect.unsafe_token().is_some() => {
ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => {
unsafe_depth -= 1
}
_ => (),
@ -757,7 +763,7 @@ impl FunctionBody {
ast::Expr::LoopExpr(_) | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) => {
loop_depth += 1;
}
ast::Expr::EffectExpr(effect) if effect.unsafe_token().is_some() => {
ast::Expr::BlockExpr(block_expr) if block_expr.unsafe_token().is_some() => {
unsafe_depth += 1
}
ast::Expr::ReturnExpr(it) => {

View file

@ -137,6 +137,7 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
}
}
#[derive(Debug)]
enum Anchor {
Before(SyntaxNode),
Replace(ast::ExprStmt),
@ -148,7 +149,7 @@ impl Anchor {
to_extract.syntax().ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find_map(
|node| {
if let Some(expr) =
node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr())
node.parent().and_then(ast::StmtList::cast).and_then(|it| it.tail_expr())
{
if expr.syntax() == &node {
cov_mark::hit!(test_extract_var_last_expr);

View file

@ -389,12 +389,16 @@ fn inline(
_ => {
let ty =
sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
body.push_front(
make::let_stmt(pat.clone(), ty, Some(expr.clone())).clone_for_update().into(),
if let Some(stmt_list) = body.stmt_list() {
stmt_list.push_front(
make::let_stmt(pat.clone(), ty, Some(expr.clone()))
.clone_for_update()
.into(),
)
}
}
}
}
if let Some(generic_arg_list) = generic_arg_list.clone() {
PathTransform::function_call(
&sema.scope(node.syntax()),

View file

@ -93,8 +93,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
| ast::Expr::ArrayExpr(_)
| ast::Expr::ParenExpr(_)
| ast::Expr::PathExpr(_)
| ast::Expr::BlockExpr(_)
| ast::Expr::EffectExpr(_),
| ast::Expr::BlockExpr(_),
);
let parent = matches!(
usage_parent,

View file

@ -46,7 +46,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
[] => {
match_ast! {
match parent {
ast::BlockExpr(__) => {
ast::StmtList(__) => {
let range = macro_call.syntax().text_range();
let range = match whitespace_start(macro_call.syntax().prev_sibling_or_token()) {
Some(start) => range.cover_offset(start),

View file

@ -30,14 +30,14 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
let assist_label = "Unwrap block";
let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?;
let mut block = ast::BlockExpr::cast(l_curly_token.parent()?)?;
let mut block = ast::BlockExpr::cast(l_curly_token.ancestors().nth(1)?)?;
let target = block.syntax().text_range();
let mut parent = block.syntax().parent()?;
if ast::MatchArm::can_cast(parent.kind()) {
parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))?
}
if matches!(parent.kind(), SyntaxKind::BLOCK_EXPR | SyntaxKind::EXPR_STMT) {
if matches!(parent.kind(), SyntaxKind::STMT_LIST | SyntaxKind::EXPR_STMT) {
return acc.add(assist_id, assist_label, target, |builder| {
builder.replace(block.syntax().text_range(), update_expr_string(block.to_string()));
});

View file

@ -25,30 +25,34 @@ use crate::assist_context::{AssistBuilder, AssistContext};
pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
extract_trivial_expression(&block)
pub(crate) fn unwrap_trivial_block(block_expr: ast::BlockExpr) -> ast::Expr {
extract_trivial_expression(&block_expr)
.filter(|expr| !expr.syntax().text().contains_char('\n'))
.unwrap_or_else(|| block.into())
.unwrap_or_else(|| block_expr.into())
}
pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option<ast::Expr> {
if block_expr.modifier().is_some() {
return None;
}
let stmt_list = block_expr.stmt_list()?;
let has_anything_else = |thing: &SyntaxNode| -> bool {
let mut non_trivial_children =
block.syntax().children_with_tokens().filter(|it| match it.kind() {
stmt_list.syntax().children_with_tokens().filter(|it| match it.kind() {
WHITESPACE | T!['{'] | T!['}'] => false,
_ => it.as_node() != Some(thing),
});
non_trivial_children.next().is_some()
};
if let Some(expr) = block.tail_expr() {
if let Some(expr) = stmt_list.tail_expr() {
if has_anything_else(expr.syntax()) {
return None;
}
return Some(expr);
}
// Unwrap `{ continue; }`
let stmt = block.statements().next()?;
let stmt = stmt_list.statements().next()?;
if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
if has_anything_else(expr_stmt.syntax()) {
return None;

View file

@ -8,7 +8,7 @@ use ide_db::{
};
use syntax::{
ast::{self, AstNode, AstToken},
SyntaxKind::{BLOCK_EXPR, EXPR_STMT},
SyntaxKind::{EXPR_STMT, STMT_LIST},
TextRange, TextSize,
};
use text_edit::TextEdit;
@ -256,7 +256,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
.add_to(acc);
if let Some(parent) = dot_receiver.syntax().parent().and_then(|p| p.parent()) {
if matches!(parent.kind(), BLOCK_EXPR | EXPR_STMT) {
if matches!(parent.kind(), STMT_LIST | EXPR_STMT) {
postfix_snippet(
ctx,
cap,

View file

@ -326,7 +326,7 @@ impl<'a> CompletionContext<'a> {
}
pub(crate) fn has_block_expr_parent(&self) -> bool {
matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
matches!(self.completion_location, Some(ImmediateLocation::StmtList))
}
pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool {
@ -818,9 +818,9 @@ impl<'a> CompletionContext<'a> {
if let Some(stmt) = ast::ExprStmt::cast(node.clone()) {
return Some(stmt.syntax().text_range() == name_ref.syntax().text_range());
}
if let Some(block) = ast::BlockExpr::cast(node) {
if let Some(stmt_list) = ast::StmtList::cast(node) {
return Some(
block.tail_expr().map(|e| e.syntax().text_range())
stmt_list.tail_expr().map(|e| e.syntax().text_range())
== Some(name_ref.syntax().text_range()),
);
}

View file

@ -38,7 +38,7 @@ pub(crate) enum ImmediateLocation {
TupleField,
RefExpr,
IdentPat,
BlockExpr,
StmtList,
ItemList,
TypeBound,
// Fake file ast node
@ -201,7 +201,7 @@ pub(crate) fn determine_location(
ast::Use(_it) => ImmediateLocation::Use,
ast::UseTree(_it) => ImmediateLocation::UseTree,
ast::UseTreeList(_it) => ImmediateLocation::UseTree,
ast::BlockExpr(_it) => ImmediateLocation::BlockExpr,
ast::StmtList(_it) => ImmediateLocation::StmtList,
ast::SourceFile(_it) => ImmediateLocation::ItemList,
ast::ItemList(_it) => ImmediateLocation::ItemList,
ast::RefExpr(_it) => ImmediateLocation::RefExpr,
@ -421,8 +421,8 @@ mod tests {
#[test]
fn test_block_expr_loc() {
check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr);
check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::BlockExpr);
check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::StmtList);
check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::StmtList);
}
#[test]

View file

@ -139,26 +139,27 @@ impl SnippetCap {
pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
match expr {
ast::Expr::BlockExpr(b) => {
if let Some(e) = b.tail_expr() {
for_each_tail_expr(&e, cb);
}
}
ast::Expr::EffectExpr(e) => match e.effect() {
ast::Effect::Label(label) => {
for_each_break_expr(Some(label), e.block_expr(), &mut |b| {
match b.modifier() {
Some(
ast::BlockModifier::Async(_)
| ast::BlockModifier::Try(_)
| ast::BlockModifier::Const(_),
) => return cb(expr),
Some(ast::BlockModifier::Label(label)) => {
for_each_break_expr(Some(label), b.stmt_list(), &mut |b| {
cb(&ast::Expr::BreakExpr(b))
});
if let Some(b) = e.block_expr() {
for_each_tail_expr(&ast::Expr::BlockExpr(b), cb);
}
Some(ast::BlockModifier::Unsafe(_)) => (),
None => (),
}
ast::Effect::Unsafe(_) => {
if let Some(e) = e.block_expr().and_then(|b| b.tail_expr()) {
if let Some(stmt_list) = b.stmt_list() {
if let Some(e) = stmt_list.tail_expr() {
for_each_tail_expr(&e, cb);
}
}
ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_) => cb(expr),
},
}
ast::Expr::IfExpr(if_) => {
let mut if_ = if_.clone();
loop {
@ -176,7 +177,9 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
}
}
ast::Expr::LoopExpr(l) => {
for_each_break_expr(l.label(), l.loop_body(), &mut |b| cb(&ast::Expr::BreakExpr(b)))
for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| {
cb(&ast::Expr::BreakExpr(b))
})
}
ast::Expr::MatchExpr(m) => {
if let Some(arms) = m.match_arm_list() {
@ -216,7 +219,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
/// Calls `cb` on each break expr inside of `body` that is applicable for the given label.
pub fn for_each_break_expr(
label: Option<ast::Label>,
body: Option<ast::BlockExpr>,
body: Option<ast::StmtList>,
cb: &mut dyn FnMut(ast::BreakExpr),
) {
let label = label.and_then(|lbl| lbl.lifetime());
@ -236,7 +239,7 @@ pub fn for_each_break_expr(
ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
depth += 1
}
ast::Expr::EffectExpr(e) if e.label().is_some() => depth += 1,
ast::Expr::BlockExpr(e) if e.label().is_some() => depth += 1,
ast::Expr::BreakExpr(b)
if (depth == 0 && b.lifetime().is_none()) || eq_label(b.lifetime()) =>
{
@ -248,7 +251,7 @@ pub fn for_each_break_expr(
ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
depth -= 1
}
ast::Expr::EffectExpr(e) if e.label().is_some() => depth -= 1,
ast::Expr::BlockExpr(e) if e.label().is_some() => depth -= 1,
_ => (),
},
}

View file

@ -46,7 +46,7 @@ pub struct InsertUseConfig {
pub enum ImportScope {
File(ast::SourceFile),
Module(ast::ItemList),
Block(ast::BlockExpr),
Block(ast::StmtList),
}
impl ImportScope {
@ -60,15 +60,15 @@ impl ImportScope {
match syntax {
ast::Module(module) => module.item_list().map(ImportScope::Module),
ast::SourceFile(file) => Some(ImportScope::File(file)),
ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().map(ImportScope::Block)).flatten(),
ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().and_then(|it| it.stmt_list().map(ImportScope::Block))).flatten(),
ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? {
ast::Expr::BlockExpr(block) => Some(block),
_ => None,
}).flatten().map(ImportScope::Block),
}).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)),
ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? {
ast::Expr::BlockExpr(block) => Some(block),
_ => None,
}).flatten().map(ImportScope::Block),
}).flatten().and_then(|it| it.stmt_list().map(ImportScope::Block)),
_ => None,
}

View file

@ -1,8 +1,8 @@
use super::*;
use hir::PrefixKind;
use test_utils::{assert_eq_text, extract_range_or_offset, CURSOR_MARKER};
use super::*;
#[test]
fn respects_cfg_attr_fn() {
check(

View file

@ -32,8 +32,8 @@ pub fn walk_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Expr)) {
/// Preorder walk all the expression's child expressions preserving events.
/// If the callback returns true on an [`WalkEvent::Enter`], the subtree of the expression will be skipped.
/// Note that the subtree may already be skipped due to the context analysis this function does.
pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
let mut preorder = expr.syntax().preorder();
pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
let mut preorder = start.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
WalkEvent::Enter(node) => node,
@ -44,17 +44,17 @@ pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>)
continue;
}
};
match ast::Stmt::cast(node.clone()) {
// recursively walk the initializer, skipping potential const pat expressions
// let statements aren't usually nested too deeply so this is fine to recurse on
Some(ast::Stmt::LetStmt(l)) => {
if let Some(expr) = l.initializer() {
preorder_expr(&expr, cb);
}
if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) {
if Some(node.clone()) != let_stmt.initializer().map(|it| it.syntax().clone()) {
// skipping potential const pat expressions in let statements
preorder.skip_subtree();
continue;
}
}
match ast::Stmt::cast(node.clone()) {
// Don't skip subtree since we want to process the expression child next
Some(ast::Stmt::ExprStmt(_)) => (),
Some(ast::Stmt::ExprStmt(_)) | Some(ast::Stmt::LetStmt(_)) => (),
// This might be an expression
Some(ast::Stmt::Item(ast::Item::MacroCall(mcall))) => {
cb(WalkEvent::Enter(ast::Expr::MacroCall(mcall)));
@ -68,15 +68,19 @@ pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>)
preorder.skip_subtree();
} else if let Some(expr) = ast::Expr::cast(node) {
let is_different_context = match &expr {
ast::Expr::EffectExpr(effect) => {
ast::Expr::BlockExpr(block_expr) => {
matches!(
effect.effect(),
ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_)
block_expr.modifier(),
Some(
ast::BlockModifier::Async(_)
| ast::BlockModifier::Try(_)
| ast::BlockModifier::Const(_)
)
)
}
ast::Expr::ClosureExpr(_) => true,
_ => false,
};
} && expr.syntax() != start.syntax();
let skip = cb(WalkEvent::Enter(expr));
if skip || is_different_context {
preorder.skip_subtree();
@ -88,8 +92,8 @@ pub fn preorder_expr(expr: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>)
}
/// Preorder walk all the expression's child patterns.
pub fn walk_patterns_in_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
let mut preorder = expr.syntax().preorder();
pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
let mut preorder = start.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
WalkEvent::Enter(node) => node,
@ -115,15 +119,19 @@ pub fn walk_patterns_in_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
preorder.skip_subtree();
} else if let Some(expr) = ast::Expr::cast(node.clone()) {
let is_different_context = match &expr {
ast::Expr::EffectExpr(effect) => match effect.effect() {
ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_) => {
true
ast::Expr::BlockExpr(block_expr) => {
matches!(
block_expr.modifier(),
Some(
ast::BlockModifier::Async(_)
| ast::BlockModifier::Try(_)
| ast::BlockModifier::Const(_)
)
)
}
ast::Effect::Unsafe(_) | ast::Effect::Label(_) => false,
},
ast::Expr::ClosureExpr(_) => true,
_ => false,
};
} && expr.syntax() != start.syntax();
if is_different_context {
preorder.skip_subtree();
}

View file

@ -217,6 +217,7 @@ fn test_expr_order() {
L_PAREN@5..6 "("
R_PAREN@6..7 ")"
BLOCK_EXPR@7..15
STMT_LIST@7..15
L_CURLY@7..8 "{"
EXPR_STMT@8..14
BIN_EXPR@8..13
@ -1320,9 +1321,10 @@ fn test_vec() {
let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
assert_eq!(
format!("{:#?}", tree).trim(),
assert_eq_text!(
&format!("{:#?}", tree),
r#"BLOCK_EXPR@0..45
STMT_LIST@0..45
L_CURLY@0..1 "{"
LET_STMT@1..20
LET_KW@1..4 "let"
@ -1383,7 +1385,8 @@ fn test_vec() {
PATH_SEGMENT@43..44
NAME_REF@43..44
IDENT@43..44 "v"
R_CURLY@44..45 "}""#
R_CURLY@44..45 "}"
"#
);
}

View file

@ -93,8 +93,8 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
// 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
@ -111,8 +111,8 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
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
@ -120,16 +120,16 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
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
@ -138,7 +138,9 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
// 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),
@ -150,9 +152,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
}
};
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))
@ -486,16 +486,18 @@ pub(crate) fn block_expr(p: &mut Parser) {
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
@ -597,8 +599,12 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
}
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

View file

@ -187,6 +187,7 @@ pub enum SyntaxKind {
BREAK_EXPR,
LABEL,
BLOCK_EXPR,
STMT_LIST,
RETURN_EXPR,
YIELD_EXPR,
MATCH_EXPR,
@ -196,7 +197,6 @@ pub enum SyntaxKind {
RECORD_EXPR,
RECORD_EXPR_FIELD_LIST,
RECORD_EXPR_FIELD,
EFFECT_EXPR,
BOX_EXPR,
CALL_EXPR,
INDEX_EXPR,

View file

@ -29,7 +29,7 @@ rayon = "1"
expect-test = "1.1"
proc-macro2 = "1.0.8"
quote = "1.0.2"
ungrammar = "=1.14"
ungrammar = "=1.14.5"
test_utils = { path = "../test_utils" }
sourcegen = { path = "../sourcegen" }

View file

@ -18,7 +18,7 @@ use crate::{
};
pub use self::{
expr_ext::{ArrayExprKind, Effect, ElseBranch, LiteralKind},
expr_ext::{ArrayExprKind, BlockModifier, ElseBranch, LiteralKind},
generated::{nodes::*, tokens::*},
node_ext::{
AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind,

View file

@ -451,7 +451,7 @@ impl ast::RecordExprFieldList {
}
}
impl ast::BlockExpr {
impl ast::StmtList {
pub fn push_front(&self, statement: ast::Stmt) {
ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax());
}

View file

@ -25,7 +25,6 @@ impl ast::Expr {
| ast::Expr::WhileExpr(_)
| ast::Expr::BlockExpr(_)
| ast::Expr::MatchExpr(_)
| ast::Expr::EffectExpr(_)
)
}
}
@ -268,38 +267,23 @@ impl ast::Literal {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Effect {
pub enum BlockModifier {
Async(SyntaxToken),
Unsafe(SyntaxToken),
Try(SyntaxToken),
Const(SyntaxToken),
// Very much not an effect, but we stuff it into this node anyway
Label(ast::Label),
}
impl ast::EffectExpr {
pub fn effect(&self) -> Effect {
if let Some(token) = self.async_token() {
return Effect::Async(token);
}
if let Some(token) = self.unsafe_token() {
return Effect::Unsafe(token);
}
if let Some(token) = self.try_token() {
return Effect::Try(token);
}
if let Some(token) = self.const_token() {
return Effect::Const(token);
}
if let Some(label) = self.label() {
return Effect::Label(label);
}
unreachable!("ast::EffectExpr without Effect")
}
}
impl ast::BlockExpr {
pub fn modifier(&self) -> Option<BlockModifier> {
self.async_token()
.map(BlockModifier::Async)
.or_else(|| self.unsafe_token().map(BlockModifier::Unsafe))
.or_else(|| self.try_token().map(BlockModifier::Try))
.or_else(|| self.const_token().map(BlockModifier::Const))
.or_else(|| self.label().map(BlockModifier::Label))
}
/// false if the block is an intrinsic part of the syntax and can't be
/// replaced with arbitrary expression.
///
@ -312,7 +296,7 @@ impl ast::BlockExpr {
Some(it) => it,
None => return true,
};
!matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR)
!matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR)
}
}

View file

@ -477,10 +477,12 @@ pub struct BlockExpr {
}
impl ast::AttrsOwner for BlockExpr {}
impl BlockExpr {
pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
pub fn stmt_list(&self) -> Option<StmtList> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SelfParam {
@ -643,7 +645,6 @@ impl Meta {
pub struct ExprStmt {
pub(crate) syntax: SyntaxNode,
}
impl ast::AttrsOwner for ExprStmt {}
impl ExprStmt {
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
@ -753,19 +754,6 @@ impl ContinueExpr {
pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EffectExpr {
pub(crate) syntax: SyntaxNode,
}
impl ast::AttrsOwner for EffectExpr {}
impl EffectExpr {
pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) }
pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FieldExpr {
pub(crate) syntax: SyntaxNode,
}
@ -945,6 +933,17 @@ impl YieldExpr {
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StmtList {
pub(crate) syntax: SyntaxNode,
}
impl ast::AttrsOwner for StmtList {}
impl StmtList {
pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Label {
pub(crate) syntax: SyntaxNode,
}
@ -1339,7 +1338,6 @@ pub enum Expr {
CastExpr(CastExpr),
ClosureExpr(ClosureExpr),
ContinueExpr(ContinueExpr),
EffectExpr(EffectExpr),
FieldExpr(FieldExpr),
ForExpr(ForExpr),
IfExpr(IfExpr),
@ -2255,17 +2253,6 @@ impl AstNode for ContinueExpr {
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl AstNode for EffectExpr {
fn can_cast(kind: SyntaxKind) -> bool { kind == EFFECT_EXPR }
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Self { syntax })
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl AstNode for FieldExpr {
fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
fn cast(syntax: SyntaxNode) -> Option<Self> {
@ -2475,6 +2462,17 @@ impl AstNode for YieldExpr {
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl AstNode for StmtList {
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) {
Some(Self { syntax })
} else {
None
}
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl AstNode for Label {
fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
fn cast(syntax: SyntaxNode) -> Option<Self> {
@ -3073,9 +3071,6 @@ impl From<ClosureExpr> for Expr {
impl From<ContinueExpr> for Expr {
fn from(node: ContinueExpr) -> Expr { Expr::ContinueExpr(node) }
}
impl From<EffectExpr> for Expr {
fn from(node: EffectExpr) -> Expr { Expr::EffectExpr(node) }
}
impl From<FieldExpr> for Expr {
fn from(node: FieldExpr) -> Expr { Expr::FieldExpr(node) }
}
@ -3143,9 +3138,9 @@ impl AstNode for Expr {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
| CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
| IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS
| MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
| CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
| YIELD_EXPR => true,
_ => false,
@ -3163,7 +3158,6 @@ impl AstNode for Expr {
CAST_EXPR => Expr::CastExpr(CastExpr { syntax }),
CLOSURE_EXPR => Expr::ClosureExpr(ClosureExpr { syntax }),
CONTINUE_EXPR => Expr::ContinueExpr(ContinueExpr { syntax }),
EFFECT_EXPR => Expr::EffectExpr(EffectExpr { syntax }),
FIELD_EXPR => Expr::FieldExpr(FieldExpr { syntax }),
FOR_EXPR => Expr::ForExpr(ForExpr { syntax }),
IF_EXPR => Expr::IfExpr(IfExpr { syntax }),
@ -3201,7 +3195,6 @@ impl AstNode for Expr {
Expr::CastExpr(it) => &it.syntax,
Expr::ClosureExpr(it) => &it.syntax,
Expr::ContinueExpr(it) => &it.syntax,
Expr::EffectExpr(it) => &it.syntax,
Expr::FieldExpr(it) => &it.syntax,
Expr::ForExpr(it) => &it.syntax,
Expr::IfExpr(it) => &it.syntax,
@ -3660,7 +3653,6 @@ impl AstNode for DynAttrsOwner {
| CONST_PARAM
| LIFETIME_PARAM
| TYPE_PARAM
| EXPR_STMT
| LET_STMT
| ARRAY_EXPR
| AWAIT_EXPR
@ -3671,7 +3663,6 @@ impl AstNode for DynAttrsOwner {
| CAST_EXPR
| CLOSURE_EXPR
| CONTINUE_EXPR
| EFFECT_EXPR
| FIELD_EXPR
| FOR_EXPR
| IF_EXPR
@ -3690,6 +3681,7 @@ impl AstNode for DynAttrsOwner {
| TUPLE_EXPR
| WHILE_EXPR
| YIELD_EXPR
| STMT_LIST
| RECORD_EXPR_FIELD_LIST
| RECORD_EXPR_FIELD
| MATCH_ARM_LIST
@ -4222,11 +4214,6 @@ impl std::fmt::Display for ContinueExpr {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for EffectExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for FieldExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
@ -4322,6 +4309,11 @@ impl std::fmt::Display for YieldExpr {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for StmtList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl std::fmt::Display for Label {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)

View file

@ -247,6 +247,7 @@ pub fn record_field(
ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty))
}
// TODO
pub fn block_expr(
stmts: impl IntoIterator<Item = ast::Stmt>,
tail_expr: Option<ast::Expr>,

View file

@ -11,8 +11,8 @@ use rowan::{GreenNodeData, GreenTokenData};
use crate::{
ast::{
self, support, AstChildren, AstNode, AstToken, AttrsOwner, GenericParamsOwner, NameOwner,
SyntaxNode,
self, support, AstNode, AstToken, AttrsOwner, GenericParamsOwner, ModuleItemOwner,
NameOwner, SyntaxNode,
},
NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
};
@ -50,14 +50,23 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
}
}
impl ast::ModuleItemOwner for ast::StmtList {}
impl ast::BlockExpr {
pub fn items(&self) -> AstChildren<ast::Item> {
support::children(self.syntax())
// FIXME: remove all these methods, they belong to ast::StmtList
pub fn items(&self) -> impl Iterator<Item = ast::Item> {
self.stmt_list().into_iter().flat_map(|it| it.items())
}
pub fn is_empty(&self) -> bool {
self.statements().next().is_none() && self.tail_expr().is_none()
}
pub fn statements(&self) -> impl Iterator<Item = ast::Stmt> {
self.stmt_list().into_iter().flat_map(|it| it.statements())
}
pub fn tail_expr(&self) -> Option<ast::Expr> {
self.stmt_list()?.tail_expr()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]

View file

@ -295,7 +295,8 @@ fn api_walkthrough() {
// Let's get the `1 + 1` expression!
let body: ast::BlockExpr = func.body().unwrap();
let expr: ast::Expr = body.tail_expr().unwrap();
let stmt_list: ast::StmtList = body.stmt_list().unwrap();
let expr: ast::Expr = stmt_list.tail_expr().unwrap();
// Enums are used to group related ast nodes together, and can be used for
// matching. However, because there are no public fields, it's possible to
@ -331,8 +332,8 @@ fn api_walkthrough() {
assert_eq!(text.to_string(), "1 + 1");
// There's a bunch of traversal methods on `SyntaxNode`:
assert_eq!(expr_syntax.parent().as_ref(), Some(body.syntax()));
assert_eq!(body.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
assert_eq!(expr_syntax.parent().as_ref(), Some(stmt_list.syntax()));
assert_eq!(stmt_list.syntax().first_child_or_token().map(|it| it.kind()), Some(T!['{']));
assert_eq!(
expr_syntax.next_sibling_or_token().map(|it| it.kind()),
Some(SyntaxKind::WHITESPACE)

View file

@ -162,8 +162,8 @@ fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
}
if prev.kind() == T!['{'] && ast::Stmt::can_cast(new.kind()) {
if let Some(block_expr) = prev.parent().and_then(ast::BlockExpr::cast) {
let mut indent = IndentLevel::from_element(&block_expr.syntax().clone().into());
if let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast) {
let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into());
indent.0 += 1;
return Some(make::tokens::whitespace(&format!("\n{}", indent)));
}

View file

@ -149,6 +149,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
"BREAK_EXPR",
"LABEL",
"BLOCK_EXPR",
"STMT_LIST",
"RETURN_EXPR",
"YIELD_EXPR",
"MATCH_EXPR",
@ -158,7 +159,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
"RECORD_EXPR",
"RECORD_EXPR_FIELD_LIST",
"RECORD_EXPR_FIELD",
"EFFECT_EXPR",
"BOX_EXPR",
// postfix
"CALL_EXPR",

View file

@ -9,14 +9,16 @@ use crate::{
pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) {
if let Some(parent) = block.syntax().parent() {
match parent.kind() {
FN | EXPR_STMT | BLOCK_EXPR => return,
FN | EXPR_STMT | STMT_LIST => return,
_ => {}
}
}
errors.extend(block.attrs().filter(|attr| attr.kind().is_inner()).map(|attr| {
if let Some(stmt_list) = block.stmt_list() {
errors.extend(stmt_list.attrs().filter(|attr| attr.kind().is_inner()).map(|attr| {
SyntaxError::new(
"A block in this position cannot accept inner attributes",
attr.syntax().text_range(),
)
}))
}
}

View file

@ -29,6 +29,7 @@ SOURCE_FILE@0..54
R_PAREN@26..27 ")"
WHITESPACE@27..28 " "
BLOCK_EXPR@28..31
STMT_LIST@28..31
L_CURLY@28..29 "{"
WHITESPACE@29..30 "\n"
R_CURLY@30..31 "}"

View file

@ -21,6 +21,7 @@ SOURCE_FILE@0..31
L_PAREN@23..24 "("
R_PAREN@24..25 ")"
BLOCK_EXPR@25..27
STMT_LIST@25..27
L_CURLY@25..26 "{"
R_CURLY@26..27 "}"
WHITESPACE@27..29 "\n\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..95
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..12
STMT_LIST@9..12
L_CURLY@9..10 "{"
WHITESPACE@10..11 "\n"
R_CURLY@11..12 "}"
@ -33,6 +34,7 @@ SOURCE_FILE@0..95
TRUE_KW@29..33 "true"
WHITESPACE@33..34 " "
BLOCK_EXPR@34..51
STMT_LIST@34..51
L_CURLY@34..35 "{"
WHITESPACE@35..44 "\n "
LITERAL@44..45
@ -43,6 +45,7 @@ SOURCE_FILE@0..95
ELSE_KW@52..56 "else"
WHITESPACE@56..57 " "
BLOCK_EXPR@57..78
STMT_LIST@57..78
L_CURLY@57..58 "{"
WHITESPACE@58..67 "\n "
BIN_EXPR@67..72
@ -68,6 +71,7 @@ SOURCE_FILE@0..95
R_PAREN@89..90 ")"
WHITESPACE@90..91 " "
BLOCK_EXPR@91..94
STMT_LIST@91..94
L_CURLY@91..92 "{"
WHITESPACE@92..93 "\n"
R_CURLY@93..94 "}"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..42
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..41
STMT_LIST@10..41
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
EXPR_STMT@16..24
@ -25,10 +26,10 @@ SOURCE_FILE@0..42
R_PAREN@23..24 ")"
WHITESPACE@24..25 " "
EXPR_STMT@25..39
EFFECT_EXPR@25..38
BLOCK_EXPR@25..38
UNSAFE_KW@25..31 "unsafe"
WHITESPACE@31..32 " "
BLOCK_EXPR@32..38
STMT_LIST@32..38
L_CURLY@32..33 "{"
WHITESPACE@33..34 " "
TUPLE_EXPR@34..36

View file

@ -25,6 +25,7 @@ SOURCE_FILE@0..23
IDENT@18..19 "T"
WHITESPACE@19..20 " "
BLOCK_EXPR@20..22
STMT_LIST@20..22
L_CURLY@20..21 "{"
R_CURLY@21..22 "}"
WHITESPACE@22..23 "\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..56
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..55
STMT_LIST@9..55
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..38

View file

@ -20,6 +20,7 @@ SOURCE_FILE@0..47
R_PAREN@15..16 ")"
WHITESPACE@16..17 " "
BLOCK_EXPR@17..46
STMT_LIST@17..46
L_CURLY@17..18 "{"
WHITESPACE@18..23 "\n "
LET_STMT@23..36

View file

@ -33,6 +33,7 @@ SOURCE_FILE@0..183
IDENT@39..46 "ScopeId"
WHITESPACE@46..47 " "
BLOCK_EXPR@47..161
STMT_LIST@47..161
L_CURLY@47..48 "{"
WHITESPACE@48..57 "\n "
LET_STMT@57..85

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..139
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..138
STMT_LIST@9..138
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
LET_STMT@15..24
@ -61,6 +62,7 @@ SOURCE_FILE@0..139
TRUE_KW@83..87 "true"
WHITESPACE@87..88 " "
BLOCK_EXPR@88..90
STMT_LIST@88..90
L_CURLY@88..89 "{"
R_CURLY@89..90 "}"
WHITESPACE@90..95 "\n "
@ -76,6 +78,7 @@ SOURCE_FILE@0..139
TRUE_KW@109..113 "true"
WHITESPACE@113..114 " "
BLOCK_EXPR@114..116
STMT_LIST@114..116
L_CURLY@114..115 "{"
R_CURLY@115..116 "}"
WHITESPACE@116..121 "\n "
@ -86,6 +89,7 @@ SOURCE_FILE@0..139
LOOP_KW@129..133 "loop"
WHITESPACE@133..134 " "
BLOCK_EXPR@134..136
STMT_LIST@134..136
L_CURLY@134..135 "{"
R_CURLY@135..136 "}"
WHITESPACE@136..137 "\n"

View file

@ -12,6 +12,7 @@ SOURCE_FILE@0..16
R_PAREN@11..12 ")"
WHITESPACE@12..13 " "
BLOCK_EXPR@13..15
STMT_LIST@13..15
L_CURLY@13..14 "{"
R_CURLY@14..15 "}"
WHITESPACE@15..16 "\n"

View file

@ -26,6 +26,7 @@ SOURCE_FILE@0..22
R_PAREN@16..17 ")"
WHITESPACE@17..18 " "
BLOCK_EXPR@18..21
STMT_LIST@18..21
L_CURLY@18..19 "{"
WHITESPACE@19..20 "\n"
R_CURLY@20..21 "}"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..112
R_PAREN@5..6 ")"
WHITESPACE@6..7 " "
BLOCK_EXPR@7..33
STMT_LIST@7..33
L_CURLY@7..8 "{"
WHITESPACE@8..9 " "
EXPR_STMT@9..17
@ -49,6 +50,7 @@ SOURCE_FILE@0..112
R_PAREN@39..40 ")"
WHITESPACE@40..41 " "
BLOCK_EXPR@41..68
STMT_LIST@41..68
L_CURLY@41..42 "{"
WHITESPACE@42..43 " "
EXPR_STMT@43..54
@ -95,6 +97,7 @@ SOURCE_FILE@0..112
R_PAREN@74..75 ")"
WHITESPACE@75..76 " "
BLOCK_EXPR@76..111
STMT_LIST@76..111
L_CURLY@76..77 "{"
WHITESPACE@77..78 " "
EXPR_STMT@78..93

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..94
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..55
STMT_LIST@10..55
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
MACRO_CALL@16..49

View file

@ -64,6 +64,7 @@ SOURCE_FILE@0..240
R_PAREN@49..50 ")"
WHITESPACE@50..51 " "
BLOCK_EXPR@51..53
STMT_LIST@51..53
L_CURLY@51..52 "{"
R_CURLY@52..53 "}"
WHITESPACE@53..55 "\n\n"
@ -77,6 +78,7 @@ SOURCE_FILE@0..240
R_PAREN@63..64 ")"
WHITESPACE@64..65 " "
BLOCK_EXPR@65..239
STMT_LIST@65..239
L_CURLY@65..66 "{"
WHITESPACE@66..71 "\n "
LET_STMT@71..121

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..575
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..574
STMT_LIST@10..574
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
ENUM@16..152
@ -130,6 +131,7 @@ SOURCE_FILE@0..575
WHITESPACE@300..306 "\n\n "
EXPR_STMT@306..459
BLOCK_EXPR@306..459
STMT_LIST@306..459
L_CURLY@306..307 "{"
WHITESPACE@307..316 "\n "
ENUM@316..453

View file

@ -21,6 +21,7 @@ SOURCE_FILE@0..30
R_ANGLE@25..26 ">"
WHITESPACE@26..27 "\n"
BLOCK_EXPR@27..29
STMT_LIST@27..29
L_CURLY@27..28 "{"
R_CURLY@28..29 "}"
WHITESPACE@29..30 "\n"

View file

@ -20,6 +20,7 @@ SOURCE_FILE@0..24
R_PAREN@11..12 ")"
WHITESPACE@12..13 " "
BLOCK_EXPR@13..23
STMT_LIST@13..23
L_CURLY@13..14 "{"
WHITESPACE@14..19 "\n "
FIELD_EXPR@19..21

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..350
R_PAREN@9..10 ")"
WHITESPACE@10..11 " "
BLOCK_EXPR@11..349
STMT_LIST@11..349
L_CURLY@11..12 "{"
WHITESPACE@12..17 "\n "
LET_STMT@17..129
@ -21,6 +22,7 @@ SOURCE_FILE@0..350
EQ@27..28 "="
WHITESPACE@28..29 " "
BLOCK_EXPR@29..128
STMT_LIST@29..128
L_CURLY@29..30 "{"
WHITESPACE@30..39 "\n "
ATTR@39..83
@ -52,6 +54,7 @@ SOURCE_FILE@0..350
TRUE_KW@137..141 "true"
WHITESPACE@141..142 " "
BLOCK_EXPR@142..257
STMT_LIST@142..257
L_CURLY@142..143 "{"
WHITESPACE@143..152 "\n "
ATTR@152..171
@ -96,6 +99,7 @@ SOURCE_FILE@0..350
TRUE_KW@268..272 "true"
WHITESPACE@272..273 " "
BLOCK_EXPR@273..347
STMT_LIST@273..347
L_CURLY@273..274 "{"
WHITESPACE@274..283 "\n "
ATTR@283..302

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..293
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..292
STMT_LIST@9..292
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..101

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..89
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..88
STMT_LIST@9..88
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
MATCH_EXPR@15..86

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..91
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..89
STMT_LIST@10..89
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
LET_STMT@16..27

View file

@ -45,6 +45,7 @@ SOURCE_FILE@0..48
R_PAREN@43..44 ")"
WHITESPACE@44..45 " "
BLOCK_EXPR@45..47
STMT_LIST@45..47
L_CURLY@45..46 "{"
R_CURLY@46..47 "}"
WHITESPACE@47..48 "\n"

View file

@ -27,6 +27,7 @@ SOURCE_FILE@0..118
R_PAREN@27..28 ")"
WHITESPACE@28..29 " "
BLOCK_EXPR@29..31
STMT_LIST@29..31
L_CURLY@29..30 "{"
R_CURLY@30..31 "}"
WHITESPACE@31..36 "\n "
@ -43,6 +44,7 @@ SOURCE_FILE@0..118
R_PAREN@47..48 ")"
WHITESPACE@48..49 " "
BLOCK_EXPR@49..51
STMT_LIST@49..51
L_CURLY@49..50 "{"
R_CURLY@50..51 "}"
WHITESPACE@51..56 "\n "

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..33
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..32
STMT_LIST@10..32
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
EXPR_STMT@16..21

View file

@ -18,6 +18,7 @@ SOURCE_FILE@0..83
IDENT@12..15 "i32"
WHITESPACE@15..16 " "
BLOCK_EXPR@16..82
STMT_LIST@16..82
L_CURLY@16..17 "{"
WHITESPACE@17..22 "\n "
EXPR_STMT@22..80

View file

@ -9,10 +9,12 @@ SOURCE_FILE@0..83
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..82
STMT_LIST@10..82
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
EXPR_STMT@16..29
BLOCK_EXPR@16..29
STMT_LIST@16..29
L_CURLY@16..17 "{"
WHITESPACE@17..18 " "
ERROR@18..24
@ -25,6 +27,7 @@ SOURCE_FILE@0..83
WHITESPACE@29..34 "\n "
EXPR_STMT@34..46
BLOCK_EXPR@34..46
STMT_LIST@34..46
L_CURLY@34..35 "{"
WHITESPACE@35..36 " "
ERROR@36..41
@ -37,10 +40,11 @@ SOURCE_FILE@0..83
WHITESPACE@46..51 "\n "
EXPR_STMT@51..61
BLOCK_EXPR@51..61
STMT_LIST@51..61
L_CURLY@51..52 "{"
WHITESPACE@52..53 " "
EXPR_STMT@53..56
EFFECT_EXPR@53..56
BLOCK_EXPR@53..56
TRY_KW@53..56 "try"
WHITESPACE@56..57 " "
LITERAL@57..59
@ -49,6 +53,7 @@ SOURCE_FILE@0..83
R_CURLY@60..61 "}"
WHITESPACE@61..66 "\n "
BLOCK_EXPR@66..80
STMT_LIST@66..80
L_CURLY@66..67 "{"
WHITESPACE@67..68 " "
ERROR@68..75

View file

@ -244,6 +244,7 @@ SOURCE_FILE@0..239
COMMA@233..234 ","
WHITESPACE@234..235 "\n"
BLOCK_EXPR@235..238
STMT_LIST@235..238
L_CURLY@235..236 "{"
WHITESPACE@236..237 "\n"
R_CURLY@237..238 "}"

View file

@ -14,6 +14,7 @@ SOURCE_FILE@0..50
R_PAREN@20..21 ")"
WHITESPACE@21..22 " "
BLOCK_EXPR@22..24
STMT_LIST@22..24
L_CURLY@22..23 "{"
R_CURLY@23..24 "}"
WHITESPACE@24..25 "\n"

View file

@ -117,6 +117,7 @@ SOURCE_FILE@0..187
R_PAREN@118..119 ")"
WHITESPACE@119..120 " "
BLOCK_EXPR@120..186
STMT_LIST@120..186
L_CURLY@120..121 "{"
WHITESPACE@121..126 "\n "
LET_STMT@126..184

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..90
R_PAREN@5..6 ")"
WHITESPACE@6..7 " "
BLOCK_EXPR@7..40
STMT_LIST@7..40
L_CURLY@7..8 "{"
WHITESPACE@8..13 "\n "
EXPR_STMT@13..31
@ -62,6 +63,7 @@ SOURCE_FILE@0..90
R_PAREN@47..48 ")"
WHITESPACE@48..49 " "
BLOCK_EXPR@49..89
STMT_LIST@49..89
L_CURLY@49..50 "{"
WHITESPACE@50..55 "\n "
LET_STMT@55..76

View file

@ -8,5 +8,6 @@ FN@0..11
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..11
STMT_LIST@9..11
L_CURLY@9..10 "{"
R_CURLY@10..11 "}"

View file

@ -1,5 +1,6 @@
EXPR_STMT@0..55
BLOCK_EXPR@0..55
STMT_LIST@0..55
L_CURLY@0..1 "{"
WHITESPACE@1..6 "\n "
LET_STMT@6..20

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..30
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..29
STMT_LIST@10..29
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
ERROR@16..22

View file

@ -8,6 +8,7 @@ SOURCE_FILE@0..33
L_PAREN@6..7 "("
R_PAREN@7..8 ")"
BLOCK_EXPR@8..10
STMT_LIST@8..10
L_CURLY@8..9 "{"
R_CURLY@9..10 "}"
WHITESPACE@10..11 " "
@ -28,6 +29,7 @@ SOURCE_FILE@0..33
L_PAREN@28..29 "("
R_PAREN@29..30 ")"
BLOCK_EXPR@30..32
STMT_LIST@30..32
L_CURLY@30..31 "{"
R_CURLY@31..32 "}"
WHITESPACE@32..33 "\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..30
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..29
STMT_LIST@9..29
L_CURLY@9..10 "{"
WHITESPACE@10..11 " "
LET_STMT@11..27
@ -19,10 +20,10 @@ SOURCE_FILE@0..30
WHITESPACE@16..17 " "
EQ@17..18 "="
WHITESPACE@18..19 " "
EFFECT_EXPR@19..27
BLOCK_EXPR@19..27
ASYNC_KW@19..24 "async"
WHITESPACE@24..25 " "
BLOCK_EXPR@25..27
STMT_LIST@25..27
L_CURLY@25..26 "{"
R_CURLY@26..27 "}"
WHITESPACE@27..28 " "

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..21
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..20
STMT_LIST@9..20
L_CURLY@9..10 "{"
WHITESPACE@10..11 " "
ERROR@11..14

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..47
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..46
STMT_LIST@9..46
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..20

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..45
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..44
STMT_LIST@10..44
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
RECORD_EXPR@16..42

View file

@ -44,6 +44,7 @@ SOURCE_FILE@0..29
R_PAREN@24..25 ")"
WHITESPACE@25..26 " "
BLOCK_EXPR@26..28
STMT_LIST@26..28
L_CURLY@26..27 "{"
R_CURLY@27..28 "}"
WHITESPACE@28..29 "\n"

View file

@ -56,6 +56,7 @@ SOURCE_FILE@0..54
R_PAREN@48..49 ")"
WHITESPACE@49..50 "\n"
BLOCK_EXPR@50..53
STMT_LIST@50..53
L_CURLY@50..51 "{"
WHITESPACE@51..52 " "
R_CURLY@52..53 "}"

View file

@ -32,6 +32,7 @@ SOURCE_FILE@0..28
L_PAREN@23..24 "("
R_PAREN@24..25 ")"
BLOCK_EXPR@25..27
STMT_LIST@25..27
L_CURLY@25..26 "{"
R_CURLY@26..27 "}"
WHITESPACE@27..28 "\n"

View file

@ -24,6 +24,7 @@ SOURCE_FILE@0..128
R_PAREN@22..23 ")"
WHITESPACE@23..24 " "
BLOCK_EXPR@24..26
STMT_LIST@24..26
L_CURLY@24..25 "{"
R_CURLY@25..26 "}"
WHITESPACE@26..31 "\n "
@ -42,6 +43,7 @@ SOURCE_FILE@0..128
R_PAREN@42..43 ")"
WHITESPACE@43..44 " "
BLOCK_EXPR@44..46
STMT_LIST@44..46
L_CURLY@44..45 "{"
R_CURLY@45..46 "}"
WHITESPACE@46..51 "\n "
@ -63,6 +65,7 @@ SOURCE_FILE@0..128
R_PAREN@65..66 ")"
WHITESPACE@66..67 " "
BLOCK_EXPR@67..69
STMT_LIST@67..69
L_CURLY@67..68 "{"
R_CURLY@68..69 "}"
WHITESPACE@69..74 "\n "
@ -98,6 +101,7 @@ SOURCE_FILE@0..128
R_PAREN@99..100 ")"
WHITESPACE@100..101 " "
BLOCK_EXPR@101..103
STMT_LIST@101..103
L_CURLY@101..102 "{"
R_CURLY@102..103 "}"
WHITESPACE@103..108 "\n "
@ -116,6 +120,7 @@ SOURCE_FILE@0..128
R_PAREN@121..122 ")"
WHITESPACE@122..123 " "
BLOCK_EXPR@123..125
STMT_LIST@123..125
L_CURLY@123..124 "{"
R_CURLY@124..125 "}"
WHITESPACE@125..126 "\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..103
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..102
STMT_LIST@9..102
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
LET_STMT@15..33

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..26
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..25
STMT_LIST@9..25
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..23
@ -16,6 +17,7 @@ SOURCE_FILE@0..26
LOOP_KW@15..19 "loop"
WHITESPACE@19..20 " "
BLOCK_EXPR@20..22
STMT_LIST@20..22
L_CURLY@20..21 "{"
R_CURLY@21..22 "}"
SEMICOLON@22..23 ";"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..48
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..47
STMT_LIST@9..47
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..21

View file

@ -9,12 +9,14 @@ SOURCE_FILE@0..69
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..68
STMT_LIST@9..68
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
LOOP_EXPR@15..66
LOOP_KW@15..19 "loop"
WHITESPACE@19..20 " "
BLOCK_EXPR@20..66
STMT_LIST@20..66
L_CURLY@20..21 "{"
WHITESPACE@21..30 "\n "
EXPR_STMT@30..39

View file

@ -33,6 +33,7 @@ SOURCE_FILE@0..69
R_PAREN@29..30 ")"
WHITESPACE@30..31 " "
BLOCK_EXPR@31..33
STMT_LIST@31..33
L_CURLY@31..32 "{"
R_CURLY@32..33 "}"
WHITESPACE@33..38 "\n "
@ -67,6 +68,7 @@ SOURCE_FILE@0..69
R_PAREN@62..63 ")"
WHITESPACE@63..64 " "
BLOCK_EXPR@64..66
STMT_LIST@64..66
L_CURLY@64..65 "{"
R_CURLY@65..66 "}"
WHITESPACE@66..67 "\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..44
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..43
STMT_LIST@9..43
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..20

View file

@ -55,6 +55,7 @@ SOURCE_FILE@0..89
R_PAREN@61..62 ")"
WHITESPACE@62..63 " "
BLOCK_EXPR@63..65
STMT_LIST@63..65
L_CURLY@63..64 "{"
R_CURLY@64..65 "}"
WHITESPACE@65..70 "\n "
@ -72,6 +73,7 @@ SOURCE_FILE@0..89
R_PAREN@82..83 ")"
WHITESPACE@83..84 " "
BLOCK_EXPR@84..86
STMT_LIST@84..86
L_CURLY@84..85 "{"
R_CURLY@85..86 "}"
WHITESPACE@86..87 "\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..39
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..38
STMT_LIST@10..38
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
LET_STMT@16..36

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..97
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..96
STMT_LIST@9..96
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
LET_STMT@15..28

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..52
R_PAREN@8..9 ")"
WHITESPACE@9..10 " "
BLOCK_EXPR@10..51
STMT_LIST@10..51
L_CURLY@10..11 "{"
WHITESPACE@11..16 "\n "
LET_STMT@16..28

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..89
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..88
STMT_LIST@9..88
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..25

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..197
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..37
STMT_LIST@9..37
L_CURLY@9..10 "{"
WHITESPACE@10..11 " "
IF_EXPR@11..35
@ -36,6 +37,7 @@ SOURCE_FILE@0..197
IDENT@28..32 "None"
WHITESPACE@32..33 " "
BLOCK_EXPR@33..35
STMT_LIST@33..35
L_CURLY@33..34 "{"
R_CURLY@34..35 "}"
WHITESPACE@35..36 " "
@ -51,6 +53,7 @@ SOURCE_FILE@0..197
R_PAREN@45..46 ")"
WHITESPACE@46..47 " "
BLOCK_EXPR@47..196
STMT_LIST@47..196
L_CURLY@47..48 "{"
WHITESPACE@48..53 "\n "
EXPR_STMT@53..87
@ -92,6 +95,7 @@ SOURCE_FILE@0..197
IDENT@80..84 "None"
WHITESPACE@84..85 " "
BLOCK_EXPR@85..87
STMT_LIST@85..87
L_CURLY@85..86 "{"
R_CURLY@86..87 "}"
WHITESPACE@87..92 "\n "
@ -123,6 +127,7 @@ SOURCE_FILE@0..197
IDENT@111..115 "None"
WHITESPACE@115..116 " "
BLOCK_EXPR@116..118
STMT_LIST@116..118
L_CURLY@116..117 "{"
R_CURLY@117..118 "}"
WHITESPACE@118..123 "\n "
@ -165,6 +170,7 @@ SOURCE_FILE@0..197
IDENT@153..157 "None"
WHITESPACE@157..158 " "
BLOCK_EXPR@158..160
STMT_LIST@158..160
L_CURLY@158..159 "{"
R_CURLY@159..160 "}"
WHITESPACE@160..165 "\n "
@ -195,6 +201,7 @@ SOURCE_FILE@0..197
IDENT@187..191 "None"
WHITESPACE@191..192 " "
BLOCK_EXPR@192..194
STMT_LIST@192..194
L_CURLY@192..193 "{"
R_CURLY@193..194 "}"
WHITESPACE@194..195 "\n"

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..93
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..92
STMT_LIST@9..92
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
EXPR_STMT@15..29
@ -20,6 +21,7 @@ SOURCE_FILE@0..93
TRUE_KW@21..25 "true"
WHITESPACE@25..26 " "
BLOCK_EXPR@26..28
STMT_LIST@26..28
L_CURLY@26..27 "{"
R_CURLY@27..28 "}"
SEMICOLON@28..29 ";"
@ -58,6 +60,7 @@ SOURCE_FILE@0..93
R_PAREN@62..63 ")"
WHITESPACE@63..64 " "
BLOCK_EXPR@64..66
STMT_LIST@64..66
L_CURLY@64..65 "{"
R_CURLY@65..66 "}"
SEMICOLON@66..67 ";"
@ -68,6 +71,7 @@ SOURCE_FILE@0..93
WHITESPACE@77..78 " "
CONDITION@78..86
BLOCK_EXPR@78..86
STMT_LIST@78..86
L_CURLY@78..79 "{"
WHITESPACE@79..80 " "
LITERAL@80..84
@ -76,6 +80,7 @@ SOURCE_FILE@0..93
R_CURLY@85..86 "}"
WHITESPACE@86..87 " "
BLOCK_EXPR@87..89
STMT_LIST@87..89
L_CURLY@87..88 "{"
R_CURLY@88..89 "}"
SEMICOLON@89..90 ";"

View file

@ -9,12 +9,14 @@ SOURCE_FILE@0..102
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..101
STMT_LIST@9..101
L_CURLY@9..10 "{"
WHITESPACE@10..15 "\n "
LOOP_EXPR@15..99
LOOP_KW@15..19 "loop"
WHITESPACE@19..20 " "
BLOCK_EXPR@20..99
STMT_LIST@20..99
L_CURLY@20..21 "{"
WHITESPACE@21..30 "\n "
EXPR_STMT@30..36

View file

@ -42,6 +42,7 @@ SOURCE_FILE@0..71
R_PAREN@34..35 ")"
WHITESPACE@35..36 " "
BLOCK_EXPR@36..70
STMT_LIST@36..70
L_CURLY@36..37 "{"
WHITESPACE@37..38 " "
EXPR_STMT@38..68

View file

@ -9,6 +9,7 @@ SOURCE_FILE@0..21
R_PAREN@7..8 ")"
WHITESPACE@8..9 " "
BLOCK_EXPR@9..20
STMT_LIST@9..20
L_CURLY@9..10 "{"
WHITESPACE@10..11 " "
EXPR_STMT@11..18

View file

@ -12,6 +12,7 @@ SOURCE_FILE@0..71
R_PAREN@14..15 ")"
WHITESPACE@15..16 " "
BLOCK_EXPR@16..19
STMT_LIST@16..19
L_CURLY@16..17 "{"
WHITESPACE@17..18 " "
R_CURLY@18..19 "}"

Some files were not shown because too many files have changed in this diff Show more