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,624 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
module Parse
|
|
5
|
+
module Expressions
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def parse_expression
|
|
9
|
+
return parse_if_expression if match(:if)
|
|
10
|
+
return parse_match_expression if match(:match)
|
|
11
|
+
return parse_unsafe_expression if match(:unsafe)
|
|
12
|
+
|
|
13
|
+
parse_range
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse_range
|
|
17
|
+
expr = parse_or
|
|
18
|
+
return expr unless match(:dot_dot)
|
|
19
|
+
|
|
20
|
+
line = previous.line
|
|
21
|
+
column = expr.respond_to?(:column) ? expr.column : 0
|
|
22
|
+
end_expr = parse_or
|
|
23
|
+
AST::RangeExpr.new(start_expr: expr, end_expr:, line:, column:)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_if_expression
|
|
27
|
+
condition = parse_or
|
|
28
|
+
consume(:colon, "expected ':' after condition in if expression")
|
|
29
|
+
then_expression = parse_expression
|
|
30
|
+
consume(:else, "expected 'else' in if expression")
|
|
31
|
+
consume(:colon, "expected ':' after 'else' in if expression")
|
|
32
|
+
else_expression = parse_expression
|
|
33
|
+
AST::IfExpr.new(condition:, then_expression:, else_expression:)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def parse_match_expression
|
|
37
|
+
token = previous
|
|
38
|
+
expression = parse_expression
|
|
39
|
+
arms = parse_match_expression_arms
|
|
40
|
+
AST::MatchExpr.new(expression:, arms:, line: token.line, column: token.column, length: token.lexeme.length)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def parse_match_expression_arms
|
|
44
|
+
consume(:colon, "expected ':' before match expression arms")
|
|
45
|
+
consume(:newline, "expected newline before match expression arms")
|
|
46
|
+
consume(:indent, "expected indented match expression arms")
|
|
47
|
+
|
|
48
|
+
arms = []
|
|
49
|
+
skip_newlines
|
|
50
|
+
until check(:dedent) || eof?
|
|
51
|
+
arms.concat(parse_match_expression_arm)
|
|
52
|
+
skip_newlines
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
consume(:dedent, "expected end of match expression arms")
|
|
56
|
+
arms
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def parse_match_expression_arm
|
|
60
|
+
patterns = []
|
|
61
|
+
if match(:else)
|
|
62
|
+
patterns << AST::Identifier.new(name: "_", line: previous.line, column: previous.column)
|
|
63
|
+
else
|
|
64
|
+
patterns << parse_bitwise_xor
|
|
65
|
+
while match(:pipe)
|
|
66
|
+
patterns << parse_bitwise_xor
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
binding_token = nil
|
|
70
|
+
binding_name = if match(:as)
|
|
71
|
+
binding_token = consume_name("expected binding name after 'as'")
|
|
72
|
+
binding_token.lexeme
|
|
73
|
+
end
|
|
74
|
+
consume(:colon, "expected ':' after match expression arm pattern")
|
|
75
|
+
value = parse_expression
|
|
76
|
+
consume_end_of_statement unless block_expression?(value)
|
|
77
|
+
patterns.map do |pattern|
|
|
78
|
+
AST::MatchExprArm.new(
|
|
79
|
+
pattern:,
|
|
80
|
+
binding_name:,
|
|
81
|
+
binding_line: binding_token&.line,
|
|
82
|
+
binding_column: binding_token&.column,
|
|
83
|
+
value:,
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_unsafe_expression
|
|
89
|
+
token = previous
|
|
90
|
+
consume(:colon, "expected ':' after unsafe in expression")
|
|
91
|
+
expression = parse_expression
|
|
92
|
+
AST::UnsafeExpr.new(expression:, line: token.line, column: token.column, length: token.lexeme.length)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def parse_or
|
|
96
|
+
parse_left_associative(:parse_and, :or)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def parse_and
|
|
100
|
+
parse_left_associative(:parse_not, :and)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def parse_not
|
|
104
|
+
if match(:not)
|
|
105
|
+
operator = previous.lexeme
|
|
106
|
+
operand = parse_not
|
|
107
|
+
return AST::UnaryOp.new(operator:, operand:)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
parse_is
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def parse_is
|
|
114
|
+
expr = parse_bitwise_or
|
|
115
|
+
while match(:is)
|
|
116
|
+
line = previous.line
|
|
117
|
+
column = previous.column
|
|
118
|
+
arm_pattern = parse_bitwise_or
|
|
119
|
+
if arm_pattern.is_a?(AST::Call) && arm_pattern.arguments.any?
|
|
120
|
+
raise error(previous, "`is` does not support struct pattern bindings; use `match` to destructure payload fields")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
expr = AST::MatchExpr.new(
|
|
124
|
+
expression: expr,
|
|
125
|
+
arms: [
|
|
126
|
+
AST::MatchExprArm.new(
|
|
127
|
+
pattern: arm_pattern,
|
|
128
|
+
binding_name: nil,
|
|
129
|
+
binding_line: nil,
|
|
130
|
+
binding_column: nil,
|
|
131
|
+
value: AST::BooleanLiteral.new(value: true),
|
|
132
|
+
),
|
|
133
|
+
AST::MatchExprArm.new(
|
|
134
|
+
pattern: AST::Identifier.new(name: "_", line:, column:),
|
|
135
|
+
binding_name: nil,
|
|
136
|
+
binding_line: nil,
|
|
137
|
+
binding_column: nil,
|
|
138
|
+
value: AST::BooleanLiteral.new(value: false),
|
|
139
|
+
),
|
|
140
|
+
],
|
|
141
|
+
line:,
|
|
142
|
+
column:,
|
|
143
|
+
length: previous.lexeme.length,
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
expr
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def parse_bitwise_or
|
|
150
|
+
parse_left_associative(:parse_bitwise_xor, :pipe)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def parse_bitwise_xor
|
|
154
|
+
parse_left_associative(:parse_bitwise_and, :caret)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def parse_bitwise_and
|
|
158
|
+
parse_left_associative(:parse_equality, :amp)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def parse_equality
|
|
162
|
+
parse_left_associative(:parse_comparison, :equal_equal, :bang_equal)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def parse_comparison
|
|
166
|
+
parse_left_associative(:parse_shift, :less, :less_equal, :greater, :greater_equal)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def parse_shift
|
|
170
|
+
parse_left_associative(:parse_additive, :shift_left, :shift_right)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def parse_additive
|
|
174
|
+
parse_left_associative(:parse_multiplicative, :plus, :minus)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def parse_multiplicative
|
|
178
|
+
parse_left_associative(:parse_unary, :star, :slash, :percent)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def parse_unary
|
|
182
|
+
if (cast_prefix = try_parse_prefix_cast_expression)
|
|
183
|
+
cast_prefix
|
|
184
|
+
elsif match(:unsafe)
|
|
185
|
+
parse_unsafe_expression
|
|
186
|
+
elsif match(:await)
|
|
187
|
+
AST::AwaitExpr.new(expression: parse_unary)
|
|
188
|
+
elsif match(:detach)
|
|
189
|
+
line = previous.line
|
|
190
|
+
column = previous.column
|
|
191
|
+
AST::DetachExpr.new(body: [AST::ExpressionStmt.new(expression: parse_unary)], line:, column:)
|
|
192
|
+
elsif match(:minus, :plus, :tilde, :out, :in, :inout)
|
|
193
|
+
operator = previous.lexeme
|
|
194
|
+
operand = parse_unary
|
|
195
|
+
AST::UnaryOp.new(operator:, operand:)
|
|
196
|
+
else
|
|
197
|
+
parse_postfix
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def try_parse_prefix_cast_expression
|
|
202
|
+
saved_current = @current
|
|
203
|
+
return nil unless check_name && known_type_like_name?(peek.lexeme)
|
|
204
|
+
|
|
205
|
+
start_token = peek
|
|
206
|
+
expression = nil
|
|
207
|
+
target_type = parse_type_ref
|
|
208
|
+
type_tail = @tokens[@current - 1]
|
|
209
|
+
less_token = peek
|
|
210
|
+
return nil unless less_token.type == :less
|
|
211
|
+
|
|
212
|
+
minus_token = @tokens[@current + 1]
|
|
213
|
+
return nil unless minus_token&.type == :minus
|
|
214
|
+
|
|
215
|
+
unless adjacent_tokens?(type_tail, less_token) && adjacent_tokens?(less_token, minus_token)
|
|
216
|
+
raise error(less_token, "did you mean T<-expr?")
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
advance
|
|
220
|
+
advance
|
|
221
|
+
|
|
222
|
+
expression = parse_unary
|
|
223
|
+
AST::PrefixCast.new(target_type:, expression:, line: start_token.line, column: start_token.column)
|
|
224
|
+
rescue ParseError => e
|
|
225
|
+
raise e if parse_diagnostic_hint?(e)
|
|
226
|
+
|
|
227
|
+
nil
|
|
228
|
+
ensure
|
|
229
|
+
@current = saved_current if expression.nil?
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def adjacent_tokens?(left, right)
|
|
233
|
+
left.line == right.line && right.column == (left.column + left.lexeme.length)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def parse_postfix
|
|
237
|
+
expression = parse_primary
|
|
238
|
+
|
|
239
|
+
loop do
|
|
240
|
+
if match(:dot)
|
|
241
|
+
member_token = consume_name_allowing_keywords("expected member name after '.'")
|
|
242
|
+
expression = AST::MemberAccess.new(
|
|
243
|
+
receiver: expression,
|
|
244
|
+
member: member_token.lexeme,
|
|
245
|
+
line: member_token.line,
|
|
246
|
+
column: member_token.column,
|
|
247
|
+
)
|
|
248
|
+
elsif check(:lbracket)
|
|
249
|
+
if (specialization = try_parse_specialization(expression))
|
|
250
|
+
expression = specialization
|
|
251
|
+
else
|
|
252
|
+
advance
|
|
253
|
+
index = parse_expression
|
|
254
|
+
consume(:rbracket, "expected ']' after index expression")
|
|
255
|
+
expression = AST::IndexAccess.new(receiver: expression, index:)
|
|
256
|
+
end
|
|
257
|
+
elsif match(:lparen)
|
|
258
|
+
expression = AST::Call.new(callee: expression, arguments: parse_call_arguments)
|
|
259
|
+
elsif match(:question)
|
|
260
|
+
expression = AST::UnaryOp.new(operator: "?", operand: expression)
|
|
261
|
+
else
|
|
262
|
+
break
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
expression
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def try_parse_specialization(expression)
|
|
270
|
+
return nil unless postfix_bracket_starts_specialization?(expression)
|
|
271
|
+
|
|
272
|
+
saved_current = @current
|
|
273
|
+
advance
|
|
274
|
+
arguments = parse_comma_separated_until(:rbracket) do
|
|
275
|
+
AST::TypeArgument.new(value: parse_type_argument)
|
|
276
|
+
end
|
|
277
|
+
consume(:rbracket, "expected ']' after specialization arguments")
|
|
278
|
+
|
|
279
|
+
if match(:lparen)
|
|
280
|
+
call_arguments = parse_call_arguments
|
|
281
|
+
unless specialization_call_target?(expression, arguments, call_arguments)
|
|
282
|
+
@current = saved_current
|
|
283
|
+
return nil
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
return AST::Call.new(callee: AST::Specialization.new(callee: expression, arguments:), arguments: call_arguments)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
unless specialization_value_target?(expression, arguments)
|
|
290
|
+
@current = saved_current
|
|
291
|
+
return nil
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
AST::Specialization.new(callee: expression, arguments:)
|
|
295
|
+
rescue ParseError => e
|
|
296
|
+
raise e if parse_diagnostic_hint?(e)
|
|
297
|
+
|
|
298
|
+
@current = saved_current
|
|
299
|
+
nil
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def parse_call_arguments
|
|
303
|
+
arguments = []
|
|
304
|
+
unless check(:rparen)
|
|
305
|
+
loop do
|
|
306
|
+
arguments << parse_call_argument
|
|
307
|
+
break unless match(:comma)
|
|
308
|
+
break if check(:rparen)
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
consume(:rparen, "expected ')' after call arguments")
|
|
312
|
+
arguments
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def parse_call_argument
|
|
316
|
+
if check_name && check_next(:equal)
|
|
317
|
+
name = advance.lexeme
|
|
318
|
+
consume(:equal, "expected '=' after named argument name")
|
|
319
|
+
AST::Argument.new(name:, value: parse_expression)
|
|
320
|
+
else
|
|
321
|
+
AST::Argument.new(name: nil, value: parse_expression)
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def parse_primary
|
|
326
|
+
if match(:size_of)
|
|
327
|
+
parse_sizeof_expr
|
|
328
|
+
elsif match(:align_of)
|
|
329
|
+
parse_alignof_expr
|
|
330
|
+
elsif match(:offset_of)
|
|
331
|
+
parse_offsetof_expr
|
|
332
|
+
elsif match(:members_of) || match(:attributes_of) || match(:field_of) || match(:callable_of) || match(:attribute_of) || match(:has_attribute) || match(:attribute_arg) || match(:fields_of)
|
|
333
|
+
AST::Identifier.new(name: previous.lexeme, line: previous.line, column: previous.column)
|
|
334
|
+
elsif match(:proc)
|
|
335
|
+
parse_proc_expr
|
|
336
|
+
elsif match_name
|
|
337
|
+
AST::Identifier.new(name: previous.lexeme, line: previous.line, column: previous.column)
|
|
338
|
+
elsif match(:integer)
|
|
339
|
+
AST::IntegerLiteral.new(lexeme: previous.lexeme, value: previous.literal)
|
|
340
|
+
elsif match(:float)
|
|
341
|
+
AST::FloatLiteral.new(lexeme: previous.lexeme, value: previous.literal)
|
|
342
|
+
elsif match(:char_literal)
|
|
343
|
+
AST::CharLiteral.new(lexeme: previous.lexeme, value: previous.literal, line: previous.line, column: previous.column)
|
|
344
|
+
elsif match(:string)
|
|
345
|
+
parse_adjacent_string_literal(previous, cstring: false)
|
|
346
|
+
elsif match(:cstring)
|
|
347
|
+
parse_adjacent_string_literal(previous, cstring: true)
|
|
348
|
+
elsif match(:fstring)
|
|
349
|
+
parse_format_string_literal(previous.literal)
|
|
350
|
+
elsif match(:true)
|
|
351
|
+
AST::BooleanLiteral.new(value: true)
|
|
352
|
+
elsif match(:false)
|
|
353
|
+
AST::BooleanLiteral.new(value: false)
|
|
354
|
+
elsif match(:null)
|
|
355
|
+
line = previous.line
|
|
356
|
+
column = previous.column
|
|
357
|
+
type = nil
|
|
358
|
+
if match(:lbracket)
|
|
359
|
+
type = parse_type_ref
|
|
360
|
+
consume(:rbracket, "expected ']' after typed null literal")
|
|
361
|
+
end
|
|
362
|
+
AST::NullLiteral.new(type:, line:, column:)
|
|
363
|
+
elsif match(:lparen)
|
|
364
|
+
line = previous.line
|
|
365
|
+
column = previous.column
|
|
366
|
+
first = if check_name && check_next(:equal)
|
|
367
|
+
name_token = advance
|
|
368
|
+
consume(:equal, "expected '=' after named tuple field")
|
|
369
|
+
AST::Argument.new(name: name_token.lexeme, value: parse_expression)
|
|
370
|
+
else
|
|
371
|
+
parse_expression
|
|
372
|
+
end
|
|
373
|
+
if match(:comma)
|
|
374
|
+
elements = [first]
|
|
375
|
+
loop do
|
|
376
|
+
if check_name && check_next(:equal)
|
|
377
|
+
name_token = advance
|
|
378
|
+
consume(:equal, "expected '=' after named tuple field")
|
|
379
|
+
value = parse_expression
|
|
380
|
+
elements << AST::Argument.new(name: name_token.lexeme, value:)
|
|
381
|
+
else
|
|
382
|
+
elements << parse_expression
|
|
383
|
+
end
|
|
384
|
+
break unless match(:comma)
|
|
385
|
+
break if check(:rparen)
|
|
386
|
+
end
|
|
387
|
+
consume(:rparen, "expected ')' after tuple elements")
|
|
388
|
+
AST::ExpressionList.new(elements:, line:, column:)
|
|
389
|
+
else
|
|
390
|
+
consume(:rparen, "expected ')' after expression")
|
|
391
|
+
first
|
|
392
|
+
end
|
|
393
|
+
elsif keyword_token?(peek)
|
|
394
|
+
advance
|
|
395
|
+
AST::Identifier.new(name: previous.lexeme, line: previous.line, column: previous.column)
|
|
396
|
+
else
|
|
397
|
+
raise error(peek, "expected expression")
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def parse_adjacent_string_literal(first_token, cstring:)
|
|
402
|
+
lexeme = +first_token.lexeme
|
|
403
|
+
value = +first_token.literal
|
|
404
|
+
all_cstring = cstring
|
|
405
|
+
|
|
406
|
+
while match(:string, :cstring)
|
|
407
|
+
token = previous
|
|
408
|
+
lexeme << token.lexeme
|
|
409
|
+
value << token.literal
|
|
410
|
+
all_cstring &&= token.type == :cstring
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
AST::StringLiteral.new(lexeme:, value:, cstring: all_cstring)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def parse_proc_expr
|
|
417
|
+
consume(:lparen, "expected '(' after proc")
|
|
418
|
+
params = parse_comma_separated_until(:rparen) { parse_function_type_param }
|
|
419
|
+
|
|
420
|
+
consume(:rparen, "expected ')' after proc parameters")
|
|
421
|
+
consume(:arrow, "expected '->' after proc parameters")
|
|
422
|
+
return_type = parse_type_ref
|
|
423
|
+
consume(:colon, "expected ':' before proc body")
|
|
424
|
+
body = if match(:newline)
|
|
425
|
+
consume(:indent, "expected indented block")
|
|
426
|
+
statements = parse_statement_block_body
|
|
427
|
+
consume(:dedent, "expected end of block")
|
|
428
|
+
statements
|
|
429
|
+
else
|
|
430
|
+
[AST::ReturnStmt.new(value: parse_expression)]
|
|
431
|
+
end
|
|
432
|
+
AST::ProcExpr.new(params:, return_type:, body:)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def parse_sizeof_expr
|
|
436
|
+
consume(:lparen, "expected '(' after size_of")
|
|
437
|
+
type = parse_type_ref
|
|
438
|
+
consume(:rparen, "expected ')' after size_of type")
|
|
439
|
+
AST::SizeofExpr.new(type:)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def parse_alignof_expr
|
|
443
|
+
consume(:lparen, "expected '(' after align_of")
|
|
444
|
+
type = parse_type_ref
|
|
445
|
+
consume(:rparen, "expected ')' after align_of type")
|
|
446
|
+
AST::AlignofExpr.new(type:)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def parse_offsetof_expr
|
|
450
|
+
consume(:lparen, "expected '(' after offset_of")
|
|
451
|
+
type = parse_type_ref
|
|
452
|
+
consume(:comma, "expected ',' after offset_of type")
|
|
453
|
+
field = consume_name("expected field name in offset_of").lexeme
|
|
454
|
+
consume(:rparen, "expected ')' after offset_of field")
|
|
455
|
+
AST::OffsetofExpr.new(type:, field:)
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def parse_format_string_literal(parts)
|
|
459
|
+
AST::FormatString.new(parts: parts.map { |part| parse_format_string_part(part) })
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def parse_format_string_part(part)
|
|
463
|
+
case part.fetch(:kind)
|
|
464
|
+
when :text
|
|
465
|
+
AST::FormatTextPart.new(value: part.fetch(:value))
|
|
466
|
+
when :expr
|
|
467
|
+
format_spec = parse_format_spec(part.fetch(:format_spec))
|
|
468
|
+
AST::FormatExprPart.new(
|
|
469
|
+
expression: parse_embedded_expression(part.fetch(:source), line: part.fetch(:line), column: part.fetch(:column)),
|
|
470
|
+
format_spec:,
|
|
471
|
+
)
|
|
472
|
+
else
|
|
473
|
+
raise error(peek, "unsupported format string part #{part.inspect}")
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def parse_format_spec(spec_str)
|
|
478
|
+
return nil if spec_str.nil? || spec_str.empty?
|
|
479
|
+
|
|
480
|
+
trimmed = spec_str.strip
|
|
481
|
+
if (m = trimmed.match(/\A\.(\d+)\z/))
|
|
482
|
+
{ kind: :precision, value: m[1].to_i }
|
|
483
|
+
elsif trimmed == "x"
|
|
484
|
+
{ kind: :hex, uppercase: false }
|
|
485
|
+
elsif trimmed == "X"
|
|
486
|
+
{ kind: :hex, uppercase: true }
|
|
487
|
+
elsif trimmed == "o"
|
|
488
|
+
{ kind: :oct, uppercase: false }
|
|
489
|
+
elsif trimmed == "O"
|
|
490
|
+
{ kind: :oct, uppercase: true }
|
|
491
|
+
elsif trimmed == "b"
|
|
492
|
+
{ kind: :bin, uppercase: false }
|
|
493
|
+
elsif trimmed == "B"
|
|
494
|
+
{ kind: :bin, uppercase: true }
|
|
495
|
+
else
|
|
496
|
+
raise error(peek, "unsupported format spec '#{trimmed}': expected .N for float precision (e.g. :.2), :x/:X, :o/:O, or :b/:B")
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def parse_embedded_expression(source, line:, column:)
|
|
501
|
+
# Interpolation source may carry surrounding whitespace (e.g. `#{ x }`);
|
|
502
|
+
# strip it so leading whitespace is not re-lexed as indentation. Shift
|
|
503
|
+
# the column by the stripped leading width to keep error positions exact.
|
|
504
|
+
leading = source.length - source.lstrip.length
|
|
505
|
+
stripped = source.strip
|
|
506
|
+
tokens = Lexer.lex(stripped, path: @path).map do |token|
|
|
507
|
+
Token.new(
|
|
508
|
+
type: token.type,
|
|
509
|
+
lexeme: token.lexeme,
|
|
510
|
+
literal: token.literal,
|
|
511
|
+
line: token.line + line - 1,
|
|
512
|
+
column: token.column + column - 1 + leading,
|
|
513
|
+
start_offset: token.start_offset,
|
|
514
|
+
end_offset: token.end_offset,
|
|
515
|
+
leading_trivia: token.leading_trivia,
|
|
516
|
+
trailing_trivia: token.trailing_trivia,
|
|
517
|
+
)
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
parser = self.class.send(:new, tokens, path: @path)
|
|
521
|
+
parser.instance_variable_set(:@known_type_names, @known_type_names.dup)
|
|
522
|
+
parser.instance_variable_set(:@known_import_aliases, @known_import_aliases.dup)
|
|
523
|
+
parser.instance_variable_set(:@known_generic_callable_names, @known_generic_callable_names.dup)
|
|
524
|
+
parser.instance_variable_set(:@current_type_param_names, @current_type_param_names.dup)
|
|
525
|
+
|
|
526
|
+
expression = parser.send(:parse_expression)
|
|
527
|
+
parser.send(:skip_newlines)
|
|
528
|
+
raise parser.send(:error, parser.send(:peek), "expected end of interpolation") unless parser.send(:eof?)
|
|
529
|
+
|
|
530
|
+
expression
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
def parse_left_associative(operand_method, *operator_types)
|
|
534
|
+
expression = send(operand_method)
|
|
535
|
+
while match(*operator_types)
|
|
536
|
+
operator = previous.lexeme
|
|
537
|
+
right = send(operand_method)
|
|
538
|
+
expression = AST::BinaryOp.new(operator:, left: expression, right:)
|
|
539
|
+
end
|
|
540
|
+
expression
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
def postfix_bracket_starts_specialization?(expression)
|
|
544
|
+
specialization_target?(expression) && matching_rbracket_index(@current)
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
def specialization_target?(expression)
|
|
548
|
+
builtin_specialization_target?(expression) || aggregate_specialization_target?(expression)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
def builtin_specialization_target?(expression)
|
|
552
|
+
expression.is_a?(AST::Identifier) && %w[array reinterpret span zero ptr const_ptr own ref adapt equal hash order].include?(expression.name)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def parse_diagnostic_hint?(error)
|
|
556
|
+
error.message.include?("did you mean T<-expr?")
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def aggregate_specialization_target?(expression)
|
|
560
|
+
case expression
|
|
561
|
+
when AST::Identifier
|
|
562
|
+
true
|
|
563
|
+
when AST::MemberAccess
|
|
564
|
+
true
|
|
565
|
+
else
|
|
566
|
+
false
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def specialization_call_target?(expression, arguments, call_arguments)
|
|
571
|
+
if expression.is_a?(AST::Identifier) && %w[default zero].include?(expression.name) &&
|
|
572
|
+
!known_type_like_name?(expression.name) && !generic_callable_specialization_target?(expression)
|
|
573
|
+
return false
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
return true if builtin_specialization_target?(expression)
|
|
577
|
+
return true if aggregate_specialization_target?(expression) && call_arguments.all?(&:name)
|
|
578
|
+
return true if generic_callable_specialization_target?(expression) && arguments.all? { |argument| explicit_specialization_argument?(argument.value) }
|
|
579
|
+
return true if imported_member_specialization_target?(expression) && arguments.all? { |argument| explicit_specialization_argument?(argument.value) }
|
|
580
|
+
|
|
581
|
+
aggregate_specialization_target?(expression) && arguments.all? { |argument| definite_type_argument?(argument.value) }
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
def specialization_value_target?(expression, arguments)
|
|
585
|
+
return true if expression.is_a?(AST::Identifier) && expression.name == "zero" && arguments.all? { |argument| explicit_specialization_argument?(argument.value) }
|
|
586
|
+
return true if aggregate_specialization_target?(expression) && arguments.all? { |argument| definite_type_argument?(argument.value) }
|
|
587
|
+
return true if generic_callable_specialization_target?(expression) && arguments.all? { |argument| explicit_specialization_argument?(argument.value) }
|
|
588
|
+
return true if imported_member_specialization_target?(expression) && arguments.all? { |argument| explicit_specialization_argument?(argument.value) }
|
|
589
|
+
|
|
590
|
+
false
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def generic_callable_specialization_target?(expression)
|
|
594
|
+
expression.is_a?(AST::Identifier) && @known_generic_callable_names.key?(expression.name)
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
def imported_member_specialization_target?(expression)
|
|
598
|
+
expression.is_a?(AST::MemberAccess) && expression.receiver.is_a?(AST::Identifier) && @known_import_aliases.key?(expression.receiver.name)
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
def explicit_specialization_argument?(value)
|
|
602
|
+
definite_type_argument?(value) ||
|
|
603
|
+
potential_named_literal_type_argument?(value) ||
|
|
604
|
+
value.is_a?(AST::IntegerLiteral) ||
|
|
605
|
+
value.is_a?(AST::FloatLiteral)
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
def potential_named_literal_type_argument?(value)
|
|
609
|
+
value.is_a?(AST::TypeRef) && value.arguments.empty? && !value.nullable
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
def definite_type_argument?(value)
|
|
613
|
+
case value
|
|
614
|
+
when AST::FunctionType
|
|
615
|
+
true
|
|
616
|
+
when AST::TypeRef
|
|
617
|
+
known_type_like_name?(value.name.parts.first)
|
|
618
|
+
else
|
|
619
|
+
false
|
|
620
|
+
end
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
end
|