mt-lang 0.3.9 → 0.3.11
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 +4 -4
- data/README.md +2 -0
- data/docs/language-design.md +1 -2
- data/docs/language-manual.md +12 -1
- data/lib/milk_tea/base.rb +1 -2
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
- data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
- data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
- data/lib/milk_tea/bindings/steamworks.rb +12 -16
- data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
- data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
- data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
- data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
- data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
- data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
- data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
- data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
- data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
- data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
- data/lib/milk_tea/core/ast.rb +109 -51
- data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
- data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
- data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
- data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
- data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
- data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
- data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
- data/lib/milk_tea/core/c_backend/statements.rb +528 -530
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
- data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
- data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
- data/lib/milk_tea/core/c_backend.rb +17 -9
- data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
- data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
- data/lib/milk_tea/core/compile_time.rb +32 -38
- data/lib/milk_tea/core/control_flow/builder.rb +3 -5
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
- data/lib/milk_tea/core/ir.rb +10 -10
- data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
- data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
- data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
- data/lib/milk_tea/core/lexer/indentation.rb +0 -2
- data/lib/milk_tea/core/lexer/numbers.rb +0 -2
- data/lib/milk_tea/core/lexer/recovery.rb +0 -2
- data/lib/milk_tea/core/lexer/strings.rb +0 -2
- data/lib/milk_tea/core/lexer/symbols.rb +0 -2
- data/lib/milk_tea/core/lexer/trivia.rb +0 -2
- data/lib/milk_tea/core/lexer.rb +0 -2
- data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
- data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
- data/lib/milk_tea/core/lowering/async/normalization.rb +5 -3
- data/lib/milk_tea/core/lowering/async.rb +627 -630
- data/lib/milk_tea/core/lowering/block.rb +413 -416
- data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
- data/lib/milk_tea/core/lowering/declarations.rb +180 -183
- data/lib/milk_tea/core/lowering/dyn.rb +48 -50
- data/lib/milk_tea/core/lowering/events.rb +983 -985
- data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
- data/lib/milk_tea/core/lowering/functions.rb +185 -188
- data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
- data/lib/milk_tea/core/lowering/proc.rb +363 -366
- data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
- data/lib/milk_tea/core/lowering/scans.rb +179 -181
- data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
- data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
- data/lib/milk_tea/core/lowering.rb +5 -7
- data/lib/milk_tea/core/module_binder.rb +0 -2
- data/lib/milk_tea/core/module_loader/errors.rb +4 -2
- data/lib/milk_tea/core/module_loader.rb +113 -20
- data/lib/milk_tea/core/module_path_resolver.rb +0 -2
- data/lib/milk_tea/core/module_roots.rb +6 -8
- data/lib/milk_tea/core/parser/attributes.rb +0 -2
- data/lib/milk_tea/core/parser/blocks.rb +0 -2
- data/lib/milk_tea/core/parser/declarations.rb +7 -9
- data/lib/milk_tea/core/parser/expressions.rb +15 -10
- data/lib/milk_tea/core/parser/recovery.rb +0 -2
- data/lib/milk_tea/core/parser/statements.rb +8 -2
- data/lib/milk_tea/core/parser/types.rb +12 -14
- data/lib/milk_tea/core/parser.rb +0 -2
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +14 -17
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +106 -109
- data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
- data/lib/milk_tea/core/types/layout.rb +21 -22
- data/lib/milk_tea/core/types/predicates.rb +0 -2
- data/lib/milk_tea/core/types/registry.rb +16 -18
- data/lib/milk_tea/core/types/visitor.rb +0 -4
- data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
- data/lib/milk_tea/dap/protocol.rb +1 -1
- data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
- data/lib/milk_tea/dap/server/debug_map.rb +0 -2
- data/lib/milk_tea/dap/server/handlers.rb +0 -2
- data/lib/milk_tea/dap/server/launch.rb +0 -2
- data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
- data/lib/milk_tea/dap/server/utilities.rb +0 -2
- data/lib/milk_tea/dap/server/wire.rb +0 -2
- data/lib/milk_tea/dap/server.rb +0 -2
- data/lib/milk_tea/lsp/diagnostics.rb +16 -16
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
- data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
- data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
- data/lib/milk_tea/lsp/server/completion.rb +873 -875
- data/lib/milk_tea/lsp/server/configuration.rb +129 -131
- data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
- data/lib/milk_tea/lsp/server/definition.rb +564 -565
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
- data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
- data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
- data/lib/milk_tea/lsp/server/formatting.rb +478 -480
- data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
- data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
- data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
- data/lib/milk_tea/lsp/server/progress.rb +0 -2
- data/lib/milk_tea/lsp/server/references.rb +316 -318
- data/lib/milk_tea/lsp/server/rename.rb +445 -447
- data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1376 -1314
- data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
- data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
- data/lib/milk_tea/lsp/server/utilities.rb +397 -399
- data/lib/milk_tea/lsp/server.rb +0 -3
- data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
- data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
- data/lib/milk_tea/packages/atomic_write.rb +4 -5
- data/lib/milk_tea/packages/dependency_solver.rb +15 -15
- data/lib/milk_tea/packages/lock.rb +4 -4
- data/lib/milk_tea/packages/manager_cli.rb +1 -1
- data/lib/milk_tea/packages/manifest.rb +3 -3
- data/lib/milk_tea/packages/registry_store.rb +4 -6
- data/lib/milk_tea/packages/services.rb +16 -16
- data/lib/milk_tea/packages/source_cache.rb +4 -6
- data/lib/milk_tea/packages/source_resolver.rb +44 -44
- data/lib/milk_tea/packages/version.rb +8 -8
- data/lib/milk_tea/tooling/build.rb +3 -7
- data/lib/milk_tea/tooling/build_cache.rb +0 -2
- data/lib/milk_tea/tooling/cli.rb +10 -4
- data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
- data/lib/milk_tea/tooling/debug_map.rb +8 -10
- data/lib/milk_tea/tooling/docs_app.rb +0 -2
- data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
- data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
- data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
- data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
- data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
- data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
- data/lib/milk_tea/tooling/linter/rules.rb +87 -89
- data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
- data/lib/milk_tea/tooling/linter/visitors.rb +112 -54
- data/lib/milk_tea/tooling/linter.rb +0 -2
- data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
- data/lib/milk_tea/tooling/run.rb +0 -2
- data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
- data/std/cli.mt +13 -32
- data/std/color.mt +28 -28
- data/std/encoding.mt +4 -4
- data/std/graph.mt +1 -2
- data/std/hash.mt +14 -14
- data/std/http/server.mt +3 -3
- data/std/input.mt +1 -1
- data/std/json.mt +1 -1
- data/std/linear_algebra.mt +6 -6
- data/std/net/mux.mt +1 -1
- data/std/noise.mt +23 -23
- data/std/parse.mt +2 -2
- data/std/process.mt +3 -4
- data/std/sparse_set.mt +1 -1
- data/std/steering.mt +5 -5
- data/std/str.mt +1 -1
- data/std/tween.mt +4 -4
- data/std/utility.mt +3 -3
- metadata +2 -2
|
@@ -139,7 +139,7 @@ module MilkTea
|
|
|
139
139
|
next if analysis.module_kind == :raw_module
|
|
140
140
|
next if modules.key?(analysis.module_name)
|
|
141
141
|
|
|
142
|
-
prepare_analysis(analysis,
|
|
142
|
+
prepare_analysis(analysis, path: path)
|
|
143
143
|
collect_structs
|
|
144
144
|
|
|
145
145
|
synth_before_s = @artifacts.synthetic_structs.length
|
|
@@ -159,7 +159,7 @@ module MilkTea
|
|
|
159
159
|
variants: lower_variants.dup,
|
|
160
160
|
static_asserts: lower_static_asserts.dup,
|
|
161
161
|
functions: [],
|
|
162
|
-
|
|
162
|
+
path: path,
|
|
163
163
|
)
|
|
164
164
|
per_module_funcs[analysis.module_name].concat(lower_functions)
|
|
165
165
|
|
|
@@ -178,7 +178,7 @@ module MilkTea
|
|
|
178
178
|
ordered_analysis_pairs.each do |path, analysis|
|
|
179
179
|
next if analysis.module_kind == :raw_module
|
|
180
180
|
|
|
181
|
-
prepare_analysis(analysis,
|
|
181
|
+
prepare_analysis(analysis, path: path)
|
|
182
182
|
ensure_events_for_analysis(analysis)
|
|
183
183
|
|
|
184
184
|
synth_before_s = @artifacts.synthetic_structs.length
|
|
@@ -279,7 +279,7 @@ module MilkTea
|
|
|
279
279
|
variants: all_variants,
|
|
280
280
|
static_asserts: all_static_asserts,
|
|
281
281
|
functions: all_functions,
|
|
282
|
-
|
|
282
|
+
path: @program.root_path,
|
|
283
283
|
)
|
|
284
284
|
end
|
|
285
285
|
|
|
@@ -287,7 +287,7 @@ module MilkTea
|
|
|
287
287
|
ordered_analysis_pairs.each do |path, analysis|
|
|
288
288
|
next if analysis.module_kind == :raw_module
|
|
289
289
|
|
|
290
|
-
prepare_analysis(analysis,
|
|
290
|
+
prepare_analysis(analysis, path: path)
|
|
291
291
|
analysis.ast.declarations.grep(AST::EventDecl).each do |decl|
|
|
292
292
|
event_type = analysis.values.fetch(decl.name).type
|
|
293
293
|
ensure_event_runtime(event_type) if event_type.is_a?(Types::Event)
|
|
@@ -359,8 +359,6 @@ module MilkTea
|
|
|
359
359
|
ordered
|
|
360
360
|
end
|
|
361
361
|
|
|
362
|
-
private
|
|
363
|
-
|
|
364
362
|
include LowererScans
|
|
365
363
|
include LowererDeclarations
|
|
366
364
|
include LowererEvents
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
class ModuleLoadError < StandardError
|
|
5
|
-
attr_reader :path
|
|
5
|
+
attr_reader :path, :line, :column
|
|
6
6
|
|
|
7
|
-
def initialize(message, path:)
|
|
7
|
+
def initialize(message, path:, line: nil, column: nil)
|
|
8
8
|
@path = path
|
|
9
|
+
@line = line
|
|
10
|
+
@column = column
|
|
9
11
|
super("#{message}: #{path}")
|
|
10
12
|
end
|
|
11
13
|
|
|
@@ -98,6 +98,7 @@ module MilkTea
|
|
|
98
98
|
@collecting_analysis_cache = {}
|
|
99
99
|
@collecting_path_errors = {}
|
|
100
100
|
@checking_paths = []
|
|
101
|
+
@forward_bindings = {}
|
|
101
102
|
@platform = self.class.normalize_platform_name(platform)
|
|
102
103
|
@package_graph = package_graph
|
|
103
104
|
@package_manifest_cache = {}
|
|
@@ -176,7 +177,59 @@ module MilkTea
|
|
|
176
177
|
# Phase 3: Topological sort into independent levels
|
|
177
178
|
levels = topo_sort_levels(graph)
|
|
178
179
|
|
|
179
|
-
#
|
|
180
|
+
# Pre-register forward bindings for cycle members
|
|
181
|
+
all_checked = levels.flatten.to_set
|
|
182
|
+
cycle_members = graph.keys.reject { |p| all_checked.include?(p) }
|
|
183
|
+
cycle_members.each do |resolved_path|
|
|
184
|
+
ast = @parse_cache[resolved_path]
|
|
185
|
+
@forward_bindings[resolved_path] = create_forward_binding(ast)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Phase 4: Check cycle members with iterative refinement
|
|
189
|
+
# Pass 1: Check with forward bindings — registers type declarations.
|
|
190
|
+
# SemanticError is expected (forward types lack fields/constructors)
|
|
191
|
+
# but ModuleLoadError indicates a broken dependency graph.
|
|
192
|
+
cycle_members.each do |resolved_path|
|
|
193
|
+
check_path(resolved_path)
|
|
194
|
+
rescue SemanticError
|
|
195
|
+
# Forward types can't satisfy constructors. Pass 2 will retry.
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Update forward type objects in-place with field/arm info from the
|
|
199
|
+
# real analyses. This way, all references to forward types (function
|
|
200
|
+
# return types, struct field types, etc.) automatically see the full
|
|
201
|
+
# type information without needing to replace the objects themselves.
|
|
202
|
+
cycle_members.each do |resolved_path|
|
|
203
|
+
analysis = @analysis_cache[resolved_path]
|
|
204
|
+
next unless analysis
|
|
205
|
+
|
|
206
|
+
fw_binding = @forward_bindings[resolved_path]
|
|
207
|
+
next unless fw_binding
|
|
208
|
+
|
|
209
|
+
analysis.types.each do |name, real_type|
|
|
210
|
+
fw_type = fw_binding.types[name]
|
|
211
|
+
next unless fw_type
|
|
212
|
+
|
|
213
|
+
if real_type.respond_to?(:fields) && fw_type.respond_to?(:define_fields)
|
|
214
|
+
fw_type.define_fields(real_type.fields) unless real_type.fields.empty?
|
|
215
|
+
end
|
|
216
|
+
if real_type.respond_to?(:arms) && fw_type.respond_to?(:define_arms)
|
|
217
|
+
fw_type.define_arms(real_type.arms) unless real_type.arms.empty?
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Pass 2: Re-check with populated types — now cycle members see
|
|
223
|
+
# complete type information for each other.
|
|
224
|
+
cycle_members.each do |resolved_path|
|
|
225
|
+
previous = @analysis_cache.delete(resolved_path)
|
|
226
|
+
check_path(resolved_path)
|
|
227
|
+
rescue SemanticError
|
|
228
|
+
@analysis_cache[resolved_path] = previous if previous
|
|
229
|
+
end
|
|
230
|
+
@forward_bindings.clear
|
|
231
|
+
|
|
232
|
+
# Phase 5: Check acyclic modules (they see fully-checked analyses for all imports)
|
|
180
233
|
levels.each do |level_paths|
|
|
181
234
|
if level_paths.length == 1
|
|
182
235
|
check_path(level_paths.first)
|
|
@@ -189,10 +242,6 @@ module MilkTea
|
|
|
189
242
|
def parse_all(resolved_path)
|
|
190
243
|
return if @parse_cache.key?(resolved_path)
|
|
191
244
|
|
|
192
|
-
if @checking_paths.include?(resolved_path)
|
|
193
|
-
raise ModuleLoadError.new("cyclic import detected", path: resolved_path)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
245
|
@checking_paths << resolved_path
|
|
197
246
|
ast = load_file(resolved_path)
|
|
198
247
|
@parse_cache[resolved_path] = ast
|
|
@@ -202,7 +251,7 @@ module MilkTea
|
|
|
202
251
|
parse_all(import_path)
|
|
203
252
|
end
|
|
204
253
|
ensure
|
|
205
|
-
@checking_paths.pop
|
|
254
|
+
@checking_paths.pop
|
|
206
255
|
end
|
|
207
256
|
|
|
208
257
|
def topo_sort_levels(graph)
|
|
@@ -252,8 +301,13 @@ module MilkTea
|
|
|
252
301
|
|
|
253
302
|
ast.imports.each do |import|
|
|
254
303
|
import_path = @path_resolver.resolve_module_path(import.path.to_s, importer_path:, importer_module_name: ast.module_name.to_s)
|
|
255
|
-
|
|
256
|
-
|
|
304
|
+
|
|
305
|
+
if @forward_bindings.key?(import_path)
|
|
306
|
+
modules[import.path.to_s] = @forward_bindings[import_path]
|
|
307
|
+
else
|
|
308
|
+
import_analysis = check_path(import_path)
|
|
309
|
+
modules[import.path.to_s] = @binder.module_binding(import_analysis)
|
|
310
|
+
end
|
|
257
311
|
end
|
|
258
312
|
|
|
259
313
|
@async_runtime_installer.install_async_runtime_dependency!(ast, modules, importer_path:, collecting_errors: false)
|
|
@@ -291,8 +345,13 @@ module MilkTea
|
|
|
291
345
|
ast.imports.each do |import|
|
|
292
346
|
begin
|
|
293
347
|
import_path = @path_resolver.resolve_module_path(import.path.to_s, importer_path:, importer_module_name: ast.module_name.to_s)
|
|
294
|
-
|
|
295
|
-
|
|
348
|
+
|
|
349
|
+
if @forward_bindings.key?(import_path)
|
|
350
|
+
modules[import.path.to_s] = @forward_bindings[import_path]
|
|
351
|
+
else
|
|
352
|
+
import_analysis = check_path_collecting_errors(import_path)
|
|
353
|
+
modules[import.path.to_s] = @binder.module_binding(import_analysis)
|
|
354
|
+
end
|
|
296
355
|
rescue ModuleLoadError, PackageLockError, SemanticError => e
|
|
297
356
|
errors << ImportResolutionError.new(import:, error: e)
|
|
298
357
|
end
|
|
@@ -321,8 +380,6 @@ module MilkTea
|
|
|
321
380
|
@collecting_path_errors
|
|
322
381
|
end
|
|
323
382
|
|
|
324
|
-
private
|
|
325
|
-
|
|
326
383
|
def self.raise_platform_conflict!(path, pinned_platform, active_platform, error_class: nil)
|
|
327
384
|
if error_class == ModuleLoadError
|
|
328
385
|
raise ModuleLoadError.new("source file targets platform #{pinned_platform}; active platform is #{active_platform}", path:)
|
|
@@ -331,12 +388,16 @@ module MilkTea
|
|
|
331
388
|
message = "source file #{path} targets platform #{pinned_platform}; active platform is #{active_platform}"
|
|
332
389
|
raise(error_class || ArgumentError, message)
|
|
333
390
|
end
|
|
334
|
-
private_class_method :raise_platform_conflict!
|
|
335
391
|
|
|
336
392
|
def check_path(path)
|
|
337
393
|
resolved_path, ast, cached = check_module_cache(path)
|
|
338
394
|
return cached if cached
|
|
339
395
|
|
|
396
|
+
if @checking_paths.include?(resolved_path) && !@forward_bindings.key?(resolved_path)
|
|
397
|
+
raise ModuleLoadError.new("circular import not resolvable: module #{@parse_cache[resolved_path]&.module_name || File.basename(path)}", path: resolved_path)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
@checking_paths << resolved_path
|
|
340
401
|
imported_modules = imported_modules_for_ast(ast, importer_path: resolved_path)
|
|
341
402
|
global_index = build_global_import_index(ast)
|
|
342
403
|
analysis = SemanticAnalyzer.check(ast, imported_modules:, path: resolved_path, global_import_index: global_index)
|
|
@@ -344,13 +405,18 @@ module MilkTea
|
|
|
344
405
|
update_shared_cache(resolved_path, analysis)
|
|
345
406
|
analysis
|
|
346
407
|
ensure
|
|
347
|
-
@checking_paths.pop
|
|
408
|
+
@checking_paths.pop
|
|
348
409
|
end
|
|
349
410
|
|
|
350
411
|
def check_path_collecting_errors(path)
|
|
351
412
|
resolved_path, ast, cached = check_module_cache(path, extra_cache: @collecting_analysis_cache)
|
|
352
413
|
return cached if cached
|
|
353
414
|
|
|
415
|
+
if @checking_paths.include?(resolved_path) && !@forward_bindings.key?(resolved_path)
|
|
416
|
+
raise ModuleLoadError.new("circular import not resolvable: module #{@parse_cache[resolved_path]&.module_name || File.basename(path)}", path: resolved_path)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
@checking_paths << resolved_path
|
|
354
420
|
imported_modules = imported_modules_for_ast_collecting_errors(ast, importer_path: resolved_path).modules
|
|
355
421
|
result = SemanticAnalyzer.check_collecting_errors(ast, imported_modules:, path: resolved_path)
|
|
356
422
|
analysis = result[:analysis]
|
|
@@ -360,7 +426,7 @@ module MilkTea
|
|
|
360
426
|
@collecting_analysis_cache[resolved_path] = analysis
|
|
361
427
|
analysis
|
|
362
428
|
ensure
|
|
363
|
-
@checking_paths.pop
|
|
429
|
+
@checking_paths.pop
|
|
364
430
|
end
|
|
365
431
|
|
|
366
432
|
def check_module_cache(path, extra_cache: nil)
|
|
@@ -380,9 +446,6 @@ module MilkTea
|
|
|
380
446
|
end
|
|
381
447
|
end
|
|
382
448
|
|
|
383
|
-
raise ModuleLoadError.new("cyclic import detected", path: resolved_path) if @checking_paths.include?(resolved_path)
|
|
384
|
-
|
|
385
|
-
@checking_paths << resolved_path
|
|
386
449
|
ast = load_file(resolved_path)
|
|
387
450
|
[resolved_path, ast, nil]
|
|
388
451
|
end
|
|
@@ -433,8 +496,8 @@ module MilkTea
|
|
|
433
496
|
end
|
|
434
497
|
|
|
435
498
|
matching_root = @module_roots
|
|
436
|
-
|
|
437
|
-
|
|
499
|
+
.select { |root| path_within_root?(path, root) }
|
|
500
|
+
.max_by(&:length)
|
|
438
501
|
return module_name_for_path(path, matching_root) if matching_root
|
|
439
502
|
|
|
440
503
|
File.basename(path).sub(/\.(linux|windows|wasm)\.mt\z/, ".mt").sub(/\.mt\z/, "")
|
|
@@ -453,6 +516,36 @@ module MilkTea
|
|
|
453
516
|
normalized_path == normalized_root || normalized_path.start_with?(normalized_root + File::SEPARATOR)
|
|
454
517
|
end
|
|
455
518
|
|
|
519
|
+
def create_forward_binding(ast)
|
|
520
|
+
module_name = ast.module_name.to_s
|
|
521
|
+
types = {}
|
|
522
|
+
|
|
523
|
+
ast.declarations.each do |decl|
|
|
524
|
+
case decl
|
|
525
|
+
when AST::StructDecl
|
|
526
|
+
types[decl.name] = Types::Struct.new(decl.name, module_name:)
|
|
527
|
+
when AST::VariantDecl
|
|
528
|
+
types[decl.name] = Types::Variant.new(decl.name, module_name:)
|
|
529
|
+
when AST::EnumDecl
|
|
530
|
+
types[decl.name] = Types::Enum.new(decl.name, module_name:)
|
|
531
|
+
when AST::FlagsDecl
|
|
532
|
+
types[decl.name] = Types::Flags.new(decl.name, module_name:)
|
|
533
|
+
when AST::OpaqueDecl
|
|
534
|
+
types[decl.name] = Types::Opaque.new(decl.name, module_name:, external: false)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
ModuleBinding.new(
|
|
539
|
+
name: module_name, types:, type_declarations: {},
|
|
540
|
+
interfaces: {}, attributes: {}, attribute_applications: {},
|
|
541
|
+
values: {}, functions: {}, methods: {},
|
|
542
|
+
implemented_interfaces: {}, imports: {},
|
|
543
|
+
private_types: {}, private_interfaces: {}, private_attributes: {},
|
|
544
|
+
private_values: {}, private_functions: {}, private_methods: {},
|
|
545
|
+
private_implemented_interfaces: {},
|
|
546
|
+
)
|
|
547
|
+
end
|
|
548
|
+
|
|
456
549
|
def use_shared_cache?
|
|
457
550
|
@shared_cache && @source_overrides.empty?
|
|
458
551
|
end
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module ModuleRoots
|
|
5
|
-
module_function
|
|
6
5
|
|
|
7
|
-
def roots_for_path(path, env: ENV, locked: false)
|
|
6
|
+
def self.roots_for_path(path, env: ENV, locked: false)
|
|
8
7
|
roots = []
|
|
9
8
|
|
|
10
9
|
add_env_roots!(roots, env)
|
|
@@ -24,7 +23,7 @@ module MilkTea
|
|
|
24
23
|
.select { |root| File.directory?(root) }
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
def package_roots_for_path(path, locked: false)
|
|
26
|
+
def self.package_roots_for_path(path, locked: false)
|
|
28
27
|
PackageGraph.load(path, locked:).source_roots
|
|
29
28
|
rescue PackageManifestError
|
|
30
29
|
package_root = package_root_for_path(path)
|
|
@@ -33,7 +32,7 @@ module MilkTea
|
|
|
33
32
|
[package_root]
|
|
34
33
|
end
|
|
35
34
|
|
|
36
|
-
def project_root_for_path(path)
|
|
35
|
+
def self.project_root_for_path(path)
|
|
37
36
|
return nil unless path
|
|
38
37
|
|
|
39
38
|
current = File.expand_path(File.directory?(path) ? path : File.dirname(path))
|
|
@@ -47,7 +46,7 @@ module MilkTea
|
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
48
|
|
|
50
|
-
def package_root_for_path(path)
|
|
49
|
+
def self.package_root_for_path(path)
|
|
51
50
|
return nil unless path
|
|
52
51
|
|
|
53
52
|
current = File.expand_path(File.directory?(path) ? path : File.dirname(path))
|
|
@@ -61,7 +60,7 @@ module MilkTea
|
|
|
61
60
|
end
|
|
62
61
|
end
|
|
63
62
|
|
|
64
|
-
def normalize_root(root)
|
|
63
|
+
def self.normalize_root(root)
|
|
65
64
|
return nil if root.nil? || root.to_s.strip.empty?
|
|
66
65
|
|
|
67
66
|
expanded = File.expand_path(root.to_s)
|
|
@@ -72,7 +71,7 @@ module MilkTea
|
|
|
72
71
|
end
|
|
73
72
|
end
|
|
74
73
|
|
|
75
|
-
def add_env_roots!(roots, env)
|
|
74
|
+
def self.add_env_roots!(roots, env)
|
|
76
75
|
env_keys = %w[MILK_TEA_MODULE_ROOT MILK_TEA_STD_ROOT]
|
|
77
76
|
env_keys.each do |key|
|
|
78
77
|
value = env[key]
|
|
@@ -83,6 +82,5 @@ module MilkTea
|
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
end
|
|
86
|
-
private_class_method :add_env_roots!
|
|
87
85
|
end
|
|
88
86
|
end
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module Parse
|
|
5
5
|
module Declarations
|
|
6
|
-
private
|
|
7
|
-
|
|
8
6
|
def parse_import
|
|
9
7
|
line = previous.line
|
|
10
8
|
path = parse_qualified_name
|
|
@@ -374,10 +372,10 @@ module MilkTea
|
|
|
374
372
|
break if check(:rbracket)
|
|
375
373
|
|
|
376
374
|
if match(:at)
|
|
377
|
-
name_token =
|
|
375
|
+
name_token = consume_name_allowing_keywords("expected lifetime name after @")
|
|
378
376
|
lifetime_params << "@#{name_token.lexeme}"
|
|
379
377
|
else
|
|
380
|
-
name_token =
|
|
378
|
+
name_token = consume_name_allowing_keywords("expected type parameter name")
|
|
381
379
|
if match(:colon)
|
|
382
380
|
value_type = parse_type_ref
|
|
383
381
|
type_params << AST::ValueTypeParam.new(
|
|
@@ -421,7 +419,7 @@ module MilkTea
|
|
|
421
419
|
|
|
422
420
|
raise error(visibility_token, "public is only allowed on struct events") if visibility == :public
|
|
423
421
|
|
|
424
|
-
field_token =
|
|
422
|
+
field_token = consume_name_allowing_keywords("expected field name")
|
|
425
423
|
field_name = field_token.lexeme
|
|
426
424
|
consume(:colon, "expected ':' after field name")
|
|
427
425
|
field_type = parse_type_ref
|
|
@@ -442,7 +440,7 @@ module MilkTea
|
|
|
442
440
|
name = name_token.lexeme
|
|
443
441
|
c_name = parse_optional_explicit_c_name
|
|
444
442
|
fields = parse_named_block do
|
|
445
|
-
|
|
443
|
+
field_name = consume_name_allowing_keywords("expected field name").lexeme
|
|
446
444
|
consume(:colon, "expected ':' after field name")
|
|
447
445
|
field_type = parse_type_ref
|
|
448
446
|
consume_end_of_statement
|
|
@@ -473,7 +471,7 @@ module MilkTea
|
|
|
473
471
|
members = []
|
|
474
472
|
skip_newlines
|
|
475
473
|
until check(:dedent) || eof?
|
|
476
|
-
member_token =
|
|
474
|
+
member_token = consume_name_allowing_keywords("expected member name")
|
|
477
475
|
member_name = member_token.lexeme
|
|
478
476
|
if match(:equal)
|
|
479
477
|
value = parse_expression
|
|
@@ -495,10 +493,10 @@ module MilkTea
|
|
|
495
493
|
name = name_token.lexeme
|
|
496
494
|
type_params = parse_declaration_type_params
|
|
497
495
|
arms = parse_named_block do
|
|
498
|
-
arm_name =
|
|
496
|
+
arm_name = consume_name_allowing_keywords("expected variant arm name").lexeme
|
|
499
497
|
fields = if match(:lparen)
|
|
500
498
|
parsed = parse_comma_separated_until(:rparen) do
|
|
501
|
-
|
|
499
|
+
field_name = consume_name_allowing_keywords("expected field name").lexeme
|
|
502
500
|
consume(:colon, "expected ':' after field name")
|
|
503
501
|
field_type = parse_type_ref
|
|
504
502
|
AST::Field.new(name: field_name, type: field_type)
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module Parse
|
|
5
5
|
module Expressions
|
|
6
|
-
private
|
|
7
|
-
|
|
8
6
|
def parse_expression
|
|
9
7
|
return parse_if_expression if match(:if)
|
|
10
8
|
return parse_match_expression if match(:match)
|
|
@@ -18,7 +16,7 @@ module MilkTea
|
|
|
18
16
|
return expr unless match(:dot_dot)
|
|
19
17
|
|
|
20
18
|
line = previous.line
|
|
21
|
-
column = expr.
|
|
19
|
+
column = expr.column || 0
|
|
22
20
|
end_expr = parse_or
|
|
23
21
|
AST::RangeExpr.new(start_expr: expr, end_expr:, line:, column:)
|
|
24
22
|
end
|
|
@@ -107,6 +105,8 @@ module MilkTea
|
|
|
107
105
|
binding_line: binding_token&.line,
|
|
108
106
|
binding_column: binding_token&.column,
|
|
109
107
|
value:,
|
|
108
|
+
line: pattern.line,
|
|
109
|
+
column: pattern.column,
|
|
110
110
|
)
|
|
111
111
|
end
|
|
112
112
|
end
|
|
@@ -155,6 +155,8 @@ module MilkTea
|
|
|
155
155
|
binding_line: nil,
|
|
156
156
|
binding_column: nil,
|
|
157
157
|
value: AST::BooleanLiteral.new(value: true),
|
|
158
|
+
line: arm_pattern.line,
|
|
159
|
+
column: arm_pattern.column,
|
|
158
160
|
),
|
|
159
161
|
AST::MatchExprArm.new(
|
|
160
162
|
pattern: AST::Identifier.new(name: "_", line:, column:),
|
|
@@ -162,6 +164,8 @@ module MilkTea
|
|
|
162
164
|
binding_line: nil,
|
|
163
165
|
binding_column: nil,
|
|
164
166
|
value: AST::BooleanLiteral.new(value: false),
|
|
167
|
+
line:,
|
|
168
|
+
column:,
|
|
165
169
|
),
|
|
166
170
|
],
|
|
167
171
|
line:,
|
|
@@ -340,7 +344,7 @@ module MilkTea
|
|
|
340
344
|
end
|
|
341
345
|
|
|
342
346
|
def parse_call_argument
|
|
343
|
-
if check_name && check_next(:equal)
|
|
347
|
+
if (check_name || keyword_token?(peek)) && check_next(:equal)
|
|
344
348
|
name = advance.lexeme
|
|
345
349
|
consume(:equal, "expected '=' after named argument name")
|
|
346
350
|
AST::Argument.new(name:, value: parse_expression)
|
|
@@ -544,24 +548,25 @@ module MilkTea
|
|
|
544
548
|
)
|
|
545
549
|
end
|
|
546
550
|
|
|
547
|
-
parser = self.class.
|
|
551
|
+
parser = self.class.new(tokens, path: @path)
|
|
548
552
|
parser.instance_variable_set(:@known_type_names, @known_type_names.dup)
|
|
549
553
|
parser.instance_variable_set(:@known_import_aliases, @known_import_aliases.dup)
|
|
550
554
|
parser.instance_variable_set(:@known_generic_callable_names, @known_generic_callable_names.dup)
|
|
551
555
|
parser.instance_variable_set(:@current_type_param_names, @current_type_param_names.dup)
|
|
552
556
|
|
|
553
|
-
expression = parser.
|
|
554
|
-
parser.
|
|
555
|
-
raise parser.
|
|
557
|
+
expression = parser.parse_expression
|
|
558
|
+
parser.skip_newlines
|
|
559
|
+
raise parser.error(parser.peek, "expected end of interpolation") unless parser.eof?
|
|
556
560
|
|
|
557
561
|
expression
|
|
558
562
|
end
|
|
559
563
|
|
|
560
564
|
def parse_left_associative(operand_method, *operator_types)
|
|
561
|
-
|
|
565
|
+
operand = method(operand_method)
|
|
566
|
+
expression = operand.call
|
|
562
567
|
while match(*operator_types)
|
|
563
568
|
operator = previous.lexeme
|
|
564
|
-
right =
|
|
569
|
+
right = operand.call
|
|
565
570
|
expression = AST::BinaryOp.new(operator:, left: expression, right:)
|
|
566
571
|
end
|
|
567
572
|
expression
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module Parse
|
|
5
5
|
module Statements
|
|
6
|
-
private
|
|
7
|
-
|
|
8
6
|
def check_inline_stmt_start?
|
|
9
7
|
return false unless check(:inline)
|
|
10
8
|
|
|
@@ -353,6 +351,8 @@ module MilkTea
|
|
|
353
351
|
binding_line: binding_token&.line,
|
|
354
352
|
binding_column: binding_token&.column,
|
|
355
353
|
value:,
|
|
354
|
+
line: pattern.line,
|
|
355
|
+
column: pattern.column,
|
|
356
356
|
)
|
|
357
357
|
end
|
|
358
358
|
else
|
|
@@ -364,6 +364,8 @@ module MilkTea
|
|
|
364
364
|
binding_line: binding_token&.line,
|
|
365
365
|
binding_column: binding_token&.column,
|
|
366
366
|
body:,
|
|
367
|
+
line: pattern.line,
|
|
368
|
+
column: pattern.column,
|
|
367
369
|
)
|
|
368
370
|
end
|
|
369
371
|
end
|
|
@@ -378,6 +380,8 @@ module MilkTea
|
|
|
378
380
|
binding_line: binding_token&.line,
|
|
379
381
|
binding_column: binding_token&.column,
|
|
380
382
|
body: recovered_body,
|
|
383
|
+
line: patterns.first&.line,
|
|
384
|
+
column: patterns.first&.column,
|
|
381
385
|
)] if recovered_body
|
|
382
386
|
|
|
383
387
|
raise
|
|
@@ -617,6 +621,8 @@ module MilkTea
|
|
|
617
621
|
binding_line: binding_token.line,
|
|
618
622
|
binding_column: binding_token.column,
|
|
619
623
|
body:,
|
|
624
|
+
line: pattern.line,
|
|
625
|
+
column: pattern.column,
|
|
620
626
|
)
|
|
621
627
|
skip_newlines
|
|
622
628
|
end
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
module MilkTea
|
|
4
4
|
module Parse
|
|
5
5
|
module Types
|
|
6
|
-
private
|
|
7
|
-
|
|
8
6
|
def parse_params(allow_variadic: false)
|
|
9
7
|
parse_parameter_list(allow_variadic:) { parse_param }
|
|
10
8
|
end
|
|
@@ -94,7 +92,7 @@ module MilkTea
|
|
|
94
92
|
|
|
95
93
|
first_token = peek
|
|
96
94
|
if match(:at)
|
|
97
|
-
lt_token =
|
|
95
|
+
lt_token = consume_name_allowing_keywords("expected lifetime name after @")
|
|
98
96
|
return AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["@#{lt_token.lexeme}"]), arguments: [], nullable: false, lifetime: nil, line: first_token.line, column: first_token.column, length: lt_token.lexeme.length + 1)
|
|
99
97
|
end
|
|
100
98
|
name = parse_qualified_name
|
|
@@ -103,7 +101,7 @@ module MilkTea
|
|
|
103
101
|
if match(:lbracket)
|
|
104
102
|
if check(:at) && name.to_s == "ref"
|
|
105
103
|
match(:at)
|
|
106
|
-
lt_token =
|
|
104
|
+
lt_token = consume_name_allowing_keywords("expected lifetime name after @")
|
|
107
105
|
lifetime = "@#{lt_token.lexeme}"
|
|
108
106
|
consume(:comma, "expected ',' after lifetime in type arguments")
|
|
109
107
|
end
|
|
@@ -169,7 +167,7 @@ module MilkTea
|
|
|
169
167
|
end
|
|
170
168
|
|
|
171
169
|
def parse_function_type_param
|
|
172
|
-
name_token =
|
|
170
|
+
name_token = consume_name_allowing_keywords("expected function type parameter name")
|
|
173
171
|
name = name_token.lexeme
|
|
174
172
|
consume(:colon, "expected ':' after function type parameter name")
|
|
175
173
|
type = parse_type_ref
|
|
@@ -192,7 +190,7 @@ module MilkTea
|
|
|
192
190
|
return [] unless match(:lbracket)
|
|
193
191
|
|
|
194
192
|
params = parse_comma_separated_until(:rbracket) do
|
|
195
|
-
name_token =
|
|
193
|
+
name_token = consume_name_allowing_keywords("expected type parameter name")
|
|
196
194
|
name = name_token.lexeme
|
|
197
195
|
if match(:colon)
|
|
198
196
|
value_type = parse_type_ref
|
|
@@ -263,14 +261,14 @@ module MilkTea
|
|
|
263
261
|
parts << consume_path_component("expected identifier after '.'").lexeme
|
|
264
262
|
end
|
|
265
263
|
type_arguments = if match(:lbracket)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
264
|
+
args = parse_comma_separated_until(:rbracket) do
|
|
265
|
+
parse_type_ref
|
|
266
|
+
end
|
|
267
|
+
consume(:rbracket, "expected ']' after type arguments")
|
|
268
|
+
args
|
|
269
|
+
else
|
|
270
|
+
[]
|
|
271
|
+
end
|
|
274
272
|
AST::QualifiedName.new(parts:, type_arguments:, line: first_token.line, column: first_token.column)
|
|
275
273
|
end
|
|
276
274
|
end
|