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,442 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "predicates"
|
|
4
|
+
|
|
5
|
+
module MilkTea
|
|
6
|
+
class TypeVisitor
|
|
7
|
+
def initialize
|
|
8
|
+
@visited = {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def visit(type)
|
|
12
|
+
return if type.nil?
|
|
13
|
+
return if @visited[type.object_id]
|
|
14
|
+
|
|
15
|
+
@visited[type.object_id] = true
|
|
16
|
+
dispatch(type)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def dispatch(type)
|
|
20
|
+
case type
|
|
21
|
+
when Types::Nullable then visit_nullable(type)
|
|
22
|
+
when Types::GenericInstance then visit_generic_instance(type)
|
|
23
|
+
when Types::Span then visit_span(type)
|
|
24
|
+
when Types::Task then visit_task(type)
|
|
25
|
+
when Types::GenericStructDefinition then visit_generic_struct_definition(type)
|
|
26
|
+
when Types::GenericVariantDefinition then visit_generic_variant_definition(type)
|
|
27
|
+
when Types::Struct then visit_struct(type)
|
|
28
|
+
when Types::Union then visit_union(type)
|
|
29
|
+
when Types::StructInstance then visit_struct_instance(type)
|
|
30
|
+
when Types::Variant then visit_variant(type)
|
|
31
|
+
when Types::VariantInstance then visit_variant_instance(type)
|
|
32
|
+
when Types::VariantArmPayload then visit_variant_arm_payload(type)
|
|
33
|
+
when Types::Proc then visit_proc(type)
|
|
34
|
+
when Types::Function then visit_function(type)
|
|
35
|
+
when Types::Parameter then visit_parameter(type)
|
|
36
|
+
when Types::TypeVar then visit_type_var(type)
|
|
37
|
+
when Types::Null then visit_null(type)
|
|
38
|
+
when Types::Tuple then visit_tuple(type)
|
|
39
|
+
when Types::Dyn then visit_dyn(type)
|
|
40
|
+
when Types::SoA then visit_soa(type)
|
|
41
|
+
when Types::Event then visit_event(type)
|
|
42
|
+
when Types::LifetimeRef then visit_lifetime_ref(type)
|
|
43
|
+
else visit_default(type)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def visit_children(type)
|
|
48
|
+
type.children.each { |child| visit(child) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def visit_nullable(type); visit_children(type); end
|
|
52
|
+
def visit_generic_instance(type); visit_children(type); end
|
|
53
|
+
def visit_span(type); visit_children(type); end
|
|
54
|
+
def visit_task(type); visit_children(type); end
|
|
55
|
+
def visit_generic_struct_definition(type); visit_children(type); end
|
|
56
|
+
def visit_generic_variant_definition(type); visit_children(type); end
|
|
57
|
+
def visit_struct(type); visit_children(type); end
|
|
58
|
+
def visit_union(type); visit_children(type); end
|
|
59
|
+
def visit_struct_instance(type); visit_children(type); end
|
|
60
|
+
def visit_variant(type); visit_children(type); end
|
|
61
|
+
def visit_variant_instance(type); visit_children(type); end
|
|
62
|
+
def visit_variant_arm_payload(type); visit_children(type); end
|
|
63
|
+
def visit_proc(type); visit_children(type); end
|
|
64
|
+
def visit_function(type); visit_children(type); end
|
|
65
|
+
def visit_parameter(type); visit_children(type); end
|
|
66
|
+
def visit_tuple(type); visit_children(type); end
|
|
67
|
+
def visit_dyn(type); visit_children(type); end
|
|
68
|
+
def visit_soa(type); visit_children(type); end
|
|
69
|
+
def visit_event(type); visit_children(type); end
|
|
70
|
+
|
|
71
|
+
def visit_type_var(type); end
|
|
72
|
+
def visit_null(type); end
|
|
73
|
+
def visit_lifetime_ref(type); end
|
|
74
|
+
def visit_default(type); end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class ContainsTypeVarVisitor < TypeVisitor
|
|
78
|
+
def initialize
|
|
79
|
+
super
|
|
80
|
+
@found = false
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def found?
|
|
84
|
+
@found
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def visit_type_var(type)
|
|
88
|
+
@found = true
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class ContainsRefTypeVisitor < TypeVisitor
|
|
93
|
+
def initialize(allow_lifetimes: [])
|
|
94
|
+
super()
|
|
95
|
+
@found = false
|
|
96
|
+
@allow_lifetimes = allow_lifetimes
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def found?
|
|
100
|
+
@found
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def visit_generic_instance(type)
|
|
104
|
+
if type.name == "ref" && [1, 2].include?(type.arguments.length)
|
|
105
|
+
if type.arguments.length == 2
|
|
106
|
+
lt = type.arguments.first
|
|
107
|
+
if lt.is_a?(String) && @allow_lifetimes.include?(lt)
|
|
108
|
+
visit_children(type)
|
|
109
|
+
return
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
@found = true
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
visit_children(type)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class ContainsProcTypeVisitor < TypeVisitor
|
|
120
|
+
def initialize
|
|
121
|
+
super
|
|
122
|
+
@found = false
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def found?
|
|
126
|
+
@found
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def visit_proc(type)
|
|
130
|
+
@found = true
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def visit_generic_instance(type)
|
|
134
|
+
if type.name == "array" && type.arguments.first && !type.arguments.first.is_a?(Types::LiteralTypeArg)
|
|
135
|
+
visit(type.arguments.first)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class ContainsCallableRefTypeVisitor < TypeVisitor
|
|
141
|
+
def initialize
|
|
142
|
+
super
|
|
143
|
+
@found = false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def found?
|
|
147
|
+
@found
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def visit_proc(type)
|
|
151
|
+
checker = ContainsRefTypeVisitor.new
|
|
152
|
+
checker.visit(type)
|
|
153
|
+
@found = true if checker.found?
|
|
154
|
+
end
|
|
155
|
+
alias visit_function visit_proc
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
class StoredRefSupportedVisitor < TypeVisitor
|
|
159
|
+
include TypePredicates
|
|
160
|
+
|
|
161
|
+
def initialize(allow_lifetimes: [])
|
|
162
|
+
super()
|
|
163
|
+
@supported = true
|
|
164
|
+
@allow_lifetimes = allow_lifetimes
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def result?
|
|
168
|
+
@supported
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def visit_generic_instance(type)
|
|
172
|
+
if ref_type?(type)
|
|
173
|
+
lt = ref_lifetime(type)
|
|
174
|
+
if lt && @allow_lifetimes.include?(lt)
|
|
175
|
+
visit_children(type)
|
|
176
|
+
return
|
|
177
|
+
end
|
|
178
|
+
@supported = false
|
|
179
|
+
return
|
|
180
|
+
end
|
|
181
|
+
visit_children(type)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def visit_proc(type)
|
|
185
|
+
@supported = false unless callable_param_ref_supported?(type)
|
|
186
|
+
end
|
|
187
|
+
alias visit_function visit_proc
|
|
188
|
+
|
|
189
|
+
private
|
|
190
|
+
|
|
191
|
+
def visit_children(type)
|
|
192
|
+
type.children.each do |child|
|
|
193
|
+
visit(child)
|
|
194
|
+
return unless @supported
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
class SendableCheckVisitor < TypeVisitor
|
|
200
|
+
def initialize
|
|
201
|
+
super
|
|
202
|
+
@sendable = true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def sendable?
|
|
206
|
+
@sendable
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def visit_children(type)
|
|
210
|
+
type.children.each do |child|
|
|
211
|
+
visit(child)
|
|
212
|
+
return unless @sendable
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def visit_event(type)
|
|
217
|
+
@sendable = false
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def visit_dyn(type)
|
|
221
|
+
@sendable = false
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def visit_span(type)
|
|
225
|
+
@sendable = false
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def visit_proc(type)
|
|
229
|
+
@sendable = false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def visit_function(type); end
|
|
233
|
+
|
|
234
|
+
def visit_generic_instance(type)
|
|
235
|
+
case type.name
|
|
236
|
+
when "ptr", "const_ptr", "own", "ref"
|
|
237
|
+
@sendable = false
|
|
238
|
+
when "array"
|
|
239
|
+
el = type.arguments.first
|
|
240
|
+
visit(el) unless el.is_a?(Types::LiteralTypeArg)
|
|
241
|
+
when "str_buffer", "atomic"
|
|
242
|
+
# sendable
|
|
243
|
+
else
|
|
244
|
+
@sendable = false
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def visit_struct(type)
|
|
249
|
+
if type.respond_to?(:has_events?) && type.has_events?
|
|
250
|
+
@sendable = false
|
|
251
|
+
return
|
|
252
|
+
end
|
|
253
|
+
visit_children(type)
|
|
254
|
+
end
|
|
255
|
+
alias visit_struct_instance visit_struct
|
|
256
|
+
|
|
257
|
+
def visit_default(type)
|
|
258
|
+
case type
|
|
259
|
+
when Types::Primitive
|
|
260
|
+
@sendable = false if type.name == "str"
|
|
261
|
+
when Types::Error, Types::Opaque, Types::StringView
|
|
262
|
+
@sendable = false
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
class SubstituteTypeVisitor
|
|
268
|
+
def initialize(substitutions)
|
|
269
|
+
@substitutions = substitutions
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def apply(type)
|
|
273
|
+
case type
|
|
274
|
+
when Types::TypeVar
|
|
275
|
+
@substitutions.fetch(type.name, type)
|
|
276
|
+
when Types::LifetimeRef
|
|
277
|
+
@substitutions.fetch(type.name, type)
|
|
278
|
+
when Types::Nullable
|
|
279
|
+
substituted = apply(type.base)
|
|
280
|
+
substituted.equal?(type.base) ? type : Types::Registry.nullable(substituted)
|
|
281
|
+
when Types::GenericInstance
|
|
282
|
+
new_args = type.arguments.map do |arg|
|
|
283
|
+
arg.is_a?(Types::LiteralTypeArg) ? arg : apply(arg)
|
|
284
|
+
end
|
|
285
|
+
type.arguments.zip(new_args).all? { |old, new| old.equal?(new) } ? type : Types::Registry.generic_instance(type.name, new_args)
|
|
286
|
+
when Types::Span
|
|
287
|
+
substituted = apply(type.element_type)
|
|
288
|
+
substituted.equal?(type.element_type) ? type : Types::Registry.span(substituted)
|
|
289
|
+
when Types::Task
|
|
290
|
+
substituted = apply(type.result_type)
|
|
291
|
+
substituted.equal?(type.result_type) ? type : Types::Registry.task(substituted)
|
|
292
|
+
when Types::Event
|
|
293
|
+
new_payload = type.payload_type ? apply(type.payload_type) : nil
|
|
294
|
+
if new_payload.equal?(type.payload_type)
|
|
295
|
+
type
|
|
296
|
+
else
|
|
297
|
+
Types::Event.new(type.name, capacity: type.capacity, payload_type: new_payload, module_name: type.module_name, visibility: type.visibility, owner_type_name: type.owner_type_name)
|
|
298
|
+
end
|
|
299
|
+
when Types::Proc
|
|
300
|
+
changed = false
|
|
301
|
+
new_params = type.params.map do |param|
|
|
302
|
+
new_param_type = apply(param.type)
|
|
303
|
+
new_boundary = param.boundary_type ? apply(param.boundary_type) : nil
|
|
304
|
+
changed = true unless new_param_type.equal?(param.type) && new_boundary.equal?(param.boundary_type)
|
|
305
|
+
Types::Registry.parameter(param.name, new_param_type, mutable: param.mutable, passing_mode: param.passing_mode, boundary_type: new_boundary)
|
|
306
|
+
end
|
|
307
|
+
new_return = apply(type.return_type)
|
|
308
|
+
changed = true unless new_return.equal?(type.return_type)
|
|
309
|
+
changed ? Types::Registry.proc(params: new_params, return_type: new_return) : type
|
|
310
|
+
when Types::Function
|
|
311
|
+
changed = false
|
|
312
|
+
new_params = type.params.map do |param|
|
|
313
|
+
new_param_type = apply(param.type)
|
|
314
|
+
new_boundary = param.boundary_type ? apply(param.boundary_type) : nil
|
|
315
|
+
changed = true unless new_param_type.equal?(param.type) && new_boundary.equal?(param.boundary_type)
|
|
316
|
+
Types::Registry.parameter(param.name, new_param_type, mutable: param.mutable, passing_mode: param.passing_mode, boundary_type: new_boundary)
|
|
317
|
+
end
|
|
318
|
+
new_return = apply(type.return_type)
|
|
319
|
+
changed = true unless new_return.equal?(type.return_type)
|
|
320
|
+
new_receiver = type.receiver_type ? apply(type.receiver_type) : nil
|
|
321
|
+
changed = true unless new_receiver.equal?(type.receiver_type)
|
|
322
|
+
changed ? Types::Registry.function(type.name, params: new_params, return_type: new_return, receiver_type: new_receiver, receiver_editable: type.receiver_editable, variadic: type.variadic, external: type.external) : type
|
|
323
|
+
when Types::StructInstance
|
|
324
|
+
new_args = type.arguments.map { |arg| apply(arg) }
|
|
325
|
+
type.arguments.zip(new_args).all? { |old, new| old.equal?(new) } ? type : type.definition.instantiate(new_args)
|
|
326
|
+
when Types::VariantInstance
|
|
327
|
+
new_args = type.arguments.map { |arg| apply(arg) }
|
|
328
|
+
type.arguments.zip(new_args).all? { |old, new| old.equal?(new) } ? type : type.definition.instantiate(new_args)
|
|
329
|
+
else
|
|
330
|
+
type
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
class ContainsArrayStorageVisitor < TypeVisitor
|
|
336
|
+
def initialize
|
|
337
|
+
super
|
|
338
|
+
@found = false
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def found?
|
|
342
|
+
@found
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def dispatch(type)
|
|
346
|
+
case type
|
|
347
|
+
when Types::Nullable, Types::Struct, Types::StructInstance
|
|
348
|
+
visit_children(type)
|
|
349
|
+
when Types::GenericInstance
|
|
350
|
+
if type.name == "array"
|
|
351
|
+
@found = true
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def visit_children(type)
|
|
357
|
+
type.children.each do |child|
|
|
358
|
+
visit(child)
|
|
359
|
+
return if @found
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
class ProcStorageSupportedVisitor < TypeVisitor
|
|
365
|
+
def initialize
|
|
366
|
+
super
|
|
367
|
+
@supported = true
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def result?
|
|
371
|
+
@supported
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def dispatch(type)
|
|
375
|
+
case type
|
|
376
|
+
when Types::Nullable, Types::GenericInstance, Types::Struct, Types::Union,
|
|
377
|
+
Types::StructInstance, Types::Variant, Types::VariantInstance, Types::VariantArmPayload,
|
|
378
|
+
Types::Tuple, Types::Span
|
|
379
|
+
visit_children(type)
|
|
380
|
+
when Types::Proc
|
|
381
|
+
when Types::Task, Types::Function, Types::Dyn, Types::SoA
|
|
382
|
+
@supported = false
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def visit_children(type)
|
|
387
|
+
type.children.each do |child|
|
|
388
|
+
visit(child)
|
|
389
|
+
return unless @supported
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
class ValidateSpecializedTypeVisitor < TypeVisitor
|
|
395
|
+
def initialize(function_name:, context:, on_error:, on_generic_instance: nil)
|
|
396
|
+
super()
|
|
397
|
+
@function_name = function_name
|
|
398
|
+
@context = context
|
|
399
|
+
@on_error = on_error
|
|
400
|
+
@on_generic_instance = on_generic_instance
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def visit_type_var(type)
|
|
404
|
+
@on_error.call("cannot infer type argument #{type.name} for function #{@function_name}")
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def visit_generic_instance(type)
|
|
408
|
+
@on_generic_instance&.call(type.name, type.arguments)
|
|
409
|
+
visit_children(type)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def visit_proc(type)
|
|
413
|
+
type.params.each do |param|
|
|
414
|
+
with_context("#{@context} parameter #{param.name}") { visit(param.type) }
|
|
415
|
+
end
|
|
416
|
+
with_context("#{@context} return type") { visit(type.return_type) }
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def visit_function(type)
|
|
420
|
+
type.params.each do |param|
|
|
421
|
+
with_context("#{@context} parameter #{param.name}") { visit(param.type) }
|
|
422
|
+
if param.boundary_type
|
|
423
|
+
with_context("#{@context} boundary parameter #{param.name}") { visit(param.boundary_type) }
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
with_context("#{@context} return type") { visit(type.return_type) }
|
|
427
|
+
if type.receiver_type
|
|
428
|
+
with_context("#{@context} receiver type") { visit(type.receiver_type) }
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
private
|
|
433
|
+
|
|
434
|
+
def with_context(new_context)
|
|
435
|
+
old = @context
|
|
436
|
+
@context = new_context
|
|
437
|
+
yield
|
|
438
|
+
ensure
|
|
439
|
+
@context = old
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
require_relative "core/keywords"
|
|
6
|
+
require_relative "core/token"
|
|
7
|
+
require_relative "core/token_stream"
|
|
8
|
+
require_relative "core/lexer"
|
|
9
|
+
require_relative "core/cst"
|
|
10
|
+
require_relative "core/cst_builder"
|
|
11
|
+
require_relative "core/ast"
|
|
12
|
+
require_relative "core/types/types"
|
|
13
|
+
require_relative "core/binding_types"
|
|
14
|
+
require_relative "core/compile_time"
|
|
15
|
+
require_relative "core/compatibility_helpers"
|
|
16
|
+
require_relative "core/parser"
|
|
17
|
+
require_relative "core/module_roots"
|
|
18
|
+
require_relative "core/module_loader"
|
|
19
|
+
require_relative "core/semantic_analyzer"
|
|
20
|
+
require_relative "core/ir"
|
|
21
|
+
require_relative "core/control_flow"
|
|
22
|
+
require_relative "core/pretty_printer"
|
|
23
|
+
require_relative "core/lowering"
|
|
24
|
+
# Codegen wrapper deleted; use CBackend.emit directly
|
|
25
|
+
require_relative "core/c_backend"
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
require "thread"
|
|
5
|
+
require "timeout"
|
|
6
|
+
|
|
7
|
+
module MilkTea
|
|
8
|
+
module DAP
|
|
9
|
+
module Backends
|
|
10
|
+
# Thin bridge to an lldb-dap compatible adapter process.
|
|
11
|
+
class LLDBDAP
|
|
12
|
+
def initialize(adapter_command: ["lldb-dap"], on_event: nil, on_request: nil)
|
|
13
|
+
@adapter_command = adapter_command
|
|
14
|
+
@on_event = on_event
|
|
15
|
+
@on_request = on_request
|
|
16
|
+
@protocol = nil
|
|
17
|
+
@stdin = nil
|
|
18
|
+
@stdout = nil
|
|
19
|
+
@stderr = nil
|
|
20
|
+
@wait_thread = nil
|
|
21
|
+
@reader_thread = nil
|
|
22
|
+
@stderr_thread = nil
|
|
23
|
+
@write_mutex = Mutex.new
|
|
24
|
+
@pending_mutex = Mutex.new
|
|
25
|
+
@pending = {}
|
|
26
|
+
@next_seq = 1
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def start!
|
|
30
|
+
return if running?
|
|
31
|
+
|
|
32
|
+
@stdin, @stdout, @stderr, @wait_thread = Open3.popen3(*@adapter_command)
|
|
33
|
+
@protocol = Protocol.new(input: @stdout, output: @stdin)
|
|
34
|
+
|
|
35
|
+
@reader_thread = Thread.new { read_loop }
|
|
36
|
+
@stderr_thread = Thread.new { drain_stderr }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def running?
|
|
40
|
+
!@wait_thread.nil? && @wait_thread.alive?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def request(command, arguments = {}, timeout: 5)
|
|
44
|
+
start! unless running?
|
|
45
|
+
|
|
46
|
+
seq = next_seq
|
|
47
|
+
queue = Queue.new
|
|
48
|
+
@pending_mutex.synchronize do
|
|
49
|
+
@pending[seq] = queue
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@write_mutex.synchronize do
|
|
53
|
+
@protocol.write_message({
|
|
54
|
+
seq: seq,
|
|
55
|
+
type: "request",
|
|
56
|
+
command: command,
|
|
57
|
+
arguments: arguments
|
|
58
|
+
})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Timeout.timeout(timeout) { queue.pop }
|
|
62
|
+
rescue Timeout::Error
|
|
63
|
+
{
|
|
64
|
+
"type" => "response",
|
|
65
|
+
"request_seq" => seq,
|
|
66
|
+
"success" => false,
|
|
67
|
+
"message" => "backend request timed out: #{command}"
|
|
68
|
+
}
|
|
69
|
+
ensure
|
|
70
|
+
@pending_mutex.synchronize { @pending.delete(seq) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def stop!
|
|
74
|
+
@stdin&.close
|
|
75
|
+
@stdout&.close
|
|
76
|
+
@stderr&.close
|
|
77
|
+
if @wait_thread&.alive?
|
|
78
|
+
Process.kill("TERM", @wait_thread.pid)
|
|
79
|
+
end
|
|
80
|
+
rescue StandardError
|
|
81
|
+
nil
|
|
82
|
+
ensure
|
|
83
|
+
@wait_thread&.join(0.2)
|
|
84
|
+
@reader_thread&.join(0.2)
|
|
85
|
+
@stderr_thread&.join(0.2)
|
|
86
|
+
@stdin = nil
|
|
87
|
+
@stdout = nil
|
|
88
|
+
@stderr = nil
|
|
89
|
+
@wait_thread = nil
|
|
90
|
+
@reader_thread = nil
|
|
91
|
+
@stderr_thread = nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def next_seq
|
|
97
|
+
seq = @next_seq
|
|
98
|
+
@next_seq += 1
|
|
99
|
+
seq
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def read_loop
|
|
103
|
+
loop do
|
|
104
|
+
message = @protocol.read_message
|
|
105
|
+
break if message.nil?
|
|
106
|
+
|
|
107
|
+
if message["type"] == "response"
|
|
108
|
+
queue = @pending_mutex.synchronize { @pending[message["request_seq"]] }
|
|
109
|
+
queue&.push(message)
|
|
110
|
+
elsif message["type"] == "event"
|
|
111
|
+
@on_event&.call(message)
|
|
112
|
+
elsif message["type"] == "request"
|
|
113
|
+
handle_adapter_request(message)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
rescue StandardError
|
|
117
|
+
nil
|
|
118
|
+
ensure
|
|
119
|
+
@pending_mutex.synchronize do
|
|
120
|
+
@pending.each_value do |queue|
|
|
121
|
+
queue.push({
|
|
122
|
+
"type" => "response",
|
|
123
|
+
"success" => false,
|
|
124
|
+
"message" => "backend closed"
|
|
125
|
+
})
|
|
126
|
+
end
|
|
127
|
+
@pending.clear
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def drain_stderr
|
|
132
|
+
return unless @stderr
|
|
133
|
+
|
|
134
|
+
@stderr.each_line do |_line|
|
|
135
|
+
# Intentionally ignored in this bridge layer.
|
|
136
|
+
end
|
|
137
|
+
rescue StandardError
|
|
138
|
+
nil
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def handle_adapter_request(message)
|
|
142
|
+
response = @on_request&.call(message)
|
|
143
|
+
response ||= {
|
|
144
|
+
"type" => "response",
|
|
145
|
+
"request_seq" => message["seq"],
|
|
146
|
+
"success" => false,
|
|
147
|
+
"command" => message["command"],
|
|
148
|
+
"message" => "unsupported reverse request: #{message['command']}"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@write_mutex.synchronize do
|
|
152
|
+
@protocol.write_message(response)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module MilkTea
|
|
6
|
+
module DAP
|
|
7
|
+
# Handles DAP framing over stdin/stdout using Content-Length headers.
|
|
8
|
+
class Protocol
|
|
9
|
+
INVALID_MESSAGE = Object.new.freeze
|
|
10
|
+
|
|
11
|
+
def initialize(input: $stdin, output: $stdout, error_output: nil)
|
|
12
|
+
@input = input
|
|
13
|
+
@output = output
|
|
14
|
+
@error_output = error_output
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def read_message
|
|
18
|
+
headers = {}
|
|
19
|
+
loop do
|
|
20
|
+
line = @input.gets
|
|
21
|
+
return nil if line.nil?
|
|
22
|
+
|
|
23
|
+
stripped = line.chomp
|
|
24
|
+
break if stripped.empty?
|
|
25
|
+
|
|
26
|
+
key, value = stripped.split(":", 2)
|
|
27
|
+
headers[key&.strip] = value&.strip
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
content_length = headers["Content-Length"]&.to_i
|
|
31
|
+
return INVALID_MESSAGE if content_length.nil? || content_length <= 0
|
|
32
|
+
|
|
33
|
+
body = @input.read(content_length)
|
|
34
|
+
JSON.parse(body)
|
|
35
|
+
rescue StandardError => e
|
|
36
|
+
log_error("DAP protocol read error: #{e.message}")
|
|
37
|
+
INVALID_MESSAGE
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def write_message(message)
|
|
41
|
+
json = JSON.dump(message)
|
|
42
|
+
@output.write("Content-Length: #{json.bytesize}\r\n\r\n")
|
|
43
|
+
@output.write(json)
|
|
44
|
+
@output.flush
|
|
45
|
+
rescue StandardError => e
|
|
46
|
+
log_error("DAP protocol write error: #{e.message}")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private def log_error(message)
|
|
50
|
+
return unless @error_output
|
|
51
|
+
|
|
52
|
+
@error_output.puts(message)
|
|
53
|
+
rescue StandardError
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|