mt-lang 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/AUTHORS +3 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +1208 -0
- data/Rakefile +332 -0
- data/bin/mtc +8 -0
- data/bin/profile-mtc-checks +133 -0
- data/bin/tracy-profiler +0 -0
- data/docs/build-guide.md +536 -0
- data/docs/index.html +2778 -0
- data/docs/language-design.md +1519 -0
- data/docs/language-manual.md +1534 -0
- data/lib/milk_tea/base.rb +49 -0
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
- data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
- data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
- data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
- data/lib/milk_tea/bindings/bindgen.rb +207 -0
- data/lib/milk_tea/bindings/cli.rb +121 -0
- data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
- data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
- data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
- data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
- data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
- data/lib/milk_tea/bindings/steamworks.rb +629 -0
- data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
- data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
- data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
- data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
- data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
- data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
- data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
- data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
- data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
- data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
- data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
- data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
- data/lib/milk_tea/bindings.rb +23 -0
- data/lib/milk_tea/core/ast.rb +311 -0
- data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
- data/lib/milk_tea/core/binding_types.rb +18 -0
- data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
- data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
- data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
- data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
- data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
- data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
- data/lib/milk_tea/core/c_backend/statements.rb +563 -0
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
- data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
- data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
- data/lib/milk_tea/core/c_backend.rb +287 -0
- data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
- data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
- data/lib/milk_tea/core/compile_time.rb +329 -0
- data/lib/milk_tea/core/control_flow/builder.rb +582 -0
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
- data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
- data/lib/milk_tea/core/control_flow/graph.rb +90 -0
- data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
- data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
- data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
- data/lib/milk_tea/core/control_flow/termination.rb +31 -0
- data/lib/milk_tea/core/control_flow.rb +34 -0
- data/lib/milk_tea/core/cst.rb +48 -0
- data/lib/milk_tea/core/cst_builder.rb +19 -0
- data/lib/milk_tea/core/ir.rb +85 -0
- data/lib/milk_tea/core/keywords.rb +97 -0
- data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
- data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
- data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
- data/lib/milk_tea/core/lexer/indentation.rb +62 -0
- data/lib/milk_tea/core/lexer/numbers.rb +96 -0
- data/lib/milk_tea/core/lexer/recovery.rb +32 -0
- data/lib/milk_tea/core/lexer/strings.rb +167 -0
- data/lib/milk_tea/core/lexer/symbols.rb +71 -0
- data/lib/milk_tea/core/lexer/trivia.rb +53 -0
- data/lib/milk_tea/core/lexer.rb +430 -0
- data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
- data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
- data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
- data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
- data/lib/milk_tea/core/lowering/async.rb +714 -0
- data/lib/milk_tea/core/lowering/block.rb +1052 -0
- data/lib/milk_tea/core/lowering/calls.rb +1565 -0
- data/lib/milk_tea/core/lowering/declarations.rb +214 -0
- data/lib/milk_tea/core/lowering/dyn.rb +206 -0
- data/lib/milk_tea/core/lowering/events.rb +1054 -0
- data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
- data/lib/milk_tea/core/lowering/functions.rb +242 -0
- data/lib/milk_tea/core/lowering/loops.rb +1087 -0
- data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
- data/lib/milk_tea/core/lowering/proc.rb +419 -0
- data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
- data/lib/milk_tea/core/lowering/scans.rb +220 -0
- data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
- data/lib/milk_tea/core/lowering/utils.rb +1453 -0
- data/lib/milk_tea/core/lowering.rb +378 -0
- data/lib/milk_tea/core/module_binder.rb +181 -0
- data/lib/milk_tea/core/module_loader/errors.rb +21 -0
- data/lib/milk_tea/core/module_loader.rb +479 -0
- data/lib/milk_tea/core/module_path_resolver.rb +153 -0
- data/lib/milk_tea/core/module_roots.rb +88 -0
- data/lib/milk_tea/core/parser/attributes.rb +71 -0
- data/lib/milk_tea/core/parser/blocks.rb +119 -0
- data/lib/milk_tea/core/parser/declarations.rb +749 -0
- data/lib/milk_tea/core/parser/expressions.rb +624 -0
- data/lib/milk_tea/core/parser/recovery.rb +131 -0
- data/lib/milk_tea/core/parser/statements.rb +756 -0
- data/lib/milk_tea/core/parser/types.rb +271 -0
- data/lib/milk_tea/core/parser.rb +400 -0
- data/lib/milk_tea/core/prelude_installer.rb +29 -0
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
- data/lib/milk_tea/core/pretty_printer.rb +17 -0
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
- data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
- data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
- data/lib/milk_tea/core/token.rb +26 -0
- data/lib/milk_tea/core/token_stream.rb +30 -0
- data/lib/milk_tea/core/types/layout.rb +243 -0
- data/lib/milk_tea/core/types/predicates.rb +609 -0
- data/lib/milk_tea/core/types/registry.rb +83 -0
- data/lib/milk_tea/core/types/types.rb +1696 -0
- data/lib/milk_tea/core/types/visitor.rb +442 -0
- data/lib/milk_tea/core.rb +25 -0
- data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
- data/lib/milk_tea/dap/protocol.rb +58 -0
- data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
- data/lib/milk_tea/dap/server/debug_map.rb +291 -0
- data/lib/milk_tea/dap/server/handlers.rb +374 -0
- data/lib/milk_tea/dap/server/launch.rb +261 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
- data/lib/milk_tea/dap/server/utilities.rb +160 -0
- data/lib/milk_tea/dap/server/wire.rb +55 -0
- data/lib/milk_tea/dap/server.rb +131 -0
- data/lib/milk_tea/dap/session.rb +152 -0
- data/lib/milk_tea/dap.rb +6 -0
- data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
- data/lib/milk_tea/lsp/diagnostics.rb +611 -0
- data/lib/milk_tea/lsp/protocol.rb +104 -0
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
- data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
- data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
- data/lib/milk_tea/lsp/server/completion.rb +1099 -0
- data/lib/milk_tea/lsp/server/configuration.rb +167 -0
- data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
- data/lib/milk_tea/lsp/server/definition.rb +779 -0
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
- data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
- data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
- data/lib/milk_tea/lsp/server/formatting.rb +575 -0
- data/lib/milk_tea/lsp/server/hover.rb +1465 -0
- data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
- data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
- data/lib/milk_tea/lsp/server/progress.rb +47 -0
- data/lib/milk_tea/lsp/server/references.rb +433 -0
- data/lib/milk_tea/lsp/server/rename.rb +598 -0
- data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
- data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
- data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
- data/lib/milk_tea/lsp/server/utilities.rb +520 -0
- data/lib/milk_tea/lsp/server.rb +415 -0
- data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
- data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
- data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
- data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
- data/lib/milk_tea/lsp/workspace/store.rb +154 -0
- data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
- data/lib/milk_tea/lsp/workspace.rb +127 -0
- data/lib/milk_tea/lsp.rb +13 -0
- data/lib/milk_tea/packages/atomic_write.rb +63 -0
- data/lib/milk_tea/packages/dependency_solver.rb +194 -0
- data/lib/milk_tea/packages/graph.rb +139 -0
- data/lib/milk_tea/packages/lock.rb +421 -0
- data/lib/milk_tea/packages/manager_cli.rb +485 -0
- data/lib/milk_tea/packages/manifest.rb +356 -0
- data/lib/milk_tea/packages/manifest_editor.rb +134 -0
- data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
- data/lib/milk_tea/packages/registry_store.rb +420 -0
- data/lib/milk_tea/packages/services.rb +41 -0
- data/lib/milk_tea/packages/source_cache.rb +71 -0
- data/lib/milk_tea/packages/source_fetcher.rb +124 -0
- data/lib/milk_tea/packages/source_resolver.rb +389 -0
- data/lib/milk_tea/packages/version.rb +164 -0
- data/lib/milk_tea/packages.rb +16 -0
- data/lib/milk_tea/tooling/asset_pack.rb +141 -0
- data/lib/milk_tea/tooling/build.rb +1124 -0
- data/lib/milk_tea/tooling/build_cache.rb +240 -0
- data/lib/milk_tea/tooling/cli.rb +2688 -0
- data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
- data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
- data/lib/milk_tea/tooling/debug_map.rb +248 -0
- data/lib/milk_tea/tooling/docs_app.rb +369 -0
- data/lib/milk_tea/tooling/error_formatter.rb +86 -0
- data/lib/milk_tea/tooling/formatter.rb +787 -0
- data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
- data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
- data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
- data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
- data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
- data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
- data/lib/milk_tea/tooling/linter/rules.rb +593 -0
- data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
- data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
- data/lib/milk_tea/tooling/linter.rb +798 -0
- data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
- data/lib/milk_tea/tooling/public/css/docs.css +166 -0
- data/lib/milk_tea/tooling/public/js/docs.js +94 -0
- data/lib/milk_tea/tooling/run.rb +408 -0
- data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
- data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
- data/lib/milk_tea/tooling/views/404.erb +7 -0
- data/lib/milk_tea/tooling/views/index.erb +87 -0
- data/lib/milk_tea/tooling/views/layout.erb +69 -0
- data/lib/milk_tea/tooling/views/module.erb +97 -0
- data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
- data/lib/milk_tea/tooling.rb +20 -0
- data/lib/milk_tea.rb +8 -0
- metadata +426 -0
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
module Parse
|
|
5
|
+
module Statements
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def check_inline_stmt_start?
|
|
9
|
+
return false unless check(:inline)
|
|
10
|
+
|
|
11
|
+
next_idx = @current + 1
|
|
12
|
+
return false if next_idx >= @tokens.length
|
|
13
|
+
|
|
14
|
+
next_token = @tokens[next_idx]
|
|
15
|
+
%i[for while match if].include?(next_token.type)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def check_parallel_for_start?
|
|
19
|
+
return false unless check(:parallel)
|
|
20
|
+
|
|
21
|
+
next_idx = @current + 1
|
|
22
|
+
return false if next_idx >= @tokens.length
|
|
23
|
+
|
|
24
|
+
@tokens[next_idx].type == :for
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check_parallel_block_start?
|
|
28
|
+
return false unless check(:parallel)
|
|
29
|
+
|
|
30
|
+
next_idx = @current + 1
|
|
31
|
+
return false if next_idx >= @tokens.length
|
|
32
|
+
|
|
33
|
+
@tokens[next_idx].type == :colon
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def check_when_start?
|
|
37
|
+
check(:when)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def parse_statement
|
|
41
|
+
if match(:let)
|
|
42
|
+
parse_local_decl(:let)
|
|
43
|
+
elsif match(:var)
|
|
44
|
+
parse_local_decl(:var)
|
|
45
|
+
elsif match(:if)
|
|
46
|
+
parse_if_stmt
|
|
47
|
+
elsif match(:match)
|
|
48
|
+
parse_match_stmt
|
|
49
|
+
elsif match(:unsafe)
|
|
50
|
+
parse_unsafe_stmt
|
|
51
|
+
elsif match(:static_assert)
|
|
52
|
+
parse_static_assert
|
|
53
|
+
elsif match(:emit)
|
|
54
|
+
parse_emit_stmt
|
|
55
|
+
elsif match(:for)
|
|
56
|
+
parse_for_stmt
|
|
57
|
+
elsif check_parallel_for_start?
|
|
58
|
+
advance
|
|
59
|
+
parse_parallel_for_stmt
|
|
60
|
+
elsif check_parallel_block_start?
|
|
61
|
+
advance
|
|
62
|
+
parse_parallel_block_stmt
|
|
63
|
+
elsif match(:gather)
|
|
64
|
+
parse_gather_stmt
|
|
65
|
+
elsif match(:while)
|
|
66
|
+
parse_while_stmt
|
|
67
|
+
elsif match(:pass)
|
|
68
|
+
parse_pass_stmt
|
|
69
|
+
elsif match(:break)
|
|
70
|
+
parse_break_stmt
|
|
71
|
+
elsif match(:continue)
|
|
72
|
+
parse_continue_stmt
|
|
73
|
+
elsif match(:return)
|
|
74
|
+
parse_return_stmt
|
|
75
|
+
elsif match(:defer)
|
|
76
|
+
parse_defer_stmt
|
|
77
|
+
elsif check_inline_stmt_start?
|
|
78
|
+
advance
|
|
79
|
+
parse_inline_stmt
|
|
80
|
+
elsif check_when_start?
|
|
81
|
+
advance
|
|
82
|
+
parse_when_stmt
|
|
83
|
+
else
|
|
84
|
+
parse_assignment_or_expression_stmt
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_local_decl(kind)
|
|
89
|
+
line = previous.line
|
|
90
|
+
name_token = nil
|
|
91
|
+
name = nil
|
|
92
|
+
var_type = nil
|
|
93
|
+
|
|
94
|
+
destructure_bindings = nil
|
|
95
|
+
destructure_type_name = nil
|
|
96
|
+
if check(:lparen)
|
|
97
|
+
destructure_bindings = parse_destructure_pattern
|
|
98
|
+
elsif check_name && check_next(:lparen)
|
|
99
|
+
destructure_type_name = advance.lexeme
|
|
100
|
+
destructure_bindings = parse_destructure_pattern
|
|
101
|
+
elsif check_name && check_next(:dot)
|
|
102
|
+
parts = [advance.lexeme]
|
|
103
|
+
while check(:dot)
|
|
104
|
+
advance
|
|
105
|
+
parts << consume_name("expected type name after '.' in destructure pattern").lexeme
|
|
106
|
+
end
|
|
107
|
+
if match(:lparen)
|
|
108
|
+
destructure_type_name = parts.length == 1 ? parts[0].dup : parts
|
|
109
|
+
destructure_bindings = parse_destructure_pattern
|
|
110
|
+
else
|
|
111
|
+
raise error(@tokens[@current], "expected '(' after type name in destructure pattern")
|
|
112
|
+
end
|
|
113
|
+
else
|
|
114
|
+
name_token = consume_name("expected local variable name")
|
|
115
|
+
name = name_token.lexeme
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
var_type = match(:colon) ? parse_type_ref : nil
|
|
119
|
+
value = nil
|
|
120
|
+
else_binding = nil
|
|
121
|
+
else_body = nil
|
|
122
|
+
else_started = false
|
|
123
|
+
|
|
124
|
+
if destructure_bindings
|
|
125
|
+
consume(:equal, "expected '=' after destructure pattern")
|
|
126
|
+
value = parse_expression
|
|
127
|
+
consume_end_of_statement
|
|
128
|
+
elsif match(:equal)
|
|
129
|
+
value = parse_expression
|
|
130
|
+
if match(:else)
|
|
131
|
+
else_started = true
|
|
132
|
+
|
|
133
|
+
if match(:as)
|
|
134
|
+
binding_token = consume_name("expected error binding name after 'as'")
|
|
135
|
+
else_binding = AST::Identifier.new(name: binding_token.lexeme, line: binding_token.line, column: binding_token.column)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
else_body = parse_block
|
|
139
|
+
else
|
|
140
|
+
consume_end_of_statement unless block_expression?(value)
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
raise error(name_token, "local declaration without initializer requires a type") unless var_type
|
|
144
|
+
|
|
145
|
+
consume_end_of_statement
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
AST::LocalDecl.new(kind:, name:, type: var_type, value:, else_binding:, else_body:, line:, column: name_token&.column || line, destructure_bindings:, destructure_type_name:)
|
|
149
|
+
rescue ParseError => e
|
|
150
|
+
raise unless @recovery_errors && name
|
|
151
|
+
|
|
152
|
+
@recovery_errors << e
|
|
153
|
+
synchronize_to_statement_boundary
|
|
154
|
+
|
|
155
|
+
if else_started
|
|
156
|
+
return AST::LocalDecl.new(
|
|
157
|
+
kind:,
|
|
158
|
+
name:,
|
|
159
|
+
type: var_type,
|
|
160
|
+
value:,
|
|
161
|
+
else_binding:,
|
|
162
|
+
else_body: nil,
|
|
163
|
+
line:,
|
|
164
|
+
column: name_token.column,
|
|
165
|
+
recovered_else: true,
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
AST::LocalDecl.new(
|
|
170
|
+
kind:,
|
|
171
|
+
name:,
|
|
172
|
+
type: var_type,
|
|
173
|
+
value: recovery_error_expr(e),
|
|
174
|
+
else_binding: nil,
|
|
175
|
+
else_body: nil,
|
|
176
|
+
line:,
|
|
177
|
+
column: name_token.column,
|
|
178
|
+
)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def parse_destructure_pattern
|
|
182
|
+
match(:lparen)
|
|
183
|
+
bindings = []
|
|
184
|
+
loop do
|
|
185
|
+
token = consume_name("expected binding name in destructure pattern")
|
|
186
|
+
bindings << token.lexeme
|
|
187
|
+
break unless match(:comma)
|
|
188
|
+
end
|
|
189
|
+
consume(:rparen, "expected ')' after destructure pattern")
|
|
190
|
+
bindings
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def parse_if_stmt
|
|
194
|
+
line = previous.line
|
|
195
|
+
branches = [parse_if_branch(previous)]
|
|
196
|
+
|
|
197
|
+
while check(:else) && check_next(:if)
|
|
198
|
+
advance
|
|
199
|
+
advance
|
|
200
|
+
branches << parse_if_branch(previous)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
else_line = nil
|
|
204
|
+
else_column = nil
|
|
205
|
+
else_body = if match(:else)
|
|
206
|
+
else_line = previous.line
|
|
207
|
+
else_column = previous.column
|
|
208
|
+
parse_else_branch_body
|
|
209
|
+
end
|
|
210
|
+
AST::IfStmt.new(branches:, else_body:, line:, else_line:, else_column:)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def parse_if_branch(token)
|
|
214
|
+
condition = nil
|
|
215
|
+
condition = parse_expression
|
|
216
|
+
body = if inline_block_body?
|
|
217
|
+
consume(:colon, "expected ':' after if condition")
|
|
218
|
+
@in_inline_block_body = true
|
|
219
|
+
result = [parse_statement]
|
|
220
|
+
@in_inline_block_body = false
|
|
221
|
+
result
|
|
222
|
+
else
|
|
223
|
+
parse_block
|
|
224
|
+
end
|
|
225
|
+
AST::IfBranch.new(
|
|
226
|
+
condition:,
|
|
227
|
+
body:,
|
|
228
|
+
line: token.line,
|
|
229
|
+
column: token.column,
|
|
230
|
+
length: token.lexeme.length,
|
|
231
|
+
)
|
|
232
|
+
rescue ParseError => e
|
|
233
|
+
raise unless @recovery_errors
|
|
234
|
+
|
|
235
|
+
@recovery_errors << e
|
|
236
|
+
recovered_body = synchronize_to_statement_boundary
|
|
237
|
+
raise unless recovered_body
|
|
238
|
+
|
|
239
|
+
AST::IfBranch.new(
|
|
240
|
+
condition: condition || recovery_error_expr(e),
|
|
241
|
+
body: recovered_body,
|
|
242
|
+
line: token.line,
|
|
243
|
+
column: token.column,
|
|
244
|
+
length: token.lexeme.length,
|
|
245
|
+
)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def parse_else_branch_body
|
|
249
|
+
if inline_block_body?
|
|
250
|
+
consume(:colon, "expected ':' before else body")
|
|
251
|
+
@in_inline_block_body = true
|
|
252
|
+
result = [parse_statement]
|
|
253
|
+
@in_inline_block_body = false
|
|
254
|
+
result
|
|
255
|
+
else
|
|
256
|
+
parse_block
|
|
257
|
+
end
|
|
258
|
+
rescue ParseError => e
|
|
259
|
+
raise unless @recovery_errors
|
|
260
|
+
|
|
261
|
+
@recovery_errors << e
|
|
262
|
+
recovered_body = synchronize_to_statement_boundary
|
|
263
|
+
raise unless recovered_body
|
|
264
|
+
|
|
265
|
+
recovered_body
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def inline_block_body?
|
|
269
|
+
check(:colon) && @current + 1 < @tokens.length && @tokens[@current + 1].type != :newline
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def parse_match_stmt
|
|
273
|
+
token = previous
|
|
274
|
+
line = token.line
|
|
275
|
+
expression = nil
|
|
276
|
+
arms = []
|
|
277
|
+
expression = parse_expression
|
|
278
|
+
arms = parse_match_arms(arms)
|
|
279
|
+
if arms.first&.is_a?(AST::MatchExprArm)
|
|
280
|
+
expr = AST::MatchExpr.new(expression:, arms:, line:, column: token.column, length: token.lexeme.length)
|
|
281
|
+
AST::ExpressionStmt.new(expression: expr, line:)
|
|
282
|
+
else
|
|
283
|
+
AST::MatchStmt.new(expression:, arms:, line:, column: token.column, length: token.lexeme.length)
|
|
284
|
+
end
|
|
285
|
+
rescue ParseError => e
|
|
286
|
+
raise unless @recovery_errors
|
|
287
|
+
|
|
288
|
+
@recovery_errors << e
|
|
289
|
+
recovered_arms = synchronize_to_match_arm_boundary
|
|
290
|
+
target_line = line
|
|
291
|
+
if recovered_arms
|
|
292
|
+
stmt =
|
|
293
|
+
if recovered_arms.first&.is_a?(AST::MatchExprArm)
|
|
294
|
+
expr = AST::MatchExpr.new(expression: expression || recovery_error_expr(e), arms: arms + recovered_arms, line: target_line, column: token.column, length: token.lexeme.length)
|
|
295
|
+
AST::ExpressionStmt.new(expression: expr, line: target_line)
|
|
296
|
+
else
|
|
297
|
+
AST::MatchStmt.new(expression: expression || recovery_error_expr(e), arms: arms + recovered_arms, line: target_line, column: token.column, length: token.lexeme.length)
|
|
298
|
+
end
|
|
299
|
+
return stmt
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
recovery_error_stmt(e)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def parse_match_arms(arms = [])
|
|
306
|
+
consume(:colon, "expected ':' before block")
|
|
307
|
+
consume(:newline, "expected newline before block")
|
|
308
|
+
consume(:indent, "expected indented block")
|
|
309
|
+
|
|
310
|
+
parse_match_arm_body(arms)
|
|
311
|
+
|
|
312
|
+
consume(:dedent, "expected end of block")
|
|
313
|
+
arms
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def parse_match_arm_body(arms = [])
|
|
317
|
+
skip_newlines
|
|
318
|
+
until check(:dedent) || eof?
|
|
319
|
+
arms.concat(parse_match_arm)
|
|
320
|
+
skip_newlines
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
arms
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def parse_match_arm
|
|
327
|
+
patterns = []
|
|
328
|
+
binding_token = nil
|
|
329
|
+
binding_name = nil
|
|
330
|
+
|
|
331
|
+
if match(:else)
|
|
332
|
+
patterns << AST::Identifier.new(name: "_", line: previous.line, column: previous.column)
|
|
333
|
+
else
|
|
334
|
+
patterns << parse_bitwise_xor
|
|
335
|
+
while match(:pipe)
|
|
336
|
+
patterns << parse_bitwise_xor
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
binding_name = if match(:as)
|
|
340
|
+
binding_token = consume_name("expected binding name after 'as'")
|
|
341
|
+
binding_token.lexeme
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
if match_arm_expr_form?
|
|
345
|
+
consume(:colon, "expected ':' after match expression arm pattern")
|
|
346
|
+
value = parse_expression
|
|
347
|
+
consume_end_of_statement unless block_expression?(value)
|
|
348
|
+
patterns.map do |pattern|
|
|
349
|
+
AST::MatchExprArm.new(
|
|
350
|
+
pattern:,
|
|
351
|
+
binding_name:,
|
|
352
|
+
binding_line: binding_token&.line,
|
|
353
|
+
binding_column: binding_token&.column,
|
|
354
|
+
value:,
|
|
355
|
+
)
|
|
356
|
+
end
|
|
357
|
+
else
|
|
358
|
+
body = parse_block
|
|
359
|
+
patterns.map do |pattern|
|
|
360
|
+
AST::MatchArm.new(
|
|
361
|
+
pattern:,
|
|
362
|
+
binding_name:,
|
|
363
|
+
binding_line: binding_token&.line,
|
|
364
|
+
binding_column: binding_token&.column,
|
|
365
|
+
body:,
|
|
366
|
+
)
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
rescue ParseError => e
|
|
370
|
+
raise unless @recovery_errors
|
|
371
|
+
|
|
372
|
+
@recovery_errors << e
|
|
373
|
+
recovered_body = synchronize_to_statement_boundary
|
|
374
|
+
return [AST::MatchArm.new(
|
|
375
|
+
pattern: patterns.first || recovery_error_expr(e),
|
|
376
|
+
binding_name:,
|
|
377
|
+
binding_line: binding_token&.line,
|
|
378
|
+
binding_column: binding_token&.column,
|
|
379
|
+
body: recovered_body,
|
|
380
|
+
)] if recovered_body
|
|
381
|
+
|
|
382
|
+
raise
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def match_arm_expr_form?
|
|
386
|
+
check(:colon) && @current + 1 < @tokens.length && @tokens[@current + 1].type != :newline
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def parse_unsafe_stmt
|
|
390
|
+
token = previous
|
|
391
|
+
consume(:colon, "expected ':' after unsafe")
|
|
392
|
+
body = if match(:newline)
|
|
393
|
+
consume(:indent, "expected indented block")
|
|
394
|
+
|
|
395
|
+
statements = parse_statement_block_body
|
|
396
|
+
consume(:dedent, "expected end of block")
|
|
397
|
+
statements
|
|
398
|
+
else
|
|
399
|
+
statement = parse_statement
|
|
400
|
+
raise ParseError.new("inline unsafe local declarations must use expression form", token:, path: @path) if statement.is_a?(AST::LocalDecl)
|
|
401
|
+
|
|
402
|
+
[statement]
|
|
403
|
+
end
|
|
404
|
+
AST::UnsafeStmt.new(body:, line: token.line, column: token.column, length: token.lexeme.length)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def parse_static_assert
|
|
408
|
+
line = previous.line
|
|
409
|
+
consume(:lparen, "expected '(' after static_assert")
|
|
410
|
+
condition = parse_expression
|
|
411
|
+
consume(:comma, "expected ',' after static_assert condition")
|
|
412
|
+
message = parse_expression
|
|
413
|
+
consume(:rparen, "expected ')' after static_assert message")
|
|
414
|
+
consume_end_of_statement
|
|
415
|
+
AST::StaticAssert.new(condition:, message:, line:)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def parse_emit_stmt
|
|
419
|
+
line = previous.line
|
|
420
|
+
column = previous.column
|
|
421
|
+
decl = parse_declaration
|
|
422
|
+
AST::EmitStmt.new(declaration: decl, line:, column:)
|
|
423
|
+
rescue ParseError => e
|
|
424
|
+
raise unless @recovery_errors
|
|
425
|
+
|
|
426
|
+
@recovery_errors << e
|
|
427
|
+
synchronize_to_statement_boundary
|
|
428
|
+
AST::EmitStmt.new(declaration: AST::ErrorExpr.new(message: e.message), line:, column:)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def parse_for_stmt
|
|
432
|
+
line = previous.line
|
|
433
|
+
bindings = []
|
|
434
|
+
iterables = nil
|
|
435
|
+
loop do
|
|
436
|
+
name_token = consume_name("expected loop variable name")
|
|
437
|
+
bindings << AST::ForBinding.new(name: name_token.lexeme, line: name_token.line, column: name_token.column)
|
|
438
|
+
break unless match(:comma)
|
|
439
|
+
end
|
|
440
|
+
consume(:in, "expected 'in' in for loop")
|
|
441
|
+
iterables = [parse_expression]
|
|
442
|
+
iterables << parse_expression while match(:comma)
|
|
443
|
+
body = parse_block
|
|
444
|
+
AST::ForStmt.new(bindings:, iterables:, body:, line:, column: bindings.first.column)
|
|
445
|
+
rescue ParseError => e
|
|
446
|
+
raise unless @recovery_errors
|
|
447
|
+
|
|
448
|
+
@recovery_errors << e
|
|
449
|
+
recovered_body = synchronize_to_statement_boundary
|
|
450
|
+
return recovery_error_block_stmt(
|
|
451
|
+
e,
|
|
452
|
+
recovered_body,
|
|
453
|
+
header_type: :for,
|
|
454
|
+
header_bindings: bindings.empty? ? nil : bindings,
|
|
455
|
+
header_iterables: iterables&.any? ? iterables : nil,
|
|
456
|
+
) if recovered_body
|
|
457
|
+
|
|
458
|
+
recovery_error_stmt(e)
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
def parse_parallel_for_stmt
|
|
462
|
+
consume(:for, "expected 'for' after 'parallel'")
|
|
463
|
+
line = previous.line
|
|
464
|
+
name_token = consume_name("expected loop variable name")
|
|
465
|
+
bindings = [AST::ForBinding.new(name: name_token.lexeme, line: name_token.line, column: name_token.column)]
|
|
466
|
+
consume(:in, "expected 'in' in parallel for loop")
|
|
467
|
+
iterables = [parse_expression]
|
|
468
|
+
body = parse_block
|
|
469
|
+
AST::ForStmt.new(bindings:, iterables:, body:, threaded: true, line:, column: bindings.first.column)
|
|
470
|
+
rescue ParseError => e
|
|
471
|
+
raise unless @recovery_errors
|
|
472
|
+
|
|
473
|
+
@recovery_errors << e
|
|
474
|
+
recovered_body = synchronize_to_statement_boundary
|
|
475
|
+
return recovery_error_block_stmt(e, recovered_body, header_type: :for) if recovered_body
|
|
476
|
+
|
|
477
|
+
recovery_error_stmt(e)
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def parse_parallel_block_stmt
|
|
481
|
+
line = previous.line
|
|
482
|
+
column = previous.column
|
|
483
|
+
consume(:colon, "expected ':' after 'parallel'")
|
|
484
|
+
consume(:newline, "expected newline after 'parallel:'")
|
|
485
|
+
consume(:indent, "expected indented block after 'parallel:'")
|
|
486
|
+
statements = parse_statement_block_body
|
|
487
|
+
consume(:dedent, "expected end of parallel block")
|
|
488
|
+
bodies = statements.map { |stmt| [stmt] }
|
|
489
|
+
AST::ParallelBlockStmt.new(bodies:, line:, column:)
|
|
490
|
+
rescue ParseError => e
|
|
491
|
+
raise unless @recovery_errors
|
|
492
|
+
|
|
493
|
+
@recovery_errors << e
|
|
494
|
+
recovered_body = synchronize_to_statement_boundary
|
|
495
|
+
return recovery_error_block_stmt(e, recovered_body, header_type: :parallel) if recovered_body
|
|
496
|
+
|
|
497
|
+
recovery_error_stmt(e)
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def parse_gather_stmt
|
|
501
|
+
line = previous.line
|
|
502
|
+
column = previous.column
|
|
503
|
+
handles = []
|
|
504
|
+
handle = parse_expression
|
|
505
|
+
handles << handle
|
|
506
|
+
while match(:comma)
|
|
507
|
+
handle = parse_expression
|
|
508
|
+
handles << handle
|
|
509
|
+
end
|
|
510
|
+
AST::GatherStmt.new(handles:, line:, column:)
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def parse_while_stmt
|
|
514
|
+
token = previous
|
|
515
|
+
line = token.line
|
|
516
|
+
condition = parse_expression
|
|
517
|
+
body = parse_block
|
|
518
|
+
AST::WhileStmt.new(condition:, body:, line:, column: token.column, length: token.lexeme.length)
|
|
519
|
+
rescue ParseError => e
|
|
520
|
+
raise unless @recovery_errors
|
|
521
|
+
|
|
522
|
+
@recovery_errors << e
|
|
523
|
+
recovered_body = synchronize_to_statement_boundary
|
|
524
|
+
return AST::WhileStmt.new(
|
|
525
|
+
condition: condition || recovery_error_expr(e),
|
|
526
|
+
body: recovered_body,
|
|
527
|
+
line:,
|
|
528
|
+
column: token.column,
|
|
529
|
+
length: token.lexeme.length,
|
|
530
|
+
) if recovered_body
|
|
531
|
+
|
|
532
|
+
recovery_error_stmt(e)
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
def parse_pass_stmt
|
|
536
|
+
token = previous
|
|
537
|
+
line = token.line
|
|
538
|
+
consume_end_of_statement
|
|
539
|
+
AST::PassStmt.new(line:, column: token.column, length: token.lexeme.length)
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def parse_break_stmt
|
|
543
|
+
token = previous
|
|
544
|
+
line = token.line
|
|
545
|
+
consume_end_of_statement
|
|
546
|
+
AST::BreakStmt.new(line:, column: token.column, length: token.lexeme.length)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def parse_continue_stmt
|
|
550
|
+
token = previous
|
|
551
|
+
line = token.line
|
|
552
|
+
consume_end_of_statement
|
|
553
|
+
AST::ContinueStmt.new(line:, column: token.column, length: token.lexeme.length)
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
def parse_return_stmt
|
|
557
|
+
token = previous
|
|
558
|
+
line = token.line
|
|
559
|
+
value = check(:newline) ? nil : parse_expression
|
|
560
|
+
consume_end_of_statement unless block_expression?(value)
|
|
561
|
+
AST::ReturnStmt.new(value:, line:, column: token.column, length: token.lexeme.length)
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def parse_defer_stmt
|
|
565
|
+
token = previous
|
|
566
|
+
line = token.line
|
|
567
|
+
if check(:colon)
|
|
568
|
+
body = parse_block
|
|
569
|
+
AST::DeferStmt.new(expression: nil, body:, line:, column: token.column, length: token.lexeme.length)
|
|
570
|
+
else
|
|
571
|
+
expression = parse_expression
|
|
572
|
+
consume_end_of_statement unless block_expression?(expression)
|
|
573
|
+
AST::DeferStmt.new(expression:, body: nil, line:, column: token.column, length: token.lexeme.length)
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def parse_when_decl
|
|
578
|
+
token = previous
|
|
579
|
+
line = token.line
|
|
580
|
+
discriminant = parse_expression
|
|
581
|
+
branches = parse_decl_when_arms
|
|
582
|
+
else_body = if check(:else)
|
|
583
|
+
if check_next(:newline) || check_next(:indent)
|
|
584
|
+
parse_declaration_block
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
AST::WhenStmt.new(discriminant:, branches:, else_body:, line:, column: token.column, length: token.lexeme.length)
|
|
588
|
+
rescue ParseError => e
|
|
589
|
+
raise unless @recovery_errors
|
|
590
|
+
|
|
591
|
+
@recovery_errors << e
|
|
592
|
+
recovered_body = synchronize_to_statement_boundary
|
|
593
|
+
return recovery_error_block_stmt(e, recovered_body, header_type: :when) if recovered_body
|
|
594
|
+
|
|
595
|
+
recovery_error_stmt(e)
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
def parse_decl_when_arms
|
|
599
|
+
consume(:colon, "expected ':' before block")
|
|
600
|
+
consume(:newline, "expected newline before block")
|
|
601
|
+
consume(:indent, "expected indented block")
|
|
602
|
+
|
|
603
|
+
arms = []
|
|
604
|
+
skip_newlines
|
|
605
|
+
until check(:dedent) || eof?
|
|
606
|
+
pattern = parse_expression
|
|
607
|
+
binding_name = if match(:as)
|
|
608
|
+
binding_token = consume_name("expected binding name after 'as'")
|
|
609
|
+
binding_token.lexeme
|
|
610
|
+
end
|
|
611
|
+
body = parse_declaration_block
|
|
612
|
+
binding_token ||= previous
|
|
613
|
+
arms << AST::WhenBranch.new(
|
|
614
|
+
pattern:,
|
|
615
|
+
binding_name:,
|
|
616
|
+
binding_line: binding_token.line,
|
|
617
|
+
binding_column: binding_token.column,
|
|
618
|
+
body:,
|
|
619
|
+
)
|
|
620
|
+
skip_newlines
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
consume(:dedent, "expected end of block")
|
|
624
|
+
arms
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
def parse_when_stmt
|
|
628
|
+
token = previous
|
|
629
|
+
line = token.line
|
|
630
|
+
discriminant = parse_expression
|
|
631
|
+
branches = parse_match_arms([])
|
|
632
|
+
else_body = if check(:else)
|
|
633
|
+
if check_next(:newline) || check_next(:indent)
|
|
634
|
+
parse_else_branch_body
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
AST::WhenStmt.new(discriminant:, branches:, else_body:, line:, column: token.column, length: token.lexeme.length)
|
|
638
|
+
rescue ParseError => e
|
|
639
|
+
raise unless @recovery_errors
|
|
640
|
+
|
|
641
|
+
@recovery_errors << e
|
|
642
|
+
recovered_body = synchronize_to_statement_boundary
|
|
643
|
+
return recovery_error_block_stmt(e, recovered_body, header_type: :when) if recovered_body
|
|
644
|
+
|
|
645
|
+
recovery_error_stmt(e)
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
def parse_inline_stmt
|
|
649
|
+
token = previous
|
|
650
|
+
if match(:for)
|
|
651
|
+
parse_inline_for_stmt(token)
|
|
652
|
+
elsif match(:while)
|
|
653
|
+
parse_inline_while_stmt(token)
|
|
654
|
+
elsif match(:match)
|
|
655
|
+
parse_inline_match_stmt(token)
|
|
656
|
+
elsif match(:if)
|
|
657
|
+
parse_inline_if_stmt(token)
|
|
658
|
+
else
|
|
659
|
+
raise error(peek, "expected for, while, match, or if after inline")
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def parse_inline_for_stmt(_inline_token)
|
|
664
|
+
line = previous.line
|
|
665
|
+
bindings = []
|
|
666
|
+
iterables = nil
|
|
667
|
+
loop do
|
|
668
|
+
name_token = consume_name("expected loop variable name")
|
|
669
|
+
bindings << AST::ForBinding.new(name: name_token.lexeme, line: name_token.line, column: name_token.column)
|
|
670
|
+
break unless match(:comma)
|
|
671
|
+
end
|
|
672
|
+
consume(:in, "expected 'in' in for loop")
|
|
673
|
+
iterables = [parse_expression]
|
|
674
|
+
iterables << parse_expression while match(:comma)
|
|
675
|
+
body = parse_block
|
|
676
|
+
AST::ForStmt.new(bindings:, iterables:, body:, inline: true, line:, column: bindings.first.column)
|
|
677
|
+
rescue ParseError => e
|
|
678
|
+
raise unless @recovery_errors
|
|
679
|
+
|
|
680
|
+
@recovery_errors << e
|
|
681
|
+
recovered_body = synchronize_to_statement_boundary
|
|
682
|
+
return recovery_error_block_stmt(e, recovered_body, header_type: :for) if recovered_body
|
|
683
|
+
|
|
684
|
+
recovery_error_stmt(e)
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
def parse_inline_while_stmt(inline_token)
|
|
688
|
+
line = inline_token.line
|
|
689
|
+
condition = parse_expression
|
|
690
|
+
body = parse_block
|
|
691
|
+
AST::WhileStmt.new(condition:, body:, inline: true, line:, column: inline_token.column, length: inline_token.lexeme.length)
|
|
692
|
+
rescue ParseError => e
|
|
693
|
+
raise unless @recovery_errors
|
|
694
|
+
|
|
695
|
+
@recovery_errors << e
|
|
696
|
+
recovered_body = synchronize_to_statement_boundary
|
|
697
|
+
return AST::WhileStmt.new(
|
|
698
|
+
condition: condition || recovery_error_expr(e),
|
|
699
|
+
body: recovered_body,
|
|
700
|
+
line:,
|
|
701
|
+
column: inline_token.column,
|
|
702
|
+
length: inline_token.lexeme.length,
|
|
703
|
+
) if recovered_body
|
|
704
|
+
|
|
705
|
+
recovery_error_stmt(e)
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
def parse_inline_match_stmt(inline_token)
|
|
709
|
+
token = previous
|
|
710
|
+
line = token.line
|
|
711
|
+
arms = []
|
|
712
|
+
expression = parse_expression
|
|
713
|
+
arms = parse_match_arms(arms)
|
|
714
|
+
AST::MatchStmt.new(expression:, arms:, inline: true, line:, column: token.column, length: token.lexeme.length)
|
|
715
|
+
rescue ParseError => e
|
|
716
|
+
raise unless @recovery_errors
|
|
717
|
+
|
|
718
|
+
@recovery_errors << e
|
|
719
|
+
recovered_arms = synchronize_to_match_arm_boundary
|
|
720
|
+
return AST::MatchStmt.new(expression: expression || recovery_error_expr(e), arms: arms + recovered_arms, inline: true, line:, column: token.column, length: token.lexeme.length) if recovered_arms
|
|
721
|
+
|
|
722
|
+
recovery_error_stmt(e)
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
def parse_inline_if_stmt(inline_token)
|
|
726
|
+
token = previous
|
|
727
|
+
line = token.line
|
|
728
|
+
branches = [parse_if_branch(token)]
|
|
729
|
+
|
|
730
|
+
while check(:else) && check_next(:if)
|
|
731
|
+
advance
|
|
732
|
+
advance
|
|
733
|
+
branches << parse_if_branch(previous)
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
else_body = match(:else) ? parse_else_branch_body : nil
|
|
737
|
+
AST::IfStmt.new(branches:, else_body:, inline: true, line:)
|
|
738
|
+
end
|
|
739
|
+
|
|
740
|
+
def parse_assignment_or_expression_stmt
|
|
741
|
+
line = peek.line
|
|
742
|
+
expression = parse_expression
|
|
743
|
+
if match(*Token::ASSIGNMENT_TYPES)
|
|
744
|
+
operator = previous.lexeme
|
|
745
|
+
column = previous.column
|
|
746
|
+
value = parse_expression
|
|
747
|
+
consume_end_of_statement unless block_expression?(value)
|
|
748
|
+
AST::Assignment.new(target: expression, operator:, value:, line:, column:)
|
|
749
|
+
else
|
|
750
|
+
consume_end_of_statement unless block_expression?(expression)
|
|
751
|
+
AST::ExpressionStmt.new(expression:, line:)
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
end
|
|
756
|
+
end
|