aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/cli/Cargo.toml11
-rw-r--r--crates/cli/src/main.rs95
-rw-r--r--crates/libanalysis/Cargo.toml12
-rw-r--r--crates/libanalysis/src/lib.rs132
-rw-r--r--crates/libeditor/Cargo.toml10
-rw-r--r--crates/libeditor/src/extend_selection.rs36
-rw-r--r--crates/libeditor/src/lib.rs155
-rw-r--r--crates/libeditor/src/line_index.rs62
-rw-r--r--crates/libeditor/tests/test.rs69
-rw-r--r--crates/libsyntax2/Cargo.toml15
-rw-r--r--crates/libsyntax2/src/algo/mod.rs123
-rw-r--r--crates/libsyntax2/src/algo/search.rs136
-rw-r--r--crates/libsyntax2/src/algo/walk.rs45
-rw-r--r--crates/libsyntax2/src/ast/generated.rs54
-rw-r--r--crates/libsyntax2/src/ast/generated.rs.tera22
-rw-r--r--crates/libsyntax2/src/ast/mod.rs74
-rw-r--r--crates/libsyntax2/src/grammar.ron227
-rw-r--r--crates/libsyntax2/src/grammar/attributes.rs79
-rw-r--r--crates/libsyntax2/src/grammar/expressions/atom.rs348
-rw-r--r--crates/libsyntax2/src/grammar/expressions/mod.rs379
-rw-r--r--crates/libsyntax2/src/grammar/items/consts.rs21
-rw-r--r--crates/libsyntax2/src/grammar/items/mod.rs332
-rw-r--r--crates/libsyntax2/src/grammar/items/structs.rs116
-rw-r--r--crates/libsyntax2/src/grammar/items/traits.rs87
-rw-r--r--crates/libsyntax2/src/grammar/items/use_item.rs66
-rw-r--r--crates/libsyntax2/src/grammar/mod.rs161
-rw-r--r--crates/libsyntax2/src/grammar/params.rs116
-rw-r--r--crates/libsyntax2/src/grammar/paths.rs86
-rw-r--r--crates/libsyntax2/src/grammar/patterns.rs204
-rw-r--r--crates/libsyntax2/src/grammar/type_args.rs48
-rw-r--r--crates/libsyntax2/src/grammar/type_params.rs127
-rw-r--r--crates/libsyntax2/src/grammar/types.rs212
-rw-r--r--crates/libsyntax2/src/lexer/classes.rs26
-rw-r--r--crates/libsyntax2/src/lexer/comments.rs57
-rw-r--r--crates/libsyntax2/src/lexer/mod.rs209
-rw-r--r--crates/libsyntax2/src/lexer/numbers.rs67
-rw-r--r--crates/libsyntax2/src/lexer/ptr.rs74
-rw-r--r--crates/libsyntax2/src/lexer/strings.rs106
-rw-r--r--crates/libsyntax2/src/lib.rs55
-rw-r--r--crates/libsyntax2/src/parser_api.rs195
-rw-r--r--crates/libsyntax2/src/parser_impl/event.rs154
-rw-r--r--crates/libsyntax2/src/parser_impl/input.rs86
-rw-r--r--crates/libsyntax2/src/parser_impl/mod.rs170
-rw-r--r--crates/libsyntax2/src/smol_str.rs83
-rw-r--r--crates/libsyntax2/src/syntax_kinds/generated.rs508
-rw-r--r--crates/libsyntax2/src/syntax_kinds/generated.rs.tera73
-rw-r--r--crates/libsyntax2/src/syntax_kinds/mod.rs26
-rw-r--r--crates/libsyntax2/src/utils.rs48
-rw-r--r--crates/libsyntax2/src/yellow/builder.rs65
-rw-r--r--crates/libsyntax2/src/yellow/green.rs95
-rw-r--r--crates/libsyntax2/src/yellow/mod.rs62
-rw-r--r--crates/libsyntax2/src/yellow/red.rs94
-rw-r--r--crates/libsyntax2/src/yellow/syntax.rs122
-rw-r--r--crates/libsyntax2/tests/data/lexer/00012_block_comment.rs4
-rw-r--r--crates/libsyntax2/tests/data/lexer/00012_block_comment.txt7
-rw-r--r--crates/libsyntax2/tests/data/lexer/0001_hello.rs1
-rw-r--r--crates/libsyntax2/tests/data/lexer/0001_hello.txt3
-rw-r--r--crates/libsyntax2/tests/data/lexer/0002_whitespace.rs4
-rw-r--r--crates/libsyntax2/tests/data/lexer/0002_whitespace.txt12
-rw-r--r--crates/libsyntax2/tests/data/lexer/0003_ident.rs1
-rw-r--r--crates/libsyntax2/tests/data/lexer/0003_ident.txt14
-rw-r--r--crates/libsyntax2/tests/data/lexer/0004_numbers.rs9
-rw-r--r--crates/libsyntax2/tests/data/lexer/0004_numbers.txt67
-rw-r--r--crates/libsyntax2/tests/data/lexer/0005_symbols.rs6
-rw-r--r--crates/libsyntax2/tests/data/lexer/0005_symbols.txt68
-rw-r--r--crates/libsyntax2/tests/data/lexer/0006_chars.rs1
-rw-r--r--crates/libsyntax2/tests/data/lexer/0006_chars.txt6
-rw-r--r--crates/libsyntax2/tests/data/lexer/0007_lifetimes.rs1
-rw-r--r--crates/libsyntax2/tests/data/lexer/0007_lifetimes.txt8
-rw-r--r--crates/libsyntax2/tests/data/lexer/0008_byte_strings.rs2
-rw-r--r--crates/libsyntax2/tests/data/lexer/0008_byte_strings.txt14
-rw-r--r--crates/libsyntax2/tests/data/lexer/0009_strings.rs1
-rw-r--r--crates/libsyntax2/tests/data/lexer/0009_strings.txt4
-rw-r--r--crates/libsyntax2/tests/data/lexer/0010_comments.rs3
-rw-r--r--crates/libsyntax2/tests/data/lexer/0010_comments.txt6
-rw-r--r--crates/libsyntax2/tests/data/lexer/0011_keywords.rs3
-rw-r--r--crates/libsyntax2/tests/data/lexer/0011_keywords.txt62
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.txt33
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.txt17
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.txt7
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.txt38
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.txt20
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.rs8
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt60
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.rs7
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.txt73
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.rs9
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.txt32
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.rs13
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt67
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.txt44
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt40
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0011_extern_struct.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0011_extern_struct.txt13
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.rs12
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.txt387
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.txt18
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0002_const_fn.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0002_const_fn.txt16
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0003_extern_block.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0003_extern_block.txt8
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.txt17
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.txt10
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.txt12
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.txt15
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.txt14
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.txt17
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.txt16
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.txt21
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.txt35
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.txt20
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0015_type_item.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0015_type_item.txt16
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.txt31
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0017_paren_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0017_paren_type.txt19
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0018_unit_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0018_unit_type.txt14
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.txt20
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0020_never_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0020_never_type.txt13
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.txt17
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.txt35
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.txt27
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0024_array_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0024_array_type.txt21
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0025_slice_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0025_slice_type.txt17
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.txt50
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.txt13
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.txt55
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt23
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt22
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0031_for_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt30
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0032_path_type.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0032_path_type.txt70
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.rs8
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.txt127
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.txt49
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.txt28
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.txt53
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt33
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0039_path_expr.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt94
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.rs12
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.txt135
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.txt34
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.txt22
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0043_call_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0043_call_expr.txt70
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.txt54
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0045_block.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0045_block.txt86
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0046_default_impl.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0046_default_impl.txt15
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0047_impl_item.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0047_impl_item.txt13
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.txt22
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.txt71
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.txt62
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0052_field_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0052_field_expr.txt42
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0053_block_items.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0053_block_items.txt28
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.txt77
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0055_self_param.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0055_self_param.txt98
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0056_trait_item.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0056_trait_item.txt45
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.txt12
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0058_type_arg.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0058_type_arg.txt40
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.txt36
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.txt32
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.txt94
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.txt39
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0063_lambda_expr.txt91
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0064_param_list.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0064_param_list.txt99
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0065_if_expr.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt90
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt93
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0067_block_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0067_block_expr.txt29
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.txt25
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0068_return_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0068_return_expr.txt28
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0069_match_arm.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0069_match_arm.txt65
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0070_match_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0070_match_expr.txt42
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.txt103
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0072_path_part.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0072_path_part.txt94
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.txt122
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.txt44
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0075_try_expr.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0075_try_expr.txt25
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0076_cond.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0076_cond.txt42
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0077_while_expr.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt64
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt62
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.txt29
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.txt38
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0081_index_expr.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0081_index_expr.txt33
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.txt40
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.txt30
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.txt24
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0085_for_expr.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0085_for_expr.txt34
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.rs7
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.txt57
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0086_array_expr.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0086_array_expr.txt54
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.rs9
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt82
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs7
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt58
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt50
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.txt40
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.txt67
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.txt21
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.rs7
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.txt59
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt45
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0094_range_pat.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0094_range_pat.txt41
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt35
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.txt81
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.txt43
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0098_where_clause.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0098_where_clause.txt69
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.txt18
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0000_empty.rs0
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0000_empty.txt1
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0001_struct_item.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0001_struct_item.txt10
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.txt21
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.rs1
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.txt2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0005_fn_item.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0005_fn_item.txt15
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.rs10
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt176
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.txt25
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0008_mod_item.rs17
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt85
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0009_use_item.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0009_use_item.txt21
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.txt42
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt32
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0012_visibility.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0012_visibility.txt102
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.txt57
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0014_use_tree.rs7
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0014_use_tree.txt91
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0015_use_tree.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0015_use_tree.txt64
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.rs10
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.txt89
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt26
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.rs17
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.txt255
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0019_enums.rs25
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0019_enums.txt146
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.rs9
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.txt193
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.rs8
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.txt56
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.rs5
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.txt19
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0023_static_items.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0023_static_items.txt41
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0024_const_item.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0024_const_item.txt41
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.txt31
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.rs3
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.txt30
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.rs4
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.txt40
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.rs14
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.txt185
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0029_range_forms.rs6
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0029_range_forms.txt83
-rw-r--r--crates/libsyntax2/tests/lexer.rs28
-rw-r--r--crates/libsyntax2/tests/parser.rs14
-rw-r--r--crates/libsyntax2/tests/testutils/Cargo.toml7
-rw-r--r--crates/libsyntax2/tests/testutils/src/lib.rs111
-rw-r--r--crates/server/Cargo.toml18
-rw-r--r--crates/server/src/caps.rs36
-rw-r--r--crates/server/src/dispatch.rs174
-rw-r--r--crates/server/src/handlers.rs61
-rw-r--r--crates/server/src/io.rs202
-rw-r--r--crates/server/src/main.rs249
-rw-r--r--crates/server/src/req.rs41
-rw-r--r--crates/tools/Cargo.toml14
-rw-r--r--crates/tools/src/lib.rs43
-rw-r--r--crates/tools/src/main.rs216
372 files changed, 15286 insertions, 0 deletions
diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml
new file mode 100644
index 000000000..ac89a48d3
--- /dev/null
+++ b/crates/cli/Cargo.toml
@@ -0,0 +1,11 @@
1[package]
2name = "cli"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5publish = false
6
7[dependencies]
8clap = "2.32.0"
9failure = "0.1.1"
10libeditor = { path = "../libeditor" }
11tools = { path = "../tools" }
diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs
new file mode 100644
index 000000000..45e0a1e4f
--- /dev/null
+++ b/crates/cli/src/main.rs
@@ -0,0 +1,95 @@
1extern crate clap;
2#[macro_use]
3extern crate failure;
4extern crate libeditor;
5extern crate tools;
6
7use std::{
8 fs, io::Read, path::Path,
9 time::Instant
10};
11use clap::{App, Arg, SubCommand};
12use tools::collect_tests;
13use libeditor::{ast, syntax_tree, symbols};
14
15type Result<T> = ::std::result::Result<T, failure::Error>;
16
17fn main() -> Result<()> {
18 let matches = App::new("libsyntax2-cli")
19 .setting(clap::AppSettings::SubcommandRequiredElseHelp)
20 .subcommand(
21 SubCommand::with_name("render-test")
22 .arg(
23 Arg::with_name("line")
24 .long("--line")
25 .required(true)
26 .takes_value(true),
27 )
28 .arg(
29 Arg::with_name("file")
30 .long("--file")
31 .required(true)
32 .takes_value(true),
33 ),
34 )
35 .subcommand(
36 SubCommand::with_name("parse")
37 .arg(Arg::with_name("no-dump").long("--no-dump"))
38 )
39 .subcommand(SubCommand::with_name("symbols"))
40 .get_matches();
41 match matches.subcommand() {
42 ("parse", Some(matches)) => {
43 let start = Instant::now();
44 let file = file()?;
45 let elapsed = start.elapsed();
46 if !matches.is_present("no-dump") {
47 println!("{}", syntax_tree(&file));
48 }
49 eprintln!("parsing: {:?}", elapsed);
50 ::std::mem::forget(file);
51 }
52 ("symbols", _) => {
53 let file = file()?;
54 for s in symbols(&file) {
55 println!("{:?}", s);
56 }
57 }
58 ("render-test", Some(matches)) => {
59 let file = matches.value_of("file").unwrap();
60 let file = Path::new(file);
61 let line: usize = matches.value_of("line").unwrap().parse()?;
62 let line = line - 1;
63 let (test, tree) = render_test(file, line)?;
64 println!("{}\n{}", test, tree);
65 }
66 _ => unreachable!(),
67 }
68 Ok(())
69}
70
71fn file() -> Result<ast::File> {
72 let text = read_stdin()?;
73 Ok(ast::File::parse(&text))
74}
75
76fn read_stdin() -> Result<String> {
77 let mut buff = String::new();
78 ::std::io::stdin().read_to_string(&mut buff)?;
79 Ok(buff)
80}
81
82fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
83 let text = fs::read_to_string(file)?;
84 let tests = collect_tests(&text);
85 let test = tests.into_iter().find(|(start_line, t)| {
86 *start_line <= line && line <= *start_line + t.text.lines().count()
87 });
88 let test = match test {
89 None => bail!("No test found at line {} at {}", line, file.display()),
90 Some((_start_line, test)) => test,
91 };
92 let file = ast::File::parse(&test.text);
93 let tree = syntax_tree(&file);
94 Ok((test.text, tree))
95}
diff --git a/crates/libanalysis/Cargo.toml b/crates/libanalysis/Cargo.toml
new file mode 100644
index 000000000..c773f4211
--- /dev/null
+++ b/crates/libanalysis/Cargo.toml
@@ -0,0 +1,12 @@
1[package]
2name = "libanalysis"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5
6[dependencies]
7log = "0.4.2"
8failure = "0.1.2"
9parking_lot = "0.6.3"
10once_cell = "0.1.4"
11libsyntax2 = { path = "../libsyntax2" }
12libeditor = { path = "../libeditor" }
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
new file mode 100644
index 000000000..6a946a0b0
--- /dev/null
+++ b/crates/libanalysis/src/lib.rs
@@ -0,0 +1,132 @@
1extern crate failure;
2extern crate parking_lot;
3#[macro_use]
4extern crate log;
5extern crate once_cell;
6extern crate libsyntax2;
7extern crate libeditor;
8
9use once_cell::sync::OnceCell;
10
11use std::{
12 fs,
13 sync::Arc,
14 collections::hash_map::HashMap,
15 path::{PathBuf, Path},
16};
17use parking_lot::RwLock;
18use libsyntax2::ast;
19use libeditor::LineIndex;
20
21pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
22
23pub struct WorldState {
24 data: Arc<WorldData>
25}
26
27pub struct World {
28 data: Arc<WorldData>,
29}
30
31impl WorldState {
32 pub fn new() -> WorldState {
33 WorldState {
34 data: Arc::new(WorldData::default())
35 }
36 }
37
38 pub fn snapshot(&self) -> World {
39 World { data: self.data.clone() }
40 }
41
42 pub fn change_overlay(&mut self, path: PathBuf, text: Option<String>) {
43 let data = self.data_mut();
44 data.file_map.get_mut().remove(&path);
45 if let Some(text) = text {
46 data.mem_map.insert(path, Arc::new(text));
47 } else {
48 data.mem_map.remove(&path);
49 }
50 }
51
52 fn data_mut(&mut self) -> &mut WorldData {
53 if Arc::get_mut(&mut self.data).is_none() {
54 let file_map = self.data.file_map.read().clone();
55 self.data = Arc::new(WorldData {
56 mem_map: self.data.mem_map.clone(),
57 file_map: RwLock::new(file_map),
58 });
59 }
60 Arc::get_mut(&mut self.data).unwrap()
61 }
62}
63
64
65impl World {
66 pub fn file_syntax(&self, path: &Path) -> Result<ast::File> {
67 let data = self.file_data(path)?;
68 let syntax = data.syntax
69 .get_or_init(|| {
70 trace!("parsing: {}", path.display());
71 ast::File::parse(self.file_text(path, &data))
72 }).clone();
73 Ok(syntax)
74 }
75
76 pub fn file_line_index(&self, path: &Path) -> Result<LineIndex> {
77 let data = self.file_data(path)?;
78 let index = data.lines
79 .get_or_init(|| {
80 trace!("calc line index: {}", path.display());
81 LineIndex::new(self.file_text(path, &data))
82 });
83 Ok(index.clone())
84 }
85
86 fn file_text<'a>(&'a self, path: &Path, file_data: &'a FileData) -> &'a str {
87 match file_data.text.as_ref() {
88 Some(text) => text.as_str(),
89 None => self.data.mem_map[path].as_str()
90 }
91 }
92
93 fn file_data(&self, path: &Path) -> Result<Arc<FileData>> {
94 {
95 let guard = self.data.file_map.read();
96 if let Some(data) = guard.get(path) {
97 return Ok(data.clone());
98 }
99 }
100
101 let text = if self.data.mem_map.contains_key(path) {
102 None
103 } else {
104 trace!("loading file from disk: {}", path.display());
105 Some(fs::read_to_string(path)?)
106 };
107 let res = {
108 let mut guard = self.data.file_map.write();
109 guard.entry(path.to_owned())
110 .or_insert_with(|| Arc::new(FileData {
111 text,
112 syntax: OnceCell::new(),
113 lines: OnceCell::new(),
114 }))
115 .clone()
116 };
117 Ok(res)
118 }
119}
120
121
122#[derive(Default)]
123struct WorldData {
124 mem_map: HashMap<PathBuf, Arc<String>>,
125 file_map: RwLock<HashMap<PathBuf, Arc<FileData>>>,
126}
127
128struct FileData {
129 text: Option<String>,
130 syntax: OnceCell<ast::File>,
131 lines: OnceCell<LineIndex>,
132}
diff --git a/crates/libeditor/Cargo.toml b/crates/libeditor/Cargo.toml
new file mode 100644
index 000000000..d6423979b
--- /dev/null
+++ b/crates/libeditor/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2name = "libeditor"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5publish = false
6
7[dependencies]
8itertools = "0.7.8"
9superslice = "0.1.0"
10libsyntax2 = { path = "../libsyntax2" }
diff --git a/crates/libeditor/src/extend_selection.rs b/crates/libeditor/src/extend_selection.rs
new file mode 100644
index 000000000..16d4bc084
--- /dev/null
+++ b/crates/libeditor/src/extend_selection.rs
@@ -0,0 +1,36 @@
1use libsyntax2::{
2 TextRange, SyntaxNodeRef,
3 SyntaxKind::WHITESPACE,
4 algo::{find_leaf_at_offset, find_covering_node, ancestors},
5};
6
7
8pub(crate) fn extend_selection(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> {
9 if range.is_empty() {
10 let offset = range.start();
11 let mut leaves = find_leaf_at_offset(root, offset);
12 if let Some(leaf) = leaves.clone().find(|node| node.kind() != WHITESPACE) {
13 return Some(leaf.range());
14 }
15 let ws = leaves.next()?;
16// let ws_suffix = file.text().slice(
17// TextRange::from_to(offset, ws.range().end())
18// );
19// if ws.text().contains("\n") && !ws_suffix.contains("\n") {
20// if let Some(line_end) = file.text()
21// .slice(TextSuffix::from(ws.range().end()))
22// .find("\n")
23// {
24// let range = TextRange::from_len(ws.range().end(), line_end);
25// return Some(find_covering_node(file.root(), range).range());
26// }
27// }
28 return Some(ws.range());
29 };
30 let node = find_covering_node(root, range);
31
32 match ancestors(node).skip_while(|n| n.range() == range).next() {
33 None => None,
34 Some(parent) => Some(parent.range()),
35 }
36}
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs
new file mode 100644
index 000000000..f77647338
--- /dev/null
+++ b/crates/libeditor/src/lib.rs
@@ -0,0 +1,155 @@
1extern crate libsyntax2;
2extern crate superslice;
3
4mod extend_selection;
5mod line_index;
6
7use libsyntax2::{
8 SyntaxNodeRef, AstNode,
9 algo::walk,
10 SyntaxKind::*,
11};
12pub use libsyntax2::{TextRange, TextUnit, ast};
13pub use self::line_index::{LineIndex, LineCol};
14
15#[derive(Debug)]
16pub struct HighlightedRange {
17 pub range: TextRange,
18 pub tag: &'static str,
19}
20
21#[derive(Debug)]
22pub struct Diagnostic {
23 pub range: TextRange,
24 pub msg: String,
25}
26
27#[derive(Debug)]
28pub struct Symbol {
29 // pub parent: ???,
30 pub name: String,
31 pub range: TextRange,
32}
33
34#[derive(Debug)]
35pub struct Runnable {
36 pub range: TextRange,
37 pub kind: RunnableKind,
38}
39
40#[derive(Debug)]
41pub enum RunnableKind {
42 Test { name: String },
43 Bin,
44}
45
46pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> {
47 let syntax = file.syntax();
48 let mut res = Vec::new();
49 for node in walk::preorder(syntax.as_ref()) {
50 let tag = match node.kind() {
51 ERROR => "error",
52 COMMENT | DOC_COMMENT => "comment",
53 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
54 ATTR => "attribute",
55 NAME_REF => "text",
56 NAME => "function",
57 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
58 LIFETIME => "parameter",
59 k if k.is_keyword() => "keyword",
60 _ => continue,
61 };
62 res.push(HighlightedRange {
63 range: node.range(),
64 tag,
65 })
66 }
67 res
68}
69
70pub fn diagnostics(file: &ast::File) -> Vec<Diagnostic> {
71 let syntax = file.syntax();
72 let mut res = Vec::new();
73
74 for node in walk::preorder(syntax.as_ref()) {
75 if node.kind() == ERROR {
76 res.push(Diagnostic {
77 range: node.range(),
78 msg: "Syntax Error".to_string(),
79 });
80 }
81 }
82 res.extend(file.errors().into_iter().map(|err| Diagnostic {
83 range: TextRange::offset_len(err.offset, 1.into()),
84 msg: err.msg,
85 }));
86 res
87}
88
89pub fn syntax_tree(file: &ast::File) -> String {
90 ::libsyntax2::utils::dump_tree(&file.syntax())
91}
92
93pub fn symbols(file: &ast::File) -> Vec<Symbol> {
94 let syntax = file.syntax();
95 let res: Vec<Symbol> = walk::preorder(syntax.as_ref())
96 .filter_map(Declaration::cast)
97 .filter_map(|decl| {
98 let name = decl.name()?;
99 let range = decl.range();
100 Some(Symbol { name, range })
101 })
102 .collect();
103 res // NLL :-(
104}
105
106pub fn extend_selection(file: &ast::File, range: TextRange) -> Option<TextRange> {
107 let syntax = file.syntax();
108 extend_selection::extend_selection(syntax.as_ref(), range)
109}
110
111pub fn runnables(file: &ast::File) -> Vec<Runnable> {
112 file
113 .functions()
114 .filter_map(|f| {
115 let name = f.name()?.text();
116 let kind = if name == "main" {
117 RunnableKind::Bin
118 } else if f.has_atom_attr("test") {
119 RunnableKind::Test {
120 name: name.to_string()
121 }
122 } else {
123 return None;
124 };
125 Some(Runnable {
126 range: f.syntax().range(),
127 kind,
128 })
129 })
130 .collect()
131}
132
133
134struct Declaration<'f> (SyntaxNodeRef<'f>);
135
136impl<'f> Declaration<'f> {
137 fn cast(node: SyntaxNodeRef<'f>) -> Option<Declaration<'f>> {
138 match node.kind() {
139 | STRUCT_ITEM | ENUM_ITEM | FUNCTION | TRAIT_ITEM
140 | CONST_ITEM | STATIC_ITEM | MOD_ITEM | NAMED_FIELD
141 | TYPE_ITEM => Some(Declaration(node)),
142 _ => None
143 }
144 }
145
146 fn name(&self) -> Option<String> {
147 let name = self.0.children()
148 .find(|child| child.kind() == NAME)?;
149 Some(name.text())
150 }
151
152 fn range(&self) -> TextRange {
153 self.0.range()
154 }
155}
diff --git a/crates/libeditor/src/line_index.rs b/crates/libeditor/src/line_index.rs
new file mode 100644
index 000000000..801726aa5
--- /dev/null
+++ b/crates/libeditor/src/line_index.rs
@@ -0,0 +1,62 @@
1use superslice::Ext;
2use ::TextUnit;
3
4#[derive(Clone, Debug)]
5pub struct LineIndex {
6 newlines: Vec<TextUnit>,
7}
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct LineCol {
11 pub line: u32,
12 pub col: TextUnit,
13}
14
15impl LineIndex {
16 pub fn new(text: &str) -> LineIndex {
17 let mut newlines = vec![0.into()];
18 let mut curr = 0.into();
19 for c in text.chars() {
20 curr += TextUnit::of_char(c);
21 if c == '\n' {
22 newlines.push(curr);
23 }
24 }
25 LineIndex { newlines }
26 }
27
28 pub fn line_col(&self, offset: TextUnit) -> LineCol {
29 let line = self.newlines.upper_bound(&offset) - 1;
30 let line_start_offset = self.newlines[line];
31 let col = offset - line_start_offset;
32 return LineCol { line: line as u32, col };
33 }
34
35 pub fn offset(&self, line_col: LineCol) -> TextUnit {
36 //TODO: return Result
37 self.newlines[line_col.line as usize] + line_col.col
38 }
39}
40
41#[test]
42fn test_line_index() {
43 let text = "hello\nworld";
44 let index = LineIndex::new(text);
45 assert_eq!(index.line_col(0.into()), LineCol { line: 0, col: 0.into() });
46 assert_eq!(index.line_col(1.into()), LineCol { line: 0, col: 1.into() });
47 assert_eq!(index.line_col(5.into()), LineCol { line: 0, col: 5.into() });
48 assert_eq!(index.line_col(6.into()), LineCol { line: 1, col: 0.into() });
49 assert_eq!(index.line_col(7.into()), LineCol { line: 1, col: 1.into() });
50 assert_eq!(index.line_col(8.into()), LineCol { line: 1, col: 2.into() });
51 assert_eq!(index.line_col(10.into()), LineCol { line: 1, col: 4.into() });
52 assert_eq!(index.line_col(11.into()), LineCol { line: 1, col: 5.into() });
53 assert_eq!(index.line_col(12.into()), LineCol { line: 1, col: 6.into() });
54
55 let text = "\nhello\nworld";
56 let index = LineIndex::new(text);
57 assert_eq!(index.line_col(0.into()), LineCol { line: 0, col: 0.into() });
58 assert_eq!(index.line_col(1.into()), LineCol { line: 1, col: 0.into() });
59 assert_eq!(index.line_col(2.into()), LineCol { line: 1, col: 1.into() });
60 assert_eq!(index.line_col(6.into()), LineCol { line: 1, col: 5.into() });
61 assert_eq!(index.line_col(7.into()), LineCol { line: 2, col: 0.into() });
62}
diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs
new file mode 100644
index 000000000..2a84c5080
--- /dev/null
+++ b/crates/libeditor/tests/test.rs
@@ -0,0 +1,69 @@
1extern crate libeditor;
2extern crate itertools;
3
4use std::fmt;
5use itertools::Itertools;
6use libeditor::{ast, highlight, runnables, extend_selection, TextRange};
7
8#[test]
9fn test_extend_selection() {
10 let file = file(r#"fn foo() {
11 1 + 1
12}
13"#);
14 let range = TextRange::offset_len(18.into(), 0.into());
15 let range = extend_selection(&file, range).unwrap();
16 assert_eq!(range, TextRange::from_to(17.into(), 18.into()));
17 let range = extend_selection(&file, range).unwrap();
18 assert_eq!(range, TextRange::from_to(15.into(), 20.into()));
19}
20
21#[test]
22fn test_highlighting() {
23 let file = file(r#"
24// comment
25fn main() {}
26 println!("Hello, {}!", 92);
27"#);
28 let hls = highlight(&file);
29 dbg_eq(
30 &hls,
31 r#"[HighlightedRange { range: [1; 11), tag: "comment" },
32 HighlightedRange { range: [12; 14), tag: "keyword" },
33 HighlightedRange { range: [15; 19), tag: "function" },
34 HighlightedRange { range: [29; 36), tag: "text" },
35 HighlightedRange { range: [38; 50), tag: "string" },
36 HighlightedRange { range: [52; 54), tag: "literal" }]"#
37 );
38}
39
40#[test]
41fn test_runnables() {
42 let file = file(r#"
43fn main() {}
44
45#[test]
46fn test_foo() {}
47
48#[test]
49#[ignore]
50fn test_foo() {}
51"#);
52 let runnables = runnables(&file);
53 dbg_eq(
54 &runnables,
55 r#"[Runnable { range: [1; 13), kind: Bin },
56 Runnable { range: [15; 39), kind: Test { name: "test_foo" } },
57 Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#,
58 )
59}
60
61fn file(text: &str) -> ast::File {
62 ast::File::parse(text)
63}
64
65fn dbg_eq(actual: &impl fmt::Debug, expected: &str) {
66 let actual = format!("{:?}", actual);
67 let expected = expected.lines().map(|l| l.trim()).join(" ");
68 assert_eq!(actual, expected);
69}
diff --git a/crates/libsyntax2/Cargo.toml b/crates/libsyntax2/Cargo.toml
new file mode 100644
index 000000000..f67735540
--- /dev/null
+++ b/crates/libsyntax2/Cargo.toml
@@ -0,0 +1,15 @@
1[package]
2name = "libsyntax2"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8unicode-xid = "0.1.0"
9text_unit = "0.1.2"
10itertools = "0.7.5"
11drop_bomb = "0.1.4"
12parking_lot = "0.6.0"
13
14[dev-dependencies]
15testutils = { path = "./tests/testutils" }
diff --git a/crates/libsyntax2/src/algo/mod.rs b/crates/libsyntax2/src/algo/mod.rs
new file mode 100644
index 000000000..d2de70fd4
--- /dev/null
+++ b/crates/libsyntax2/src/algo/mod.rs
@@ -0,0 +1,123 @@
1pub mod walk;
2
3use {SyntaxNodeRef, TextUnit, TextRange};
4
5pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
6 let range = node.range();
7 assert!(
8 contains_offset_nonstrict(range, offset),
9 "Bad offset: range {:?} offset {:?}", range, offset
10 );
11 if range.is_empty() {
12 return LeafAtOffset::None;
13 }
14
15 if node.is_leaf() {
16 return LeafAtOffset::Single(node);
17 }
18
19 let mut children = node.children()
20 .filter(|child| {
21 let child_range = child.range();
22 !child_range.is_empty() && contains_offset_nonstrict(child_range, offset)
23 });
24
25 let left = children.next().unwrap();
26 let right = children.next();
27 assert!(children.next().is_none());
28 return if let Some(right) = right {
29 match (find_leaf_at_offset(left, offset), find_leaf_at_offset(right, offset)) {
30 (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) =>
31 LeafAtOffset::Between(left, right),
32 _ => unreachable!()
33 }
34 } else {
35 find_leaf_at_offset(left, offset)
36 };
37}
38
39#[derive(Clone, Copy, Debug)]
40pub enum LeafAtOffset<'a> {
41 None,
42 Single(SyntaxNodeRef<'a>),
43 Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>)
44}
45
46impl<'a> LeafAtOffset<'a> {
47 pub fn right_biased(self) -> Option<SyntaxNodeRef<'a>> {
48 match self {
49 LeafAtOffset::None => None,
50 LeafAtOffset::Single(node) => Some(node),
51 LeafAtOffset::Between(_, right) => Some(right)
52 }
53 }
54
55 pub fn left_biased(self) -> Option<SyntaxNodeRef<'a>> {
56 match self {
57 LeafAtOffset::None => None,
58 LeafAtOffset::Single(node) => Some(node),
59 LeafAtOffset::Between(left, _) => Some(left)
60 }
61 }
62}
63
64impl<'f> Iterator for LeafAtOffset<'f> {
65 type Item = SyntaxNodeRef<'f>;
66
67 fn next(&mut self) -> Option<SyntaxNodeRef<'f>> {
68 match *self {
69 LeafAtOffset::None => None,
70 LeafAtOffset::Single(node) => { *self = LeafAtOffset::None; Some(node) }
71 LeafAtOffset::Between(left, right) => { *self = LeafAtOffset::Single(right); Some(left) }
72 }
73 }
74}
75
76
77pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRef {
78 assert!(is_subrange(root.range(), range));
79 let (left, right) = match (
80 find_leaf_at_offset(root, range.start()).right_biased(),
81 find_leaf_at_offset(root, range.end()).left_biased()
82 ) {
83 (Some(l), Some(r)) => (l, r),
84 _ => return root
85 };
86
87 common_ancestor(left, right)
88}
89
90fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> {
91 for p in ancestors(n1) {
92 if ancestors(n2).any(|a| a == p) {
93 return p;
94 }
95 }
96 panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
97}
98
99pub fn ancestors<'a>(node: SyntaxNodeRef<'a>) -> impl Iterator<Item=SyntaxNodeRef<'a>> {
100 Ancestors(Some(node))
101}
102
103#[derive(Debug)]
104struct Ancestors<'a>(Option<SyntaxNodeRef<'a>>);
105
106impl<'a> Iterator for Ancestors<'a> {
107 type Item = SyntaxNodeRef<'a>;
108
109 fn next(&mut self) -> Option<Self::Item> {
110 self.0.take().map(|n| {
111 self.0 = n.parent();
112 n
113 })
114 }
115}
116
117fn contains_offset_nonstrict(range: TextRange, offset: TextUnit) -> bool {
118 range.start() <= offset && offset <= range.end()
119}
120
121fn is_subrange(range: TextRange, subrange: TextRange) -> bool {
122 range.start() <= subrange.start() && subrange.end() <= range.end()
123}
diff --git a/crates/libsyntax2/src/algo/search.rs b/crates/libsyntax2/src/algo/search.rs
new file mode 100644
index 000000000..46404f537
--- /dev/null
+++ b/crates/libsyntax2/src/algo/search.rs
@@ -0,0 +1,136 @@
1use {Node, NodeType, TextUnit, TextRange};
2use ::visitor::{visitor, process_subtree_bottom_up};
3
4pub fn child_of_type(node: Node, ty: NodeType) -> Option<Node> {
5 node.children().find(|n| n.ty() == ty)
6}
7
8pub fn children_of_type<'f>(node: Node<'f>, ty: NodeType) -> Box<Iterator<Item=Node<'f>> + 'f> {
9 Box::new(node.children().filter(move |n| n.ty() == ty))
10}
11
12pub fn subtree<'f>(node: Node<'f>) -> Box<Iterator<Item=Node<'f>> + 'f> {
13 Box::new(node.children().flat_map(subtree).chain(::std::iter::once(node)))
14}
15
16pub fn descendants_of_type<'f>(node: Node<'f>, ty: NodeType) -> Vec<Node<'f>> {
17 process_subtree_bottom_up(
18 node,
19 visitor(Vec::new())
20 .visit_nodes(&[ty], |node, nodes| nodes.push(node))
21 )
22}
23
24pub fn child_of_type_exn(node: Node, ty: NodeType) -> Node {
25 child_of_type(node, ty).unwrap_or_else(|| {
26 panic!("No child of type {:?} for {:?}\
27 ----\
28 {}\
29 ----", ty, node.ty(), node.text())
30 })
31}
32
33
34pub fn ancestors(node: Node) -> Ancestors {
35 Ancestors(Some(node))
36}
37
38pub struct Ancestors<'f>(Option<Node<'f>>);
39
40impl<'f> Iterator for Ancestors<'f> {
41 type Item = Node<'f>;
42
43 fn next(&mut self) -> Option<Self::Item> {
44 let current = self.0;
45 self.0 = current.and_then(|n| n.parent());
46 current
47 }
48}
49
50pub fn is_leaf(node: Node) -> bool {
51 node.children().next().is_none() && !node.range().is_empty()
52}
53
54
55#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
56pub enum Direction {
57 Left, Right
58}
59
60pub fn sibling(node: Node, dir: Direction) -> Option<Node> {
61 let (parent, idx) = child_position(node)?;
62 let idx = match dir {
63 Direction::Left => idx.checked_sub(1)?,
64 Direction::Right => idx + 1,
65 };
66 parent.children().nth(idx)
67}
68
69pub mod ast {
70 use {Node, AstNode, TextUnit, AstChildren};
71 use visitor::{visitor, process_subtree_bottom_up};
72 use super::{ancestors, find_leaf_at_offset, LeafAtOffset};
73
74 pub fn ancestor<'f, T: AstNode<'f>>(node: Node<'f>) -> Option<T> {
75 ancestors(node)
76 .filter_map(T::wrap)
77 .next()
78 }
79
80 pub fn ancestor_exn<'f, T: AstNode<'f>>(node: Node<'f>) -> T {
81 ancestor(node).unwrap()
82 }
83
84 pub fn children_of_type<'f, N: AstNode<'f>>(node: Node<'f>) -> AstChildren<N> {
85 AstChildren::new(node.children())
86 }
87
88 pub fn descendants_of_type<'f, N: AstNode<'f>>(node: Node<'f>) -> Vec<N> {
89 process_subtree_bottom_up(
90 node,
91 visitor(Vec::new())
92 .visit::<N, _>(|node, acc| acc.push(node))
93 )
94 }
95
96 pub fn node_at_offset<'f, T: AstNode<'f>>(node: Node<'f>, offset: TextUnit) -> Option<T> {
97 match find_leaf_at_offset(node, offset) {
98 LeafAtOffset::None => None,
99 LeafAtOffset::Single(node) => ancestor(node),
100 LeafAtOffset::Between(left, right) => ancestor(left).or_else(|| ancestor(right)),
101 }
102 }
103}
104
105pub mod traversal {
106 use {Node};
107
108 pub fn bottom_up<'f, F: FnMut(Node<'f>)>(node: Node<'f>, mut f: F)
109 {
110 go(node, &mut f);
111
112 fn go<'f, F: FnMut(Node<'f>)>(node: Node<'f>, f: &mut F) {
113 for child in node.children() {
114 go(child, f)
115 }
116 f(node);
117 }
118 }
119}
120
121fn child_position(child: Node) -> Option<(Node, usize)> {
122 child.parent()
123 .map(|parent| {
124 (parent, parent.children().position(|n| n == child).unwrap())
125 })
126}
127
128fn common_ancestor<'f>(n1: Node<'f>, n2: Node<'f>) -> Node<'f> {
129 for p in ancestors(n1) {
130 if ancestors(n2).any(|a| a == p) {
131 return p;
132 }
133 }
134 panic!("Can't find common ancestor of {:?} and {:?}", n1, n2)
135}
136
diff --git a/crates/libsyntax2/src/algo/walk.rs b/crates/libsyntax2/src/algo/walk.rs
new file mode 100644
index 000000000..a50ec2a09
--- /dev/null
+++ b/crates/libsyntax2/src/algo/walk.rs
@@ -0,0 +1,45 @@
1use SyntaxNodeRef;
2
3pub fn preorder<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = SyntaxNodeRef<'a>> {
4 walk(root).filter_map(|event| match event {
5 WalkEvent::Enter(node) => Some(node),
6 WalkEvent::Exit(_) => None,
7 })
8}
9
10#[derive(Debug, Copy, Clone)]
11pub enum WalkEvent<'a> {
12 Enter(SyntaxNodeRef<'a>),
13 Exit(SyntaxNodeRef<'a>),
14}
15
16pub fn walk<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = WalkEvent<'a>> {
17 let mut done = false;
18 ::itertools::unfold(WalkEvent::Enter(root), move |pos| {
19 if done {
20 return None;
21 }
22 let res = *pos;
23 *pos = match *pos {
24 WalkEvent::Enter(node) => match node.first_child() {
25 Some(child) => WalkEvent::Enter(child),
26 None => WalkEvent::Exit(node),
27 },
28 WalkEvent::Exit(node) => {
29 if node == root {
30 done = true;
31 WalkEvent::Exit(node)
32 } else {
33 match node.next_sibling() {
34 Some(sibling) => WalkEvent::Enter(sibling),
35 None => match node.parent() {
36 Some(node) => WalkEvent::Exit(node),
37 None => WalkEvent::Exit(node),
38 },
39 }
40 }
41 }
42 };
43 Some(res)
44 })
45}
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs
new file mode 100644
index 000000000..2f813050a
--- /dev/null
+++ b/crates/libsyntax2/src/ast/generated.rs
@@ -0,0 +1,54 @@
1use std::sync::Arc;
2use {
3 SyntaxNode, SyntaxRoot, TreeRoot, AstNode,
4 SyntaxKind::*,
5};
6
7
8#[derive(Debug, Clone, Copy)]
9pub struct File<R: TreeRoot = Arc<SyntaxRoot>> {
10 syntax: SyntaxNode<R>,
11}
12
13impl<R: TreeRoot> AstNode<R> for File<R> {
14 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
15 match syntax.kind() {
16 FILE => Some(File { syntax }),
17 _ => None,
18 }
19 }
20 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
21}
22
23
24#[derive(Debug, Clone, Copy)]
25pub struct Function<R: TreeRoot = Arc<SyntaxRoot>> {
26 syntax: SyntaxNode<R>,
27}
28
29impl<R: TreeRoot> AstNode<R> for Function<R> {
30 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
31 match syntax.kind() {
32 FUNCTION => Some(Function { syntax }),
33 _ => None,
34 }
35 }
36 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
37}
38
39
40#[derive(Debug, Clone, Copy)]
41pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> {
42 syntax: SyntaxNode<R>,
43}
44
45impl<R: TreeRoot> AstNode<R> for Name<R> {
46 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
47 match syntax.kind() {
48 NAME => Some(Name { syntax }),
49 _ => None,
50 }
51 }
52 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
53}
54
diff --git a/crates/libsyntax2/src/ast/generated.rs.tera b/crates/libsyntax2/src/ast/generated.rs.tera
new file mode 100644
index 000000000..242837801
--- /dev/null
+++ b/crates/libsyntax2/src/ast/generated.rs.tera
@@ -0,0 +1,22 @@
1use std::sync::Arc;
2use {
3 SyntaxNode, SyntaxRoot, TreeRoot, AstNode,
4 SyntaxKind::*,
5};
6{% for node in ast %}
7{% set Name = node.kind | camel %}
8#[derive(Debug, Clone, Copy)]
9pub struct {{ Name }}<R: TreeRoot = Arc<SyntaxRoot>> {
10 syntax: SyntaxNode<R>,
11}
12
13impl<R: TreeRoot> AstNode<R> for {{ Name }}<R> {
14 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
15 match syntax.kind() {
16 {{ node.kind }} => Some({{ Name }} { syntax }),
17 _ => None,
18 }
19 }
20 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
21}
22{% endfor %}
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs
new file mode 100644
index 000000000..eeb7ae6f6
--- /dev/null
+++ b/crates/libsyntax2/src/ast/mod.rs
@@ -0,0 +1,74 @@
1mod generated;
2
3use std::sync::Arc;
4use {
5 SyntaxNode, SyntaxRoot, TreeRoot, SyntaxError,
6 SyntaxKind::*,
7};
8pub use self::generated::*;
9
10pub trait AstNode<R: TreeRoot>: Sized {
11 fn cast(syntax: SyntaxNode<R>) -> Option<Self>;
12 fn syntax(&self) -> &SyntaxNode<R>;
13}
14
15impl File<Arc<SyntaxRoot>> {
16 pub fn parse(text: &str) -> Self {
17 File::cast(::parse(text)).unwrap()
18 }
19}
20
21impl<R: TreeRoot> File<R> {
22 pub fn errors(&self) -> Vec<SyntaxError> {
23 self.syntax().root.errors.clone()
24 }
25
26 pub fn functions<'a>(&'a self) -> impl Iterator<Item = Function<R>> + 'a {
27 self.syntax()
28 .children()
29 .filter_map(Function::cast)
30 }
31}
32
33impl<R: TreeRoot> Function<R> {
34 pub fn name(&self) -> Option<Name<R>> {
35 self.syntax()
36 .children()
37 .filter_map(Name::cast)
38 .next()
39 }
40
41 pub fn has_atom_attr(&self, atom: &str) -> bool {
42 self.syntax()
43 .children()
44 .filter(|node| node.kind() == ATTR)
45 .any(|attr| {
46 let mut metas = attr.children().filter(|node| node.kind() == META_ITEM);
47 let meta = match metas.next() {
48 None => return false,
49 Some(meta) => {
50 if metas.next().is_some() {
51 return false;
52 }
53 meta
54 }
55 };
56 let mut children = meta.children();
57 match children.next() {
58 None => false,
59 Some(child) => {
60 if children.next().is_some() {
61 return false;
62 }
63 child.kind() == IDENT && child.text() == atom
64 }
65 }
66 })
67 }
68}
69
70impl<R: TreeRoot> Name<R> {
71 pub fn text(&self) -> String {
72 self.syntax().text()
73 }
74}
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
new file mode 100644
index 000000000..bcc79843a
--- /dev/null
+++ b/crates/libsyntax2/src/grammar.ron
@@ -0,0 +1,227 @@
1Grammar(
2 single_byte_tokens: [
3 [";", "SEMI"],
4 [",", "COMMA"],
5 ["(", "L_PAREN"],
6 [")", "R_PAREN"],
7 ["{", "L_CURLY"],
8 ["}", "R_CURLY"],
9 ["[", "L_BRACK"],
10 ["]", "R_BRACK"],
11 ["<", "L_ANGLE"],
12 [">", "R_ANGLE"],
13 ["@", "AT"],
14 ["#", "POUND"],
15 ["~", "TILDE"],
16 ["?", "QUESTION"],
17 ["$", "DOLLAR"],
18 ["&", "AMP"],
19 ["|", "PIPE"],
20 ["+", "PLUS"],
21 ["*", "STAR"],
22 ["/", "SLASH"],
23 ["^", "CARET"],
24 ["%", "PERCENT"],
25 ],
26 multi_byte_tokens: [
27 [".", "DOT"],
28 ["..", "DOTDOT"],
29 ["...", "DOTDOTDOT"],
30 ["..=", "DOTDOTEQ"],
31 [":", "COLON"],
32 ["::", "COLONCOLON"],
33 ["=", "EQ"],
34 ["==", "EQEQ"],
35 ["=>", "FAT_ARROW"],
36 ["!", "EXCL"],
37 ["!=", "NEQ"],
38 ["-", "MINUS"],
39 ["->", "THIN_ARROW"],
40 ["<=", "LTEQ"],
41 [">=", "GTEQ"],
42 ["+=", "PLUSEQ"],
43 ["-=", "MINUSEQ"],
44 ["&&", "AMPAMP"],
45 ["||", "PIPEPIPE"],
46 ["<<", "SHL"],
47 [">>", "SHR"],
48 ["<<=", "SHLEQ"],
49 [">>=", "SHREQ"],
50 ],
51 keywords: [
52 "use",
53 "fn",
54 "struct",
55 "enum",
56 "trait",
57 "impl",
58 "true",
59 "false",
60 "as",
61 "extern",
62 "crate",
63 "mod",
64 "pub",
65 "self",
66 "super",
67 "in",
68 "where",
69 "for",
70 "loop",
71 "while",
72 "if",
73 "else",
74 "match",
75 "const",
76 "static",
77 "mut",
78 "unsafe",
79 "type",
80 "ref",
81 "let",
82 "move",
83 "return",
84 ],
85 contextual_keywords: [
86 "auto",
87 "default",
88 "union",
89 ],
90 tokens: [
91 "ERROR",
92 "IDENT",
93 "UNDERSCORE",
94 "WHITESPACE",
95 "INT_NUMBER",
96 "FLOAT_NUMBER",
97 "LIFETIME",
98 "CHAR",
99 "BYTE",
100 "STRING",
101 "RAW_STRING",
102 "BYTE_STRING",
103 "RAW_BYTE_STRING",
104 "COMMENT",
105 "DOC_COMMENT",
106 "SHEBANG",
107 ],
108 nodes: [
109 "FILE",
110
111 "STRUCT_ITEM",
112 "ENUM_ITEM",
113 "FUNCTION",
114 "EXTERN_CRATE_ITEM",
115 "MOD_ITEM",
116 "USE_ITEM",
117 "STATIC_ITEM",
118 "CONST_ITEM",
119 "TRAIT_ITEM",
120 "IMPL_ITEM",
121 "TYPE_ITEM",
122 "MACRO_CALL",
123 "TOKEN_TREE",
124
125 "PAREN_TYPE",
126 "TUPLE_TYPE",
127 "NEVER_TYPE",
128 "PATH_TYPE",
129 "POINTER_TYPE",
130 "ARRAY_TYPE",
131 "SLICE_TYPE",
132 "REFERENCE_TYPE",
133 "PLACEHOLDER_TYPE",
134 "FN_POINTER_TYPE",
135 "FOR_TYPE",
136 "IMPL_TRAIT_TYPE",
137
138 "REF_PAT",
139 "BIND_PAT",
140 "PLACEHOLDER_PAT",
141 "PATH_PAT",
142 "STRUCT_PAT",
143 "TUPLE_STRUCT_PAT",
144 "TUPLE_PAT",
145 "SLICE_PAT",
146 "RANGE_PAT",
147
148 // atoms
149 "TUPLE_EXPR",
150 "ARRAY_EXPR",
151 "PAREN_EXPR",
152 "PATH_EXPR",
153 "LAMBDA_EXPR",
154 "IF_EXPR",
155 "WHILE_EXPR",
156 "LOOP_EXPR",
157 "FOR_EXPR",
158 "BLOCK_EXPR",
159 "RETURN_EXPR",
160 "MATCH_EXPR",
161 "MATCH_ARM",
162 "MATCH_GUARD",
163 "STRUCT_LIT",
164 "STRUCT_LIT_FIELD",
165
166 // postfix
167 "CALL_EXPR",
168 "INDEX_EXPR",
169 "METHOD_CALL_EXPR",
170 "FIELD_EXPR",
171 "TRY_EXPR",
172 "CAST_EXPR",
173
174 // unary
175 "REF_EXPR",
176 "PREFIX_EXPR",
177
178 "RANGE_EXPR", // just weird
179 "BIN_EXPR",
180
181
182 "EXTERN_BLOCK_EXPR",
183 "ENUM_VARIANT",
184 "NAMED_FIELD",
185 "POS_FIELD",
186 "ATTR",
187 "META_ITEM", // not an item actually
188 "USE_TREE",
189 "PATH",
190 "PATH_SEGMENT",
191 "LITERAL",
192 "ALIAS",
193 "VISIBILITY",
194 "WHERE_CLAUSE",
195 "WHERE_PRED",
196 "ABI",
197 "NAME",
198 "NAME_REF",
199
200 "LET_STMT",
201 "EXPR_STMT",
202
203 "TYPE_PARAM_LIST",
204 "LIFETIME_PARAM",
205 "TYPE_PARAM",
206 "TYPE_ARG_LIST",
207 "LIFETIME_ARG",
208 "TYPE_ARG",
209 "ASSOC_TYPE_ARG",
210
211 "PARAM_LIST",
212 "PARAM",
213 "SELF_PARAM",
214 "ARG_LIST",
215 ],
216 ast: [
217 (
218 kind: "FILE"
219 ),
220 (
221 kind: "FUNCTION"
222 ),
223 (
224 kind: "NAME"
225 ),
226 ]
227)
diff --git a/crates/libsyntax2/src/grammar/attributes.rs b/crates/libsyntax2/src/grammar/attributes.rs
new file mode 100644
index 000000000..c411d4d7f
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/attributes.rs
@@ -0,0 +1,79 @@
1use super::*;
2
3pub(super) fn inner_attributes(p: &mut Parser) {
4 while p.current() == POUND && p.nth(1) == EXCL {
5 attribute(p, true)
6 }
7}
8
9pub(super) fn outer_attributes(p: &mut Parser) {
10 while p.at(POUND) {
11 attribute(p, false)
12 }
13}
14
15fn attribute(p: &mut Parser, inner: bool) {
16 let attr = p.start();
17 assert!(p.at(POUND));
18 p.bump();
19
20 if inner {
21 assert!(p.at(EXCL));
22 p.bump();
23 }
24
25 if p.expect(L_BRACK) {
26 meta_item(p);
27 p.expect(R_BRACK);
28 }
29 attr.complete(p, ATTR);
30}
31
32fn meta_item(p: &mut Parser) {
33 if p.at(IDENT) {
34 let meta_item = p.start();
35 p.bump();
36 match p.current() {
37 EQ => {
38 p.bump();
39 if expressions::literal(p).is_none() {
40 p.error("expected literal");
41 }
42 }
43 L_PAREN => meta_item_arg_list(p),
44 _ => (),
45 }
46 meta_item.complete(p, META_ITEM);
47 } else {
48 p.error("expected attribute value");
49 }
50}
51
52fn meta_item_arg_list(p: &mut Parser) {
53 assert!(p.at(L_PAREN));
54 p.bump();
55 loop {
56 match p.current() {
57 EOF | R_PAREN => break,
58 IDENT => meta_item(p),
59 c => if expressions::literal(p).is_none() {
60 let message = "expected attribute";
61
62 if items::ITEM_FIRST.contains(c) {
63 p.error(message);
64 return;
65 }
66
67 let err = p.start();
68 p.error(message);
69 p.bump();
70 err.complete(p, ERROR);
71 continue;
72 },
73 }
74 if !p.at(R_PAREN) {
75 p.expect(COMMA);
76 }
77 }
78 p.expect(R_PAREN);
79}
diff --git a/crates/libsyntax2/src/grammar/expressions/atom.rs b/crates/libsyntax2/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..af9f47c5e
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/expressions/atom.rs
@@ -0,0 +1,348 @@
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, WHILE_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, r: Restrictions) -> 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, r));
43 }
44 let la = p.nth(1);
45 let done = match p.current() {
46 L_PAREN => tuple_expr(p),
47 L_BRACK => array_expr(p),
48 PIPE => lambda_expr(p),
49 MOVE_KW if la == PIPE => lambda_expr(p),
50 IF_KW => if_expr(p),
51 WHILE_KW => while_expr(p),
52 LOOP_KW => loop_expr(p),
53 FOR_KW => for_expr(p),
54 MATCH_KW => match_expr(p),
55 UNSAFE_KW if la == L_CURLY => block_expr(p),
56 L_CURLY => block_expr(p),
57 RETURN_KW => return_expr(p),
58 _ => {
59 p.err_and_bump("expected expression");
60 return None;
61 }
62 };
63 Some(done)
64}
65
66// test tuple_expr
67// fn foo() {
68// ();
69// (1);
70// (1,);
71// }
72fn tuple_expr(p: &mut Parser) -> CompletedMarker {
73 assert!(p.at(L_PAREN));
74 let m = p.start();
75 p.expect(L_PAREN);
76
77 let mut saw_comma = false;
78 let mut saw_expr = false;
79 while !p.at(EOF) && !p.at(R_PAREN) {
80 saw_expr = true;
81 expr(p);
82 if !p.at(R_PAREN) {
83 saw_comma = true;
84 p.expect(COMMA);
85 }
86 }
87 p.expect(R_PAREN);
88 m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
89}
90
91// test array_expr
92// fn foo() {
93// [];
94// [1];
95// [1, 2,];
96// [1; 2];
97// }
98fn array_expr(p: &mut Parser) -> CompletedMarker {
99 assert!(p.at(L_BRACK));
100 let m = p.start();
101 p.bump();
102 if p.eat(R_BRACK) {
103 return m.complete(p, ARRAY_EXPR);
104 }
105 expr(p);
106 if p.eat(SEMI) {
107 expr(p);
108 p.expect(R_BRACK);
109 return m.complete(p, ARRAY_EXPR);
110 }
111 while !p.at(EOF) && !p.at(R_BRACK) {
112 p.expect(COMMA);
113 if !p.at(R_BRACK) {
114 expr(p);
115 }
116 }
117 p.expect(R_BRACK);
118 m.complete(p, ARRAY_EXPR)
119}
120
121// test lambda_expr
122// fn foo() {
123// || ();
124// || -> i32 { 92 };
125// |x| x;
126// move |x: i32,| x;
127// }
128fn lambda_expr(p: &mut Parser) -> CompletedMarker {
129 assert!(p.at(PIPE) || (p.at(MOVE_KW) && p.nth(1) == PIPE));
130 let m = p.start();
131 p.eat(MOVE_KW);
132 params::param_list_opt_types(p);
133 if fn_ret_type(p) {
134 block(p);
135 } else {
136 expr(p);
137 }
138 m.complete(p, LAMBDA_EXPR)
139}
140
141// test if_expr
142// fn foo() {
143// if true {};
144// if true {} else {};
145// if true {} else if false {} else {};
146// if S {};
147// }
148fn if_expr(p: &mut Parser) -> CompletedMarker {
149 assert!(p.at(IF_KW));
150 let m = p.start();
151 p.bump();
152 cond(p);
153 block(p);
154 if p.at(ELSE_KW) {
155 p.bump();
156 if p.at(IF_KW) {
157 if_expr(p);
158 } else {
159 block(p);
160 }
161 }
162 m.complete(p, IF_EXPR)
163}
164
165// test while_expr
166// fn foo() {
167// while true {};
168// while let Some(x) = it.next() {};
169// }
170fn while_expr(p: &mut Parser) -> CompletedMarker {
171 assert!(p.at(WHILE_KW));
172 let m = p.start();
173 p.bump();
174 cond(p);
175 block(p);
176 m.complete(p, WHILE_EXPR)
177}
178
179// test loop_expr
180// fn foo() {
181// loop {};
182// }
183fn loop_expr(p: &mut Parser) -> CompletedMarker {
184 assert!(p.at(LOOP_KW));
185 let m = p.start();
186 p.bump();
187 block(p);
188 m.complete(p, LOOP_EXPR)
189}
190
191// test for_expr
192// fn foo() {
193// for x in [] {};
194// }
195fn for_expr(p: &mut Parser) -> CompletedMarker {
196 assert!(p.at(FOR_KW));
197 let m = p.start();
198 p.bump();
199 patterns::pattern(p);
200 p.expect(IN_KW);
201 expr_no_struct(p);
202 block(p);
203 m.complete(p, FOR_EXPR)
204}
205
206// test cond
207// fn foo() { if let Some(_) = None {} }
208fn cond(p: &mut Parser) {
209 if p.eat(LET_KW) {
210 patterns::pattern(p);
211 p.expect(EQ);
212 }
213 expr_no_struct(p)
214}
215
216// test match_expr
217// fn foo() {
218// match () { };
219// match S {};
220// }
221fn match_expr(p: &mut Parser) -> CompletedMarker {
222 assert!(p.at(MATCH_KW));
223 let m = p.start();
224 p.bump();
225 expr_no_struct(p);
226 p.eat(L_CURLY);
227 while !p.at(EOF) && !p.at(R_CURLY) {
228 // test match_arms_commas
229 // fn foo() {
230 // match () {
231 // _ => (),
232 // _ => {}
233 // _ => ()
234 // }
235 // }
236 if match_arm(p).is_block() {
237 p.eat(COMMA);
238 } else if !p.at(R_CURLY) {
239 p.expect(COMMA);
240 }
241 }
242 p.expect(R_CURLY);
243 m.complete(p, MATCH_EXPR)
244}
245
246// test match_arm
247// fn foo() {
248// match () {
249// _ => (),
250// X | Y if Z => (),
251// };
252// }
253fn match_arm(p: &mut Parser) -> BlockLike {
254 let m = p.start();
255 loop {
256 patterns::pattern(p);
257 if !p.eat(PIPE) {
258 break;
259 }
260 }
261 if p.eat(IF_KW) {
262 expr_no_struct(p);
263 }
264 p.expect(FAT_ARROW);
265 let ret = expr_stmt(p);
266 m.complete(p, MATCH_ARM);
267 ret
268}
269
270// test block_expr
271// fn foo() {
272// {};
273// unsafe {};
274// }
275pub(super) fn block_expr(p: &mut Parser) -> CompletedMarker {
276 assert!(p.at(L_CURLY) || p.at(UNSAFE_KW) && p.nth(1) == L_CURLY);
277 let m = p.start();
278 p.eat(UNSAFE_KW);
279 p.bump();
280 while !p.at(EOF) && !p.at(R_CURLY) {
281 match p.current() {
282 LET_KW => let_stmt(p),
283 _ => {
284 // test block_items
285 // fn a() { fn b() {} }
286 let m = p.start();
287 match items::maybe_item(p) {
288 items::MaybeItem::Item(kind) => {
289 m.complete(p, kind);
290 }
291 items::MaybeItem::Modifiers => {
292 m.abandon(p);
293 p.error("expected an item");
294 }
295 // test pub_expr
296 // fn foo() { pub 92; } //FIXME
297 items::MaybeItem::None => {
298 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
299 if p.eat(SEMI) || (is_blocklike && !p.at(R_CURLY)) {
300 m.complete(p, EXPR_STMT);
301 } else {
302 m.abandon(p);
303 }
304 }
305 }
306 }
307 }
308 }
309 p.expect(R_CURLY);
310 m.complete(p, BLOCK_EXPR)
311}
312
313// test let_stmt;
314// fn foo() {
315// let a;
316// let b: i32;
317// let c = 92;
318// let d: i32 = 92;
319// }
320fn let_stmt(p: &mut Parser) {
321 assert!(p.at(LET_KW));
322 let m = p.start();
323 p.bump();
324 patterns::pattern(p);
325 if p.at(COLON) {
326 types::ascription(p);
327 }
328 if p.eat(EQ) {
329 expressions::expr(p);
330 }
331 p.expect(SEMI);
332 m.complete(p, LET_STMT);
333}
334
335// test return_expr
336// fn foo() {
337// return;
338// return 92;
339// }
340fn return_expr(p: &mut Parser) -> CompletedMarker {
341 assert!(p.at(RETURN_KW));
342 let m = p.start();
343 p.bump();
344 if EXPR_FIRST.contains(p.current()) {
345 expr(p);
346 }
347 m.complete(p, RETURN_EXPR)
348}
diff --git a/crates/libsyntax2/src/grammar/expressions/mod.rs b/crates/libsyntax2/src/grammar/expressions/mod.rs
new file mode 100644
index 000000000..dcbb1e2a8
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/expressions/mod.rs
@@ -0,0 +1,379 @@
1mod atom;
2
3use super::*;
4pub(super) use self::atom::literal;
5
6const EXPR_FIRST: TokenSet = LHS_FIRST;
7
8pub(super) fn expr(p: &mut Parser) -> BlockLike {
9 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
10 expr_bp(p, r, 1)
11}
12
13pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
14 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
15 expr_bp(p, r, 1)
16}
17
18fn expr_no_struct(p: &mut Parser) {
19 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
20 expr_bp(p, r, 1);
21}
22
23// test block
24// fn a() {}
25// fn b() { let _ = 1; }
26// fn c() { 1; 2; }
27// fn d() { 1; 2 }
28pub(super) fn block(p: &mut Parser) {
29 if !p.at(L_CURLY) {
30 p.error("expected block");
31 return;
32 }
33 atom::block_expr(p);
34}
35
36#[derive(Clone, Copy)]
37struct Restrictions {
38 forbid_structs: bool,
39 prefer_stmt: bool,
40}
41
42enum Op {
43 Simple,
44 Composite(SyntaxKind, u8),
45}
46
47fn current_op(p: &Parser) -> (u8, Op) {
48 if p.at_compound2(PLUS, EQ) {
49 return (1, Op::Composite(PLUSEQ, 2));
50 }
51 if p.at_compound2(MINUS, EQ) {
52 return (1, Op::Composite(MINUSEQ, 2));
53 }
54 if p.at_compound3(L_ANGLE, L_ANGLE, EQ) {
55 return (1, Op::Composite(SHLEQ, 3));
56 }
57 if p.at_compound3(R_ANGLE, R_ANGLE, EQ) {
58 return (1, Op::Composite(SHREQ, 3));
59 }
60 if p.at_compound2(PIPE, PIPE) {
61 return (3, Op::Composite(PIPEPIPE, 2));
62 }
63 if p.at_compound2(AMP, AMP) {
64 return (4, Op::Composite(AMPAMP, 2));
65 }
66 if p.at_compound2(L_ANGLE, EQ) {
67 return (5, Op::Composite(LTEQ, 2));
68 }
69 if p.at_compound2(R_ANGLE, EQ) {
70 return (5, Op::Composite(GTEQ, 2));
71 }
72 if p.at_compound2(L_ANGLE, L_ANGLE) {
73 return (9, Op::Composite(SHL, 2));
74 }
75 if p.at_compound2(R_ANGLE, R_ANGLE) {
76 return (9, Op::Composite(SHR, 2));
77 }
78
79 let bp = match p.current() {
80 EQ => 1,
81 DOTDOT => 2,
82 EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
83 PIPE => 6,
84 CARET => 7,
85 AMP => 8,
86 MINUS | PLUS => 10,
87 STAR | SLASH | PERCENT => 11,
88 _ => 0,
89 };
90 (bp, Op::Simple)
91}
92
93// Parses expression with binding power of at least bp.
94fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
95 let mut lhs = match lhs(p, r) {
96 Some(lhs) => {
97 // test stmt_bin_expr_ambiguity
98 // fn foo() {
99 // let _ = {1} & 2;
100 // {1} &2;
101 // }
102 if r.prefer_stmt && is_block(lhs.kind()) {
103 return BlockLike::Block;
104 }
105 lhs
106 }
107 None => return BlockLike::NotBlock,
108 };
109
110 loop {
111 let is_range = p.current() == DOTDOT;
112 let (op_bp, op) = current_op(p);
113 if op_bp < bp {
114 break;
115 }
116 let m = lhs.precede(p);
117 match op {
118 Op::Simple => p.bump(),
119 Op::Composite(kind, n) => {
120 p.bump_compound(kind, n);
121 }
122 }
123 expr_bp(p, r, op_bp + 1);
124 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
125 }
126 BlockLike::NotBlock
127}
128
129// test no_semi_after_block
130// fn foo() {
131// if true {}
132// loop {}
133// match () {}
134// while true {}
135// for _ in () {}
136// {}
137// {}
138// }
139fn is_block(kind: SyntaxKind) -> bool {
140 match kind {
141 IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => true,
142 _ => false,
143 }
144}
145
146const LHS_FIRST: TokenSet =
147 token_set_union![
148 token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
149 atom::ATOM_EXPR_FIRST,
150 ];
151
152fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
153 let m;
154 let kind = match p.current() {
155 // test ref_expr
156 // fn foo() {
157 // let _ = &1;
158 // let _ = &mut &f();
159 // }
160 AMP => {
161 m = p.start();
162 p.bump();
163 p.eat(MUT_KW);
164 REF_EXPR
165 }
166 // test unary_expr
167 // fn foo() {
168 // **&1;
169 // !!true;
170 // --1;
171 // }
172 STAR | EXCL | MINUS => {
173 m = p.start();
174 p.bump();
175 PREFIX_EXPR
176 }
177 DOTDOT => {
178 m = p.start();
179 p.bump();
180 expr_bp(p, r, 2);
181 return Some(m.complete(p, RANGE_EXPR));
182 }
183 _ => {
184 let lhs = atom::atom_expr(p, r)?;
185 return Some(postfix_expr(p, r, lhs));
186 }
187 };
188 expr_bp(p, r, 255);
189 Some(m.complete(p, kind))
190}
191
192fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker {
193 let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind());
194 loop {
195 lhs = match p.current() {
196 // test stmt_postfix_expr_ambiguity
197 // fn foo() {
198 // match () {
199 // _ => {}
200 // () => {}
201 // [] => {}
202 // }
203 // }
204 L_PAREN if allow_calls => call_expr(p, lhs),
205 L_BRACK if allow_calls => index_expr(p, lhs),
206 DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
207 method_call_expr(p, lhs)
208 } else {
209 field_expr(p, lhs)
210 },
211 DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
212 // test postfix_range
213 // fn foo() { let x = 1..; }
214 DOTDOT if !EXPR_FIRST.contains(p.nth(1)) => {
215 let m = lhs.precede(p);
216 p.bump();
217 m.complete(p, RANGE_EXPR)
218 }
219 QUESTION => try_expr(p, lhs),
220 AS_KW => cast_expr(p, lhs),
221 _ => break,
222 };
223 allow_calls = true
224 }
225 lhs
226}
227
228// test call_expr
229// fn foo() {
230// let _ = f();
231// let _ = f()(1)(1, 2,);
232// }
233fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
234 assert!(p.at(L_PAREN));
235 let m = lhs.precede(p);
236 arg_list(p);
237 m.complete(p, CALL_EXPR)
238}
239
240// test index_expr
241// fn foo() {
242// x[1][2];
243// }
244fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
245 assert!(p.at(L_BRACK));
246 let m = lhs.precede(p);
247 p.bump();
248 expr(p);
249 p.expect(R_BRACK);
250 m.complete(p, INDEX_EXPR)
251}
252
253// test method_call_expr
254// fn foo() {
255// x.foo();
256// y.bar::<T>(1, 2,);
257// }
258fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
259 assert!(
260 p.at(DOT) && p.nth(1) == IDENT
261 && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)
262 );
263 let m = lhs.precede(p);
264 p.bump();
265 name_ref(p);
266 type_args::type_arg_list(p, true);
267 arg_list(p);
268 m.complete(p, METHOD_CALL_EXPR)
269}
270
271// test field_expr
272// fn foo() {
273// x.foo;
274// x.0.bar;
275// }
276fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
277 assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
278 let m = lhs.precede(p);
279 p.bump();
280 if p.at(IDENT) {
281 name_ref(p)
282 } else {
283 p.bump()
284 }
285 m.complete(p, FIELD_EXPR)
286}
287
288// test try_expr
289// fn foo() {
290// x?;
291// }
292fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
293 assert!(p.at(QUESTION));
294 let m = lhs.precede(p);
295 p.bump();
296 m.complete(p, TRY_EXPR)
297}
298
299// test cast_expr
300// fn foo() {
301// 82 as i32;
302// }
303fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
304 assert!(p.at(AS_KW));
305 let m = lhs.precede(p);
306 p.bump();
307 types::type_(p);
308 m.complete(p, CAST_EXPR)
309}
310
311fn arg_list(p: &mut Parser) {
312 assert!(p.at(L_PAREN));
313 let m = p.start();
314 p.bump();
315 while !p.at(R_PAREN) && !p.at(EOF) {
316 expr(p);
317 if !p.at(R_PAREN) && !p.expect(COMMA) {
318 break;
319 }
320 }
321 p.eat(R_PAREN);
322 m.complete(p, ARG_LIST);
323}
324
325// test path_expr
326// fn foo() {
327// let _ = a;
328// let _ = a::b;
329// let _ = ::a::<b>;
330// let _ = format!();
331// }
332fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
333 assert!(paths::is_path_start(p));
334 let m = p.start();
335 paths::expr_path(p);
336 match p.current() {
337 L_CURLY if !r.forbid_structs => {
338 struct_lit(p);
339 m.complete(p, STRUCT_LIT)
340 }
341 EXCL => {
342 items::macro_call_after_excl(p);
343 m.complete(p, MACRO_CALL)
344 }
345 _ => m.complete(p, PATH_EXPR)
346 }
347}
348
349// test struct_lit
350// fn foo() {
351// S {};
352// S { x, y: 32, };
353// S { x, y: 32, ..Default::default() };
354// }
355fn struct_lit(p: &mut Parser) {
356 assert!(p.at(L_CURLY));
357 p.bump();
358 while !p.at(EOF) && !p.at(R_CURLY) {
359 match p.current() {
360 IDENT => {
361 let m = p.start();
362 name_ref(p);
363 if p.eat(COLON) {
364 expr(p);
365 }
366 m.complete(p, STRUCT_LIT_FIELD);
367 }
368 DOTDOT => {
369 p.bump();
370 expr(p);
371 }
372 _ => p.err_and_bump("expected identifier"),
373 }
374 if !p.at(R_CURLY) {
375 p.expect(COMMA);
376 }
377 }
378 p.expect(R_CURLY);
379}
diff --git a/crates/libsyntax2/src/grammar/items/consts.rs b/crates/libsyntax2/src/grammar/items/consts.rs
new file mode 100644
index 000000000..b11949b49
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/consts.rs
@@ -0,0 +1,21 @@
1use super::*;
2
3pub(super) fn static_item(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_item(p: &mut Parser) {
8 const_or_static(p, CONST_KW)
9}
10
11fn const_or_static(p: &mut Parser, kw: SyntaxKind) {
12 assert!(p.at(kw));
13 p.bump();
14 p.eat(MUT_KW); // TODO: validator to forbid const mut
15 name(p);
16 types::ascription(p);
17 if p.eat(EQ) {
18 expressions::expr(p);
19 }
20 p.expect(SEMI);
21}
diff --git a/crates/libsyntax2/src/grammar/items/mod.rs b/crates/libsyntax2/src/grammar/items/mod.rs
new file mode 100644
index 000000000..3bf906f85
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/mod.rs
@@ -0,0 +1,332 @@
1use super::*;
2
3mod consts;
4mod structs;
5mod traits;
6mod use_item;
7
8// test mod_contents
9// fn foo() {}
10// macro_rules! foo {}
11// foo::bar!();
12// super::baz! {}
13// struct S;
14pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
15 attributes::inner_attributes(p);
16 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
17 item_or_macro(p, stop_on_r_curly)
18 }
19}
20
21pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
22 let m = p.start();
23 match maybe_item(p) {
24 MaybeItem::Item(kind) => {
25 m.complete(p, kind);
26 }
27 MaybeItem::None => {
28 if paths::is_path_start(p) {
29 match macro_call(p) {
30 BlockLike::Block => (),
31 BlockLike::NotBlock => {
32 p.expect(SEMI);
33 }
34 }
35 m.complete(p, MACRO_CALL);
36 } else {
37 m.abandon(p);
38 if p.at(L_CURLY) {
39 error_block(p, "expected an item");
40 } else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
41 p.err_and_bump("expected an item");
42 } else {
43 p.error("expected an item");
44 }
45 }
46 }
47 MaybeItem::Modifiers => {
48 p.error("expected fn, trait or impl");
49 m.complete(p, ERROR);
50 }
51 }
52}
53
54pub(super) const ITEM_FIRST: TokenSet =
55 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
56
57pub(super) enum MaybeItem {
58 None,
59 Item(SyntaxKind),
60 Modifiers,
61}
62
63pub(super) fn maybe_item(p: &mut Parser) -> MaybeItem {
64 attributes::outer_attributes(p);
65 visibility(p);
66 if let Some(kind) = items_without_modifiers(p) {
67 return MaybeItem::Item(kind);
68 }
69
70 let mut has_mods = false;
71 // modifiers
72 has_mods |= p.eat(CONST_KW);
73
74 // test unsafe_block_in_mod
75 // fn foo(){} unsafe { } fn bar(){}
76 if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY {
77 p.eat(UNSAFE_KW);
78 has_mods = true;
79 }
80 if p.at(EXTERN_KW) {
81 has_mods = true;
82 abi(p);
83 }
84 if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == TRAIT_KW {
85 p.bump_remap(AUTO_KW);
86 has_mods = true;
87 }
88 if p.at(IDENT) && p.at_contextual_kw("default") && p.nth(1) == IMPL_KW {
89 p.bump_remap(DEFAULT_KW);
90 has_mods = true;
91 }
92
93 // items
94 let kind = match p.current() {
95 // test extern_fn
96 // extern fn foo() {}
97
98 // test const_fn
99 // const fn foo() {}
100
101 // test const_unsafe_fn
102 // const unsafe fn foo() {}
103
104 // test unsafe_extern_fn
105 // unsafe extern "C" fn foo() {}
106
107 // test unsafe_fn
108 // unsafe fn foo() {}
109 FN_KW => {
110 function(p);
111 FUNCTION
112 }
113
114 // test unsafe_trait
115 // unsafe trait T {}
116
117 // test auto_trait
118 // auto trait T {}
119
120 // test unsafe_auto_trait
121 // unsafe auto trait T {}
122 TRAIT_KW => {
123 traits::trait_item(p);
124 TRAIT_ITEM
125 }
126
127 // test unsafe_impl
128 // unsafe impl Foo {}
129
130 // test default_impl
131 // default impl Foo {}
132
133 // test unsafe_default_impl
134 // unsafe default impl Foo {}
135 IMPL_KW => {
136 traits::impl_item(p);
137 IMPL_ITEM
138 }
139 _ => return if has_mods {
140 MaybeItem::Modifiers
141 } else {
142 MaybeItem::None
143 }
144 };
145
146 MaybeItem::Item(kind)
147}
148
149fn items_without_modifiers(p: &mut Parser) -> Option<SyntaxKind> {
150 let la = p.nth(1);
151 let kind = match p.current() {
152 // test extern_crate
153 // extern crate foo;
154 EXTERN_KW if la == CRATE_KW => {
155 extern_crate_item(p);
156 EXTERN_CRATE_ITEM
157 }
158 TYPE_KW => {
159 type_item(p);
160 TYPE_ITEM
161 }
162 MOD_KW => {
163 mod_item(p);
164 MOD_ITEM
165 }
166 STRUCT_KW => {
167 structs::struct_item(p);
168 if p.at(SEMI) {
169 p.err_and_bump(
170 "expected item, found `;`\n\
171 consider removing this semicolon"
172 );
173 }
174 STRUCT_ITEM
175 }
176 ENUM_KW => {
177 structs::enum_item(p);
178 ENUM_ITEM
179 }
180 USE_KW => {
181 use_item::use_item(p);
182 USE_ITEM
183 }
184 CONST_KW if (la == IDENT || la == MUT_KW) => {
185 consts::const_item(p);
186 CONST_ITEM
187 }
188 STATIC_KW => {
189 consts::static_item(p);
190 STATIC_ITEM
191 }
192 // test extern_block
193 // extern {}
194 EXTERN_KW if la == L_CURLY || ((la == STRING || la == RAW_STRING) && p.nth(2) == L_CURLY) => {
195 abi(p);
196 extern_block(p);
197 EXTERN_BLOCK_EXPR
198 }
199 _ => return None,
200 };
201 Some(kind)
202}
203
204fn extern_crate_item(p: &mut Parser) {
205 assert!(p.at(EXTERN_KW));
206 p.bump();
207 assert!(p.at(CRATE_KW));
208 p.bump();
209 name(p);
210 alias(p);
211 p.expect(SEMI);
212}
213
214fn extern_block(p: &mut Parser) {
215 assert!(p.at(L_CURLY));
216 p.bump();
217 p.expect(R_CURLY);
218}
219
220fn function(p: &mut Parser) {
221 assert!(p.at(FN_KW));
222 p.bump();
223
224 name(p);
225 // test function_type_params
226 // fn foo<T: Clone + Copy>(){}
227 type_params::type_param_list(p);
228
229 if p.at(L_PAREN) {
230 params::param_list(p);
231 } else {
232 p.error("expected function arguments");
233 }
234 // test function_ret_type
235 // fn foo() {}
236 // fn bar() -> () {}
237 fn_ret_type(p);
238
239 // test function_where_clause
240 // fn foo<T>() where T: Copy {}
241 type_params::where_clause(p);
242
243 // test fn_decl
244 // trait T { fn foo(); }
245 if !p.eat(SEMI) {
246 expressions::block(p);
247 }
248}
249
250// test type_item
251// type Foo = Bar;
252fn type_item(p: &mut Parser) {
253 assert!(p.at(TYPE_KW));
254 p.bump();
255
256 name(p);
257
258 // test type_item_type_params
259 // type Result<T> = ();
260 type_params::type_param_list(p);
261
262 if p.at(COLON) {
263 type_params::bounds(p);
264 }
265
266 // test type_item_where_clause
267 // type Foo where Foo: Copy = ();
268 type_params::where_clause(p);
269
270 if p.eat(EQ) {
271 types::type_(p);
272 }
273 p.expect(SEMI);
274}
275
276fn mod_item(p: &mut Parser) {
277 assert!(p.at(MOD_KW));
278 p.bump();
279
280 name(p);
281 if !p.eat(SEMI) {
282 if p.expect(L_CURLY) {
283 mod_contents(p, true);
284 p.expect(R_CURLY);
285 }
286 }
287}
288
289fn macro_call(p: &mut Parser) -> BlockLike {
290 assert!(paths::is_path_start(p));
291 paths::use_path(p);
292 macro_call_after_excl(p)
293}
294
295pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
296 p.expect(EXCL);
297 p.eat(IDENT);
298 let flavor = match p.current() {
299 L_CURLY => {
300 token_tree(p);
301 BlockLike::Block
302 }
303 L_PAREN | L_BRACK => {
304 token_tree(p);
305 BlockLike::NotBlock
306 }
307 _ => {
308 p.error("expected `{`, `[`, `(`");
309 BlockLike::NotBlock
310 },
311 };
312
313 flavor
314}
315
316fn token_tree(p: &mut Parser) {
317 let closing_paren_kind = match p.current() {
318 L_CURLY => R_CURLY,
319 L_PAREN => R_PAREN,
320 L_BRACK => R_BRACK,
321 _ => unreachable!(),
322 };
323 p.bump();
324 while !p.at(EOF) && !p.at(closing_paren_kind) {
325 match p.current() {
326 L_CURLY | L_PAREN | L_BRACK => token_tree(p),
327 R_CURLY | R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"),
328 _ => p.bump()
329 }
330 };
331 p.expect(closing_paren_kind);
332}
diff --git a/crates/libsyntax2/src/grammar/items/structs.rs b/crates/libsyntax2/src/grammar/items/structs.rs
new file mode 100644
index 000000000..67616eaad
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/structs.rs
@@ -0,0 +1,116 @@
1use super::*;
2
3pub(super) fn struct_item(p: &mut Parser) {
4 assert!(p.at(STRUCT_KW));
5 p.bump();
6
7 name(p);
8 type_params::type_param_list(p);
9 match p.current() {
10 WHERE_KW => {
11 type_params::where_clause(p);
12 match p.current() {
13 SEMI => {
14 p.bump();
15 return;
16 }
17 L_CURLY => named_fields(p),
18 _ => {
19 //TODO: special case `(` error message
20 p.error("expected `;` or `{`");
21 return;
22 }
23 }
24 }
25 SEMI => {
26 p.bump();
27 return;
28 }
29 L_CURLY => named_fields(p),
30 L_PAREN => {
31 pos_fields(p);
32 p.expect(SEMI);
33 }
34 _ => {
35 p.error("expected `;`, `{`, or `(`");
36 return;
37 }
38 }
39}
40
41pub(super) fn enum_item(p: &mut Parser) {
42 assert!(p.at(ENUM_KW));
43 p.bump();
44 name(p);
45 type_params::type_param_list(p);
46 type_params::where_clause(p);
47 if p.expect(L_CURLY) {
48 while !p.at(EOF) && !p.at(R_CURLY) {
49 let var = p.start();
50 attributes::outer_attributes(p);
51 if p.at(IDENT) {
52 name(p);
53 match p.current() {
54 L_CURLY => named_fields(p),
55 L_PAREN => pos_fields(p),
56 EQ => {
57 p.bump();
58 expressions::expr(p);
59 }
60 _ => (),
61 }
62 var.complete(p, ENUM_VARIANT);
63 } else {
64 var.abandon(p);
65 p.err_and_bump("expected enum variant");
66 }
67 if !p.at(R_CURLY) {
68 p.expect(COMMA);
69 }
70 }
71 p.expect(R_CURLY);
72 }
73}
74
75fn named_fields(p: &mut Parser) {
76 assert!(p.at(L_CURLY));
77 p.bump();
78 while !p.at(R_CURLY) && !p.at(EOF) {
79 named_field(p);
80 if !p.at(R_CURLY) {
81 p.expect(COMMA);
82 }
83 }
84 p.expect(R_CURLY);
85
86 fn named_field(p: &mut Parser) {
87 let field = p.start();
88 visibility(p);
89 if p.at(IDENT) {
90 name(p);
91 p.expect(COLON);
92 types::type_(p);
93 field.complete(p, NAMED_FIELD);
94 } else {
95 field.abandon(p);
96 p.err_and_bump("expected field declaration");
97 }
98 }
99}
100
101fn pos_fields(p: &mut Parser) {
102 if !p.expect(L_PAREN) {
103 return;
104 }
105 while !p.at(R_PAREN) && !p.at(EOF) {
106 let pos_field = p.start();
107 visibility(p);
108 types::type_(p);
109 pos_field.complete(p, POS_FIELD);
110
111 if !p.at(R_PAREN) {
112 p.expect(COMMA);
113 }
114 }
115 p.expect(R_PAREN);
116}
diff --git a/crates/libsyntax2/src/grammar/items/traits.rs b/crates/libsyntax2/src/grammar/items/traits.rs
new file mode 100644
index 000000000..0b9fb2b0b
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/traits.rs
@@ -0,0 +1,87 @@
1use super::*;
2
3// test trait_item
4// trait T<U>: Hash + Clone where U: Copy {}
5pub(super) fn trait_item(p: &mut Parser) {
6 assert!(p.at(TRAIT_KW));
7 p.bump();
8 name(p);
9 type_params::type_param_list(p);
10 if p.at(COLON) {
11 type_params::bounds(p);
12 }
13 type_params::where_clause(p);
14 p.expect(L_CURLY);
15 // test trait_item_items
16 // impl F {
17 // type A: Clone;
18 // const B: i32;
19 // fn foo() {}
20 // fn bar(&self);
21 // }
22 while !p.at(EOF) && !p.at(R_CURLY) {
23 item_or_macro(p, true);
24 }
25 p.expect(R_CURLY);
26}
27
28// test impl_item
29// impl Foo {}
30pub(super) fn impl_item(p: &mut Parser) {
31 assert!(p.at(IMPL_KW));
32 p.bump();
33 if choose_type_params_over_qpath(p) {
34 type_params::type_param_list(p);
35 }
36
37 // TODO: never type
38 // impl ! {}
39
40 // test impl_item_neg
41 // impl !Send for X {}
42 p.eat(EXCL);
43 types::type_(p);
44 if p.eat(FOR_KW) {
45 types::type_(p);
46 }
47 type_params::where_clause(p);
48 p.expect(L_CURLY);
49
50 // test impl_item_items
51 // impl F {
52 // type A = i32;
53 // const B: i32 = 92;
54 // fn foo() {}
55 // fn bar(&self) {}
56 // }
57 while !p.at(EOF) && !p.at(R_CURLY) {
58 item_or_macro(p, true);
59 }
60 p.expect(R_CURLY);
61}
62
63fn choose_type_params_over_qpath(p: &Parser) -> bool {
64 // There's an ambiguity between generic parameters and qualified paths in impls.
65 // If we see `<` it may start both, so we have to inspect some following tokens.
66 // The following combinations can only start generics,
67 // but not qualified paths (with one exception):
68 // `<` `>` - empty generic parameters
69 // `<` `#` - generic parameters with attributes
70 // `<` (LIFETIME|IDENT) `>` - single generic parameter
71 // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
72 // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
73 // `<` (LIFETIME|IDENT) `=` - generic parameter with a default
74 // The only truly ambiguous case is
75 // `<` IDENT `>` `::` IDENT ...
76 // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
77 // because this is what almost always expected in practice, qualified paths in impls
78 // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
79 if !p.at(L_ANGLE) {
80 return false;
81 }
82 if p.nth(1) == POUND || p.nth(1) == R_ANGLE {
83 return true;
84 }
85 (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
86 && (p.nth(2) == R_ANGLE || p.nth(2) == COMMA || p.nth(2) == COLON || p.nth(2) == EQ)
87}
diff --git a/crates/libsyntax2/src/grammar/items/use_item.rs b/crates/libsyntax2/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..a3f7f0da8
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/items/use_item.rs
@@ -0,0 +1,66 @@
1use super::*;
2
3pub(super) fn use_item(p: &mut Parser) {
4 assert!(p.at(USE_KW));
5 p.bump();
6 use_tree(p);
7 p.expect(SEMI);
8}
9
10fn use_tree(p: &mut Parser) {
11 let la = p.nth(1);
12 let m = p.start();
13 match (p.current(), la) {
14 (STAR, _) => p.bump(),
15 (COLONCOLON, STAR) => {
16 p.bump();
17 p.bump();
18 }
19 (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
20 if p.at(COLONCOLON) {
21 p.bump();
22 }
23 nested_trees(p);
24 }
25 _ if paths::is_path_start(p) => {
26 paths::use_path(p);
27 match p.current() {
28 AS_KW => {
29 alias(p);
30 }
31 COLONCOLON => {
32 p.bump();
33 match p.current() {
34 STAR => {
35 p.bump();
36 }
37 L_CURLY => nested_trees(p),
38 _ => {
39 // is this unreachable?
40 p.error("expected `{` or `*`");
41 }
42 }
43 }
44 _ => (),
45 }
46 }
47 _ => {
48 m.abandon(p);
49 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
50 return;
51 }
52 }
53 m.complete(p, USE_TREE);
54}
55
56fn nested_trees(p: &mut Parser) {
57 assert!(p.at(L_CURLY));
58 p.bump();
59 while !p.at(EOF) && !p.at(R_CURLY) {
60 use_tree(p);
61 if !p.at(R_CURLY) {
62 p.expect(COMMA);
63 }
64 }
65 p.expect(R_CURLY);
66}
diff --git a/crates/libsyntax2/src/grammar/mod.rs b/crates/libsyntax2/src/grammar/mod.rs
new file mode 100644
index 000000000..e1329044d
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/mod.rs
@@ -0,0 +1,161 @@
1//! This is the actual "grammar" of the Rust language.
2//!
3//! Each function in this module and its children corresponds
4//! to a production of the format grammar. Submodules roughly
5//! correspond to different *areas* of the grammar. By convention,
6//! each submodule starts with `use super::*` import and exports
7//! "public" productions via `pub(super)`.
8//!
9//! See docs for `Parser` to learn about API, available to the grammar,
10//! and see docs for `Event` to learn how this actually manages to
11//! produce parse trees.
12//!
13//! Code in this module also contains inline tests, which start with
14//! `// test name-of-the-test` comment and look like this:
15//!
16//! ```
17//! // test function_with_zero_parameters
18//! // fn foo() {}
19//! ```
20//!
21//! After adding a new inline-test, run `cargo collect-tests` to extract
22//! it as a standalone text-fixture into `tests/data/parser/inline`, and
23//! run `cargo test` once to create the "gold" value.
24mod attributes;
25mod expressions;
26mod items;
27mod params;
28mod paths;
29mod patterns;
30mod type_args;
31mod type_params;
32mod types;
33
34use {
35 parser_api::{CompletedMarker, Parser, TokenSet},
36 SyntaxKind::{self, *},
37};
38
39pub(crate) fn file(p: &mut Parser) {
40 let file = p.start();
41 p.eat(SHEBANG);
42 items::mod_contents(p, false);
43 file.complete(p, FILE);
44}
45
46
47#[derive(Clone, Copy, PartialEq, Eq)]
48enum BlockLike {
49 Block,
50 NotBlock,
51}
52
53impl BlockLike {
54 fn is_block(self) -> bool { self == BlockLike::Block }
55}
56
57fn visibility(p: &mut Parser) {
58 match p.current() {
59 PUB_KW => {
60 let m = p.start();
61 p.bump();
62 if p.at(L_PAREN) {
63 match p.nth(1) {
64 // test crate_visibility
65 // pub(crate) struct S;
66 // pub(self) struct S;
67 // pub(self) struct S;
68 // pub(self) struct S;
69 CRATE_KW | SELF_KW | SUPER_KW => {
70 p.bump();
71 p.bump();
72 p.expect(R_PAREN);
73 }
74 IN_KW => {
75 p.bump();
76 p.bump();
77 paths::use_path(p);
78 p.expect(R_PAREN);
79 }
80 _ => (),
81 }
82 }
83 m.complete(p, VISIBILITY);
84 }
85 // test crate_keyword_vis
86 // crate fn main() { }
87 CRATE_KW => {
88 let m = p.start();
89 p.bump();
90 m.complete(p, VISIBILITY);
91 }
92 _ => (),
93 }
94}
95fn alias(p: &mut Parser) -> bool {
96 if p.at(AS_KW) {
97 let alias = p.start();
98 p.bump();
99 name(p);
100 alias.complete(p, ALIAS);
101 }
102 true //FIXME: return false if three are errors
103}
104
105fn abi(p: &mut Parser) {
106 assert!(p.at(EXTERN_KW));
107 let abi = p.start();
108 p.bump();
109 match p.current() {
110 STRING | RAW_STRING => p.bump(),
111 _ => (),
112 }
113 abi.complete(p, ABI);
114}
115
116fn fn_ret_type(p: &mut Parser) -> bool {
117 if p.at(THIN_ARROW) {
118 p.bump();
119 types::type_(p);
120 true
121 } else {
122 false
123 }
124}
125
126fn name(p: &mut Parser) {
127 if p.at(IDENT) {
128 let m = p.start();
129 p.bump();
130 m.complete(p, NAME);
131 } else {
132 p.error("expected a name");
133 }
134}
135
136fn name_ref(p: &mut Parser) {
137 if p.at(IDENT) {
138 let m = p.start();
139 p.bump();
140 m.complete(p, NAME_REF);
141 } else {
142 p.error("expected identifier");
143 }
144}
145
146fn error_block(p: &mut Parser, message: &str) {
147 assert!(p.at(L_CURLY));
148 let err = p.start();
149 p.error(message);
150 p.bump();
151 let mut level: u32 = 1;
152 while level > 0 && !p.at(EOF) {
153 match p.current() {
154 L_CURLY => level += 1,
155 R_CURLY => level -= 1,
156 _ => (),
157 }
158 p.bump();
159 }
160 err.complete(p, ERROR);
161}
diff --git a/crates/libsyntax2/src/grammar/params.rs b/crates/libsyntax2/src/grammar/params.rs
new file mode 100644
index 000000000..32e905cb2
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/params.rs
@@ -0,0 +1,116 @@
1use super::*;
2
3// test param_list
4// fn a() {}
5// fn b(x: i32) {}
6// fn c(x: i32, ) {}
7// fn d(x: i32, y: ()) {}
8pub(super) fn param_list(p: &mut Parser) {
9 list_(p, Flavor::Normal)
10}
11
12// test param_list_opt_patterns
13// fn foo<F: FnMut(&mut Foo<'a>)>(){}
14pub(super) fn param_list_opt_patterns(p: &mut Parser) {
15 list_(p, Flavor::OptionalPattern)
16}
17
18pub(super) fn param_list_opt_types(p: &mut Parser) {
19 list_(p, Flavor::OptionalType)
20}
21
22#[derive(Clone, Copy, Eq, PartialEq)]
23enum Flavor {
24 OptionalType,
25 OptionalPattern,
26 Normal,
27}
28
29impl Flavor {
30 fn type_required(self) -> bool {
31 match self {
32 Flavor::OptionalType => false,
33 _ => true,
34 }
35 }
36}
37
38fn list_(p: &mut Parser, flavor: Flavor) {
39 let (bra, ket) = if flavor.type_required() {
40 (L_PAREN, R_PAREN)
41 } else {
42 (PIPE, PIPE)
43 };
44 assert!(p.at(bra));
45 let m = p.start();
46 p.bump();
47 if flavor.type_required() {
48 self_param(p);
49 }
50 while !p.at(EOF) && !p.at(ket) {
51 value_parameter(p, flavor);
52 if !p.at(ket) {
53 p.expect(COMMA);
54 }
55 }
56 p.expect(ket);
57 m.complete(p, PARAM_LIST);
58}
59
60fn value_parameter(p: &mut Parser, flavor: Flavor) {
61 let m = p.start();
62 match flavor {
63 Flavor::OptionalType | Flavor::Normal => {
64 patterns::pattern(p);
65 if p.at(COLON) || flavor.type_required() {
66 types::ascription(p)
67 }
68 },
69 // test value_parameters_no_patterns
70 // type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
71 Flavor::OptionalPattern => {
72 let la0 = p.current();
73 let la1 = p.nth(1);
74 let la2 = p.nth(2);
75 let la3 = p.nth(3);
76 if la0 == IDENT && la1 == COLON
77 || la0 == AMP && la1 == IDENT && la2 == COLON
78 || la0 == AMP && la1 == MUT_KW && la2 == IDENT && la3 == COLON {
79 patterns::pattern(p);
80 types::ascription(p);
81 } else {
82 types::type_(p);
83 }
84 },
85 }
86 m.complete(p, PARAM);
87}
88
89// test self_param
90// impl S {
91// fn a(self) {}
92// fn b(&self,) {}
93// fn c(&'a self,) {}
94// fn d(&'a mut self, x: i32) {}
95// }
96fn self_param(p: &mut Parser) {
97 let la1 = p.nth(1);
98 let la2 = p.nth(2);
99 let la3 = p.nth(3);
100 let n_toks = match (p.current(), la1, la2, la3) {
101 (SELF_KW, _, _, _) => 1,
102 (AMP, SELF_KW, _, _) => 2,
103 (AMP, MUT_KW, SELF_KW, _) => 3,
104 (AMP, LIFETIME, SELF_KW, _) => 3,
105 (AMP, LIFETIME, MUT_KW, SELF_KW) => 4,
106 _ => return,
107 };
108 let m = p.start();
109 for _ in 0..n_toks {
110 p.bump();
111 }
112 m.complete(p, SELF_PARAM);
113 if !p.at(R_PAREN) {
114 p.expect(COMMA);
115 }
116}
diff --git a/crates/libsyntax2/src/grammar/paths.rs b/crates/libsyntax2/src/grammar/paths.rs
new file mode 100644
index 000000000..c277e2a6b
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/paths.rs
@@ -0,0 +1,86 @@
1use super::*;
2
3pub(super) fn is_path_start(p: &Parser) -> bool {
4 match p.current() {
5 IDENT | SELF_KW | SUPER_KW | COLONCOLON => true,
6 _ => false,
7 }
8}
9
10pub(super) fn use_path(p: &mut Parser) {
11 path(p, Mode::Use)
12}
13
14pub(super) fn type_path(p: &mut Parser) {
15 path(p, Mode::Type)
16}
17
18pub(super) fn expr_path(p: &mut Parser) {
19 path(p, Mode::Expr)
20}
21
22#[derive(Clone, Copy, Eq, PartialEq)]
23enum Mode {
24 Use,
25 Type,
26 Expr,
27}
28
29fn path(p: &mut Parser, mode: Mode) {
30 if !is_path_start(p) {
31 return;
32 }
33 let path = p.start();
34 path_segment(p, mode, true);
35 let mut qual = path.complete(p, PATH);
36 loop {
37 let use_tree = match p.nth(1) {
38 STAR | L_CURLY => true,
39 _ => false,
40 };
41 if p.at(COLONCOLON) && !use_tree {
42 let path = qual.precede(p);
43 p.bump();
44 path_segment(p, mode, false);
45 let path = path.complete(p, PATH);
46 qual = path;
47 } else {
48 break;
49 }
50 }
51}
52
53fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
54 let segment = p.start();
55 if first {
56 p.eat(COLONCOLON);
57 }
58 match p.current() {
59 IDENT => {
60 name_ref(p);
61 path_generic_args(p, mode);
62 }
63 SELF_KW | SUPER_KW => p.bump(),
64 _ => {
65 p.error("expected identifier");
66 }
67 };
68 segment.complete(p, PATH_SEGMENT);
69}
70
71fn path_generic_args(p: &mut Parser, mode: Mode) {
72 match mode {
73 Mode::Use => return,
74 Mode::Type => {
75 // test path_fn_trait_args
76 // type F = Box<Fn(x: i32) -> ()>;
77 if p.at(L_PAREN) {
78 params::param_list_opt_patterns(p);
79 fn_ret_type(p);
80 } else {
81 type_args::type_arg_list(p, false)
82 }
83 },
84 Mode::Expr => type_args::type_arg_list(p, true),
85 }
86}
diff --git a/crates/libsyntax2/src/grammar/patterns.rs b/crates/libsyntax2/src/grammar/patterns.rs
new file mode 100644
index 000000000..436f3b26d
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/patterns.rs
@@ -0,0 +1,204 @@
1use super::*;
2
3pub(super) fn pattern(p: &mut Parser) {
4 if let Some(lhs) = atom_pat(p) {
5 // test range_pat
6 // fn main() {
7 // match 92 { 0 ... 100 => () }
8 // }
9 if p.at(DOTDOTDOT) {
10 let m = lhs.precede(p);
11 p.bump();
12 atom_pat(p);
13 m.complete(p, RANGE_PAT);
14 }
15 }
16}
17
18fn atom_pat(p: &mut Parser) -> Option<CompletedMarker> {
19 let la0 = p.nth(0);
20 let la1 = p.nth(1);
21 if la0 == REF_KW || la0 == MUT_KW
22 || (la0 == IDENT && !(la1 == COLONCOLON || la1 == L_PAREN || la1 == L_CURLY)) {
23 return Some(bind_pat(p, true));
24 }
25 if paths::is_path_start(p) {
26 return Some(path_pat(p));
27 }
28
29 // test literal_pattern
30 // fn main() {
31 // match () {
32 // 92 => (),
33 // 'c' => (),
34 // "hello" => (),
35 // }
36 // }
37 match expressions::literal(p) {
38 Some(m) => return Some(m),
39 None => (),
40 }
41
42 let m = match la0 {
43 UNDERSCORE => placeholder_pat(p),
44 AMP => ref_pat(p),
45 L_PAREN => tuple_pat(p),
46 L_BRACK => slice_pat(p),
47 _ => {
48 p.err_and_bump("expected pattern");
49 return None;
50 }
51 };
52 Some(m)
53}
54
55// test path_part
56// fn foo() {
57// let foo::Bar = ();
58// let ::Bar = ();
59// let Bar { .. } = ();
60// let Bar(..) = ();
61// }
62fn path_pat(p: &mut Parser) -> CompletedMarker {
63 let m = p.start();
64 paths::expr_path(p);
65 let kind = match p.current() {
66 L_PAREN => {
67 tuple_pat_fields(p);
68 TUPLE_STRUCT_PAT
69 }
70 L_CURLY => {
71 struct_pat_fields(p);
72 STRUCT_PAT
73 }
74 _ => PATH_PAT
75 };
76 m.complete(p, kind)
77}
78
79// test tuple_pat_fields
80// fn foo() {
81// let S() = ();
82// let S(_) = ();
83// let S(_,) = ();
84// let S(_, .. , x) = ();
85// }
86fn tuple_pat_fields(p: &mut Parser) {
87 assert!(p.at(L_PAREN));
88 p.bump();
89 while !p.at(EOF) && !p.at(R_PAREN) {
90 match p.current() {
91 DOTDOT => p.bump(),
92 _ => pattern(p),
93 }
94 if !p.at(R_PAREN) {
95 p.expect(COMMA);
96 }
97 }
98 p.expect(R_PAREN);
99}
100
101// test struct_pat_fields
102// fn foo() {
103// let S {} = ();
104// let S { f, ref mut g } = ();
105// let S { h: _, ..} = ();
106// let S { h: _, } = ();
107// }
108fn struct_pat_fields(p: &mut Parser) {
109 assert!(p.at(L_CURLY));
110 p.bump();
111 while !p.at(EOF) && !p.at(R_CURLY) {
112 match p.current() {
113 DOTDOT => p.bump(),
114 IDENT if p.nth(1) == COLON => {
115 p.bump();
116 p.bump();
117 pattern(p);
118 }
119 _ => {
120 bind_pat(p, false);
121 }
122 }
123 if !p.at(R_CURLY) {
124 p.expect(COMMA);
125 }
126 }
127 p.expect(R_CURLY);
128}
129
130// test placeholder_pat
131// fn main() { let _ = (); }
132fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
133 assert!(p.at(UNDERSCORE));
134 let m = p.start();
135 p.bump();
136 m.complete(p, PLACEHOLDER_PAT)
137}
138
139// test ref_pat
140// fn main() {
141// let &a = ();
142// let &mut b = ();
143// }
144fn ref_pat(p: &mut Parser) -> CompletedMarker {
145 assert!(p.at(AMP));
146 let m = p.start();
147 p.bump();
148 p.eat(MUT_KW);
149 pattern(p);
150 m.complete(p, REF_PAT)
151}
152
153// test tuple_pat
154// fn main() {
155// let (a, b, ..) = ();
156// }
157fn tuple_pat(p: &mut Parser) -> CompletedMarker {
158 assert!(p.at(L_PAREN));
159 let m = p.start();
160 tuple_pat_fields(p);
161 m.complete(p, TUPLE_PAT)
162}
163
164// test slice_pat
165// fn main() {
166// let [a, b, ..] = [];
167// }
168fn slice_pat(p: &mut Parser) -> CompletedMarker {
169 assert!(p.at(L_BRACK));
170 let m = p.start();
171 p.bump();
172 while !p.at(EOF) && !p.at(R_BRACK) {
173 match p.current() {
174 DOTDOT => p.bump(),
175 _ => pattern(p),
176 }
177 if !p.at(R_BRACK) {
178 p.expect(COMMA);
179 }
180 }
181 p.expect(R_BRACK);
182
183 m.complete(p, SLICE_PAT)
184}
185
186// test bind_pat
187// fn main() {
188// let a = ();
189// let mut b = ();
190// let ref c = ();
191// let ref mut d = ();
192// let e @ _ = ();
193// let ref mut f @ g @ _ = ();
194// }
195fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
196 let m = p.start();
197 p.eat(REF_KW);
198 p.eat(MUT_KW);
199 name(p);
200 if with_at && p.eat(AT) {
201 pattern(p);
202 }
203 m.complete(p, BIND_PAT)
204}
diff --git a/crates/libsyntax2/src/grammar/type_args.rs b/crates/libsyntax2/src/grammar/type_args.rs
new file mode 100644
index 000000000..5b960f10b
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/type_args.rs
@@ -0,0 +1,48 @@
1use super::*;
2
3pub(super) fn type_arg_list(p: &mut Parser, colon_colon_required: bool) {
4 let m;
5 match (colon_colon_required, p.nth(0), p.nth(1)) {
6 (_, COLONCOLON, L_ANGLE) => {
7 m = p.start();
8 p.bump();
9 p.bump();
10 }
11 (false, L_ANGLE, _) => {
12 m = p.start();
13 p.bump();
14 }
15 _ => return,
16 };
17
18 while !p.at(EOF) && !p.at(R_ANGLE) {
19 type_arg(p);
20 if !p.at(R_ANGLE) && !p.expect(COMMA) {
21 break;
22 }
23 }
24 p.expect(R_ANGLE);
25 m.complete(p, TYPE_ARG_LIST);
26}
27
28// test type_arg
29// type A = B<'static, i32, Item=u64>
30fn type_arg(p: &mut Parser) {
31 let m = p.start();
32 match p.current() {
33 LIFETIME => {
34 p.bump();
35 m.complete(p, LIFETIME_ARG);
36 }
37 IDENT if p.nth(1) == EQ => {
38 name_ref(p);
39 p.bump();
40 types::type_(p);
41 m.complete(p, ASSOC_TYPE_ARG);
42 }
43 _ => {
44 types::type_(p);
45 m.complete(p, TYPE_ARG);
46 }
47 }
48}
diff --git a/crates/libsyntax2/src/grammar/type_params.rs b/crates/libsyntax2/src/grammar/type_params.rs
new file mode 100644
index 000000000..0a3e8fd07
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/type_params.rs
@@ -0,0 +1,127 @@
1use super::*;
2
3pub(super) fn type_param_list(p: &mut Parser) {
4 if !p.at(L_ANGLE) {
5 return;
6 }
7 let m = p.start();
8 p.bump();
9
10 while !p.at(EOF) && !p.at(R_ANGLE) {
11 match p.current() {
12 LIFETIME => lifetime_param(p),
13 IDENT => type_param(p),
14 _ => p.err_and_bump("expected type parameter"),
15 }
16 if !p.at(R_ANGLE) && !p.expect(COMMA) {
17 break;
18 }
19 }
20 p.expect(R_ANGLE);
21 m.complete(p, TYPE_PARAM_LIST);
22
23 fn lifetime_param(p: &mut Parser) {
24 assert!(p.at(LIFETIME));
25 let m = p.start();
26 p.bump();
27 if p.at(COLON) {
28 lifetime_bounds(p);
29 }
30 m.complete(p, LIFETIME_PARAM);
31 }
32
33 fn type_param(p: &mut Parser) {
34 assert!(p.at(IDENT));
35 let m = p.start();
36 name(p);
37 if p.at(COLON) {
38 bounds(p);
39 }
40 // test type_param_default
41 // struct S<T = i32>;
42 if p.at(EQ) {
43 p.bump();
44 types::type_(p)
45 }
46 m.complete(p, TYPE_PARAM);
47 }
48}
49
50// test type_param_bounds
51// struct S<T: 'a + ?Sized + (Copy)>;
52pub(super) fn bounds(p: &mut Parser) {
53 assert!(p.at(COLON));
54 p.bump();
55 bounds_without_colon(p);
56}
57
58fn lifetime_bounds(p: &mut Parser) {
59 assert!(p.at(COLON));
60 p.bump();
61 while p.at(LIFETIME) {
62 p.bump();
63 if !p.eat(PLUS) {
64 break;
65 }
66 }
67}
68
69pub(super) fn bounds_without_colon(p: &mut Parser) {
70 loop {
71 let has_paren = p.eat(L_PAREN);
72 p.eat(QUESTION);
73 if p.at(FOR_KW) {
74 //TODO
75 }
76 if p.at(LIFETIME) {
77 p.bump();
78 } else if paths::is_path_start(p) {
79 paths::type_path(p);
80 } else {
81 break;
82 }
83 if has_paren {
84 p.expect(R_PAREN);
85 }
86 if !p.eat(PLUS) {
87 break;
88 }
89 }
90}
91
92// test where_clause
93// fn foo()
94// where
95// 'a: 'b + 'c,
96// T: Clone + Copy + 'static,
97// Iterator::Item: 'a,
98// {}
99pub(super) fn where_clause(p: &mut Parser) {
100 if !p.at(WHERE_KW) {
101 return;
102 }
103 let m = p.start();
104 p.bump();
105 loop {
106 if !(paths::is_path_start(p) || p.current() == LIFETIME) {
107 break
108 }
109 where_predicate(p);
110 if p.current() != L_CURLY && p.current() != SEMI {
111 p.expect(COMMA);
112 }
113 }
114 m.complete(p, WHERE_CLAUSE);
115}
116
117fn where_predicate(p: &mut Parser) {
118 let m = p.start();
119 if p.at(LIFETIME) {
120 p.eat(LIFETIME);
121 lifetime_bounds(p)
122 } else {
123 types::path_type(p);
124 bounds(p);
125 }
126 m.complete(p, WHERE_PRED);
127}
diff --git a/crates/libsyntax2/src/grammar/types.rs b/crates/libsyntax2/src/grammar/types.rs
new file mode 100644
index 000000000..0d8c6bfba
--- /dev/null
+++ b/crates/libsyntax2/src/grammar/types.rs
@@ -0,0 +1,212 @@
1use super::*;
2
3pub(super) fn type_(p: &mut Parser) {
4 match p.current() {
5 L_PAREN => paren_or_tuple_type(p),
6 EXCL => never_type(p),
7 STAR => pointer_type(p),
8 L_BRACK => array_or_slice_type(p),
9 AMP => reference_type(p),
10 UNDERSCORE => placeholder_type(p),
11 FN_KW | UNSAFE_KW | EXTERN_KW => fn_pointer_type(p),
12 FOR_KW => for_type(p),
13 IMPL_KW => impl_trait_type(p),
14 _ if paths::is_path_start(p) => path_type(p),
15 _ => {
16 p.error("expected type");
17 }
18 }
19}
20
21pub(super) fn ascription(p: &mut Parser) {
22 p.expect(COLON);
23 type_(p)
24}
25
26fn type_no_plus(p: &mut Parser) {
27 type_(p);
28}
29
30fn paren_or_tuple_type(p: &mut Parser) {
31 assert!(p.at(L_PAREN));
32 let m = p.start();
33 p.bump();
34 let mut n_types: u32 = 0;
35 let mut trailing_comma: bool = false;
36 while !p.at(EOF) && !p.at(R_PAREN) {
37 n_types += 1;
38 type_(p);
39 if p.eat(COMMA) {
40 trailing_comma = true;
41 } else {
42 trailing_comma = false;
43 break;
44 }
45 }
46 p.expect(R_PAREN);
47
48 let kind = if n_types == 1 && !trailing_comma {
49 // test paren_type
50 // type T = (i32);
51 PAREN_TYPE
52 } else {
53 // test unit_type
54 // type T = ();
55
56 // test singleton_tuple_type
57 // type T = (i32,);
58 TUPLE_TYPE
59 };
60 m.complete(p, kind);
61}
62
63// test never_type
64// type Never = !;
65fn never_type(p: &mut Parser) {
66 assert!(p.at(EXCL));
67 let m = p.start();
68 p.bump();
69 m.complete(p, NEVER_TYPE);
70}
71
72fn pointer_type(p: &mut Parser) {
73 assert!(p.at(STAR));
74 let m = p.start();
75 p.bump();
76
77 match p.current() {
78 // test pointer_type_mut
79 // type M = *mut ();
80 // type C = *mut ();
81 MUT_KW | CONST_KW => p.bump(),
82 _ => {
83 // test pointer_type_no_mutability
84 // type T = *();
85 p.error(
86 "expected mut or const in raw pointer type \
87 (use `*mut T` or `*const T` as appropriate)",
88 );
89 }
90 };
91
92 type_no_plus(p);
93 m.complete(p, POINTER_TYPE);
94}
95
96fn array_or_slice_type(p: &mut Parser) {
97 assert!(p.at(L_BRACK));
98 let m = p.start();
99 p.bump();
100
101 type_(p);
102 let kind = match p.current() {
103 // test slice_type
104 // type T = [()];
105 R_BRACK => {
106 p.bump();
107 SLICE_TYPE
108 }
109
110 // test array_type
111 // type T = [(); 92];
112 SEMI => {
113 p.bump();
114 expressions::expr(p);
115 p.expect(R_BRACK);
116 ARRAY_TYPE
117 }
118 // test array_type_missing_semi
119 // type T = [() 92];
120 _ => {
121 p.error("expected `;` or `]`");
122 SLICE_TYPE
123 }
124 };
125 m.complete(p, kind);
126}
127
128// test reference_type;
129// type A = &();
130// type B = &'static ();
131// type C = &mut ();
132fn reference_type(p: &mut Parser) {
133 assert!(p.at(AMP));
134 let m = p.start();
135 p.bump();
136 p.eat(LIFETIME);
137 p.eat(MUT_KW);
138 type_no_plus(p);
139 m.complete(p, REFERENCE_TYPE);
140}
141
142// test placeholder_type
143// type Placeholder = _;
144fn placeholder_type(p: &mut Parser) {
145 assert!(p.at(UNDERSCORE));
146 let m = p.start();
147 p.bump();
148 m.complete(p, PLACEHOLDER_TYPE);
149}
150
151// test fn_pointer_type
152// type A = fn();
153// type B = unsafe fn();
154// type C = unsafe extern "C" fn();
155fn fn_pointer_type(p: &mut Parser) {
156 let m = p.start();
157 p.eat(UNSAFE_KW);
158 if p.at(EXTERN_KW) {
159 abi(p);
160 }
161 // test fn_pointer_type_missing_fn
162 // type F = unsafe ();
163 if !p.eat(FN_KW) {
164 m.abandon(p);
165 p.error("expected `fn`");
166 return;
167 }
168
169 params::param_list_opt_patterns(p);
170 // test fn_pointer_type_with_ret
171 // type F = fn() -> ();
172 fn_ret_type(p);
173 m.complete(p, FN_POINTER_TYPE);
174}
175
176// test for_type
177// type A = for<'a> fn() -> ();
178fn for_type(p: &mut Parser) {
179 assert!(p.at(FOR_KW));
180 let m = p.start();
181 p.bump();
182 type_params::type_param_list(p);
183 type_(p);
184 m.complete(p, FOR_TYPE);
185}
186
187// test impl_trait_type
188// type A = impl Iterator<Item=Foo<'a>> + 'a;
189fn impl_trait_type(p: &mut Parser) {
190 assert!(p.at(IMPL_KW));
191 let m = p.start();
192 p.bump();
193 type_params::bounds_without_colon(p);
194 m.complete(p, IMPL_TRAIT_TYPE);
195}
196
197// test path_type
198// type A = Foo;
199// type B = ::Foo;
200// type C = self::Foo;
201// type D = super::Foo;
202pub(super) fn path_type(p: &mut Parser) {
203 assert!(paths::is_path_start(p));
204 let m = p.start();
205 paths::type_path(p);
206 // test path_type_with_bounds
207 // fn foo() -> Box<T + 'f> {}
208 if p.eat(PLUS) {
209 type_params::bounds_without_colon(p);
210 }
211 m.complete(p, PATH_TYPE);
212}
diff --git a/crates/libsyntax2/src/lexer/classes.rs b/crates/libsyntax2/src/lexer/classes.rs
new file mode 100644
index 000000000..4235d2648
--- /dev/null
+++ b/crates/libsyntax2/src/lexer/classes.rs
@@ -0,0 +1,26 @@
1use unicode_xid::UnicodeXID;
2
3pub fn is_ident_start(c: char) -> bool {
4 (c >= 'a' && c <= 'z')
5 || (c >= 'A' && c <= 'Z')
6 || c == '_'
7 || (c > '\x7f' && UnicodeXID::is_xid_start(c))
8}
9
10pub fn is_ident_continue(c: char) -> bool {
11 (c >= 'a' && c <= 'z')
12 || (c >= 'A' && c <= 'Z')
13 || (c >= '0' && c <= '9')
14 || c == '_'
15 || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
16}
17
18pub fn is_whitespace(c: char) -> bool {
19 //FIXME: use is_pattern_whitespace
20 //https://github.com/behnam/rust-unic/issues/192
21 c.is_whitespace()
22}
23
24pub fn is_dec_digit(c: char) -> bool {
25 '0' <= c && c <= '9'
26}
diff --git a/crates/libsyntax2/src/lexer/comments.rs b/crates/libsyntax2/src/lexer/comments.rs
new file mode 100644
index 000000000..01acb6515
--- /dev/null
+++ b/crates/libsyntax2/src/lexer/comments.rs
@@ -0,0 +1,57 @@
1use lexer::ptr::Ptr;
2
3use SyntaxKind::{self, *};
4
5pub(crate) fn scan_shebang(ptr: &mut Ptr) -> bool {
6 if ptr.next_is('!') && ptr.nnext_is('/') {
7 ptr.bump();
8 ptr.bump();
9 bump_until_eol(ptr);
10 true
11 } else {
12 false
13 }
14}
15
16fn scan_block_comment(ptr: &mut Ptr) -> Option<SyntaxKind> {
17 if ptr.next_is('*') {
18 ptr.bump();
19 let mut depth: u32 = 1;
20 while depth > 0 {
21 if ptr.next_is('*') && ptr.nnext_is('/') {
22 depth -= 1;
23 ptr.bump();
24 ptr.bump();
25 } else if ptr.next_is('/') && ptr.nnext_is('*') {
26 depth += 1;
27 ptr.bump();
28 ptr.bump();
29 } else if ptr.bump().is_none() {
30 break;
31 }
32 }
33 Some(COMMENT)
34 } else {
35 None
36 }
37}
38
39pub(crate) fn scan_comment(ptr: &mut Ptr) -> Option<SyntaxKind> {
40 if ptr.next_is('/') {
41 bump_until_eol(ptr);
42 Some(COMMENT)
43 } else {
44 scan_block_comment(ptr)
45 }
46}
47
48fn bump_until_eol(ptr: &mut Ptr) {
49 loop {
50 if ptr.next_is('\n') || ptr.next_is('\r') && ptr.nnext_is('\n') {
51 return;
52 }
53 if ptr.bump().is_none() {
54 break;
55 }
56 }
57}
diff --git a/crates/libsyntax2/src/lexer/mod.rs b/crates/libsyntax2/src/lexer/mod.rs
new file mode 100644
index 000000000..f8fdc41ac
--- /dev/null
+++ b/crates/libsyntax2/src/lexer/mod.rs
@@ -0,0 +1,209 @@
1mod classes;
2mod comments;
3mod numbers;
4mod ptr;
5mod strings;
6
7use {
8 SyntaxKind::{self, *},
9 TextUnit,
10};
11
12use self::{
13 classes::*,
14 comments::{scan_comment, scan_shebang},
15 numbers::scan_number,
16 ptr::Ptr,
17 strings::{
18 is_string_literal_start, scan_byte_char_or_string, scan_char, scan_raw_string, scan_string,
19 },
20};
21
22/// A token of Rust source.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct Token {
25 /// The kind of token.
26 pub kind: SyntaxKind,
27 /// The length of the token.
28 pub len: TextUnit,
29}
30
31/// Break a string up into its component tokens
32pub fn tokenize(text: &str) -> Vec<Token> {
33 let mut text = text;
34 let mut acc = Vec::new();
35 while !text.is_empty() {
36 let token = next_token(text);
37 acc.push(token);
38 let len: u32 = token.len.into();
39 text = &text[len as usize..];
40 }
41 acc
42}
43
44/// Get the next token from a string
45pub fn next_token(text: &str) -> Token {
46 assert!(!text.is_empty());
47 let mut ptr = Ptr::new(text);
48 let c = ptr.bump().unwrap();
49 let kind = next_token_inner(c, &mut ptr);
50 let len = ptr.into_len();
51 Token { kind, len }
52}
53
54fn next_token_inner(c: char, ptr: &mut Ptr) -> SyntaxKind {
55 if is_whitespace(c) {
56 ptr.bump_while(is_whitespace);
57 return WHITESPACE;
58 }
59
60 match c {
61 '#' => if scan_shebang(ptr) {
62 return SHEBANG;
63 },
64 '/' => if let Some(kind) = scan_comment(ptr) {
65 return kind;
66 },
67 _ => (),
68 }
69
70 let ident_start = is_ident_start(c) && !is_string_literal_start(c, ptr.next(), ptr.nnext());
71 if ident_start {
72 return scan_ident(c, ptr);
73 }
74
75 if is_dec_digit(c) {
76 let kind = scan_number(c, ptr);
77 scan_literal_suffix(ptr);
78 return kind;
79 }
80
81 // One-byte tokens.
82 if let Some(kind) = SyntaxKind::from_char(c) {
83 return kind;
84 }
85
86 match c {
87 // Multi-byte tokens.
88 '.' => {
89 return match (ptr.next(), ptr.nnext()) {
90 (Some('.'), Some('.')) => {
91 ptr.bump();
92 ptr.bump();
93 DOTDOTDOT
94 }
95 (Some('.'), Some('=')) => {
96 ptr.bump();
97 ptr.bump();
98 DOTDOTEQ
99 }
100 (Some('.'), _) => {
101 ptr.bump();
102 DOTDOT
103 }
104 _ => DOT,
105 };
106 }
107 ':' => {
108 return match ptr.next() {
109 Some(':') => {
110 ptr.bump();
111 COLONCOLON
112 }
113 _ => COLON,
114 };
115 }
116 '=' => {
117 return match ptr.next() {
118 Some('=') => {
119 ptr.bump();
120 EQEQ
121 }
122 Some('>') => {
123 ptr.bump();
124 FAT_ARROW
125 }
126 _ => EQ,
127 };
128 }
129 '!' => {
130 return match ptr.next() {
131 Some('=') => {
132 ptr.bump();
133 NEQ
134 }
135 _ => EXCL,
136 };
137 }
138 '-' => {
139 return if ptr.next_is('>') {
140 ptr.bump();
141 THIN_ARROW
142 } else {
143 MINUS
144 };
145 }
146
147 // If the character is an ident start not followed by another single
148 // quote, then this is a lifetime name:
149 '\'' => {
150 return if ptr.next_is_p(is_ident_start) && !ptr.nnext_is('\'') {
151 ptr.bump();
152 while ptr.next_is_p(is_ident_continue) {
153 ptr.bump();
154 }
155 // lifetimes shouldn't end with a single quote
156 // if we find one, then this is an invalid character literal
157 if ptr.next_is('\'') {
158 ptr.bump();
159 return CHAR; // TODO: error reporting
160 }
161 LIFETIME
162 } else {
163 scan_char(ptr);
164 scan_literal_suffix(ptr);
165 CHAR
166 };
167 }
168 'b' => {
169 let kind = scan_byte_char_or_string(ptr);
170 scan_literal_suffix(ptr);
171 return kind;
172 }
173 '"' => {
174 scan_string(ptr);
175 scan_literal_suffix(ptr);
176 return STRING;
177 }
178 'r' => {
179 scan_raw_string(ptr);
180 scan_literal_suffix(ptr);
181 return RAW_STRING;
182 }
183 _ => (),
184 }
185 ERROR
186}
187
188fn scan_ident(c: char, ptr: &mut Ptr) -> SyntaxKind {
189 let is_single_letter = match ptr.next() {
190 None => true,
191 Some(c) if !is_ident_continue(c) => true,
192 _ => false,
193 };
194 if is_single_letter {
195 return if c == '_' { UNDERSCORE } else { IDENT };
196 }
197 ptr.bump_while(is_ident_continue);
198 if let Some(kind) = SyntaxKind::from_keyword(ptr.current_token_text()) {
199 return kind;
200 }
201 IDENT
202}
203
204fn scan_literal_suffix(ptr: &mut Ptr) {
205 if ptr.next_is_p(is_ident_start) {
206 ptr.bump();
207 }
208 ptr.bump_while(is_ident_continue);
209}
diff --git a/crates/libsyntax2/src/lexer/numbers.rs b/crates/libsyntax2/src/lexer/numbers.rs
new file mode 100644
index 000000000..5c4641a2d
--- /dev/null
+++ b/crates/libsyntax2/src/lexer/numbers.rs
@@ -0,0 +1,67 @@
1use lexer::classes::*;
2use lexer::ptr::Ptr;
3
4use SyntaxKind::{self, *};
5
6pub(crate) fn scan_number(c: char, ptr: &mut Ptr) -> SyntaxKind {
7 if c == '0' {
8 match ptr.next().unwrap_or('\0') {
9 'b' | 'o' => {
10 ptr.bump();
11 scan_digits(ptr, false);
12 }
13 'x' => {
14 ptr.bump();
15 scan_digits(ptr, true);
16 }
17 '0'...'9' | '_' | '.' | 'e' | 'E' => {
18 scan_digits(ptr, true);
19 }
20 _ => return INT_NUMBER,
21 }
22 } else {
23 scan_digits(ptr, false);
24 }
25
26 // might be a float, but don't be greedy if this is actually an
27 // integer literal followed by field/method access or a range pattern
28 // (`0..2` and `12.foo()`)
29 if ptr.next_is('.') && !(ptr.nnext_is('.') || ptr.nnext_is_p(is_ident_start)) {
30 // might have stuff after the ., and if it does, it needs to start
31 // with a number
32 ptr.bump();
33 scan_digits(ptr, false);
34 scan_float_exponent(ptr);
35 return FLOAT_NUMBER;
36 }
37 // it might be a float if it has an exponent
38 if ptr.next_is('e') || ptr.next_is('E') {
39 scan_float_exponent(ptr);
40 return FLOAT_NUMBER;
41 }
42 INT_NUMBER
43}
44
45fn scan_digits(ptr: &mut Ptr, allow_hex: bool) {
46 while let Some(c) = ptr.next() {
47 match c {
48 '_' | '0'...'9' => {
49 ptr.bump();
50 }
51 'a'...'f' | 'A'...'F' if allow_hex => {
52 ptr.bump();
53 }
54 _ => return,
55 }
56 }
57}
58
59fn scan_float_exponent(ptr: &mut Ptr) {
60 if ptr.next_is('e') || ptr.next_is('E') {
61 ptr.bump();
62 if ptr.next_is('-') || ptr.next_is('+') {
63 ptr.bump();
64 }
65 scan_digits(ptr, false);
66 }
67}
diff --git a/crates/libsyntax2/src/lexer/ptr.rs b/crates/libsyntax2/src/lexer/ptr.rs
new file mode 100644
index 000000000..d1391fd5f
--- /dev/null
+++ b/crates/libsyntax2/src/lexer/ptr.rs
@@ -0,0 +1,74 @@
1use TextUnit;
2
3use std::str::Chars;
4
5pub(crate) struct Ptr<'s> {
6 text: &'s str,
7 len: TextUnit,
8}
9
10impl<'s> Ptr<'s> {
11 pub fn new(text: &'s str) -> Ptr<'s> {
12 Ptr {
13 text,
14 len: 0.into(),
15 }
16 }
17
18 pub fn into_len(self) -> TextUnit {
19 self.len
20 }
21
22 pub fn next(&self) -> Option<char> {
23 self.chars().next()
24 }
25
26 pub fn nnext(&self) -> Option<char> {
27 let mut chars = self.chars();
28 chars.next()?;
29 chars.next()
30 }
31
32 pub fn next_is(&self, c: char) -> bool {
33 self.next() == Some(c)
34 }
35
36 pub fn nnext_is(&self, c: char) -> bool {
37 self.nnext() == Some(c)
38 }
39
40 pub fn next_is_p<P: Fn(char) -> bool>(&self, p: P) -> bool {
41 self.next().map(p) == Some(true)
42 }
43
44 pub fn nnext_is_p<P: Fn(char) -> bool>(&self, p: P) -> bool {
45 self.nnext().map(p) == Some(true)
46 }
47
48 pub fn bump(&mut self) -> Option<char> {
49 let ch = self.chars().next()?;
50 self.len += TextUnit::of_char(ch);
51 Some(ch)
52 }
53
54 pub fn bump_while<F: Fn(char) -> bool>(&mut self, pred: F) {
55 loop {
56 match self.next() {
57 Some(c) if pred(c) => {
58 self.bump();
59 }
60 _ => return,
61 }
62 }
63 }
64
65 pub fn current_token_text(&self) -> &str {
66 let len: u32 = self.len.into();
67 &self.text[..len as usize]
68 }
69
70 fn chars(&self) -> Chars {
71 let len: u32 = self.len.into();
72 self.text[len as usize..].chars()
73 }
74}
diff --git a/crates/libsyntax2/src/lexer/strings.rs b/crates/libsyntax2/src/lexer/strings.rs
new file mode 100644
index 000000000..e3704fbb3
--- /dev/null
+++ b/crates/libsyntax2/src/lexer/strings.rs
@@ -0,0 +1,106 @@
1use SyntaxKind::{self, *};
2
3use lexer::ptr::Ptr;
4
5pub(crate) fn is_string_literal_start(c: char, c1: Option<char>, c2: Option<char>) -> bool {
6 match (c, c1, c2) {
7 ('r', Some('"'), _)
8 | ('r', Some('#'), _)
9 | ('b', Some('"'), _)
10 | ('b', Some('\''), _)
11 | ('b', Some('r'), Some('"'))
12 | ('b', Some('r'), Some('#')) => true,
13 _ => false,
14 }
15}
16
17pub(crate) fn scan_char(ptr: &mut Ptr) {
18 if ptr.bump().is_none() {
19 return; // TODO: error reporting is upper in the stack
20 }
21 scan_char_or_byte(ptr);
22 if !ptr.next_is('\'') {
23 return; // TODO: error reporting
24 }
25 ptr.bump();
26}
27
28pub(crate) fn scan_byte_char_or_string(ptr: &mut Ptr) -> SyntaxKind {
29 // unwrapping and not-exhaustive match are ok
30 // because of string_literal_start
31 let c = ptr.bump().unwrap();
32 match c {
33 '\'' => {
34 scan_byte(ptr);
35 BYTE
36 }
37 '"' => {
38 scan_byte_string(ptr);
39 BYTE_STRING
40 }
41 'r' => {
42 scan_raw_byte_string(ptr);
43 RAW_BYTE_STRING
44 }
45 _ => unreachable!(),
46 }
47}
48
49pub(crate) fn scan_string(ptr: &mut Ptr) {
50 while let Some(c) = ptr.bump() {
51 if c == '"' {
52 return;
53 }
54 }
55}
56
57pub(crate) fn scan_raw_string(ptr: &mut Ptr) {
58 if !ptr.next_is('"') {
59 return;
60 }
61 ptr.bump();
62
63 while let Some(c) = ptr.bump() {
64 if c == '"' {
65 return;
66 }
67 }
68}
69
70fn scan_byte(ptr: &mut Ptr) {
71 if ptr.next_is('\'') {
72 ptr.bump();
73 return;
74 }
75 ptr.bump();
76 if ptr.next_is('\'') {
77 ptr.bump();
78 return;
79 }
80}
81
82fn scan_byte_string(ptr: &mut Ptr) {
83 while let Some(c) = ptr.bump() {
84 if c == '"' {
85 return;
86 }
87 }
88}
89
90fn scan_raw_byte_string(ptr: &mut Ptr) {
91 if !ptr.next_is('"') {
92 return;
93 }
94 ptr.bump();
95
96 while let Some(c) = ptr.bump() {
97 if c == '"' {
98 return;
99 }
100 }
101}
102
103fn scan_char_or_byte(ptr: &mut Ptr) {
104 //FIXME: deal with escape sequencies
105 ptr.bump();
106}
diff --git a/crates/libsyntax2/src/lib.rs b/crates/libsyntax2/src/lib.rs
new file mode 100644
index 000000000..ca33618a0
--- /dev/null
+++ b/crates/libsyntax2/src/lib.rs
@@ -0,0 +1,55 @@
1//! An experimental implementation of [Rust RFC#2256 libsyntax2.0][rfc#2256].
2//!
3//! The intent is to be an IDE-ready parser, i.e. one that offers
4//!
5//! - easy and fast incremental re-parsing,
6//! - graceful handling of errors, and
7//! - maintains all information in the source file.
8//!
9//! For more information, see [the RFC][rfc#2265], or [the working draft][RFC.md].
10//!
11//! [rfc#2256]: <https://github.com/rust-lang/rfcs/pull/2256>
12//! [RFC.md]: <https://github.com/matklad/libsyntax2/blob/master/docs/RFC.md>
13
14#![forbid(
15 missing_debug_implementations,
16 unconditional_recursion,
17 future_incompatible
18)]
19#![deny(bad_style, missing_docs)]
20#![allow(missing_docs)]
21//#![warn(unreachable_pub)] // rust-lang/rust#47816
22
23extern crate itertools;
24extern crate text_unit;
25extern crate unicode_xid;
26extern crate drop_bomb;
27extern crate parking_lot;
28
29pub mod algo;
30pub mod ast;
31mod lexer;
32#[macro_use]
33mod parser_api;
34mod grammar;
35mod parser_impl;
36
37mod syntax_kinds;
38mod smol_str;
39mod yellow;
40/// Utilities for simple uses of the parser.
41pub mod utils;
42
43pub use {
44 ast::{AstNode, File},
45 lexer::{tokenize, Token},
46 syntax_kinds::SyntaxKind,
47 text_unit::{TextRange, TextUnit},
48 yellow::{SyntaxNode, SyntaxNodeRef, SyntaxRoot, TreeRoot, SyntaxError},
49};
50
51
52pub fn parse(text: &str) -> SyntaxNode {
53 let tokens = tokenize(&text);
54 parser_impl::parse::<yellow::GreenBuilder>(text, &tokens)
55}
diff --git a/crates/libsyntax2/src/parser_api.rs b/crates/libsyntax2/src/parser_api.rs
new file mode 100644
index 000000000..c78c6e43a
--- /dev/null
+++ b/crates/libsyntax2/src/parser_api.rs
@@ -0,0 +1,195 @@
1use {
2 parser_impl::ParserImpl,
3 SyntaxKind::{self, ERROR},
4 drop_bomb::DropBomb,
5};
6
7#[derive(Clone, Copy)]
8pub(crate) struct TokenSet(pub(crate) u128);
9
10fn mask(kind: SyntaxKind) -> u128 {
11 1u128 << (kind as usize)
12}
13
14impl TokenSet {
15 pub fn contains(&self, kind: SyntaxKind) -> bool {
16 self.0 & mask(kind) != 0
17 }
18}
19
20#[macro_export]
21macro_rules! token_set {
22 ($($t:ident),*) => { TokenSet($(1u128 << ($t as usize))|*) };
23 ($($t:ident),* ,) => { token_set!($($t),*) };
24}
25
26#[macro_export]
27macro_rules! token_set_union {
28 ($($ts:expr),*) => { TokenSet($($ts.0)|*) };
29 ($($ts:expr),* ,) => { token_set_union!($($ts),*) };
30}
31
32#[test]
33fn token_set_works_for_tokens() {
34 use SyntaxKind::*;
35 let ts = token_set! { EOF, SHEBANG };
36 assert!(ts.contains(EOF));
37 assert!(ts.contains(SHEBANG));
38 assert!(!ts.contains(PLUS));
39}
40
41/// `Parser` struct provides the low-level API for
42/// navigating through the stream of tokens and
43/// constructing the parse tree. The actual parsing
44/// happens in the `grammar` module.
45///
46/// However, the result of this `Parser` is not a real
47/// tree, but rather a flat stream of events of the form
48/// "start expression, consume number literal,
49/// finish expression". See `Event` docs for more.
50pub(crate) struct Parser<'t>(pub(super) ParserImpl<'t>);
51
52impl<'t> Parser<'t> {
53 /// Returns the kind of the current token.
54 /// If parser has already reached the end of input,
55 /// the special `EOF` kind is returned.
56 pub(crate) fn current(&self) -> SyntaxKind {
57 self.nth(0)
58 }
59
60 /// Lookahead operation: returns the kind of the next nth
61 /// token.
62 pub(crate) fn nth(&self, n: u32) -> SyntaxKind {
63 self.0.nth(n)
64 }
65
66 /// Checks if the current token is `kind`.
67 pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
68 self.current() == kind
69 }
70
71 pub(crate) fn at_compound2(&self, c1: SyntaxKind, c2: SyntaxKind) -> bool {
72 self.0.at_compound2(c1, c2)
73 }
74
75 pub(crate) fn at_compound3(&self, c1: SyntaxKind, c2: SyntaxKind, c3: SyntaxKind) -> bool {
76 self.0.at_compound3(c1, c2, c3)
77 }
78
79 /// Checks if the current token is contextual keyword with text `t`.
80 pub(crate) fn at_contextual_kw(&self, t: &str) -> bool {
81 self.0.at_kw(t)
82 }
83
84 /// Starts a new node in the syntax tree. All nodes and tokens
85 /// consumed between the `start` and the corresponding `Marker::complete`
86 /// belong to the same node.
87 pub(crate) fn start(&mut self) -> Marker {
88 Marker::new(self.0.start())
89 }
90
91 /// Advances the parser by one token.
92 pub(crate) fn bump(&mut self) {
93 self.0.bump();
94 }
95
96 /// Advances the parser by one token, remapping its kind.
97 /// This is useful to create contextual keywords from
98 /// identifiers. For example, the lexer creates an `union`
99 /// *identifier* token, but the parser remaps it to the
100 /// `union` keyword, and keyword is what ends up in the
101 /// final tree.
102 pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) {
103 self.0.bump_remap(kind);
104 }
105
106 /// Advances the parser by `n` tokens, remapping its kind.
107 /// This is useful to create compound tokens from parts. For
108 /// example, an `<<` token is two consecutive remapped `<` tokens
109 pub(crate) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) {
110 self.0.bump_compound(kind, n);
111 }
112
113 /// Emit error with the `message`
114 /// TODO: this should be much more fancy and support
115 /// structured errors with spans and notes, like rustc
116 /// does.
117 pub(crate) fn error<T: Into<String>>(&mut self, message: T) {
118 self.0.error(message.into())
119 }
120
121 /// Consume the next token if it is `kind`.
122 pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
123 if !self.at(kind) {
124 return false;
125 }
126 self.bump();
127 true
128 }
129
130 /// Consume the next token if it is `kind` or emit an error
131 /// otherwise.
132 pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
133 if self.eat(kind) {
134 return true;
135 }
136 self.error(format!("expected {:?}", kind));
137 false
138 }
139
140 /// Create an error node and consume the next token.
141 pub(crate) fn err_and_bump(&mut self, message: &str) {
142 let m = self.start();
143 self.error(message);
144 self.bump();
145 m.complete(self, ERROR);
146 }
147}
148
149/// See `Parser::start`.
150pub(crate) struct Marker {
151 pos: u32,
152 bomb: DropBomb,
153}
154
155impl Marker {
156 fn new(pos: u32) -> Marker {
157 Marker {
158 pos,
159 bomb: DropBomb::new("Marker must be either completed or abandoned"),
160 }
161 }
162
163 /// Finishes the syntax tree node and assigns `kind` to it.
164 pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
165 self.bomb.defuse();
166 p.0.complete(self.pos, kind);
167 CompletedMarker(self.pos, kind)
168 }
169
170 /// Abandons the syntax tree node. All its children
171 /// are attached to its parent instead.
172 pub(crate) fn abandon(mut self, p: &mut Parser) {
173 self.bomb.defuse();
174 p.0.abandon(self.pos);
175 }
176}
177
178pub(crate) struct CompletedMarker(u32, SyntaxKind);
179
180impl CompletedMarker {
181 /// This one is tricky :-)
182 /// This method allows to create a new node which starts
183 /// *before* the current one. That is, parser could start
184 /// node `A`, then complete it, and then after parsing the
185 /// whole `A`, decide that it should have started some node
186 /// `B` before starting `A`. `precede` allows to do exactly
187 /// that. See also docs about `forward_parent` in `Event::Start`.
188 pub(crate) fn precede(self, p: &mut Parser) -> Marker {
189 Marker::new(p.0.precede(self.0))
190 }
191
192 pub(crate) fn kind(&self) -> SyntaxKind {
193 self.1
194 }
195}
diff --git a/crates/libsyntax2/src/parser_impl/event.rs b/crates/libsyntax2/src/parser_impl/event.rs
new file mode 100644
index 000000000..9fd56b996
--- /dev/null
+++ b/crates/libsyntax2/src/parser_impl/event.rs
@@ -0,0 +1,154 @@
1//! This module provides a way to construct a `File`.
2//! It is intended to be completely decoupled from the
3//! parser, so as to allow to evolve the tree representation
4//! and the parser algorithm independently.
5//!
6//! The `Sink` trait is the bridge between the parser and the
7//! tree builder: the parser produces a stream of events like
8//! `start node`, `finish node`, and `FileBuilder` converts
9//! this stream to a real tree.
10use std::mem;
11use {
12 lexer::Token,
13 parser_impl::Sink,
14 SyntaxKind::{self, TOMBSTONE},
15};
16
17
18/// `Parser` produces a flat list of `Event`s.
19/// They are converted to a tree-structure in
20/// a separate pass, via `TreeBuilder`.
21#[derive(Debug)]
22pub(crate) enum Event {
23 /// This event signifies the start of the node.
24 /// It should be either abandoned (in which case the
25 /// `kind` is `TOMBSTONE`, and the event is ignored),
26 /// or completed via a `Finish` event.
27 ///
28 /// All tokens between a `Start` and a `Finish` would
29 /// become the children of the respective node.
30 ///
31 /// For left-recursive syntactic constructs, the parser produces
32 /// a child node before it sees a parent. `forward_parent`
33 /// exists to allow to tweak parent-child relationships.
34 ///
35 /// Consider this path
36 ///
37 /// foo::bar
38 ///
39 /// The events for it would look like this:
40 ///
41 ///
42 /// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
43 /// | /\
44 /// | |
45 /// +------forward-parent------+
46 ///
47 /// And the tree would look like this
48 ///
49 /// +--PATH---------+
50 /// | | |
51 /// | | |
52 /// | '::' 'bar'
53 /// |
54 /// PATH
55 /// |
56 /// 'foo'
57 ///
58 /// See also `CompletedMarker::precede`.
59 Start {
60 kind: SyntaxKind,
61 forward_parent: Option<u32>,
62 },
63
64 /// Complete the previous `Start` event
65 Finish,
66
67 /// Produce a single leaf-element.
68 /// `n_raw_tokens` is used to glue complex contextual tokens.
69 /// For example, lexer tokenizes `>>` as `>`, `>`, and
70 /// `n_raw_tokens = 2` is used to produced a single `>>`.
71 Token {
72 kind: SyntaxKind,
73 n_raw_tokens: u8,
74 },
75
76 Error {
77 msg: String,
78 },
79}
80
81
82pub(super) fn process<'a, S: Sink<'a>>(builder: &mut S, tokens: &[Token], mut events: Vec<Event>) {
83 fn tombstone() -> Event {
84 Event::Start { kind: TOMBSTONE, forward_parent: None }
85 }
86 let eat_ws = |idx: &mut usize, builder: &mut S| {
87 while let Some(token) = tokens.get(*idx) {
88 if !token.kind.is_trivia() {
89 break;
90 }
91 builder.leaf(token.kind, token.len);
92 *idx += 1
93 }
94 };
95
96 let events: &mut [Event] = &mut events;
97 let mut depth = 0;
98 let mut forward_parents = Vec::new();
99 let mut next_tok_idx = 0;
100 for i in 0..events.len() {
101 match mem::replace(&mut events[i], tombstone()) {
102 Event::Start {
103 kind: TOMBSTONE, ..
104 } => (),
105
106 Event::Start { kind, forward_parent } => {
107 forward_parents.push(kind);
108 let mut idx = i;
109 let mut fp = forward_parent;
110 while let Some(fwd) = fp {
111 idx += fwd as usize;
112 fp = match mem::replace(&mut events[idx], tombstone()) {
113 Event::Start {
114 kind,
115 forward_parent,
116 } => {
117 forward_parents.push(kind);
118 forward_parent
119 },
120 _ => unreachable!(),
121 };
122 }
123 for kind in forward_parents.drain(..).rev() {
124 if depth > 0 {
125 eat_ws(&mut next_tok_idx, builder);
126 }
127 depth += 1;
128 builder.start_internal(kind);
129 }
130 }
131 Event::Finish => {
132 depth -= 1;
133 if depth == 0 {
134 eat_ws(&mut next_tok_idx, builder);
135 }
136
137 builder.finish_internal();
138 }
139 Event::Token {
140 kind,
141 mut n_raw_tokens,
142 } => {
143 eat_ws(&mut next_tok_idx, builder);
144 let mut len = 0.into();
145 for _ in 0..n_raw_tokens {
146 len += tokens[next_tok_idx].len;
147 next_tok_idx += 1;
148 }
149 builder.leaf(kind, len);
150 }
151 Event::Error { msg } => builder.error(msg),
152 }
153 }
154}
diff --git a/crates/libsyntax2/src/parser_impl/input.rs b/crates/libsyntax2/src/parser_impl/input.rs
new file mode 100644
index 000000000..c0fe4d488
--- /dev/null
+++ b/crates/libsyntax2/src/parser_impl/input.rs
@@ -0,0 +1,86 @@
1use {lexer::Token, SyntaxKind, SyntaxKind::EOF, TextRange, TextUnit};
2
3use std::ops::{Add, AddAssign};
4
5pub(crate) struct ParserInput<'t> {
6 text: &'t str,
7 start_offsets: Vec<TextUnit>,
8 tokens: Vec<Token>, // non-whitespace tokens
9}
10
11impl<'t> ParserInput<'t> {
12 pub fn new(text: &'t str, raw_tokens: &'t [Token]) -> ParserInput<'t> {
13 let mut tokens = Vec::new();
14 let mut start_offsets = Vec::new();
15 let mut len = 0.into();
16 for &token in raw_tokens.iter() {
17 if !token.kind.is_trivia() {
18 tokens.push(token);
19 start_offsets.push(len);
20 }
21 len += token.len;
22 }
23
24 ParserInput {
25 text,
26 start_offsets,
27 tokens,
28 }
29 }
30
31 pub fn kind(&self, pos: InputPosition) -> SyntaxKind {
32 let idx = pos.0 as usize;
33 if !(idx < self.tokens.len()) {
34 return EOF;
35 }
36 self.tokens[idx].kind
37 }
38
39 pub fn len(&self, pos: InputPosition) -> TextUnit {
40 let idx = pos.0 as usize;
41 if !(idx < self.tokens.len()) {
42 return 0.into();
43 }
44 self.tokens[idx].len
45 }
46
47 pub fn start(&self, pos: InputPosition) -> TextUnit {
48 let idx = pos.0 as usize;
49 if !(idx < self.tokens.len()) {
50 return 0.into();
51 }
52 self.start_offsets[idx]
53 }
54
55 pub fn text(&self, pos: InputPosition) -> &'t str {
56 let idx = pos.0 as usize;
57 if !(idx < self.tokens.len()) {
58 return "";
59 }
60 let range = TextRange::offset_len(self.start_offsets[idx], self.tokens[idx].len);
61 &self.text[range]
62 }
63}
64
65#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
66pub(crate) struct InputPosition(u32);
67
68impl InputPosition {
69 pub fn new() -> Self {
70 InputPosition(0)
71 }
72}
73
74impl Add<u32> for InputPosition {
75 type Output = InputPosition;
76
77 fn add(self, rhs: u32) -> InputPosition {
78 InputPosition(self.0 + rhs)
79 }
80}
81
82impl AddAssign<u32> for InputPosition {
83 fn add_assign(&mut self, rhs: u32) {
84 self.0 += rhs
85 }
86}
diff --git a/crates/libsyntax2/src/parser_impl/mod.rs b/crates/libsyntax2/src/parser_impl/mod.rs
new file mode 100644
index 000000000..06c16cdb4
--- /dev/null
+++ b/crates/libsyntax2/src/parser_impl/mod.rs
@@ -0,0 +1,170 @@
1mod event;
2mod input;
3
4use {
5 grammar,
6 lexer::Token,
7 parser_api::Parser,
8 parser_impl::{
9 event::{process, Event},
10 input::{InputPosition, ParserInput},
11 },
12 TextUnit,
13};
14
15use SyntaxKind::{self, EOF, TOMBSTONE};
16
17pub(crate) trait Sink<'a> {
18 type Tree;
19
20 fn new(text: &'a str) -> Self;
21
22 fn leaf(&mut self, kind: SyntaxKind, len: TextUnit);
23 fn start_internal(&mut self, kind: SyntaxKind);
24 fn finish_internal(&mut self);
25 fn error(&mut self, err: String);
26 fn finish(self) -> Self::Tree;
27}
28
29/// Parse a sequence of tokens into the representative node tree
30pub(crate) fn parse<'a, S: Sink<'a>>(text: &'a str, tokens: &[Token]) -> S::Tree {
31 let events = {
32 let input = input::ParserInput::new(text, tokens);
33 let parser_impl = ParserImpl::new(&input);
34 let mut parser_api = Parser(parser_impl);
35 grammar::file(&mut parser_api);
36 parser_api.0.into_events()
37 };
38 let mut sink = S::new(text);
39 process(&mut sink, tokens, events);
40 sink.finish()
41}
42
43/// Implementation details of `Parser`, extracted
44/// to a separate struct in order not to pollute
45/// the public API of the `Parser`.
46pub(crate) struct ParserImpl<'t> {
47 inp: &'t ParserInput<'t>,
48
49 pos: InputPosition,
50 events: Vec<Event>,
51}
52
53impl<'t> ParserImpl<'t> {
54 pub(crate) fn new(inp: &'t ParserInput<'t>) -> ParserImpl<'t> {
55 ParserImpl {
56 inp,
57
58 pos: InputPosition::new(),
59 events: Vec::new(),
60 }
61 }
62
63 pub(crate) fn into_events(self) -> Vec<Event> {
64 assert_eq!(self.nth(0), EOF);
65 self.events
66 }
67
68 pub(super) fn at_compound2(&self, c1: SyntaxKind, c2: SyntaxKind) -> bool {
69 self.inp.kind(self.pos) == c1 && self.inp.kind(self.pos + 1) == c2
70 && self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos)
71 }
72
73 pub(super) fn at_compound3(&self, c1: SyntaxKind, c2: SyntaxKind, c3: SyntaxKind) -> bool {
74 self.inp.kind(self.pos) == c1 && self.inp.kind(self.pos + 1) == c2 && self.inp.kind(self.pos + 2) == c3
75 && self.inp.start(self.pos + 1) == self.inp.start(self.pos) + self.inp.len(self.pos)
76 && self.inp.start(self.pos + 2) == self.inp.start(self.pos + 1) + self.inp.len(self.pos + 1)
77 }
78
79 pub(super) fn nth(&self, n: u32) -> SyntaxKind {
80 self.inp.kind(self.pos + n)
81 }
82
83 pub(super) fn at_kw(&self, t: &str) -> bool {
84 self.inp.text(self.pos) == t
85 }
86
87 pub(super) fn start(&mut self) -> u32 {
88 let pos = self.events.len() as u32;
89 self.event(Event::Start {
90 kind: TOMBSTONE,
91 forward_parent: None,
92 });
93 pos
94 }
95
96 pub(super) fn bump(&mut self) {
97 let kind = self.nth(0);
98 if kind == EOF {
99 return;
100 }
101 self.do_bump(kind, 1);
102 }
103
104 pub(super) fn bump_remap(&mut self, kind: SyntaxKind) {
105 if self.nth(0) == EOF {
106 // TODO: panic!?
107 return;
108 }
109 self.do_bump(kind, 1);
110 }
111
112 pub(super) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) {
113 self.do_bump(kind, n);
114 }
115
116 fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
117 self.pos += u32::from(n_raw_tokens);
118 self.event(Event::Token {
119 kind,
120 n_raw_tokens,
121 });
122 }
123
124 pub(super) fn error(&mut self, msg: String) {
125 self.event(Event::Error { msg })
126 }
127
128 pub(super) fn complete(&mut self, pos: u32, kind: SyntaxKind) {
129 match self.events[pos as usize] {
130 Event::Start {
131 kind: ref mut slot, ..
132 } => {
133 *slot = kind;
134 }
135 _ => unreachable!(),
136 }
137 self.event(Event::Finish);
138 }
139
140 pub(super) fn abandon(&mut self, pos: u32) {
141 let idx = pos as usize;
142 if idx == self.events.len() - 1 {
143 match self.events.pop() {
144 Some(Event::Start {
145 kind: TOMBSTONE,
146 forward_parent: None,
147 }) => (),
148 _ => unreachable!(),
149 }
150 }
151 }
152
153 pub(super) fn precede(&mut self, pos: u32) -> u32 {
154 let new_pos = self.start();
155 match self.events[pos as usize] {
156 Event::Start {
157 ref mut forward_parent,
158 ..
159 } => {
160 *forward_parent = Some(new_pos - pos);
161 }
162 _ => unreachable!(),
163 }
164 new_pos
165 }
166
167 fn event(&mut self, event: Event) {
168 self.events.push(event)
169 }
170}
diff --git a/crates/libsyntax2/src/smol_str.rs b/crates/libsyntax2/src/smol_str.rs
new file mode 100644
index 000000000..abf69dce7
--- /dev/null
+++ b/crates/libsyntax2/src/smol_str.rs
@@ -0,0 +1,83 @@
1use std::{sync::Arc};
2
3const INLINE_CAP: usize = 22;
4const WS_TAG: u8 = (INLINE_CAP + 1) as u8;
5
6#[derive(Clone, Debug)]
7pub(crate) enum SmolStr {
8 Heap(Arc<str>),
9 Inline {
10 len: u8,
11 buf: [u8; INLINE_CAP],
12 },
13}
14
15impl SmolStr {
16 pub fn new(text: &str) -> SmolStr {
17 let len = text.len();
18 if len <= INLINE_CAP {
19 let mut buf = [0; INLINE_CAP];
20 buf[..len].copy_from_slice(text.as_bytes());
21 return SmolStr::Inline { len: len as u8, buf };
22 }
23
24 let newlines = text.bytes().take_while(|&b| b == b'\n').count();
25 let spaces = text[newlines..].bytes().take_while(|&b| b == b' ').count();
26 if newlines + spaces == len && newlines <= N_NEWLINES && spaces <= N_SPACES {
27 let mut buf = [0; INLINE_CAP];
28 buf[0] = newlines as u8;
29 buf[1] = spaces as u8;
30 return SmolStr::Inline { len: WS_TAG, buf };
31 }
32
33 SmolStr::Heap(
34 text.to_string().into_boxed_str().into()
35 )
36 }
37
38 pub fn as_str(&self) -> &str {
39 match self {
40 SmolStr::Heap(data) => &*data,
41 SmolStr::Inline { len, buf } => {
42 if *len == WS_TAG {
43 let newlines = buf[0] as usize;
44 let spaces = buf[1] as usize;
45 assert!(newlines <= N_NEWLINES && spaces <= N_SPACES);
46 return &WS[N_NEWLINES - newlines..N_NEWLINES + spaces]
47 }
48
49 let len = *len as usize;
50 let buf = &buf[..len];
51 unsafe { ::std::str::from_utf8_unchecked(buf) }
52 }
53 }
54 }
55}
56
57const N_NEWLINES: usize = 32;
58const N_SPACES: usize = 128;
59const WS: &str =
60 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n ";
61
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 #[cfg(target_pointer_width = "64")]
69 fn smol_str_is_smol() {
70 assert_eq!(::std::mem::size_of::<SmolStr>(), 8 + 8 + 8)
71 }
72
73 #[test]
74 fn test_round_trip() {
75 let mut text = String::new();
76 for n in 0..256 {
77 let smol = SmolStr::new(&text);
78 assert_eq!(smol.as_str(), text.as_str());
79 text.push_str(&n.to_string());
80 }
81 }
82}
83
diff --git a/crates/libsyntax2/src/syntax_kinds/generated.rs b/crates/libsyntax2/src/syntax_kinds/generated.rs
new file mode 100644
index 000000000..de2807ba6
--- /dev/null
+++ b/crates/libsyntax2/src/syntax_kinds/generated.rs
@@ -0,0 +1,508 @@
1#![allow(bad_style, missing_docs, unreachable_pub)]
2#![cfg_attr(rustfmt, rustfmt_skip)]
3use super::SyntaxInfo;
4
5/// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`.
6#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum SyntaxKind {
8 // Technical SyntaxKinds: they appear temporally during parsing,
9 // but never end up in the final tree
10 #[doc(hidden)]
11 TOMBSTONE,
12 #[doc(hidden)]
13 EOF,
14 SEMI,
15 COMMA,
16 L_PAREN,
17 R_PAREN,
18 L_CURLY,
19 R_CURLY,
20 L_BRACK,
21 R_BRACK,
22 L_ANGLE,
23 R_ANGLE,
24 AT,
25 POUND,
26 TILDE,
27 QUESTION,
28 DOLLAR,
29 AMP,
30 PIPE,
31 PLUS,
32 STAR,
33 SLASH,
34 CARET,
35 PERCENT,
36 DOT,
37 DOTDOT,
38 DOTDOTDOT,
39 DOTDOTEQ,
40 COLON,
41 COLONCOLON,
42 EQ,
43 EQEQ,
44 FAT_ARROW,
45 EXCL,
46 NEQ,
47 MINUS,
48 THIN_ARROW,
49 LTEQ,
50 GTEQ,
51 PLUSEQ,
52 MINUSEQ,
53 AMPAMP,
54 PIPEPIPE,
55 SHL,
56 SHR,
57 SHLEQ,
58 SHREQ,
59 USE_KW,
60 FN_KW,
61 STRUCT_KW,
62 ENUM_KW,
63 TRAIT_KW,
64 IMPL_KW,
65 TRUE_KW,
66 FALSE_KW,
67 AS_KW,
68 EXTERN_KW,
69 CRATE_KW,
70 MOD_KW,
71 PUB_KW,
72 SELF_KW,
73 SUPER_KW,
74 IN_KW,
75 WHERE_KW,
76 FOR_KW,
77 LOOP_KW,
78 WHILE_KW,
79 IF_KW,
80 ELSE_KW,
81 MATCH_KW,
82 CONST_KW,
83 STATIC_KW,
84 MUT_KW,
85 UNSAFE_KW,
86 TYPE_KW,
87 REF_KW,
88 LET_KW,
89 MOVE_KW,
90 RETURN_KW,
91 AUTO_KW,
92 DEFAULT_KW,
93 UNION_KW,
94 ERROR,
95 IDENT,
96 UNDERSCORE,
97 WHITESPACE,
98 INT_NUMBER,
99 FLOAT_NUMBER,
100 LIFETIME,
101 CHAR,
102 BYTE,
103 STRING,
104 RAW_STRING,
105 BYTE_STRING,
106 RAW_BYTE_STRING,
107 COMMENT,
108 DOC_COMMENT,
109 SHEBANG,
110 FILE,
111 STRUCT_ITEM,
112 ENUM_ITEM,
113 FUNCTION,
114 EXTERN_CRATE_ITEM,
115 MOD_ITEM,
116 USE_ITEM,
117 STATIC_ITEM,
118 CONST_ITEM,
119 TRAIT_ITEM,
120 IMPL_ITEM,
121 TYPE_ITEM,
122 MACRO_CALL,
123 TOKEN_TREE,
124 PAREN_TYPE,
125 TUPLE_TYPE,
126 NEVER_TYPE,
127 PATH_TYPE,
128 POINTER_TYPE,
129 ARRAY_TYPE,
130 SLICE_TYPE,
131 REFERENCE_TYPE,
132 PLACEHOLDER_TYPE,
133 FN_POINTER_TYPE,
134 FOR_TYPE,
135 IMPL_TRAIT_TYPE,
136 REF_PAT,
137 BIND_PAT,
138 PLACEHOLDER_PAT,
139 PATH_PAT,
140 STRUCT_PAT,
141 TUPLE_STRUCT_PAT,
142 TUPLE_PAT,
143 SLICE_PAT,
144 RANGE_PAT,
145 TUPLE_EXPR,
146 ARRAY_EXPR,
147 PAREN_EXPR,
148 PATH_EXPR,
149 LAMBDA_EXPR,
150 IF_EXPR,
151 WHILE_EXPR,
152 LOOP_EXPR,
153 FOR_EXPR,
154 BLOCK_EXPR,
155 RETURN_EXPR,
156 MATCH_EXPR,
157 MATCH_ARM,
158 MATCH_GUARD,
159 STRUCT_LIT,
160 STRUCT_LIT_FIELD,
161 CALL_EXPR,
162 INDEX_EXPR,
163 METHOD_CALL_EXPR,
164 FIELD_EXPR,
165 TRY_EXPR,
166 CAST_EXPR,
167 REF_EXPR,
168 PREFIX_EXPR,
169 RANGE_EXPR,
170 BIN_EXPR,
171 EXTERN_BLOCK_EXPR,
172 ENUM_VARIANT,
173 NAMED_FIELD,
174 POS_FIELD,
175 ATTR,
176 META_ITEM,
177 USE_TREE,
178 PATH,
179 PATH_SEGMENT,
180 LITERAL,
181 ALIAS,
182 VISIBILITY,
183 WHERE_CLAUSE,
184 WHERE_PRED,
185 ABI,
186 NAME,
187 NAME_REF,
188 LET_STMT,
189 EXPR_STMT,
190 TYPE_PARAM_LIST,
191 LIFETIME_PARAM,
192 TYPE_PARAM,
193 TYPE_ARG_LIST,
194 LIFETIME_ARG,
195 TYPE_ARG,
196 ASSOC_TYPE_ARG,
197 PARAM_LIST,
198 PARAM,
199 SELF_PARAM,
200 ARG_LIST,
201}
202use self::SyntaxKind::*;
203
204impl SyntaxKind {
205 pub fn is_keyword(self) -> bool {
206 match self {
207 | USE_KW
208 | FN_KW
209 | STRUCT_KW
210 | ENUM_KW
211 | TRAIT_KW
212 | IMPL_KW
213 | TRUE_KW
214 | FALSE_KW
215 | AS_KW
216 | EXTERN_KW
217 | CRATE_KW
218 | MOD_KW
219 | PUB_KW
220 | SELF_KW
221 | SUPER_KW
222 | IN_KW
223 | WHERE_KW
224 | FOR_KW
225 | LOOP_KW
226 | WHILE_KW
227 | IF_KW
228 | ELSE_KW
229 | MATCH_KW
230 | CONST_KW
231 | STATIC_KW
232 | MUT_KW
233 | UNSAFE_KW
234 | TYPE_KW
235 | REF_KW
236 | LET_KW
237 | MOVE_KW
238 | RETURN_KW
239 | AUTO_KW
240 | DEFAULT_KW
241 | UNION_KW
242 => true,
243 _ => false
244 }
245 }
246
247 pub(crate) fn info(self) -> &'static SyntaxInfo {
248 match self {
249 SEMI => &SyntaxInfo { name: "SEMI" },
250 COMMA => &SyntaxInfo { name: "COMMA" },
251 L_PAREN => &SyntaxInfo { name: "L_PAREN" },
252 R_PAREN => &SyntaxInfo { name: "R_PAREN" },
253 L_CURLY => &SyntaxInfo { name: "L_CURLY" },
254 R_CURLY => &SyntaxInfo { name: "R_CURLY" },
255 L_BRACK => &SyntaxInfo { name: "L_BRACK" },
256 R_BRACK => &SyntaxInfo { name: "R_BRACK" },
257 L_ANGLE => &SyntaxInfo { name: "L_ANGLE" },
258 R_ANGLE => &SyntaxInfo { name: "R_ANGLE" },
259 AT => &SyntaxInfo { name: "AT" },
260 POUND => &SyntaxInfo { name: "POUND" },
261 TILDE => &SyntaxInfo { name: "TILDE" },
262 QUESTION => &SyntaxInfo { name: "QUESTION" },
263 DOLLAR => &SyntaxInfo { name: "DOLLAR" },
264 AMP => &SyntaxInfo { name: "AMP" },
265 PIPE => &SyntaxInfo { name: "PIPE" },
266 PLUS => &SyntaxInfo { name: "PLUS" },
267 STAR => &SyntaxInfo { name: "STAR" },
268 SLASH => &SyntaxInfo { name: "SLASH" },
269 CARET => &SyntaxInfo { name: "CARET" },
270 PERCENT => &SyntaxInfo { name: "PERCENT" },
271 DOT => &SyntaxInfo { name: "DOT" },
272 DOTDOT => &SyntaxInfo { name: "DOTDOT" },
273 DOTDOTDOT => &SyntaxInfo { name: "DOTDOTDOT" },
274 DOTDOTEQ => &SyntaxInfo { name: "DOTDOTEQ" },
275 COLON => &SyntaxInfo { name: "COLON" },
276 COLONCOLON => &SyntaxInfo { name: "COLONCOLON" },
277 EQ => &SyntaxInfo { name: "EQ" },
278 EQEQ => &SyntaxInfo { name: "EQEQ" },
279 FAT_ARROW => &SyntaxInfo { name: "FAT_ARROW" },
280 EXCL => &SyntaxInfo { name: "EXCL" },
281 NEQ => &SyntaxInfo { name: "NEQ" },
282 MINUS => &SyntaxInfo { name: "MINUS" },
283 THIN_ARROW => &SyntaxInfo { name: "THIN_ARROW" },
284 LTEQ => &SyntaxInfo { name: "LTEQ" },
285 GTEQ => &SyntaxInfo { name: "GTEQ" },
286 PLUSEQ => &SyntaxInfo { name: "PLUSEQ" },
287 MINUSEQ => &SyntaxInfo { name: "MINUSEQ" },
288 AMPAMP => &SyntaxInfo { name: "AMPAMP" },
289 PIPEPIPE => &SyntaxInfo { name: "PIPEPIPE" },
290 SHL => &SyntaxInfo { name: "SHL" },
291 SHR => &SyntaxInfo { name: "SHR" },
292 SHLEQ => &SyntaxInfo { name: "SHLEQ" },
293 SHREQ => &SyntaxInfo { name: "SHREQ" },
294 USE_KW => &SyntaxInfo { name: "USE_KW" },
295 FN_KW => &SyntaxInfo { name: "FN_KW" },
296 STRUCT_KW => &SyntaxInfo { name: "STRUCT_KW" },
297 ENUM_KW => &SyntaxInfo { name: "ENUM_KW" },
298 TRAIT_KW => &SyntaxInfo { name: "TRAIT_KW" },
299 IMPL_KW => &SyntaxInfo { name: "IMPL_KW" },
300 TRUE_KW => &SyntaxInfo { name: "TRUE_KW" },
301 FALSE_KW => &SyntaxInfo { name: "FALSE_KW" },
302 AS_KW => &SyntaxInfo { name: "AS_KW" },
303 EXTERN_KW => &SyntaxInfo { name: "EXTERN_KW" },
304 CRATE_KW => &SyntaxInfo { name: "CRATE_KW" },
305 MOD_KW => &SyntaxInfo { name: "MOD_KW" },
306 PUB_KW => &SyntaxInfo { name: "PUB_KW" },
307 SELF_KW => &SyntaxInfo { name: "SELF_KW" },
308 SUPER_KW => &SyntaxInfo { name: "SUPER_KW" },
309 IN_KW => &SyntaxInfo { name: "IN_KW" },
310 WHERE_KW => &SyntaxInfo { name: "WHERE_KW" },
311 FOR_KW => &SyntaxInfo { name: "FOR_KW" },
312 LOOP_KW => &SyntaxInfo { name: "LOOP_KW" },
313 WHILE_KW => &SyntaxInfo { name: "WHILE_KW" },
314 IF_KW => &SyntaxInfo { name: "IF_KW" },
315 ELSE_KW => &SyntaxInfo { name: "ELSE_KW" },
316 MATCH_KW => &SyntaxInfo { name: "MATCH_KW" },
317 CONST_KW => &SyntaxInfo { name: "CONST_KW" },
318 STATIC_KW => &SyntaxInfo { name: "STATIC_KW" },
319 MUT_KW => &SyntaxInfo { name: "MUT_KW" },
320 UNSAFE_KW => &SyntaxInfo { name: "UNSAFE_KW" },
321 TYPE_KW => &SyntaxInfo { name: "TYPE_KW" },
322 REF_KW => &SyntaxInfo { name: "REF_KW" },
323 LET_KW => &SyntaxInfo { name: "LET_KW" },
324 MOVE_KW => &SyntaxInfo { name: "MOVE_KW" },
325 RETURN_KW => &SyntaxInfo { name: "RETURN_KW" },
326 AUTO_KW => &SyntaxInfo { name: "AUTO_KW" },
327 DEFAULT_KW => &SyntaxInfo { name: "DEFAULT_KW" },
328 UNION_KW => &SyntaxInfo { name: "UNION_KW" },
329 ERROR => &SyntaxInfo { name: "ERROR" },
330 IDENT => &SyntaxInfo { name: "IDENT" },
331 UNDERSCORE => &SyntaxInfo { name: "UNDERSCORE" },
332 WHITESPACE => &SyntaxInfo { name: "WHITESPACE" },
333 INT_NUMBER => &SyntaxInfo { name: "INT_NUMBER" },
334 FLOAT_NUMBER => &SyntaxInfo { name: "FLOAT_NUMBER" },
335 LIFETIME => &SyntaxInfo { name: "LIFETIME" },
336 CHAR => &SyntaxInfo { name: "CHAR" },
337 BYTE => &SyntaxInfo { name: "BYTE" },
338 STRING => &SyntaxInfo { name: "STRING" },
339 RAW_STRING => &SyntaxInfo { name: "RAW_STRING" },
340 BYTE_STRING => &SyntaxInfo { name: "BYTE_STRING" },
341 RAW_BYTE_STRING => &SyntaxInfo { name: "RAW_BYTE_STRING" },
342 COMMENT => &SyntaxInfo { name: "COMMENT" },
343 DOC_COMMENT => &SyntaxInfo { name: "DOC_COMMENT" },
344 SHEBANG => &SyntaxInfo { name: "SHEBANG" },
345 FILE => &SyntaxInfo { name: "FILE" },
346 STRUCT_ITEM => &SyntaxInfo { name: "STRUCT_ITEM" },
347 ENUM_ITEM => &SyntaxInfo { name: "ENUM_ITEM" },
348 FUNCTION => &SyntaxInfo { name: "FUNCTION" },
349 EXTERN_CRATE_ITEM => &SyntaxInfo { name: "EXTERN_CRATE_ITEM" },
350 MOD_ITEM => &SyntaxInfo { name: "MOD_ITEM" },
351 USE_ITEM => &SyntaxInfo { name: "USE_ITEM" },
352 STATIC_ITEM => &SyntaxInfo { name: "STATIC_ITEM" },
353 CONST_ITEM => &SyntaxInfo { name: "CONST_ITEM" },
354 TRAIT_ITEM => &SyntaxInfo { name: "TRAIT_ITEM" },
355 IMPL_ITEM => &SyntaxInfo { name: "IMPL_ITEM" },
356 TYPE_ITEM => &SyntaxInfo { name: "TYPE_ITEM" },
357 MACRO_CALL => &SyntaxInfo { name: "MACRO_CALL" },
358 TOKEN_TREE => &SyntaxInfo { name: "TOKEN_TREE" },
359 PAREN_TYPE => &SyntaxInfo { name: "PAREN_TYPE" },
360 TUPLE_TYPE => &SyntaxInfo { name: "TUPLE_TYPE" },
361 NEVER_TYPE => &SyntaxInfo { name: "NEVER_TYPE" },
362 PATH_TYPE => &SyntaxInfo { name: "PATH_TYPE" },
363 POINTER_TYPE => &SyntaxInfo { name: "POINTER_TYPE" },
364 ARRAY_TYPE => &SyntaxInfo { name: "ARRAY_TYPE" },
365 SLICE_TYPE => &SyntaxInfo { name: "SLICE_TYPE" },
366 REFERENCE_TYPE => &SyntaxInfo { name: "REFERENCE_TYPE" },
367 PLACEHOLDER_TYPE => &SyntaxInfo { name: "PLACEHOLDER_TYPE" },
368 FN_POINTER_TYPE => &SyntaxInfo { name: "FN_POINTER_TYPE" },
369 FOR_TYPE => &SyntaxInfo { name: "FOR_TYPE" },
370 IMPL_TRAIT_TYPE => &SyntaxInfo { name: "IMPL_TRAIT_TYPE" },
371 REF_PAT => &SyntaxInfo { name: "REF_PAT" },
372 BIND_PAT => &SyntaxInfo { name: "BIND_PAT" },
373 PLACEHOLDER_PAT => &SyntaxInfo { name: "PLACEHOLDER_PAT" },
374 PATH_PAT => &SyntaxInfo { name: "PATH_PAT" },
375 STRUCT_PAT => &SyntaxInfo { name: "STRUCT_PAT" },
376 TUPLE_STRUCT_PAT => &SyntaxInfo { name: "TUPLE_STRUCT_PAT" },
377 TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" },
378 SLICE_PAT => &SyntaxInfo { name: "SLICE_PAT" },
379 RANGE_PAT => &SyntaxInfo { name: "RANGE_PAT" },
380 TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" },
381 ARRAY_EXPR => &SyntaxInfo { name: "ARRAY_EXPR" },
382 PAREN_EXPR => &SyntaxInfo { name: "PAREN_EXPR" },
383 PATH_EXPR => &SyntaxInfo { name: "PATH_EXPR" },
384 LAMBDA_EXPR => &SyntaxInfo { name: "LAMBDA_EXPR" },
385 IF_EXPR => &SyntaxInfo { name: "IF_EXPR" },
386 WHILE_EXPR => &SyntaxInfo { name: "WHILE_EXPR" },
387 LOOP_EXPR => &SyntaxInfo { name: "LOOP_EXPR" },
388 FOR_EXPR => &SyntaxInfo { name: "FOR_EXPR" },
389 BLOCK_EXPR => &SyntaxInfo { name: "BLOCK_EXPR" },
390 RETURN_EXPR => &SyntaxInfo { name: "RETURN_EXPR" },
391 MATCH_EXPR => &SyntaxInfo { name: "MATCH_EXPR" },
392 MATCH_ARM => &SyntaxInfo { name: "MATCH_ARM" },
393 MATCH_GUARD => &SyntaxInfo { name: "MATCH_GUARD" },
394 STRUCT_LIT => &SyntaxInfo { name: "STRUCT_LIT" },
395 STRUCT_LIT_FIELD => &SyntaxInfo { name: "STRUCT_LIT_FIELD" },
396 CALL_EXPR => &SyntaxInfo { name: "CALL_EXPR" },
397 INDEX_EXPR => &SyntaxInfo { name: "INDEX_EXPR" },
398 METHOD_CALL_EXPR => &SyntaxInfo { name: "METHOD_CALL_EXPR" },
399 FIELD_EXPR => &SyntaxInfo { name: "FIELD_EXPR" },
400 TRY_EXPR => &SyntaxInfo { name: "TRY_EXPR" },
401 CAST_EXPR => &SyntaxInfo { name: "CAST_EXPR" },
402 REF_EXPR => &SyntaxInfo { name: "REF_EXPR" },
403 PREFIX_EXPR => &SyntaxInfo { name: "PREFIX_EXPR" },
404 RANGE_EXPR => &SyntaxInfo { name: "RANGE_EXPR" },
405 BIN_EXPR => &SyntaxInfo { name: "BIN_EXPR" },
406 EXTERN_BLOCK_EXPR => &SyntaxInfo { name: "EXTERN_BLOCK_EXPR" },
407 ENUM_VARIANT => &SyntaxInfo { name: "ENUM_VARIANT" },
408 NAMED_FIELD => &SyntaxInfo { name: "NAMED_FIELD" },
409 POS_FIELD => &SyntaxInfo { name: "POS_FIELD" },
410 ATTR => &SyntaxInfo { name: "ATTR" },
411 META_ITEM => &SyntaxInfo { name: "META_ITEM" },
412 USE_TREE => &SyntaxInfo { name: "USE_TREE" },
413 PATH => &SyntaxInfo { name: "PATH" },
414 PATH_SEGMENT => &SyntaxInfo { name: "PATH_SEGMENT" },
415 LITERAL => &SyntaxInfo { name: "LITERAL" },
416 ALIAS => &SyntaxInfo { name: "ALIAS" },
417 VISIBILITY => &SyntaxInfo { name: "VISIBILITY" },
418 WHERE_CLAUSE => &SyntaxInfo { name: "WHERE_CLAUSE" },
419 WHERE_PRED => &SyntaxInfo { name: "WHERE_PRED" },
420 ABI => &SyntaxInfo { name: "ABI" },
421 NAME => &SyntaxInfo { name: "NAME" },
422 NAME_REF => &SyntaxInfo { name: "NAME_REF" },
423 LET_STMT => &SyntaxInfo { name: "LET_STMT" },
424 EXPR_STMT => &SyntaxInfo { name: "EXPR_STMT" },
425 TYPE_PARAM_LIST => &SyntaxInfo { name: "TYPE_PARAM_LIST" },
426 LIFETIME_PARAM => &SyntaxInfo { name: "LIFETIME_PARAM" },
427 TYPE_PARAM => &SyntaxInfo { name: "TYPE_PARAM" },
428 TYPE_ARG_LIST => &SyntaxInfo { name: "TYPE_ARG_LIST" },
429 LIFETIME_ARG => &SyntaxInfo { name: "LIFETIME_ARG" },
430 TYPE_ARG => &SyntaxInfo { name: "TYPE_ARG" },
431 ASSOC_TYPE_ARG => &SyntaxInfo { name: "ASSOC_TYPE_ARG" },
432 PARAM_LIST => &SyntaxInfo { name: "PARAM_LIST" },
433 PARAM => &SyntaxInfo { name: "PARAM" },
434 SELF_PARAM => &SyntaxInfo { name: "SELF_PARAM" },
435 ARG_LIST => &SyntaxInfo { name: "ARG_LIST" },
436 TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" },
437 EOF => &SyntaxInfo { name: "EOF" },
438 }
439 }
440 pub(crate) fn from_keyword(ident: &str) -> Option<SyntaxKind> {
441 let kw = match ident {
442 "use" => USE_KW,
443 "fn" => FN_KW,
444 "struct" => STRUCT_KW,
445 "enum" => ENUM_KW,
446 "trait" => TRAIT_KW,
447 "impl" => IMPL_KW,
448 "true" => TRUE_KW,
449 "false" => FALSE_KW,
450 "as" => AS_KW,
451 "extern" => EXTERN_KW,
452 "crate" => CRATE_KW,
453 "mod" => MOD_KW,
454 "pub" => PUB_KW,
455 "self" => SELF_KW,
456 "super" => SUPER_KW,
457 "in" => IN_KW,
458 "where" => WHERE_KW,
459 "for" => FOR_KW,
460 "loop" => LOOP_KW,
461 "while" => WHILE_KW,
462 "if" => IF_KW,
463 "else" => ELSE_KW,
464 "match" => MATCH_KW,
465 "const" => CONST_KW,
466 "static" => STATIC_KW,
467 "mut" => MUT_KW,
468 "unsafe" => UNSAFE_KW,
469 "type" => TYPE_KW,
470 "ref" => REF_KW,
471 "let" => LET_KW,
472 "move" => MOVE_KW,
473 "return" => RETURN_KW,
474 _ => return None,
475 };
476 Some(kw)
477 }
478
479 pub(crate) fn from_char(c: char) -> Option<SyntaxKind> {
480 let tok = match c {
481 ';' => SEMI,
482 ',' => COMMA,
483 '(' => L_PAREN,
484 ')' => R_PAREN,
485 '{' => L_CURLY,
486 '}' => R_CURLY,
487 '[' => L_BRACK,
488 ']' => R_BRACK,
489 '<' => L_ANGLE,
490 '>' => R_ANGLE,
491 '@' => AT,
492 '#' => POUND,
493 '~' => TILDE,
494 '?' => QUESTION,
495 '$' => DOLLAR,
496 '&' => AMP,
497 '|' => PIPE,
498 '+' => PLUS,
499 '*' => STAR,
500 '/' => SLASH,
501 '^' => CARET,
502 '%' => PERCENT,
503 _ => return None,
504 };
505 Some(tok)
506 }
507}
508
diff --git a/crates/libsyntax2/src/syntax_kinds/generated.rs.tera b/crates/libsyntax2/src/syntax_kinds/generated.rs.tera
new file mode 100644
index 000000000..90618721a
--- /dev/null
+++ b/crates/libsyntax2/src/syntax_kinds/generated.rs.tera
@@ -0,0 +1,73 @@
1#![allow(bad_style, missing_docs, unreachable_pub)]
2#![cfg_attr(rustfmt, rustfmt_skip)]
3use super::SyntaxInfo;
4
5/// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`.
6#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum SyntaxKind {
8 // Technical SyntaxKinds: they appear temporally during parsing,
9 // but never end up in the final tree
10 #[doc(hidden)]
11 TOMBSTONE,
12 #[doc(hidden)]
13 EOF,
14
15{%- for t in concat(a=single_byte_tokens, b=multi_byte_tokens) %}
16 {{t.1}},
17{%- endfor -%}
18{% for kw in concat(a=keywords, b=contextual_keywords) %}
19 {{kw | upper}}_KW,
20{%- endfor -%}
21{% for t in concat(a=tokens, b=nodes) %}
22 {{t}},
23{%- endfor %}
24}
25use self::SyntaxKind::*;
26
27impl SyntaxKind {
28 pub fn is_keyword(self) -> bool {
29 match self {
30{%- for kw in concat(a=keywords, b=contextual_keywords) %}
31 | {{kw | upper}}_KW
32{%- endfor %}
33 => true,
34 _ => false
35 }
36 }
37
38 pub(crate) fn info(self) -> &'static SyntaxInfo {
39 match self {
40{%- for t in concat(a=single_byte_tokens, b=multi_byte_tokens) %}
41 {{t.1}} => &SyntaxInfo { name: "{{t.1}}" },
42{%- endfor -%}
43{% for kw in concat(a=keywords, b=contextual_keywords) %}
44 {{kw | upper}}_KW => &SyntaxInfo { name: "{{kw | upper}}_KW" },
45{%- endfor -%}
46{% for t in concat(a=tokens, b=nodes) %}
47 {{t}} => &SyntaxInfo { name: "{{t}}" },
48{%- endfor %}
49 TOMBSTONE => &SyntaxInfo { name: "TOMBSTONE" },
50 EOF => &SyntaxInfo { name: "EOF" },
51 }
52 }
53 pub(crate) fn from_keyword(ident: &str) -> Option<SyntaxKind> {
54 let kw = match ident {
55{%- for kw in keywords %}
56 "{{kw}}" => {{kw | upper}}_KW,
57{%- endfor %}
58 _ => return None,
59 };
60 Some(kw)
61 }
62
63 pub(crate) fn from_char(c: char) -> Option<SyntaxKind> {
64 let tok = match c {
65{%- for t in single_byte_tokens %}
66 '{{t.0}}' => {{t.1}},
67{%- endfor %}
68 _ => return None,
69 };
70 Some(tok)
71 }
72}
73
diff --git a/crates/libsyntax2/src/syntax_kinds/mod.rs b/crates/libsyntax2/src/syntax_kinds/mod.rs
new file mode 100644
index 000000000..ed4fa5d4d
--- /dev/null
+++ b/crates/libsyntax2/src/syntax_kinds/mod.rs
@@ -0,0 +1,26 @@
1mod generated;
2
3use std::fmt;
4use SyntaxKind::*;
5
6pub use self::generated::SyntaxKind;
7
8impl fmt::Debug for SyntaxKind {
9 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10 let name = self.info().name;
11 f.write_str(name)
12 }
13}
14
15pub(crate) struct SyntaxInfo {
16 pub name: &'static str,
17}
18
19impl SyntaxKind {
20 pub(crate) fn is_trivia(self) -> bool {
21 match self {
22 WHITESPACE | COMMENT | DOC_COMMENT => true,
23 _ => false,
24 }
25 }
26}
diff --git a/crates/libsyntax2/src/utils.rs b/crates/libsyntax2/src/utils.rs
new file mode 100644
index 000000000..1fbb872a5
--- /dev/null
+++ b/crates/libsyntax2/src/utils.rs
@@ -0,0 +1,48 @@
1use std::fmt::Write;
2use {
3 algo::walk::{walk, WalkEvent},
4 SyntaxNode,
5};
6
7/// Parse a file and create a string representation of the resulting parse tree.
8pub fn dump_tree(syntax: &SyntaxNode) -> String {
9 let syntax = syntax.as_ref();
10 let mut errors: Vec<_> = syntax.root.errors.iter().cloned().collect();
11 errors.sort_by_key(|e| e.offset);
12 let mut err_pos = 0;
13 let mut level = 0;
14 let mut buf = String::new();
15 macro_rules! indent {
16 () => {
17 for _ in 0..level {
18 buf.push_str(" ");
19 }
20 };
21 }
22
23 for event in walk(syntax) {
24 match event {
25 WalkEvent::Enter(node) => {
26 indent!();
27 writeln!(buf, "{:?}", node).unwrap();
28 if node.first_child().is_none() {
29 let off = node.range().end();
30 while err_pos < errors.len() && errors[err_pos].offset <= off {
31 indent!();
32 writeln!(buf, "err: `{}`", errors[err_pos].msg).unwrap();
33 err_pos += 1;
34 }
35 }
36 level += 1;
37 }
38 WalkEvent::Exit(_) => level -= 1,
39 }
40 }
41
42 assert_eq!(level, 0);
43 for err in errors[err_pos..].iter() {
44 writeln!(buf, "err: `{}`", err.msg).unwrap();
45 }
46
47 return buf;
48}
diff --git a/crates/libsyntax2/src/yellow/builder.rs b/crates/libsyntax2/src/yellow/builder.rs
new file mode 100644
index 000000000..5e94e5055
--- /dev/null
+++ b/crates/libsyntax2/src/yellow/builder.rs
@@ -0,0 +1,65 @@
1use {
2 parser_impl::Sink,
3 yellow::{GreenNode, SyntaxError, SyntaxNode, SyntaxRoot},
4 SyntaxKind, TextRange, TextUnit,
5};
6
7pub(crate) struct GreenBuilder<'a> {
8 text: &'a str,
9 parents: Vec<(SyntaxKind, usize)>,
10 children: Vec<GreenNode>,
11 pos: TextUnit,
12 errors: Vec<SyntaxError>,
13}
14
15impl<'a> Sink<'a> for GreenBuilder<'a> {
16 type Tree = SyntaxNode;
17
18 fn new(text: &'a str) -> Self {
19 GreenBuilder {
20 text,
21 parents: Vec::new(),
22 children: Vec::new(),
23 pos: 0.into(),
24 errors: Vec::new(),
25 }
26 }
27
28 fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
29 let range = TextRange::offset_len(self.pos, len);
30 self.pos += len;
31 let text = &self.text[range];
32 self.children.push(
33 GreenNode::new_leaf(kind, text)
34 );
35 }
36
37 fn start_internal(&mut self, kind: SyntaxKind) {
38 let len = self.children.len();
39 self.parents.push((kind, len));
40 }
41
42 fn finish_internal(&mut self) {
43 let (kind, first_child) = self.parents.pop().unwrap();
44 let children: Vec<_> = self.children
45 .drain(first_child..)
46 .collect();
47 self.children.push(
48 GreenNode::new_branch(kind, children.into_boxed_slice())
49 );
50 }
51
52 fn error(&mut self, message: String) {
53 self.errors.push(SyntaxError {
54 msg: message,
55 offset: self.pos,
56 })
57 }
58
59 fn finish(mut self) -> SyntaxNode {
60 assert_eq!(self.children.len(), 1);
61 let root = self.children.pop().unwrap();
62 let root = SyntaxRoot::new(root, self.errors);
63 SyntaxNode::new_owned(root)
64 }
65}
diff --git a/crates/libsyntax2/src/yellow/green.rs b/crates/libsyntax2/src/yellow/green.rs
new file mode 100644
index 000000000..f505b26d7
--- /dev/null
+++ b/crates/libsyntax2/src/yellow/green.rs
@@ -0,0 +1,95 @@
1use std::sync::Arc;
2use {
3 SyntaxKind, TextUnit,
4 smol_str::SmolStr,
5};
6
7#[derive(Clone, Debug)]
8pub(crate) enum GreenNode {
9 Leaf {
10 kind: SyntaxKind,
11 text: SmolStr,
12 },
13 Branch(Arc<GreenBranch>),
14}
15
16impl GreenNode {
17 pub(crate) fn new_leaf(kind: SyntaxKind, text: &str) -> GreenNode {
18 GreenNode::Leaf { kind, text: SmolStr::new(text) }
19 }
20
21 pub(crate) fn new_branch(kind: SyntaxKind, children: Box<[GreenNode]>) -> GreenNode {
22 GreenNode::Branch(Arc::new(GreenBranch::new(kind, children)))
23 }
24
25 pub fn kind(&self) -> SyntaxKind {
26 match self {
27 GreenNode::Leaf { kind, .. } => *kind,
28 GreenNode::Branch(b) => b.kind(),
29 }
30 }
31
32 pub fn text_len(&self) -> TextUnit {
33 match self {
34 GreenNode::Leaf { text, ..} => TextUnit::of_str(text.as_str()),
35 GreenNode::Branch(b) => b.text_len(),
36 }
37 }
38
39 pub fn children(&self) -> &[GreenNode] {
40 match self {
41 GreenNode::Leaf { .. } => &[],
42 GreenNode::Branch(b) => b.children(),
43 }
44 }
45
46 pub fn text(&self) -> String {
47 let mut buff = String::new();
48 go(self, &mut buff);
49 return buff;
50 fn go(node: &GreenNode, buff: &mut String) {
51 match node {
52 GreenNode::Leaf { text, .. } => buff.push_str(text.as_str()),
53 GreenNode::Branch(b) => b.children().iter().for_each(|child| go(child, buff)),
54 }
55 }
56 }
57}
58
59#[derive(Clone, Debug)]
60pub(crate) struct GreenBranch {
61 text_len: TextUnit,
62 kind: SyntaxKind,
63 children: Box<[GreenNode]>,
64}
65
66impl GreenBranch {
67 fn new(kind: SyntaxKind, children: Box<[GreenNode]>) -> GreenBranch {
68 let text_len = children.iter().map(|x| x.text_len()).sum::<TextUnit>();
69 GreenBranch {
70 text_len,
71 kind,
72 children,
73 }
74 }
75
76 pub fn kind(&self) -> SyntaxKind {
77 self.kind
78 }
79
80 pub fn text_len(&self) -> TextUnit {
81 self.text_len
82 }
83
84 pub fn children(&self) -> &[GreenNode] {
85 &*self.children
86 }
87}
88
89#[test]
90fn test_sizes() {
91 use std::mem::size_of;
92 println!("GreenBranch = {}", size_of::<GreenBranch>());
93 println!("GreenNode = {}", size_of::<GreenNode>());
94 println!("SmolStr = {}", size_of::<SmolStr>());
95}
diff --git a/crates/libsyntax2/src/yellow/mod.rs b/crates/libsyntax2/src/yellow/mod.rs
new file mode 100644
index 000000000..ff3bb221b
--- /dev/null
+++ b/crates/libsyntax2/src/yellow/mod.rs
@@ -0,0 +1,62 @@
1mod builder;
2mod green;
3mod red;
4mod syntax;
5
6use std::{
7 ops::Deref,
8 sync::Arc,
9 ptr,
10};
11pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError};
12pub(crate) use self::{
13 builder::GreenBuilder,
14 green::GreenNode,
15 red::RedNode,
16};
17
18pub trait TreeRoot: Deref<Target=SyntaxRoot> + Clone + Send + Sync {}
19
20#[derive(Debug)]
21pub struct SyntaxRoot {
22 red: RedNode,
23 pub(crate) errors: Vec<SyntaxError>,
24}
25
26impl TreeRoot for Arc<SyntaxRoot> {}
27
28impl<'a> TreeRoot for &'a SyntaxRoot {}
29
30impl SyntaxRoot {
31 pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
32 SyntaxRoot {
33 red: RedNode::new_root(green),
34 errors,
35 }
36 }
37}
38
39#[derive(Clone, Copy, PartialEq, Eq, Debug)]
40pub(crate) struct RedPtr(ptr::NonNull<RedNode>);
41
42unsafe impl Send for RedPtr {}
43
44unsafe impl Sync for RedPtr {}
45
46impl RedPtr {
47 fn new(red: &RedNode) -> RedPtr {
48 RedPtr(red.into())
49 }
50
51 unsafe fn get<'a>(self, _root: &'a impl TreeRoot) -> &'a RedNode {
52 &*self.0.as_ptr()
53 }
54}
55
56#[test]
57fn assert_send_sync() {
58 fn f<T: Send + Sync>() {}
59 f::<GreenNode>();
60 f::<RedNode>();
61 f::<SyntaxNode>();
62}
diff --git a/crates/libsyntax2/src/yellow/red.rs b/crates/libsyntax2/src/yellow/red.rs
new file mode 100644
index 000000000..13ad44c65
--- /dev/null
+++ b/crates/libsyntax2/src/yellow/red.rs
@@ -0,0 +1,94 @@
1use parking_lot::RwLock;
2use {yellow::{GreenNode, RedPtr}, TextUnit};
3
4#[derive(Debug)]
5pub(crate) struct RedNode {
6 green: GreenNode,
7 parent: Option<ParentData>,
8 children: RwLock<Box<[Option<RedNode>]>>,
9}
10
11#[derive(Debug)]
12struct ParentData {
13 parent: RedPtr,
14 start_offset: TextUnit,
15 index_in_parent: usize,
16}
17
18impl RedNode {
19 pub fn new_root(green: GreenNode) -> RedNode {
20 RedNode::new(green, None)
21 }
22
23 fn new_child(
24 green: GreenNode,
25 parent: RedPtr,
26 start_offset: TextUnit,
27 index_in_parent: usize,
28 ) -> RedNode {
29 let parent_data = ParentData {
30 parent,
31 start_offset,
32 index_in_parent,
33 };
34 RedNode::new(green, Some(parent_data))
35 }
36
37 fn new(green: GreenNode, parent: Option<ParentData>) -> RedNode {
38 let n_children = green.children().len();
39 let children = (0..n_children)
40 .map(|_| None)
41 .collect::<Vec<_>>()
42 .into_boxed_slice();
43 RedNode {
44 green,
45 parent,
46 children: RwLock::new(children),
47 }
48 }
49
50 pub(crate) fn green(&self) -> &GreenNode {
51 &self.green
52 }
53
54 pub(crate) fn start_offset(&self) -> TextUnit {
55 match &self.parent {
56 None => 0.into(),
57 Some(p) => p.start_offset,
58 }
59 }
60
61 pub(crate) fn n_children(&self) -> usize {
62 self.green.children().len()
63 }
64
65 pub(crate) fn get_child(&self, idx: usize) -> Option<RedPtr> {
66 if idx >= self.n_children() {
67 return None;
68 }
69 match &self.children.read()[idx] {
70 Some(child) => return Some(RedPtr::new(child)),
71 None => (),
72 };
73 let green_children = self.green.children();
74 let start_offset = self.start_offset()
75 + green_children[..idx]
76 .iter()
77 .map(|x| x.text_len())
78 .sum::<TextUnit>();
79 let child =
80 RedNode::new_child(green_children[idx].clone(), RedPtr::new(self), start_offset, idx);
81 let mut children = self.children.write();
82 if children[idx].is_none() {
83 children[idx] = Some(child)
84 }
85 Some(RedPtr::new(children[idx].as_ref().unwrap()))
86 }
87
88 pub(crate) fn parent(&self) -> Option<RedPtr> {
89 Some(self.parent.as_ref()?.parent)
90 }
91 pub(crate) fn index_in_parent(&self) -> Option<usize> {
92 Some(self.parent.as_ref()?.index_in_parent)
93 }
94}
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs
new file mode 100644
index 000000000..6e33310f1
--- /dev/null
+++ b/crates/libsyntax2/src/yellow/syntax.rs
@@ -0,0 +1,122 @@
1use std::{fmt, sync::Arc};
2
3use {
4 yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr},
5 SyntaxKind::{self, *},
6 TextRange, TextUnit,
7};
8
9
10#[derive(Clone, Copy)]
11pub struct SyntaxNode<R: TreeRoot = Arc<SyntaxRoot>> {
12 pub(crate) root: R,
13 // Guaranteed to not dangle, because `root` holds a
14 // strong reference to red's ancestor
15 red: RedPtr,
16}
17
18unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {}
19unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {}
20
21impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
22 fn eq(&self, other: &SyntaxNode<R1>) -> bool {
23 self.red == other.red
24 }
25}
26
27impl<R: TreeRoot> Eq for SyntaxNode<R> {}
28
29pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>;
30
31#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
32pub struct SyntaxError {
33 pub msg: String,
34 pub offset: TextUnit,
35}
36
37impl SyntaxNode<Arc<SyntaxRoot>> {
38 pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
39 let root = Arc::new(root);
40 let red = RedPtr::new(&root.red);
41 SyntaxNode { root, red }
42 }
43}
44
45impl<R: TreeRoot> SyntaxNode<R> {
46 pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> {
47 SyntaxNode {
48 root: &*self.root,
49 red: self.red,
50 }
51 }
52
53 pub fn kind(&self) -> SyntaxKind {
54 self.red().green().kind()
55 }
56
57 pub fn range(&self) -> TextRange {
58 let red = self.red();
59 TextRange::offset_len(red.start_offset(), red.green().text_len())
60 }
61
62 pub fn text(&self) -> String {
63 self.red().green().text()
64 }
65
66 pub fn children<'a>(&'a self) -> impl Iterator<Item = SyntaxNode<R>> + 'a {
67 let red = self.red();
68 let n_children = red.n_children();
69 (0..n_children).map(move |i| SyntaxNode {
70 root: self.root.clone(),
71 red: red.get_child(i).unwrap(),
72 })
73 }
74
75 pub fn parent(&self) -> Option<SyntaxNode<R>> {
76 let parent = self.red().parent()?;
77 Some(SyntaxNode {
78 root: self.root.clone(),
79 red: parent,
80 })
81 }
82
83 pub fn first_child(&self) -> Option<SyntaxNode<R>> {
84 self.children().next()
85 }
86
87 pub fn next_sibling(&self) -> Option<SyntaxNode<R>> {
88 let red = self.red();
89 let parent = self.parent()?;
90 let next_sibling_idx = red.index_in_parent()? + 1;
91 let sibling_red = parent.red().get_child(next_sibling_idx)?;
92 Some(SyntaxNode {
93 root: self.root.clone(),
94 red: sibling_red,
95 })
96 }
97
98 pub fn is_leaf(&self) -> bool {
99 self.first_child().is_none()
100 }
101
102 fn red(&self) -> &RedNode {
103 unsafe { self.red.get(&self.root) }
104 }
105}
106
107impl<R: TreeRoot> fmt::Debug for SyntaxNode<R> {
108 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
109 write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
110 if has_short_text(self.kind()) {
111 write!(fmt, " \"{}\"", self.text())?;
112 }
113 Ok(())
114 }
115}
116
117fn has_short_text(kind: SyntaxKind) -> bool {
118 match kind {
119 IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
120 _ => false,
121 }
122}
diff --git a/crates/libsyntax2/tests/data/lexer/00012_block_comment.rs b/crates/libsyntax2/tests/data/lexer/00012_block_comment.rs
new file mode 100644
index 000000000..708aac197
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/00012_block_comment.rs
@@ -0,0 +1,4 @@
1/* */
2/**/
3/* /* */ */
4/*
diff --git a/crates/libsyntax2/tests/data/lexer/00012_block_comment.txt b/crates/libsyntax2/tests/data/lexer/00012_block_comment.txt
new file mode 100644
index 000000000..9958b2518
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/00012_block_comment.txt
@@ -0,0 +1,7 @@
1COMMENT 5 "/* */"
2WHITESPACE 1 "\n"
3COMMENT 4 "/**/"
4WHITESPACE 1 "\n"
5COMMENT 11 "/* /* */ */"
6WHITESPACE 1 "\n"
7COMMENT 3 "/*\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0001_hello.rs b/crates/libsyntax2/tests/data/lexer/0001_hello.rs
new file mode 100644
index 000000000..95d09f2b1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0001_hello.rs
@@ -0,0 +1 @@
hello world \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/lexer/0001_hello.txt b/crates/libsyntax2/tests/data/lexer/0001_hello.txt
new file mode 100644
index 000000000..27a5940a9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0001_hello.txt
@@ -0,0 +1,3 @@
1IDENT 5 "hello"
2WHITESPACE 1 " "
3IDENT 5 "world"
diff --git a/crates/libsyntax2/tests/data/lexer/0002_whitespace.rs b/crates/libsyntax2/tests/data/lexer/0002_whitespace.rs
new file mode 100644
index 000000000..08fce1418
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0002_whitespace.rs
@@ -0,0 +1,4 @@
1a b c
2d
3
4e f
diff --git a/crates/libsyntax2/tests/data/lexer/0002_whitespace.txt b/crates/libsyntax2/tests/data/lexer/0002_whitespace.txt
new file mode 100644
index 000000000..01d260918
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0002_whitespace.txt
@@ -0,0 +1,12 @@
1IDENT 1 "a"
2WHITESPACE 1 " "
3IDENT 1 "b"
4WHITESPACE 2 " "
5IDENT 1 "c"
6WHITESPACE 1 "\n"
7IDENT 1 "d"
8WHITESPACE 2 "\n\n"
9IDENT 1 "e"
10WHITESPACE 1 "\t"
11IDENT 1 "f"
12WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0003_ident.rs b/crates/libsyntax2/tests/data/lexer/0003_ident.rs
new file mode 100644
index 000000000..c05c9c009
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0003_ident.rs
@@ -0,0 +1 @@
foo foo_ _foo _ __ x привет
diff --git a/crates/libsyntax2/tests/data/lexer/0003_ident.txt b/crates/libsyntax2/tests/data/lexer/0003_ident.txt
new file mode 100644
index 000000000..4a0d5c053
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0003_ident.txt
@@ -0,0 +1,14 @@
1IDENT 3 "foo"
2WHITESPACE 1 " "
3IDENT 4 "foo_"
4WHITESPACE 1 " "
5IDENT 4 "_foo"
6WHITESPACE 1 " "
7UNDERSCORE 1 "_"
8WHITESPACE 1 " "
9IDENT 2 "__"
10WHITESPACE 1 " "
11IDENT 1 "x"
12WHITESPACE 1 " "
13IDENT 12 "привет"
14WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0004_numbers.rs b/crates/libsyntax2/tests/data/lexer/0004_numbers.rs
new file mode 100644
index 000000000..dc974b553
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0004_numbers.rs
@@ -0,0 +1,9 @@
10 0b 0o 0x 00 0_ 0. 0e 0E 0z
201790 0b1790 0o1790 0x1790aAbBcCdDeEfF 001279 0_1279 0.1279 0e1279 0E1279
30..2
40.foo()
50e+1
60.e+1
70.0E-2
80___0.10000____0000e+111__
91i64 92.0f32 11__s \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/lexer/0004_numbers.txt b/crates/libsyntax2/tests/data/lexer/0004_numbers.txt
new file mode 100644
index 000000000..4b5fd9f71
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0004_numbers.txt
@@ -0,0 +1,67 @@
1INT_NUMBER 1 "0"
2WHITESPACE 1 " "
3INT_NUMBER 2 "0b"
4WHITESPACE 1 " "
5INT_NUMBER 2 "0o"
6WHITESPACE 1 " "
7INT_NUMBER 2 "0x"
8WHITESPACE 1 " "
9INT_NUMBER 2 "00"
10WHITESPACE 1 " "
11INT_NUMBER 2 "0_"
12WHITESPACE 1 " "
13FLOAT_NUMBER 2 "0."
14WHITESPACE 1 " "
15INT_NUMBER 2 "0e"
16WHITESPACE 1 " "
17INT_NUMBER 2 "0E"
18WHITESPACE 1 " "
19INT_NUMBER 2 "0z"
20WHITESPACE 1 "\n"
21INT_NUMBER 5 "01790"
22WHITESPACE 1 " "
23INT_NUMBER 6 "0b1790"
24WHITESPACE 1 " "
25INT_NUMBER 6 "0o1790"
26WHITESPACE 1 " "
27INT_NUMBER 18 "0x1790aAbBcCdDeEfF"
28WHITESPACE 1 " "
29INT_NUMBER 6 "001279"
30WHITESPACE 1 " "
31INT_NUMBER 6 "0_1279"
32WHITESPACE 1 " "
33FLOAT_NUMBER 6 "0.1279"
34WHITESPACE 1 " "
35INT_NUMBER 6 "0e1279"
36WHITESPACE 1 " "
37INT_NUMBER 6 "0E1279"
38WHITESPACE 1 "\n"
39INT_NUMBER 1 "0"
40DOTDOT 2 ".."
41INT_NUMBER 1 "2"
42WHITESPACE 1 "\n"
43INT_NUMBER 1 "0"
44DOT 1 "."
45IDENT 3 "foo"
46L_PAREN 1 "("
47R_PAREN 1 ")"
48WHITESPACE 1 "\n"
49INT_NUMBER 2 "0e"
50PLUS 1 "+"
51INT_NUMBER 1 "1"
52WHITESPACE 1 "\n"
53INT_NUMBER 1 "0"
54DOT 1 "."
55IDENT 1 "e"
56PLUS 1 "+"
57INT_NUMBER 1 "1"
58WHITESPACE 1 "\n"
59FLOAT_NUMBER 6 "0.0E-2"
60WHITESPACE 1 "\n"
61FLOAT_NUMBER 26 "0___0.10000____0000e+111__"
62WHITESPACE 1 "\n"
63INT_NUMBER 4 "1i64"
64WHITESPACE 1 " "
65FLOAT_NUMBER 7 "92.0f32"
66WHITESPACE 1 " "
67INT_NUMBER 5 "11__s"
diff --git a/crates/libsyntax2/tests/data/lexer/0005_symbols.rs b/crates/libsyntax2/tests/data/lexer/0005_symbols.rs
new file mode 100644
index 000000000..487569b5a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0005_symbols.rs
@@ -0,0 +1,6 @@
1; , ( ) { } [ ] < > @ # ~ ? $ & | + * / ^ %
2. .. ... ..=
3: ::
4= =>
5! !=
6- ->
diff --git a/crates/libsyntax2/tests/data/lexer/0005_symbols.txt b/crates/libsyntax2/tests/data/lexer/0005_symbols.txt
new file mode 100644
index 000000000..a6bc83a6f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0005_symbols.txt
@@ -0,0 +1,68 @@
1SEMI 1 ";"
2WHITESPACE 1 " "
3COMMA 1 ","
4WHITESPACE 1 " "
5L_PAREN 1 "("
6WHITESPACE 1 " "
7R_PAREN 1 ")"
8WHITESPACE 1 " "
9L_CURLY 1 "{"
10WHITESPACE 1 " "
11R_CURLY 1 "}"
12WHITESPACE 1 " "
13L_BRACK 1 "["
14WHITESPACE 1 " "
15R_BRACK 1 "]"
16WHITESPACE 1 " "
17L_ANGLE 1 "<"
18WHITESPACE 1 " "
19R_ANGLE 1 ">"
20WHITESPACE 1 " "
21AT 1 "@"
22WHITESPACE 1 " "
23POUND 1 "#"
24WHITESPACE 1 " "
25TILDE 1 "~"
26WHITESPACE 1 " "
27QUESTION 1 "?"
28WHITESPACE 1 " "
29DOLLAR 1 "$"
30WHITESPACE 1 " "
31AMP 1 "&"
32WHITESPACE 1 " "
33PIPE 1 "|"
34WHITESPACE 1 " "
35PLUS 1 "+"
36WHITESPACE 1 " "
37STAR 1 "*"
38WHITESPACE 1 " "
39SLASH 1 "/"
40WHITESPACE 1 " "
41CARET 1 "^"
42WHITESPACE 1 " "
43PERCENT 1 "%"
44WHITESPACE 1 "\n"
45DOT 1 "."
46WHITESPACE 1 " "
47DOTDOT 2 ".."
48WHITESPACE 1 " "
49DOTDOTDOT 3 "..."
50WHITESPACE 1 " "
51DOTDOTEQ 3 "..="
52WHITESPACE 1 "\n"
53COLON 1 ":"
54WHITESPACE 1 " "
55COLONCOLON 2 "::"
56WHITESPACE 1 "\n"
57EQ 1 "="
58WHITESPACE 1 " "
59FAT_ARROW 2 "=>"
60WHITESPACE 1 "\n"
61EXCL 1 "!"
62WHITESPACE 1 " "
63NEQ 2 "!="
64WHITESPACE 1 "\n"
65MINUS 1 "-"
66WHITESPACE 1 " "
67THIN_ARROW 2 "->"
68WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0006_chars.rs b/crates/libsyntax2/tests/data/lexer/0006_chars.rs
new file mode 100644
index 000000000..03598d908
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0006_chars.rs
@@ -0,0 +1 @@
'x' ' ' '0'
diff --git a/crates/libsyntax2/tests/data/lexer/0006_chars.txt b/crates/libsyntax2/tests/data/lexer/0006_chars.txt
new file mode 100644
index 000000000..ecaf22355
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0006_chars.txt
@@ -0,0 +1,6 @@
1CHAR 3 "\'x\'"
2WHITESPACE 1 " "
3CHAR 3 "\' \'"
4WHITESPACE 1 " "
5CHAR 3 "\'0\'"
6WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0007_lifetimes.rs b/crates/libsyntax2/tests/data/lexer/0007_lifetimes.rs
new file mode 100644
index 000000000..b764f1dce
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0007_lifetimes.rs
@@ -0,0 +1 @@
'a 'foo 'foo_bar_baz '_
diff --git a/crates/libsyntax2/tests/data/lexer/0007_lifetimes.txt b/crates/libsyntax2/tests/data/lexer/0007_lifetimes.txt
new file mode 100644
index 000000000..005c29100
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0007_lifetimes.txt
@@ -0,0 +1,8 @@
1LIFETIME 2 "\'a"
2WHITESPACE 1 " "
3LIFETIME 4 "\'foo"
4WHITESPACE 1 " "
5LIFETIME 12 "\'foo_bar_baz"
6WHITESPACE 1 " "
7LIFETIME 2 "\'_"
8WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0008_byte_strings.rs b/crates/libsyntax2/tests/data/lexer/0008_byte_strings.rs
new file mode 100644
index 000000000..9dd1570de
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0008_byte_strings.rs
@@ -0,0 +1,2 @@
1b'' b'x' b"foo" br""
2b''suf b""ix br""br
diff --git a/crates/libsyntax2/tests/data/lexer/0008_byte_strings.txt b/crates/libsyntax2/tests/data/lexer/0008_byte_strings.txt
new file mode 100644
index 000000000..ed8cd4bab
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0008_byte_strings.txt
@@ -0,0 +1,14 @@
1BYTE 3 "b\'\'"
2WHITESPACE 1 " "
3BYTE 4 "b\'x\'"
4WHITESPACE 1 " "
5BYTE_STRING 6 "b\"foo\""
6WHITESPACE 1 " "
7RAW_BYTE_STRING 4 "br\"\""
8WHITESPACE 1 "\n"
9BYTE 6 "b\'\'suf"
10WHITESPACE 1 " "
11BYTE_STRING 5 "b\"\"ix"
12WHITESPACE 1 " "
13RAW_BYTE_STRING 6 "br\"\"br"
14WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0009_strings.rs b/crates/libsyntax2/tests/data/lexer/0009_strings.rs
new file mode 100644
index 000000000..7b7faa5d8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0009_strings.rs
@@ -0,0 +1 @@
"hello" r"world"
diff --git a/crates/libsyntax2/tests/data/lexer/0009_strings.txt b/crates/libsyntax2/tests/data/lexer/0009_strings.txt
new file mode 100644
index 000000000..7fb6b7b36
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0009_strings.txt
@@ -0,0 +1,4 @@
1STRING 7 "\"hello\""
2WHITESPACE 1 " "
3RAW_STRING 8 "r\"world\""
4WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0010_comments.rs b/crates/libsyntax2/tests/data/lexer/0010_comments.rs
new file mode 100644
index 000000000..71bdd1f9c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0010_comments.rs
@@ -0,0 +1,3 @@
1#!/usr/bin/env bash
2// hello
3//! World
diff --git a/crates/libsyntax2/tests/data/lexer/0010_comments.txt b/crates/libsyntax2/tests/data/lexer/0010_comments.txt
new file mode 100644
index 000000000..3c997de3f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0010_comments.txt
@@ -0,0 +1,6 @@
1SHEBANG 19 "#!/usr/bin/env bash"
2WHITESPACE 1 "\n"
3COMMENT 8 "// hello"
4WHITESPACE 1 "\n"
5COMMENT 9 "//! World"
6WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/lexer/0011_keywords.rs b/crates/libsyntax2/tests/data/lexer/0011_keywords.rs
new file mode 100644
index 000000000..e6bf64d4d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0011_keywords.rs
@@ -0,0 +1,3 @@
1fn use struct trait enum impl true false as extern crate
2mod pub self super in where for loop while if match const
3static mut type ref let else move return
diff --git a/crates/libsyntax2/tests/data/lexer/0011_keywords.txt b/crates/libsyntax2/tests/data/lexer/0011_keywords.txt
new file mode 100644
index 000000000..d6a1abe8a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/lexer/0011_keywords.txt
@@ -0,0 +1,62 @@
1FN_KW 2 "fn"
2WHITESPACE 1 " "
3USE_KW 3 "use"
4WHITESPACE 1 " "
5STRUCT_KW 6 "struct"
6WHITESPACE 1 " "
7TRAIT_KW 5 "trait"
8WHITESPACE 1 " "
9ENUM_KW 4 "enum"
10WHITESPACE 1 " "
11IMPL_KW 4 "impl"
12WHITESPACE 1 " "
13TRUE_KW 4 "true"
14WHITESPACE 1 " "
15FALSE_KW 5 "false"
16WHITESPACE 1 " "
17AS_KW 2 "as"
18WHITESPACE 1 " "
19EXTERN_KW 6 "extern"
20WHITESPACE 1 " "
21CRATE_KW 5 "crate"
22WHITESPACE 1 "\n"
23MOD_KW 3 "mod"
24WHITESPACE 1 " "
25PUB_KW 3 "pub"
26WHITESPACE 1 " "
27SELF_KW 4 "self"
28WHITESPACE 1 " "
29SUPER_KW 5 "super"
30WHITESPACE 1 " "
31IN_KW 2 "in"
32WHITESPACE 1 " "
33WHERE_KW 5 "where"
34WHITESPACE 1 " "
35FOR_KW 3 "for"
36WHITESPACE 1 " "
37LOOP_KW 4 "loop"
38WHITESPACE 1 " "
39WHILE_KW 5 "while"
40WHITESPACE 1 " "
41IF_KW 2 "if"
42WHITESPACE 1 " "
43MATCH_KW 5 "match"
44WHITESPACE 1 " "
45CONST_KW 5 "const"
46WHITESPACE 1 "\n"
47STATIC_KW 6 "static"
48WHITESPACE 1 " "
49MUT_KW 3 "mut"
50WHITESPACE 1 " "
51TYPE_KW 4 "type"
52WHITESPACE 1 " "
53REF_KW 3 "ref"
54WHITESPACE 1 " "
55LET_KW 3 "let"
56WHITESPACE 1 " "
57ELSE_KW 4 "else"
58WHITESPACE 1 " "
59MOVE_KW 4 "move"
60WHITESPACE 1 " "
61RETURN_KW 6 "return"
62WHITESPACE 1 "\n"
diff --git a/crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.rs b/crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.rs
new file mode 100644
index 000000000..fe5030d89
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.rs
@@ -0,0 +1,4 @@
1struct S {
2 a: u32
3 b: u32
4} \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.txt b/crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.txt
new file mode 100644
index 000000000..1b5d722f8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0000_struct_field_missing_comma.txt
@@ -0,0 +1,33 @@
1FILE@[0; 34)
2 STRUCT_ITEM@[0; 34)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 WHITESPACE@[8; 9)
8 L_CURLY@[9; 10)
9 WHITESPACE@[10; 15)
10 NAMED_FIELD@[15; 21)
11 NAME@[15; 16)
12 IDENT@[15; 16) "a"
13 COLON@[16; 17)
14 WHITESPACE@[17; 18)
15 PATH_TYPE@[18; 21)
16 PATH@[18; 21)
17 PATH_SEGMENT@[18; 21)
18 NAME_REF@[18; 21)
19 IDENT@[18; 21) "u32"
20 err: `expected COMMA`
21 WHITESPACE@[21; 26)
22 NAMED_FIELD@[26; 32)
23 NAME@[26; 27)
24 IDENT@[26; 27) "b"
25 COLON@[27; 28)
26 WHITESPACE@[28; 29)
27 PATH_TYPE@[29; 32)
28 PATH@[29; 32)
29 PATH_SEGMENT@[29; 32)
30 NAME_REF@[29; 32)
31 IDENT@[29; 32) "u32"
32 WHITESPACE@[32; 33)
33 R_CURLY@[33; 34)
diff --git a/crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.rs b/crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.rs
new file mode 100644
index 000000000..98f23de1f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.rs
@@ -0,0 +1,3 @@
1if match
2
3struct S {} \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.txt b/crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.txt
new file mode 100644
index 000000000..1aaf07625
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0001_item_recovery_in_file.txt
@@ -0,0 +1,17 @@
1FILE@[0; 21)
2 ERROR@[0; 2)
3 IF_KW@[0; 2)
4 err: `expected an item`
5 WHITESPACE@[2; 3)
6 err: `expected an item`
7 ERROR@[3; 8)
8 MATCH_KW@[3; 8)
9 WHITESPACE@[8; 10)
10 STRUCT_ITEM@[10; 21)
11 STRUCT_KW@[10; 16)
12 WHITESPACE@[16; 17)
13 NAME@[17; 18)
14 IDENT@[17; 18) "S"
15 WHITESPACE@[18; 19)
16 L_CURLY@[19; 20)
17 R_CURLY@[20; 21)
diff --git a/crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.rs b/crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.rs
new file mode 100644
index 000000000..48a3a3980
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.rs
@@ -0,0 +1,2 @@
1#!/use/bin/env rusti
2#!/use/bin/env rusti
diff --git a/crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.txt b/crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.txt
new file mode 100644
index 000000000..0b6aa26eb
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0002_duplicate_shebang.txt
@@ -0,0 +1,7 @@
1FILE@[0; 42)
2 SHEBANG@[0; 20)
3 WHITESPACE@[20; 21)
4 err: `expected an item`
5 ERROR@[21; 41)
6 SHEBANG@[21; 41)
7 WHITESPACE@[41; 42)
diff --git a/crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.rs b/crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.rs
new file mode 100644
index 000000000..009312270
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.rs
@@ -0,0 +1,4 @@
1struct S {
2 a: i32,
3 b: String,
4}; \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.txt b/crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.txt
new file mode 100644
index 000000000..81777fec0
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0003_C++_semicolon.txt
@@ -0,0 +1,38 @@
1FILE@[0; 40)
2 STRUCT_ITEM@[0; 40)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 WHITESPACE@[8; 9)
8 L_CURLY@[9; 10)
9 WHITESPACE@[10; 15)
10 NAMED_FIELD@[15; 21)
11 NAME@[15; 16)
12 IDENT@[15; 16) "a"
13 COLON@[16; 17)
14 WHITESPACE@[17; 18)
15 PATH_TYPE@[18; 21)
16 PATH@[18; 21)
17 PATH_SEGMENT@[18; 21)
18 NAME_REF@[18; 21)
19 IDENT@[18; 21) "i32"
20 COMMA@[21; 22)
21 WHITESPACE@[22; 27)
22 NAMED_FIELD@[27; 36)
23 NAME@[27; 28)
24 IDENT@[27; 28) "b"
25 COLON@[28; 29)
26 WHITESPACE@[29; 30)
27 PATH_TYPE@[30; 36)
28 PATH@[30; 36)
29 PATH_SEGMENT@[30; 36)
30 NAME_REF@[30; 36)
31 IDENT@[30; 36) "String"
32 COMMA@[36; 37)
33 WHITESPACE@[37; 38)
34 R_CURLY@[38; 39)
35 err: `expected item, found `;`
36consider removing this semicolon`
37 ERROR@[39; 40)
38 SEMI@[39; 40)
diff --git a/crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.rs b/crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.rs
new file mode 100644
index 000000000..060e65d06
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.rs
@@ -0,0 +1 @@
use foo::92; \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.txt b/crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.txt
new file mode 100644
index 000000000..c6ae68103
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0004_use_path_bad_segment.txt
@@ -0,0 +1,20 @@
1FILE@[0; 12)
2 USE_ITEM@[0; 9)
3 USE_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 USE_TREE@[4; 9)
6 PATH@[4; 9)
7 PATH@[4; 7)
8 PATH_SEGMENT@[4; 7)
9 NAME_REF@[4; 7)
10 IDENT@[4; 7) "foo"
11 COLONCOLON@[7; 9)
12 err: `expected identifier`
13 err: `expected SEMI`
14 err: `expected an item`
15 PATH_SEGMENT@[9; 9)
16 ERROR@[9; 11)
17 INT_NUMBER@[9; 11) "92"
18 err: `expected an item`
19 ERROR@[11; 12)
20 SEMI@[11; 12)
diff --git a/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.rs b/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.rs
new file mode 100644
index 000000000..de7f81628
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.rs
@@ -0,0 +1,8 @@
1#[foo(foo, +, 92)]
2fn foo() {
3}
4
5
6#[foo(
7fn foo() {
8}
diff --git a/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt b/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt
new file mode 100644
index 000000000..079b0d1f6
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt
@@ -0,0 +1,60 @@
1FILE@[0; 54)
2 FUNCTION@[0; 31)
3 ATTR@[0; 18)
4 POUND@[0; 1)
5 L_BRACK@[1; 2)
6 META_ITEM@[2; 17)
7 IDENT@[2; 5) "foo"
8 L_PAREN@[5; 6)
9 META_ITEM@[6; 9)
10 IDENT@[6; 9) "foo"
11 COMMA@[9; 10)
12 WHITESPACE@[10; 11)
13 err: `expected attribute`
14 ERROR@[11; 12)
15 PLUS@[11; 12)
16 err: `expected attribute`
17 ERROR@[12; 13)
18 COMMA@[12; 13)
19 WHITESPACE@[13; 14)
20 LITERAL@[14; 16)
21 INT_NUMBER@[14; 16) "92"
22 R_PAREN@[16; 17)
23 R_BRACK@[17; 18)
24 WHITESPACE@[18; 19)
25 FN_KW@[19; 21)
26 WHITESPACE@[21; 22)
27 NAME@[22; 25)
28 IDENT@[22; 25) "foo"
29 PARAM_LIST@[25; 27)
30 L_PAREN@[25; 26)
31 R_PAREN@[26; 27)
32 WHITESPACE@[27; 28)
33 BLOCK_EXPR@[28; 31)
34 L_CURLY@[28; 29)
35 WHITESPACE@[29; 30)
36 R_CURLY@[30; 31)
37 WHITESPACE@[31; 34)
38 FUNCTION@[34; 53)
39 ATTR@[34; 40)
40 POUND@[34; 35)
41 L_BRACK@[35; 36)
42 META_ITEM@[36; 40)
43 IDENT@[36; 39) "foo"
44 L_PAREN@[39; 40)
45 err: `expected attribute`
46 err: `expected R_BRACK`
47 WHITESPACE@[40; 41)
48 FN_KW@[41; 43)
49 WHITESPACE@[43; 44)
50 NAME@[44; 47)
51 IDENT@[44; 47) "foo"
52 PARAM_LIST@[47; 49)
53 L_PAREN@[47; 48)
54 R_PAREN@[48; 49)
55 WHITESPACE@[49; 50)
56 BLOCK_EXPR@[50; 53)
57 L_CURLY@[50; 51)
58 WHITESPACE@[51; 52)
59 R_CURLY@[52; 53)
60 WHITESPACE@[53; 54)
diff --git a/crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.rs b/crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.rs
new file mode 100644
index 000000000..8069c111b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.rs
@@ -0,0 +1,7 @@
1struct S {
2 f: u32,
3 pub 92
4 + - *
5 pub x: u32,
6 z: f64,
7}
diff --git a/crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.txt b/crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.txt
new file mode 100644
index 000000000..009b307b1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0006_named_field_recovery.txt
@@ -0,0 +1,73 @@
1FILE@[0; 74)
2 STRUCT_ITEM@[0; 73)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 WHITESPACE@[8; 9)
8 L_CURLY@[9; 10)
9 WHITESPACE@[10; 15)
10 NAMED_FIELD@[15; 21)
11 NAME@[15; 16)
12 IDENT@[15; 16) "f"
13 COLON@[16; 17)
14 WHITESPACE@[17; 18)
15 PATH_TYPE@[18; 21)
16 PATH@[18; 21)
17 PATH_SEGMENT@[18; 21)
18 NAME_REF@[18; 21)
19 IDENT@[18; 21) "u32"
20 COMMA@[21; 22)
21 WHITESPACE@[22; 27)
22 VISIBILITY@[27; 30)
23 PUB_KW@[27; 30)
24 WHITESPACE@[30; 31)
25 err: `expected field declaration`
26 ERROR@[31; 33)
27 INT_NUMBER@[31; 33) "92"
28 err: `expected COMMA`
29 WHITESPACE@[33; 38)
30 err: `expected field declaration`
31 ERROR@[38; 39)
32 PLUS@[38; 39)
33 err: `expected COMMA`
34 WHITESPACE@[39; 40)
35 err: `expected field declaration`
36 ERROR@[40; 41)
37 MINUS@[40; 41)
38 err: `expected COMMA`
39 WHITESPACE@[41; 42)
40 err: `expected field declaration`
41 ERROR@[42; 43)
42 STAR@[42; 43)
43 err: `expected COMMA`
44 WHITESPACE@[43; 48)
45 NAMED_FIELD@[48; 58)
46 VISIBILITY@[48; 51)
47 PUB_KW@[48; 51)
48 WHITESPACE@[51; 52)
49 NAME@[52; 53)
50 IDENT@[52; 53) "x"
51 COLON@[53; 54)
52 WHITESPACE@[54; 55)
53 PATH_TYPE@[55; 58)
54 PATH@[55; 58)
55 PATH_SEGMENT@[55; 58)
56 NAME_REF@[55; 58)
57 IDENT@[55; 58) "u32"
58 COMMA@[58; 59)
59 WHITESPACE@[59; 64)
60 NAMED_FIELD@[64; 70)
61 NAME@[64; 65)
62 IDENT@[64; 65) "z"
63 COLON@[65; 66)
64 WHITESPACE@[66; 67)
65 PATH_TYPE@[67; 70)
66 PATH@[67; 70)
67 PATH_SEGMENT@[67; 70)
68 NAME_REF@[67; 70)
69 IDENT@[67; 70) "f64"
70 COMMA@[70; 71)
71 WHITESPACE@[71; 72)
72 R_CURLY@[72; 73)
73 WHITESPACE@[73; 74)
diff --git a/crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.rs b/crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.rs
new file mode 100644
index 000000000..dc869fb78
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.rs
@@ -0,0 +1,9 @@
1}
2
3struct S;
4
5}
6
7fn foo(){}
8
9}
diff --git a/crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.txt b/crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.txt
new file mode 100644
index 000000000..b36decb46
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0007_stray_curly_in_file.txt
@@ -0,0 +1,32 @@
1FILE@[0; 31)
2 ERROR@[0; 1)
3 R_CURLY@[0; 1)
4 err: `expected an item`
5 WHITESPACE@[1; 3)
6 STRUCT_ITEM@[3; 12)
7 STRUCT_KW@[3; 9)
8 WHITESPACE@[9; 10)
9 NAME@[10; 11)
10 IDENT@[10; 11) "S"
11 SEMI@[11; 12)
12 WHITESPACE@[12; 14)
13 err: `expected an item`
14 ERROR@[14; 15)
15 R_CURLY@[14; 15)
16 WHITESPACE@[15; 17)
17 FUNCTION@[17; 27)
18 FN_KW@[17; 19)
19 WHITESPACE@[19; 20)
20 NAME@[20; 23)
21 IDENT@[20; 23) "foo"
22 PARAM_LIST@[23; 25)
23 L_PAREN@[23; 24)
24 R_PAREN@[24; 25)
25 BLOCK_EXPR@[25; 27)
26 L_CURLY@[25; 26)
27 R_CURLY@[26; 27)
28 WHITESPACE@[27; 29)
29 err: `expected an item`
30 ERROR@[29; 30)
31 R_CURLY@[29; 30)
32 WHITESPACE@[30; 31)
diff --git a/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.rs b/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.rs
new file mode 100644
index 000000000..9fcac19b5
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.rs
@@ -0,0 +1,13 @@
1fn foo() {
2}
3
4bar() {
5 if true {
6 1
7 } else {
8 2 + 3
9 }
10}
11
12fn baz() {
13}
diff --git a/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt b/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt
new file mode 100644
index 000000000..f2a503cec
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt
@@ -0,0 +1,67 @@
1FILE@[0; 95)
2 FUNCTION@[0; 12)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 12)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 11)
14 R_CURLY@[11; 12)
15 WHITESPACE@[12; 14)
16 MACRO_CALL@[14; 19)
17 PATH@[14; 17)
18 PATH_SEGMENT@[14; 17)
19 NAME_REF@[14; 17)
20 IDENT@[14; 17) "bar"
21 err: `expected EXCL`
22 L_PAREN@[17; 18)
23 R_PAREN@[18; 19)
24 err: `expected SEMI`
25 WHITESPACE@[19; 20)
26 err: `expected an item`
27 ERROR@[20; 80)
28 L_CURLY@[20; 21)
29 WHITESPACE@[21; 26)
30 IF_KW@[26; 28)
31 WHITESPACE@[28; 29)
32 TRUE_KW@[29; 33)
33 WHITESPACE@[33; 34)
34 L_CURLY@[34; 35)
35 WHITESPACE@[35; 44)
36 INT_NUMBER@[44; 45) "1"
37 WHITESPACE@[45; 50)
38 R_CURLY@[50; 51)
39 WHITESPACE@[51; 52)
40 ELSE_KW@[52; 56)
41 WHITESPACE@[56; 57)
42 L_CURLY@[57; 58)
43 WHITESPACE@[58; 67)
44 INT_NUMBER@[67; 68) "2"
45 WHITESPACE@[68; 69)
46 PLUS@[69; 70)
47 WHITESPACE@[70; 71)
48 INT_NUMBER@[71; 72) "3"
49 WHITESPACE@[72; 77)
50 R_CURLY@[77; 78)
51 WHITESPACE@[78; 79)
52 R_CURLY@[79; 80)
53 WHITESPACE@[80; 82)
54 FUNCTION@[82; 94)
55 FN_KW@[82; 84)
56 WHITESPACE@[84; 85)
57 NAME@[85; 88)
58 IDENT@[85; 88) "baz"
59 PARAM_LIST@[88; 90)
60 L_PAREN@[88; 89)
61 R_PAREN@[89; 90)
62 WHITESPACE@[90; 91)
63 BLOCK_EXPR@[91; 94)
64 L_CURLY@[91; 92)
65 WHITESPACE@[92; 93)
66 R_CURLY@[93; 94)
67 WHITESPACE@[94; 95)
diff --git a/crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.rs b/crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.rs
new file mode 100644
index 000000000..0dd30d0bd
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.rs
@@ -0,0 +1,5 @@
1struct S<90 + 2> {
2 f: u32
3}
4
5struct T;
diff --git a/crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.txt b/crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.txt
new file mode 100644
index 000000000..fc736f0e9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0009_broken_struct_type_parameter.txt
@@ -0,0 +1,44 @@
1FILE@[0; 43)
2 STRUCT_ITEM@[0; 11)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 TYPE_PARAM_LIST@[8; 11)
8 L_ANGLE@[8; 9)
9 err: `expected type parameter`
10 ERROR@[9; 11)
11 INT_NUMBER@[9; 11) "90"
12 err: `expected COMMA`
13 err: `expected R_ANGLE`
14 err: `expected `;`, `{`, or `(``
15 WHITESPACE@[11; 12)
16 err: `expected an item`
17 ERROR@[12; 13)
18 PLUS@[12; 13)
19 WHITESPACE@[13; 14)
20 err: `expected an item`
21 ERROR@[14; 15)
22 INT_NUMBER@[14; 15) "2"
23 err: `expected an item`
24 ERROR@[15; 16)
25 R_ANGLE@[15; 16)
26 WHITESPACE@[16; 17)
27 err: `expected an item`
28 ERROR@[17; 31)
29 L_CURLY@[17; 18)
30 WHITESPACE@[18; 23)
31 IDENT@[23; 24) "f"
32 COLON@[24; 25)
33 WHITESPACE@[25; 26)
34 IDENT@[26; 29) "u32"
35 WHITESPACE@[29; 30)
36 R_CURLY@[30; 31)
37 WHITESPACE@[31; 33)
38 STRUCT_ITEM@[33; 42)
39 STRUCT_KW@[33; 39)
40 WHITESPACE@[39; 40)
41 NAME@[40; 41)
42 IDENT@[40; 41) "T"
43 SEMI@[41; 42)
44 WHITESPACE@[42; 43)
diff --git a/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.rs b/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.rs
new file mode 100644
index 000000000..985775282
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.rs
@@ -0,0 +1,3 @@
1fn main() {
2 || -> () unsafe { () };
3}
diff --git a/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt b/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt
new file mode 100644
index 000000000..95d4af424
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt
@@ -0,0 +1,40 @@
1FILE@[0; 42)
2 FUNCTION@[0; 41)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 41)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 LAMBDA_EXPR@[16; 24)
15 PARAM_LIST@[16; 18)
16 PIPE@[16; 17)
17 PIPE@[17; 18)
18 WHITESPACE@[18; 19)
19 THIN_ARROW@[19; 21)
20 WHITESPACE@[21; 22)
21 TUPLE_TYPE@[22; 24)
22 L_PAREN@[22; 23)
23 R_PAREN@[23; 24)
24 err: `expected block`
25 WHITESPACE@[24; 25)
26 EXPR_STMT@[25; 39)
27 BLOCK_EXPR@[25; 38)
28 UNSAFE_KW@[25; 31)
29 WHITESPACE@[31; 32)
30 L_CURLY@[32; 33)
31 WHITESPACE@[33; 34)
32 TUPLE_EXPR@[34; 36)
33 L_PAREN@[34; 35)
34 R_PAREN@[35; 36)
35 WHITESPACE@[36; 37)
36 R_CURLY@[37; 38)
37 SEMI@[38; 39)
38 WHITESPACE@[39; 40)
39 R_CURLY@[40; 41)
40 WHITESPACE@[41; 42)
diff --git a/crates/libsyntax2/tests/data/parser/err/0011_extern_struct.rs b/crates/libsyntax2/tests/data/parser/err/0011_extern_struct.rs
new file mode 100644
index 000000000..c1bd0a2d1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0011_extern_struct.rs
@@ -0,0 +1 @@
extern struct Foo;
diff --git a/crates/libsyntax2/tests/data/parser/err/0011_extern_struct.txt b/crates/libsyntax2/tests/data/parser/err/0011_extern_struct.txt
new file mode 100644
index 000000000..3c5b678a1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0011_extern_struct.txt
@@ -0,0 +1,13 @@
1FILE@[0; 19)
2 ERROR@[0; 6)
3 ABI@[0; 6)
4 EXTERN_KW@[0; 6)
5 err: `expected fn, trait or impl`
6 WHITESPACE@[6; 7)
7 STRUCT_ITEM@[7; 18)
8 STRUCT_KW@[7; 13)
9 WHITESPACE@[13; 14)
10 NAME@[14; 17)
11 IDENT@[14; 17) "Foo"
12 SEMI@[17; 18)
13 WHITESPACE@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.rs b/crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.rs
new file mode 100644
index 000000000..ad0d8eb4c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.rs
@@ -0,0 +1,12 @@
1pub(super) fn process<'a, S: Sink<'a>>(builder: &mut S, tokens: &[Token], events: Vec<Event>) {
2 let mut next_tok_idx = 0;
3 let eat_ws = |idx: &mut usize, &mut | {
4 while let Some(token) = tokens.get(*idx) {
5 if !token.kind.is_trivia() {
6 break;
7 }
8 builder.leaf(token.kind, token.len);
9 *idx += 1
10 }
11 };
12}
diff --git a/crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.txt b/crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.txt
new file mode 100644
index 000000000..cf6e68a78
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/err/0012_broken_lambda.txt
@@ -0,0 +1,387 @@
1FILE@[0; 389)
2 FUNCTION@[0; 389)
3 VISIBILITY@[0; 10)
4 PUB_KW@[0; 3)
5 L_PAREN@[3; 4)
6 SUPER_KW@[4; 9)
7 R_PAREN@[9; 10)
8 WHITESPACE@[10; 11)
9 FN_KW@[11; 13)
10 WHITESPACE@[13; 14)
11 NAME@[14; 21)
12 IDENT@[14; 21) "process"
13 TYPE_PARAM_LIST@[21; 38)
14 L_ANGLE@[21; 22)
15 LIFETIME_PARAM@[22; 24)
16 LIFETIME@[22; 24) "'a"
17 COMMA@[24; 25)
18 WHITESPACE@[25; 26)
19 TYPE_PARAM@[26; 37)
20 NAME@[26; 27)
21 IDENT@[26; 27) "S"
22 COLON@[27; 28)
23 WHITESPACE@[28; 29)
24 PATH@[29; 37)
25 PATH_SEGMENT@[29; 37)
26 NAME_REF@[29; 33)
27 IDENT@[29; 33) "Sink"
28 TYPE_ARG_LIST@[33; 37)
29 L_ANGLE@[33; 34)
30 LIFETIME_ARG@[34; 36)
31 LIFETIME@[34; 36) "'a"
32 R_ANGLE@[36; 37)
33 R_ANGLE@[37; 38)
34 PARAM_LIST@[38; 93)
35 L_PAREN@[38; 39)
36 PARAM@[39; 54)
37 BIND_PAT@[39; 46)
38 NAME@[39; 46)
39 IDENT@[39; 46) "builder"
40 COLON@[46; 47)
41 WHITESPACE@[47; 48)
42 REFERENCE_TYPE@[48; 54)
43 AMP@[48; 49)
44 MUT_KW@[49; 52)
45 WHITESPACE@[52; 53)
46 PATH_TYPE@[53; 54)
47 PATH@[53; 54)
48 PATH_SEGMENT@[53; 54)
49 NAME_REF@[53; 54)
50 IDENT@[53; 54) "S"
51 COMMA@[54; 55)
52 WHITESPACE@[55; 56)
53 PARAM@[56; 72)
54 BIND_PAT@[56; 62)
55 NAME@[56; 62)
56 IDENT@[56; 62) "tokens"
57 COLON@[62; 63)
58 WHITESPACE@[63; 64)
59 REFERENCE_TYPE@[64; 72)
60 AMP@[64; 65)
61 SLICE_TYPE@[65; 72)
62 L_BRACK@[65; 66)
63 PATH_TYPE@[66; 71)
64 PATH@[66; 71)
65 PATH_SEGMENT@[66; 71)
66 NAME_REF@[66; 71)
67 IDENT@[66; 71) "Token"
68 R_BRACK@[71; 72)
69 COMMA@[72; 73)
70 WHITESPACE@[73; 74)
71 PARAM@[74; 92)
72 BIND_PAT@[74; 80)
73 NAME@[74; 80)
74 IDENT@[74; 80) "events"
75 COLON@[80; 81)
76 WHITESPACE@[81; 82)
77 PATH_TYPE@[82; 92)
78 PATH@[82; 92)
79 PATH_SEGMENT@[82; 92)
80 NAME_REF@[82; 85)
81 IDENT@[82; 85) "Vec"
82 TYPE_ARG_LIST@[85; 92)
83 L_ANGLE@[85; 86)
84 TYPE_ARG@[86; 91)
85 PATH_TYPE@[86; 91)
86 PATH@[86; 91)
87 PATH_SEGMENT@[86; 91)
88 NAME_REF@[86; 91)
89 IDENT@[86; 91) "Event"
90 R_ANGLE@[91; 92)
91 R_PAREN@[92; 93)
92 WHITESPACE@[93; 94)
93 BLOCK_EXPR@[94; 389)
94 L_CURLY@[94; 95)
95 WHITESPACE@[95; 100)
96 LET_STMT@[100; 125)
97 LET_KW@[100; 103)
98 WHITESPACE@[103; 104)
99 BIND_PAT@[104; 120)
100 MUT_KW@[104; 107)
101 WHITESPACE@[107; 108)
102 NAME@[108; 120)
103 IDENT@[108; 120) "next_tok_idx"
104 WHITESPACE@[120; 121)
105 EQ@[121; 122)
106 WHITESPACE@[122; 123)
107 LITERAL@[123; 124)
108 INT_NUMBER@[123; 124) "0"
109 SEMI@[124; 125)
110 WHITESPACE@[125; 130)
111 LET_STMT@[130; 389)
112 LET_KW@[130; 133)
113 WHITESPACE@[133; 134)
114 BIND_PAT@[134; 140)
115 NAME@[134; 140)
116 IDENT@[134; 140) "eat_ws"
117 WHITESPACE@[140; 141)
118 EQ@[141; 142)
119 WHITESPACE@[142; 143)
120 LAMBDA_EXPR@[143; 389)
121 PARAM_LIST@[143; 388)
122 PIPE@[143; 144)
123 PARAM@[144; 159)
124 BIND_PAT@[144; 147)
125 NAME@[144; 147)
126 IDENT@[144; 147) "idx"
127 COLON@[147; 148)
128 WHITESPACE@[148; 149)
129 REFERENCE_TYPE@[149; 159)
130 AMP@[149; 150)
131 MUT_KW@[150; 153)
132 WHITESPACE@[153; 154)
133 PATH_TYPE@[154; 159)
134 PATH@[154; 159)
135 PATH_SEGMENT@[154; 159)
136 NAME_REF@[154; 159)
137 IDENT@[154; 159) "usize"
138 COMMA@[159; 160)
139 WHITESPACE@[160; 161)
140 PARAM@[161; 167)
141 REF_PAT@[161; 167)
142 AMP@[161; 162)
143 MUT_KW@[162; 165)
144 WHITESPACE@[165; 166)
145 err: `expected pattern`
146 ERROR@[166; 167)
147 PIPE@[166; 167)
148 err: `expected COMMA`
149 WHITESPACE@[167; 168)
150 err: `expected pattern`
151 PARAM@[168; 169)
152 ERROR@[168; 169)
153 L_CURLY@[168; 169)
154 err: `expected COMMA`
155 WHITESPACE@[169; 178)
156 err: `expected pattern`
157 PARAM@[178; 183)
158 ERROR@[178; 183)
159 WHILE_KW@[178; 183)
160 err: `expected COMMA`
161 WHITESPACE@[183; 184)
162 err: `expected pattern`
163 PARAM@[184; 187)
164 ERROR@[184; 187)
165 LET_KW@[184; 187)
166 err: `expected COMMA`
167 WHITESPACE@[187; 188)
168 PARAM@[188; 199)
169 TUPLE_STRUCT_PAT@[188; 199)
170 PATH@[188; 192)
171 PATH_SEGMENT@[188; 192)
172 NAME_REF@[188; 192)
173 IDENT@[188; 192) "Some"
174 L_PAREN@[192; 193)
175 BIND_PAT@[193; 198)
176 NAME@[193; 198)
177 IDENT@[193; 198) "token"
178 R_PAREN@[198; 199)
179 err: `expected COMMA`
180 WHITESPACE@[199; 200)
181 err: `expected pattern`
182 PARAM@[200; 201)
183 ERROR@[200; 201)
184 EQ@[200; 201)
185 err: `expected COMMA`
186 WHITESPACE@[201; 202)
187 PARAM@[202; 208)
188 BIND_PAT@[202; 208)
189 NAME@[202; 208)
190 IDENT@[202; 208) "tokens"
191 err: `expected COMMA`
192 err: `expected pattern`
193 PARAM@[208; 209)
194 ERROR@[208; 209)
195 DOT@[208; 209)
196 err: `expected COMMA`
197 PARAM@[209; 218)
198 TUPLE_STRUCT_PAT@[209; 218)
199 PATH@[209; 212)
200 PATH_SEGMENT@[209; 212)
201 NAME_REF@[209; 212)
202 IDENT@[209; 212) "get"
203 L_PAREN@[212; 213)
204 err: `expected pattern`
205 ERROR@[213; 214)
206 STAR@[213; 214)
207 err: `expected COMMA`
208 BIND_PAT@[214; 217)
209 NAME@[214; 217)
210 IDENT@[214; 217) "idx"
211 R_PAREN@[217; 218)
212 err: `expected COMMA`
213 WHITESPACE@[218; 219)
214 err: `expected pattern`
215 PARAM@[219; 220)
216 ERROR@[219; 220)
217 L_CURLY@[219; 220)
218 err: `expected COMMA`
219 WHITESPACE@[220; 233)
220 err: `expected pattern`
221 PARAM@[233; 235)
222 ERROR@[233; 235)
223 IF_KW@[233; 235)
224 err: `expected COMMA`
225 WHITESPACE@[235; 236)
226 err: `expected pattern`
227 PARAM@[236; 237)
228 ERROR@[236; 237)
229 EXCL@[236; 237)
230 err: `expected COMMA`
231 PARAM@[237; 242)
232 BIND_PAT@[237; 242)
233 NAME@[237; 242)
234 IDENT@[237; 242) "token"
235 err: `expected COMMA`
236 err: `expected pattern`
237 PARAM@[242; 243)
238 ERROR@[242; 243)
239 DOT@[242; 243)
240 err: `expected COMMA`
241 PARAM@[243; 247)
242 BIND_PAT@[243; 247)
243 NAME@[243; 247)
244 IDENT@[243; 247) "kind"
245 err: `expected COMMA`
246 err: `expected pattern`
247 PARAM@[247; 248)
248 ERROR@[247; 248)
249 DOT@[247; 248)
250 err: `expected COMMA`
251 PARAM@[248; 259)
252 TUPLE_STRUCT_PAT@[248; 259)
253 PATH@[248; 257)
254 PATH_SEGMENT@[248; 257)
255 NAME_REF@[248; 257)
256 IDENT@[248; 257) "is_trivia"
257 L_PAREN@[257; 258)
258 R_PAREN@[258; 259)
259 err: `expected COMMA`
260 WHITESPACE@[259; 260)
261 err: `expected pattern`
262 PARAM@[260; 261)
263 ERROR@[260; 261)
264 L_CURLY@[260; 261)
265 err: `expected COMMA`
266 WHITESPACE@[261; 278)
267 PARAM@[278; 283)
268 BIND_PAT@[278; 283)
269 NAME@[278; 283)
270 IDENT@[278; 283) "break"
271 err: `expected COMMA`
272 err: `expected pattern`
273 PARAM@[283; 284)
274 ERROR@[283; 284)
275 SEMI@[283; 284)
276 err: `expected COMMA`
277 WHITESPACE@[284; 297)
278 err: `expected pattern`
279 PARAM@[297; 298)
280 ERROR@[297; 298)
281 R_CURLY@[297; 298)
282 err: `expected COMMA`
283 WHITESPACE@[298; 311)
284 PARAM@[311; 318)
285 BIND_PAT@[311; 318)
286 NAME@[311; 318)
287 IDENT@[311; 318) "builder"
288 err: `expected COMMA`
289 err: `expected pattern`
290 PARAM@[318; 319)
291 ERROR@[318; 319)
292 DOT@[318; 319)
293 err: `expected COMMA`
294 PARAM@[319; 346)
295 TUPLE_STRUCT_PAT@[319; 346)
296 PATH@[319; 323)
297 PATH_SEGMENT@[319; 323)
298 NAME_REF@[319; 323)
299 IDENT@[319; 323) "leaf"
300 L_PAREN@[323; 324)
301 BIND_PAT@[324; 329)
302 NAME@[324; 329)
303 IDENT@[324; 329) "token"
304 err: `expected COMMA`
305 err: `expected pattern`
306 ERROR@[329; 330)
307 DOT@[329; 330)
308 err: `expected COMMA`
309 BIND_PAT@[330; 334)
310 NAME@[330; 334)
311 IDENT@[330; 334) "kind"
312 COMMA@[334; 335)
313 WHITESPACE@[335; 336)
314 BIND_PAT@[336; 341)
315 NAME@[336; 341)
316 IDENT@[336; 341) "token"
317 err: `expected COMMA`
318 err: `expected pattern`
319 ERROR@[341; 342)
320 DOT@[341; 342)
321 err: `expected COMMA`
322 BIND_PAT@[342; 345)
323 NAME@[342; 345)
324 IDENT@[342; 345) "len"
325 R_PAREN@[345; 346)
326 err: `expected COMMA`
327 err: `expected pattern`
328 PARAM@[346; 347)
329 ERROR@[346; 347)
330 SEMI@[346; 347)
331 err: `expected COMMA`
332 WHITESPACE@[347; 360)
333 err: `expected pattern`
334 PARAM@[360; 361)
335 ERROR@[360; 361)
336 STAR@[360; 361)
337 err: `expected COMMA`
338 PARAM@[361; 364)
339 BIND_PAT@[361; 364)
340 NAME@[361; 364)
341 IDENT@[361; 364) "idx"
342 err: `expected COMMA`
343 WHITESPACE@[364; 365)
344 err: `expected pattern`
345 PARAM@[365; 366)
346 ERROR@[365; 366)
347 PLUS@[365; 366)
348 err: `expected COMMA`
349 err: `expected pattern`
350 PARAM@[366; 367)
351 ERROR@[366; 367)
352 EQ@[366; 367)
353 err: `expected COMMA`
354 WHITESPACE@[367; 368)
355 PARAM@[368; 369)
356 LITERAL@[368; 369)
357 INT_NUMBER@[368; 369) "1"
358 err: `expected COMMA`
359 WHITESPACE@[369; 378)
360 err: `expected pattern`
361 PARAM@[378; 379)
362 ERROR@[378; 379)
363 R_CURLY@[378; 379)
364 err: `expected COMMA`
365 WHITESPACE@[379; 384)
366 err: `expected pattern`
367 PARAM@[384; 385)
368 ERROR@[384; 385)
369 R_CURLY@[384; 385)
370 err: `expected COMMA`
371 err: `expected pattern`
372 PARAM@[385; 386)
373 ERROR@[385; 386)
374 SEMI@[385; 386)
375 err: `expected COMMA`
376 WHITESPACE@[386; 387)
377 err: `expected pattern`
378 PARAM@[387; 388)
379 ERROR@[387; 388)
380 R_CURLY@[387; 388)
381 err: `expected COMMA`
382 err: `expected PIPE`
383 WHITESPACE@[388; 389)
384 err: `expected expression`
385 err: `expected SEMI`
386 err: `expected R_CURLY`
387 ERROR@[389; 389)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.rs b/crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.rs
new file mode 100644
index 000000000..31a1e435f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.rs
@@ -0,0 +1 @@
const unsafe fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.txt b/crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.txt
new file mode 100644
index 000000000..3932d033c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0001_const_unsafe_fn.txt
@@ -0,0 +1,18 @@
1FILE@[0; 25)
2 FUNCTION@[0; 24)
3 CONST_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 UNSAFE_KW@[6; 12)
6 WHITESPACE@[12; 13)
7 FN_KW@[13; 15)
8 WHITESPACE@[15; 16)
9 NAME@[16; 19)
10 IDENT@[16; 19) "foo"
11 PARAM_LIST@[19; 21)
12 L_PAREN@[19; 20)
13 R_PAREN@[20; 21)
14 WHITESPACE@[21; 22)
15 BLOCK_EXPR@[22; 24)
16 L_CURLY@[22; 23)
17 R_CURLY@[23; 24)
18 WHITESPACE@[24; 25)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0002_const_fn.rs b/crates/libsyntax2/tests/data/parser/inline/0002_const_fn.rs
new file mode 100644
index 000000000..8c84d9cd7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0002_const_fn.rs
@@ -0,0 +1 @@
const fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0002_const_fn.txt b/crates/libsyntax2/tests/data/parser/inline/0002_const_fn.txt
new file mode 100644
index 000000000..bc72ab235
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0002_const_fn.txt
@@ -0,0 +1,16 @@
1FILE@[0; 18)
2 FUNCTION@[0; 17)
3 CONST_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 FN_KW@[6; 8)
6 WHITESPACE@[8; 9)
7 NAME@[9; 12)
8 IDENT@[9; 12) "foo"
9 PARAM_LIST@[12; 14)
10 L_PAREN@[12; 13)
11 R_PAREN@[13; 14)
12 WHITESPACE@[14; 15)
13 BLOCK_EXPR@[15; 17)
14 L_CURLY@[15; 16)
15 R_CURLY@[16; 17)
16 WHITESPACE@[17; 18)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0003_extern_block.rs b/crates/libsyntax2/tests/data/parser/inline/0003_extern_block.rs
new file mode 100644
index 000000000..26a9ccd1e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0003_extern_block.rs
@@ -0,0 +1 @@
extern {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0003_extern_block.txt b/crates/libsyntax2/tests/data/parser/inline/0003_extern_block.txt
new file mode 100644
index 000000000..cbe9a1ebc
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0003_extern_block.txt
@@ -0,0 +1,8 @@
1FILE@[0; 10)
2 EXTERN_BLOCK_EXPR@[0; 9)
3 ABI@[0; 6)
4 EXTERN_KW@[0; 6)
5 WHITESPACE@[6; 7)
6 L_CURLY@[7; 8)
7 R_CURLY@[8; 9)
8 WHITESPACE@[9; 10)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.rs b/crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.rs
new file mode 100644
index 000000000..394a049f0
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.rs
@@ -0,0 +1 @@
extern fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.txt b/crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.txt
new file mode 100644
index 000000000..e7787d4ab
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0004_extern_fn.txt
@@ -0,0 +1,17 @@
1FILE@[0; 19)
2 FUNCTION@[0; 18)
3 ABI@[0; 6)
4 EXTERN_KW@[0; 6)
5 WHITESPACE@[6; 7)
6 FN_KW@[7; 9)
7 WHITESPACE@[9; 10)
8 NAME@[10; 13)
9 IDENT@[10; 13) "foo"
10 PARAM_LIST@[13; 15)
11 L_PAREN@[13; 14)
12 R_PAREN@[14; 15)
13 WHITESPACE@[15; 16)
14 BLOCK_EXPR@[16; 18)
15 L_CURLY@[16; 17)
16 R_CURLY@[17; 18)
17 WHITESPACE@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.rs b/crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.rs
new file mode 100644
index 000000000..49af74e1b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.rs
@@ -0,0 +1 @@
extern crate foo;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.txt b/crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.txt
new file mode 100644
index 000000000..eac8656ac
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0005_extern_crate.txt
@@ -0,0 +1,10 @@
1FILE@[0; 18)
2 EXTERN_CRATE_ITEM@[0; 17)
3 EXTERN_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 CRATE_KW@[7; 12)
6 WHITESPACE@[12; 13)
7 NAME@[13; 16)
8 IDENT@[13; 16) "foo"
9 SEMI@[16; 17)
10 WHITESPACE@[17; 18)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.rs b/crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.rs
new file mode 100644
index 000000000..04e021550
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.rs
@@ -0,0 +1 @@
unsafe trait T {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.txt b/crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.txt
new file mode 100644
index 000000000..afa6637d3
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0007_unsafe_trait.txt
@@ -0,0 +1,12 @@
1FILE@[0; 18)
2 TRAIT_ITEM@[0; 17)
3 UNSAFE_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 TRAIT_KW@[7; 12)
6 WHITESPACE@[12; 13)
7 NAME@[13; 14)
8 IDENT@[13; 14) "T"
9 WHITESPACE@[14; 15)
10 L_CURLY@[15; 16)
11 R_CURLY@[16; 17)
12 WHITESPACE@[17; 18)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.rs b/crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.rs
new file mode 100644
index 000000000..41055f41d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.rs
@@ -0,0 +1 @@
unsafe impl Foo {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.txt b/crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.txt
new file mode 100644
index 000000000..6fd3f868f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0008_unsafe_impl.txt
@@ -0,0 +1,15 @@
1FILE@[0; 19)
2 IMPL_ITEM@[0; 18)
3 UNSAFE_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 IMPL_KW@[7; 11)
6 WHITESPACE@[11; 12)
7 PATH_TYPE@[12; 15)
8 PATH@[12; 15)
9 PATH_SEGMENT@[12; 15)
10 NAME_REF@[12; 15)
11 IDENT@[12; 15) "Foo"
12 WHITESPACE@[15; 16)
13 L_CURLY@[16; 17)
14 R_CURLY@[17; 18)
15 WHITESPACE@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.rs b/crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.rs
new file mode 100644
index 000000000..03d29f324
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.rs
@@ -0,0 +1 @@
unsafe auto trait T {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.txt b/crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.txt
new file mode 100644
index 000000000..825a56f17
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0009_unsafe_auto_trait.txt
@@ -0,0 +1,14 @@
1FILE@[0; 23)
2 TRAIT_ITEM@[0; 22)
3 UNSAFE_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 AUTO_KW@[7; 11)
6 WHITESPACE@[11; 12)
7 TRAIT_KW@[12; 17)
8 WHITESPACE@[17; 18)
9 NAME@[18; 19)
10 IDENT@[18; 19) "T"
11 WHITESPACE@[19; 20)
12 L_CURLY@[20; 21)
13 R_CURLY@[21; 22)
14 WHITESPACE@[22; 23)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.rs b/crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.rs
new file mode 100644
index 000000000..9cd6c57bd
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.rs
@@ -0,0 +1 @@
unsafe default impl Foo {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.txt b/crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.txt
new file mode 100644
index 000000000..ab12d5fc0
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0010_unsafe_default_impl.txt
@@ -0,0 +1,17 @@
1FILE@[0; 27)
2 IMPL_ITEM@[0; 26)
3 UNSAFE_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 DEFAULT_KW@[7; 14)
6 WHITESPACE@[14; 15)
7 IMPL_KW@[15; 19)
8 WHITESPACE@[19; 20)
9 PATH_TYPE@[20; 23)
10 PATH@[20; 23)
11 PATH_SEGMENT@[20; 23)
12 NAME_REF@[20; 23)
13 IDENT@[20; 23) "Foo"
14 WHITESPACE@[23; 24)
15 L_CURLY@[24; 25)
16 R_CURLY@[25; 26)
17 WHITESPACE@[26; 27)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.rs b/crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.rs
new file mode 100644
index 000000000..33cfc4cd7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.rs
@@ -0,0 +1 @@
unsafe fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.txt b/crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.txt
new file mode 100644
index 000000000..9e5dcafa6
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0011_unsafe_fn.txt
@@ -0,0 +1,16 @@
1FILE@[0; 19)
2 FUNCTION@[0; 18)
3 UNSAFE_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 FN_KW@[7; 9)
6 WHITESPACE@[9; 10)
7 NAME@[10; 13)
8 IDENT@[10; 13) "foo"
9 PARAM_LIST@[13; 15)
10 L_PAREN@[13; 14)
11 R_PAREN@[14; 15)
12 WHITESPACE@[15; 16)
13 BLOCK_EXPR@[16; 18)
14 L_CURLY@[16; 17)
15 R_CURLY@[17; 18)
16 WHITESPACE@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.rs b/crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.rs
new file mode 100644
index 000000000..1295c2cd2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.rs
@@ -0,0 +1 @@
unsafe extern "C" fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.txt b/crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.txt
new file mode 100644
index 000000000..7ed4d42c1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0012_unsafe_extern_fn.txt
@@ -0,0 +1,21 @@
1FILE@[0; 30)
2 FUNCTION@[0; 29)
3 UNSAFE_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 ABI@[7; 17)
6 EXTERN_KW@[7; 13)
7 WHITESPACE@[13; 14)
8 STRING@[14; 17)
9 WHITESPACE@[17; 18)
10 FN_KW@[18; 20)
11 WHITESPACE@[20; 21)
12 NAME@[21; 24)
13 IDENT@[21; 24) "foo"
14 PARAM_LIST@[24; 26)
15 L_PAREN@[24; 25)
16 R_PAREN@[25; 26)
17 WHITESPACE@[26; 27)
18 BLOCK_EXPR@[27; 29)
19 L_CURLY@[27; 28)
20 R_CURLY@[28; 29)
21 WHITESPACE@[29; 30)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.rs b/crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.rs
new file mode 100644
index 000000000..26141e904
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.rs
@@ -0,0 +1 @@
fn foo(){} unsafe { } fn bar(){}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.txt b/crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.txt
new file mode 100644
index 000000000..d1bcffe77
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0013_unsafe_block_in_mod.txt
@@ -0,0 +1,35 @@
1FILE@[0; 33)
2 FUNCTION@[0; 10)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 BLOCK_EXPR@[8; 10)
11 L_CURLY@[8; 9)
12 R_CURLY@[9; 10)
13 WHITESPACE@[10; 11)
14 err: `expected an item`
15 ERROR@[11; 17)
16 UNSAFE_KW@[11; 17)
17 WHITESPACE@[17; 18)
18 err: `expected an item`
19 ERROR@[18; 21)
20 L_CURLY@[18; 19)
21 WHITESPACE@[19; 20)
22 R_CURLY@[20; 21)
23 WHITESPACE@[21; 22)
24 FUNCTION@[22; 32)
25 FN_KW@[22; 24)
26 WHITESPACE@[24; 25)
27 NAME@[25; 28)
28 IDENT@[25; 28) "bar"
29 PARAM_LIST@[28; 30)
30 L_PAREN@[28; 29)
31 R_PAREN@[29; 30)
32 BLOCK_EXPR@[30; 32)
33 L_CURLY@[30; 31)
34 R_CURLY@[31; 32)
35 WHITESPACE@[32; 33)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.rs b/crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.rs
new file mode 100644
index 000000000..defd110c4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.rs
@@ -0,0 +1 @@
type Result<T> = ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.txt b/crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.txt
new file mode 100644
index 000000000..e39e57889
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0014_type_item_type_params.txt
@@ -0,0 +1,20 @@
1FILE@[0; 21)
2 TYPE_ITEM@[0; 20)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 11)
6 IDENT@[5; 11) "Result"
7 TYPE_PARAM_LIST@[11; 14)
8 L_ANGLE@[11; 12)
9 TYPE_PARAM@[12; 13)
10 NAME@[12; 13)
11 IDENT@[12; 13) "T"
12 R_ANGLE@[13; 14)
13 WHITESPACE@[14; 15)
14 EQ@[15; 16)
15 WHITESPACE@[16; 17)
16 TUPLE_TYPE@[17; 19)
17 L_PAREN@[17; 18)
18 R_PAREN@[18; 19)
19 SEMI@[19; 20)
20 WHITESPACE@[20; 21)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0015_type_item.rs b/crates/libsyntax2/tests/data/parser/inline/0015_type_item.rs
new file mode 100644
index 000000000..04c0344fa
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0015_type_item.rs
@@ -0,0 +1 @@
type Foo = Bar;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0015_type_item.txt b/crates/libsyntax2/tests/data/parser/inline/0015_type_item.txt
new file mode 100644
index 000000000..964071aa1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0015_type_item.txt
@@ -0,0 +1,16 @@
1FILE@[0; 16)
2 TYPE_ITEM@[0; 15)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 8)
6 IDENT@[5; 8) "Foo"
7 WHITESPACE@[8; 9)
8 EQ@[9; 10)
9 WHITESPACE@[10; 11)
10 PATH_TYPE@[11; 14)
11 PATH@[11; 14)
12 PATH_SEGMENT@[11; 14)
13 NAME_REF@[11; 14)
14 IDENT@[11; 14) "Bar"
15 SEMI@[14; 15)
16 WHITESPACE@[15; 16)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.rs b/crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.rs
new file mode 100644
index 000000000..a602d07f0
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.rs
@@ -0,0 +1 @@
type Foo where Foo: Copy = ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.txt b/crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.txt
new file mode 100644
index 000000000..2f3c52960
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0016_type_item_where_clause.txt
@@ -0,0 +1,31 @@
1FILE@[0; 31)
2 TYPE_ITEM@[0; 30)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 8)
6 IDENT@[5; 8) "Foo"
7 WHITESPACE@[8; 9)
8 WHERE_CLAUSE@[9; 24)
9 WHERE_KW@[9; 14)
10 WHITESPACE@[14; 15)
11 WHERE_PRED@[15; 24)
12 PATH_TYPE@[15; 18)
13 PATH@[15; 18)
14 PATH_SEGMENT@[15; 18)
15 NAME_REF@[15; 18)
16 IDENT@[15; 18) "Foo"
17 COLON@[18; 19)
18 WHITESPACE@[19; 20)
19 PATH@[20; 24)
20 PATH_SEGMENT@[20; 24)
21 NAME_REF@[20; 24)
22 IDENT@[20; 24) "Copy"
23 err: `expected COMMA`
24 WHITESPACE@[24; 25)
25 EQ@[25; 26)
26 WHITESPACE@[26; 27)
27 TUPLE_TYPE@[27; 29)
28 L_PAREN@[27; 28)
29 R_PAREN@[28; 29)
30 SEMI@[29; 30)
31 WHITESPACE@[30; 31)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0017_paren_type.rs b/crates/libsyntax2/tests/data/parser/inline/0017_paren_type.rs
new file mode 100644
index 000000000..6e1b25101
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0017_paren_type.rs
@@ -0,0 +1 @@
type T = (i32);
diff --git a/crates/libsyntax2/tests/data/parser/inline/0017_paren_type.txt b/crates/libsyntax2/tests/data/parser/inline/0017_paren_type.txt
new file mode 100644
index 000000000..1194fb02c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0017_paren_type.txt
@@ -0,0 +1,19 @@
1FILE@[0; 16)
2 TYPE_ITEM@[0; 15)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 PAREN_TYPE@[9; 14)
11 L_PAREN@[9; 10)
12 PATH_TYPE@[10; 13)
13 PATH@[10; 13)
14 PATH_SEGMENT@[10; 13)
15 NAME_REF@[10; 13)
16 IDENT@[10; 13) "i32"
17 R_PAREN@[13; 14)
18 SEMI@[14; 15)
19 WHITESPACE@[15; 16)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0018_unit_type.rs b/crates/libsyntax2/tests/data/parser/inline/0018_unit_type.rs
new file mode 100644
index 000000000..c039cf7d3
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0018_unit_type.rs
@@ -0,0 +1 @@
type T = ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0018_unit_type.txt b/crates/libsyntax2/tests/data/parser/inline/0018_unit_type.txt
new file mode 100644
index 000000000..e52af7b1e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0018_unit_type.txt
@@ -0,0 +1,14 @@
1FILE@[0; 13)
2 TYPE_ITEM@[0; 12)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 TUPLE_TYPE@[9; 11)
11 L_PAREN@[9; 10)
12 R_PAREN@[10; 11)
13 SEMI@[11; 12)
14 WHITESPACE@[12; 13)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.rs b/crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.rs
new file mode 100644
index 000000000..cb66bad24
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.rs
@@ -0,0 +1 @@
type T = (i32,);
diff --git a/crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.txt b/crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.txt
new file mode 100644
index 000000000..7b8e06c25
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0019_singleton_tuple_type.txt
@@ -0,0 +1,20 @@
1FILE@[0; 17)
2 TYPE_ITEM@[0; 16)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 TUPLE_TYPE@[9; 15)
11 L_PAREN@[9; 10)
12 PATH_TYPE@[10; 13)
13 PATH@[10; 13)
14 PATH_SEGMENT@[10; 13)
15 NAME_REF@[10; 13)
16 IDENT@[10; 13) "i32"
17 COMMA@[13; 14)
18 R_PAREN@[14; 15)
19 SEMI@[15; 16)
20 WHITESPACE@[16; 17)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0020_never_type.rs b/crates/libsyntax2/tests/data/parser/inline/0020_never_type.rs
new file mode 100644
index 000000000..de399fcf4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0020_never_type.rs
@@ -0,0 +1 @@
type Never = !;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0020_never_type.txt b/crates/libsyntax2/tests/data/parser/inline/0020_never_type.txt
new file mode 100644
index 000000000..89f8a9eea
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0020_never_type.txt
@@ -0,0 +1,13 @@
1FILE@[0; 16)
2 TYPE_ITEM@[0; 15)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 10)
6 IDENT@[5; 10) "Never"
7 WHITESPACE@[10; 11)
8 EQ@[11; 12)
9 WHITESPACE@[12; 13)
10 NEVER_TYPE@[13; 14)
11 EXCL@[13; 14)
12 SEMI@[14; 15)
13 WHITESPACE@[15; 16)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.rs b/crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.rs
new file mode 100644
index 000000000..fae705131
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.rs
@@ -0,0 +1 @@
type T = *();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.txt b/crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.txt
new file mode 100644
index 000000000..d86fc6388
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0021_pointer_type_no_mutability.txt
@@ -0,0 +1,17 @@
1FILE@[0; 14)
2 TYPE_ITEM@[0; 13)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 POINTER_TYPE@[9; 12)
11 STAR@[9; 10)
12 err: `expected mut or const in raw pointer type (use `*mut T` or `*const T` as appropriate)`
13 TUPLE_TYPE@[10; 12)
14 L_PAREN@[10; 11)
15 R_PAREN@[11; 12)
16 SEMI@[12; 13)
17 WHITESPACE@[13; 14)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.rs b/crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.rs
new file mode 100644
index 000000000..04b2bb9ba
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.rs
@@ -0,0 +1,2 @@
1type M = *mut ();
2type C = *mut ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.txt b/crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.txt
new file mode 100644
index 000000000..fbeba506e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0022_pointer_type_mut.txt
@@ -0,0 +1,35 @@
1FILE@[0; 36)
2 TYPE_ITEM@[0; 17)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "M"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 POINTER_TYPE@[9; 16)
11 STAR@[9; 10)
12 MUT_KW@[10; 13)
13 WHITESPACE@[13; 14)
14 TUPLE_TYPE@[14; 16)
15 L_PAREN@[14; 15)
16 R_PAREN@[15; 16)
17 SEMI@[16; 17)
18 WHITESPACE@[17; 18)
19 TYPE_ITEM@[18; 35)
20 TYPE_KW@[18; 22)
21 WHITESPACE@[22; 23)
22 NAME@[23; 24)
23 IDENT@[23; 24) "C"
24 WHITESPACE@[24; 25)
25 EQ@[25; 26)
26 WHITESPACE@[26; 27)
27 POINTER_TYPE@[27; 34)
28 STAR@[27; 28)
29 MUT_KW@[28; 31)
30 WHITESPACE@[31; 32)
31 TUPLE_TYPE@[32; 34)
32 L_PAREN@[32; 33)
33 R_PAREN@[33; 34)
34 SEMI@[34; 35)
35 WHITESPACE@[35; 36)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.rs b/crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.rs
new file mode 100644
index 000000000..a94851443
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.rs
@@ -0,0 +1 @@
type T = [() 92];
diff --git a/crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.txt b/crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.txt
new file mode 100644
index 000000000..4d90d52c7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0023_array_type_missing_semi.txt
@@ -0,0 +1,27 @@
1FILE@[0; 18)
2 TYPE_ITEM@[0; 12)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 SLICE_TYPE@[9; 12)
11 L_BRACK@[9; 10)
12 TUPLE_TYPE@[10; 12)
13 L_PAREN@[10; 11)
14 R_PAREN@[11; 12)
15 err: `expected `;` or `]``
16 err: `expected SEMI`
17 WHITESPACE@[12; 13)
18 err: `expected an item`
19 ERROR@[13; 15)
20 INT_NUMBER@[13; 15) "92"
21 err: `expected an item`
22 ERROR@[15; 16)
23 R_BRACK@[15; 16)
24 err: `expected an item`
25 ERROR@[16; 17)
26 SEMI@[16; 17)
27 WHITESPACE@[17; 18)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0024_array_type.rs b/crates/libsyntax2/tests/data/parser/inline/0024_array_type.rs
new file mode 100644
index 000000000..27eb22f22
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0024_array_type.rs
@@ -0,0 +1 @@
type T = [(); 92];
diff --git a/crates/libsyntax2/tests/data/parser/inline/0024_array_type.txt b/crates/libsyntax2/tests/data/parser/inline/0024_array_type.txt
new file mode 100644
index 000000000..5a6b76904
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0024_array_type.txt
@@ -0,0 +1,21 @@
1FILE@[0; 19)
2 TYPE_ITEM@[0; 18)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 ARRAY_TYPE@[9; 17)
11 L_BRACK@[9; 10)
12 TUPLE_TYPE@[10; 12)
13 L_PAREN@[10; 11)
14 R_PAREN@[11; 12)
15 SEMI@[12; 13)
16 WHITESPACE@[13; 14)
17 LITERAL@[14; 16)
18 INT_NUMBER@[14; 16) "92"
19 R_BRACK@[16; 17)
20 SEMI@[17; 18)
21 WHITESPACE@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0025_slice_type.rs b/crates/libsyntax2/tests/data/parser/inline/0025_slice_type.rs
new file mode 100644
index 000000000..4da1af827
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0025_slice_type.rs
@@ -0,0 +1 @@
type T = [()];
diff --git a/crates/libsyntax2/tests/data/parser/inline/0025_slice_type.txt b/crates/libsyntax2/tests/data/parser/inline/0025_slice_type.txt
new file mode 100644
index 000000000..52508cda4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0025_slice_type.txt
@@ -0,0 +1,17 @@
1FILE@[0; 15)
2 TYPE_ITEM@[0; 14)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "T"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 SLICE_TYPE@[9; 13)
11 L_BRACK@[9; 10)
12 TUPLE_TYPE@[10; 12)
13 L_PAREN@[10; 11)
14 R_PAREN@[11; 12)
15 R_BRACK@[12; 13)
16 SEMI@[13; 14)
17 WHITESPACE@[14; 15)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.rs b/crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.rs
new file mode 100644
index 000000000..3ac0badab
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.rs
@@ -0,0 +1,3 @@
1type A = &();
2type B = &'static ();
3type C = &mut ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.txt b/crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.txt
new file mode 100644
index 000000000..b6bd6a48c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0026_reference_type;.txt
@@ -0,0 +1,50 @@
1FILE@[0; 54)
2 TYPE_ITEM@[0; 13)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 REFERENCE_TYPE@[9; 12)
11 AMP@[9; 10)
12 TUPLE_TYPE@[10; 12)
13 L_PAREN@[10; 11)
14 R_PAREN@[11; 12)
15 SEMI@[12; 13)
16 WHITESPACE@[13; 14)
17 TYPE_ITEM@[14; 35)
18 TYPE_KW@[14; 18)
19 WHITESPACE@[18; 19)
20 NAME@[19; 20)
21 IDENT@[19; 20) "B"
22 WHITESPACE@[20; 21)
23 EQ@[21; 22)
24 WHITESPACE@[22; 23)
25 REFERENCE_TYPE@[23; 34)
26 AMP@[23; 24)
27 LIFETIME@[24; 31) "'static"
28 WHITESPACE@[31; 32)
29 TUPLE_TYPE@[32; 34)
30 L_PAREN@[32; 33)
31 R_PAREN@[33; 34)
32 SEMI@[34; 35)
33 WHITESPACE@[35; 36)
34 TYPE_ITEM@[36; 53)
35 TYPE_KW@[36; 40)
36 WHITESPACE@[40; 41)
37 NAME@[41; 42)
38 IDENT@[41; 42) "C"
39 WHITESPACE@[42; 43)
40 EQ@[43; 44)
41 WHITESPACE@[44; 45)
42 REFERENCE_TYPE@[45; 52)
43 AMP@[45; 46)
44 MUT_KW@[46; 49)
45 WHITESPACE@[49; 50)
46 TUPLE_TYPE@[50; 52)
47 L_PAREN@[50; 51)
48 R_PAREN@[51; 52)
49 SEMI@[52; 53)
50 WHITESPACE@[53; 54)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.rs b/crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.rs
new file mode 100644
index 000000000..7952dbd57
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.rs
@@ -0,0 +1 @@
type Placeholder = _;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.txt b/crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.txt
new file mode 100644
index 000000000..5e6e6c397
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0027_placeholder_type.txt
@@ -0,0 +1,13 @@
1FILE@[0; 22)
2 TYPE_ITEM@[0; 21)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 16)
6 IDENT@[5; 16) "Placeholder"
7 WHITESPACE@[16; 17)
8 EQ@[17; 18)
9 WHITESPACE@[18; 19)
10 PLACEHOLDER_TYPE@[19; 20)
11 UNDERSCORE@[19; 20)
12 SEMI@[20; 21)
13 WHITESPACE@[21; 22)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.rs b/crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.rs
new file mode 100644
index 000000000..c9bf3bdb4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.rs
@@ -0,0 +1,3 @@
1type A = fn();
2type B = unsafe fn();
3type C = unsafe extern "C" fn();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.txt b/crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.txt
new file mode 100644
index 000000000..31818365a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0028_fn_pointer_type.txt
@@ -0,0 +1,55 @@
1FILE@[0; 70)
2 TYPE_ITEM@[0; 14)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 FN_POINTER_TYPE@[9; 13)
11 FN_KW@[9; 11)
12 PARAM_LIST@[11; 13)
13 L_PAREN@[11; 12)
14 R_PAREN@[12; 13)
15 SEMI@[13; 14)
16 WHITESPACE@[14; 15)
17 TYPE_ITEM@[15; 36)
18 TYPE_KW@[15; 19)
19 WHITESPACE@[19; 20)
20 NAME@[20; 21)
21 IDENT@[20; 21) "B"
22 WHITESPACE@[21; 22)
23 EQ@[22; 23)
24 WHITESPACE@[23; 24)
25 FN_POINTER_TYPE@[24; 35)
26 UNSAFE_KW@[24; 30)
27 WHITESPACE@[30; 31)
28 FN_KW@[31; 33)
29 PARAM_LIST@[33; 35)
30 L_PAREN@[33; 34)
31 R_PAREN@[34; 35)
32 SEMI@[35; 36)
33 WHITESPACE@[36; 37)
34 TYPE_ITEM@[37; 69)
35 TYPE_KW@[37; 41)
36 WHITESPACE@[41; 42)
37 NAME@[42; 43)
38 IDENT@[42; 43) "C"
39 WHITESPACE@[43; 44)
40 EQ@[44; 45)
41 WHITESPACE@[45; 46)
42 FN_POINTER_TYPE@[46; 68)
43 UNSAFE_KW@[46; 52)
44 WHITESPACE@[52; 53)
45 ABI@[53; 63)
46 EXTERN_KW@[53; 59)
47 WHITESPACE@[59; 60)
48 STRING@[60; 63)
49 WHITESPACE@[63; 64)
50 FN_KW@[64; 66)
51 PARAM_LIST@[66; 68)
52 L_PAREN@[66; 67)
53 R_PAREN@[67; 68)
54 SEMI@[68; 69)
55 WHITESPACE@[69; 70)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.rs b/crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.rs
new file mode 100644
index 000000000..f014914ff
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.rs
@@ -0,0 +1 @@
type F = unsafe ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt b/crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt
new file mode 100644
index 000000000..ddec1b866
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt
@@ -0,0 +1,23 @@
1FILE@[0; 20)
2 TYPE_ITEM@[0; 15)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "F"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 UNSAFE_KW@[9; 15)
11 err: `expected `fn``
12 err: `expected SEMI`
13 WHITESPACE@[15; 16)
14 err: `expected an item`
15 ERROR@[16; 17)
16 L_PAREN@[16; 17)
17 err: `expected an item`
18 ERROR@[17; 18)
19 R_PAREN@[17; 18)
20 err: `expected an item`
21 ERROR@[18; 19)
22 SEMI@[18; 19)
23 WHITESPACE@[19; 20)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.rs b/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.rs
new file mode 100644
index 000000000..e3ba5e87f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.rs
@@ -0,0 +1 @@
type F = fn() -> ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt b/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt
new file mode 100644
index 000000000..447b1ed3f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt
@@ -0,0 +1,22 @@
1FILE@[0; 21)
2 TYPE_ITEM@[0; 20)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "F"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 FN_POINTER_TYPE@[9; 19)
11 FN_KW@[9; 11)
12 PARAM_LIST@[11; 13)
13 L_PAREN@[11; 12)
14 R_PAREN@[12; 13)
15 WHITESPACE@[13; 14)
16 THIN_ARROW@[14; 16)
17 WHITESPACE@[16; 17)
18 TUPLE_TYPE@[17; 19)
19 L_PAREN@[17; 18)
20 R_PAREN@[18; 19)
21 SEMI@[19; 20)
22 WHITESPACE@[20; 21)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0031_for_type.rs b/crates/libsyntax2/tests/data/parser/inline/0031_for_type.rs
new file mode 100644
index 000000000..4d6a18c6b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0031_for_type.rs
@@ -0,0 +1 @@
type A = for<'a> fn() -> ();
diff --git a/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt b/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt
new file mode 100644
index 000000000..65753a702
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt
@@ -0,0 +1,30 @@
1FILE@[0; 29)
2 TYPE_ITEM@[0; 28)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 FOR_TYPE@[9; 27)
11 FOR_KW@[9; 12)
12 TYPE_PARAM_LIST@[12; 16)
13 L_ANGLE@[12; 13)
14 LIFETIME_PARAM@[13; 15)
15 LIFETIME@[13; 15) "'a"
16 R_ANGLE@[15; 16)
17 WHITESPACE@[16; 17)
18 FN_POINTER_TYPE@[17; 27)
19 FN_KW@[17; 19)
20 PARAM_LIST@[19; 21)
21 L_PAREN@[19; 20)
22 R_PAREN@[20; 21)
23 WHITESPACE@[21; 22)
24 THIN_ARROW@[22; 24)
25 WHITESPACE@[24; 25)
26 TUPLE_TYPE@[25; 27)
27 L_PAREN@[25; 26)
28 R_PAREN@[26; 27)
29 SEMI@[27; 28)
30 WHITESPACE@[28; 29)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0032_path_type.rs b/crates/libsyntax2/tests/data/parser/inline/0032_path_type.rs
new file mode 100644
index 000000000..bf94f32e1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0032_path_type.rs
@@ -0,0 +1,4 @@
1type A = Foo;
2type B = ::Foo;
3type C = self::Foo;
4type D = super::Foo;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0032_path_type.txt b/crates/libsyntax2/tests/data/parser/inline/0032_path_type.txt
new file mode 100644
index 000000000..d9085118a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0032_path_type.txt
@@ -0,0 +1,70 @@
1FILE@[0; 71)
2 TYPE_ITEM@[0; 13)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 PATH_TYPE@[9; 12)
11 PATH@[9; 12)
12 PATH_SEGMENT@[9; 12)
13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "Foo"
15 SEMI@[12; 13)
16 WHITESPACE@[13; 14)
17 TYPE_ITEM@[14; 29)
18 TYPE_KW@[14; 18)
19 WHITESPACE@[18; 19)
20 NAME@[19; 20)
21 IDENT@[19; 20) "B"
22 WHITESPACE@[20; 21)
23 EQ@[21; 22)
24 WHITESPACE@[22; 23)
25 PATH_TYPE@[23; 28)
26 PATH@[23; 28)
27 PATH_SEGMENT@[23; 28)
28 COLONCOLON@[23; 25)
29 NAME_REF@[25; 28)
30 IDENT@[25; 28) "Foo"
31 SEMI@[28; 29)
32 WHITESPACE@[29; 30)
33 TYPE_ITEM@[30; 49)
34 TYPE_KW@[30; 34)
35 WHITESPACE@[34; 35)
36 NAME@[35; 36)
37 IDENT@[35; 36) "C"
38 WHITESPACE@[36; 37)
39 EQ@[37; 38)
40 WHITESPACE@[38; 39)
41 PATH_TYPE@[39; 48)
42 PATH@[39; 48)
43 PATH@[39; 43)
44 PATH_SEGMENT@[39; 43)
45 SELF_KW@[39; 43)
46 COLONCOLON@[43; 45)
47 PATH_SEGMENT@[45; 48)
48 NAME_REF@[45; 48)
49 IDENT@[45; 48) "Foo"
50 SEMI@[48; 49)
51 WHITESPACE@[49; 50)
52 TYPE_ITEM@[50; 70)
53 TYPE_KW@[50; 54)
54 WHITESPACE@[54; 55)
55 NAME@[55; 56)
56 IDENT@[55; 56) "D"
57 WHITESPACE@[56; 57)
58 EQ@[57; 58)
59 WHITESPACE@[58; 59)
60 PATH_TYPE@[59; 69)
61 PATH@[59; 69)
62 PATH@[59; 64)
63 PATH_SEGMENT@[59; 64)
64 SUPER_KW@[59; 64)
65 COLONCOLON@[64; 66)
66 PATH_SEGMENT@[66; 69)
67 NAME_REF@[66; 69)
68 IDENT@[66; 69) "Foo"
69 SEMI@[69; 70)
70 WHITESPACE@[70; 71)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.rs b/crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.rs
new file mode 100644
index 000000000..820a9e72c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.rs
@@ -0,0 +1,8 @@
1fn main() {
2 let a = ();
3 let mut b = ();
4 let ref c = ();
5 let ref mut d = ();
6 let e @ _ = ();
7 let ref mut f @ g @ _ = ();
8}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.txt b/crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.txt
new file mode 100644
index 000000000..e8e4e4c2b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0034_bind_pat.txt
@@ -0,0 +1,127 @@
1FILE@[0; 146)
2 FUNCTION@[0; 145)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 145)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 LET_STMT@[16; 27)
15 LET_KW@[16; 19)
16 WHITESPACE@[19; 20)
17 BIND_PAT@[20; 21)
18 NAME@[20; 21)
19 IDENT@[20; 21) "a"
20 WHITESPACE@[21; 22)
21 EQ@[22; 23)
22 WHITESPACE@[23; 24)
23 TUPLE_EXPR@[24; 26)
24 L_PAREN@[24; 25)
25 R_PAREN@[25; 26)
26 SEMI@[26; 27)
27 WHITESPACE@[27; 32)
28 LET_STMT@[32; 47)
29 LET_KW@[32; 35)
30 WHITESPACE@[35; 36)
31 BIND_PAT@[36; 41)
32 MUT_KW@[36; 39)
33 WHITESPACE@[39; 40)
34 NAME@[40; 41)
35 IDENT@[40; 41) "b"
36 WHITESPACE@[41; 42)
37 EQ@[42; 43)
38 WHITESPACE@[43; 44)
39 TUPLE_EXPR@[44; 46)
40 L_PAREN@[44; 45)
41 R_PAREN@[45; 46)
42 SEMI@[46; 47)
43 WHITESPACE@[47; 52)
44 LET_STMT@[52; 67)
45 LET_KW@[52; 55)
46 WHITESPACE@[55; 56)
47 BIND_PAT@[56; 61)
48 REF_KW@[56; 59)
49 WHITESPACE@[59; 60)
50 NAME@[60; 61)
51 IDENT@[60; 61) "c"
52 WHITESPACE@[61; 62)
53 EQ@[62; 63)
54 WHITESPACE@[63; 64)
55 TUPLE_EXPR@[64; 66)
56 L_PAREN@[64; 65)
57 R_PAREN@[65; 66)
58 SEMI@[66; 67)
59 WHITESPACE@[67; 72)
60 LET_STMT@[72; 91)
61 LET_KW@[72; 75)
62 WHITESPACE@[75; 76)
63 BIND_PAT@[76; 85)
64 REF_KW@[76; 79)
65 WHITESPACE@[79; 80)
66 MUT_KW@[80; 83)
67 WHITESPACE@[83; 84)
68 NAME@[84; 85)
69 IDENT@[84; 85) "d"
70 WHITESPACE@[85; 86)
71 EQ@[86; 87)
72 WHITESPACE@[87; 88)
73 TUPLE_EXPR@[88; 90)
74 L_PAREN@[88; 89)
75 R_PAREN@[89; 90)
76 SEMI@[90; 91)
77 WHITESPACE@[91; 96)
78 LET_STMT@[96; 111)
79 LET_KW@[96; 99)
80 WHITESPACE@[99; 100)
81 BIND_PAT@[100; 105)
82 NAME@[100; 101)
83 IDENT@[100; 101) "e"
84 WHITESPACE@[101; 102)
85 AT@[102; 103)
86 WHITESPACE@[103; 104)
87 PLACEHOLDER_PAT@[104; 105)
88 UNDERSCORE@[104; 105)
89 WHITESPACE@[105; 106)
90 EQ@[106; 107)
91 WHITESPACE@[107; 108)
92 TUPLE_EXPR@[108; 110)
93 L_PAREN@[108; 109)
94 R_PAREN@[109; 110)
95 SEMI@[110; 111)
96 WHITESPACE@[111; 116)
97 LET_STMT@[116; 143)
98 LET_KW@[116; 119)
99 WHITESPACE@[119; 120)
100 BIND_PAT@[120; 137)
101 REF_KW@[120; 123)
102 WHITESPACE@[123; 124)
103 MUT_KW@[124; 127)
104 WHITESPACE@[127; 128)
105 NAME@[128; 129)
106 IDENT@[128; 129) "f"
107 WHITESPACE@[129; 130)
108 AT@[130; 131)
109 WHITESPACE@[131; 132)
110 BIND_PAT@[132; 137)
111 NAME@[132; 133)
112 IDENT@[132; 133) "g"
113 WHITESPACE@[133; 134)
114 AT@[134; 135)
115 WHITESPACE@[135; 136)
116 PLACEHOLDER_PAT@[136; 137)
117 UNDERSCORE@[136; 137)
118 WHITESPACE@[137; 138)
119 EQ@[138; 139)
120 WHITESPACE@[139; 140)
121 TUPLE_EXPR@[140; 142)
122 L_PAREN@[140; 141)
123 R_PAREN@[141; 142)
124 SEMI@[142; 143)
125 WHITESPACE@[143; 144)
126 R_CURLY@[144; 145)
127 WHITESPACE@[145; 146)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.rs b/crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.rs
new file mode 100644
index 000000000..de41f5cae
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.rs
@@ -0,0 +1,4 @@
1fn main() {
2 let &a = ();
3 let &mut b = ();
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.txt b/crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.txt
new file mode 100644
index 000000000..6fbffd8b7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0035_ref_pat.txt
@@ -0,0 +1,49 @@
1FILE@[0; 52)
2 FUNCTION@[0; 51)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 51)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 LET_STMT@[16; 28)
15 LET_KW@[16; 19)
16 WHITESPACE@[19; 20)
17 REF_PAT@[20; 22)
18 AMP@[20; 21)
19 BIND_PAT@[21; 22)
20 NAME@[21; 22)
21 IDENT@[21; 22) "a"
22 WHITESPACE@[22; 23)
23 EQ@[23; 24)
24 WHITESPACE@[24; 25)
25 TUPLE_EXPR@[25; 27)
26 L_PAREN@[25; 26)
27 R_PAREN@[26; 27)
28 SEMI@[27; 28)
29 WHITESPACE@[28; 33)
30 LET_STMT@[33; 49)
31 LET_KW@[33; 36)
32 WHITESPACE@[36; 37)
33 REF_PAT@[37; 43)
34 AMP@[37; 38)
35 MUT_KW@[38; 41)
36 WHITESPACE@[41; 42)
37 BIND_PAT@[42; 43)
38 NAME@[42; 43)
39 IDENT@[42; 43) "b"
40 WHITESPACE@[43; 44)
41 EQ@[44; 45)
42 WHITESPACE@[45; 46)
43 TUPLE_EXPR@[46; 48)
44 L_PAREN@[46; 47)
45 R_PAREN@[47; 48)
46 SEMI@[48; 49)
47 WHITESPACE@[49; 50)
48 R_CURLY@[50; 51)
49 WHITESPACE@[51; 52)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.rs b/crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.rs
new file mode 100644
index 000000000..4d719c433
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.rs
@@ -0,0 +1 @@
fn main() { let _ = (); }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.txt b/crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.txt
new file mode 100644
index 000000000..8c63cdfae
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0036_placeholder_pat.txt
@@ -0,0 +1,28 @@
1FILE@[0; 26)
2 FUNCTION@[0; 25)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 25)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 12)
14 LET_STMT@[12; 23)
15 LET_KW@[12; 15)
16 WHITESPACE@[15; 16)
17 PLACEHOLDER_PAT@[16; 17)
18 UNDERSCORE@[16; 17)
19 WHITESPACE@[17; 18)
20 EQ@[18; 19)
21 WHITESPACE@[19; 20)
22 TUPLE_EXPR@[20; 22)
23 L_PAREN@[20; 21)
24 R_PAREN@[21; 22)
25 SEMI@[22; 23)
26 WHITESPACE@[23; 24)
27 R_CURLY@[24; 25)
28 WHITESPACE@[25; 26)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.rs b/crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.rs
new file mode 100644
index 000000000..faeefde94
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.rs
@@ -0,0 +1,4 @@
1pub(crate) struct S;
2pub(self) struct S;
3pub(self) struct S;
4pub(self) struct S;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.txt b/crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.txt
new file mode 100644
index 000000000..113ac59e2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0037_crate_visibility.txt
@@ -0,0 +1,53 @@
1FILE@[0; 81)
2 STRUCT_ITEM@[0; 20)
3 VISIBILITY@[0; 10)
4 PUB_KW@[0; 3)
5 L_PAREN@[3; 4)
6 CRATE_KW@[4; 9)
7 R_PAREN@[9; 10)
8 WHITESPACE@[10; 11)
9 STRUCT_KW@[11; 17)
10 WHITESPACE@[17; 18)
11 NAME@[18; 19)
12 IDENT@[18; 19) "S"
13 SEMI@[19; 20)
14 WHITESPACE@[20; 21)
15 STRUCT_ITEM@[21; 40)
16 VISIBILITY@[21; 30)
17 PUB_KW@[21; 24)
18 L_PAREN@[24; 25)
19 SELF_KW@[25; 29)
20 R_PAREN@[29; 30)
21 WHITESPACE@[30; 31)
22 STRUCT_KW@[31; 37)
23 WHITESPACE@[37; 38)
24 NAME@[38; 39)
25 IDENT@[38; 39) "S"
26 SEMI@[39; 40)
27 WHITESPACE@[40; 41)
28 STRUCT_ITEM@[41; 60)
29 VISIBILITY@[41; 50)
30 PUB_KW@[41; 44)
31 L_PAREN@[44; 45)
32 SELF_KW@[45; 49)
33 R_PAREN@[49; 50)
34 WHITESPACE@[50; 51)
35 STRUCT_KW@[51; 57)
36 WHITESPACE@[57; 58)
37 NAME@[58; 59)
38 IDENT@[58; 59) "S"
39 SEMI@[59; 60)
40 WHITESPACE@[60; 61)
41 STRUCT_ITEM@[61; 80)
42 VISIBILITY@[61; 70)
43 PUB_KW@[61; 64)
44 L_PAREN@[64; 65)
45 SELF_KW@[65; 69)
46 R_PAREN@[69; 70)
47 WHITESPACE@[70; 71)
48 STRUCT_KW@[71; 77)
49 WHITESPACE@[77; 78)
50 NAME@[78; 79)
51 IDENT@[78; 79) "S"
52 SEMI@[79; 80)
53 WHITESPACE@[80; 81)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.rs b/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.rs
new file mode 100644
index 000000000..d22d8cada
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.rs
@@ -0,0 +1,2 @@
1fn foo() {}
2fn bar() -> () {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt b/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt
new file mode 100644
index 000000000..58583eefe
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt
@@ -0,0 +1,33 @@
1FILE@[0; 30)
2 FUNCTION@[0; 11)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 11)
12 L_CURLY@[9; 10)
13 R_CURLY@[10; 11)
14 WHITESPACE@[11; 12)
15 FUNCTION@[12; 29)
16 FN_KW@[12; 14)
17 WHITESPACE@[14; 15)
18 NAME@[15; 18)
19 IDENT@[15; 18) "bar"
20 PARAM_LIST@[18; 20)
21 L_PAREN@[18; 19)
22 R_PAREN@[19; 20)
23 WHITESPACE@[20; 21)
24 THIN_ARROW@[21; 23)
25 WHITESPACE@[23; 24)
26 TUPLE_TYPE@[24; 26)
27 L_PAREN@[24; 25)
28 R_PAREN@[25; 26)
29 WHITESPACE@[26; 27)
30 BLOCK_EXPR@[27; 29)
31 L_CURLY@[27; 28)
32 R_CURLY@[28; 29)
33 WHITESPACE@[29; 30)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.rs
new file mode 100644
index 000000000..333ebabef
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 let _ = a;
3 let _ = a::b;
4 let _ = ::a::<b>;
5 let _ = format!();
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt
new file mode 100644
index 000000000..8b505774f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt
@@ -0,0 +1,94 @@
1FILE@[0; 91)
2 FUNCTION@[0; 90)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 90)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 25)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PLACEHOLDER_PAT@[19; 20)
18 UNDERSCORE@[19; 20)
19 WHITESPACE@[20; 21)
20 EQ@[21; 22)
21 WHITESPACE@[22; 23)
22 PATH_EXPR@[23; 24)
23 PATH@[23; 24)
24 PATH_SEGMENT@[23; 24)
25 NAME_REF@[23; 24)
26 IDENT@[23; 24) "a"
27 SEMI@[24; 25)
28 WHITESPACE@[25; 30)
29 LET_STMT@[30; 43)
30 LET_KW@[30; 33)
31 WHITESPACE@[33; 34)
32 PLACEHOLDER_PAT@[34; 35)
33 UNDERSCORE@[34; 35)
34 WHITESPACE@[35; 36)
35 EQ@[36; 37)
36 WHITESPACE@[37; 38)
37 PATH_EXPR@[38; 42)
38 PATH@[38; 42)
39 PATH@[38; 39)
40 PATH_SEGMENT@[38; 39)
41 NAME_REF@[38; 39)
42 IDENT@[38; 39) "a"
43 COLONCOLON@[39; 41)
44 PATH_SEGMENT@[41; 42)
45 NAME_REF@[41; 42)
46 IDENT@[41; 42) "b"
47 SEMI@[42; 43)
48 WHITESPACE@[43; 48)
49 LET_STMT@[48; 65)
50 LET_KW@[48; 51)
51 WHITESPACE@[51; 52)
52 PLACEHOLDER_PAT@[52; 53)
53 UNDERSCORE@[52; 53)
54 WHITESPACE@[53; 54)
55 EQ@[54; 55)
56 WHITESPACE@[55; 56)
57 PATH_EXPR@[56; 64)
58 PATH@[56; 64)
59 PATH_SEGMENT@[56; 64)
60 COLONCOLON@[56; 58)
61 NAME_REF@[58; 59)
62 IDENT@[58; 59) "a"
63 TYPE_ARG_LIST@[59; 64)
64 COLONCOLON@[59; 61)
65 L_ANGLE@[61; 62)
66 TYPE_ARG@[62; 63)
67 PATH_TYPE@[62; 63)
68 PATH@[62; 63)
69 PATH_SEGMENT@[62; 63)
70 NAME_REF@[62; 63)
71 IDENT@[62; 63) "b"
72 R_ANGLE@[63; 64)
73 SEMI@[64; 65)
74 WHITESPACE@[65; 70)
75 LET_STMT@[70; 88)
76 LET_KW@[70; 73)
77 WHITESPACE@[73; 74)
78 PLACEHOLDER_PAT@[74; 75)
79 UNDERSCORE@[74; 75)
80 WHITESPACE@[75; 76)
81 EQ@[76; 77)
82 WHITESPACE@[77; 78)
83 MACRO_CALL@[78; 87)
84 PATH@[78; 84)
85 PATH_SEGMENT@[78; 84)
86 NAME_REF@[78; 84)
87 IDENT@[78; 84) "format"
88 EXCL@[84; 85)
89 L_PAREN@[85; 86)
90 R_PAREN@[86; 87)
91 SEMI@[87; 88)
92 WHITESPACE@[88; 89)
93 R_CURLY@[89; 90)
94 WHITESPACE@[90; 91)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.rs b/crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.rs
new file mode 100644
index 000000000..2e11a5a6e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.rs
@@ -0,0 +1,12 @@
1fn foo() {
2 let _ = true;
3 let _ = false;
4 let _ = 1;
5 let _ = 2.0;
6 let _ = b'a';
7 let _ = 'b';
8 let _ = "c";
9 let _ = r"d";
10 let _ = b"e";
11 let _ = br"f";
12}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.txt b/crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.txt
new file mode 100644
index 000000000..192b62211
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0040_expr_literals.txt
@@ -0,0 +1,135 @@
1FILE@[0; 189)
2 FUNCTION@[0; 188)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 188)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 28)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PLACEHOLDER_PAT@[19; 20)
18 UNDERSCORE@[19; 20)
19 WHITESPACE@[20; 21)
20 EQ@[21; 22)
21 WHITESPACE@[22; 23)
22 LITERAL@[23; 27)
23 TRUE_KW@[23; 27)
24 SEMI@[27; 28)
25 WHITESPACE@[28; 33)
26 LET_STMT@[33; 47)
27 LET_KW@[33; 36)
28 WHITESPACE@[36; 37)
29 PLACEHOLDER_PAT@[37; 38)
30 UNDERSCORE@[37; 38)
31 WHITESPACE@[38; 39)
32 EQ@[39; 40)
33 WHITESPACE@[40; 41)
34 LITERAL@[41; 46)
35 FALSE_KW@[41; 46)
36 SEMI@[46; 47)
37 WHITESPACE@[47; 52)
38 LET_STMT@[52; 62)
39 LET_KW@[52; 55)
40 WHITESPACE@[55; 56)
41 PLACEHOLDER_PAT@[56; 57)
42 UNDERSCORE@[56; 57)
43 WHITESPACE@[57; 58)
44 EQ@[58; 59)
45 WHITESPACE@[59; 60)
46 LITERAL@[60; 61)
47 INT_NUMBER@[60; 61) "1"
48 SEMI@[61; 62)
49 WHITESPACE@[62; 67)
50 LET_STMT@[67; 79)
51 LET_KW@[67; 70)
52 WHITESPACE@[70; 71)
53 PLACEHOLDER_PAT@[71; 72)
54 UNDERSCORE@[71; 72)
55 WHITESPACE@[72; 73)
56 EQ@[73; 74)
57 WHITESPACE@[74; 75)
58 LITERAL@[75; 78)
59 FLOAT_NUMBER@[75; 78) "2.0"
60 SEMI@[78; 79)
61 WHITESPACE@[79; 84)
62 LET_STMT@[84; 97)
63 LET_KW@[84; 87)
64 WHITESPACE@[87; 88)
65 PLACEHOLDER_PAT@[88; 89)
66 UNDERSCORE@[88; 89)
67 WHITESPACE@[89; 90)
68 EQ@[90; 91)
69 WHITESPACE@[91; 92)
70 LITERAL@[92; 96)
71 BYTE@[92; 96)
72 SEMI@[96; 97)
73 WHITESPACE@[97; 102)
74 LET_STMT@[102; 114)
75 LET_KW@[102; 105)
76 WHITESPACE@[105; 106)
77 PLACEHOLDER_PAT@[106; 107)
78 UNDERSCORE@[106; 107)
79 WHITESPACE@[107; 108)
80 EQ@[108; 109)
81 WHITESPACE@[109; 110)
82 LITERAL@[110; 113)
83 CHAR@[110; 113)
84 SEMI@[113; 114)
85 WHITESPACE@[114; 119)
86 LET_STMT@[119; 131)
87 LET_KW@[119; 122)
88 WHITESPACE@[122; 123)
89 PLACEHOLDER_PAT@[123; 124)
90 UNDERSCORE@[123; 124)
91 WHITESPACE@[124; 125)
92 EQ@[125; 126)
93 WHITESPACE@[126; 127)
94 LITERAL@[127; 130)
95 STRING@[127; 130)
96 SEMI@[130; 131)
97 WHITESPACE@[131; 136)
98 LET_STMT@[136; 149)
99 LET_KW@[136; 139)
100 WHITESPACE@[139; 140)
101 PLACEHOLDER_PAT@[140; 141)
102 UNDERSCORE@[140; 141)
103 WHITESPACE@[141; 142)
104 EQ@[142; 143)
105 WHITESPACE@[143; 144)
106 LITERAL@[144; 148)
107 RAW_STRING@[144; 148)
108 SEMI@[148; 149)
109 WHITESPACE@[149; 154)
110 LET_STMT@[154; 167)
111 LET_KW@[154; 157)
112 WHITESPACE@[157; 158)
113 PLACEHOLDER_PAT@[158; 159)
114 UNDERSCORE@[158; 159)
115 WHITESPACE@[159; 160)
116 EQ@[160; 161)
117 WHITESPACE@[161; 162)
118 LITERAL@[162; 166)
119 BYTE_STRING@[162; 166)
120 SEMI@[166; 167)
121 WHITESPACE@[167; 172)
122 LET_STMT@[172; 186)
123 LET_KW@[172; 175)
124 WHITESPACE@[175; 176)
125 PLACEHOLDER_PAT@[176; 177)
126 UNDERSCORE@[176; 177)
127 WHITESPACE@[177; 178)
128 EQ@[178; 179)
129 WHITESPACE@[179; 180)
130 LITERAL@[180; 185)
131 RAW_BYTE_STRING@[180; 185)
132 SEMI@[185; 186)
133 WHITESPACE@[186; 187)
134 R_CURLY@[187; 188)
135 WHITESPACE@[188; 189)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.rs b/crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.rs
new file mode 100644
index 000000000..919bde0ee
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.rs
@@ -0,0 +1 @@
struct S<T: 'a + ?Sized + (Copy)>;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.txt b/crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.txt
new file mode 100644
index 000000000..4996d6ace
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0041_type_param_bounds.txt
@@ -0,0 +1,34 @@
1FILE@[0; 35)
2 STRUCT_ITEM@[0; 34)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 TYPE_PARAM_LIST@[8; 33)
8 L_ANGLE@[8; 9)
9 TYPE_PARAM@[9; 32)
10 NAME@[9; 10)
11 IDENT@[9; 10) "T"
12 COLON@[10; 11)
13 WHITESPACE@[11; 12)
14 LIFETIME@[12; 14) "'a"
15 WHITESPACE@[14; 15)
16 PLUS@[15; 16)
17 WHITESPACE@[16; 17)
18 QUESTION@[17; 18)
19 PATH@[18; 23)
20 PATH_SEGMENT@[18; 23)
21 NAME_REF@[18; 23)
22 IDENT@[18; 23) "Sized"
23 WHITESPACE@[23; 24)
24 PLUS@[24; 25)
25 WHITESPACE@[25; 26)
26 L_PAREN@[26; 27)
27 PATH@[27; 31)
28 PATH_SEGMENT@[27; 31)
29 NAME_REF@[27; 31)
30 IDENT@[27; 31) "Copy"
31 R_PAREN@[31; 32)
32 R_ANGLE@[32; 33)
33 SEMI@[33; 34)
34 WHITESPACE@[34; 35)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.rs b/crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.rs
new file mode 100644
index 000000000..540eacb02
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.rs
@@ -0,0 +1 @@
struct S<T = i32>;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.txt b/crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.txt
new file mode 100644
index 000000000..ec875e9a2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0042_type_param_default.txt
@@ -0,0 +1,22 @@
1FILE@[0; 19)
2 STRUCT_ITEM@[0; 18)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 TYPE_PARAM_LIST@[8; 17)
8 L_ANGLE@[8; 9)
9 TYPE_PARAM@[9; 16)
10 NAME@[9; 10)
11 IDENT@[9; 10) "T"
12 WHITESPACE@[10; 11)
13 EQ@[11; 12)
14 WHITESPACE@[12; 13)
15 PATH_TYPE@[13; 16)
16 PATH@[13; 16)
17 PATH_SEGMENT@[13; 16)
18 NAME_REF@[13; 16)
19 IDENT@[13; 16) "i32"
20 R_ANGLE@[16; 17)
21 SEMI@[17; 18)
22 WHITESPACE@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0043_call_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0043_call_expr.rs
new file mode 100644
index 000000000..0c9a20718
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0043_call_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 let _ = f();
3 let _ = f()(1)(1, 2,);
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0043_call_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0043_call_expr.txt
new file mode 100644
index 000000000..f4789d2d9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0043_call_expr.txt
@@ -0,0 +1,70 @@
1FILE@[0; 57)
2 FUNCTION@[0; 56)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 56)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 27)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PLACEHOLDER_PAT@[19; 20)
18 UNDERSCORE@[19; 20)
19 WHITESPACE@[20; 21)
20 EQ@[21; 22)
21 WHITESPACE@[22; 23)
22 CALL_EXPR@[23; 26)
23 PATH_EXPR@[23; 24)
24 PATH@[23; 24)
25 PATH_SEGMENT@[23; 24)
26 NAME_REF@[23; 24)
27 IDENT@[23; 24) "f"
28 ARG_LIST@[24; 26)
29 L_PAREN@[24; 25)
30 R_PAREN@[25; 26)
31 SEMI@[26; 27)
32 WHITESPACE@[27; 32)
33 LET_STMT@[32; 54)
34 LET_KW@[32; 35)
35 WHITESPACE@[35; 36)
36 PLACEHOLDER_PAT@[36; 37)
37 UNDERSCORE@[36; 37)
38 WHITESPACE@[37; 38)
39 EQ@[38; 39)
40 WHITESPACE@[39; 40)
41 CALL_EXPR@[40; 53)
42 CALL_EXPR@[40; 46)
43 CALL_EXPR@[40; 43)
44 PATH_EXPR@[40; 41)
45 PATH@[40; 41)
46 PATH_SEGMENT@[40; 41)
47 NAME_REF@[40; 41)
48 IDENT@[40; 41) "f"
49 ARG_LIST@[41; 43)
50 L_PAREN@[41; 42)
51 R_PAREN@[42; 43)
52 ARG_LIST@[43; 46)
53 L_PAREN@[43; 44)
54 LITERAL@[44; 45)
55 INT_NUMBER@[44; 45) "1"
56 R_PAREN@[45; 46)
57 ARG_LIST@[46; 53)
58 L_PAREN@[46; 47)
59 LITERAL@[47; 48)
60 INT_NUMBER@[47; 48) "1"
61 COMMA@[48; 49)
62 WHITESPACE@[49; 50)
63 LITERAL@[50; 51)
64 INT_NUMBER@[50; 51) "2"
65 COMMA@[51; 52)
66 R_PAREN@[52; 53)
67 SEMI@[53; 54)
68 WHITESPACE@[54; 55)
69 R_CURLY@[55; 56)
70 WHITESPACE@[56; 57)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.rs
new file mode 100644
index 000000000..2dac6be95
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 let _ = &1;
3 let _ = &mut &f();
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.txt
new file mode 100644
index 000000000..05f6c015a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0044_ref_expr.txt
@@ -0,0 +1,54 @@
1FILE@[0; 52)
2 FUNCTION@[0; 51)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 51)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 26)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PLACEHOLDER_PAT@[19; 20)
18 UNDERSCORE@[19; 20)
19 WHITESPACE@[20; 21)
20 EQ@[21; 22)
21 WHITESPACE@[22; 23)
22 REF_EXPR@[23; 25)
23 AMP@[23; 24)
24 LITERAL@[24; 25)
25 INT_NUMBER@[24; 25) "1"
26 SEMI@[25; 26)
27 WHITESPACE@[26; 31)
28 LET_STMT@[31; 49)
29 LET_KW@[31; 34)
30 WHITESPACE@[34; 35)
31 PLACEHOLDER_PAT@[35; 36)
32 UNDERSCORE@[35; 36)
33 WHITESPACE@[36; 37)
34 EQ@[37; 38)
35 WHITESPACE@[38; 39)
36 REF_EXPR@[39; 48)
37 AMP@[39; 40)
38 MUT_KW@[40; 43)
39 WHITESPACE@[43; 44)
40 REF_EXPR@[44; 48)
41 AMP@[44; 45)
42 CALL_EXPR@[45; 48)
43 PATH_EXPR@[45; 46)
44 PATH@[45; 46)
45 PATH_SEGMENT@[45; 46)
46 NAME_REF@[45; 46)
47 IDENT@[45; 46) "f"
48 ARG_LIST@[46; 48)
49 L_PAREN@[46; 47)
50 R_PAREN@[47; 48)
51 SEMI@[48; 49)
52 WHITESPACE@[49; 50)
53 R_CURLY@[50; 51)
54 WHITESPACE@[51; 52)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0045_block.rs b/crates/libsyntax2/tests/data/parser/inline/0045_block.rs
new file mode 100644
index 000000000..81f44c533
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0045_block.rs
@@ -0,0 +1,4 @@
1fn a() {}
2fn b() { let _ = 1; }
3fn c() { 1; 2; }
4fn d() { 1; 2 }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0045_block.txt b/crates/libsyntax2/tests/data/parser/inline/0045_block.txt
new file mode 100644
index 000000000..8519101c3
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0045_block.txt
@@ -0,0 +1,86 @@
1FILE@[0; 65)
2 FUNCTION@[0; 9)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 4)
6 IDENT@[3; 4) "a"
7 PARAM_LIST@[4; 6)
8 L_PAREN@[4; 5)
9 R_PAREN@[5; 6)
10 WHITESPACE@[6; 7)
11 BLOCK_EXPR@[7; 9)
12 L_CURLY@[7; 8)
13 R_CURLY@[8; 9)
14 WHITESPACE@[9; 10)
15 FUNCTION@[10; 31)
16 FN_KW@[10; 12)
17 WHITESPACE@[12; 13)
18 NAME@[13; 14)
19 IDENT@[13; 14) "b"
20 PARAM_LIST@[14; 16)
21 L_PAREN@[14; 15)
22 R_PAREN@[15; 16)
23 WHITESPACE@[16; 17)
24 BLOCK_EXPR@[17; 31)
25 L_CURLY@[17; 18)
26 WHITESPACE@[18; 19)
27 LET_STMT@[19; 29)
28 LET_KW@[19; 22)
29 WHITESPACE@[22; 23)
30 PLACEHOLDER_PAT@[23; 24)
31 UNDERSCORE@[23; 24)
32 WHITESPACE@[24; 25)
33 EQ@[25; 26)
34 WHITESPACE@[26; 27)
35 LITERAL@[27; 28)
36 INT_NUMBER@[27; 28) "1"
37 SEMI@[28; 29)
38 WHITESPACE@[29; 30)
39 R_CURLY@[30; 31)
40 WHITESPACE@[31; 32)
41 FUNCTION@[32; 48)
42 FN_KW@[32; 34)
43 WHITESPACE@[34; 35)
44 NAME@[35; 36)
45 IDENT@[35; 36) "c"
46 PARAM_LIST@[36; 38)
47 L_PAREN@[36; 37)
48 R_PAREN@[37; 38)
49 WHITESPACE@[38; 39)
50 BLOCK_EXPR@[39; 48)
51 L_CURLY@[39; 40)
52 WHITESPACE@[40; 41)
53 EXPR_STMT@[41; 43)
54 LITERAL@[41; 42)
55 INT_NUMBER@[41; 42) "1"
56 SEMI@[42; 43)
57 WHITESPACE@[43; 44)
58 EXPR_STMT@[44; 46)
59 LITERAL@[44; 45)
60 INT_NUMBER@[44; 45) "2"
61 SEMI@[45; 46)
62 WHITESPACE@[46; 47)
63 R_CURLY@[47; 48)
64 WHITESPACE@[48; 49)
65 FUNCTION@[49; 64)
66 FN_KW@[49; 51)
67 WHITESPACE@[51; 52)
68 NAME@[52; 53)
69 IDENT@[52; 53) "d"
70 PARAM_LIST@[53; 55)
71 L_PAREN@[53; 54)
72 R_PAREN@[54; 55)
73 WHITESPACE@[55; 56)
74 BLOCK_EXPR@[56; 64)
75 L_CURLY@[56; 57)
76 WHITESPACE@[57; 58)
77 EXPR_STMT@[58; 60)
78 LITERAL@[58; 59)
79 INT_NUMBER@[58; 59) "1"
80 SEMI@[59; 60)
81 WHITESPACE@[60; 61)
82 LITERAL@[61; 62)
83 INT_NUMBER@[61; 62) "2"
84 WHITESPACE@[62; 63)
85 R_CURLY@[63; 64)
86 WHITESPACE@[64; 65)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0046_default_impl.rs b/crates/libsyntax2/tests/data/parser/inline/0046_default_impl.rs
new file mode 100644
index 000000000..ef6aa84a2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0046_default_impl.rs
@@ -0,0 +1 @@
default impl Foo {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0046_default_impl.txt b/crates/libsyntax2/tests/data/parser/inline/0046_default_impl.txt
new file mode 100644
index 000000000..d5a27baf7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0046_default_impl.txt
@@ -0,0 +1,15 @@
1FILE@[0; 20)
2 IMPL_ITEM@[0; 19)
3 DEFAULT_KW@[0; 7)
4 WHITESPACE@[7; 8)
5 IMPL_KW@[8; 12)
6 WHITESPACE@[12; 13)
7 PATH_TYPE@[13; 16)
8 PATH@[13; 16)
9 PATH_SEGMENT@[13; 16)
10 NAME_REF@[13; 16)
11 IDENT@[13; 16) "Foo"
12 WHITESPACE@[16; 17)
13 L_CURLY@[17; 18)
14 R_CURLY@[18; 19)
15 WHITESPACE@[19; 20)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0047_impl_item.rs b/crates/libsyntax2/tests/data/parser/inline/0047_impl_item.rs
new file mode 100644
index 000000000..d6337f6b3
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0047_impl_item.rs
@@ -0,0 +1 @@
impl Foo {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0047_impl_item.txt b/crates/libsyntax2/tests/data/parser/inline/0047_impl_item.txt
new file mode 100644
index 000000000..76b29f95d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0047_impl_item.txt
@@ -0,0 +1,13 @@
1FILE@[0; 12)
2 IMPL_ITEM@[0; 11)
3 IMPL_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 PATH_TYPE@[5; 8)
6 PATH@[5; 8)
7 PATH_SEGMENT@[5; 8)
8 NAME_REF@[5; 8)
9 IDENT@[5; 8) "Foo"
10 WHITESPACE@[8; 9)
11 L_CURLY@[9; 10)
12 R_CURLY@[10; 11)
13 WHITESPACE@[11; 12)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.rs b/crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.rs
new file mode 100644
index 000000000..b7527c870
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.rs
@@ -0,0 +1 @@
impl !Send for X {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.txt b/crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.txt
new file mode 100644
index 000000000..2d01419c0
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0048_impl_item_neg.txt
@@ -0,0 +1,22 @@
1FILE@[0; 20)
2 IMPL_ITEM@[0; 19)
3 IMPL_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 EXCL@[5; 6)
6 PATH_TYPE@[6; 10)
7 PATH@[6; 10)
8 PATH_SEGMENT@[6; 10)
9 NAME_REF@[6; 10)
10 IDENT@[6; 10) "Send"
11 WHITESPACE@[10; 11)
12 FOR_KW@[11; 14)
13 WHITESPACE@[14; 15)
14 PATH_TYPE@[15; 16)
15 PATH@[15; 16)
16 PATH_SEGMENT@[15; 16)
17 NAME_REF@[15; 16)
18 IDENT@[15; 16) "X"
19 WHITESPACE@[16; 17)
20 L_CURLY@[17; 18)
21 R_CURLY@[18; 19)
22 WHITESPACE@[19; 20)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.rs b/crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.rs
new file mode 100644
index 000000000..0a9af907f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 let a;
3 let b: i32;
4 let c = 92;
5 let d: i32 = 92;
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.txt b/crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.txt
new file mode 100644
index 000000000..44e357092
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0050_let_stmt;.txt
@@ -0,0 +1,71 @@
1FILE@[0; 77)
2 FUNCTION@[0; 76)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 76)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 21)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 BIND_PAT@[19; 20)
18 NAME@[19; 20)
19 IDENT@[19; 20) "a"
20 SEMI@[20; 21)
21 WHITESPACE@[21; 26)
22 LET_STMT@[26; 37)
23 LET_KW@[26; 29)
24 WHITESPACE@[29; 30)
25 BIND_PAT@[30; 31)
26 NAME@[30; 31)
27 IDENT@[30; 31) "b"
28 COLON@[31; 32)
29 WHITESPACE@[32; 33)
30 PATH_TYPE@[33; 36)
31 PATH@[33; 36)
32 PATH_SEGMENT@[33; 36)
33 NAME_REF@[33; 36)
34 IDENT@[33; 36) "i32"
35 SEMI@[36; 37)
36 WHITESPACE@[37; 42)
37 LET_STMT@[42; 53)
38 LET_KW@[42; 45)
39 WHITESPACE@[45; 46)
40 BIND_PAT@[46; 47)
41 NAME@[46; 47)
42 IDENT@[46; 47) "c"
43 WHITESPACE@[47; 48)
44 EQ@[48; 49)
45 WHITESPACE@[49; 50)
46 LITERAL@[50; 52)
47 INT_NUMBER@[50; 52) "92"
48 SEMI@[52; 53)
49 WHITESPACE@[53; 58)
50 LET_STMT@[58; 74)
51 LET_KW@[58; 61)
52 WHITESPACE@[61; 62)
53 BIND_PAT@[62; 63)
54 NAME@[62; 63)
55 IDENT@[62; 63) "d"
56 COLON@[63; 64)
57 WHITESPACE@[64; 65)
58 PATH_TYPE@[65; 68)
59 PATH@[65; 68)
60 PATH_SEGMENT@[65; 68)
61 NAME_REF@[65; 68)
62 IDENT@[65; 68) "i32"
63 WHITESPACE@[68; 69)
64 EQ@[69; 70)
65 WHITESPACE@[70; 71)
66 LITERAL@[71; 73)
67 INT_NUMBER@[71; 73) "92"
68 SEMI@[73; 74)
69 WHITESPACE@[74; 75)
70 R_CURLY@[75; 76)
71 WHITESPACE@[76; 77)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.rs
new file mode 100644
index 000000000..1a3aa35ae
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 x.foo();
3 y.bar::<T>(1, 2,);
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.txt
new file mode 100644
index 000000000..aafb2d5f1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0051_method_call_expr.txt
@@ -0,0 +1,62 @@
1FILE@[0; 49)
2 FUNCTION@[0; 48)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 48)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 23)
15 METHOD_CALL_EXPR@[15; 22)
16 PATH_EXPR@[15; 16)
17 PATH@[15; 16)
18 PATH_SEGMENT@[15; 16)
19 NAME_REF@[15; 16)
20 IDENT@[15; 16) "x"
21 DOT@[16; 17)
22 NAME_REF@[17; 20)
23 IDENT@[17; 20) "foo"
24 ARG_LIST@[20; 22)
25 L_PAREN@[20; 21)
26 R_PAREN@[21; 22)
27 SEMI@[22; 23)
28 WHITESPACE@[23; 28)
29 EXPR_STMT@[28; 46)
30 METHOD_CALL_EXPR@[28; 45)
31 PATH_EXPR@[28; 29)
32 PATH@[28; 29)
33 PATH_SEGMENT@[28; 29)
34 NAME_REF@[28; 29)
35 IDENT@[28; 29) "y"
36 DOT@[29; 30)
37 NAME_REF@[30; 33)
38 IDENT@[30; 33) "bar"
39 TYPE_ARG_LIST@[33; 38)
40 COLONCOLON@[33; 35)
41 L_ANGLE@[35; 36)
42 TYPE_ARG@[36; 37)
43 PATH_TYPE@[36; 37)
44 PATH@[36; 37)
45 PATH_SEGMENT@[36; 37)
46 NAME_REF@[36; 37)
47 IDENT@[36; 37) "T"
48 R_ANGLE@[37; 38)
49 ARG_LIST@[38; 45)
50 L_PAREN@[38; 39)
51 LITERAL@[39; 40)
52 INT_NUMBER@[39; 40) "1"
53 COMMA@[40; 41)
54 WHITESPACE@[41; 42)
55 LITERAL@[42; 43)
56 INT_NUMBER@[42; 43) "2"
57 COMMA@[43; 44)
58 R_PAREN@[44; 45)
59 SEMI@[45; 46)
60 WHITESPACE@[46; 47)
61 R_CURLY@[47; 48)
62 WHITESPACE@[48; 49)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0052_field_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0052_field_expr.rs
new file mode 100644
index 000000000..3e69538e5
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0052_field_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 x.foo;
3 x.0.bar;
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0052_field_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0052_field_expr.txt
new file mode 100644
index 000000000..213884f90
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0052_field_expr.txt
@@ -0,0 +1,42 @@
1FILE@[0; 37)
2 FUNCTION@[0; 36)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 36)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 21)
15 FIELD_EXPR@[15; 20)
16 PATH_EXPR@[15; 16)
17 PATH@[15; 16)
18 PATH_SEGMENT@[15; 16)
19 NAME_REF@[15; 16)
20 IDENT@[15; 16) "x"
21 DOT@[16; 17)
22 NAME_REF@[17; 20)
23 IDENT@[17; 20) "foo"
24 SEMI@[20; 21)
25 WHITESPACE@[21; 26)
26 EXPR_STMT@[26; 34)
27 FIELD_EXPR@[26; 33)
28 FIELD_EXPR@[26; 29)
29 PATH_EXPR@[26; 27)
30 PATH@[26; 27)
31 PATH_SEGMENT@[26; 27)
32 NAME_REF@[26; 27)
33 IDENT@[26; 27) "x"
34 DOT@[27; 28)
35 INT_NUMBER@[28; 29) "0"
36 DOT@[29; 30)
37 NAME_REF@[30; 33)
38 IDENT@[30; 33) "bar"
39 SEMI@[33; 34)
40 WHITESPACE@[34; 35)
41 R_CURLY@[35; 36)
42 WHITESPACE@[36; 37)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0053_block_items.rs b/crates/libsyntax2/tests/data/parser/inline/0053_block_items.rs
new file mode 100644
index 000000000..d9868718c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0053_block_items.rs
@@ -0,0 +1 @@
fn a() { fn b() {} }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0053_block_items.txt b/crates/libsyntax2/tests/data/parser/inline/0053_block_items.txt
new file mode 100644
index 000000000..c5498532b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0053_block_items.txt
@@ -0,0 +1,28 @@
1FILE@[0; 21)
2 FUNCTION@[0; 20)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 4)
6 IDENT@[3; 4) "a"
7 PARAM_LIST@[4; 6)
8 L_PAREN@[4; 5)
9 R_PAREN@[5; 6)
10 WHITESPACE@[6; 7)
11 BLOCK_EXPR@[7; 20)
12 L_CURLY@[7; 8)
13 WHITESPACE@[8; 9)
14 FUNCTION@[9; 18)
15 FN_KW@[9; 11)
16 WHITESPACE@[11; 12)
17 NAME@[12; 13)
18 IDENT@[12; 13) "b"
19 PARAM_LIST@[13; 15)
20 L_PAREN@[13; 14)
21 R_PAREN@[14; 15)
22 WHITESPACE@[15; 16)
23 BLOCK_EXPR@[16; 18)
24 L_CURLY@[16; 17)
25 R_CURLY@[17; 18)
26 WHITESPACE@[18; 19)
27 R_CURLY@[19; 20)
28 WHITESPACE@[20; 21)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.rs b/crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.rs
new file mode 100644
index 000000000..f10851487
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.rs
@@ -0,0 +1,6 @@
1impl F {
2 type A = i32;
3 const B: i32 = 92;
4 fn foo() {}
5 fn bar(&self) {}
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.txt b/crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.txt
new file mode 100644
index 000000000..739ecbbcd
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0054_impl_item_items.txt
@@ -0,0 +1,77 @@
1FILE@[0; 89)
2 IMPL_ITEM@[0; 88)
3 IMPL_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 PATH_TYPE@[5; 6)
6 PATH@[5; 6)
7 PATH_SEGMENT@[5; 6)
8 NAME_REF@[5; 6)
9 IDENT@[5; 6) "F"
10 WHITESPACE@[6; 7)
11 L_CURLY@[7; 8)
12 WHITESPACE@[8; 13)
13 TYPE_ITEM@[13; 26)
14 TYPE_KW@[13; 17)
15 WHITESPACE@[17; 18)
16 NAME@[18; 19)
17 IDENT@[18; 19) "A"
18 WHITESPACE@[19; 20)
19 EQ@[20; 21)
20 WHITESPACE@[21; 22)
21 PATH_TYPE@[22; 25)
22 PATH@[22; 25)
23 PATH_SEGMENT@[22; 25)
24 NAME_REF@[22; 25)
25 IDENT@[22; 25) "i32"
26 SEMI@[25; 26)
27 WHITESPACE@[26; 31)
28 CONST_ITEM@[31; 49)
29 CONST_KW@[31; 36)
30 WHITESPACE@[36; 37)
31 NAME@[37; 38)
32 IDENT@[37; 38) "B"
33 COLON@[38; 39)
34 WHITESPACE@[39; 40)
35 PATH_TYPE@[40; 43)
36 PATH@[40; 43)
37 PATH_SEGMENT@[40; 43)
38 NAME_REF@[40; 43)
39 IDENT@[40; 43) "i32"
40 WHITESPACE@[43; 44)
41 EQ@[44; 45)
42 WHITESPACE@[45; 46)
43 LITERAL@[46; 48)
44 INT_NUMBER@[46; 48) "92"
45 SEMI@[48; 49)
46 WHITESPACE@[49; 54)
47 FUNCTION@[54; 65)
48 FN_KW@[54; 56)
49 WHITESPACE@[56; 57)
50 NAME@[57; 60)
51 IDENT@[57; 60) "foo"
52 PARAM_LIST@[60; 62)
53 L_PAREN@[60; 61)
54 R_PAREN@[61; 62)
55 WHITESPACE@[62; 63)
56 BLOCK_EXPR@[63; 65)
57 L_CURLY@[63; 64)
58 R_CURLY@[64; 65)
59 WHITESPACE@[65; 70)
60 FUNCTION@[70; 86)
61 FN_KW@[70; 72)
62 WHITESPACE@[72; 73)
63 NAME@[73; 76)
64 IDENT@[73; 76) "bar"
65 PARAM_LIST@[76; 83)
66 L_PAREN@[76; 77)
67 SELF_PARAM@[77; 82)
68 AMP@[77; 78)
69 SELF_KW@[78; 82)
70 R_PAREN@[82; 83)
71 WHITESPACE@[83; 84)
72 BLOCK_EXPR@[84; 86)
73 L_CURLY@[84; 85)
74 R_CURLY@[85; 86)
75 WHITESPACE@[86; 87)
76 R_CURLY@[87; 88)
77 WHITESPACE@[88; 89)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0055_self_param.rs b/crates/libsyntax2/tests/data/parser/inline/0055_self_param.rs
new file mode 100644
index 000000000..7bb1ca50c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0055_self_param.rs
@@ -0,0 +1,6 @@
1impl S {
2 fn a(self) {}
3 fn b(&self,) {}
4 fn c(&'a self,) {}
5 fn d(&'a mut self, x: i32) {}
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0055_self_param.txt b/crates/libsyntax2/tests/data/parser/inline/0055_self_param.txt
new file mode 100644
index 000000000..1275fb8b1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0055_self_param.txt
@@ -0,0 +1,98 @@
1FILE@[0; 106)
2 IMPL_ITEM@[0; 105)
3 IMPL_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 PATH_TYPE@[5; 6)
6 PATH@[5; 6)
7 PATH_SEGMENT@[5; 6)
8 NAME_REF@[5; 6)
9 IDENT@[5; 6) "S"
10 WHITESPACE@[6; 7)
11 L_CURLY@[7; 8)
12 WHITESPACE@[8; 13)
13 FUNCTION@[13; 26)
14 FN_KW@[13; 15)
15 WHITESPACE@[15; 16)
16 NAME@[16; 17)
17 IDENT@[16; 17) "a"
18 PARAM_LIST@[17; 23)
19 L_PAREN@[17; 18)
20 SELF_PARAM@[18; 22)
21 SELF_KW@[18; 22)
22 R_PAREN@[22; 23)
23 WHITESPACE@[23; 24)
24 BLOCK_EXPR@[24; 26)
25 L_CURLY@[24; 25)
26 R_CURLY@[25; 26)
27 WHITESPACE@[26; 31)
28 FUNCTION@[31; 46)
29 FN_KW@[31; 33)
30 WHITESPACE@[33; 34)
31 NAME@[34; 35)
32 IDENT@[34; 35) "b"
33 PARAM_LIST@[35; 43)
34 L_PAREN@[35; 36)
35 SELF_PARAM@[36; 41)
36 AMP@[36; 37)
37 SELF_KW@[37; 41)
38 COMMA@[41; 42)
39 R_PAREN@[42; 43)
40 WHITESPACE@[43; 44)
41 BLOCK_EXPR@[44; 46)
42 L_CURLY@[44; 45)
43 R_CURLY@[45; 46)
44 WHITESPACE@[46; 51)
45 FUNCTION@[51; 69)
46 FN_KW@[51; 53)
47 WHITESPACE@[53; 54)
48 NAME@[54; 55)
49 IDENT@[54; 55) "c"
50 PARAM_LIST@[55; 66)
51 L_PAREN@[55; 56)
52 SELF_PARAM@[56; 64)
53 AMP@[56; 57)
54 LIFETIME@[57; 59) "'a"
55 WHITESPACE@[59; 60)
56 SELF_KW@[60; 64)
57 COMMA@[64; 65)
58 R_PAREN@[65; 66)
59 WHITESPACE@[66; 67)
60 BLOCK_EXPR@[67; 69)
61 L_CURLY@[67; 68)
62 R_CURLY@[68; 69)
63 WHITESPACE@[69; 74)
64 FUNCTION@[74; 103)
65 FN_KW@[74; 76)
66 WHITESPACE@[76; 77)
67 NAME@[77; 78)
68 IDENT@[77; 78) "d"
69 PARAM_LIST@[78; 100)
70 L_PAREN@[78; 79)
71 SELF_PARAM@[79; 91)
72 AMP@[79; 80)
73 LIFETIME@[80; 82) "'a"
74 WHITESPACE@[82; 83)
75 MUT_KW@[83; 86)
76 WHITESPACE@[86; 87)
77 SELF_KW@[87; 91)
78 COMMA@[91; 92)
79 WHITESPACE@[92; 93)
80 PARAM@[93; 99)
81 BIND_PAT@[93; 94)
82 NAME@[93; 94)
83 IDENT@[93; 94) "x"
84 COLON@[94; 95)
85 WHITESPACE@[95; 96)
86 PATH_TYPE@[96; 99)
87 PATH@[96; 99)
88 PATH_SEGMENT@[96; 99)
89 NAME_REF@[96; 99)
90 IDENT@[96; 99) "i32"
91 R_PAREN@[99; 100)
92 WHITESPACE@[100; 101)
93 BLOCK_EXPR@[101; 103)
94 L_CURLY@[101; 102)
95 R_CURLY@[102; 103)
96 WHITESPACE@[103; 104)
97 R_CURLY@[104; 105)
98 WHITESPACE@[105; 106)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0056_trait_item.rs b/crates/libsyntax2/tests/data/parser/inline/0056_trait_item.rs
new file mode 100644
index 000000000..4385afca9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0056_trait_item.rs
@@ -0,0 +1 @@
trait T<U>: Hash + Clone where U: Copy {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0056_trait_item.txt b/crates/libsyntax2/tests/data/parser/inline/0056_trait_item.txt
new file mode 100644
index 000000000..ba4e0ebc8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0056_trait_item.txt
@@ -0,0 +1,45 @@
1FILE@[0; 42)
2 TRAIT_ITEM@[0; 41)
3 TRAIT_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 NAME@[6; 7)
6 IDENT@[6; 7) "T"
7 TYPE_PARAM_LIST@[7; 10)
8 L_ANGLE@[7; 8)
9 TYPE_PARAM@[8; 9)
10 NAME@[8; 9)
11 IDENT@[8; 9) "U"
12 R_ANGLE@[9; 10)
13 COLON@[10; 11)
14 WHITESPACE@[11; 12)
15 PATH@[12; 16)
16 PATH_SEGMENT@[12; 16)
17 NAME_REF@[12; 16)
18 IDENT@[12; 16) "Hash"
19 WHITESPACE@[16; 17)
20 PLUS@[17; 18)
21 WHITESPACE@[18; 19)
22 PATH@[19; 24)
23 PATH_SEGMENT@[19; 24)
24 NAME_REF@[19; 24)
25 IDENT@[19; 24) "Clone"
26 WHITESPACE@[24; 25)
27 WHERE_CLAUSE@[25; 38)
28 WHERE_KW@[25; 30)
29 WHITESPACE@[30; 31)
30 WHERE_PRED@[31; 38)
31 PATH_TYPE@[31; 32)
32 PATH@[31; 32)
33 PATH_SEGMENT@[31; 32)
34 NAME_REF@[31; 32)
35 IDENT@[31; 32) "U"
36 COLON@[32; 33)
37 WHITESPACE@[33; 34)
38 PATH@[34; 38)
39 PATH_SEGMENT@[34; 38)
40 NAME_REF@[34; 38)
41 IDENT@[34; 38) "Copy"
42 WHITESPACE@[38; 39)
43 L_CURLY@[39; 40)
44 R_CURLY@[40; 41)
45 WHITESPACE@[41; 42)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.rs b/crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.rs
new file mode 100644
index 000000000..72adf6035
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.rs
@@ -0,0 +1 @@
auto trait T {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.txt b/crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.txt
new file mode 100644
index 000000000..6bb4ffdba
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0057_auto_trait.txt
@@ -0,0 +1,12 @@
1FILE@[0; 16)
2 TRAIT_ITEM@[0; 15)
3 AUTO_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 TRAIT_KW@[5; 10)
6 WHITESPACE@[10; 11)
7 NAME@[11; 12)
8 IDENT@[11; 12) "T"
9 WHITESPACE@[12; 13)
10 L_CURLY@[13; 14)
11 R_CURLY@[14; 15)
12 WHITESPACE@[15; 16)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0058_type_arg.rs b/crates/libsyntax2/tests/data/parser/inline/0058_type_arg.rs
new file mode 100644
index 000000000..f0c8cc3a8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0058_type_arg.rs
@@ -0,0 +1 @@
type A = B<'static, i32, Item=u64>
diff --git a/crates/libsyntax2/tests/data/parser/inline/0058_type_arg.txt b/crates/libsyntax2/tests/data/parser/inline/0058_type_arg.txt
new file mode 100644
index 000000000..f69ce4738
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0058_type_arg.txt
@@ -0,0 +1,40 @@
1FILE@[0; 35)
2 TYPE_ITEM@[0; 34)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 PATH_TYPE@[9; 34)
11 PATH@[9; 34)
12 PATH_SEGMENT@[9; 34)
13 NAME_REF@[9; 10)
14 IDENT@[9; 10) "B"
15 TYPE_ARG_LIST@[10; 34)
16 L_ANGLE@[10; 11)
17 LIFETIME_ARG@[11; 18)
18 LIFETIME@[11; 18) "'static"
19 COMMA@[18; 19)
20 WHITESPACE@[19; 20)
21 TYPE_ARG@[20; 23)
22 PATH_TYPE@[20; 23)
23 PATH@[20; 23)
24 PATH_SEGMENT@[20; 23)
25 NAME_REF@[20; 23)
26 IDENT@[20; 23) "i32"
27 COMMA@[23; 24)
28 WHITESPACE@[24; 25)
29 ASSOC_TYPE_ARG@[25; 33)
30 NAME_REF@[25; 29)
31 IDENT@[25; 29) "Item"
32 EQ@[29; 30)
33 PATH_TYPE@[30; 33)
34 PATH@[30; 33)
35 PATH_SEGMENT@[30; 33)
36 NAME_REF@[30; 33)
37 IDENT@[30; 33) "u64"
38 R_ANGLE@[33; 34)
39 err: `expected SEMI`
40 WHITESPACE@[34; 35)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.rs b/crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.rs
new file mode 100644
index 000000000..f0920b2a8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.rs
@@ -0,0 +1 @@
fn foo<T>() where T: Copy {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.txt b/crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.txt
new file mode 100644
index 000000000..065b0fd21
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0059_function_where_clause.txt
@@ -0,0 +1,36 @@
1FILE@[0; 29)
2 FUNCTION@[0; 28)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 TYPE_PARAM_LIST@[6; 9)
8 L_ANGLE@[6; 7)
9 TYPE_PARAM@[7; 8)
10 NAME@[7; 8)
11 IDENT@[7; 8) "T"
12 R_ANGLE@[8; 9)
13 PARAM_LIST@[9; 11)
14 L_PAREN@[9; 10)
15 R_PAREN@[10; 11)
16 WHITESPACE@[11; 12)
17 WHERE_CLAUSE@[12; 25)
18 WHERE_KW@[12; 17)
19 WHITESPACE@[17; 18)
20 WHERE_PRED@[18; 25)
21 PATH_TYPE@[18; 19)
22 PATH@[18; 19)
23 PATH_SEGMENT@[18; 19)
24 NAME_REF@[18; 19)
25 IDENT@[18; 19) "T"
26 COLON@[19; 20)
27 WHITESPACE@[20; 21)
28 PATH@[21; 25)
29 PATH_SEGMENT@[21; 25)
30 NAME_REF@[21; 25)
31 IDENT@[21; 25) "Copy"
32 WHITESPACE@[25; 26)
33 BLOCK_EXPR@[26; 28)
34 L_CURLY@[26; 27)
35 R_CURLY@[27; 28)
36 WHITESPACE@[28; 29)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.rs b/crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.rs
new file mode 100644
index 000000000..9df40ed39
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.rs
@@ -0,0 +1 @@
fn foo<T: Clone + Copy>(){}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.txt b/crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.txt
new file mode 100644
index 000000000..8809ebc04
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0060_function_type_params.txt
@@ -0,0 +1,32 @@
1FILE@[0; 28)
2 FUNCTION@[0; 27)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 TYPE_PARAM_LIST@[6; 23)
8 L_ANGLE@[6; 7)
9 TYPE_PARAM@[7; 22)
10 NAME@[7; 8)
11 IDENT@[7; 8) "T"
12 COLON@[8; 9)
13 WHITESPACE@[9; 10)
14 PATH@[10; 15)
15 PATH_SEGMENT@[10; 15)
16 NAME_REF@[10; 15)
17 IDENT@[10; 15) "Clone"
18 WHITESPACE@[15; 16)
19 PLUS@[16; 17)
20 WHITESPACE@[17; 18)
21 PATH@[18; 22)
22 PATH_SEGMENT@[18; 22)
23 NAME_REF@[18; 22)
24 IDENT@[18; 22) "Copy"
25 R_ANGLE@[22; 23)
26 PARAM_LIST@[23; 25)
27 L_PAREN@[23; 24)
28 R_PAREN@[24; 25)
29 BLOCK_EXPR@[25; 27)
30 L_CURLY@[25; 26)
31 R_CURLY@[26; 27)
32 WHITESPACE@[27; 28)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.rs b/crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.rs
new file mode 100644
index 000000000..eb711f68a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.rs
@@ -0,0 +1,5 @@
1fn foo() {
2 S {};
3 S { x, y: 32, };
4 S { x, y: 32, ..Default::default() };
5}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.txt b/crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.txt
new file mode 100644
index 000000000..1d048c5ba
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0061_struct_lit.txt
@@ -0,0 +1,94 @@
1FILE@[0; 86)
2 FUNCTION@[0; 85)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 85)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 20)
15 STRUCT_LIT@[15; 19)
16 PATH@[15; 16)
17 PATH_SEGMENT@[15; 16)
18 NAME_REF@[15; 16)
19 IDENT@[15; 16) "S"
20 WHITESPACE@[16; 17)
21 L_CURLY@[17; 18)
22 R_CURLY@[18; 19)
23 SEMI@[19; 20)
24 WHITESPACE@[20; 25)
25 EXPR_STMT@[25; 41)
26 STRUCT_LIT@[25; 40)
27 PATH@[25; 26)
28 PATH_SEGMENT@[25; 26)
29 NAME_REF@[25; 26)
30 IDENT@[25; 26) "S"
31 WHITESPACE@[26; 27)
32 L_CURLY@[27; 28)
33 WHITESPACE@[28; 29)
34 STRUCT_LIT_FIELD@[29; 30)
35 NAME_REF@[29; 30)
36 IDENT@[29; 30) "x"
37 COMMA@[30; 31)
38 WHITESPACE@[31; 32)
39 STRUCT_LIT_FIELD@[32; 37)
40 NAME_REF@[32; 33)
41 IDENT@[32; 33) "y"
42 COLON@[33; 34)
43 WHITESPACE@[34; 35)
44 LITERAL@[35; 37)
45 INT_NUMBER@[35; 37) "32"
46 COMMA@[37; 38)
47 WHITESPACE@[38; 39)
48 R_CURLY@[39; 40)
49 SEMI@[40; 41)
50 WHITESPACE@[41; 46)
51 EXPR_STMT@[46; 83)
52 STRUCT_LIT@[46; 82)
53 PATH@[46; 47)
54 PATH_SEGMENT@[46; 47)
55 NAME_REF@[46; 47)
56 IDENT@[46; 47) "S"
57 WHITESPACE@[47; 48)
58 L_CURLY@[48; 49)
59 WHITESPACE@[49; 50)
60 STRUCT_LIT_FIELD@[50; 51)
61 NAME_REF@[50; 51)
62 IDENT@[50; 51) "x"
63 COMMA@[51; 52)
64 WHITESPACE@[52; 53)
65 STRUCT_LIT_FIELD@[53; 58)
66 NAME_REF@[53; 54)
67 IDENT@[53; 54) "y"
68 COLON@[54; 55)
69 WHITESPACE@[55; 56)
70 LITERAL@[56; 58)
71 INT_NUMBER@[56; 58) "32"
72 COMMA@[58; 59)
73 WHITESPACE@[59; 60)
74 DOTDOT@[60; 62)
75 CALL_EXPR@[62; 80)
76 PATH_EXPR@[62; 78)
77 PATH@[62; 78)
78 PATH@[62; 69)
79 PATH_SEGMENT@[62; 69)
80 NAME_REF@[62; 69)
81 IDENT@[62; 69) "Default"
82 COLONCOLON@[69; 71)
83 PATH_SEGMENT@[71; 78)
84 NAME_REF@[71; 78)
85 IDENT@[71; 78) "default"
86 ARG_LIST@[78; 80)
87 L_PAREN@[78; 79)
88 R_PAREN@[79; 80)
89 WHITESPACE@[80; 81)
90 R_CURLY@[81; 82)
91 SEMI@[82; 83)
92 WHITESPACE@[83; 84)
93 R_CURLY@[84; 85)
94 WHITESPACE@[85; 86)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.rs b/crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.rs
new file mode 100644
index 000000000..54c5a7c46
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.rs
@@ -0,0 +1 @@
type A = impl Iterator<Item=Foo<'a>> + 'a;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.txt b/crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.txt
new file mode 100644
index 000000000..bbebf1086
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0063_impl_trait_type.txt
@@ -0,0 +1,39 @@
1FILE@[0; 43)
2 TYPE_ITEM@[0; 42)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "A"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 IMPL_TRAIT_TYPE@[9; 41)
11 IMPL_KW@[9; 13)
12 WHITESPACE@[13; 14)
13 PATH@[14; 36)
14 PATH_SEGMENT@[14; 36)
15 NAME_REF@[14; 22)
16 IDENT@[14; 22) "Iterator"
17 TYPE_ARG_LIST@[22; 36)
18 L_ANGLE@[22; 23)
19 ASSOC_TYPE_ARG@[23; 35)
20 NAME_REF@[23; 27)
21 IDENT@[23; 27) "Item"
22 EQ@[27; 28)
23 PATH_TYPE@[28; 35)
24 PATH@[28; 35)
25 PATH_SEGMENT@[28; 35)
26 NAME_REF@[28; 31)
27 IDENT@[28; 31) "Foo"
28 TYPE_ARG_LIST@[31; 35)
29 L_ANGLE@[31; 32)
30 LIFETIME_ARG@[32; 34)
31 LIFETIME@[32; 34) "'a"
32 R_ANGLE@[34; 35)
33 R_ANGLE@[35; 36)
34 WHITESPACE@[36; 37)
35 PLUS@[37; 38)
36 WHITESPACE@[38; 39)
37 LIFETIME@[39; 41) "'a"
38 SEMI@[41; 42)
39 WHITESPACE@[42; 43)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0063_lambda_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0063_lambda_expr.txt
new file mode 100644
index 000000000..122a99e52
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0063_lambda_expr.txt
@@ -0,0 +1,91 @@
1FILE@[0; 74)
2 FUNCTION@[0; 74)
3 FN_KW@[0; 2)
4 NAME@[2; 6)
5 WHITESPACE@[2; 3)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 9)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 74)
12 L_CURLY@[9; 10)
13 EXPR_STMT@[10; 26)
14 LAMBDA_EXPR@[10; 20)
15 PARAM_LIST@[10; 18)
16 WHITESPACE@[10; 15)
17 PIPE@[15; 16)
18 PIPE@[16; 17)
19 WHITESPACE@[17; 18)
20 TUPLE_EXPR@[18; 20)
21 L_PAREN@[18; 19)
22 R_PAREN@[19; 20)
23 SEMI@[20; 21)
24 WHITESPACE@[21; 26)
25 EXPR_STMT@[26; 48)
26 LAMBDA_EXPR@[26; 42)
27 PARAM_LIST@[26; 29)
28 PIPE@[26; 27)
29 PIPE@[27; 28)
30 WHITESPACE@[28; 29)
31 THIN_ARROW@[29; 31)
32 PATH_TYPE@[31; 36)
33 PATH@[31; 36)
34 PATH_SEGMENT@[31; 36)
35 NAME_REF@[31; 36)
36 WHITESPACE@[31; 32)
37 IDENT@[32; 35) "i32"
38 WHITESPACE@[35; 36)
39 BLOCK_EXPR@[36; 42)
40 L_CURLY@[36; 37)
41 LITERAL@[37; 41)
42 WHITESPACE@[37; 38)
43 INT_NUMBER@[38; 40) "92"
44 WHITESPACE@[40; 41)
45 R_CURLY@[41; 42)
46 SEMI@[42; 43)
47 WHITESPACE@[43; 48)
48 EXPR_STMT@[48; 59)
49 LAMBDA_EXPR@[48; 53)
50 PARAM_LIST@[48; 52)
51 PIPE@[48; 49)
52 PARAM@[49; 50)
53 BIND_PAT@[49; 50)
54 NAME@[49; 50)
55 IDENT@[49; 50) "x"
56 PIPE@[50; 51)
57 WHITESPACE@[51; 52)
58 PATH_EXPR@[52; 53)
59 PATH@[52; 53)
60 PATH_SEGMENT@[52; 53)
61 NAME_REF@[52; 53)
62 IDENT@[52; 53) "x"
63 SEMI@[53; 54)
64 WHITESPACE@[54; 59)
65 EXPR_STMT@[59; 72)
66 LAMBDA_EXPR@[59; 70)
67 PARAM_LIST@[59; 69)
68 PIPE@[59; 60)
69 PARAM@[60; 66)
70 BIND_PAT@[60; 61)
71 NAME@[60; 61)
72 IDENT@[60; 61) "x"
73 COLON@[61; 62)
74 PATH_TYPE@[62; 66)
75 PATH@[62; 66)
76 PATH_SEGMENT@[62; 66)
77 NAME_REF@[62; 66)
78 WHITESPACE@[62; 63)
79 IDENT@[63; 66) "i32"
80 COMMA@[66; 67)
81 PIPE@[67; 68)
82 WHITESPACE@[68; 69)
83 PATH_EXPR@[69; 70)
84 PATH@[69; 70)
85 PATH_SEGMENT@[69; 70)
86 NAME_REF@[69; 70)
87 IDENT@[69; 70) "x"
88 SEMI@[70; 71)
89 WHITESPACE@[71; 72)
90 R_CURLY@[72; 73)
91 WHITESPACE@[73; 74)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0064_param_list.rs b/crates/libsyntax2/tests/data/parser/inline/0064_param_list.rs
new file mode 100644
index 000000000..9d55bedbb
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0064_param_list.rs
@@ -0,0 +1,4 @@
1fn a() {}
2fn b(x: i32) {}
3fn c(x: i32, ) {}
4fn d(x: i32, y: ()) {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0064_param_list.txt b/crates/libsyntax2/tests/data/parser/inline/0064_param_list.txt
new file mode 100644
index 000000000..14db495b9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0064_param_list.txt
@@ -0,0 +1,99 @@
1FILE@[0; 67)
2 FUNCTION@[0; 9)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 4)
6 IDENT@[3; 4) "a"
7 PARAM_LIST@[4; 6)
8 L_PAREN@[4; 5)
9 R_PAREN@[5; 6)
10 WHITESPACE@[6; 7)
11 BLOCK_EXPR@[7; 9)
12 L_CURLY@[7; 8)
13 R_CURLY@[8; 9)
14 WHITESPACE@[9; 10)
15 FUNCTION@[10; 25)
16 FN_KW@[10; 12)
17 WHITESPACE@[12; 13)
18 NAME@[13; 14)
19 IDENT@[13; 14) "b"
20 PARAM_LIST@[14; 22)
21 L_PAREN@[14; 15)
22 PARAM@[15; 21)
23 BIND_PAT@[15; 16)
24 NAME@[15; 16)
25 IDENT@[15; 16) "x"
26 COLON@[16; 17)
27 WHITESPACE@[17; 18)
28 PATH_TYPE@[18; 21)
29 PATH@[18; 21)
30 PATH_SEGMENT@[18; 21)
31 NAME_REF@[18; 21)
32 IDENT@[18; 21) "i32"
33 R_PAREN@[21; 22)
34 WHITESPACE@[22; 23)
35 BLOCK_EXPR@[23; 25)
36 L_CURLY@[23; 24)
37 R_CURLY@[24; 25)
38 WHITESPACE@[25; 26)
39 FUNCTION@[26; 43)
40 FN_KW@[26; 28)
41 WHITESPACE@[28; 29)
42 NAME@[29; 30)
43 IDENT@[29; 30) "c"
44 PARAM_LIST@[30; 40)
45 L_PAREN@[30; 31)
46 PARAM@[31; 37)
47 BIND_PAT@[31; 32)
48 NAME@[31; 32)
49 IDENT@[31; 32) "x"
50 COLON@[32; 33)
51 WHITESPACE@[33; 34)
52 PATH_TYPE@[34; 37)
53 PATH@[34; 37)
54 PATH_SEGMENT@[34; 37)
55 NAME_REF@[34; 37)
56 IDENT@[34; 37) "i32"
57 COMMA@[37; 38)
58 WHITESPACE@[38; 39)
59 R_PAREN@[39; 40)
60 WHITESPACE@[40; 41)
61 BLOCK_EXPR@[41; 43)
62 L_CURLY@[41; 42)
63 R_CURLY@[42; 43)
64 WHITESPACE@[43; 44)
65 FUNCTION@[44; 66)
66 FN_KW@[44; 46)
67 WHITESPACE@[46; 47)
68 NAME@[47; 48)
69 IDENT@[47; 48) "d"
70 PARAM_LIST@[48; 63)
71 L_PAREN@[48; 49)
72 PARAM@[49; 55)
73 BIND_PAT@[49; 50)
74 NAME@[49; 50)
75 IDENT@[49; 50) "x"
76 COLON@[50; 51)
77 WHITESPACE@[51; 52)
78 PATH_TYPE@[52; 55)
79 PATH@[52; 55)
80 PATH_SEGMENT@[52; 55)
81 NAME_REF@[52; 55)
82 IDENT@[52; 55) "i32"
83 COMMA@[55; 56)
84 WHITESPACE@[56; 57)
85 PARAM@[57; 62)
86 BIND_PAT@[57; 58)
87 NAME@[57; 58)
88 IDENT@[57; 58) "y"
89 COLON@[58; 59)
90 WHITESPACE@[59; 60)
91 TUPLE_TYPE@[60; 62)
92 L_PAREN@[60; 61)
93 R_PAREN@[61; 62)
94 R_PAREN@[62; 63)
95 WHITESPACE@[63; 64)
96 BLOCK_EXPR@[64; 66)
97 L_CURLY@[64; 65)
98 R_CURLY@[65; 66)
99 WHITESPACE@[66; 67)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.rs
new file mode 100644
index 000000000..4b0d9af89
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 if true {};
3 if true {} else {};
4 if true {} else if false {} else {};
5 if S {};
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt
new file mode 100644
index 000000000..6ed53264a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0065_if_expr.txt
@@ -0,0 +1,90 @@
1FILE@[0; 107)
2 FUNCTION@[0; 106)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 106)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 26)
15 IF_EXPR@[15; 25)
16 IF_KW@[15; 17)
17 WHITESPACE@[17; 18)
18 LITERAL@[18; 22)
19 TRUE_KW@[18; 22)
20 WHITESPACE@[22; 23)
21 BLOCK_EXPR@[23; 25)
22 L_CURLY@[23; 24)
23 R_CURLY@[24; 25)
24 SEMI@[25; 26)
25 WHITESPACE@[26; 31)
26 EXPR_STMT@[31; 50)
27 IF_EXPR@[31; 49)
28 IF_KW@[31; 33)
29 WHITESPACE@[33; 34)
30 LITERAL@[34; 38)
31 TRUE_KW@[34; 38)
32 WHITESPACE@[38; 39)
33 BLOCK_EXPR@[39; 41)
34 L_CURLY@[39; 40)
35 R_CURLY@[40; 41)
36 WHITESPACE@[41; 42)
37 ELSE_KW@[42; 46)
38 WHITESPACE@[46; 47)
39 BLOCK_EXPR@[47; 49)
40 L_CURLY@[47; 48)
41 R_CURLY@[48; 49)
42 SEMI@[49; 50)
43 WHITESPACE@[50; 55)
44 EXPR_STMT@[55; 91)
45 IF_EXPR@[55; 90)
46 IF_KW@[55; 57)
47 WHITESPACE@[57; 58)
48 LITERAL@[58; 62)
49 TRUE_KW@[58; 62)
50 WHITESPACE@[62; 63)
51 BLOCK_EXPR@[63; 65)
52 L_CURLY@[63; 64)
53 R_CURLY@[64; 65)
54 WHITESPACE@[65; 66)
55 ELSE_KW@[66; 70)
56 WHITESPACE@[70; 71)
57 IF_EXPR@[71; 90)
58 IF_KW@[71; 73)
59 WHITESPACE@[73; 74)
60 LITERAL@[74; 79)
61 FALSE_KW@[74; 79)
62 WHITESPACE@[79; 80)
63 BLOCK_EXPR@[80; 82)
64 L_CURLY@[80; 81)
65 R_CURLY@[81; 82)
66 WHITESPACE@[82; 83)
67 ELSE_KW@[83; 87)
68 WHITESPACE@[87; 88)
69 BLOCK_EXPR@[88; 90)
70 L_CURLY@[88; 89)
71 R_CURLY@[89; 90)
72 SEMI@[90; 91)
73 WHITESPACE@[91; 96)
74 EXPR_STMT@[96; 104)
75 IF_EXPR@[96; 103)
76 IF_KW@[96; 98)
77 WHITESPACE@[98; 99)
78 PATH_EXPR@[99; 100)
79 PATH@[99; 100)
80 PATH_SEGMENT@[99; 100)
81 NAME_REF@[99; 100)
82 IDENT@[99; 100) "S"
83 WHITESPACE@[100; 101)
84 BLOCK_EXPR@[101; 103)
85 L_CURLY@[101; 102)
86 R_CURLY@[102; 103)
87 SEMI@[103; 104)
88 WHITESPACE@[104; 105)
89 R_CURLY@[105; 106)
90 WHITESPACE@[106; 107)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.rs
new file mode 100644
index 000000000..c20d29751
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 || ();
3 || -> i32 { 92 };
4 |x| x;
5 move |x: i32,| x;
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt
new file mode 100644
index 000000000..6d9aeb331
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt
@@ -0,0 +1,93 @@
1FILE@[0; 79)
2 FUNCTION@[0; 78)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 78)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 21)
15 LAMBDA_EXPR@[15; 20)
16 PARAM_LIST@[15; 17)
17 PIPE@[15; 16)
18 PIPE@[16; 17)
19 WHITESPACE@[17; 18)
20 TUPLE_EXPR@[18; 20)
21 L_PAREN@[18; 19)
22 R_PAREN@[19; 20)
23 SEMI@[20; 21)
24 WHITESPACE@[21; 26)
25 EXPR_STMT@[26; 43)
26 LAMBDA_EXPR@[26; 42)
27 PARAM_LIST@[26; 28)
28 PIPE@[26; 27)
29 PIPE@[27; 28)
30 WHITESPACE@[28; 29)
31 THIN_ARROW@[29; 31)
32 WHITESPACE@[31; 32)
33 PATH_TYPE@[32; 35)
34 PATH@[32; 35)
35 PATH_SEGMENT@[32; 35)
36 NAME_REF@[32; 35)
37 IDENT@[32; 35) "i32"
38 WHITESPACE@[35; 36)
39 BLOCK_EXPR@[36; 42)
40 L_CURLY@[36; 37)
41 WHITESPACE@[37; 38)
42 LITERAL@[38; 40)
43 INT_NUMBER@[38; 40) "92"
44 WHITESPACE@[40; 41)
45 R_CURLY@[41; 42)
46 SEMI@[42; 43)
47 WHITESPACE@[43; 48)
48 EXPR_STMT@[48; 54)
49 LAMBDA_EXPR@[48; 53)
50 PARAM_LIST@[48; 51)
51 PIPE@[48; 49)
52 PARAM@[49; 50)
53 BIND_PAT@[49; 50)
54 NAME@[49; 50)
55 IDENT@[49; 50) "x"
56 PIPE@[50; 51)
57 WHITESPACE@[51; 52)
58 PATH_EXPR@[52; 53)
59 PATH@[52; 53)
60 PATH_SEGMENT@[52; 53)
61 NAME_REF@[52; 53)
62 IDENT@[52; 53) "x"
63 SEMI@[53; 54)
64 WHITESPACE@[54; 59)
65 EXPR_STMT@[59; 76)
66 LAMBDA_EXPR@[59; 75)
67 MOVE_KW@[59; 63)
68 WHITESPACE@[63; 64)
69 PARAM_LIST@[64; 73)
70 PIPE@[64; 65)
71 PARAM@[65; 71)
72 BIND_PAT@[65; 66)
73 NAME@[65; 66)
74 IDENT@[65; 66) "x"
75 COLON@[66; 67)
76 WHITESPACE@[67; 68)
77 PATH_TYPE@[68; 71)
78 PATH@[68; 71)
79 PATH_SEGMENT@[68; 71)
80 NAME_REF@[68; 71)
81 IDENT@[68; 71) "i32"
82 COMMA@[71; 72)
83 PIPE@[72; 73)
84 WHITESPACE@[73; 74)
85 PATH_EXPR@[74; 75)
86 PATH@[74; 75)
87 PATH_SEGMENT@[74; 75)
88 NAME_REF@[74; 75)
89 IDENT@[74; 75) "x"
90 SEMI@[75; 76)
91 WHITESPACE@[76; 77)
92 R_CURLY@[77; 78)
93 WHITESPACE@[78; 79)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0067_block_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0067_block_expr.rs
new file mode 100644
index 000000000..ec3780a04
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0067_block_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 {};
3 unsafe {};
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0067_block_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0067_block_expr.txt
new file mode 100644
index 000000000..981f39e6e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0067_block_expr.txt
@@ -0,0 +1,29 @@
1FILE@[0; 36)
2 FUNCTION@[0; 35)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 35)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 18)
15 BLOCK_EXPR@[15; 17)
16 L_CURLY@[15; 16)
17 R_CURLY@[16; 17)
18 SEMI@[17; 18)
19 WHITESPACE@[18; 23)
20 EXPR_STMT@[23; 33)
21 BLOCK_EXPR@[23; 32)
22 UNSAFE_KW@[23; 29)
23 WHITESPACE@[29; 30)
24 L_CURLY@[30; 31)
25 R_CURLY@[31; 32)
26 SEMI@[32; 33)
27 WHITESPACE@[33; 34)
28 R_CURLY@[34; 35)
29 WHITESPACE@[35; 36)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.rs
new file mode 100644
index 000000000..d9d99d2d3
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.rs
@@ -0,0 +1 @@
fn foo() { pub 92; } //FIXME
diff --git a/crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.txt
new file mode 100644
index 000000000..92e58938b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0068_pub_expr.txt
@@ -0,0 +1,25 @@
1FILE@[0; 29)
2 FUNCTION@[0; 20)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 20)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 11)
14 EXPR_STMT@[11; 18)
15 VISIBILITY@[11; 14)
16 PUB_KW@[11; 14)
17 WHITESPACE@[14; 15)
18 LITERAL@[15; 17)
19 INT_NUMBER@[15; 17) "92"
20 SEMI@[17; 18)
21 WHITESPACE@[18; 19)
22 R_CURLY@[19; 20)
23 WHITESPACE@[20; 21)
24 COMMENT@[21; 28)
25 WHITESPACE@[28; 29)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0068_return_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0068_return_expr.rs
new file mode 100644
index 000000000..5733666b6
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0068_return_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 return;
3 return 92;
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0068_return_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0068_return_expr.txt
new file mode 100644
index 000000000..4e4ec85b6
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0068_return_expr.txt
@@ -0,0 +1,28 @@
1FILE@[0; 40)
2 FUNCTION@[0; 39)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 39)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 22)
15 RETURN_EXPR@[15; 21)
16 RETURN_KW@[15; 21)
17 SEMI@[21; 22)
18 WHITESPACE@[22; 27)
19 EXPR_STMT@[27; 37)
20 RETURN_EXPR@[27; 36)
21 RETURN_KW@[27; 33)
22 WHITESPACE@[33; 34)
23 LITERAL@[34; 36)
24 INT_NUMBER@[34; 36) "92"
25 SEMI@[36; 37)
26 WHITESPACE@[37; 38)
27 R_CURLY@[38; 39)
28 WHITESPACE@[39; 40)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0069_match_arm.rs b/crates/libsyntax2/tests/data/parser/inline/0069_match_arm.rs
new file mode 100644
index 000000000..2c0e88414
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0069_match_arm.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 match () {
3 _ => (),
4 X | Y if Z => (),
5 };
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0069_match_arm.txt b/crates/libsyntax2/tests/data/parser/inline/0069_match_arm.txt
new file mode 100644
index 000000000..3377e8342
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0069_match_arm.txt
@@ -0,0 +1,65 @@
1FILE@[0; 78)
2 FUNCTION@[0; 77)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 77)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 75)
15 MATCH_EXPR@[15; 74)
16 MATCH_KW@[15; 20)
17 WHITESPACE@[20; 21)
18 TUPLE_EXPR@[21; 23)
19 L_PAREN@[21; 22)
20 R_PAREN@[22; 23)
21 WHITESPACE@[23; 24)
22 L_CURLY@[24; 25)
23 WHITESPACE@[25; 34)
24 MATCH_ARM@[34; 41)
25 PLACEHOLDER_PAT@[34; 35)
26 UNDERSCORE@[34; 35)
27 WHITESPACE@[35; 36)
28 FAT_ARROW@[36; 38)
29 WHITESPACE@[38; 39)
30 TUPLE_EXPR@[39; 41)
31 L_PAREN@[39; 40)
32 R_PAREN@[40; 41)
33 COMMA@[41; 42)
34 WHITESPACE@[42; 51)
35 MATCH_ARM@[51; 67)
36 BIND_PAT@[51; 52)
37 NAME@[51; 52)
38 IDENT@[51; 52) "X"
39 WHITESPACE@[52; 53)
40 PIPE@[53; 54)
41 WHITESPACE@[54; 55)
42 BIND_PAT@[55; 56)
43 NAME@[55; 56)
44 IDENT@[55; 56) "Y"
45 WHITESPACE@[56; 57)
46 IF_KW@[57; 59)
47 WHITESPACE@[59; 60)
48 PATH_EXPR@[60; 61)
49 PATH@[60; 61)
50 PATH_SEGMENT@[60; 61)
51 NAME_REF@[60; 61)
52 IDENT@[60; 61) "Z"
53 WHITESPACE@[61; 62)
54 FAT_ARROW@[62; 64)
55 WHITESPACE@[64; 65)
56 TUPLE_EXPR@[65; 67)
57 L_PAREN@[65; 66)
58 R_PAREN@[66; 67)
59 COMMA@[67; 68)
60 WHITESPACE@[68; 73)
61 R_CURLY@[73; 74)
62 SEMI@[74; 75)
63 WHITESPACE@[75; 76)
64 R_CURLY@[76; 77)
65 WHITESPACE@[77; 78)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0070_match_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0070_match_expr.rs
new file mode 100644
index 000000000..c9205dfa3
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0070_match_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 match () { };
3 match S {};
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0070_match_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0070_match_expr.txt
new file mode 100644
index 000000000..f9ba54486
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0070_match_expr.txt
@@ -0,0 +1,42 @@
1FILE@[0; 47)
2 FUNCTION@[0; 46)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 46)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 28)
15 MATCH_EXPR@[15; 27)
16 MATCH_KW@[15; 20)
17 WHITESPACE@[20; 21)
18 TUPLE_EXPR@[21; 23)
19 L_PAREN@[21; 22)
20 R_PAREN@[22; 23)
21 WHITESPACE@[23; 24)
22 L_CURLY@[24; 25)
23 WHITESPACE@[25; 26)
24 R_CURLY@[26; 27)
25 SEMI@[27; 28)
26 WHITESPACE@[28; 33)
27 EXPR_STMT@[33; 44)
28 MATCH_EXPR@[33; 43)
29 MATCH_KW@[33; 38)
30 WHITESPACE@[38; 39)
31 PATH_EXPR@[39; 40)
32 PATH@[39; 40)
33 PATH_SEGMENT@[39; 40)
34 NAME_REF@[39; 40)
35 IDENT@[39; 40) "S"
36 WHITESPACE@[40; 41)
37 L_CURLY@[41; 42)
38 R_CURLY@[42; 43)
39 SEMI@[43; 44)
40 WHITESPACE@[44; 45)
41 R_CURLY@[45; 46)
42 WHITESPACE@[46; 47)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.rs b/crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.rs
new file mode 100644
index 000000000..0dfe63629
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 let S() = ();
3 let S(_) = ();
4 let S(_,) = ();
5 let S(_, .. , x) = ();
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.txt b/crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.txt
new file mode 100644
index 000000000..f54835277
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0071_tuple_pat_fields.txt
@@ -0,0 +1,103 @@
1FILE@[0; 97)
2 FUNCTION@[0; 96)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 96)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 28)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 TUPLE_STRUCT_PAT@[19; 22)
18 PATH@[19; 20)
19 PATH_SEGMENT@[19; 20)
20 NAME_REF@[19; 20)
21 IDENT@[19; 20) "S"
22 L_PAREN@[20; 21)
23 R_PAREN@[21; 22)
24 WHITESPACE@[22; 23)
25 EQ@[23; 24)
26 WHITESPACE@[24; 25)
27 TUPLE_EXPR@[25; 27)
28 L_PAREN@[25; 26)
29 R_PAREN@[26; 27)
30 SEMI@[27; 28)
31 WHITESPACE@[28; 33)
32 LET_STMT@[33; 47)
33 LET_KW@[33; 36)
34 WHITESPACE@[36; 37)
35 TUPLE_STRUCT_PAT@[37; 41)
36 PATH@[37; 38)
37 PATH_SEGMENT@[37; 38)
38 NAME_REF@[37; 38)
39 IDENT@[37; 38) "S"
40 L_PAREN@[38; 39)
41 PLACEHOLDER_PAT@[39; 40)
42 UNDERSCORE@[39; 40)
43 R_PAREN@[40; 41)
44 WHITESPACE@[41; 42)
45 EQ@[42; 43)
46 WHITESPACE@[43; 44)
47 TUPLE_EXPR@[44; 46)
48 L_PAREN@[44; 45)
49 R_PAREN@[45; 46)
50 SEMI@[46; 47)
51 WHITESPACE@[47; 52)
52 LET_STMT@[52; 67)
53 LET_KW@[52; 55)
54 WHITESPACE@[55; 56)
55 TUPLE_STRUCT_PAT@[56; 61)
56 PATH@[56; 57)
57 PATH_SEGMENT@[56; 57)
58 NAME_REF@[56; 57)
59 IDENT@[56; 57) "S"
60 L_PAREN@[57; 58)
61 PLACEHOLDER_PAT@[58; 59)
62 UNDERSCORE@[58; 59)
63 COMMA@[59; 60)
64 R_PAREN@[60; 61)
65 WHITESPACE@[61; 62)
66 EQ@[62; 63)
67 WHITESPACE@[63; 64)
68 TUPLE_EXPR@[64; 66)
69 L_PAREN@[64; 65)
70 R_PAREN@[65; 66)
71 SEMI@[66; 67)
72 WHITESPACE@[67; 72)
73 LET_STMT@[72; 94)
74 LET_KW@[72; 75)
75 WHITESPACE@[75; 76)
76 TUPLE_STRUCT_PAT@[76; 88)
77 PATH@[76; 77)
78 PATH_SEGMENT@[76; 77)
79 NAME_REF@[76; 77)
80 IDENT@[76; 77) "S"
81 L_PAREN@[77; 78)
82 PLACEHOLDER_PAT@[78; 79)
83 UNDERSCORE@[78; 79)
84 COMMA@[79; 80)
85 WHITESPACE@[80; 81)
86 DOTDOT@[81; 83)
87 WHITESPACE@[83; 84)
88 COMMA@[84; 85)
89 WHITESPACE@[85; 86)
90 BIND_PAT@[86; 87)
91 NAME@[86; 87)
92 IDENT@[86; 87) "x"
93 R_PAREN@[87; 88)
94 WHITESPACE@[88; 89)
95 EQ@[89; 90)
96 WHITESPACE@[90; 91)
97 TUPLE_EXPR@[91; 93)
98 L_PAREN@[91; 92)
99 R_PAREN@[92; 93)
100 SEMI@[93; 94)
101 WHITESPACE@[94; 95)
102 R_CURLY@[95; 96)
103 WHITESPACE@[96; 97)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0072_path_part.rs b/crates/libsyntax2/tests/data/parser/inline/0072_path_part.rs
new file mode 100644
index 000000000..f6e32c7c1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0072_path_part.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 let foo::Bar = ();
3 let ::Bar = ();
4 let Bar { .. } = ();
5 let Bar(..) = ();
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0072_path_part.txt b/crates/libsyntax2/tests/data/parser/inline/0072_path_part.txt
new file mode 100644
index 000000000..20da5de86
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0072_path_part.txt
@@ -0,0 +1,94 @@
1FILE@[0; 103)
2 FUNCTION@[0; 102)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 102)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 33)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PATH_PAT@[19; 27)
18 PATH@[19; 27)
19 PATH@[19; 22)
20 PATH_SEGMENT@[19; 22)
21 NAME_REF@[19; 22)
22 IDENT@[19; 22) "foo"
23 COLONCOLON@[22; 24)
24 PATH_SEGMENT@[24; 27)
25 NAME_REF@[24; 27)
26 IDENT@[24; 27) "Bar"
27 WHITESPACE@[27; 28)
28 EQ@[28; 29)
29 WHITESPACE@[29; 30)
30 TUPLE_EXPR@[30; 32)
31 L_PAREN@[30; 31)
32 R_PAREN@[31; 32)
33 SEMI@[32; 33)
34 WHITESPACE@[33; 38)
35 LET_STMT@[38; 53)
36 LET_KW@[38; 41)
37 WHITESPACE@[41; 42)
38 PATH_PAT@[42; 47)
39 PATH@[42; 47)
40 PATH_SEGMENT@[42; 47)
41 COLONCOLON@[42; 44)
42 NAME_REF@[44; 47)
43 IDENT@[44; 47) "Bar"
44 WHITESPACE@[47; 48)
45 EQ@[48; 49)
46 WHITESPACE@[49; 50)
47 TUPLE_EXPR@[50; 52)
48 L_PAREN@[50; 51)
49 R_PAREN@[51; 52)
50 SEMI@[52; 53)
51 WHITESPACE@[53; 58)
52 LET_STMT@[58; 78)
53 LET_KW@[58; 61)
54 WHITESPACE@[61; 62)
55 STRUCT_PAT@[62; 72)
56 PATH@[62; 65)
57 PATH_SEGMENT@[62; 65)
58 NAME_REF@[62; 65)
59 IDENT@[62; 65) "Bar"
60 WHITESPACE@[65; 66)
61 L_CURLY@[66; 67)
62 WHITESPACE@[67; 68)
63 DOTDOT@[68; 70)
64 WHITESPACE@[70; 71)
65 R_CURLY@[71; 72)
66 WHITESPACE@[72; 73)
67 EQ@[73; 74)
68 WHITESPACE@[74; 75)
69 TUPLE_EXPR@[75; 77)
70 L_PAREN@[75; 76)
71 R_PAREN@[76; 77)
72 SEMI@[77; 78)
73 WHITESPACE@[78; 83)
74 LET_STMT@[83; 100)
75 LET_KW@[83; 86)
76 WHITESPACE@[86; 87)
77 TUPLE_STRUCT_PAT@[87; 94)
78 PATH@[87; 90)
79 PATH_SEGMENT@[87; 90)
80 NAME_REF@[87; 90)
81 IDENT@[87; 90) "Bar"
82 L_PAREN@[90; 91)
83 DOTDOT@[91; 93)
84 R_PAREN@[93; 94)
85 WHITESPACE@[94; 95)
86 EQ@[95; 96)
87 WHITESPACE@[96; 97)
88 TUPLE_EXPR@[97; 99)
89 L_PAREN@[97; 98)
90 R_PAREN@[98; 99)
91 SEMI@[99; 100)
92 WHITESPACE@[100; 101)
93 R_CURLY@[101; 102)
94 WHITESPACE@[102; 103)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.rs b/crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.rs
new file mode 100644
index 000000000..da3412fa8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 let S {} = ();
3 let S { f, ref mut g } = ();
4 let S { h: _, ..} = ();
5 let S { h: _, } = ();
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.txt b/crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.txt
new file mode 100644
index 000000000..fc0d44f7a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0073_struct_pat_fields.txt
@@ -0,0 +1,122 @@
1FILE@[0; 119)
2 FUNCTION@[0; 118)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 118)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 29)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 STRUCT_PAT@[19; 23)
18 PATH@[19; 20)
19 PATH_SEGMENT@[19; 20)
20 NAME_REF@[19; 20)
21 IDENT@[19; 20) "S"
22 WHITESPACE@[20; 21)
23 L_CURLY@[21; 22)
24 R_CURLY@[22; 23)
25 WHITESPACE@[23; 24)
26 EQ@[24; 25)
27 WHITESPACE@[25; 26)
28 TUPLE_EXPR@[26; 28)
29 L_PAREN@[26; 27)
30 R_PAREN@[27; 28)
31 SEMI@[28; 29)
32 WHITESPACE@[29; 34)
33 LET_STMT@[34; 62)
34 LET_KW@[34; 37)
35 WHITESPACE@[37; 38)
36 STRUCT_PAT@[38; 56)
37 PATH@[38; 39)
38 PATH_SEGMENT@[38; 39)
39 NAME_REF@[38; 39)
40 IDENT@[38; 39) "S"
41 WHITESPACE@[39; 40)
42 L_CURLY@[40; 41)
43 WHITESPACE@[41; 42)
44 BIND_PAT@[42; 43)
45 NAME@[42; 43)
46 IDENT@[42; 43) "f"
47 COMMA@[43; 44)
48 WHITESPACE@[44; 45)
49 BIND_PAT@[45; 54)
50 REF_KW@[45; 48)
51 WHITESPACE@[48; 49)
52 MUT_KW@[49; 52)
53 WHITESPACE@[52; 53)
54 NAME@[53; 54)
55 IDENT@[53; 54) "g"
56 WHITESPACE@[54; 55)
57 R_CURLY@[55; 56)
58 WHITESPACE@[56; 57)
59 EQ@[57; 58)
60 WHITESPACE@[58; 59)
61 TUPLE_EXPR@[59; 61)
62 L_PAREN@[59; 60)
63 R_PAREN@[60; 61)
64 SEMI@[61; 62)
65 WHITESPACE@[62; 67)
66 LET_STMT@[67; 90)
67 LET_KW@[67; 70)
68 WHITESPACE@[70; 71)
69 STRUCT_PAT@[71; 84)
70 PATH@[71; 72)
71 PATH_SEGMENT@[71; 72)
72 NAME_REF@[71; 72)
73 IDENT@[71; 72) "S"
74 WHITESPACE@[72; 73)
75 L_CURLY@[73; 74)
76 WHITESPACE@[74; 75)
77 IDENT@[75; 76) "h"
78 COLON@[76; 77)
79 WHITESPACE@[77; 78)
80 PLACEHOLDER_PAT@[78; 79)
81 UNDERSCORE@[78; 79)
82 COMMA@[79; 80)
83 WHITESPACE@[80; 81)
84 DOTDOT@[81; 83)
85 R_CURLY@[83; 84)
86 WHITESPACE@[84; 85)
87 EQ@[85; 86)
88 WHITESPACE@[86; 87)
89 TUPLE_EXPR@[87; 89)
90 L_PAREN@[87; 88)
91 R_PAREN@[88; 89)
92 SEMI@[89; 90)
93 WHITESPACE@[90; 95)
94 LET_STMT@[95; 116)
95 LET_KW@[95; 98)
96 WHITESPACE@[98; 99)
97 STRUCT_PAT@[99; 110)
98 PATH@[99; 100)
99 PATH_SEGMENT@[99; 100)
100 NAME_REF@[99; 100)
101 IDENT@[99; 100) "S"
102 WHITESPACE@[100; 101)
103 L_CURLY@[101; 102)
104 WHITESPACE@[102; 103)
105 IDENT@[103; 104) "h"
106 COLON@[104; 105)
107 WHITESPACE@[105; 106)
108 PLACEHOLDER_PAT@[106; 107)
109 UNDERSCORE@[106; 107)
110 COMMA@[107; 108)
111 WHITESPACE@[108; 109)
112 R_CURLY@[109; 110)
113 WHITESPACE@[110; 111)
114 EQ@[111; 112)
115 WHITESPACE@[112; 113)
116 TUPLE_EXPR@[113; 115)
117 L_PAREN@[113; 114)
118 R_PAREN@[114; 115)
119 SEMI@[115; 116)
120 WHITESPACE@[116; 117)
121 R_CURLY@[117; 118)
122 WHITESPACE@[118; 119)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.rs
new file mode 100644
index 000000000..f1c3f7118
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.rs
@@ -0,0 +1,5 @@
1fn foo() {
2 **&1;
3 !!true;
4 --1;
5}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.txt
new file mode 100644
index 000000000..e0b4ff964
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0074_unary_expr.txt
@@ -0,0 +1,44 @@
1FILE@[0; 44)
2 FUNCTION@[0; 43)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 43)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 20)
15 PREFIX_EXPR@[15; 19)
16 STAR@[15; 16)
17 PREFIX_EXPR@[16; 19)
18 STAR@[16; 17)
19 REF_EXPR@[17; 19)
20 AMP@[17; 18)
21 LITERAL@[18; 19)
22 INT_NUMBER@[18; 19) "1"
23 SEMI@[19; 20)
24 WHITESPACE@[20; 25)
25 EXPR_STMT@[25; 32)
26 PREFIX_EXPR@[25; 31)
27 EXCL@[25; 26)
28 PREFIX_EXPR@[26; 31)
29 EXCL@[26; 27)
30 LITERAL@[27; 31)
31 TRUE_KW@[27; 31)
32 SEMI@[31; 32)
33 WHITESPACE@[32; 37)
34 EXPR_STMT@[37; 41)
35 PREFIX_EXPR@[37; 40)
36 MINUS@[37; 38)
37 PREFIX_EXPR@[38; 40)
38 MINUS@[38; 39)
39 LITERAL@[39; 40)
40 INT_NUMBER@[39; 40) "1"
41 SEMI@[40; 41)
42 WHITESPACE@[41; 42)
43 R_CURLY@[42; 43)
44 WHITESPACE@[43; 44)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0075_try_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0075_try_expr.rs
new file mode 100644
index 000000000..8b74f7bc8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0075_try_expr.rs
@@ -0,0 +1,3 @@
1fn foo() {
2 x?;
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0075_try_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0075_try_expr.txt
new file mode 100644
index 000000000..f7b86f269
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0075_try_expr.txt
@@ -0,0 +1,25 @@
1FILE@[0; 21)
2 FUNCTION@[0; 20)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 20)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 18)
15 TRY_EXPR@[15; 17)
16 PATH_EXPR@[15; 16)
17 PATH@[15; 16)
18 PATH_SEGMENT@[15; 16)
19 NAME_REF@[15; 16)
20 IDENT@[15; 16) "x"
21 QUESTION@[16; 17)
22 SEMI@[17; 18)
23 WHITESPACE@[18; 19)
24 R_CURLY@[19; 20)
25 WHITESPACE@[20; 21)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0076_cond.rs b/crates/libsyntax2/tests/data/parser/inline/0076_cond.rs
new file mode 100644
index 000000000..fdb37ee6f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0076_cond.rs
@@ -0,0 +1 @@
fn foo() { if let Some(_) = None {} }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt b/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt
new file mode 100644
index 000000000..0cde88a90
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0076_cond.txt
@@ -0,0 +1,42 @@
1FILE@[0; 38)
2 FUNCTION@[0; 37)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 37)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 11)
14 IF_EXPR@[11; 35)
15 IF_KW@[11; 13)
16 WHITESPACE@[13; 14)
17 LET_KW@[14; 17)
18 WHITESPACE@[17; 18)
19 TUPLE_STRUCT_PAT@[18; 25)
20 PATH@[18; 22)
21 PATH_SEGMENT@[18; 22)
22 NAME_REF@[18; 22)
23 IDENT@[18; 22) "Some"
24 L_PAREN@[22; 23)
25 PLACEHOLDER_PAT@[23; 24)
26 UNDERSCORE@[23; 24)
27 R_PAREN@[24; 25)
28 WHITESPACE@[25; 26)
29 EQ@[26; 27)
30 WHITESPACE@[27; 28)
31 PATH_EXPR@[28; 32)
32 PATH@[28; 32)
33 PATH_SEGMENT@[28; 32)
34 NAME_REF@[28; 32)
35 IDENT@[28; 32) "None"
36 WHITESPACE@[32; 33)
37 BLOCK_EXPR@[33; 35)
38 L_CURLY@[33; 34)
39 R_CURLY@[34; 35)
40 WHITESPACE@[35; 36)
41 R_CURLY@[36; 37)
42 WHITESPACE@[37; 38)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.rs
new file mode 100644
index 000000000..293046a04
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 while true {};
3 while let Some(x) = it.next() {};
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt
new file mode 100644
index 000000000..82e63fd46
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0077_while_expr.txt
@@ -0,0 +1,64 @@
1FILE@[0; 70)
2 FUNCTION@[0; 69)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 69)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 29)
15 WHILE_EXPR@[15; 28)
16 WHILE_KW@[15; 20)
17 WHITESPACE@[20; 21)
18 LITERAL@[21; 25)
19 TRUE_KW@[21; 25)
20 WHITESPACE@[25; 26)
21 BLOCK_EXPR@[26; 28)
22 L_CURLY@[26; 27)
23 R_CURLY@[27; 28)
24 SEMI@[28; 29)
25 WHITESPACE@[29; 34)
26 EXPR_STMT@[34; 67)
27 WHILE_EXPR@[34; 66)
28 WHILE_KW@[34; 39)
29 WHITESPACE@[39; 40)
30 LET_KW@[40; 43)
31 WHITESPACE@[43; 44)
32 TUPLE_STRUCT_PAT@[44; 51)
33 PATH@[44; 48)
34 PATH_SEGMENT@[44; 48)
35 NAME_REF@[44; 48)
36 IDENT@[44; 48) "Some"
37 L_PAREN@[48; 49)
38 BIND_PAT@[49; 50)
39 NAME@[49; 50)
40 IDENT@[49; 50) "x"
41 R_PAREN@[50; 51)
42 WHITESPACE@[51; 52)
43 EQ@[52; 53)
44 WHITESPACE@[53; 54)
45 METHOD_CALL_EXPR@[54; 63)
46 PATH_EXPR@[54; 56)
47 PATH@[54; 56)
48 PATH_SEGMENT@[54; 56)
49 NAME_REF@[54; 56)
50 IDENT@[54; 56) "it"
51 DOT@[56; 57)
52 NAME_REF@[57; 61)
53 IDENT@[57; 61) "next"
54 ARG_LIST@[61; 63)
55 L_PAREN@[61; 62)
56 R_PAREN@[62; 63)
57 WHITESPACE@[63; 64)
58 BLOCK_EXPR@[64; 66)
59 L_CURLY@[64; 65)
60 R_CURLY@[65; 66)
61 SEMI@[66; 67)
62 WHITESPACE@[67; 68)
63 R_CURLY@[68; 69)
64 WHITESPACE@[69; 70)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.rs b/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.rs
new file mode 100644
index 000000000..24a15c5c5
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.rs
@@ -0,0 +1,5 @@
1fn foo() {}
2macro_rules! foo {}
3foo::bar!();
4super::baz! {}
5struct S;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt b/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt
new file mode 100644
index 000000000..c003d24e1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt
@@ -0,0 +1,62 @@
1FILE@[0; 70)
2 FUNCTION@[0; 11)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 11)
12 L_CURLY@[9; 10)
13 R_CURLY@[10; 11)
14 WHITESPACE@[11; 12)
15 MACRO_CALL@[12; 31)
16 PATH@[12; 23)
17 PATH_SEGMENT@[12; 23)
18 NAME_REF@[12; 23)
19 IDENT@[12; 23) "macro_rules"
20 EXCL@[23; 24)
21 WHITESPACE@[24; 25)
22 IDENT@[25; 28) "foo"
23 WHITESPACE@[28; 29)
24 L_CURLY@[29; 30)
25 R_CURLY@[30; 31)
26 WHITESPACE@[31; 32)
27 MACRO_CALL@[32; 44)
28 PATH@[32; 40)
29 PATH@[32; 35)
30 PATH_SEGMENT@[32; 35)
31 NAME_REF@[32; 35)
32 IDENT@[32; 35) "foo"
33 COLONCOLON@[35; 37)
34 PATH_SEGMENT@[37; 40)
35 NAME_REF@[37; 40)
36 IDENT@[37; 40) "bar"
37 EXCL@[40; 41)
38 L_PAREN@[41; 42)
39 R_PAREN@[42; 43)
40 SEMI@[43; 44)
41 WHITESPACE@[44; 45)
42 MACRO_CALL@[45; 59)
43 PATH@[45; 55)
44 PATH@[45; 50)
45 PATH_SEGMENT@[45; 50)
46 SUPER_KW@[45; 50)
47 COLONCOLON@[50; 52)
48 PATH_SEGMENT@[52; 55)
49 NAME_REF@[52; 55)
50 IDENT@[52; 55) "baz"
51 EXCL@[55; 56)
52 WHITESPACE@[56; 57)
53 L_CURLY@[57; 58)
54 R_CURLY@[58; 59)
55 WHITESPACE@[59; 60)
56 STRUCT_ITEM@[60; 69)
57 STRUCT_KW@[60; 66)
58 WHITESPACE@[66; 67)
59 NAME@[67; 68)
60 IDENT@[67; 68) "S"
61 SEMI@[68; 69)
62 WHITESPACE@[69; 70)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.rs
new file mode 100644
index 000000000..3e53d56d6
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.rs
@@ -0,0 +1,3 @@
1fn foo() {
2 82 as i32;
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.txt
new file mode 100644
index 000000000..642557e15
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0079_cast_expr.txt
@@ -0,0 +1,29 @@
1FILE@[0; 28)
2 FUNCTION@[0; 27)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 27)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 25)
15 CAST_EXPR@[15; 24)
16 LITERAL@[15; 17)
17 INT_NUMBER@[15; 17) "82"
18 WHITESPACE@[17; 18)
19 AS_KW@[18; 20)
20 WHITESPACE@[20; 21)
21 PATH_TYPE@[21; 24)
22 PATH@[21; 24)
23 PATH_SEGMENT@[21; 24)
24 NAME_REF@[21; 24)
25 IDENT@[21; 24) "i32"
26 SEMI@[24; 25)
27 WHITESPACE@[25; 26)
28 R_CURLY@[26; 27)
29 WHITESPACE@[27; 28)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.rs
new file mode 100644
index 000000000..e4f774280
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.rs
@@ -0,0 +1,5 @@
1fn foo() {
2 ();
3 (1);
4 (1,);
5}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.txt
new file mode 100644
index 000000000..728ba6ec7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0080_tuple_expr.txt
@@ -0,0 +1,38 @@
1FILE@[0; 40)
2 FUNCTION@[0; 39)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 39)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 18)
15 TUPLE_EXPR@[15; 17)
16 L_PAREN@[15; 16)
17 R_PAREN@[16; 17)
18 SEMI@[17; 18)
19 WHITESPACE@[18; 23)
20 EXPR_STMT@[23; 27)
21 PAREN_EXPR@[23; 26)
22 L_PAREN@[23; 24)
23 LITERAL@[24; 25)
24 INT_NUMBER@[24; 25) "1"
25 R_PAREN@[25; 26)
26 SEMI@[26; 27)
27 WHITESPACE@[27; 32)
28 EXPR_STMT@[32; 37)
29 TUPLE_EXPR@[32; 36)
30 L_PAREN@[32; 33)
31 LITERAL@[33; 34)
32 INT_NUMBER@[33; 34) "1"
33 COMMA@[34; 35)
34 R_PAREN@[35; 36)
35 SEMI@[36; 37)
36 WHITESPACE@[37; 38)
37 R_CURLY@[38; 39)
38 WHITESPACE@[39; 40)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0081_index_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0081_index_expr.rs
new file mode 100644
index 000000000..b9ba78a6c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0081_index_expr.rs
@@ -0,0 +1,3 @@
1fn foo() {
2 x[1][2];
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0081_index_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0081_index_expr.txt
new file mode 100644
index 000000000..80af4caed
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0081_index_expr.txt
@@ -0,0 +1,33 @@
1FILE@[0; 26)
2 FUNCTION@[0; 25)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 25)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 23)
15 INDEX_EXPR@[15; 22)
16 INDEX_EXPR@[15; 19)
17 PATH_EXPR@[15; 16)
18 PATH@[15; 16)
19 PATH_SEGMENT@[15; 16)
20 NAME_REF@[15; 16)
21 IDENT@[15; 16) "x"
22 L_BRACK@[16; 17)
23 LITERAL@[17; 18)
24 INT_NUMBER@[17; 18) "1"
25 R_BRACK@[18; 19)
26 L_BRACK@[19; 20)
27 LITERAL@[20; 21)
28 INT_NUMBER@[20; 21) "2"
29 R_BRACK@[21; 22)
30 SEMI@[22; 23)
31 WHITESPACE@[23; 24)
32 R_CURLY@[24; 25)
33 WHITESPACE@[25; 26)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.rs b/crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.rs
new file mode 100644
index 000000000..f785acd36
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.rs
@@ -0,0 +1,3 @@
1fn main() {
2 let (a, b, ..) = ();
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.txt b/crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.txt
new file mode 100644
index 000000000..d8314b5d8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0082_tuple_pat.txt
@@ -0,0 +1,40 @@
1FILE@[0; 39)
2 FUNCTION@[0; 38)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 38)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 LET_STMT@[16; 36)
15 LET_KW@[16; 19)
16 WHITESPACE@[19; 20)
17 TUPLE_PAT@[20; 30)
18 L_PAREN@[20; 21)
19 BIND_PAT@[21; 22)
20 NAME@[21; 22)
21 IDENT@[21; 22) "a"
22 COMMA@[22; 23)
23 WHITESPACE@[23; 24)
24 BIND_PAT@[24; 25)
25 NAME@[24; 25)
26 IDENT@[24; 25) "b"
27 COMMA@[25; 26)
28 WHITESPACE@[26; 27)
29 DOTDOT@[27; 29)
30 R_PAREN@[29; 30)
31 WHITESPACE@[30; 31)
32 EQ@[31; 32)
33 WHITESPACE@[32; 33)
34 TUPLE_EXPR@[33; 35)
35 L_PAREN@[33; 34)
36 R_PAREN@[34; 35)
37 SEMI@[35; 36)
38 WHITESPACE@[36; 37)
39 R_CURLY@[37; 38)
40 WHITESPACE@[38; 39)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.rs b/crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.rs
new file mode 100644
index 000000000..c39fe8e68
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.rs
@@ -0,0 +1 @@
fn foo() { let x = 1..; }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.txt b/crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.txt
new file mode 100644
index 000000000..bf9b2c695
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0083_postfix_range.txt
@@ -0,0 +1,30 @@
1FILE@[0; 26)
2 FUNCTION@[0; 25)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 25)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 11)
14 LET_STMT@[11; 23)
15 LET_KW@[11; 14)
16 WHITESPACE@[14; 15)
17 BIND_PAT@[15; 16)
18 NAME@[15; 16)
19 IDENT@[15; 16) "x"
20 WHITESPACE@[16; 17)
21 EQ@[17; 18)
22 WHITESPACE@[18; 19)
23 RANGE_EXPR@[19; 22)
24 LITERAL@[19; 20)
25 INT_NUMBER@[19; 20) "1"
26 DOTDOT@[20; 22)
27 SEMI@[22; 23)
28 WHITESPACE@[23; 24)
29 R_CURLY@[24; 25)
30 WHITESPACE@[25; 26)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.rs
new file mode 100644
index 000000000..9f078fa48
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.rs
@@ -0,0 +1,3 @@
1fn foo() {
2 loop {};
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.txt
new file mode 100644
index 000000000..5e0de55d4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0084_loop_expr.txt
@@ -0,0 +1,24 @@
1FILE@[0; 26)
2 FUNCTION@[0; 25)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 25)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 23)
15 LOOP_EXPR@[15; 22)
16 LOOP_KW@[15; 19)
17 WHITESPACE@[19; 20)
18 BLOCK_EXPR@[20; 22)
19 L_CURLY@[20; 21)
20 R_CURLY@[21; 22)
21 SEMI@[22; 23)
22 WHITESPACE@[23; 24)
23 R_CURLY@[24; 25)
24 WHITESPACE@[25; 26)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0085_for_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0085_for_expr.rs
new file mode 100644
index 000000000..972197d2a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0085_for_expr.rs
@@ -0,0 +1,3 @@
1fn foo() {
2 for x in [] {};
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0085_for_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0085_for_expr.txt
new file mode 100644
index 000000000..3a378cfcf
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0085_for_expr.txt
@@ -0,0 +1,34 @@
1FILE@[0; 33)
2 FUNCTION@[0; 32)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 32)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 30)
15 FOR_EXPR@[15; 29)
16 FOR_KW@[15; 18)
17 WHITESPACE@[18; 19)
18 BIND_PAT@[19; 20)
19 NAME@[19; 20)
20 IDENT@[19; 20) "x"
21 WHITESPACE@[20; 21)
22 IN_KW@[21; 23)
23 WHITESPACE@[23; 24)
24 ARRAY_EXPR@[24; 26)
25 L_BRACK@[24; 25)
26 R_BRACK@[25; 26)
27 WHITESPACE@[26; 27)
28 BLOCK_EXPR@[27; 29)
29 L_CURLY@[27; 28)
30 R_CURLY@[28; 29)
31 SEMI@[29; 30)
32 WHITESPACE@[30; 31)
33 R_CURLY@[31; 32)
34 WHITESPACE@[32; 33)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.rs b/crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.rs
new file mode 100644
index 000000000..1f25d577a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.rs
@@ -0,0 +1,7 @@
1fn foo() {
2 match () {
3 _ => (),
4 _ => {}
5 _ => ()
6 }
7}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.txt b/crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.txt
new file mode 100644
index 000000000..5465a3797
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0085_match_arms_commas.txt
@@ -0,0 +1,57 @@
1FILE@[0; 83)
2 FUNCTION@[0; 82)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 82)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 MATCH_EXPR@[15; 80)
15 MATCH_KW@[15; 20)
16 WHITESPACE@[20; 21)
17 TUPLE_EXPR@[21; 23)
18 L_PAREN@[21; 22)
19 R_PAREN@[22; 23)
20 WHITESPACE@[23; 24)
21 L_CURLY@[24; 25)
22 WHITESPACE@[25; 34)
23 MATCH_ARM@[34; 41)
24 PLACEHOLDER_PAT@[34; 35)
25 UNDERSCORE@[34; 35)
26 WHITESPACE@[35; 36)
27 FAT_ARROW@[36; 38)
28 WHITESPACE@[38; 39)
29 TUPLE_EXPR@[39; 41)
30 L_PAREN@[39; 40)
31 R_PAREN@[40; 41)
32 COMMA@[41; 42)
33 WHITESPACE@[42; 51)
34 MATCH_ARM@[51; 58)
35 PLACEHOLDER_PAT@[51; 52)
36 UNDERSCORE@[51; 52)
37 WHITESPACE@[52; 53)
38 FAT_ARROW@[53; 55)
39 WHITESPACE@[55; 56)
40 BLOCK_EXPR@[56; 58)
41 L_CURLY@[56; 57)
42 R_CURLY@[57; 58)
43 WHITESPACE@[58; 67)
44 MATCH_ARM@[67; 74)
45 PLACEHOLDER_PAT@[67; 68)
46 UNDERSCORE@[67; 68)
47 WHITESPACE@[68; 69)
48 FAT_ARROW@[69; 71)
49 WHITESPACE@[71; 72)
50 TUPLE_EXPR@[72; 74)
51 L_PAREN@[72; 73)
52 R_PAREN@[73; 74)
53 WHITESPACE@[74; 79)
54 R_CURLY@[79; 80)
55 WHITESPACE@[80; 81)
56 R_CURLY@[81; 82)
57 WHITESPACE@[82; 83)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0086_array_expr.rs b/crates/libsyntax2/tests/data/parser/inline/0086_array_expr.rs
new file mode 100644
index 000000000..4dc1999d1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0086_array_expr.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 [];
3 [1];
4 [1, 2,];
5 [1; 2];
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0086_array_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0086_array_expr.txt
new file mode 100644
index 000000000..9a5f56edf
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0086_array_expr.txt
@@ -0,0 +1,54 @@
1FILE@[0; 55)
2 FUNCTION@[0; 54)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 54)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 18)
15 ARRAY_EXPR@[15; 17)
16 L_BRACK@[15; 16)
17 R_BRACK@[16; 17)
18 SEMI@[17; 18)
19 WHITESPACE@[18; 23)
20 EXPR_STMT@[23; 27)
21 ARRAY_EXPR@[23; 26)
22 L_BRACK@[23; 24)
23 LITERAL@[24; 25)
24 INT_NUMBER@[24; 25) "1"
25 R_BRACK@[25; 26)
26 SEMI@[26; 27)
27 WHITESPACE@[27; 32)
28 EXPR_STMT@[32; 40)
29 ARRAY_EXPR@[32; 39)
30 L_BRACK@[32; 33)
31 LITERAL@[33; 34)
32 INT_NUMBER@[33; 34) "1"
33 COMMA@[34; 35)
34 WHITESPACE@[35; 36)
35 LITERAL@[36; 37)
36 INT_NUMBER@[36; 37) "2"
37 COMMA@[37; 38)
38 R_BRACK@[38; 39)
39 SEMI@[39; 40)
40 WHITESPACE@[40; 45)
41 EXPR_STMT@[45; 52)
42 ARRAY_EXPR@[45; 51)
43 L_BRACK@[45; 46)
44 LITERAL@[46; 47)
45 INT_NUMBER@[46; 47) "1"
46 SEMI@[47; 48)
47 WHITESPACE@[48; 49)
48 LITERAL@[49; 50)
49 INT_NUMBER@[49; 50) "2"
50 R_BRACK@[50; 51)
51 SEMI@[51; 52)
52 WHITESPACE@[52; 53)
53 R_CURLY@[53; 54)
54 WHITESPACE@[54; 55)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.rs b/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.rs
new file mode 100644
index 000000000..d769da43d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.rs
@@ -0,0 +1,9 @@
1fn foo() {
2 if true {}
3 loop {}
4 match () {}
5 while true {}
6 for _ in () {}
7 {}
8 {}
9}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt b/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt
new file mode 100644
index 000000000..d19a270ac
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0086_no_semi_after_block.txt
@@ -0,0 +1,82 @@
1FILE@[0; 107)
2 FUNCTION@[0; 106)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 106)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 25)
15 IF_EXPR@[15; 25)
16 IF_KW@[15; 17)
17 WHITESPACE@[17; 18)
18 LITERAL@[18; 22)
19 TRUE_KW@[18; 22)
20 WHITESPACE@[22; 23)
21 BLOCK_EXPR@[23; 25)
22 L_CURLY@[23; 24)
23 R_CURLY@[24; 25)
24 WHITESPACE@[25; 30)
25 EXPR_STMT@[30; 37)
26 LOOP_EXPR@[30; 37)
27 LOOP_KW@[30; 34)
28 WHITESPACE@[34; 35)
29 BLOCK_EXPR@[35; 37)
30 L_CURLY@[35; 36)
31 R_CURLY@[36; 37)
32 WHITESPACE@[37; 42)
33 EXPR_STMT@[42; 53)
34 MATCH_EXPR@[42; 53)
35 MATCH_KW@[42; 47)
36 WHITESPACE@[47; 48)
37 TUPLE_EXPR@[48; 50)
38 L_PAREN@[48; 49)
39 R_PAREN@[49; 50)
40 WHITESPACE@[50; 51)
41 L_CURLY@[51; 52)
42 R_CURLY@[52; 53)
43 WHITESPACE@[53; 58)
44 EXPR_STMT@[58; 71)
45 WHILE_EXPR@[58; 71)
46 WHILE_KW@[58; 63)
47 WHITESPACE@[63; 64)
48 LITERAL@[64; 68)
49 TRUE_KW@[64; 68)
50 WHITESPACE@[68; 69)
51 BLOCK_EXPR@[69; 71)
52 L_CURLY@[69; 70)
53 R_CURLY@[70; 71)
54 WHITESPACE@[71; 76)
55 EXPR_STMT@[76; 90)
56 FOR_EXPR@[76; 90)
57 FOR_KW@[76; 79)
58 WHITESPACE@[79; 80)
59 PLACEHOLDER_PAT@[80; 81)
60 UNDERSCORE@[80; 81)
61 WHITESPACE@[81; 82)
62 IN_KW@[82; 84)
63 WHITESPACE@[84; 85)
64 TUPLE_EXPR@[85; 87)
65 L_PAREN@[85; 86)
66 R_PAREN@[86; 87)
67 WHITESPACE@[87; 88)
68 BLOCK_EXPR@[88; 90)
69 L_CURLY@[88; 89)
70 R_CURLY@[89; 90)
71 WHITESPACE@[90; 95)
72 EXPR_STMT@[95; 97)
73 BLOCK_EXPR@[95; 97)
74 L_CURLY@[95; 96)
75 R_CURLY@[96; 97)
76 WHITESPACE@[97; 102)
77 BLOCK_EXPR@[102; 104)
78 L_CURLY@[102; 103)
79 R_CURLY@[103; 104)
80 WHITESPACE@[104; 105)
81 R_CURLY@[105; 106)
82 WHITESPACE@[106; 107)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs b/crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs
new file mode 100644
index 000000000..2edd578f9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.rs
@@ -0,0 +1,7 @@
1fn foo() {
2 match () {
3 _ => {}
4 () => {}
5 [] => {}
6 }
7}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt b/crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt
new file mode 100644
index 000000000..e83b6d183
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt
@@ -0,0 +1,58 @@
1FILE@[0; 84)
2 FUNCTION@[0; 83)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 83)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 MATCH_EXPR@[15; 81)
15 MATCH_KW@[15; 20)
16 WHITESPACE@[20; 21)
17 TUPLE_EXPR@[21; 23)
18 L_PAREN@[21; 22)
19 R_PAREN@[22; 23)
20 WHITESPACE@[23; 24)
21 L_CURLY@[24; 25)
22 WHITESPACE@[25; 34)
23 MATCH_ARM@[34; 41)
24 PLACEHOLDER_PAT@[34; 35)
25 UNDERSCORE@[34; 35)
26 WHITESPACE@[35; 36)
27 FAT_ARROW@[36; 38)
28 WHITESPACE@[38; 39)
29 BLOCK_EXPR@[39; 41)
30 L_CURLY@[39; 40)
31 R_CURLY@[40; 41)
32 WHITESPACE@[41; 50)
33 MATCH_ARM@[50; 58)
34 TUPLE_PAT@[50; 52)
35 L_PAREN@[50; 51)
36 R_PAREN@[51; 52)
37 WHITESPACE@[52; 53)
38 FAT_ARROW@[53; 55)
39 WHITESPACE@[55; 56)
40 BLOCK_EXPR@[56; 58)
41 L_CURLY@[56; 57)
42 R_CURLY@[57; 58)
43 WHITESPACE@[58; 67)
44 MATCH_ARM@[67; 75)
45 SLICE_PAT@[67; 69)
46 L_BRACK@[67; 68)
47 R_BRACK@[68; 69)
48 WHITESPACE@[69; 70)
49 FAT_ARROW@[70; 72)
50 WHITESPACE@[72; 73)
51 BLOCK_EXPR@[73; 75)
52 L_CURLY@[73; 74)
53 R_CURLY@[74; 75)
54 WHITESPACE@[75; 80)
55 R_CURLY@[80; 81)
56 WHITESPACE@[81; 82)
57 R_CURLY@[82; 83)
58 WHITESPACE@[83; 84)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs b/crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs
new file mode 100644
index 000000000..37b843742
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.rs
@@ -0,0 +1,4 @@
1fn foo() {
2 let _ = {1} & 2;
3 {1} &2;
4}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt b/crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt
new file mode 100644
index 000000000..df4c20b0e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt
@@ -0,0 +1,50 @@
1FILE@[0; 46)
2 FUNCTION@[0; 45)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 45)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 LET_STMT@[15; 31)
15 LET_KW@[15; 18)
16 WHITESPACE@[18; 19)
17 PLACEHOLDER_PAT@[19; 20)
18 UNDERSCORE@[19; 20)
19 WHITESPACE@[20; 21)
20 EQ@[21; 22)
21 WHITESPACE@[22; 23)
22 BIN_EXPR@[23; 30)
23 BLOCK_EXPR@[23; 26)
24 L_CURLY@[23; 24)
25 LITERAL@[24; 25)
26 INT_NUMBER@[24; 25) "1"
27 R_CURLY@[25; 26)
28 WHITESPACE@[26; 27)
29 AMP@[27; 28)
30 WHITESPACE@[28; 29)
31 LITERAL@[29; 30)
32 INT_NUMBER@[29; 30) "2"
33 SEMI@[30; 31)
34 WHITESPACE@[31; 36)
35 EXPR_STMT@[36; 39)
36 BLOCK_EXPR@[36; 39)
37 L_CURLY@[36; 37)
38 LITERAL@[37; 38)
39 INT_NUMBER@[37; 38) "1"
40 R_CURLY@[38; 39)
41 WHITESPACE@[39; 40)
42 EXPR_STMT@[40; 43)
43 REF_EXPR@[40; 42)
44 AMP@[40; 41)
45 LITERAL@[41; 42)
46 INT_NUMBER@[41; 42) "2"
47 SEMI@[42; 43)
48 WHITESPACE@[43; 44)
49 R_CURLY@[44; 45)
50 WHITESPACE@[45; 46)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.rs b/crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.rs
new file mode 100644
index 000000000..7955973b9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.rs
@@ -0,0 +1,3 @@
1fn main() {
2 let [a, b, ..] = [];
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.txt b/crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.txt
new file mode 100644
index 000000000..8379df33b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0089_slice_pat.txt
@@ -0,0 +1,40 @@
1FILE@[0; 39)
2 FUNCTION@[0; 38)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 38)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 LET_STMT@[16; 36)
15 LET_KW@[16; 19)
16 WHITESPACE@[19; 20)
17 SLICE_PAT@[20; 30)
18 L_BRACK@[20; 21)
19 BIND_PAT@[21; 22)
20 NAME@[21; 22)
21 IDENT@[21; 22) "a"
22 COMMA@[22; 23)
23 WHITESPACE@[23; 24)
24 BIND_PAT@[24; 25)
25 NAME@[24; 25)
26 IDENT@[24; 25) "b"
27 COMMA@[25; 26)
28 WHITESPACE@[26; 27)
29 DOTDOT@[27; 29)
30 R_BRACK@[29; 30)
31 WHITESPACE@[30; 31)
32 EQ@[31; 32)
33 WHITESPACE@[32; 33)
34 ARRAY_EXPR@[33; 35)
35 L_BRACK@[33; 34)
36 R_BRACK@[34; 35)
37 SEMI@[35; 36)
38 WHITESPACE@[36; 37)
39 R_CURLY@[37; 38)
40 WHITESPACE@[38; 39)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.rs b/crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.rs
new file mode 100644
index 000000000..a5ec3239f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.rs
@@ -0,0 +1,6 @@
1impl F {
2 type A: Clone;
3 const B: i32;
4 fn foo() {}
5 fn bar(&self);
6}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.txt b/crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.txt
new file mode 100644
index 000000000..c04c48588
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0090_trait_item_items.txt
@@ -0,0 +1,67 @@
1FILE@[0; 83)
2 IMPL_ITEM@[0; 82)
3 IMPL_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 PATH_TYPE@[5; 6)
6 PATH@[5; 6)
7 PATH_SEGMENT@[5; 6)
8 NAME_REF@[5; 6)
9 IDENT@[5; 6) "F"
10 WHITESPACE@[6; 7)
11 L_CURLY@[7; 8)
12 WHITESPACE@[8; 13)
13 TYPE_ITEM@[13; 27)
14 TYPE_KW@[13; 17)
15 WHITESPACE@[17; 18)
16 NAME@[18; 19)
17 IDENT@[18; 19) "A"
18 COLON@[19; 20)
19 WHITESPACE@[20; 21)
20 PATH@[21; 26)
21 PATH_SEGMENT@[21; 26)
22 NAME_REF@[21; 26)
23 IDENT@[21; 26) "Clone"
24 SEMI@[26; 27)
25 WHITESPACE@[27; 32)
26 CONST_ITEM@[32; 45)
27 CONST_KW@[32; 37)
28 WHITESPACE@[37; 38)
29 NAME@[38; 39)
30 IDENT@[38; 39) "B"
31 COLON@[39; 40)
32 WHITESPACE@[40; 41)
33 PATH_TYPE@[41; 44)
34 PATH@[41; 44)
35 PATH_SEGMENT@[41; 44)
36 NAME_REF@[41; 44)
37 IDENT@[41; 44) "i32"
38 SEMI@[44; 45)
39 WHITESPACE@[45; 50)
40 FUNCTION@[50; 61)
41 FN_KW@[50; 52)
42 WHITESPACE@[52; 53)
43 NAME@[53; 56)
44 IDENT@[53; 56) "foo"
45 PARAM_LIST@[56; 58)
46 L_PAREN@[56; 57)
47 R_PAREN@[57; 58)
48 WHITESPACE@[58; 59)
49 BLOCK_EXPR@[59; 61)
50 L_CURLY@[59; 60)
51 R_CURLY@[60; 61)
52 WHITESPACE@[61; 66)
53 FUNCTION@[66; 80)
54 FN_KW@[66; 68)
55 WHITESPACE@[68; 69)
56 NAME@[69; 72)
57 IDENT@[69; 72) "bar"
58 PARAM_LIST@[72; 79)
59 L_PAREN@[72; 73)
60 SELF_PARAM@[73; 78)
61 AMP@[73; 74)
62 SELF_KW@[74; 78)
63 R_PAREN@[78; 79)
64 SEMI@[79; 80)
65 WHITESPACE@[80; 81)
66 R_CURLY@[81; 82)
67 WHITESPACE@[82; 83)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.rs b/crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.rs
new file mode 100644
index 000000000..c9f74f7f5
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.rs
@@ -0,0 +1 @@
trait T { fn foo(); }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.txt b/crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.txt
new file mode 100644
index 000000000..5a76af652
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0091_fn_decl.txt
@@ -0,0 +1,21 @@
1FILE@[0; 22)
2 TRAIT_ITEM@[0; 21)
3 TRAIT_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 NAME@[6; 7)
6 IDENT@[6; 7) "T"
7 WHITESPACE@[7; 8)
8 L_CURLY@[8; 9)
9 WHITESPACE@[9; 10)
10 FUNCTION@[10; 19)
11 FN_KW@[10; 12)
12 WHITESPACE@[12; 13)
13 NAME@[13; 16)
14 IDENT@[13; 16) "foo"
15 PARAM_LIST@[16; 18)
16 L_PAREN@[16; 17)
17 R_PAREN@[17; 18)
18 SEMI@[18; 19)
19 WHITESPACE@[19; 20)
20 R_CURLY@[20; 21)
21 WHITESPACE@[21; 22)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.rs b/crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.rs
new file mode 100644
index 000000000..16f674d9d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.rs
@@ -0,0 +1,7 @@
1fn main() {
2 match () {
3 92 => (),
4 'c' => (),
5 "hello" => (),
6 }
7}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.txt b/crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.txt
new file mode 100644
index 000000000..a2f985408
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0092_literal_pattern.txt
@@ -0,0 +1,59 @@
1FILE@[0; 95)
2 FUNCTION@[0; 94)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 94)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 MATCH_EXPR@[16; 92)
15 MATCH_KW@[16; 21)
16 WHITESPACE@[21; 22)
17 TUPLE_EXPR@[22; 24)
18 L_PAREN@[22; 23)
19 R_PAREN@[23; 24)
20 WHITESPACE@[24; 25)
21 L_CURLY@[25; 26)
22 WHITESPACE@[26; 35)
23 MATCH_ARM@[35; 43)
24 LITERAL@[35; 37)
25 INT_NUMBER@[35; 37) "92"
26 WHITESPACE@[37; 38)
27 FAT_ARROW@[38; 40)
28 WHITESPACE@[40; 41)
29 TUPLE_EXPR@[41; 43)
30 L_PAREN@[41; 42)
31 R_PAREN@[42; 43)
32 COMMA@[43; 44)
33 WHITESPACE@[44; 53)
34 MATCH_ARM@[53; 62)
35 LITERAL@[53; 56)
36 CHAR@[53; 56)
37 WHITESPACE@[56; 57)
38 FAT_ARROW@[57; 59)
39 WHITESPACE@[59; 60)
40 TUPLE_EXPR@[60; 62)
41 L_PAREN@[60; 61)
42 R_PAREN@[61; 62)
43 COMMA@[62; 63)
44 WHITESPACE@[63; 72)
45 MATCH_ARM@[72; 85)
46 LITERAL@[72; 79)
47 STRING@[72; 79)
48 WHITESPACE@[79; 80)
49 FAT_ARROW@[80; 82)
50 WHITESPACE@[82; 83)
51 TUPLE_EXPR@[83; 85)
52 L_PAREN@[83; 84)
53 R_PAREN@[84; 85)
54 COMMA@[85; 86)
55 WHITESPACE@[86; 91)
56 R_CURLY@[91; 92)
57 WHITESPACE@[92; 93)
58 R_CURLY@[93; 94)
59 WHITESPACE@[94; 95)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.rs b/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.rs
new file mode 100644
index 000000000..aef45e561
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.rs
@@ -0,0 +1 @@
type F = Box<Fn(x: i32) -> ()>;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt b/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt
new file mode 100644
index 000000000..800a4ac14
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt
@@ -0,0 +1,45 @@
1FILE@[0; 32)
2 TYPE_ITEM@[0; 31)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "F"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 PATH_TYPE@[9; 30)
11 PATH@[9; 30)
12 PATH_SEGMENT@[9; 30)
13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "Box"
15 TYPE_ARG_LIST@[12; 30)
16 L_ANGLE@[12; 13)
17 TYPE_ARG@[13; 29)
18 PATH_TYPE@[13; 29)
19 PATH@[13; 29)
20 PATH_SEGMENT@[13; 29)
21 NAME_REF@[13; 15)
22 IDENT@[13; 15) "Fn"
23 PARAM_LIST@[15; 23)
24 L_PAREN@[15; 16)
25 PARAM@[16; 22)
26 BIND_PAT@[16; 17)
27 NAME@[16; 17)
28 IDENT@[16; 17) "x"
29 COLON@[17; 18)
30 WHITESPACE@[18; 19)
31 PATH_TYPE@[19; 22)
32 PATH@[19; 22)
33 PATH_SEGMENT@[19; 22)
34 NAME_REF@[19; 22)
35 IDENT@[19; 22) "i32"
36 R_PAREN@[22; 23)
37 WHITESPACE@[23; 24)
38 THIN_ARROW@[24; 26)
39 WHITESPACE@[26; 27)
40 TUPLE_TYPE@[27; 29)
41 L_PAREN@[27; 28)
42 R_PAREN@[28; 29)
43 R_ANGLE@[29; 30)
44 SEMI@[30; 31)
45 WHITESPACE@[31; 32)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0094_range_pat.rs b/crates/libsyntax2/tests/data/parser/inline/0094_range_pat.rs
new file mode 100644
index 000000000..657467e75
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0094_range_pat.rs
@@ -0,0 +1,3 @@
1fn main() {
2 match 92 { 0 ... 100 => () }
3}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0094_range_pat.txt b/crates/libsyntax2/tests/data/parser/inline/0094_range_pat.txt
new file mode 100644
index 000000000..cb858044a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0094_range_pat.txt
@@ -0,0 +1,41 @@
1FILE@[0; 47)
2 FUNCTION@[0; 46)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 46)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 MATCH_EXPR@[16; 44)
15 MATCH_KW@[16; 21)
16 WHITESPACE@[21; 22)
17 LITERAL@[22; 24)
18 INT_NUMBER@[22; 24) "92"
19 WHITESPACE@[24; 25)
20 L_CURLY@[25; 26)
21 WHITESPACE@[26; 27)
22 MATCH_ARM@[27; 42)
23 RANGE_PAT@[27; 36)
24 LITERAL@[27; 28)
25 INT_NUMBER@[27; 28) "0"
26 WHITESPACE@[28; 29)
27 DOTDOTDOT@[29; 32)
28 WHITESPACE@[32; 33)
29 LITERAL@[33; 36)
30 INT_NUMBER@[33; 36) "100"
31 WHITESPACE@[36; 37)
32 FAT_ARROW@[37; 39)
33 WHITESPACE@[39; 40)
34 TUPLE_EXPR@[40; 42)
35 L_PAREN@[40; 41)
36 R_PAREN@[41; 42)
37 WHITESPACE@[42; 43)
38 R_CURLY@[43; 44)
39 WHITESPACE@[44; 45)
40 R_CURLY@[45; 46)
41 WHITESPACE@[46; 47)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.rs b/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.rs
new file mode 100644
index 000000000..215210e27
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.rs
@@ -0,0 +1 @@
fn foo() -> Box<T + 'f> {}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt b/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt
new file mode 100644
index 000000000..57c38e7ee
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt
@@ -0,0 +1,35 @@
1FILE@[0; 27)
2 FUNCTION@[0; 26)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 THIN_ARROW@[9; 11)
12 WHITESPACE@[11; 12)
13 PATH_TYPE@[12; 23)
14 PATH@[12; 23)
15 PATH_SEGMENT@[12; 23)
16 NAME_REF@[12; 15)
17 IDENT@[12; 15) "Box"
18 TYPE_ARG_LIST@[15; 23)
19 L_ANGLE@[15; 16)
20 TYPE_ARG@[16; 22)
21 PATH_TYPE@[16; 22)
22 PATH@[16; 17)
23 PATH_SEGMENT@[16; 17)
24 NAME_REF@[16; 17)
25 IDENT@[16; 17) "T"
26 WHITESPACE@[17; 18)
27 PLUS@[18; 19)
28 WHITESPACE@[19; 20)
29 LIFETIME@[20; 22) "'f"
30 R_ANGLE@[22; 23)
31 WHITESPACE@[23; 24)
32 BLOCK_EXPR@[24; 26)
33 L_CURLY@[24; 25)
34 R_CURLY@[25; 26)
35 WHITESPACE@[26; 27)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.rs b/crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.rs
new file mode 100644
index 000000000..d8c23c76a
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.rs
@@ -0,0 +1 @@
type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>;
diff --git a/crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.txt b/crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.txt
new file mode 100644
index 000000000..c3f9bf685
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0096_value_parameters_no_patterns.txt
@@ -0,0 +1,81 @@
1FILE@[0; 54)
2 TYPE_ITEM@[0; 53)
3 TYPE_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 6)
6 IDENT@[5; 6) "F"
7 WHITESPACE@[6; 7)
8 EQ@[7; 8)
9 WHITESPACE@[8; 9)
10 PATH_TYPE@[9; 52)
11 PATH@[9; 52)
12 PATH_SEGMENT@[9; 52)
13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "Box"
15 TYPE_ARG_LIST@[12; 52)
16 L_ANGLE@[12; 13)
17 TYPE_ARG@[13; 51)
18 PATH_TYPE@[13; 51)
19 PATH@[13; 51)
20 PATH_SEGMENT@[13; 51)
21 NAME_REF@[13; 15)
22 IDENT@[13; 15) "Fn"
23 PARAM_LIST@[15; 51)
24 L_PAREN@[15; 16)
25 PARAM@[16; 22)
26 BIND_PAT@[16; 17)
27 NAME@[16; 17)
28 IDENT@[16; 17) "a"
29 COLON@[17; 18)
30 WHITESPACE@[18; 19)
31 PATH_TYPE@[19; 22)
32 PATH@[19; 22)
33 PATH_SEGMENT@[19; 22)
34 NAME_REF@[19; 22)
35 IDENT@[19; 22) "i32"
36 COMMA@[22; 23)
37 WHITESPACE@[23; 24)
38 PARAM@[24; 32)
39 REF_PAT@[24; 26)
40 AMP@[24; 25)
41 BIND_PAT@[25; 26)
42 NAME@[25; 26)
43 IDENT@[25; 26) "b"
44 COLON@[26; 27)
45 WHITESPACE@[27; 28)
46 REFERENCE_TYPE@[28; 32)
47 AMP@[28; 29)
48 PATH_TYPE@[29; 32)
49 PATH@[29; 32)
50 PATH_SEGMENT@[29; 32)
51 NAME_REF@[29; 32)
52 IDENT@[29; 32) "i32"
53 COMMA@[32; 33)
54 WHITESPACE@[33; 34)
55 PARAM@[34; 46)
56 REF_PAT@[34; 40)
57 AMP@[34; 35)
58 MUT_KW@[35; 38)
59 WHITESPACE@[38; 39)
60 BIND_PAT@[39; 40)
61 NAME@[39; 40)
62 IDENT@[39; 40) "c"
63 COLON@[40; 41)
64 WHITESPACE@[41; 42)
65 REFERENCE_TYPE@[42; 46)
66 AMP@[42; 43)
67 PATH_TYPE@[43; 46)
68 PATH@[43; 46)
69 PATH_SEGMENT@[43; 46)
70 NAME_REF@[43; 46)
71 IDENT@[43; 46) "i32"
72 COMMA@[46; 47)
73 WHITESPACE@[47; 48)
74 PARAM@[48; 50)
75 TUPLE_TYPE@[48; 50)
76 L_PAREN@[48; 49)
77 R_PAREN@[49; 50)
78 R_PAREN@[50; 51)
79 R_ANGLE@[51; 52)
80 SEMI@[52; 53)
81 WHITESPACE@[53; 54)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.rs b/crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.rs
new file mode 100644
index 000000000..9b93442c0
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.rs
@@ -0,0 +1 @@
fn foo<F: FnMut(&mut Foo<'a>)>(){}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.txt b/crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.txt
new file mode 100644
index 000000000..4cb3bdac5
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0097_param_list_opt_patterns.txt
@@ -0,0 +1,43 @@
1FILE@[0; 35)
2 FUNCTION@[0; 34)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 TYPE_PARAM_LIST@[6; 30)
8 L_ANGLE@[6; 7)
9 TYPE_PARAM@[7; 29)
10 NAME@[7; 8)
11 IDENT@[7; 8) "F"
12 COLON@[8; 9)
13 WHITESPACE@[9; 10)
14 PATH@[10; 29)
15 PATH_SEGMENT@[10; 29)
16 NAME_REF@[10; 15)
17 IDENT@[10; 15) "FnMut"
18 PARAM_LIST@[15; 29)
19 L_PAREN@[15; 16)
20 PARAM@[16; 28)
21 REFERENCE_TYPE@[16; 28)
22 AMP@[16; 17)
23 MUT_KW@[17; 20)
24 WHITESPACE@[20; 21)
25 PATH_TYPE@[21; 28)
26 PATH@[21; 28)
27 PATH_SEGMENT@[21; 28)
28 NAME_REF@[21; 24)
29 IDENT@[21; 24) "Foo"
30 TYPE_ARG_LIST@[24; 28)
31 L_ANGLE@[24; 25)
32 LIFETIME_ARG@[25; 27)
33 LIFETIME@[25; 27) "'a"
34 R_ANGLE@[27; 28)
35 R_PAREN@[28; 29)
36 R_ANGLE@[29; 30)
37 PARAM_LIST@[30; 32)
38 L_PAREN@[30; 31)
39 R_PAREN@[31; 32)
40 BLOCK_EXPR@[32; 34)
41 L_CURLY@[32; 33)
42 R_CURLY@[33; 34)
43 WHITESPACE@[34; 35)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0098_where_clause.rs b/crates/libsyntax2/tests/data/parser/inline/0098_where_clause.rs
new file mode 100644
index 000000000..592a005f9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0098_where_clause.rs
@@ -0,0 +1,6 @@
1fn foo()
2where
3 'a: 'b + 'c,
4 T: Clone + Copy + 'static,
5 Iterator::Item: 'a,
6{}
diff --git a/crates/libsyntax2/tests/data/parser/inline/0098_where_clause.txt b/crates/libsyntax2/tests/data/parser/inline/0098_where_clause.txt
new file mode 100644
index 000000000..150f125a7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0098_where_clause.txt
@@ -0,0 +1,69 @@
1FILE@[0; 87)
2 FUNCTION@[0; 86)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 WHERE_CLAUSE@[9; 83)
12 WHERE_KW@[9; 14)
13 WHITESPACE@[14; 18)
14 WHERE_PRED@[18; 29)
15 LIFETIME@[18; 20) "'a"
16 COLON@[20; 21)
17 WHITESPACE@[21; 22)
18 LIFETIME@[22; 24) "'b"
19 WHITESPACE@[24; 25)
20 PLUS@[25; 26)
21 WHITESPACE@[26; 27)
22 LIFETIME@[27; 29) "'c"
23 COMMA@[29; 30)
24 WHITESPACE@[30; 34)
25 WHERE_PRED@[34; 59)
26 PATH_TYPE@[34; 35)
27 PATH@[34; 35)
28 PATH_SEGMENT@[34; 35)
29 NAME_REF@[34; 35)
30 IDENT@[34; 35) "T"
31 COLON@[35; 36)
32 WHITESPACE@[36; 37)
33 PATH@[37; 42)
34 PATH_SEGMENT@[37; 42)
35 NAME_REF@[37; 42)
36 IDENT@[37; 42) "Clone"
37 WHITESPACE@[42; 43)
38 PLUS@[43; 44)
39 WHITESPACE@[44; 45)
40 PATH@[45; 49)
41 PATH_SEGMENT@[45; 49)
42 NAME_REF@[45; 49)
43 IDENT@[45; 49) "Copy"
44 WHITESPACE@[49; 50)
45 PLUS@[50; 51)
46 WHITESPACE@[51; 52)
47 LIFETIME@[52; 59) "'static"
48 COMMA@[59; 60)
49 WHITESPACE@[60; 64)
50 WHERE_PRED@[64; 82)
51 PATH_TYPE@[64; 78)
52 PATH@[64; 78)
53 PATH@[64; 72)
54 PATH_SEGMENT@[64; 72)
55 NAME_REF@[64; 72)
56 IDENT@[64; 72) "Iterator"
57 COLONCOLON@[72; 74)
58 PATH_SEGMENT@[74; 78)
59 NAME_REF@[74; 78)
60 IDENT@[74; 78) "Item"
61 COLON@[78; 79)
62 WHITESPACE@[79; 80)
63 LIFETIME@[80; 82) "'a"
64 COMMA@[82; 83)
65 WHITESPACE@[83; 84)
66 BLOCK_EXPR@[84; 86)
67 L_CURLY@[84; 85)
68 R_CURLY@[85; 86)
69 WHITESPACE@[86; 87)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.rs b/crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.rs
new file mode 100644
index 000000000..660d927cf
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.rs
@@ -0,0 +1 @@
crate fn main() { }
diff --git a/crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.txt b/crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.txt
new file mode 100644
index 000000000..a830d99d9
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/inline/0099_crate_keyword_vis.txt
@@ -0,0 +1,18 @@
1FILE@[0; 20)
2 FUNCTION@[0; 19)
3 VISIBILITY@[0; 5)
4 CRATE_KW@[0; 5)
5 WHITESPACE@[5; 6)
6 FN_KW@[6; 8)
7 WHITESPACE@[8; 9)
8 NAME@[9; 13)
9 IDENT@[9; 13) "main"
10 PARAM_LIST@[13; 15)
11 L_PAREN@[13; 14)
12 R_PAREN@[14; 15)
13 WHITESPACE@[15; 16)
14 BLOCK_EXPR@[16; 19)
15 L_CURLY@[16; 17)
16 WHITESPACE@[17; 18)
17 R_CURLY@[18; 19)
18 WHITESPACE@[19; 20)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0000_empty.rs b/crates/libsyntax2/tests/data/parser/ok/0000_empty.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0000_empty.rs
diff --git a/crates/libsyntax2/tests/data/parser/ok/0000_empty.txt b/crates/libsyntax2/tests/data/parser/ok/0000_empty.txt
new file mode 100644
index 000000000..54be3e7bc
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0000_empty.txt
@@ -0,0 +1 @@
FILE@[0; 0)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0001_struct_item.rs b/crates/libsyntax2/tests/data/parser/ok/0001_struct_item.rs
new file mode 100644
index 000000000..d3a8c1d23
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0001_struct_item.rs
@@ -0,0 +1,3 @@
1struct S {
2
3} \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/ok/0001_struct_item.txt b/crates/libsyntax2/tests/data/parser/ok/0001_struct_item.txt
new file mode 100644
index 000000000..3d5b5cb7f
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0001_struct_item.txt
@@ -0,0 +1,10 @@
1FILE@[0; 13)
2 STRUCT_ITEM@[0; 13)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 WHITESPACE@[8; 9)
8 L_CURLY@[9; 10)
9 WHITESPACE@[10; 12)
10 R_CURLY@[12; 13)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.rs b/crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.rs
new file mode 100644
index 000000000..cc3866d25
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.rs
@@ -0,0 +1,3 @@
1struct S {
2 foo: u32
3} \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.txt b/crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.txt
new file mode 100644
index 000000000..1129ce39e
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0002_struct_item_field.txt
@@ -0,0 +1,21 @@
1FILE@[0; 25)
2 STRUCT_ITEM@[0; 25)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 WHITESPACE@[8; 9)
8 L_CURLY@[9; 10)
9 WHITESPACE@[10; 15)
10 NAMED_FIELD@[15; 23)
11 NAME@[15; 18)
12 IDENT@[15; 18) "foo"
13 COLON@[18; 19)
14 WHITESPACE@[19; 20)
15 PATH_TYPE@[20; 23)
16 PATH@[20; 23)
17 PATH_SEGMENT@[20; 23)
18 NAME_REF@[20; 23)
19 IDENT@[20; 23) "u32"
20 WHITESPACE@[23; 24)
21 R_CURLY@[24; 25)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.rs b/crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.rs
new file mode 100644
index 000000000..53dc9e617
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.rs
@@ -0,0 +1 @@
#!/use/bin/env rusti \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.txt b/crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.txt
new file mode 100644
index 000000000..33055cf3d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0004_file_shebang.txt
@@ -0,0 +1,2 @@
1FILE@[0; 20)
2 SHEBANG@[0; 20)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0005_fn_item.rs b/crates/libsyntax2/tests/data/parser/ok/0005_fn_item.rs
new file mode 100644
index 000000000..03210551c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0005_fn_item.rs
@@ -0,0 +1,2 @@
1fn foo() {
2}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0005_fn_item.txt b/crates/libsyntax2/tests/data/parser/ok/0005_fn_item.txt
new file mode 100644
index 000000000..4ab93d408
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0005_fn_item.txt
@@ -0,0 +1,15 @@
1FILE@[0; 13)
2 FUNCTION@[0; 12)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 12)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 11)
14 R_CURLY@[11; 12)
15 WHITESPACE@[12; 13)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.rs b/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.rs
new file mode 100644
index 000000000..e81f8b1e8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.rs
@@ -0,0 +1,10 @@
1#![attr]
2#![attr(true)]
3#![attr(ident)]
4#![attr(ident, 100, true, "true", ident = 100, ident = "hello", ident(100))]
5#![attr(100)]
6#![attr(enabled = true)]
7#![enabled(true)]
8#![attr("hello")]
9#![repr(C, align = 4)]
10#![repr(C, align(4))] \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt b/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt
new file mode 100644
index 000000000..562c8d917
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt
@@ -0,0 +1,176 @@
1FILE@[0; 236)
2 ATTR@[0; 8)
3 POUND@[0; 1)
4 EXCL@[1; 2)
5 L_BRACK@[2; 3)
6 META_ITEM@[3; 7)
7 IDENT@[3; 7) "attr"
8 R_BRACK@[7; 8)
9 WHITESPACE@[8; 9)
10 ATTR@[9; 23)
11 POUND@[9; 10)
12 EXCL@[10; 11)
13 L_BRACK@[11; 12)
14 META_ITEM@[12; 22)
15 IDENT@[12; 16) "attr"
16 L_PAREN@[16; 17)
17 LITERAL@[17; 21)
18 TRUE_KW@[17; 21)
19 R_PAREN@[21; 22)
20 R_BRACK@[22; 23)
21 WHITESPACE@[23; 24)
22 ATTR@[24; 39)
23 POUND@[24; 25)
24 EXCL@[25; 26)
25 L_BRACK@[26; 27)
26 META_ITEM@[27; 38)
27 IDENT@[27; 31) "attr"
28 L_PAREN@[31; 32)
29 META_ITEM@[32; 37)
30 IDENT@[32; 37) "ident"
31 R_PAREN@[37; 38)
32 R_BRACK@[38; 39)
33 WHITESPACE@[39; 40)
34 ATTR@[40; 116)
35 POUND@[40; 41)
36 EXCL@[41; 42)
37 L_BRACK@[42; 43)
38 META_ITEM@[43; 115)
39 IDENT@[43; 47) "attr"
40 L_PAREN@[47; 48)
41 META_ITEM@[48; 53)
42 IDENT@[48; 53) "ident"
43 COMMA@[53; 54)
44 WHITESPACE@[54; 55)
45 LITERAL@[55; 58)
46 INT_NUMBER@[55; 58) "100"
47 COMMA@[58; 59)
48 WHITESPACE@[59; 60)
49 LITERAL@[60; 64)
50 TRUE_KW@[60; 64)
51 COMMA@[64; 65)
52 WHITESPACE@[65; 66)
53 LITERAL@[66; 72)
54 STRING@[66; 72)
55 COMMA@[72; 73)
56 WHITESPACE@[73; 74)
57 META_ITEM@[74; 85)
58 IDENT@[74; 79) "ident"
59 WHITESPACE@[79; 80)
60 EQ@[80; 81)
61 WHITESPACE@[81; 82)
62 LITERAL@[82; 85)
63 INT_NUMBER@[82; 85) "100"
64 COMMA@[85; 86)
65 WHITESPACE@[86; 87)
66 META_ITEM@[87; 102)
67 IDENT@[87; 92) "ident"
68 WHITESPACE@[92; 93)
69 EQ@[93; 94)
70 WHITESPACE@[94; 95)
71 LITERAL@[95; 102)
72 STRING@[95; 102)
73 COMMA@[102; 103)
74 WHITESPACE@[103; 104)
75 META_ITEM@[104; 114)
76 IDENT@[104; 109) "ident"
77 L_PAREN@[109; 110)
78 LITERAL@[110; 113)
79 INT_NUMBER@[110; 113) "100"
80 R_PAREN@[113; 114)
81 R_PAREN@[114; 115)
82 R_BRACK@[115; 116)
83 WHITESPACE@[116; 117)
84 ATTR@[117; 130)
85 POUND@[117; 118)
86 EXCL@[118; 119)
87 L_BRACK@[119; 120)
88 META_ITEM@[120; 129)
89 IDENT@[120; 124) "attr"
90 L_PAREN@[124; 125)
91 LITERAL@[125; 128)
92 INT_NUMBER@[125; 128) "100"
93 R_PAREN@[128; 129)
94 R_BRACK@[129; 130)
95 WHITESPACE@[130; 131)
96 ATTR@[131; 155)
97 POUND@[131; 132)
98 EXCL@[132; 133)
99 L_BRACK@[133; 134)
100 META_ITEM@[134; 154)
101 IDENT@[134; 138) "attr"
102 L_PAREN@[138; 139)
103 META_ITEM@[139; 153)
104 IDENT@[139; 146) "enabled"
105 WHITESPACE@[146; 147)
106 EQ@[147; 148)
107 WHITESPACE@[148; 149)
108 LITERAL@[149; 153)
109 TRUE_KW@[149; 153)
110 R_PAREN@[153; 154)
111 R_BRACK@[154; 155)
112 WHITESPACE@[155; 156)
113 ATTR@[156; 173)
114 POUND@[156; 157)
115 EXCL@[157; 158)
116 L_BRACK@[158; 159)
117 META_ITEM@[159; 172)
118 IDENT@[159; 166) "enabled"
119 L_PAREN@[166; 167)
120 LITERAL@[167; 171)
121 TRUE_KW@[167; 171)
122 R_PAREN@[171; 172)
123 R_BRACK@[172; 173)
124 WHITESPACE@[173; 174)
125 ATTR@[174; 191)
126 POUND@[174; 175)
127 EXCL@[175; 176)
128 L_BRACK@[176; 177)
129 META_ITEM@[177; 190)
130 IDENT@[177; 181) "attr"
131 L_PAREN@[181; 182)
132 LITERAL@[182; 189)
133 STRING@[182; 189)
134 R_PAREN@[189; 190)
135 R_BRACK@[190; 191)
136 WHITESPACE@[191; 192)
137 ATTR@[192; 214)
138 POUND@[192; 193)
139 EXCL@[193; 194)
140 L_BRACK@[194; 195)
141 META_ITEM@[195; 213)
142 IDENT@[195; 199) "repr"
143 L_PAREN@[199; 200)
144 META_ITEM@[200; 201)
145 IDENT@[200; 201) "C"
146 COMMA@[201; 202)
147 WHITESPACE@[202; 203)
148 META_ITEM@[203; 212)
149 IDENT@[203; 208) "align"
150 WHITESPACE@[208; 209)
151 EQ@[209; 210)
152 WHITESPACE@[210; 211)
153 LITERAL@[211; 212)
154 INT_NUMBER@[211; 212) "4"
155 R_PAREN@[212; 213)
156 R_BRACK@[213; 214)
157 WHITESPACE@[214; 215)
158 ATTR@[215; 236)
159 POUND@[215; 216)
160 EXCL@[216; 217)
161 L_BRACK@[217; 218)
162 META_ITEM@[218; 235)
163 IDENT@[218; 222) "repr"
164 L_PAREN@[222; 223)
165 META_ITEM@[223; 224)
166 IDENT@[223; 224) "C"
167 COMMA@[224; 225)
168 WHITESPACE@[225; 226)
169 META_ITEM@[226; 234)
170 IDENT@[226; 231) "align"
171 L_PAREN@[231; 232)
172 LITERAL@[232; 233)
173 INT_NUMBER@[232; 233) "4"
174 R_PAREN@[233; 234)
175 R_PAREN@[234; 235)
176 R_BRACK@[235; 236)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.rs b/crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.rs
new file mode 100644
index 000000000..3ce336676
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.rs
@@ -0,0 +1,2 @@
1extern crate foo;
2extern crate foo as bar;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.txt b/crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.txt
new file mode 100644
index 000000000..533af33c4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0007_extern_crate.txt
@@ -0,0 +1,25 @@
1FILE@[0; 43)
2 EXTERN_CRATE_ITEM@[0; 17)
3 EXTERN_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 CRATE_KW@[7; 12)
6 WHITESPACE@[12; 13)
7 NAME@[13; 16)
8 IDENT@[13; 16) "foo"
9 SEMI@[16; 17)
10 WHITESPACE@[17; 18)
11 EXTERN_CRATE_ITEM@[18; 42)
12 EXTERN_KW@[18; 24)
13 WHITESPACE@[24; 25)
14 CRATE_KW@[25; 30)
15 WHITESPACE@[30; 31)
16 NAME@[31; 34)
17 IDENT@[31; 34) "foo"
18 WHITESPACE@[34; 35)
19 ALIAS@[35; 41)
20 AS_KW@[35; 37)
21 WHITESPACE@[37; 38)
22 NAME@[38; 41)
23 IDENT@[38; 41) "bar"
24 SEMI@[41; 42)
25 WHITESPACE@[42; 43)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.rs b/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.rs
new file mode 100644
index 000000000..d22993bc1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.rs
@@ -0,0 +1,17 @@
1mod a;
2
3mod b {
4}
5
6mod c {
7 fn foo() {
8 }
9 struct S {}
10}
11
12mod d {
13 #![attr]
14 mod e;
15 mod f {
16 }
17} \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt b/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt
new file mode 100644
index 000000000..1dcaaedce
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt
@@ -0,0 +1,85 @@
1FILE@[0; 118)
2 MOD_ITEM@[0; 6)
3 MOD_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 NAME@[4; 5)
6 IDENT@[4; 5) "a"
7 SEMI@[5; 6)
8 WHITESPACE@[6; 8)
9 MOD_ITEM@[8; 17)
10 MOD_KW@[8; 11)
11 WHITESPACE@[11; 12)
12 NAME@[12; 13)
13 IDENT@[12; 13) "b"
14 WHITESPACE@[13; 14)
15 L_CURLY@[14; 15)
16 WHITESPACE@[15; 16)
17 R_CURLY@[16; 17)
18 WHITESPACE@[17; 19)
19 MOD_ITEM@[19; 65)
20 MOD_KW@[19; 22)
21 WHITESPACE@[22; 23)
22 NAME@[23; 24)
23 IDENT@[23; 24) "c"
24 WHITESPACE@[24; 25)
25 L_CURLY@[25; 26)
26 WHITESPACE@[26; 31)
27 FUNCTION@[31; 47)
28 FN_KW@[31; 33)
29 WHITESPACE@[33; 34)
30 NAME@[34; 37)
31 IDENT@[34; 37) "foo"
32 PARAM_LIST@[37; 39)
33 L_PAREN@[37; 38)
34 R_PAREN@[38; 39)
35 WHITESPACE@[39; 40)
36 BLOCK_EXPR@[40; 47)
37 L_CURLY@[40; 41)
38 WHITESPACE@[41; 46)
39 R_CURLY@[46; 47)
40 WHITESPACE@[47; 52)
41 STRUCT_ITEM@[52; 63)
42 STRUCT_KW@[52; 58)
43 WHITESPACE@[58; 59)
44 NAME@[59; 60)
45 IDENT@[59; 60) "S"
46 WHITESPACE@[60; 61)
47 L_CURLY@[61; 62)
48 R_CURLY@[62; 63)
49 WHITESPACE@[63; 64)
50 R_CURLY@[64; 65)
51 WHITESPACE@[65; 67)
52 MOD_ITEM@[67; 118)
53 MOD_KW@[67; 70)
54 WHITESPACE@[70; 71)
55 NAME@[71; 72)
56 IDENT@[71; 72) "d"
57 WHITESPACE@[72; 73)
58 L_CURLY@[73; 74)
59 WHITESPACE@[74; 79)
60 ATTR@[79; 87)
61 POUND@[79; 80)
62 EXCL@[80; 81)
63 L_BRACK@[81; 82)
64 META_ITEM@[82; 86)
65 IDENT@[82; 86) "attr"
66 R_BRACK@[86; 87)
67 WHITESPACE@[87; 92)
68 MOD_ITEM@[92; 98)
69 MOD_KW@[92; 95)
70 WHITESPACE@[95; 96)
71 NAME@[96; 97)
72 IDENT@[96; 97) "e"
73 SEMI@[97; 98)
74 WHITESPACE@[98; 103)
75 MOD_ITEM@[103; 116)
76 MOD_KW@[103; 106)
77 WHITESPACE@[106; 107)
78 NAME@[107; 108)
79 IDENT@[107; 108) "f"
80 WHITESPACE@[108; 109)
81 L_CURLY@[109; 110)
82 WHITESPACE@[110; 115)
83 R_CURLY@[115; 116)
84 WHITESPACE@[116; 117)
85 R_CURLY@[117; 118)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0009_use_item.rs b/crates/libsyntax2/tests/data/parser/ok/0009_use_item.rs
new file mode 100644
index 000000000..05a6aff83
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0009_use_item.rs
@@ -0,0 +1,2 @@
1use foo;
2use ::bar; \ No newline at end of file
diff --git a/crates/libsyntax2/tests/data/parser/ok/0009_use_item.txt b/crates/libsyntax2/tests/data/parser/ok/0009_use_item.txt
new file mode 100644
index 000000000..8f850cd1c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0009_use_item.txt
@@ -0,0 +1,21 @@
1FILE@[0; 19)
2 USE_ITEM@[0; 8)
3 USE_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 USE_TREE@[4; 7)
6 PATH@[4; 7)
7 PATH_SEGMENT@[4; 7)
8 NAME_REF@[4; 7)
9 IDENT@[4; 7) "foo"
10 SEMI@[7; 8)
11 WHITESPACE@[8; 9)
12 USE_ITEM@[9; 19)
13 USE_KW@[9; 12)
14 WHITESPACE@[12; 13)
15 USE_TREE@[13; 18)
16 PATH@[13; 18)
17 PATH_SEGMENT@[13; 18)
18 COLONCOLON@[13; 15)
19 NAME_REF@[15; 18)
20 IDENT@[15; 18) "bar"
21 SEMI@[18; 19)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.rs b/crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.rs
new file mode 100644
index 000000000..1e71b7a6c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.rs
@@ -0,0 +1,2 @@
1use ::foo::bar::baz;
2use foo::bar::baz;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.txt b/crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.txt
new file mode 100644
index 000000000..03ec342c2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0010_use_path_segments.txt
@@ -0,0 +1,42 @@
1FILE@[0; 40)
2 USE_ITEM@[0; 20)
3 USE_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 USE_TREE@[4; 19)
6 PATH@[4; 19)
7 PATH@[4; 14)
8 PATH@[4; 9)
9 PATH_SEGMENT@[4; 9)
10 COLONCOLON@[4; 6)
11 NAME_REF@[6; 9)
12 IDENT@[6; 9) "foo"
13 COLONCOLON@[9; 11)
14 PATH_SEGMENT@[11; 14)
15 NAME_REF@[11; 14)
16 IDENT@[11; 14) "bar"
17 COLONCOLON@[14; 16)
18 PATH_SEGMENT@[16; 19)
19 NAME_REF@[16; 19)
20 IDENT@[16; 19) "baz"
21 SEMI@[19; 20)
22 WHITESPACE@[20; 21)
23 USE_ITEM@[21; 39)
24 USE_KW@[21; 24)
25 WHITESPACE@[24; 25)
26 USE_TREE@[25; 38)
27 PATH@[25; 38)
28 PATH@[25; 33)
29 PATH@[25; 28)
30 PATH_SEGMENT@[25; 28)
31 NAME_REF@[25; 28)
32 IDENT@[25; 28) "foo"
33 COLONCOLON@[28; 30)
34 PATH_SEGMENT@[30; 33)
35 NAME_REF@[30; 33)
36 IDENT@[30; 33) "bar"
37 COLONCOLON@[33; 35)
38 PATH_SEGMENT@[35; 38)
39 NAME_REF@[35; 38)
40 IDENT@[35; 38) "baz"
41 SEMI@[38; 39)
42 WHITESPACE@[39; 40)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.rs b/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.rs
new file mode 100644
index 000000000..8b80c0d90
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.rs
@@ -0,0 +1,3 @@
1#[cfg(test)]
2#[ignore]
3fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt b/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt
new file mode 100644
index 000000000..9824c9083
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt
@@ -0,0 +1,32 @@
1FILE@[0; 35)
2 FUNCTION@[0; 34)
3 ATTR@[0; 12)
4 POUND@[0; 1)
5 L_BRACK@[1; 2)
6 META_ITEM@[2; 11)
7 IDENT@[2; 5) "cfg"
8 L_PAREN@[5; 6)
9 META_ITEM@[6; 10)
10 IDENT@[6; 10) "test"
11 R_PAREN@[10; 11)
12 R_BRACK@[11; 12)
13 WHITESPACE@[12; 13)
14 ATTR@[13; 22)
15 POUND@[13; 14)
16 L_BRACK@[14; 15)
17 META_ITEM@[15; 21)
18 IDENT@[15; 21) "ignore"
19 R_BRACK@[21; 22)
20 WHITESPACE@[22; 23)
21 FN_KW@[23; 25)
22 WHITESPACE@[25; 26)
23 NAME@[26; 29)
24 IDENT@[26; 29) "foo"
25 PARAM_LIST@[29; 31)
26 L_PAREN@[29; 30)
27 R_PAREN@[30; 31)
28 WHITESPACE@[31; 32)
29 BLOCK_EXPR@[32; 34)
30 L_CURLY@[32; 33)
31 R_CURLY@[33; 34)
32 WHITESPACE@[34; 35)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0012_visibility.rs b/crates/libsyntax2/tests/data/parser/ok/0012_visibility.rs
new file mode 100644
index 000000000..75b1db121
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0012_visibility.rs
@@ -0,0 +1,5 @@
1fn a() {}
2pub fn b() {}
3pub(crate) fn c() {}
4pub(super) fn d() {}
5pub(in foo::bar::baz) fn e() {}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0012_visibility.txt b/crates/libsyntax2/tests/data/parser/ok/0012_visibility.txt
new file mode 100644
index 000000000..af0c59543
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0012_visibility.txt
@@ -0,0 +1,102 @@
1FILE@[0; 98)
2 FUNCTION@[0; 9)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 4)
6 IDENT@[3; 4) "a"
7 PARAM_LIST@[4; 6)
8 L_PAREN@[4; 5)
9 R_PAREN@[5; 6)
10 WHITESPACE@[6; 7)
11 BLOCK_EXPR@[7; 9)
12 L_CURLY@[7; 8)
13 R_CURLY@[8; 9)
14 WHITESPACE@[9; 10)
15 FUNCTION@[10; 23)
16 VISIBILITY@[10; 13)
17 PUB_KW@[10; 13)
18 WHITESPACE@[13; 14)
19 FN_KW@[14; 16)
20 WHITESPACE@[16; 17)
21 NAME@[17; 18)
22 IDENT@[17; 18) "b"
23 PARAM_LIST@[18; 20)
24 L_PAREN@[18; 19)
25 R_PAREN@[19; 20)
26 WHITESPACE@[20; 21)
27 BLOCK_EXPR@[21; 23)
28 L_CURLY@[21; 22)
29 R_CURLY@[22; 23)
30 WHITESPACE@[23; 24)
31 FUNCTION@[24; 44)
32 VISIBILITY@[24; 34)
33 PUB_KW@[24; 27)
34 L_PAREN@[27; 28)
35 CRATE_KW@[28; 33)
36 R_PAREN@[33; 34)
37 WHITESPACE@[34; 35)
38 FN_KW@[35; 37)
39 WHITESPACE@[37; 38)
40 NAME@[38; 39)
41 IDENT@[38; 39) "c"
42 PARAM_LIST@[39; 41)
43 L_PAREN@[39; 40)
44 R_PAREN@[40; 41)
45 WHITESPACE@[41; 42)
46 BLOCK_EXPR@[42; 44)
47 L_CURLY@[42; 43)
48 R_CURLY@[43; 44)
49 WHITESPACE@[44; 45)
50 FUNCTION@[45; 65)
51 VISIBILITY@[45; 55)
52 PUB_KW@[45; 48)
53 L_PAREN@[48; 49)
54 SUPER_KW@[49; 54)
55 R_PAREN@[54; 55)
56 WHITESPACE@[55; 56)
57 FN_KW@[56; 58)
58 WHITESPACE@[58; 59)
59 NAME@[59; 60)
60 IDENT@[59; 60) "d"
61 PARAM_LIST@[60; 62)
62 L_PAREN@[60; 61)
63 R_PAREN@[61; 62)
64 WHITESPACE@[62; 63)
65 BLOCK_EXPR@[63; 65)
66 L_CURLY@[63; 64)
67 R_CURLY@[64; 65)
68 WHITESPACE@[65; 66)
69 FUNCTION@[66; 97)
70 VISIBILITY@[66; 87)
71 PUB_KW@[66; 69)
72 L_PAREN@[69; 70)
73 IN_KW@[70; 72)
74 WHITESPACE@[72; 73)
75 PATH@[73; 86)
76 PATH@[73; 81)
77 PATH@[73; 76)
78 PATH_SEGMENT@[73; 76)
79 NAME_REF@[73; 76)
80 IDENT@[73; 76) "foo"
81 COLONCOLON@[76; 78)
82 PATH_SEGMENT@[78; 81)
83 NAME_REF@[78; 81)
84 IDENT@[78; 81) "bar"
85 COLONCOLON@[81; 83)
86 PATH_SEGMENT@[83; 86)
87 NAME_REF@[83; 86)
88 IDENT@[83; 86) "baz"
89 R_PAREN@[86; 87)
90 WHITESPACE@[87; 88)
91 FN_KW@[88; 90)
92 WHITESPACE@[90; 91)
93 NAME@[91; 92)
94 IDENT@[91; 92) "e"
95 PARAM_LIST@[92; 94)
96 L_PAREN@[92; 93)
97 R_PAREN@[93; 94)
98 WHITESPACE@[94; 95)
99 BLOCK_EXPR@[95; 97)
100 L_CURLY@[95; 96)
101 R_CURLY@[96; 97)
102 WHITESPACE@[97; 98)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.rs b/crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.rs
new file mode 100644
index 000000000..faf6a42c7
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.rs
@@ -0,0 +1,3 @@
1use self::foo;
2use super::super::bar;
3use ::self::a::super::bar;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.txt b/crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.txt
new file mode 100644
index 000000000..5ed27ca37
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0013_use_path_self_super.txt
@@ -0,0 +1,57 @@
1FILE@[0; 65)
2 USE_ITEM@[0; 14)
3 USE_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 USE_TREE@[4; 13)
6 PATH@[4; 13)
7 PATH@[4; 8)
8 PATH_SEGMENT@[4; 8)
9 SELF_KW@[4; 8)
10 COLONCOLON@[8; 10)
11 PATH_SEGMENT@[10; 13)
12 NAME_REF@[10; 13)
13 IDENT@[10; 13) "foo"
14 SEMI@[13; 14)
15 WHITESPACE@[14; 15)
16 USE_ITEM@[15; 37)
17 USE_KW@[15; 18)
18 WHITESPACE@[18; 19)
19 USE_TREE@[19; 36)
20 PATH@[19; 36)
21 PATH@[19; 31)
22 PATH@[19; 24)
23 PATH_SEGMENT@[19; 24)
24 SUPER_KW@[19; 24)
25 COLONCOLON@[24; 26)
26 PATH_SEGMENT@[26; 31)
27 SUPER_KW@[26; 31)
28 COLONCOLON@[31; 33)
29 PATH_SEGMENT@[33; 36)
30 NAME_REF@[33; 36)
31 IDENT@[33; 36) "bar"
32 SEMI@[36; 37)
33 WHITESPACE@[37; 38)
34 USE_ITEM@[38; 64)
35 USE_KW@[38; 41)
36 WHITESPACE@[41; 42)
37 USE_TREE@[42; 63)
38 PATH@[42; 63)
39 PATH@[42; 58)
40 PATH@[42; 51)
41 PATH@[42; 48)
42 PATH_SEGMENT@[42; 48)
43 COLONCOLON@[42; 44)
44 SELF_KW@[44; 48)
45 COLONCOLON@[48; 50)
46 PATH_SEGMENT@[50; 51)
47 NAME_REF@[50; 51)
48 IDENT@[50; 51) "a"
49 COLONCOLON@[51; 53)
50 PATH_SEGMENT@[53; 58)
51 SUPER_KW@[53; 58)
52 COLONCOLON@[58; 60)
53 PATH_SEGMENT@[60; 63)
54 NAME_REF@[60; 63)
55 IDENT@[60; 63) "bar"
56 SEMI@[63; 64)
57 WHITESPACE@[64; 65)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0014_use_tree.rs b/crates/libsyntax2/tests/data/parser/ok/0014_use_tree.rs
new file mode 100644
index 000000000..5e4aa3a33
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0014_use_tree.rs
@@ -0,0 +1,7 @@
1use *;
2use ::*;
3use ::{};
4use {};
5use foo::*;
6use foo::{};
7use ::foo::{a, b, c};
diff --git a/crates/libsyntax2/tests/data/parser/ok/0014_use_tree.txt b/crates/libsyntax2/tests/data/parser/ok/0014_use_tree.txt
new file mode 100644
index 000000000..730d5539b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0014_use_tree.txt
@@ -0,0 +1,91 @@
1FILE@[0; 81)
2 USE_ITEM@[0; 6)
3 USE_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 USE_TREE@[4; 5)
6 STAR@[4; 5)
7 SEMI@[5; 6)
8 WHITESPACE@[6; 7)
9 USE_ITEM@[7; 15)
10 USE_KW@[7; 10)
11 WHITESPACE@[10; 11)
12 USE_TREE@[11; 14)
13 COLONCOLON@[11; 13)
14 STAR@[13; 14)
15 SEMI@[14; 15)
16 WHITESPACE@[15; 16)
17 USE_ITEM@[16; 25)
18 USE_KW@[16; 19)
19 WHITESPACE@[19; 20)
20 USE_TREE@[20; 24)
21 COLONCOLON@[20; 22)
22 L_CURLY@[22; 23)
23 R_CURLY@[23; 24)
24 SEMI@[24; 25)
25 WHITESPACE@[25; 26)
26 USE_ITEM@[26; 33)
27 USE_KW@[26; 29)
28 WHITESPACE@[29; 30)
29 USE_TREE@[30; 32)
30 L_CURLY@[30; 31)
31 R_CURLY@[31; 32)
32 SEMI@[32; 33)
33 WHITESPACE@[33; 34)
34 USE_ITEM@[34; 45)
35 USE_KW@[34; 37)
36 WHITESPACE@[37; 38)
37 USE_TREE@[38; 44)
38 PATH@[38; 41)
39 PATH_SEGMENT@[38; 41)
40 NAME_REF@[38; 41)
41 IDENT@[38; 41) "foo"
42 COLONCOLON@[41; 43)
43 STAR@[43; 44)
44 SEMI@[44; 45)
45 WHITESPACE@[45; 46)
46 USE_ITEM@[46; 58)
47 USE_KW@[46; 49)
48 WHITESPACE@[49; 50)
49 USE_TREE@[50; 57)
50 PATH@[50; 53)
51 PATH_SEGMENT@[50; 53)
52 NAME_REF@[50; 53)
53 IDENT@[50; 53) "foo"
54 COLONCOLON@[53; 55)
55 L_CURLY@[55; 56)
56 R_CURLY@[56; 57)
57 SEMI@[57; 58)
58 WHITESPACE@[58; 59)
59 USE_ITEM@[59; 80)
60 USE_KW@[59; 62)
61 WHITESPACE@[62; 63)
62 USE_TREE@[63; 79)
63 PATH@[63; 68)
64 PATH_SEGMENT@[63; 68)
65 COLONCOLON@[63; 65)
66 NAME_REF@[65; 68)
67 IDENT@[65; 68) "foo"
68 COLONCOLON@[68; 70)
69 L_CURLY@[70; 71)
70 USE_TREE@[71; 72)
71 PATH@[71; 72)
72 PATH_SEGMENT@[71; 72)
73 NAME_REF@[71; 72)
74 IDENT@[71; 72) "a"
75 COMMA@[72; 73)
76 WHITESPACE@[73; 74)
77 USE_TREE@[74; 75)
78 PATH@[74; 75)
79 PATH_SEGMENT@[74; 75)
80 NAME_REF@[74; 75)
81 IDENT@[74; 75) "b"
82 COMMA@[75; 76)
83 WHITESPACE@[76; 77)
84 USE_TREE@[77; 78)
85 PATH@[77; 78)
86 PATH_SEGMENT@[77; 78)
87 NAME_REF@[77; 78)
88 IDENT@[77; 78) "c"
89 R_CURLY@[78; 79)
90 SEMI@[79; 80)
91 WHITESPACE@[80; 81)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0015_use_tree.rs b/crates/libsyntax2/tests/data/parser/ok/0015_use_tree.rs
new file mode 100644
index 000000000..46a0783a2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0015_use_tree.rs
@@ -0,0 +1,2 @@
1use foo as bar;
2use foo::{a as b, *, ::*, ::foo as x};
diff --git a/crates/libsyntax2/tests/data/parser/ok/0015_use_tree.txt b/crates/libsyntax2/tests/data/parser/ok/0015_use_tree.txt
new file mode 100644
index 000000000..4438e417b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0015_use_tree.txt
@@ -0,0 +1,64 @@
1FILE@[0; 55)
2 USE_ITEM@[0; 15)
3 USE_KW@[0; 3)
4 WHITESPACE@[3; 4)
5 USE_TREE@[4; 14)
6 PATH@[4; 7)
7 PATH_SEGMENT@[4; 7)
8 NAME_REF@[4; 7)
9 IDENT@[4; 7) "foo"
10 WHITESPACE@[7; 8)
11 ALIAS@[8; 14)
12 AS_KW@[8; 10)
13 WHITESPACE@[10; 11)
14 NAME@[11; 14)
15 IDENT@[11; 14) "bar"
16 SEMI@[14; 15)
17 WHITESPACE@[15; 16)
18 USE_ITEM@[16; 54)
19 USE_KW@[16; 19)
20 WHITESPACE@[19; 20)
21 USE_TREE@[20; 53)
22 PATH@[20; 23)
23 PATH_SEGMENT@[20; 23)
24 NAME_REF@[20; 23)
25 IDENT@[20; 23) "foo"
26 COLONCOLON@[23; 25)
27 L_CURLY@[25; 26)
28 USE_TREE@[26; 32)
29 PATH@[26; 27)
30 PATH_SEGMENT@[26; 27)
31 NAME_REF@[26; 27)
32 IDENT@[26; 27) "a"
33 WHITESPACE@[27; 28)
34 ALIAS@[28; 32)
35 AS_KW@[28; 30)
36 WHITESPACE@[30; 31)
37 NAME@[31; 32)
38 IDENT@[31; 32) "b"
39 COMMA@[32; 33)
40 WHITESPACE@[33; 34)
41 USE_TREE@[34; 35)
42 STAR@[34; 35)
43 COMMA@[35; 36)
44 WHITESPACE@[36; 37)
45 USE_TREE@[37; 40)
46 COLONCOLON@[37; 39)
47 STAR@[39; 40)
48 COMMA@[40; 41)
49 WHITESPACE@[41; 42)
50 USE_TREE@[42; 52)
51 PATH@[42; 47)
52 PATH_SEGMENT@[42; 47)
53 COLONCOLON@[42; 44)
54 NAME_REF@[44; 47)
55 IDENT@[44; 47) "foo"
56 WHITESPACE@[47; 48)
57 ALIAS@[48; 52)
58 AS_KW@[48; 50)
59 WHITESPACE@[50; 51)
60 NAME@[51; 52)
61 IDENT@[51; 52) "x"
62 R_CURLY@[52; 53)
63 SEMI@[53; 54)
64 WHITESPACE@[54; 55)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.rs b/crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.rs
new file mode 100644
index 000000000..69638350c
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.rs
@@ -0,0 +1,10 @@
1struct A;
2struct B {}
3struct C();
4
5struct D {
6 a: u32,
7 pub b: u32
8}
9
10struct E(pub x, y,);
diff --git a/crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.txt b/crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.txt
new file mode 100644
index 000000000..5dd480d1b
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0016_struct_flavors.txt
@@ -0,0 +1,89 @@
1FILE@[0; 97)
2 STRUCT_ITEM@[0; 9)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "A"
7 SEMI@[8; 9)
8 WHITESPACE@[9; 10)
9 STRUCT_ITEM@[10; 21)
10 STRUCT_KW@[10; 16)
11 WHITESPACE@[16; 17)
12 NAME@[17; 18)
13 IDENT@[17; 18) "B"
14 WHITESPACE@[18; 19)
15 L_CURLY@[19; 20)
16 R_CURLY@[20; 21)
17 WHITESPACE@[21; 22)
18 STRUCT_ITEM@[22; 33)
19 STRUCT_KW@[22; 28)
20 WHITESPACE@[28; 29)
21 NAME@[29; 30)
22 IDENT@[29; 30) "C"
23 L_PAREN@[30; 31)
24 R_PAREN@[31; 32)
25 SEMI@[32; 33)
26 WHITESPACE@[33; 35)
27 STRUCT_ITEM@[35; 74)
28 STRUCT_KW@[35; 41)
29 WHITESPACE@[41; 42)
30 NAME@[42; 43)
31 IDENT@[42; 43) "D"
32 WHITESPACE@[43; 44)
33 L_CURLY@[44; 45)
34 WHITESPACE@[45; 50)
35 NAMED_FIELD@[50; 56)
36 NAME@[50; 51)
37 IDENT@[50; 51) "a"
38 COLON@[51; 52)
39 WHITESPACE@[52; 53)
40 PATH_TYPE@[53; 56)
41 PATH@[53; 56)
42 PATH_SEGMENT@[53; 56)
43 NAME_REF@[53; 56)
44 IDENT@[53; 56) "u32"
45 COMMA@[56; 57)
46 WHITESPACE@[57; 62)
47 NAMED_FIELD@[62; 72)
48 VISIBILITY@[62; 65)
49 PUB_KW@[62; 65)
50 WHITESPACE@[65; 66)
51 NAME@[66; 67)
52 IDENT@[66; 67) "b"
53 COLON@[67; 68)
54 WHITESPACE@[68; 69)
55 PATH_TYPE@[69; 72)
56 PATH@[69; 72)
57 PATH_SEGMENT@[69; 72)
58 NAME_REF@[69; 72)
59 IDENT@[69; 72) "u32"
60 WHITESPACE@[72; 73)
61 R_CURLY@[73; 74)
62 WHITESPACE@[74; 76)
63 STRUCT_ITEM@[76; 96)
64 STRUCT_KW@[76; 82)
65 WHITESPACE@[82; 83)
66 NAME@[83; 84)
67 IDENT@[83; 84) "E"
68 L_PAREN@[84; 85)
69 POS_FIELD@[85; 90)
70 VISIBILITY@[85; 88)
71 PUB_KW@[85; 88)
72 WHITESPACE@[88; 89)
73 PATH_TYPE@[89; 90)
74 PATH@[89; 90)
75 PATH_SEGMENT@[89; 90)
76 NAME_REF@[89; 90)
77 IDENT@[89; 90) "x"
78 COMMA@[90; 91)
79 WHITESPACE@[91; 92)
80 POS_FIELD@[92; 93)
81 PATH_TYPE@[92; 93)
82 PATH@[92; 93)
83 PATH_SEGMENT@[92; 93)
84 NAME_REF@[92; 93)
85 IDENT@[92; 93) "y"
86 COMMA@[93; 94)
87 R_PAREN@[94; 95)
88 SEMI@[95; 96)
89 WHITESPACE@[96; 97)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.rs b/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.rs
new file mode 100644
index 000000000..fe0a7bb97
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.rs
@@ -0,0 +1,2 @@
1#[foo(a,)]
2fn foo() {}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt b/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt
new file mode 100644
index 000000000..69724cdc8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt
@@ -0,0 +1,26 @@
1FILE@[0; 23)
2 FUNCTION@[0; 22)
3 ATTR@[0; 10)
4 POUND@[0; 1)
5 L_BRACK@[1; 2)
6 META_ITEM@[2; 9)
7 IDENT@[2; 5) "foo"
8 L_PAREN@[5; 6)
9 META_ITEM@[6; 7)
10 IDENT@[6; 7) "a"
11 COMMA@[7; 8)
12 R_PAREN@[8; 9)
13 R_BRACK@[9; 10)
14 WHITESPACE@[10; 11)
15 FN_KW@[11; 13)
16 WHITESPACE@[13; 14)
17 NAME@[14; 17)
18 IDENT@[14; 17) "foo"
19 PARAM_LIST@[17; 19)
20 L_PAREN@[17; 18)
21 R_PAREN@[18; 19)
22 WHITESPACE@[19; 20)
23 BLOCK_EXPR@[20; 22)
24 L_CURLY@[20; 21)
25 R_CURLY@[21; 22)
26 WHITESPACE@[22; 23)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.rs b/crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.rs
new file mode 100644
index 000000000..88c544923
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.rs
@@ -0,0 +1,17 @@
1struct S1<T>;
2struct S2<T>(u32);
3struct S3<T> { u: u32 }
4
5struct S4<>;
6struct S5<'a>;
7struct S6<'a:>;
8struct S7<'a: 'b>;
9struct S8<'a: 'b + >;
10struct S9<'a: 'b + 'c>;
11struct S10<'a,>;
12struct S11<'a, 'b>;
13struct S12<'a: 'b+, 'b: 'c,>;
14
15struct S13<T>;
16struct S14<T, U>;
17struct S15<'a, T, U>;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.txt b/crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.txt
new file mode 100644
index 000000000..6457c2639
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0018_struct_type_params.txt
@@ -0,0 +1,255 @@
1FILE@[0; 290)
2 STRUCT_ITEM@[0; 13)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 9)
6 IDENT@[7; 9) "S1"
7 TYPE_PARAM_LIST@[9; 12)
8 L_ANGLE@[9; 10)
9 TYPE_PARAM@[10; 11)
10 NAME@[10; 11)
11 IDENT@[10; 11) "T"
12 R_ANGLE@[11; 12)
13 SEMI@[12; 13)
14 WHITESPACE@[13; 14)
15 STRUCT_ITEM@[14; 32)
16 STRUCT_KW@[14; 20)
17 WHITESPACE@[20; 21)
18 NAME@[21; 23)
19 IDENT@[21; 23) "S2"
20 TYPE_PARAM_LIST@[23; 26)
21 L_ANGLE@[23; 24)
22 TYPE_PARAM@[24; 25)
23 NAME@[24; 25)
24 IDENT@[24; 25) "T"
25 R_ANGLE@[25; 26)
26 L_PAREN@[26; 27)
27 POS_FIELD@[27; 30)
28 PATH_TYPE@[27; 30)
29 PATH@[27; 30)
30 PATH_SEGMENT@[27; 30)
31 NAME_REF@[27; 30)
32 IDENT@[27; 30) "u32"
33 R_PAREN@[30; 31)
34 SEMI@[31; 32)
35 WHITESPACE@[32; 33)
36 STRUCT_ITEM@[33; 56)
37 STRUCT_KW@[33; 39)
38 WHITESPACE@[39; 40)
39 NAME@[40; 42)
40 IDENT@[40; 42) "S3"
41 TYPE_PARAM_LIST@[42; 45)
42 L_ANGLE@[42; 43)
43 TYPE_PARAM@[43; 44)
44 NAME@[43; 44)
45 IDENT@[43; 44) "T"
46 R_ANGLE@[44; 45)
47 WHITESPACE@[45; 46)
48 L_CURLY@[46; 47)
49 WHITESPACE@[47; 48)
50 NAMED_FIELD@[48; 54)
51 NAME@[48; 49)
52 IDENT@[48; 49) "u"
53 COLON@[49; 50)
54 WHITESPACE@[50; 51)
55 PATH_TYPE@[51; 54)
56 PATH@[51; 54)
57 PATH_SEGMENT@[51; 54)
58 NAME_REF@[51; 54)
59 IDENT@[51; 54) "u32"
60 WHITESPACE@[54; 55)
61 R_CURLY@[55; 56)
62 WHITESPACE@[56; 58)
63 STRUCT_ITEM@[58; 70)
64 STRUCT_KW@[58; 64)
65 WHITESPACE@[64; 65)
66 NAME@[65; 67)
67 IDENT@[65; 67) "S4"
68 TYPE_PARAM_LIST@[67; 69)
69 L_ANGLE@[67; 68)
70 R_ANGLE@[68; 69)
71 SEMI@[69; 70)
72 WHITESPACE@[70; 71)
73 STRUCT_ITEM@[71; 85)
74 STRUCT_KW@[71; 77)
75 WHITESPACE@[77; 78)
76 NAME@[78; 80)
77 IDENT@[78; 80) "S5"
78 TYPE_PARAM_LIST@[80; 84)
79 L_ANGLE@[80; 81)
80 LIFETIME_PARAM@[81; 83)
81 LIFETIME@[81; 83) "'a"
82 R_ANGLE@[83; 84)
83 SEMI@[84; 85)
84 WHITESPACE@[85; 86)
85 STRUCT_ITEM@[86; 101)
86 STRUCT_KW@[86; 92)
87 WHITESPACE@[92; 93)
88 NAME@[93; 95)
89 IDENT@[93; 95) "S6"
90 TYPE_PARAM_LIST@[95; 100)
91 L_ANGLE@[95; 96)
92 LIFETIME_PARAM@[96; 99)
93 LIFETIME@[96; 98) "'a"
94 COLON@[98; 99)
95 R_ANGLE@[99; 100)
96 SEMI@[100; 101)
97 WHITESPACE@[101; 102)
98 STRUCT_ITEM@[102; 120)
99 STRUCT_KW@[102; 108)
100 WHITESPACE@[108; 109)
101 NAME@[109; 111)
102 IDENT@[109; 111) "S7"
103 TYPE_PARAM_LIST@[111; 119)
104 L_ANGLE@[111; 112)
105 LIFETIME_PARAM@[112; 118)
106 LIFETIME@[112; 114) "'a"
107 COLON@[114; 115)
108 WHITESPACE@[115; 116)
109 LIFETIME@[116; 118) "'b"
110 R_ANGLE@[118; 119)
111 SEMI@[119; 120)
112 WHITESPACE@[120; 121)
113 STRUCT_ITEM@[121; 142)
114 STRUCT_KW@[121; 127)
115 WHITESPACE@[127; 128)
116 NAME@[128; 130)
117 IDENT@[128; 130) "S8"
118 TYPE_PARAM_LIST@[130; 141)
119 L_ANGLE@[130; 131)
120 LIFETIME_PARAM@[131; 139)
121 LIFETIME@[131; 133) "'a"
122 COLON@[133; 134)
123 WHITESPACE@[134; 135)
124 LIFETIME@[135; 137) "'b"
125 WHITESPACE@[137; 138)
126 PLUS@[138; 139)
127 WHITESPACE@[139; 140)
128 R_ANGLE@[140; 141)
129 SEMI@[141; 142)
130 WHITESPACE@[142; 143)
131 STRUCT_ITEM@[143; 166)
132 STRUCT_KW@[143; 149)
133 WHITESPACE@[149; 150)
134 NAME@[150; 152)
135 IDENT@[150; 152) "S9"
136 TYPE_PARAM_LIST@[152; 165)
137 L_ANGLE@[152; 153)
138 LIFETIME_PARAM@[153; 164)
139 LIFETIME@[153; 155) "'a"
140 COLON@[155; 156)
141 WHITESPACE@[156; 157)
142 LIFETIME@[157; 159) "'b"
143 WHITESPACE@[159; 160)
144 PLUS@[160; 161)
145 WHITESPACE@[161; 162)
146 LIFETIME@[162; 164) "'c"
147 R_ANGLE@[164; 165)
148 SEMI@[165; 166)
149 WHITESPACE@[166; 167)
150 STRUCT_ITEM@[167; 183)
151 STRUCT_KW@[167; 173)
152 WHITESPACE@[173; 174)
153 NAME@[174; 177)
154 IDENT@[174; 177) "S10"
155 TYPE_PARAM_LIST@[177; 182)
156 L_ANGLE@[177; 178)
157 LIFETIME_PARAM@[178; 180)
158 LIFETIME@[178; 180) "'a"
159 COMMA@[180; 181)
160 R_ANGLE@[181; 182)
161 SEMI@[182; 183)
162 WHITESPACE@[183; 184)
163 STRUCT_ITEM@[184; 203)
164 STRUCT_KW@[184; 190)
165 WHITESPACE@[190; 191)
166 NAME@[191; 194)
167 IDENT@[191; 194) "S11"
168 TYPE_PARAM_LIST@[194; 202)
169 L_ANGLE@[194; 195)
170 LIFETIME_PARAM@[195; 197)
171 LIFETIME@[195; 197) "'a"
172 COMMA@[197; 198)
173 WHITESPACE@[198; 199)
174 LIFETIME_PARAM@[199; 201)
175 LIFETIME@[199; 201) "'b"
176 R_ANGLE@[201; 202)
177 SEMI@[202; 203)
178 WHITESPACE@[203; 204)
179 STRUCT_ITEM@[204; 233)
180 STRUCT_KW@[204; 210)
181 WHITESPACE@[210; 211)
182 NAME@[211; 214)
183 IDENT@[211; 214) "S12"
184 TYPE_PARAM_LIST@[214; 232)
185 L_ANGLE@[214; 215)
186 LIFETIME_PARAM@[215; 222)
187 LIFETIME@[215; 217) "'a"
188 COLON@[217; 218)
189 WHITESPACE@[218; 219)
190 LIFETIME@[219; 221) "'b"
191 PLUS@[221; 222)
192 COMMA@[222; 223)
193 WHITESPACE@[223; 224)
194 LIFETIME_PARAM@[224; 230)
195 LIFETIME@[224; 226) "'b"
196 COLON@[226; 227)
197 WHITESPACE@[227; 228)
198 LIFETIME@[228; 230) "'c"
199 COMMA@[230; 231)
200 R_ANGLE@[231; 232)
201 SEMI@[232; 233)
202 WHITESPACE@[233; 235)
203 STRUCT_ITEM@[235; 249)
204 STRUCT_KW@[235; 241)
205 WHITESPACE@[241; 242)
206 NAME@[242; 245)
207 IDENT@[242; 245) "S13"
208 TYPE_PARAM_LIST@[245; 248)
209 L_ANGLE@[245; 246)
210 TYPE_PARAM@[246; 247)
211 NAME@[246; 247)
212 IDENT@[246; 247) "T"
213 R_ANGLE@[247; 248)
214 SEMI@[248; 249)
215 WHITESPACE@[249; 250)
216 STRUCT_ITEM@[250; 267)
217 STRUCT_KW@[250; 256)
218 WHITESPACE@[256; 257)
219 NAME@[257; 260)
220 IDENT@[257; 260) "S14"
221 TYPE_PARAM_LIST@[260; 266)
222 L_ANGLE@[260; 261)
223 TYPE_PARAM@[261; 262)
224 NAME@[261; 262)
225 IDENT@[261; 262) "T"
226 COMMA@[262; 263)
227 WHITESPACE@[263; 264)
228 TYPE_PARAM@[264; 265)
229 NAME@[264; 265)
230 IDENT@[264; 265) "U"
231 R_ANGLE@[265; 266)
232 SEMI@[266; 267)
233 WHITESPACE@[267; 268)
234 STRUCT_ITEM@[268; 289)
235 STRUCT_KW@[268; 274)
236 WHITESPACE@[274; 275)
237 NAME@[275; 278)
238 IDENT@[275; 278) "S15"
239 TYPE_PARAM_LIST@[278; 288)
240 L_ANGLE@[278; 279)
241 LIFETIME_PARAM@[279; 281)
242 LIFETIME@[279; 281) "'a"
243 COMMA@[281; 282)
244 WHITESPACE@[282; 283)
245 TYPE_PARAM@[283; 284)
246 NAME@[283; 284)
247 IDENT@[283; 284) "T"
248 COMMA@[284; 285)
249 WHITESPACE@[285; 286)
250 TYPE_PARAM@[286; 287)
251 NAME@[286; 287)
252 IDENT@[286; 287) "U"
253 R_ANGLE@[287; 288)
254 SEMI@[288; 289)
255 WHITESPACE@[289; 290)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0019_enums.rs b/crates/libsyntax2/tests/data/parser/ok/0019_enums.rs
new file mode 100644
index 000000000..7a1afa0e6
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0019_enums.rs
@@ -0,0 +1,25 @@
1enum E1 {
2}
3
4enum E2<T> {
5}
6
7enum E3 {
8 X
9}
10
11enum E4 {
12 X,
13}
14
15enum E5 {
16 A,
17 B = 92,
18 C {
19 a: u32,
20 pub b: f64,
21 },
22 F {},
23 D(u32,),
24 E(),
25}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0019_enums.txt b/crates/libsyntax2/tests/data/parser/ok/0019_enums.txt
new file mode 100644
index 000000000..8650381cd
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0019_enums.txt
@@ -0,0 +1,146 @@
1FILE@[0; 182)
2 ENUM_ITEM@[0; 11)
3 ENUM_KW@[0; 4)
4 WHITESPACE@[4; 5)
5 NAME@[5; 7)
6 IDENT@[5; 7) "E1"
7 WHITESPACE@[7; 8)
8 L_CURLY@[8; 9)
9 WHITESPACE@[9; 10)
10 R_CURLY@[10; 11)
11 WHITESPACE@[11; 13)
12 ENUM_ITEM@[13; 27)
13 ENUM_KW@[13; 17)
14 WHITESPACE@[17; 18)
15 NAME@[18; 20)
16 IDENT@[18; 20) "E2"
17 TYPE_PARAM_LIST@[20; 23)
18 L_ANGLE@[20; 21)
19 TYPE_PARAM@[21; 22)
20 NAME@[21; 22)
21 IDENT@[21; 22) "T"
22 R_ANGLE@[22; 23)
23 WHITESPACE@[23; 24)
24 L_CURLY@[24; 25)
25 WHITESPACE@[25; 26)
26 R_CURLY@[26; 27)
27 WHITESPACE@[27; 29)
28 ENUM_ITEM@[29; 46)
29 ENUM_KW@[29; 33)
30 WHITESPACE@[33; 34)
31 NAME@[34; 36)
32 IDENT@[34; 36) "E3"
33 WHITESPACE@[36; 37)
34 L_CURLY@[37; 38)
35 WHITESPACE@[38; 43)
36 ENUM_VARIANT@[43; 44)
37 NAME@[43; 44)
38 IDENT@[43; 44) "X"
39 WHITESPACE@[44; 45)
40 R_CURLY@[45; 46)
41 WHITESPACE@[46; 48)
42 ENUM_ITEM@[48; 66)
43 ENUM_KW@[48; 52)
44 WHITESPACE@[52; 53)
45 NAME@[53; 55)
46 IDENT@[53; 55) "E4"
47 WHITESPACE@[55; 56)
48 L_CURLY@[56; 57)
49 WHITESPACE@[57; 62)
50 ENUM_VARIANT@[62; 63)
51 NAME@[62; 63)
52 IDENT@[62; 63) "X"
53 COMMA@[63; 64)
54 WHITESPACE@[64; 65)
55 R_CURLY@[65; 66)
56 WHITESPACE@[66; 68)
57 ENUM_ITEM@[68; 181)
58 ENUM_KW@[68; 72)
59 WHITESPACE@[72; 73)
60 NAME@[73; 75)
61 IDENT@[73; 75) "E5"
62 WHITESPACE@[75; 76)
63 L_CURLY@[76; 77)
64 WHITESPACE@[77; 82)
65 ENUM_VARIANT@[82; 83)
66 NAME@[82; 83)
67 IDENT@[82; 83) "A"
68 COMMA@[83; 84)
69 WHITESPACE@[84; 89)
70 ENUM_VARIANT@[89; 95)
71 NAME@[89; 90)
72 IDENT@[89; 90) "B"
73 WHITESPACE@[90; 91)
74 EQ@[91; 92)
75 WHITESPACE@[92; 93)
76 LITERAL@[93; 95)
77 INT_NUMBER@[93; 95) "92"
78 COMMA@[95; 96)
79 WHITESPACE@[96; 101)
80 ENUM_VARIANT@[101; 146)
81 NAME@[101; 102)
82 IDENT@[101; 102) "C"
83 WHITESPACE@[102; 103)
84 L_CURLY@[103; 104)
85 WHITESPACE@[104; 113)
86 NAMED_FIELD@[113; 119)
87 NAME@[113; 114)
88 IDENT@[113; 114) "a"
89 COLON@[114; 115)
90 WHITESPACE@[115; 116)
91 PATH_TYPE@[116; 119)
92 PATH@[116; 119)
93 PATH_SEGMENT@[116; 119)
94 NAME_REF@[116; 119)
95 IDENT@[116; 119) "u32"
96 COMMA@[119; 120)
97 WHITESPACE@[120; 129)
98 NAMED_FIELD@[129; 139)
99 VISIBILITY@[129; 132)
100 PUB_KW@[129; 132)
101 WHITESPACE@[132; 133)
102 NAME@[133; 134)
103 IDENT@[133; 134) "b"
104 COLON@[134; 135)
105 WHITESPACE@[135; 136)
106 PATH_TYPE@[136; 139)
107 PATH@[136; 139)
108 PATH_SEGMENT@[136; 139)
109 NAME_REF@[136; 139)
110 IDENT@[136; 139) "f64"
111 COMMA@[139; 140)
112 WHITESPACE@[140; 145)
113 R_CURLY@[145; 146)
114 COMMA@[146; 147)
115 WHITESPACE@[147; 152)
116 ENUM_VARIANT@[152; 156)
117 NAME@[152; 153)
118 IDENT@[152; 153) "F"
119 WHITESPACE@[153; 154)
120 L_CURLY@[154; 155)
121 R_CURLY@[155; 156)
122 COMMA@[156; 157)
123 WHITESPACE@[157; 162)
124 ENUM_VARIANT@[162; 169)
125 NAME@[162; 163)
126 IDENT@[162; 163) "D"
127 L_PAREN@[163; 164)
128 POS_FIELD@[164; 167)
129 PATH_TYPE@[164; 167)
130 PATH@[164; 167)
131 PATH_SEGMENT@[164; 167)
132 NAME_REF@[164; 167)
133 IDENT@[164; 167) "u32"
134 COMMA@[167; 168)
135 R_PAREN@[168; 169)
136 COMMA@[169; 170)
137 WHITESPACE@[170; 175)
138 ENUM_VARIANT@[175; 178)
139 NAME@[175; 176)
140 IDENT@[175; 176) "E"
141 L_PAREN@[176; 177)
142 R_PAREN@[177; 178)
143 COMMA@[178; 179)
144 WHITESPACE@[179; 180)
145 R_CURLY@[180; 181)
146 WHITESPACE@[181; 182)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.rs b/crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.rs
new file mode 100644
index 000000000..a1b9f00a4
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.rs
@@ -0,0 +1,9 @@
1struct A<T>;
2struct B<T:>;
3struct C<T: 'a>;
4struct D<T: 'a + >;
5struct E<T: 'a + 'd >;
6struct F<T: 'a + 'd + Clone>;
7struct G<T: Clone + Copy>;
8struct H<T: ::Foo + self::Bar + 'a>;
9struct I<T:, U:,>;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.txt b/crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.txt
new file mode 100644
index 000000000..fe12cbb94
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0020_type_param_bounds.txt
@@ -0,0 +1,193 @@
1FILE@[0; 200)
2 STRUCT_ITEM@[0; 12)
3 STRUCT_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 8)
6 IDENT@[7; 8) "A"
7 TYPE_PARAM_LIST@[8; 11)
8 L_ANGLE@[8; 9)
9 TYPE_PARAM@[9; 10)
10 NAME@[9; 10)
11 IDENT@[9; 10) "T"
12 R_ANGLE@[10; 11)
13 SEMI@[11; 12)
14 WHITESPACE@[12; 13)
15 STRUCT_ITEM@[13; 26)
16 STRUCT_KW@[13; 19)
17 WHITESPACE@[19; 20)
18 NAME@[20; 21)
19 IDENT@[20; 21) "B"
20 TYPE_PARAM_LIST@[21; 25)
21 L_ANGLE@[21; 22)
22 TYPE_PARAM@[22; 24)
23 NAME@[22; 23)
24 IDENT@[22; 23) "T"
25 COLON@[23; 24)
26 R_ANGLE@[24; 25)
27 SEMI@[25; 26)
28 WHITESPACE@[26; 27)
29 STRUCT_ITEM@[27; 43)
30 STRUCT_KW@[27; 33)
31 WHITESPACE@[33; 34)
32 NAME@[34; 35)
33 IDENT@[34; 35) "C"
34 TYPE_PARAM_LIST@[35; 42)
35 L_ANGLE@[35; 36)
36 TYPE_PARAM@[36; 41)
37 NAME@[36; 37)
38 IDENT@[36; 37) "T"
39 COLON@[37; 38)
40 WHITESPACE@[38; 39)
41 LIFETIME@[39; 41) "'a"
42 R_ANGLE@[41; 42)
43 SEMI@[42; 43)
44 WHITESPACE@[43; 44)
45 STRUCT_ITEM@[44; 63)
46 STRUCT_KW@[44; 50)
47 WHITESPACE@[50; 51)
48 NAME@[51; 52)
49 IDENT@[51; 52) "D"
50 TYPE_PARAM_LIST@[52; 62)
51 L_ANGLE@[52; 53)
52 TYPE_PARAM@[53; 60)
53 NAME@[53; 54)
54 IDENT@[53; 54) "T"
55 COLON@[54; 55)
56 WHITESPACE@[55; 56)
57 LIFETIME@[56; 58) "'a"
58 WHITESPACE@[58; 59)
59 PLUS@[59; 60)
60 WHITESPACE@[60; 61)
61 R_ANGLE@[61; 62)
62 SEMI@[62; 63)
63 WHITESPACE@[63; 64)
64 STRUCT_ITEM@[64; 86)
65 STRUCT_KW@[64; 70)
66 WHITESPACE@[70; 71)
67 NAME@[71; 72)
68 IDENT@[71; 72) "E"
69 TYPE_PARAM_LIST@[72; 85)
70 L_ANGLE@[72; 73)
71 TYPE_PARAM@[73; 83)
72 NAME@[73; 74)
73 IDENT@[73; 74) "T"
74 COLON@[74; 75)
75 WHITESPACE@[75; 76)
76 LIFETIME@[76; 78) "'a"
77 WHITESPACE@[78; 79)
78 PLUS@[79; 80)
79 WHITESPACE@[80; 81)
80 LIFETIME@[81; 83) "'d"
81 WHITESPACE@[83; 84)
82 R_ANGLE@[84; 85)
83 SEMI@[85; 86)
84 WHITESPACE@[86; 87)
85 STRUCT_ITEM@[87; 116)
86 STRUCT_KW@[87; 93)
87 WHITESPACE@[93; 94)
88 NAME@[94; 95)
89 IDENT@[94; 95) "F"
90 TYPE_PARAM_LIST@[95; 115)
91 L_ANGLE@[95; 96)
92 TYPE_PARAM@[96; 114)
93 NAME@[96; 97)
94 IDENT@[96; 97) "T"
95 COLON@[97; 98)
96 WHITESPACE@[98; 99)
97 LIFETIME@[99; 101) "'a"
98 WHITESPACE@[101; 102)
99 PLUS@[102; 103)
100 WHITESPACE@[103; 104)
101 LIFETIME@[104; 106) "'d"
102 WHITESPACE@[106; 107)
103 PLUS@[107; 108)
104 WHITESPACE@[108; 109)
105 PATH@[109; 114)
106 PATH_SEGMENT@[109; 114)
107 NAME_REF@[109; 114)
108 IDENT@[109; 114) "Clone"
109 R_ANGLE@[114; 115)
110 SEMI@[115; 116)
111 WHITESPACE@[116; 117)
112 STRUCT_ITEM@[117; 143)
113 STRUCT_KW@[117; 123)
114 WHITESPACE@[123; 124)
115 NAME@[124; 125)
116 IDENT@[124; 125) "G"
117 TYPE_PARAM_LIST@[125; 142)
118 L_ANGLE@[125; 126)
119 TYPE_PARAM@[126; 141)
120 NAME@[126; 127)
121 IDENT@[126; 127) "T"
122 COLON@[127; 128)
123 WHITESPACE@[128; 129)
124 PATH@[129; 134)
125 PATH_SEGMENT@[129; 134)
126 NAME_REF@[129; 134)
127 IDENT@[129; 134) "Clone"
128 WHITESPACE@[134; 135)
129 PLUS@[135; 136)
130 WHITESPACE@[136; 137)
131 PATH@[137; 141)
132 PATH_SEGMENT@[137; 141)
133 NAME_REF@[137; 141)
134 IDENT@[137; 141) "Copy"
135 R_ANGLE@[141; 142)
136 SEMI@[142; 143)
137 WHITESPACE@[143; 144)
138 STRUCT_ITEM@[144; 180)
139 STRUCT_KW@[144; 150)
140 WHITESPACE@[150; 151)
141 NAME@[151; 152)
142 IDENT@[151; 152) "H"
143 TYPE_PARAM_LIST@[152; 179)
144 L_ANGLE@[152; 153)
145 TYPE_PARAM@[153; 178)
146 NAME@[153; 154)
147 IDENT@[153; 154) "T"
148 COLON@[154; 155)
149 WHITESPACE@[155; 156)
150 PATH@[156; 161)
151 PATH_SEGMENT@[156; 161)
152 COLONCOLON@[156; 158)
153 NAME_REF@[158; 161)
154 IDENT@[158; 161) "Foo"
155 WHITESPACE@[161; 162)
156 PLUS@[162; 163)
157 WHITESPACE@[163; 164)
158 PATH@[164; 173)
159 PATH@[164; 168)
160 PATH_SEGMENT@[164; 168)
161 SELF_KW@[164; 168)
162 COLONCOLON@[168; 170)
163 PATH_SEGMENT@[170; 173)
164 NAME_REF@[170; 173)
165 IDENT@[170; 173) "Bar"
166 WHITESPACE@[173; 174)
167 PLUS@[174; 175)
168 WHITESPACE@[175; 176)
169 LIFETIME@[176; 178) "'a"
170 R_ANGLE@[178; 179)
171 SEMI@[179; 180)
172 WHITESPACE@[180; 181)
173 STRUCT_ITEM@[181; 199)
174 STRUCT_KW@[181; 187)
175 WHITESPACE@[187; 188)
176 NAME@[188; 189)
177 IDENT@[188; 189) "I"
178 TYPE_PARAM_LIST@[189; 198)
179 L_ANGLE@[189; 190)
180 TYPE_PARAM@[190; 192)
181 NAME@[190; 191)
182 IDENT@[190; 191) "T"
183 COLON@[191; 192)
184 COMMA@[192; 193)
185 WHITESPACE@[193; 194)
186 TYPE_PARAM@[194; 196)
187 NAME@[194; 195)
188 IDENT@[194; 195) "U"
189 COLON@[195; 196)
190 COMMA@[196; 197)
191 R_ANGLE@[197; 198)
192 SEMI@[198; 199)
193 WHITESPACE@[199; 200)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.rs b/crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.rs
new file mode 100644
index 000000000..e929eef74
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.rs
@@ -0,0 +1,8 @@
1extern fn foo() {
2}
3
4extern "C" fn bar() {
5}
6
7extern r"D" fn baz() {
8}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.txt b/crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.txt
new file mode 100644
index 000000000..07d5cc157
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0021_extern_fn.txt
@@ -0,0 +1,56 @@
1FILE@[0; 71)
2 FUNCTION@[0; 19)
3 ABI@[0; 6)
4 EXTERN_KW@[0; 6)
5 WHITESPACE@[6; 7)
6 FN_KW@[7; 9)
7 WHITESPACE@[9; 10)
8 NAME@[10; 13)
9 IDENT@[10; 13) "foo"
10 PARAM_LIST@[13; 15)
11 L_PAREN@[13; 14)
12 R_PAREN@[14; 15)
13 WHITESPACE@[15; 16)
14 BLOCK_EXPR@[16; 19)
15 L_CURLY@[16; 17)
16 WHITESPACE@[17; 18)
17 R_CURLY@[18; 19)
18 WHITESPACE@[19; 21)
19 FUNCTION@[21; 44)
20 ABI@[21; 31)
21 EXTERN_KW@[21; 27)
22 WHITESPACE@[27; 28)
23 STRING@[28; 31)
24 WHITESPACE@[31; 32)
25 FN_KW@[32; 34)
26 WHITESPACE@[34; 35)
27 NAME@[35; 38)
28 IDENT@[35; 38) "bar"
29 PARAM_LIST@[38; 40)
30 L_PAREN@[38; 39)
31 R_PAREN@[39; 40)
32 WHITESPACE@[40; 41)
33 BLOCK_EXPR@[41; 44)
34 L_CURLY@[41; 42)
35 WHITESPACE@[42; 43)
36 R_CURLY@[43; 44)
37 WHITESPACE@[44; 46)
38 FUNCTION@[46; 70)
39 ABI@[46; 57)
40 EXTERN_KW@[46; 52)
41 WHITESPACE@[52; 53)
42 RAW_STRING@[53; 57)
43 WHITESPACE@[57; 58)
44 FN_KW@[58; 60)
45 WHITESPACE@[60; 61)
46 NAME@[61; 64)
47 IDENT@[61; 64) "baz"
48 PARAM_LIST@[64; 66)
49 L_PAREN@[64; 65)
50 R_PAREN@[65; 66)
51 WHITESPACE@[66; 67)
52 BLOCK_EXPR@[67; 70)
53 L_CURLY@[67; 68)
54 WHITESPACE@[68; 69)
55 R_CURLY@[69; 70)
56 WHITESPACE@[70; 71)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.rs b/crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.rs
new file mode 100644
index 000000000..f5fe0e6ef
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.rs
@@ -0,0 +1,5 @@
1extern {
2}
3
4extern "C" {
5}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.txt b/crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.txt
new file mode 100644
index 000000000..81b92d394
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0022_empty_extern_block.txt
@@ -0,0 +1,19 @@
1FILE@[0; 27)
2 EXTERN_BLOCK_EXPR@[0; 10)
3 ABI@[0; 6)
4 EXTERN_KW@[0; 6)
5 WHITESPACE@[6; 7)
6 L_CURLY@[7; 8)
7 WHITESPACE@[8; 9)
8 R_CURLY@[9; 10)
9 WHITESPACE@[10; 12)
10 EXTERN_BLOCK_EXPR@[12; 26)
11 ABI@[12; 22)
12 EXTERN_KW@[12; 18)
13 WHITESPACE@[18; 19)
14 STRING@[19; 22)
15 WHITESPACE@[22; 23)
16 L_CURLY@[23; 24)
17 WHITESPACE@[24; 25)
18 R_CURLY@[25; 26)
19 WHITESPACE@[26; 27)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0023_static_items.rs b/crates/libsyntax2/tests/data/parser/ok/0023_static_items.rs
new file mode 100644
index 000000000..5fb92ce33
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0023_static_items.rs
@@ -0,0 +1,2 @@
1static FOO: u32 = 1;
2static mut BAR: i32 = 92;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0023_static_items.txt b/crates/libsyntax2/tests/data/parser/ok/0023_static_items.txt
new file mode 100644
index 000000000..b8dfdd251
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0023_static_items.txt
@@ -0,0 +1,41 @@
1FILE@[0; 47)
2 STATIC_ITEM@[0; 20)
3 STATIC_KW@[0; 6)
4 WHITESPACE@[6; 7)
5 NAME@[7; 10)
6 IDENT@[7; 10) "FOO"
7 COLON@[10; 11)
8 WHITESPACE@[11; 12)
9 PATH_TYPE@[12; 15)
10 PATH@[12; 15)
11 PATH_SEGMENT@[12; 15)
12 NAME_REF@[12; 15)
13 IDENT@[12; 15) "u32"
14 WHITESPACE@[15; 16)
15 EQ@[16; 17)
16 WHITESPACE@[17; 18)
17 LITERAL@[18; 19)
18 INT_NUMBER@[18; 19) "1"
19 SEMI@[19; 20)
20 WHITESPACE@[20; 21)
21 STATIC_ITEM@[21; 46)
22 STATIC_KW@[21; 27)
23 WHITESPACE@[27; 28)
24 MUT_KW@[28; 31)
25 WHITESPACE@[31; 32)
26 NAME@[32; 35)
27 IDENT@[32; 35) "BAR"
28 COLON@[35; 36)
29 WHITESPACE@[36; 37)
30 PATH_TYPE@[37; 40)
31 PATH@[37; 40)
32 PATH_SEGMENT@[37; 40)
33 NAME_REF@[37; 40)
34 IDENT@[37; 40) "i32"
35 WHITESPACE@[40; 41)
36 EQ@[41; 42)
37 WHITESPACE@[42; 43)
38 LITERAL@[43; 45)
39 INT_NUMBER@[43; 45) "92"
40 SEMI@[45; 46)
41 WHITESPACE@[46; 47)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0024_const_item.rs b/crates/libsyntax2/tests/data/parser/ok/0024_const_item.rs
new file mode 100644
index 000000000..7446859b5
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0024_const_item.rs
@@ -0,0 +1,2 @@
1const FOO: u32 = 92;
2const mut BAR: u32 = 62;
diff --git a/crates/libsyntax2/tests/data/parser/ok/0024_const_item.txt b/crates/libsyntax2/tests/data/parser/ok/0024_const_item.txt
new file mode 100644
index 000000000..85083e9c1
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0024_const_item.txt
@@ -0,0 +1,41 @@
1FILE@[0; 46)
2 CONST_ITEM@[0; 20)
3 CONST_KW@[0; 5)
4 WHITESPACE@[5; 6)
5 NAME@[6; 9)
6 IDENT@[6; 9) "FOO"
7 COLON@[9; 10)
8 WHITESPACE@[10; 11)
9 PATH_TYPE@[11; 14)
10 PATH@[11; 14)
11 PATH_SEGMENT@[11; 14)
12 NAME_REF@[11; 14)
13 IDENT@[11; 14) "u32"
14 WHITESPACE@[14; 15)
15 EQ@[15; 16)
16 WHITESPACE@[16; 17)
17 LITERAL@[17; 19)
18 INT_NUMBER@[17; 19) "92"
19 SEMI@[19; 20)
20 WHITESPACE@[20; 21)
21 CONST_ITEM@[21; 45)
22 CONST_KW@[21; 26)
23 WHITESPACE@[26; 27)
24 MUT_KW@[27; 30)
25 WHITESPACE@[30; 31)
26 NAME@[31; 34)
27 IDENT@[31; 34) "BAR"
28 COLON@[34; 35)
29 WHITESPACE@[35; 36)
30 PATH_TYPE@[36; 39)
31 PATH@[36; 39)
32 PATH_SEGMENT@[36; 39)
33 NAME_REF@[36; 39)
34 IDENT@[36; 39) "u32"
35 WHITESPACE@[39; 40)
36 EQ@[40; 41)
37 WHITESPACE@[41; 42)
38 LITERAL@[42; 44)
39 INT_NUMBER@[42; 44) "62"
40 SEMI@[44; 45)
41 WHITESPACE@[45; 46)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.rs b/crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.rs
new file mode 100644
index 000000000..289809809
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.rs
@@ -0,0 +1,3 @@
1fn main() {
2 extern fn f() {}
3}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.txt b/crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.txt
new file mode 100644
index 000000000..46fb177b2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0025_extern_fn_in_block.txt
@@ -0,0 +1,31 @@
1FILE@[0; 35)
2 FUNCTION@[0; 34)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 34)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 FUNCTION@[16; 32)
15 ABI@[16; 22)
16 EXTERN_KW@[16; 22)
17 WHITESPACE@[22; 23)
18 FN_KW@[23; 25)
19 WHITESPACE@[25; 26)
20 NAME@[26; 27)
21 IDENT@[26; 27) "f"
22 PARAM_LIST@[27; 29)
23 L_PAREN@[27; 28)
24 R_PAREN@[28; 29)
25 WHITESPACE@[29; 30)
26 BLOCK_EXPR@[30; 32)
27 L_CURLY@[30; 31)
28 R_CURLY@[31; 32)
29 WHITESPACE@[32; 33)
30 R_CURLY@[33; 34)
31 WHITESPACE@[34; 35)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.rs b/crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.rs
new file mode 100644
index 000000000..7641a3d28
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.rs
@@ -0,0 +1,3 @@
1fn main() {
2 const fn f() {}
3}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.txt b/crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.txt
new file mode 100644
index 000000000..a450762a8
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0026_const_fn_in_block.txt
@@ -0,0 +1,30 @@
1FILE@[0; 34)
2 FUNCTION@[0; 33)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 33)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 FUNCTION@[16; 31)
15 CONST_KW@[16; 21)
16 WHITESPACE@[21; 22)
17 FN_KW@[22; 24)
18 WHITESPACE@[24; 25)
19 NAME@[25; 26)
20 IDENT@[25; 26) "f"
21 PARAM_LIST@[26; 28)
22 L_PAREN@[26; 27)
23 R_PAREN@[27; 28)
24 WHITESPACE@[28; 29)
25 BLOCK_EXPR@[29; 31)
26 L_CURLY@[29; 30)
27 R_CURLY@[30; 31)
28 WHITESPACE@[31; 32)
29 R_CURLY@[32; 33)
30 WHITESPACE@[33; 34)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.rs b/crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.rs
new file mode 100644
index 000000000..f3c5ff938
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.rs
@@ -0,0 +1,4 @@
1fn main() {
2 unsafe fn f() {}
3 unsafe { 92 }
4}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.txt b/crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.txt
new file mode 100644
index 000000000..28cd7ad3d
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0027_unsafe_fn_in_block.txt
@@ -0,0 +1,40 @@
1FILE@[0; 53)
2 FUNCTION@[0; 52)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8)
9 R_PAREN@[8; 9)
10 WHITESPACE@[9; 10)
11 BLOCK_EXPR@[10; 52)
12 L_CURLY@[10; 11)
13 WHITESPACE@[11; 16)
14 FUNCTION@[16; 32)
15 UNSAFE_KW@[16; 22)
16 WHITESPACE@[22; 23)
17 FN_KW@[23; 25)
18 WHITESPACE@[25; 26)
19 NAME@[26; 27)
20 IDENT@[26; 27) "f"
21 PARAM_LIST@[27; 29)
22 L_PAREN@[27; 28)
23 R_PAREN@[28; 29)
24 WHITESPACE@[29; 30)
25 BLOCK_EXPR@[30; 32)
26 L_CURLY@[30; 31)
27 R_CURLY@[31; 32)
28 WHITESPACE@[32; 37)
29 BLOCK_EXPR@[37; 50)
30 UNSAFE_KW@[37; 43)
31 WHITESPACE@[43; 44)
32 L_CURLY@[44; 45)
33 WHITESPACE@[45; 46)
34 LITERAL@[46; 48)
35 INT_NUMBER@[46; 48) "92"
36 WHITESPACE@[48; 49)
37 R_CURLY@[49; 50)
38 WHITESPACE@[50; 51)
39 R_CURLY@[51; 52)
40 WHITESPACE@[52; 53)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.rs b/crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.rs
new file mode 100644
index 000000000..cc9598470
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.rs
@@ -0,0 +1,14 @@
1fn binding_power() {
2 let x = 1 + 2 * 3 % 4 - 5 / 6;
3 1 + 2 * 3;
4 1 << 2 + 3;
5 1 & 2 >> 3;
6 1 ^ 2 & 3;
7 1 | 2 ^ 3;
8 1 == 2 | 3;
9 1 && 2 == 3;
10 //1 || 2 && 2;
11 //1 .. 2 || 3;
12 //1 = 2 .. 3;
13 //---&*1 - --2 * 9;
14}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.txt b/crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.txt
new file mode 100644
index 000000000..3fb1ae811
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0028_operator_binding_power.txt
@@ -0,0 +1,185 @@
1FILE@[0; 248)
2 FUNCTION@[0; 247)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 16)
6 IDENT@[3; 16) "binding_power"
7 PARAM_LIST@[16; 18)
8 L_PAREN@[16; 17)
9 R_PAREN@[17; 18)
10 WHITESPACE@[18; 19)
11 BLOCK_EXPR@[19; 247)
12 L_CURLY@[19; 20)
13 WHITESPACE@[20; 25)
14 LET_STMT@[25; 55)
15 LET_KW@[25; 28)
16 WHITESPACE@[28; 29)
17 BIND_PAT@[29; 30)
18 NAME@[29; 30)
19 IDENT@[29; 30) "x"
20 WHITESPACE@[30; 31)
21 EQ@[31; 32)
22 WHITESPACE@[32; 33)
23 BIN_EXPR@[33; 54)
24 BIN_EXPR@[33; 46)
25 LITERAL@[33; 34)
26 INT_NUMBER@[33; 34) "1"
27 WHITESPACE@[34; 35)
28 PLUS@[35; 36)
29 WHITESPACE@[36; 37)
30 BIN_EXPR@[37; 46)
31 BIN_EXPR@[37; 42)
32 LITERAL@[37; 38)
33 INT_NUMBER@[37; 38) "2"
34 WHITESPACE@[38; 39)
35 STAR@[39; 40)
36 WHITESPACE@[40; 41)
37 LITERAL@[41; 42)
38 INT_NUMBER@[41; 42) "3"
39 WHITESPACE@[42; 43)
40 PERCENT@[43; 44)
41 WHITESPACE@[44; 45)
42 LITERAL@[45; 46)
43 INT_NUMBER@[45; 46) "4"
44 WHITESPACE@[46; 47)
45 MINUS@[47; 48)
46 WHITESPACE@[48; 49)
47 BIN_EXPR@[49; 54)
48 LITERAL@[49; 50)
49 INT_NUMBER@[49; 50) "5"
50 WHITESPACE@[50; 51)
51 SLASH@[51; 52)
52 WHITESPACE@[52; 53)
53 LITERAL@[53; 54)
54 INT_NUMBER@[53; 54) "6"
55 SEMI@[54; 55)
56 WHITESPACE@[55; 60)
57 EXPR_STMT@[60; 70)
58 BIN_EXPR@[60; 69)
59 LITERAL@[60; 61)
60 INT_NUMBER@[60; 61) "1"
61 WHITESPACE@[61; 62)
62 PLUS@[62; 63)
63 WHITESPACE@[63; 64)
64 BIN_EXPR@[64; 69)
65 LITERAL@[64; 65)
66 INT_NUMBER@[64; 65) "2"
67 WHITESPACE@[65; 66)
68 STAR@[66; 67)
69 WHITESPACE@[67; 68)
70 LITERAL@[68; 69)
71 INT_NUMBER@[68; 69) "3"
72 SEMI@[69; 70)
73 WHITESPACE@[70; 75)
74 EXPR_STMT@[75; 86)
75 BIN_EXPR@[75; 85)
76 LITERAL@[75; 76)
77 INT_NUMBER@[75; 76) "1"
78 WHITESPACE@[76; 77)
79 SHL@[77; 79)
80 WHITESPACE@[79; 80)
81 BIN_EXPR@[80; 85)
82 LITERAL@[80; 81)
83 INT_NUMBER@[80; 81) "2"
84 WHITESPACE@[81; 82)
85 PLUS@[82; 83)
86 WHITESPACE@[83; 84)
87 LITERAL@[84; 85)
88 INT_NUMBER@[84; 85) "3"
89 SEMI@[85; 86)
90 WHITESPACE@[86; 91)
91 EXPR_STMT@[91; 102)
92 BIN_EXPR@[91; 101)
93 LITERAL@[91; 92)
94 INT_NUMBER@[91; 92) "1"
95 WHITESPACE@[92; 93)
96 AMP@[93; 94)
97 WHITESPACE@[94; 95)
98 BIN_EXPR@[95; 101)
99 LITERAL@[95; 96)
100 INT_NUMBER@[95; 96) "2"
101 WHITESPACE@[96; 97)
102 SHR@[97; 99)
103 WHITESPACE@[99; 100)
104 LITERAL@[100; 101)
105 INT_NUMBER@[100; 101) "3"
106 SEMI@[101; 102)
107 WHITESPACE@[102; 107)
108 EXPR_STMT@[107; 117)
109 BIN_EXPR@[107; 116)
110 LITERAL@[107; 108)
111 INT_NUMBER@[107; 108) "1"
112 WHITESPACE@[108; 109)
113 CARET@[109; 110)
114 WHITESPACE@[110; 111)
115 BIN_EXPR@[111; 116)
116 LITERAL@[111; 112)
117 INT_NUMBER@[111; 112) "2"
118 WHITESPACE@[112; 113)
119 AMP@[113; 114)
120 WHITESPACE@[114; 115)
121 LITERAL@[115; 116)
122 INT_NUMBER@[115; 116) "3"
123 SEMI@[116; 117)
124 WHITESPACE@[117; 122)
125 EXPR_STMT@[122; 132)
126 BIN_EXPR@[122; 131)
127 LITERAL@[122; 123)
128 INT_NUMBER@[122; 123) "1"
129 WHITESPACE@[123; 124)
130 PIPE@[124; 125)
131 WHITESPACE@[125; 126)
132 BIN_EXPR@[126; 131)
133 LITERAL@[126; 127)
134 INT_NUMBER@[126; 127) "2"
135 WHITESPACE@[127; 128)
136 CARET@[128; 129)
137 WHITESPACE@[129; 130)
138 LITERAL@[130; 131)
139 INT_NUMBER@[130; 131) "3"
140 SEMI@[131; 132)
141 WHITESPACE@[132; 137)
142 EXPR_STMT@[137; 148)
143 BIN_EXPR@[137; 147)
144 LITERAL@[137; 138)
145 INT_NUMBER@[137; 138) "1"
146 WHITESPACE@[138; 139)
147 EQEQ@[139; 141)
148 WHITESPACE@[141; 142)
149 BIN_EXPR@[142; 147)
150 LITERAL@[142; 143)
151 INT_NUMBER@[142; 143) "2"
152 WHITESPACE@[143; 144)
153 PIPE@[144; 145)
154 WHITESPACE@[145; 146)
155 LITERAL@[146; 147)
156 INT_NUMBER@[146; 147) "3"
157 SEMI@[147; 148)
158 WHITESPACE@[148; 153)
159 EXPR_STMT@[153; 165)
160 BIN_EXPR@[153; 164)
161 LITERAL@[153; 154)
162 INT_NUMBER@[153; 154) "1"
163 WHITESPACE@[154; 155)
164 AMPAMP@[155; 157)
165 WHITESPACE@[157; 158)
166 BIN_EXPR@[158; 164)
167 LITERAL@[158; 159)
168 INT_NUMBER@[158; 159) "2"
169 WHITESPACE@[159; 160)
170 EQEQ@[160; 162)
171 WHITESPACE@[162; 163)
172 LITERAL@[163; 164)
173 INT_NUMBER@[163; 164) "3"
174 SEMI@[164; 165)
175 WHITESPACE@[165; 170)
176 COMMENT@[170; 184)
177 WHITESPACE@[184; 189)
178 COMMENT@[189; 203)
179 WHITESPACE@[203; 208)
180 COMMENT@[208; 221)
181 WHITESPACE@[221; 226)
182 COMMENT@[226; 245)
183 WHITESPACE@[245; 246)
184 R_CURLY@[246; 247)
185 WHITESPACE@[247; 248)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0029_range_forms.rs b/crates/libsyntax2/tests/data/parser/ok/0029_range_forms.rs
new file mode 100644
index 000000000..03f4ae7b2
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0029_range_forms.rs
@@ -0,0 +1,6 @@
1fn foo() {
2 ..1 + 1;
3 ..z = 2;
4 x = false..1 == 1;
5 let x = 1..;
6}
diff --git a/crates/libsyntax2/tests/data/parser/ok/0029_range_forms.txt b/crates/libsyntax2/tests/data/parser/ok/0029_range_forms.txt
new file mode 100644
index 000000000..91d5e5bba
--- /dev/null
+++ b/crates/libsyntax2/tests/data/parser/ok/0029_range_forms.txt
@@ -0,0 +1,83 @@
1FILE@[0; 79)
2 FUNCTION@[0; 78)
3 FN_KW@[0; 2)
4 WHITESPACE@[2; 3)
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9)
11 BLOCK_EXPR@[9; 78)
12 L_CURLY@[9; 10)
13 WHITESPACE@[10; 15)
14 EXPR_STMT@[15; 23)
15 RANGE_EXPR@[15; 22)
16 DOTDOT@[15; 17)
17 BIN_EXPR@[17; 22)
18 LITERAL@[17; 18)
19 INT_NUMBER@[17; 18) "1"
20 WHITESPACE@[18; 19)
21 PLUS@[19; 20)
22 WHITESPACE@[20; 21)
23 LITERAL@[21; 22)
24 INT_NUMBER@[21; 22) "1"
25 SEMI@[22; 23)
26 WHITESPACE@[23; 28)
27 EXPR_STMT@[28; 36)
28 BIN_EXPR@[28; 35)
29 RANGE_EXPR@[28; 31)
30 DOTDOT@[28; 30)
31 PATH_EXPR@[30; 31)
32 PATH@[30; 31)
33 PATH_SEGMENT@[30; 31)
34 NAME_REF@[30; 31)
35 IDENT@[30; 31) "z"
36 WHITESPACE@[31; 32)
37 EQ@[32; 33)
38 WHITESPACE@[33; 34)
39 LITERAL@[34; 35)
40 INT_NUMBER@[34; 35) "2"
41 SEMI@[35; 36)
42 WHITESPACE@[36; 41)
43 EXPR_STMT@[41; 59)
44 BIN_EXPR@[41; 58)
45 PATH_EXPR@[41; 42)
46 PATH@[41; 42)
47 PATH_SEGMENT@[41; 42)
48 NAME_REF@[41; 42)
49 IDENT@[41; 42) "x"
50 WHITESPACE@[42; 43)
51 EQ@[43; 44)
52 WHITESPACE@[44; 45)
53 RANGE_EXPR@[45; 58)
54 LITERAL@[45; 50)
55 FALSE_KW@[45; 50)
56 DOTDOT@[50; 52)
57 BIN_EXPR@[52; 58)
58 LITERAL@[52; 53)
59 INT_NUMBER@[52; 53) "1"
60 WHITESPACE@[53; 54)
61 EQEQ@[54; 56)
62 WHITESPACE@[56; 57)
63 LITERAL@[57; 58)
64 INT_NUMBER@[57; 58) "1"
65 SEMI@[58; 59)
66 WHITESPACE@[59; 64)
67 LET_STMT@[64; 76)
68 LET_KW@[64; 67)
69 WHITESPACE@[67; 68)
70 BIND_PAT@[68; 69)
71 NAME@[68; 69)
72 IDENT@[68; 69) "x"
73 WHITESPACE@[69; 70)
74 EQ@[70; 71)
75 WHITESPACE@[71; 72)
76 RANGE_EXPR@[72; 75)
77 LITERAL@[72; 73)
78 INT_NUMBER@[72; 73) "1"
79 DOTDOT@[73; 75)
80 SEMI@[75; 76)
81 WHITESPACE@[76; 77)
82 R_CURLY@[77; 78)
83 WHITESPACE@[78; 79)
diff --git a/crates/libsyntax2/tests/lexer.rs b/crates/libsyntax2/tests/lexer.rs
new file mode 100644
index 000000000..46ac9fedd
--- /dev/null
+++ b/crates/libsyntax2/tests/lexer.rs
@@ -0,0 +1,28 @@
1extern crate libsyntax2;
2extern crate testutils;
3
4use std::fmt::Write;
5
6use libsyntax2::{tokenize, Token};
7use testutils::dir_tests;
8
9#[test]
10fn lexer_tests() {
11 dir_tests(&["lexer"], |text| {
12 let tokens = tokenize(text);
13 dump_tokens(&tokens, text)
14 })
15}
16
17fn dump_tokens(tokens: &[Token], text: &str) -> String {
18 let mut acc = String::new();
19 let mut offset = 0;
20 for token in tokens {
21 let len: u32 = token.len.into();
22 let len = len as usize;
23 let token_text = &text[offset..offset + len];
24 offset += len;
25 write!(acc, "{:?} {} {:?}\n", token.kind, token.len, token_text).unwrap()
26 }
27 acc
28}
diff --git a/crates/libsyntax2/tests/parser.rs b/crates/libsyntax2/tests/parser.rs
new file mode 100644
index 000000000..af2ae11bb
--- /dev/null
+++ b/crates/libsyntax2/tests/parser.rs
@@ -0,0 +1,14 @@
1extern crate libsyntax2;
2extern crate testutils;
3
4use libsyntax2::parse;
5use libsyntax2::utils::dump_tree;
6use testutils::dir_tests;
7
8#[test]
9fn parser_tests() {
10 dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| {
11 let file = parse(text);
12 dump_tree(&file)
13 })
14}
diff --git a/crates/libsyntax2/tests/testutils/Cargo.toml b/crates/libsyntax2/tests/testutils/Cargo.toml
new file mode 100644
index 000000000..53b20f17b
--- /dev/null
+++ b/crates/libsyntax2/tests/testutils/Cargo.toml
@@ -0,0 +1,7 @@
1[package]
2name = "testutils"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5
6[dependencies]
7difference = "2.0.0"
diff --git a/crates/libsyntax2/tests/testutils/src/lib.rs b/crates/libsyntax2/tests/testutils/src/lib.rs
new file mode 100644
index 000000000..39c821661
--- /dev/null
+++ b/crates/libsyntax2/tests/testutils/src/lib.rs
@@ -0,0 +1,111 @@
1extern crate difference;
2
3use std::{
4 fs,
5 path::{Path, PathBuf},
6};
7
8use difference::Changeset;
9
10/// Read file and normalize newlines.
11///
12/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
13///
14/// ```
15/// let s = "
16/// ";
17/// assert_eq!(s.as_bytes(), &[10]);
18/// ```
19///
20/// so this should always be correct.
21fn read_text(path: &Path) -> String {
22 fs::read_to_string(path).unwrap().replace("\r\n", "\n")
23}
24
25pub fn dir_tests<F>(paths: &[&str], f: F)
26where
27 F: Fn(&str) -> String,
28{
29 for path in collect_tests(paths) {
30 let input_code = read_text(&path);
31 let parse_tree = f(&input_code);
32 let path = path.with_extension("txt");
33 if !path.exists() {
34 println!("\nfile: {}", path.display());
35 println!("No .txt file with expected result, creating...\n");
36 println!("{}\n{}", input_code, parse_tree);
37 fs::write(&path, parse_tree).unwrap();
38 panic!("No expected result")
39 }
40 let expected = read_text(&path);
41 let expected = expected.as_str();
42 let parse_tree = parse_tree.as_str();
43 assert_equal_text(expected, parse_tree, &path);
44 }
45}
46
47fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
48 if expected != actual {
49 print_difference(expected, actual, path)
50 }
51}
52
53fn collect_tests(paths: &[&str]) -> Vec<PathBuf> {
54 paths
55 .iter()
56 .flat_map(|path| {
57 let path = test_data_dir().join(path);
58 test_from_dir(&path).into_iter()
59 })
60 .collect()
61}
62
63fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
64 let mut acc = Vec::new();
65 for file in fs::read_dir(&dir).unwrap() {
66 let file = file.unwrap();
67 let path = file.path();
68 if path.extension().unwrap_or_default() == "rs" {
69 acc.push(path);
70 }
71 }
72 acc.sort();
73 acc
74}
75
76const REWRITE: bool = false;
77
78fn print_difference(expected: &str, actual: &str, path: &Path) {
79 let dir = project_dir();
80 let path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
81 if expected.trim() == actual.trim() {
82 println!("whitespace difference, rewriting");
83 println!("file: {}\n", path.display());
84 fs::write(path, actual).unwrap();
85 return;
86 }
87 if REWRITE {
88 println!("rewriting {}", path.display());
89 fs::write(path, actual).unwrap();
90 return;
91 }
92 let changeset = Changeset::new(actual, expected, "\n");
93 println!("Expected:\n{}\n\nActual:\n{}\n", expected, actual);
94 print!("{}", changeset);
95 println!("file: {}\n", path.display());
96 panic!("Comparison failed")
97}
98
99fn project_dir() -> PathBuf {
100 let dir = env!("CARGO_MANIFEST_DIR");
101 PathBuf::from(dir)
102 .parent()
103 .unwrap()
104 .parent()
105 .unwrap()
106 .to_owned()
107}
108
109fn test_data_dir() -> PathBuf {
110 project_dir().join("tests/data")
111}
diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml
new file mode 100644
index 000000000..e6d1b18c3
--- /dev/null
+++ b/crates/server/Cargo.toml
@@ -0,0 +1,18 @@
1[package]
2name = "m"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5
6[dependencies]
7failure = "0.1.2"
8languageserver-types = "0.48.0"
9serde_json = "1.0.24"
10serde = "1.0.71"
11serde_derive = "1.0.71"
12drop_bomb = "0.1.0"
13crossbeam-channel = "0.2.4"
14threadpool = "1.7.1"
15flexi_logger = "0.9.0"
16log = "0.4.3"
17libeditor = { path = "../libeditor" }
18libanalysis = { path = "../libanalysis" }
diff --git a/crates/server/src/caps.rs b/crates/server/src/caps.rs
new file mode 100644
index 000000000..3d89c64a9
--- /dev/null
+++ b/crates/server/src/caps.rs
@@ -0,0 +1,36 @@
1use languageserver_types::{
2 ServerCapabilities,
3 TextDocumentSyncCapability,
4 TextDocumentSyncOptions,
5 TextDocumentSyncKind,
6};
7
8pub const SERVER_CAPABILITIES: ServerCapabilities = ServerCapabilities {
9 text_document_sync: Some(TextDocumentSyncCapability::Options(
10 TextDocumentSyncOptions {
11 open_close: Some(true),
12 change: Some(TextDocumentSyncKind::Full),
13 will_save: None,
14 will_save_wait_until: None,
15 save: None,
16 }
17 )),
18 hover_provider: None,
19 completion_provider: None,
20 signature_help_provider: None,
21 definition_provider: None,
22 type_definition_provider: None,
23 implementation_provider: None,
24 references_provider: None,
25 document_highlight_provider: None,
26 document_symbol_provider: None,
27 workspace_symbol_provider: None,
28 code_action_provider: None,
29 code_lens_provider: None,
30 document_formatting_provider: None,
31 document_range_formatting_provider: None,
32 document_on_type_formatting_provider: None,
33 rename_provider: None,
34 color_provider: None,
35 execute_command_provider: None,
36};
diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs
new file mode 100644
index 000000000..2da0996e3
--- /dev/null
+++ b/crates/server/src/dispatch.rs
@@ -0,0 +1,174 @@
1use std::marker::PhantomData;
2
3use serde::{
4 ser::Serialize,
5 de::DeserializeOwned,
6};
7use serde_json;
8use drop_bomb::DropBomb;
9
10use ::{
11 Result,
12 req::{Request, Notification},
13 io::{Io, RawMsg, RawResponse, RawRequest, RawNotification},
14};
15
16pub struct Responder<R: Request> {
17 id: u64,
18 bomb: DropBomb,
19 ph: PhantomData<R>,
20}
21
22impl<R: Request> Responder<R>
23 where
24 R::Params: DeserializeOwned,
25 R::Result: Serialize,
26{
27 pub fn response(self, io: &mut Io, resp: Result<R::Result>) -> Result<()> {
28 match resp {
29 Ok(res) => self.result(io, res)?,
30 Err(e) => {
31 self.error(io)?;
32 return Err(e);
33 }
34 }
35 Ok(())
36 }
37
38 pub fn result(mut self, io: &mut Io, result: R::Result) -> Result<()> {
39 self.bomb.defuse();
40 io.send(RawMsg::Response(RawResponse {
41 id: Some(self.id),
42 result: serde_json::to_value(result)?,
43 error: serde_json::Value::Null,
44 }));
45 Ok(())
46 }
47
48 pub fn error(mut self, io: &mut Io) -> Result<()> {
49 self.bomb.defuse();
50 error(io, self.id, ErrorCode::InternalError, "internal error")
51 }
52}
53
54
55fn parse_request_as<R>(raw: RawRequest) -> Result<::std::result::Result<(R::Params, Responder<R>), RawRequest>>
56 where
57 R: Request,
58 R::Params: DeserializeOwned,
59 R::Result: Serialize,
60{
61 if raw.method != R::METHOD {
62 return Ok(Err(raw));
63 }
64
65 let params: R::Params = serde_json::from_value(raw.params)?;
66 let responder = Responder {
67 id: raw.id,
68 bomb: DropBomb::new("dropped request"),
69 ph: PhantomData,
70 };
71 Ok(Ok((params, responder)))
72}
73
74pub fn handle_request<R, F>(req: &mut Option<RawRequest>, f: F) -> Result<()>
75 where
76 R: Request,
77 R::Params: DeserializeOwned,
78 R::Result: Serialize,
79 F: FnOnce(R::Params, Responder<R>) -> Result<()>
80{
81 match req.take() {
82 None => Ok(()),
83 Some(r) => match parse_request_as::<R>(r)? {
84 Ok((params, responder)) => f(params, responder),
85 Err(r) => {
86 *req = Some(r);
87 Ok(())
88 },
89 }
90 }
91}
92
93pub fn expect_request<R>(io: &mut Io, raw: RawRequest) -> Result<Option<(R::Params, Responder<R>)>>
94 where
95 R: Request,
96 R::Params: DeserializeOwned,
97 R::Result: Serialize,
98{
99 let ret = match parse_request_as::<R>(raw)? {
100 Ok(x) => Some(x),
101 Err(raw) => {
102 unknown_method(io, raw)?;
103 None
104 }
105 };
106 Ok(ret)
107}
108
109fn parse_notification_as<N>(raw: RawNotification) -> Result<::std::result::Result<N::Params, RawNotification>>
110 where
111 N: Notification,
112 N::Params: DeserializeOwned,
113{
114 if raw.method != N::METHOD {
115 return Ok(Err(raw));
116 }
117 let params: N::Params = serde_json::from_value(raw.params)?;
118 Ok(Ok(params))
119}
120
121pub fn handle_notification<N, F>(not: &mut Option<RawNotification>, f: F) -> Result<()>
122 where
123 N: Notification,
124 N::Params: DeserializeOwned,
125 F: FnOnce(N::Params) -> Result<()>
126{
127 match not.take() {
128 None => Ok(()),
129 Some(n) => match parse_notification_as::<N>(n)? {
130 Ok(params) => f(params),
131 Err(n) => {
132 *not = Some(n);
133 Ok(())
134 },
135 }
136 }
137}
138
139
140pub fn unknown_method(io: &mut Io, raw: RawRequest) -> Result<()> {
141 error(io, raw.id, ErrorCode::MethodNotFound, "unknown method")
142}
143
144fn error(io: &mut Io, id: u64, code: ErrorCode, message: &'static str) -> Result<()> {
145 #[derive(Serialize)]
146 struct Error {
147 code: i32,
148 message: &'static str,
149 }
150 io.send(RawMsg::Response(RawResponse {
151 id: Some(id),
152 result: serde_json::Value::Null,
153 error: serde_json::to_value(Error {
154 code: code as i32,
155 message,
156 })?,
157 }));
158 Ok(())
159}
160
161
162#[allow(unused)]
163enum ErrorCode {
164 ParseError = -32700,
165 InvalidRequest = -32600,
166 MethodNotFound = -32601,
167 InvalidParams = -32602,
168 InternalError = -32603,
169 ServerErrorStart = -32099,
170 ServerErrorEnd = -32000,
171 ServerNotInitialized = -32002,
172 UnknownErrorCode = -32001,
173 RequestCancelled = -32800,
174}
diff --git a/crates/server/src/handlers.rs b/crates/server/src/handlers.rs
new file mode 100644
index 000000000..5ee87a4dd
--- /dev/null
+++ b/crates/server/src/handlers.rs
@@ -0,0 +1,61 @@
1use languageserver_types::{Range, Position};
2use libanalysis::World;
3use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};
4use {req, Result, FilePath};
5
6pub fn handle_syntax_tree(
7 world: World,
8 params: req::SyntaxTreeParams,
9) -> Result<String> {
10 let path = params.text_document.file_path()?;
11 let file = world.file_syntax(&path)?;
12 Ok(libeditor::syntax_tree(&file))
13}
14
15pub fn handle_extend_selection(
16 world: World,
17 params: req::ExtendSelectionParams,
18) -> Result<req::ExtendSelectionResult> {
19 let path = params.text_document.file_path()?;
20 let file = world.file_syntax(&path)?;
21 let line_index = world.file_line_index(&path)?;
22 let selections = params.selections.into_iter()
23 .map(|r| {
24 let r = to_text_range(&line_index, r);
25 let r = libeditor::extend_selection(&file, r).unwrap_or(r);
26 to_vs_range(&line_index, r)
27 })
28 .collect();
29 Ok(req::ExtendSelectionResult { selections })
30}
31
32
33fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange {
34 TextRange::from_to(
35 to_text_unit(line_index, range.start),
36 to_text_unit(line_index, range.end),
37 )
38}
39
40fn to_text_unit(line_index: &LineIndex, position: Position) -> TextUnit {
41 // TODO: UTF-16
42 let line_col = LineCol {
43 line: position.line as u32,
44 col: (position.character as u32).into(),
45 };
46 line_index.offset(line_col)
47}
48
49
50fn to_vs_range(line_index: &LineIndex, range: TextRange) -> Range {
51 Range::new(
52 to_vs_position(line_index, range.start()),
53 to_vs_position(line_index, range.end()),
54 )
55}
56
57fn to_vs_position(line_index: &LineIndex, offset: TextUnit) -> Position {
58 let line_col = line_index.line_col(offset);
59 // TODO: UTF-16
60 Position::new(line_col.line as u64, u32::from(line_col.col) as u64)
61}
diff --git a/crates/server/src/io.rs b/crates/server/src/io.rs
new file mode 100644
index 000000000..5eafc6942
--- /dev/null
+++ b/crates/server/src/io.rs
@@ -0,0 +1,202 @@
1use std::{
2 thread,
3 io::{
4 stdout, stdin,
5 BufRead, Write,
6 },
7};
8use serde_json::{Value, from_str, to_string};
9use crossbeam_channel::{Receiver, Sender, bounded};
10
11use Result;
12
13
14#[derive(Debug, Serialize, Deserialize)]
15#[serde(untagged)]
16pub enum RawMsg {
17 Request(RawRequest),
18 Notification(RawNotification),
19 Response(RawResponse),
20}
21
22#[derive(Debug, Serialize, Deserialize)]
23pub struct RawRequest {
24 pub id: u64,
25 pub method: String,
26 pub params: Value,
27}
28
29#[derive(Debug, Serialize, Deserialize)]
30pub struct RawNotification {
31 pub method: String,
32 pub params: Value,
33}
34
35#[derive(Debug, Serialize, Deserialize)]
36pub struct RawResponse {
37 pub id: Option<u64>,
38 pub result: Value,
39 pub error: Value,
40}
41
42struct MsgReceiver {
43 chan: Receiver<RawMsg>,
44 thread: Option<thread::JoinHandle<Result<()>>>,
45}
46
47impl MsgReceiver {
48 fn recv(&mut self) -> Result<RawMsg> {
49 match self.chan.recv() {
50 Some(msg) => Ok(msg),
51 None => {
52 self.cleanup()?;
53 unreachable!()
54 }
55 }
56 }
57
58 fn cleanup(&mut self) -> Result<()> {
59 self.thread
60 .take()
61 .ok_or_else(|| format_err!("MsgReceiver thread panicked"))?
62 .join()
63 .map_err(|_| format_err!("MsgReceiver thread panicked"))??;
64 bail!("client disconnected")
65 }
66
67 fn stop(self) -> Result<()> {
68 // Can't really self.thread.join() here, b/c it might be
69 // blocking on read
70 Ok(())
71 }
72}
73
74struct MsgSender {
75 chan: Sender<RawMsg>,
76 thread: thread::JoinHandle<Result<()>>,
77}
78
79impl MsgSender {
80 fn send(&mut self, msg: RawMsg) {
81 self.chan.send(msg)
82 }
83
84 fn stop(self) -> Result<()> {
85 drop(self.chan);
86 self.thread.join()
87 .map_err(|_| format_err!("MsgSender thread panicked"))??;
88 Ok(())
89 }
90}
91
92pub struct Io {
93 receiver: MsgReceiver,
94 sender: MsgSender,
95}
96
97impl Io {
98 pub fn from_stdio() -> Io {
99 let sender = {
100 let (tx, rx) = bounded(16);
101 MsgSender {
102 chan: tx,
103 thread: thread::spawn(move || {
104 let stdout = stdout();
105 let mut stdout = stdout.lock();
106 for msg in rx {
107 #[derive(Serialize)]
108 struct JsonRpc {
109 jsonrpc: &'static str,
110 #[serde(flatten)]
111 msg: RawMsg,
112 }
113 let text = to_string(&JsonRpc {
114 jsonrpc: "2.0",
115 msg,
116 })?;
117 write_msg_text(&mut stdout, &text)?;
118 }
119 Ok(())
120 }),
121 }
122 };
123 let receiver = {
124 let (tx, rx) = bounded(16);
125 MsgReceiver {
126 chan: rx,
127 thread: Some(thread::spawn(move || {
128 let stdin = stdin();
129 let mut stdin = stdin.lock();
130 while let Some(text) = read_msg_text(&mut stdin)? {
131 let msg: RawMsg = from_str(&text)?;
132 tx.send(msg);
133 }
134 Ok(())
135 })),
136 }
137 };
138 Io { receiver, sender }
139 }
140
141 pub fn send(&mut self, msg: RawMsg) {
142 self.sender.send(msg)
143 }
144
145 pub fn recv(&mut self) -> Result<RawMsg> {
146 self.receiver.recv()
147 }
148
149 pub fn receiver(&mut self) -> &mut Receiver<RawMsg> {
150 &mut self.receiver.chan
151 }
152
153 pub fn cleanup_receiver(&mut self) -> Result<()> {
154 self.receiver.cleanup()
155 }
156
157 pub fn stop(self) -> Result<()> {
158 self.receiver.stop()?;
159 self.sender.stop()?;
160 Ok(())
161 }
162}
163
164
165fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> {
166 let mut size = None;
167 let mut buf = String::new();
168 loop {
169 buf.clear();
170 if inp.read_line(&mut buf)? == 0 {
171 return Ok(None);
172 }
173 if !buf.ends_with("\r\n") {
174 bail!("malformed header: {:?}", buf);
175 }
176 let buf = &buf[..buf.len() - 2];
177 if buf.is_empty() {
178 break;
179 }
180 let mut parts = buf.splitn(2, ": ");
181 let header_name = parts.next().unwrap();
182 let header_value = parts.next().ok_or_else(|| format_err!("malformed header: {:?}", buf))?;
183 if header_name == "Content-Length" {
184 size = Some(header_value.parse::<usize>()?);
185 }
186 }
187 let size = size.ok_or_else(|| format_err!("no Content-Length"))?;
188 let mut buf = buf.into_bytes();
189 buf.resize(size, 0);
190 inp.read_exact(&mut buf)?;
191 let buf = String::from_utf8(buf)?;
192 debug!("< {}", buf);
193 Ok(Some(buf))
194}
195
196fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> {
197 debug!("> {}", msg);
198 write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
199 out.write_all(msg.as_bytes())?;
200 out.flush()?;
201 Ok(())
202}
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs
new file mode 100644
index 000000000..116abce1c
--- /dev/null
+++ b/crates/server/src/main.rs
@@ -0,0 +1,249 @@
1#[macro_use]
2extern crate failure;
3#[macro_use]
4extern crate serde_derive;
5extern crate serde;
6extern crate serde_json;
7extern crate languageserver_types;
8extern crate drop_bomb;
9#[macro_use]
10extern crate crossbeam_channel;
11extern crate threadpool;
12#[macro_use]
13extern crate log;
14extern crate flexi_logger;
15extern crate libeditor;
16extern crate libanalysis;
17
18mod io;
19mod caps;
20mod req;
21mod dispatch;
22mod handlers;
23
24use std::path::PathBuf;
25
26use threadpool::ThreadPool;
27use crossbeam_channel::{bounded, Sender, Receiver};
28use flexi_logger::Logger;
29use libanalysis::WorldState;
30use languageserver_types::{TextDocumentItem, VersionedTextDocumentIdentifier, TextDocumentIdentifier};
31
32use ::{
33 io::{Io, RawMsg},
34 handlers::{handle_syntax_tree, handle_extend_selection},
35};
36
37pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
38
39fn main() -> Result<()> {
40 Logger::with_env_or_str("m=trace, libanalysis=trace")
41 .log_to_file()
42 .directory("log")
43 .start()?;
44 info!("starting server");
45 match ::std::panic::catch_unwind(|| main_inner()) {
46 Ok(res) => {
47 info!("shutting down: {:?}", res);
48 res
49 }
50 Err(_) => {
51 error!("server panicked");
52 bail!("server panicked")
53 }
54 }
55}
56
57fn main_inner() -> Result<()> {
58 let mut io = Io::from_stdio();
59 let res = initialize(&mut io);
60 info!("shutting down IO...");
61 let io_res = io.stop();
62 info!("... IO is down");
63 match (res, io_res) {
64 (Ok(()), Ok(())) => Ok(()),
65 (res, Ok(())) => res,
66 (Ok(()), io_res) => io_res,
67 (res, Err(io_err)) => {
68 error!("shutdown error: {:?}", io_err);
69 res
70 }
71 }
72}
73
74fn initialize(io: &mut Io) -> Result<()> {
75 loop {
76 match io.recv()? {
77 RawMsg::Request(req) => {
78 if let Some((_params, resp)) = dispatch::expect_request::<req::Initialize>(io, req)? {
79 resp.result(io, req::InitializeResult {
80 capabilities: caps::SERVER_CAPABILITIES
81 })?;
82 match io.recv()? {
83 RawMsg::Notification(n) => {
84 if n.method != "initialized" {
85 bail!("expected initialized notification");
86 }
87 }
88 _ => {
89 bail!("expected initialized notification");
90 }
91 }
92 return initialized(io);
93 }
94 }
95 RawMsg::Notification(n) => {
96 bail!("expected initialize request, got {:?}", n)
97 }
98 RawMsg::Response(res) => {
99 bail!("expected initialize request, got {:?}", res)
100 }
101 }
102 }
103}
104
105type Thunk = Box<for<'a> FnBox<&'a mut Io, Result<()>>>;
106
107fn initialized(io: &mut Io) -> Result<()> {
108 let mut world = WorldState::new();
109 let mut pool = ThreadPool::new(4);
110 let (sender, receiver) = bounded::<Thunk>(16);
111 let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone());
112 info!("waiting for background jobs to finish...");
113 receiver.for_each(drop);
114 pool.join();
115 info!("...background jobs have finished");
116 res
117}
118
119fn main_loop(
120 io: &mut Io,
121 world: &mut WorldState,
122 pool: &mut ThreadPool,
123 sender: Sender<Thunk>,
124 receiver: Receiver<Thunk>,
125) -> Result<()> {
126 info!("server initialized, serving requests");
127 loop {
128 enum Event {
129 Msg(RawMsg),
130 Thunk(Thunk),
131 ReceiverDead,
132 }
133
134 let event = select! {
135 recv(io.receiver(), msg) => match msg {
136 Some(msg) => Event::Msg(msg),
137 None => Event::ReceiverDead,
138 },
139 recv(receiver, thunk) => Event::Thunk(thunk.unwrap()),
140 };
141
142 let msg = match event {
143 Event::ReceiverDead => {
144 io.cleanup_receiver()?;
145 unreachable!();
146 }
147 Event::Thunk(thunk) => {
148 thunk.call_box(io)?;
149 continue;
150 }
151 Event::Msg(msg) => msg,
152 };
153
154 match msg {
155 RawMsg::Request(req) => {
156 let mut req = Some(req);
157 dispatch::handle_request::<req::SyntaxTree, _>(&mut req, |params, resp| {
158 let world = world.snapshot();
159 let sender = sender.clone();
160 pool.execute(move || {
161 let res = handle_syntax_tree(world, params);
162 sender.send(Box::new(|io: &mut Io| resp.response(io, res)))
163 });
164 Ok(())
165 })?;
166 dispatch::handle_request::<req::ExtendSelection, _>(&mut req, |params, resp| {
167 let world = world.snapshot();
168 let sender = sender.clone();
169 pool.execute(move || {
170 let res = handle_extend_selection(world, params);
171 sender.send(Box::new(|io: &mut Io| resp.response(io, res)))
172 });
173 Ok(())
174 })?;
175 dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
176 resp.result(io, ())?;
177 Ok(())
178 })?;
179 if let Some(req) = req {
180 error!("unknown method: {:?}", req);
181 dispatch::unknown_method(io, req)?;
182 }
183 }
184 RawMsg::Notification(not) => {
185 let mut not = Some(not);
186 dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| {
187 let path = params.text_document.file_path()?;
188 world.change_overlay(path, Some(params.text_document.text));
189 Ok(())
190 })?;
191 dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| {
192 let path = params.text_document.file_path()?;
193 let text = params.content_changes.pop()
194 .ok_or_else(|| format_err!("empty changes"))?
195 .text;
196 world.change_overlay(path, Some(text));
197 Ok(())
198 })?;
199 dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| {
200 let path = params.text_document.file_path()?;
201 world.change_overlay(path, None);
202 Ok(())
203 })?;
204
205 if let Some(not) = not {
206 error!("unhandled notification: {:?}", not)
207 }
208 }
209 msg => {
210 eprintln!("msg = {:?}", msg);
211 }
212 }
213 }
214}
215
216trait FnBox<A, R>: Send {
217 fn call_box(self: Box<Self>, a: A) -> R;
218}
219
220impl<A, R, F: FnOnce(A) -> R + Send> FnBox<A, R> for F {
221 fn call_box(self: Box<F>, a: A) -> R {
222 (*self)(a)
223 }
224}
225
226trait FilePath {
227 fn file_path(&self) -> Result<PathBuf>;
228}
229
230impl FilePath for TextDocumentItem {
231 fn file_path(&self) -> Result<PathBuf> {
232 self.uri.to_file_path()
233 .map_err(|()| format_err!("invalid uri: {}", self.uri))
234 }
235}
236
237impl FilePath for VersionedTextDocumentIdentifier {
238 fn file_path(&self) -> Result<PathBuf> {
239 self.uri.to_file_path()
240 .map_err(|()| format_err!("invalid uri: {}", self.uri))
241 }
242}
243
244impl FilePath for TextDocumentIdentifier {
245 fn file_path(&self) -> Result<PathBuf> {
246 self.uri.to_file_path()
247 .map_err(|()| format_err!("invalid uri: {}", self.uri))
248 }
249}
diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs
new file mode 100644
index 000000000..4e588159b
--- /dev/null
+++ b/crates/server/src/req.rs
@@ -0,0 +1,41 @@
1use languageserver_types::{TextDocumentIdentifier, Range};
2
3pub use languageserver_types::{
4 request::*, notification::*,
5 InitializeResult,
6};
7
8pub enum SyntaxTree {}
9
10impl Request for SyntaxTree {
11 type Params = SyntaxTreeParams;
12 type Result = String;
13 const METHOD: &'static str = "m/syntaxTree";
14}
15
16#[derive(Deserialize, Debug)]
17#[serde(rename_all = "camelCase")]
18pub struct SyntaxTreeParams {
19 pub text_document: TextDocumentIdentifier
20}
21
22pub enum ExtendSelection {}
23
24impl Request for ExtendSelection {
25 type Params = ExtendSelectionParams;
26 type Result = ExtendSelectionResult;
27 const METHOD: &'static str = "m/extendSelection";
28}
29
30#[derive(Deserialize, Debug)]
31#[serde(rename_all = "camelCase")]
32pub struct ExtendSelectionParams {
33 pub text_document: TextDocumentIdentifier,
34 pub selections: Vec<Range>,
35}
36
37#[derive(Serialize, Debug)]
38#[serde(rename_all = "camelCase")]
39pub struct ExtendSelectionResult {
40 pub selections: Vec<Range>,
41}
diff --git a/crates/tools/Cargo.toml b/crates/tools/Cargo.toml
new file mode 100644
index 000000000..f9fee16f9
--- /dev/null
+++ b/crates/tools/Cargo.toml
@@ -0,0 +1,14 @@
1[package]
2name = "tools"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5publish = false
6
7[dependencies]
8ron = "0.1.7"
9walkdir = "2.1.3"
10itertools = "0.7.8"
11tera = "0.11"
12clap = "2.32.0"
13failure = "0.1.1"
14commandspec = "0.10"
diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs
new file mode 100644
index 000000000..97a56a31f
--- /dev/null
+++ b/crates/tools/src/lib.rs
@@ -0,0 +1,43 @@
1extern crate itertools;
2
3use itertools::Itertools;
4
5#[derive(Debug)]
6pub struct Test {
7 pub name: String,
8 pub text: String,
9}
10
11pub fn collect_tests(s: &str) -> Vec<(usize, Test)> {
12 let mut res = vec![];
13 let prefix = "// ";
14 let comment_blocks = s
15 .lines()
16 .map(str::trim_left)
17 .enumerate()
18 .group_by(|(_idx, line)| line.starts_with(prefix));
19
20 'outer: for (is_comment, block) in comment_blocks.into_iter() {
21 if !is_comment {
22 continue;
23 }
24 let mut block = block.map(|(idx, line)| (idx, &line[prefix.len()..]));
25
26 let (start_line, name) = loop {
27 match block.next() {
28 Some((idx, line)) if line.starts_with("test ") => {
29 break (idx, line["test ".len()..].to_string())
30 }
31 Some(_) => (),
32 None => continue 'outer,
33 }
34 };
35 let text: String = itertools::join(
36 block.map(|(_, line)| line).chain(::std::iter::once("")),
37 "\n",
38 );
39 assert!(!text.trim().is_empty() && text.ends_with("\n"));
40 res.push((start_line, Test { name, text }))
41 }
42 res
43}
diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs
new file mode 100644
index 000000000..d42d3ecb7
--- /dev/null
+++ b/crates/tools/src/main.rs
@@ -0,0 +1,216 @@
1extern crate clap;
2#[macro_use]
3extern crate failure;
4extern crate ron;
5extern crate tera;
6extern crate tools;
7extern crate walkdir;
8#[macro_use]
9extern crate commandspec;
10
11use clap::{App, Arg, SubCommand};
12use std::{
13 collections::HashMap,
14 fs,
15 path::{Path, PathBuf},
16};
17use tools::{collect_tests, Test};
18
19type Result<T> = ::std::result::Result<T, failure::Error>;
20
21const GRAMMAR_DIR: &str = "./crates/libsyntax2/src/grammar";
22const INLINE_TESTS_DIR: &str = "./crates/libsyntax2/tests/data/parser/inline";
23const GRAMMAR: &str = "./crates/libsyntax2/src/grammar.ron";
24const SYNTAX_KINDS: &str = "./crates/libsyntax2/src/syntax_kinds/generated.rs";
25const SYNTAX_KINDS_TEMPLATE: &str = "./crates/libsyntax2/src/syntax_kinds/generated.rs.tera";
26const AST: &str = "./crates/libsyntax2/src/ast/generated.rs";
27const AST_TEMPLATE: &str = "./crates/libsyntax2/src/ast/generated.rs.tera";
28
29fn main() -> Result<()> {
30 let matches = App::new("tasks")
31 .setting(clap::AppSettings::SubcommandRequiredElseHelp)
32 .arg(
33 Arg::with_name("verify")
34 .long("--verify")
35 .help("Verify that generated code is up-to-date")
36 .global(true),
37 )
38 .subcommand(SubCommand::with_name("gen-kinds"))
39 .subcommand(SubCommand::with_name("gen-tests"))
40 .subcommand(SubCommand::with_name("install-code"))
41 .get_matches();
42 match matches.subcommand() {
43 ("install-code", _) => install_code_extension()?,
44 (name, Some(matches)) => run_gen_command(name, matches.is_present("verify"))?,
45 _ => unreachable!(),
46 }
47 Ok(())
48}
49
50fn run_gen_command(name: &str, verify: bool) -> Result<()> {
51 match name {
52 "gen-kinds" => {
53 update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE)?, verify)?;
54 update(Path::new(AST), &render_template(AST_TEMPLATE)?, verify)?;
55 },
56 "gen-tests" => {
57 gen_tests(verify)?
58 },
59 _ => unreachable!(),
60 }
61 Ok(())
62}
63
64fn update(path: &Path, contents: &str, verify: bool) -> Result<()> {
65 match fs::read_to_string(path) {
66 Ok(ref old_contents) if old_contents == contents => {
67 return Ok(());
68 }
69 _ => (),
70 }
71 if verify {
72 bail!("`{}` is not up-to-date", path.display());
73 }
74 eprintln!("updating {}", path.display());
75 fs::write(path, contents)?;
76 Ok(())
77}
78
79fn render_template(template: &str) -> Result<String> {
80 let grammar: ron::value::Value = {
81 let text = fs::read_to_string(GRAMMAR)?;
82 ron::de::from_str(&text)?
83 };
84 let template = fs::read_to_string(template)?;
85 let mut tera = tera::Tera::default();
86 tera.add_raw_template("grammar", &template)
87 .map_err(|e| format_err!("template error: {:?}", e))?;
88 tera.register_global_function("concat", Box::new(concat));
89 tera.register_filter("camel", |arg, _| {
90 Ok(arg.as_str().unwrap()
91 .split("_")
92 .flat_map(|word| {
93 word.chars()
94 .next().unwrap()
95 .to_uppercase()
96 .chain(
97 word.chars().skip(1).flat_map(|c| c.to_lowercase())
98 )
99 })
100 .collect::<String>()
101 .into())
102 });
103 let ret = tera
104 .render("grammar", &grammar)
105 .map_err(|e| format_err!("template error: {:?}", e))?;
106 return Ok(ret);
107
108 fn concat(args: HashMap<String, tera::Value>) -> tera::Result<tera::Value> {
109 let mut elements = Vec::new();
110 for &key in ["a", "b", "c"].iter() {
111 let val = match args.get(key) {
112 Some(val) => val,
113 None => continue,
114 };
115 let val = val.as_array().unwrap();
116 elements.extend(val.iter().cloned());
117 }
118 Ok(tera::Value::Array(elements))
119 }
120}
121
122fn gen_tests(verify: bool) -> Result<()> {
123 let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?;
124
125 let inline_tests_dir = Path::new(INLINE_TESTS_DIR);
126 if !inline_tests_dir.is_dir() {
127 fs::create_dir_all(inline_tests_dir)?;
128 }
129 let existing = existing_tests(inline_tests_dir)?;
130
131 for t in existing.keys().filter(|&t| !tests.contains_key(t)) {
132 panic!("Test is deleted: {}", t);
133 }
134
135 let mut new_idx = existing.len() + 2;
136 for (name, test) in tests {
137 let path = match existing.get(&name) {
138 Some((path, _test)) => path.clone(),
139 None => {
140 let file_name = format!("{:04}_{}.rs", new_idx, name);
141 new_idx += 1;
142 inline_tests_dir.join(file_name)
143 }
144 };
145 update(&path, &test.text, verify)?;
146 }
147 Ok(())
148}
149
150fn tests_from_dir(dir: &Path) -> Result<HashMap<String, Test>> {
151 let mut res = HashMap::new();
152 for entry in ::walkdir::WalkDir::new(dir) {
153 let entry = entry.unwrap();
154 if !entry.file_type().is_file() {
155 continue;
156 }
157 if entry.path().extension().unwrap_or_default() != "rs" {
158 continue;
159 }
160 let text = fs::read_to_string(entry.path())?;
161
162 for (_, test) in collect_tests(&text) {
163 if let Some(old_test) = res.insert(test.name.clone(), test) {
164 bail!("Duplicate test: {}", old_test.name)
165 }
166 }
167 }
168 Ok(res)
169}
170
171fn existing_tests(dir: &Path) -> Result<HashMap<String, (PathBuf, Test)>> {
172 let mut res = HashMap::new();
173 for file in fs::read_dir(dir)? {
174 let file = file?;
175 let path = file.path();
176 if path.extension().unwrap_or_default() != "rs" {
177 continue;
178 }
179 let name = {
180 let file_name = path.file_name().unwrap().to_str().unwrap();
181 file_name[5..file_name.len() - 3].to_string()
182 };
183 let text = fs::read_to_string(&path)?;
184 let test = Test {
185 name: name.clone(),
186 text,
187 };
188 match res.insert(name, (path, test)) {
189 Some(old) => println!("Duplicate test: {:?}", old),
190 None => (),
191 }
192 }
193 Ok(res)
194}
195
196fn install_code_extension() -> Result<()> {
197 execute!(
198 r"
199cd code
200npm install
201 "
202 )?;
203 execute!(
204 r"
205cd code
206./node_modules/vsce/out/vsce package
207 "
208 )?;
209 execute!(
210 r"
211cd code
212code --install-extension ./libsyntax-rust-0.0.1.vsix
213 "
214 )?;
215 Ok(())
216}