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,749 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
module Parse
|
|
5
|
+
module Declarations
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def parse_import
|
|
9
|
+
line = previous.line
|
|
10
|
+
path = parse_qualified_name
|
|
11
|
+
local_name = path.parts.last
|
|
12
|
+
local_column = previous.column
|
|
13
|
+
alias_name = if match(:as)
|
|
14
|
+
alias_token = consume_name("expected import alias")
|
|
15
|
+
local_name = alias_token.lexeme
|
|
16
|
+
local_column = alias_token.column
|
|
17
|
+
alias_token.lexeme
|
|
18
|
+
end
|
|
19
|
+
consume_end_of_statement
|
|
20
|
+
AST::Import.new(path:, alias_name:, line:, column: local_column, length: local_name.length)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def parse_declaration
|
|
24
|
+
attributes = parse_attribute_applications
|
|
25
|
+
visibility, visibility_token = parse_visibility
|
|
26
|
+
|
|
27
|
+
if legacy_layout_modifier_start?(peek)
|
|
28
|
+
raise error(peek, "layout modifiers must use attributes like @[packed] or @[align(...)]")
|
|
29
|
+
elsif match(:attribute)
|
|
30
|
+
reject_attributes!(attributes, "attribute")
|
|
31
|
+
parse_attribute_decl(visibility:)
|
|
32
|
+
elsif match(:const)
|
|
33
|
+
if match(:function)
|
|
34
|
+
parse_function_def(visibility:, const: true, attributes:)
|
|
35
|
+
else
|
|
36
|
+
parse_const_decl(visibility:, attributes:)
|
|
37
|
+
end
|
|
38
|
+
elsif match(:var)
|
|
39
|
+
reject_attributes!(attributes, "var")
|
|
40
|
+
parse_var_decl(visibility:)
|
|
41
|
+
elsif match(:event)
|
|
42
|
+
parse_event_decl(visibility:, attributes:)
|
|
43
|
+
elsif match(:type)
|
|
44
|
+
reject_attributes!(attributes, "type")
|
|
45
|
+
parse_type_alias_decl(visibility:)
|
|
46
|
+
elsif match(:struct)
|
|
47
|
+
parse_struct_decl(visibility:, attributes:)
|
|
48
|
+
elsif match(:union)
|
|
49
|
+
parse_union_decl(visibility:, attributes:)
|
|
50
|
+
elsif match(:enum)
|
|
51
|
+
parse_enum_decl(AST::EnumDecl, visibility:, attributes:)
|
|
52
|
+
elsif match(:flags)
|
|
53
|
+
parse_enum_decl(AST::FlagsDecl, visibility:, attributes:)
|
|
54
|
+
elsif match(:variant)
|
|
55
|
+
parse_variant_decl(visibility:, attributes:)
|
|
56
|
+
elsif match(:interface)
|
|
57
|
+
reject_attributes!(attributes, "interface")
|
|
58
|
+
parse_interface_decl(visibility:)
|
|
59
|
+
elsif match(:opaque)
|
|
60
|
+
reject_attributes!(attributes, "opaque")
|
|
61
|
+
parse_opaque_decl(visibility:)
|
|
62
|
+
elsif match(:extending)
|
|
63
|
+
reject_attributes!(attributes, "extending")
|
|
64
|
+
raise error(visibility_token, "public is not allowed on extending blocks") if visibility == :public
|
|
65
|
+
|
|
66
|
+
parse_extending_block
|
|
67
|
+
elsif check(:editable) || check(:static)
|
|
68
|
+
reject_attributes!(attributes, "standalone method")
|
|
69
|
+
raise error(peek, "#{peek.lexeme} function is only allowed inside extending blocks")
|
|
70
|
+
elsif match(:foreign)
|
|
71
|
+
parse_foreign_decl(visibility:, attributes:)
|
|
72
|
+
elsif match(:async)
|
|
73
|
+
consume(:function, "expected function after async")
|
|
74
|
+
parse_function_def(visibility:, async: true, attributes:)
|
|
75
|
+
elsif match(:function)
|
|
76
|
+
parse_function_def(visibility:, attributes:)
|
|
77
|
+
elsif match(:external)
|
|
78
|
+
raise error(visibility_token, "public is not allowed on external declarations") if visibility == :public
|
|
79
|
+
|
|
80
|
+
parse_extern_decl(attributes:)
|
|
81
|
+
elsif match(:static_assert)
|
|
82
|
+
reject_attributes!(attributes, "static_assert")
|
|
83
|
+
raise error(visibility_token, "public is not allowed on static_assert") if visibility == :public
|
|
84
|
+
|
|
85
|
+
parse_static_assert
|
|
86
|
+
elsif check_when_start?
|
|
87
|
+
reject_attributes!(attributes, "when")
|
|
88
|
+
raise error(visibility_token, "public is not allowed on when") if visibility == :public
|
|
89
|
+
|
|
90
|
+
advance
|
|
91
|
+
parse_when_decl
|
|
92
|
+
else
|
|
93
|
+
message = visibility == :public ? "expected exportable declaration after public" : "expected declaration"
|
|
94
|
+
raise error(peek, message)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def parse_raw_module_body(errors: nil)
|
|
99
|
+
imports = []
|
|
100
|
+
directives = []
|
|
101
|
+
declarations = []
|
|
102
|
+
|
|
103
|
+
while match(:import)
|
|
104
|
+
if errors
|
|
105
|
+
begin
|
|
106
|
+
imports << parse_import
|
|
107
|
+
rescue ParseError => e
|
|
108
|
+
errors << e
|
|
109
|
+
synchronize_to_top_level_boundary
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
imports << parse_import
|
|
113
|
+
end
|
|
114
|
+
skip_newlines
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
while raw_module_directive_start?
|
|
118
|
+
if errors
|
|
119
|
+
begin
|
|
120
|
+
directives << parse_raw_module_directive
|
|
121
|
+
rescue ParseError => e
|
|
122
|
+
errors << e
|
|
123
|
+
synchronize_to_top_level_boundary
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
directives << parse_raw_module_directive
|
|
127
|
+
end
|
|
128
|
+
skip_newlines
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
until eof?
|
|
132
|
+
if errors
|
|
133
|
+
begin
|
|
134
|
+
declarations << parse_raw_module_declaration
|
|
135
|
+
rescue ParseError => e
|
|
136
|
+
errors << e
|
|
137
|
+
synchronize_to_top_level_boundary
|
|
138
|
+
end
|
|
139
|
+
else
|
|
140
|
+
declarations << parse_raw_module_declaration
|
|
141
|
+
end
|
|
142
|
+
skip_newlines
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
[imports, directives, declarations]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def raw_module_directive_start?
|
|
149
|
+
check(:link) || check(:include) || check(:compiler_flag)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def parse_raw_module_directive
|
|
153
|
+
if match(:link)
|
|
154
|
+
parse_link_directive
|
|
155
|
+
elsif match(:include)
|
|
156
|
+
parse_include_directive
|
|
157
|
+
elsif match(:compiler_flag)
|
|
158
|
+
parse_compiler_flag_directive
|
|
159
|
+
else
|
|
160
|
+
raise error(peek, "expected external directive")
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def parse_link_directive
|
|
165
|
+
value = consume(:string, "expected string literal after link").literal
|
|
166
|
+
consume_end_of_statement
|
|
167
|
+
AST::LinkDirective.new(value:)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def parse_include_directive
|
|
171
|
+
value = consume(:string, "expected string literal after include").literal
|
|
172
|
+
consume_end_of_statement
|
|
173
|
+
AST::IncludeDirective.new(value:)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def parse_compiler_flag_directive
|
|
177
|
+
value = consume(:string, "expected string literal after compiler_flag").literal
|
|
178
|
+
consume_end_of_statement
|
|
179
|
+
AST::CompilerFlagDirective.new(value:)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def parse_raw_module_declaration
|
|
183
|
+
attributes = parse_attribute_applications
|
|
184
|
+
|
|
185
|
+
if match(:public)
|
|
186
|
+
reject_attributes!(attributes)
|
|
187
|
+
raise error(previous, "public is not allowed in external files")
|
|
188
|
+
elsif legacy_layout_modifier_start?(peek)
|
|
189
|
+
raise error(peek, "layout modifiers must use attributes like @[packed] or @[align(...)]")
|
|
190
|
+
elsif match(:attribute)
|
|
191
|
+
reject_attributes!(attributes)
|
|
192
|
+
raise error(previous, "attribute is not allowed in external files")
|
|
193
|
+
elsif match(:const)
|
|
194
|
+
reject_attributes!(attributes)
|
|
195
|
+
if match(:function)
|
|
196
|
+
parse_function_def(visibility:, const: true, attributes:)
|
|
197
|
+
else
|
|
198
|
+
parse_const_decl(visibility: nil)
|
|
199
|
+
end
|
|
200
|
+
elsif match(:event)
|
|
201
|
+
reject_attributes!(attributes)
|
|
202
|
+
raise error(previous, "event is not allowed in external files")
|
|
203
|
+
elsif match(:type)
|
|
204
|
+
reject_attributes!(attributes)
|
|
205
|
+
parse_type_alias_decl(visibility: nil)
|
|
206
|
+
elsif match(:struct)
|
|
207
|
+
parse_struct_decl(visibility: nil, attributes:)
|
|
208
|
+
elsif match(:union)
|
|
209
|
+
reject_attributes!(attributes)
|
|
210
|
+
parse_union_decl(visibility: nil)
|
|
211
|
+
elsif match(:enum)
|
|
212
|
+
reject_attributes!(attributes)
|
|
213
|
+
parse_enum_decl(AST::EnumDecl, visibility: nil)
|
|
214
|
+
elsif match(:flags)
|
|
215
|
+
reject_attributes!(attributes)
|
|
216
|
+
parse_enum_decl(AST::FlagsDecl, visibility: nil)
|
|
217
|
+
elsif match(:opaque)
|
|
218
|
+
reject_attributes!(attributes)
|
|
219
|
+
parse_opaque_decl(visibility: nil)
|
|
220
|
+
elsif match(:external)
|
|
221
|
+
reject_attributes!(attributes)
|
|
222
|
+
parse_extern_decl(attributes:)
|
|
223
|
+
elsif check_when_start?
|
|
224
|
+
reject_attributes!(attributes)
|
|
225
|
+
advance
|
|
226
|
+
parse_when_stmt
|
|
227
|
+
else
|
|
228
|
+
raise error(peek, raw_module_declaration_error_message(peek))
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def raw_module_declaration_error_message(token)
|
|
233
|
+
case token.type
|
|
234
|
+
when :import
|
|
235
|
+
"imports must appear before external directives and declarations"
|
|
236
|
+
when :link, :include, :compiler_flag
|
|
237
|
+
"#{token.lexeme} directives must appear before external declarations"
|
|
238
|
+
when :attribute, :event, :var, :variant, :interface, :extending, :foreign, :function, :static_assert
|
|
239
|
+
"#{token.lexeme} is not allowed in external files"
|
|
240
|
+
when :async
|
|
241
|
+
"async function is not allowed in external files"
|
|
242
|
+
when :module
|
|
243
|
+
"module headers are not allowed in external files"
|
|
244
|
+
else
|
|
245
|
+
"expected external declaration"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def parse_const_decl(visibility: :private, attributes: [])
|
|
250
|
+
line = previous.line
|
|
251
|
+
name = nil
|
|
252
|
+
type = nil
|
|
253
|
+
name_token = consume_name("expected constant name")
|
|
254
|
+
name = name_token.lexeme
|
|
255
|
+
if match(:arrow)
|
|
256
|
+
type = parse_type_ref
|
|
257
|
+
body = parse_block
|
|
258
|
+
return AST::ConstDecl.new(name:, type:, value: nil, block_body: body, visibility:, attributes:, line:, column: name_token.column)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
consume(:colon, "expected ':' after constant name")
|
|
262
|
+
type = parse_type_ref
|
|
263
|
+
consume(:equal, "expected '=' after constant type")
|
|
264
|
+
value = parse_expression
|
|
265
|
+
consume_end_of_statement
|
|
266
|
+
AST::ConstDecl.new(name:, type:, value:, visibility:, attributes:, line:, column: name_token.column)
|
|
267
|
+
rescue ParseError => e
|
|
268
|
+
raise unless @recovery_errors && name
|
|
269
|
+
|
|
270
|
+
@recovery_errors << e
|
|
271
|
+
synchronize_to_statement_boundary
|
|
272
|
+
AST::ConstDecl.new(name:, type: type || recovery_error_expr(e), value: recovery_error_expr(e), visibility:, attributes:, line:, column: name_token.column)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def parse_var_decl(visibility: :private)
|
|
276
|
+
line = previous.line
|
|
277
|
+
name = nil
|
|
278
|
+
var_type = nil
|
|
279
|
+
name_token = consume_name("expected variable name")
|
|
280
|
+
name = name_token.lexeme
|
|
281
|
+
var_type = match(:colon) ? parse_type_ref : nil
|
|
282
|
+
value = if match(:equal)
|
|
283
|
+
parse_expression
|
|
284
|
+
else
|
|
285
|
+
raise error(name_token, "module variable without initializer requires a type") unless var_type
|
|
286
|
+
|
|
287
|
+
nil
|
|
288
|
+
end
|
|
289
|
+
consume_end_of_statement
|
|
290
|
+
AST::VarDecl.new(name:, type: var_type, value:, visibility:, line:, column: name_token.column)
|
|
291
|
+
rescue ParseError => e
|
|
292
|
+
raise unless @recovery_errors && name
|
|
293
|
+
|
|
294
|
+
@recovery_errors << e
|
|
295
|
+
synchronize_to_statement_boundary
|
|
296
|
+
AST::VarDecl.new(name:, type: var_type || recovery_error_expr(e), value: recovery_error_expr(e), visibility:, line:, column: name_token.column)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def parse_event_decl(visibility: :private, attributes: [])
|
|
300
|
+
line = previous.line
|
|
301
|
+
name_token = consume_name("expected event name")
|
|
302
|
+
consume(:lbracket, "expected '[' after event name")
|
|
303
|
+
capacity = consume(:integer, "expected positive integer capacity").literal
|
|
304
|
+
consume(:rbracket, "expected ']' after event capacity")
|
|
305
|
+
payload_type = nil
|
|
306
|
+
if match(:lparen)
|
|
307
|
+
payload_type = parse_type_ref
|
|
308
|
+
consume(:rparen, "expected ')' after event payload type")
|
|
309
|
+
end
|
|
310
|
+
consume_end_of_statement
|
|
311
|
+
AST::EventDecl.new(name: name_token.lexeme, capacity:, payload_type:, visibility:, attributes:, line:, column: name_token.column)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def parse_type_alias_decl(visibility: :private)
|
|
315
|
+
line = previous.line
|
|
316
|
+
name_token = consume_name("expected type alias name")
|
|
317
|
+
name = name_token.lexeme
|
|
318
|
+
consume(:equal, "expected '=' after type alias name")
|
|
319
|
+
target = parse_type_ref
|
|
320
|
+
consume_end_of_statement
|
|
321
|
+
AST::TypeAliasDecl.new(name:, target:, visibility:, line:, column: name_token.column)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def parse_attribute_decl(visibility: :private)
|
|
325
|
+
line = previous.line
|
|
326
|
+
consume(:lbracket, "expected '[' after attribute")
|
|
327
|
+
targets = parse_comma_separated_until(:rbracket) do
|
|
328
|
+
target_token = consume_path_component("expected attribute target")
|
|
329
|
+
case target_token.lexeme
|
|
330
|
+
when "struct" then :struct
|
|
331
|
+
when "field" then :field
|
|
332
|
+
when "callable" then :callable
|
|
333
|
+
when "const" then :const
|
|
334
|
+
when "event" then :event
|
|
335
|
+
when "enum" then :enum
|
|
336
|
+
when "flags" then :flags
|
|
337
|
+
when "union" then :union
|
|
338
|
+
when "variant" then :variant
|
|
339
|
+
else
|
|
340
|
+
raise error(target_token, "unknown attribute target #{target_token.lexeme}")
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
consume(:rbracket, "expected ']' after attribute targets")
|
|
344
|
+
name_token = consume_name_allowing_keywords("expected attribute name")
|
|
345
|
+
params = check(:lparen) ? parse_signature_params : []
|
|
346
|
+
consume_end_of_statement
|
|
347
|
+
AST::AttributeDecl.new(name: name_token.lexeme, targets:, params:, visibility:, line:, column: name_token.column)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def parse_struct_decl(packed: false, alignment: nil, visibility: :private, attributes: [])
|
|
351
|
+
line = previous.line
|
|
352
|
+
name_token = consume_name("expected struct name")
|
|
353
|
+
name = name_token.lexeme
|
|
354
|
+
lifetime_params, type_params = parse_struct_decl_params
|
|
355
|
+
implements = parse_implements_clause
|
|
356
|
+
c_name = parse_optional_explicit_c_name
|
|
357
|
+
packed, alignment = parse_struct_layout_attributes(attributes) if attributes.any?
|
|
358
|
+
members = parse_named_block do
|
|
359
|
+
parse_struct_member
|
|
360
|
+
end
|
|
361
|
+
fields = members.filter_map { |kind, member| member if kind == :field }
|
|
362
|
+
events = members.filter_map { |kind, member| member if kind == :event }
|
|
363
|
+
nested_types = members.filter_map { |kind, member| member if kind == :nested_type }
|
|
364
|
+
AST::StructDecl.new(name:, type_params:, implements:, c_name:, fields:, events:, nested_types:, attributes:, packed:, alignment:, visibility:, lifetime_params:, line:, column: name_token.column)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def parse_struct_decl_params
|
|
368
|
+
return [[], []] unless match(:lbracket)
|
|
369
|
+
|
|
370
|
+
lifetime_params = []
|
|
371
|
+
type_params = []
|
|
372
|
+
|
|
373
|
+
loop do
|
|
374
|
+
break if check(:rbracket)
|
|
375
|
+
|
|
376
|
+
if match(:at)
|
|
377
|
+
name_token = consume_name("expected lifetime name after @")
|
|
378
|
+
lifetime_params << "@#{name_token.lexeme}"
|
|
379
|
+
else
|
|
380
|
+
name_token = consume_name("expected type parameter name")
|
|
381
|
+
if match(:colon)
|
|
382
|
+
value_type = parse_type_ref
|
|
383
|
+
type_params << AST::ValueTypeParam.new(
|
|
384
|
+
name: name_token.lexeme,
|
|
385
|
+
type: value_type,
|
|
386
|
+
line: name_token.line,
|
|
387
|
+
column: name_token.column,
|
|
388
|
+
length: name_token.lexeme.length,
|
|
389
|
+
)
|
|
390
|
+
else
|
|
391
|
+
constraints = parse_type_param_constraints
|
|
392
|
+
type_params << AST::TypeParam.new(
|
|
393
|
+
name: name_token.lexeme,
|
|
394
|
+
constraints:,
|
|
395
|
+
line: name_token.line,
|
|
396
|
+
column: name_token.column,
|
|
397
|
+
length: name_token.lexeme.length,
|
|
398
|
+
)
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
break unless match(:comma)
|
|
403
|
+
next if check(:rbracket)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
consume(:rbracket, "expected ']' after struct parameters")
|
|
407
|
+
[lifetime_params, type_params]
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
def parse_struct_member
|
|
411
|
+
field_attributes = parse_attribute_applications
|
|
412
|
+
visibility, visibility_token = parse_visibility
|
|
413
|
+
|
|
414
|
+
if match(:event)
|
|
415
|
+
return [:event, parse_event_decl(visibility:, attributes: field_attributes)]
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
if match(:struct)
|
|
419
|
+
return [:nested_type, parse_struct_decl(visibility:, attributes: field_attributes)]
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
raise error(visibility_token, "public is only allowed on struct events") if visibility == :public
|
|
423
|
+
|
|
424
|
+
field_token = consume_name("expected field name")
|
|
425
|
+
field_name = field_token.lexeme
|
|
426
|
+
consume(:colon, "expected ':' after field name")
|
|
427
|
+
field_type = parse_type_ref
|
|
428
|
+
consume_end_of_statement
|
|
429
|
+
[:field, AST::Field.new(name: field_name, type: field_type, attributes: field_attributes, line: field_token.line, column: field_token.column)]
|
|
430
|
+
rescue ParseError => e
|
|
431
|
+
raise unless @recovery_errors
|
|
432
|
+
|
|
433
|
+
@recovery_errors << e
|
|
434
|
+
synchronize_to_statement_boundary
|
|
435
|
+
field_name_error = (field_name if defined?(field_name)) || "error"
|
|
436
|
+
[:field, AST::Field.new(name: field_name_error, type: recovery_error_expr(e), attributes: field_attributes, line: e.token&.line || 1, column: e.token&.column || 1)]
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def parse_union_decl(visibility: :private, attributes: [])
|
|
440
|
+
line = previous.line
|
|
441
|
+
name_token = consume_name("expected union name")
|
|
442
|
+
name = name_token.lexeme
|
|
443
|
+
c_name = parse_optional_explicit_c_name
|
|
444
|
+
fields = parse_named_block do
|
|
445
|
+
field_name = consume_name("expected field name").lexeme
|
|
446
|
+
consume(:colon, "expected ':' after field name")
|
|
447
|
+
field_type = parse_type_ref
|
|
448
|
+
consume_end_of_statement
|
|
449
|
+
AST::Field.new(name: field_name, type: field_type)
|
|
450
|
+
end
|
|
451
|
+
AST::UnionDecl.new(name:, c_name:, fields:, visibility:, attributes:, line:, column: name_token.column)
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def parse_optional_explicit_c_name
|
|
455
|
+
return nil unless match(:equal)
|
|
456
|
+
|
|
457
|
+
consume(:cstring, "expected C string literal after '='").literal
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def parse_enum_decl(node_class, visibility: :private, attributes: [])
|
|
461
|
+
line = previous.line
|
|
462
|
+
name_token = consume_name("expected declaration name")
|
|
463
|
+
name = name_token.lexeme
|
|
464
|
+
consume(:colon, "expected ':' after declaration name")
|
|
465
|
+
backing_type = if check(:newline) || check(:indent)
|
|
466
|
+
AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["int"], type_arguments: []), arguments: [], nullable: false, lifetime: nil, line: line, column: name.length + 1)
|
|
467
|
+
else
|
|
468
|
+
parse_type_ref
|
|
469
|
+
end
|
|
470
|
+
skip_newlines
|
|
471
|
+
consume(:indent, "expected indented declaration body")
|
|
472
|
+
|
|
473
|
+
members = []
|
|
474
|
+
skip_newlines
|
|
475
|
+
auto_value = 0
|
|
476
|
+
until check(:dedent) || eof?
|
|
477
|
+
member_token = consume_name("expected member name")
|
|
478
|
+
member_name = member_token.lexeme
|
|
479
|
+
if match(:equal)
|
|
480
|
+
value = parse_expression
|
|
481
|
+
if value.is_a?(AST::IntegerLiteral)
|
|
482
|
+
auto_value = value.value + 1
|
|
483
|
+
elsif value.is_a?(AST::UnaryOp) && value.operator == "-" && value.operand.is_a?(AST::IntegerLiteral)
|
|
484
|
+
auto_value = -value.operand.value + 1
|
|
485
|
+
end
|
|
486
|
+
else
|
|
487
|
+
value = AST::IntegerLiteral.new(lexeme: auto_value.to_s, value: auto_value)
|
|
488
|
+
auto_value += 1
|
|
489
|
+
end
|
|
490
|
+
consume_end_of_statement
|
|
491
|
+
members << AST::EnumMember.new(name: member_name, value:, line: member_token.line, column: member_token.column)
|
|
492
|
+
skip_newlines
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
consume(:dedent, "expected end of declaration body")
|
|
496
|
+
node_class.new(name:, backing_type:, members:, visibility:, attributes:, line:, column: name_token.column)
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def parse_variant_decl(visibility: :private, attributes: [])
|
|
500
|
+
line = previous.line
|
|
501
|
+
name_token = consume_name("expected variant name")
|
|
502
|
+
name = name_token.lexeme
|
|
503
|
+
type_params = parse_declaration_type_params
|
|
504
|
+
arms = parse_named_block do
|
|
505
|
+
arm_name = consume_name("expected variant arm name").lexeme
|
|
506
|
+
fields = if match(:lparen)
|
|
507
|
+
parsed = parse_comma_separated_until(:rparen) do
|
|
508
|
+
field_name = consume_name("expected field name").lexeme
|
|
509
|
+
consume(:colon, "expected ':' after field name")
|
|
510
|
+
field_type = parse_type_ref
|
|
511
|
+
AST::Field.new(name: field_name, type: field_type)
|
|
512
|
+
end
|
|
513
|
+
consume(:rparen, "expected ')' after variant arm fields")
|
|
514
|
+
parsed
|
|
515
|
+
else
|
|
516
|
+
[]
|
|
517
|
+
end
|
|
518
|
+
consume_end_of_statement
|
|
519
|
+
AST::VariantArm.new(name: arm_name, fields:)
|
|
520
|
+
end
|
|
521
|
+
AST::VariantDecl.new(name:, type_params:, arms:, visibility:, attributes:, line:, column: name_token.column)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
def parse_opaque_decl(visibility: :private)
|
|
525
|
+
line = previous.line
|
|
526
|
+
name_token = consume_name("expected opaque type name")
|
|
527
|
+
name = name_token.lexeme
|
|
528
|
+
implements = parse_implements_clause
|
|
529
|
+
c_name = nil
|
|
530
|
+
if match(:equal)
|
|
531
|
+
c_name = consume(:cstring, "expected C string literal after '='").literal
|
|
532
|
+
end
|
|
533
|
+
consume_end_of_statement
|
|
534
|
+
AST::OpaqueDecl.new(name:, implements:, c_name:, visibility:, line:, column: name_token.column)
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
def parse_interface_decl(visibility: :private)
|
|
538
|
+
line = previous.line
|
|
539
|
+
name_token = consume_name("expected interface name")
|
|
540
|
+
name = name_token.lexeme
|
|
541
|
+
type_params = parse_declaration_type_params
|
|
542
|
+
methods = parse_named_block do
|
|
543
|
+
method_attributes = parse_attribute_applications
|
|
544
|
+
parse_interface_method_decl(attributes: method_attributes)
|
|
545
|
+
end
|
|
546
|
+
AST::InterfaceDecl.new(name:, type_params:, methods:, visibility:, line:, column: name_token.column)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def parse_extending_block
|
|
550
|
+
line = previous.line
|
|
551
|
+
type_name = parse_type_ref
|
|
552
|
+
receiver_type_param_names = extending_target_type_param_names(type_name)
|
|
553
|
+
methods = with_type_param_names(receiver_type_param_names) do
|
|
554
|
+
parse_named_block do
|
|
555
|
+
method_attributes = parse_attribute_applications
|
|
556
|
+
parse_method_def(attributes: method_attributes)
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
AST::ExtendingBlock.new(type_name:, methods:, line:, column: type_name.column)
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
def extending_target_type_param_names(type_name)
|
|
563
|
+
type_name.arguments.flat_map do |argument|
|
|
564
|
+
extending_target_type_param_names_from_argument(argument.value)
|
|
565
|
+
end.uniq
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def extending_target_type_param_names_from_argument(value)
|
|
569
|
+
case value
|
|
570
|
+
when AST::TypeRef
|
|
571
|
+
nested_names = value.arguments.flat_map do |argument|
|
|
572
|
+
extending_target_type_param_names_from_argument(argument.value)
|
|
573
|
+
end
|
|
574
|
+
if value.name.parts.length == 1 && value.arguments.empty? && !value.nullable
|
|
575
|
+
name = value.name.parts.first
|
|
576
|
+
nested_names << name unless known_type_like_name?(name)
|
|
577
|
+
end
|
|
578
|
+
nested_names
|
|
579
|
+
when AST::FunctionType, AST::ProcType
|
|
580
|
+
value.params.flat_map { |param| extending_target_type_param_names_from_argument(param.type) } +
|
|
581
|
+
extending_target_type_param_names_from_argument(value.return_type)
|
|
582
|
+
else
|
|
583
|
+
[]
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def parse_function_def(visibility: :private, async: false, const: false, attributes: [])
|
|
588
|
+
line = previous.line
|
|
589
|
+
name_token = consume_name("expected function name")
|
|
590
|
+
name = name_token.lexeme
|
|
591
|
+
type_params, params, return_type, body = parse_callable_signature
|
|
592
|
+
AST::FunctionDef.new(name:, type_params:, params:, return_type:, body:, visibility:, async:, const:, attributes:, line:, column: name_token.column)
|
|
593
|
+
rescue ParseError => e
|
|
594
|
+
raise unless @recovery_errors
|
|
595
|
+
|
|
596
|
+
@recovery_errors << e
|
|
597
|
+
AST::FunctionDef.new(name:, type_params: [], params: [], return_type: nil, body: nil, visibility:, async:, const:, attributes:, line:, column: name_token.column)
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def parse_method_def(attributes: [])
|
|
601
|
+
visibility, _visibility_token, async, kind, line, name_token = parse_method_like_decl_head
|
|
602
|
+
name = name_token.lexeme
|
|
603
|
+
type_params, params, return_type, body = parse_callable_signature
|
|
604
|
+
AST::MethodDef.new(name:, type_params:, params:, return_type:, body:, kind:, visibility:, async:, attributes:, line:, column: name_token.column)
|
|
605
|
+
rescue ParseError => e
|
|
606
|
+
raise unless @recovery_errors
|
|
607
|
+
|
|
608
|
+
@recovery_errors << e
|
|
609
|
+
name = name_token&.lexeme || "unknown"
|
|
610
|
+
col = name_token&.column || 1
|
|
611
|
+
advance until eof? || check(:function) || check(:dedent)
|
|
612
|
+
AST::MethodDef.new(name:, type_params: [], params: [], return_type: nil, body: nil, kind: kind || :plain, visibility: visibility || :private, async: async || false, attributes:, line:, column: col)
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
def parse_interface_method_decl(attributes: [])
|
|
616
|
+
visibility, visibility_token, async, kind, line, name_token = parse_method_like_decl_head
|
|
617
|
+
raise error(visibility_token, "public is not allowed on interface methods") if visibility == :public
|
|
618
|
+
|
|
619
|
+
name = name_token.lexeme
|
|
620
|
+
_type_params, params, return_type, _body = parse_callable_signature(
|
|
621
|
+
allow_type_params: false,
|
|
622
|
+
generic_error_token: name_token,
|
|
623
|
+
generic_error_message: "interface method #{name} cannot be generic",
|
|
624
|
+
allow_body: false
|
|
625
|
+
)
|
|
626
|
+
AST::InterfaceMethodDecl.new(name:, params:, return_type:, kind:, async:, attributes:, line:, column: name_token.column)
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def parse_method_like_decl_head
|
|
630
|
+
visibility, visibility_token = parse_visibility
|
|
631
|
+
async = match(:async)
|
|
632
|
+
kind = parse_method_kind
|
|
633
|
+
if check(:function)
|
|
634
|
+
consume(:function, "expected function declaration")
|
|
635
|
+
elsif check(:identifier)
|
|
636
|
+
bad_token = advance
|
|
637
|
+
@recovery_errors << ParseError.new("unknown keyword '#{bad_token.lexeme}'; expected 'function' (did you mean 'editable', 'static', or 'async'?)", token: bad_token, path: @path) if @recovery_errors
|
|
638
|
+
else
|
|
639
|
+
raise error(peek, "expected function declaration")
|
|
640
|
+
end
|
|
641
|
+
line = previous.line
|
|
642
|
+
name_token = consume_name("expected function name")
|
|
643
|
+
[visibility, visibility_token, async, kind, line, name_token]
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
def parse_method_kind
|
|
647
|
+
return :editable if match(:editable)
|
|
648
|
+
return :static if match(:static)
|
|
649
|
+
|
|
650
|
+
:plain
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
def parse_callable_signature(allow_type_params: true, generic_error_token: nil, generic_error_message: nil, allow_body: true)
|
|
654
|
+
type_params = parse_declaration_type_params
|
|
655
|
+
if !allow_type_params && type_params.any?
|
|
656
|
+
raise error(generic_error_token || previous, generic_error_message || "generic callable declarations are not allowed here")
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
params = nil
|
|
660
|
+
return_type = nil
|
|
661
|
+
body = nil
|
|
662
|
+
|
|
663
|
+
with_type_param_names(type_params.map(&:name)) do
|
|
664
|
+
params = parse_params
|
|
665
|
+
return_type = match(:arrow) ? parse_type_ref : nil
|
|
666
|
+
if allow_body
|
|
667
|
+
body = parse_block_body_safe
|
|
668
|
+
else
|
|
669
|
+
consume_end_of_statement
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
[type_params, params, return_type, body]
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
def parse_block_body_safe
|
|
677
|
+
parse_block
|
|
678
|
+
rescue ParseError => e
|
|
679
|
+
raise unless @recovery_errors
|
|
680
|
+
|
|
681
|
+
@recovery_errors << e
|
|
682
|
+
match(:newline)
|
|
683
|
+
if match(:indent)
|
|
684
|
+
begin
|
|
685
|
+
parse_and_dedent_block_body || []
|
|
686
|
+
rescue ParseError => e2
|
|
687
|
+
@recovery_errors << e2
|
|
688
|
+
[]
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def parse_visibility
|
|
694
|
+
return [:public, previous] if match(:public)
|
|
695
|
+
|
|
696
|
+
[:private, nil]
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
def parse_extern_decl(attributes: [])
|
|
700
|
+
consume(:function, "expected function after external")
|
|
701
|
+
parse_extern_function_decl(attributes:)
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
def parse_foreign_decl(visibility: :private, attributes: [])
|
|
705
|
+
consume(:function, "expected function after foreign")
|
|
706
|
+
parse_foreign_function_decl(visibility:, attributes:)
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
def parse_extern_function_decl(attributes: [])
|
|
710
|
+
line = previous.line
|
|
711
|
+
name = consume_name("expected function name").lexeme
|
|
712
|
+
type_params = parse_declaration_type_params
|
|
713
|
+
params = nil
|
|
714
|
+
variadic = false
|
|
715
|
+
return_type = nil
|
|
716
|
+
mapping = nil
|
|
717
|
+
with_type_param_names(type_params.map(&:name)) do
|
|
718
|
+
params, variadic = parse_foreign_params(allow_variadic: true)
|
|
719
|
+
consume(:arrow, "expected '->' before external function return type")
|
|
720
|
+
return_type = parse_type_ref
|
|
721
|
+
if match(:equal)
|
|
722
|
+
mapping = parse_expression
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
consume_end_of_statement
|
|
726
|
+
AST::ExternFunctionDecl.new(name:, type_params:, params:, return_type:, variadic:, attributes:, line:, mapping:)
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
def parse_foreign_function_decl(visibility: :private, attributes: [])
|
|
730
|
+
line = previous.line
|
|
731
|
+
name = consume_name("expected function name").lexeme
|
|
732
|
+
type_params = parse_declaration_type_params
|
|
733
|
+
params = nil
|
|
734
|
+
variadic = false
|
|
735
|
+
return_type = nil
|
|
736
|
+
mapping = nil
|
|
737
|
+
with_type_param_names(type_params.map(&:name)) do
|
|
738
|
+
params, variadic = parse_foreign_params(allow_variadic: true)
|
|
739
|
+
consume(:arrow, "expected '->' before foreign function return type")
|
|
740
|
+
return_type = parse_type_ref
|
|
741
|
+
consume(:equal, "expected '=' before foreign function mapping")
|
|
742
|
+
mapping = parse_expression
|
|
743
|
+
end
|
|
744
|
+
consume_end_of_statement
|
|
745
|
+
AST::ForeignFunctionDecl.new(name:, type_params:, params:, return_type:, variadic:, mapping:, visibility:, attributes:, line:)
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
end
|