mt-lang 0.3.16 → 0.3.20
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/docs/language-design.md +3 -4
- data/docs/language-manual.md +3 -3
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/{binding_types.rb → bindings.rb} +1 -1
- data/lib/milk_tea/core/c_backend/expressions.rb +34 -23
- data/lib/milk_tea/core/c_backend/feature_detection.rb +25 -45
- data/lib/milk_tea/core/c_backend/type_collectors.rb +18 -30
- data/lib/milk_tea/core/c_backend/type_declaration.rb +0 -6
- data/lib/milk_tea/core/c_backend.rb +63 -54
- data/lib/milk_tea/core/compile_time.rb +279 -74
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +1 -1
- data/lib/milk_tea/core/{compatibility_helpers.rb → intrinsics.rb} +9 -2
- data/lib/milk_tea/core/lexer.rb +55 -48
- data/lib/milk_tea/core/lowering/block.rb +9 -0
- data/lib/milk_tea/core/lowering/calls.rb +2 -0
- data/lib/milk_tea/core/lowering/declarations.rb +1 -1
- data/lib/milk_tea/core/lowering/functions.rb +11 -8
- data/lib/milk_tea/core/lowering/resolve.rb +10 -3
- data/lib/milk_tea/core/lowering/scans.rb +13 -18
- data/lib/milk_tea/core/lowering.rb +18 -18
- data/lib/milk_tea/core/module_binder.rb +9 -10
- data/lib/milk_tea/core/module_loader.rb +64 -57
- data/lib/milk_tea/core/module_path_resolver.rb +1 -4
- data/lib/milk_tea/core/parser/declarations.rb +43 -19
- data/lib/milk_tea/core/parser/expressions.rb +4 -7
- data/lib/milk_tea/core/parser/statements.rb +5 -5
- data/lib/milk_tea/core/parser.rb +43 -17
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +24 -31
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +20 -23
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +117 -85
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +19 -41
- data/lib/milk_tea/core/semantic_analyzer.rb +57 -38
- data/lib/milk_tea/core.rb +6 -2
- data/lib/milk_tea/dap/lldb_dap_backend.rb +153 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +1 -1
- data/lib/milk_tea/dap.rb +1 -1
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +6 -0
- data/lib/milk_tea/lsp.rb +1 -7
- data/lib/milk_tea/{bindings/cli.rb → tooling/bindgen_cli.rb} +1 -1
- data/lib/milk_tea/tooling/cli/commands/bindgen.rb +11 -0
- data/lib/milk_tea/tooling/cli/commands/build.rb +37 -0
- data/lib/milk_tea/tooling/cli/commands/cache.rb +46 -0
- data/lib/milk_tea/tooling/cli/commands/check.rb +116 -0
- data/lib/milk_tea/tooling/cli/commands/command_base.rb +8 -0
- data/lib/milk_tea/tooling/cli/commands/completions.rb +48 -0
- data/lib/milk_tea/tooling/cli/commands/dap.rb +58 -0
- data/lib/milk_tea/tooling/cli/commands/debug.rb +77 -0
- data/lib/milk_tea/tooling/cli/commands/deps.rb +17 -0
- data/lib/milk_tea/tooling/cli/commands/docs.rb +58 -0
- data/lib/milk_tea/tooling/cli/commands/emit_c.rb +64 -0
- data/lib/milk_tea/tooling/cli/commands/format.rb +199 -0
- data/lib/milk_tea/tooling/cli/commands/lex.rb +46 -0
- data/lib/milk_tea/tooling/cli/commands/lint.rb +248 -0
- data/lib/milk_tea/tooling/cli/commands/lower.rb +50 -0
- data/lib/milk_tea/tooling/cli/commands/lsp.rb +43 -0
- data/lib/milk_tea/tooling/cli/commands/new.rb +26 -0
- data/lib/milk_tea/tooling/cli/commands/parse.rb +51 -0
- data/lib/milk_tea/tooling/cli/commands/run.rb +99 -0
- data/lib/milk_tea/tooling/cli/commands/snapshot.rb +117 -0
- data/lib/milk_tea/tooling/cli/commands/test.rb +557 -0
- data/lib/milk_tea/tooling/cli/commands/toolchain.rb +16 -0
- data/lib/milk_tea/tooling/cli.rb +101 -1893
- data/lib/milk_tea/tooling.rb +1 -1
- metadata +29 -9
- data/lib/milk_tea/core/compile_time/const_eval.rb +0 -182
- data/lib/milk_tea/core/module_loader/errors.rb +0 -23
- data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -156
- /data/lib/milk_tea/core/lowering/{async.rb → async/frame_builder.rb} +0 -0
data/lib/milk_tea/tooling.rb
CHANGED
|
@@ -18,5 +18,5 @@ require_relative "tooling/linter"
|
|
|
18
18
|
require_relative "tooling/docs_app"
|
|
19
19
|
require_relative "tooling/project_scaffold"
|
|
20
20
|
require_relative "tooling/toolchain_cli"
|
|
21
|
-
require_relative "
|
|
21
|
+
require_relative "tooling/bindgen_cli"
|
|
22
22
|
require_relative "tooling/cli"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mt-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -158,7 +158,6 @@ files:
|
|
|
158
158
|
- lib/milk_tea/bindings/bindgen/emitter.rb
|
|
159
159
|
- lib/milk_tea/bindings/bindgen/overrides.rb
|
|
160
160
|
- lib/milk_tea/bindings/bindgen/type_mapper.rb
|
|
161
|
-
- lib/milk_tea/bindings/cli.rb
|
|
162
161
|
- lib/milk_tea/bindings/imported_bindings.rb
|
|
163
162
|
- lib/milk_tea/bindings/imported_bindings/defaults.rb
|
|
164
163
|
- lib/milk_tea/bindings/imported_bindings/generator.rb
|
|
@@ -185,7 +184,7 @@ files:
|
|
|
185
184
|
- lib/milk_tea/core.rb
|
|
186
185
|
- lib/milk_tea/core/ast.rb
|
|
187
186
|
- lib/milk_tea/core/async_runtime_installer.rb
|
|
188
|
-
- lib/milk_tea/core/
|
|
187
|
+
- lib/milk_tea/core/bindings.rb
|
|
189
188
|
- lib/milk_tea/core/bindings/attribute_binding.rb
|
|
190
189
|
- lib/milk_tea/core/bindings/function_binding.rb
|
|
191
190
|
- lib/milk_tea/core/bindings/module_binding.rb
|
|
@@ -203,9 +202,7 @@ files:
|
|
|
203
202
|
- lib/milk_tea/core/c_backend/type_collectors.rb
|
|
204
203
|
- lib/milk_tea/core/c_backend/type_declaration.rb
|
|
205
204
|
- lib/milk_tea/core/c_backend/type_system.rb
|
|
206
|
-
- lib/milk_tea/core/compatibility_helpers.rb
|
|
207
205
|
- lib/milk_tea/core/compile_time.rb
|
|
208
|
-
- lib/milk_tea/core/compile_time/const_eval.rb
|
|
209
206
|
- lib/milk_tea/core/control_flow.rb
|
|
210
207
|
- lib/milk_tea/core/control_flow/builder.rb
|
|
211
208
|
- lib/milk_tea/core/control_flow/constant_propagation.rb
|
|
@@ -218,6 +215,7 @@ files:
|
|
|
218
215
|
- lib/milk_tea/core/control_flow/termination.rb
|
|
219
216
|
- lib/milk_tea/core/cst.rb
|
|
220
217
|
- lib/milk_tea/core/cst_builder.rb
|
|
218
|
+
- lib/milk_tea/core/intrinsics.rb
|
|
221
219
|
- lib/milk_tea/core/ir.rb
|
|
222
220
|
- lib/milk_tea/core/keywords.rb
|
|
223
221
|
- lib/milk_tea/core/lexer.rb
|
|
@@ -232,8 +230,8 @@ files:
|
|
|
232
230
|
- lib/milk_tea/core/lexer/trivia.rb
|
|
233
231
|
- lib/milk_tea/core/lowering.rb
|
|
234
232
|
- lib/milk_tea/core/lowering/artifacts.rb
|
|
235
|
-
- lib/milk_tea/core/lowering/async.rb
|
|
236
233
|
- lib/milk_tea/core/lowering/async/analysis.rb
|
|
234
|
+
- lib/milk_tea/core/lowering/async/frame_builder.rb
|
|
237
235
|
- lib/milk_tea/core/lowering/async/lowering.rb
|
|
238
236
|
- lib/milk_tea/core/lowering/async/normalization.rb
|
|
239
237
|
- lib/milk_tea/core/lowering/block.rb
|
|
@@ -253,7 +251,6 @@ files:
|
|
|
253
251
|
- lib/milk_tea/core/lowering/utils.rb
|
|
254
252
|
- lib/milk_tea/core/module_binder.rb
|
|
255
253
|
- lib/milk_tea/core/module_loader.rb
|
|
256
|
-
- lib/milk_tea/core/module_loader/errors.rb
|
|
257
254
|
- lib/milk_tea/core/module_path_resolver.rb
|
|
258
255
|
- lib/milk_tea/core/module_roots.rb
|
|
259
256
|
- lib/milk_tea/core/parser.rb
|
|
@@ -294,7 +291,7 @@ files:
|
|
|
294
291
|
- lib/milk_tea/core/types/registry.rb
|
|
295
292
|
- lib/milk_tea/core/types/visitor.rb
|
|
296
293
|
- lib/milk_tea/dap.rb
|
|
297
|
-
- lib/milk_tea/dap/
|
|
294
|
+
- lib/milk_tea/dap/lldb_dap_backend.rb
|
|
298
295
|
- lib/milk_tea/dap/protocol.rb
|
|
299
296
|
- lib/milk_tea/dap/server.rb
|
|
300
297
|
- lib/milk_tea/dap/server/breakpoints.rb
|
|
@@ -361,9 +358,32 @@ files:
|
|
|
361
358
|
- lib/milk_tea/packages/version.rb
|
|
362
359
|
- lib/milk_tea/tooling.rb
|
|
363
360
|
- lib/milk_tea/tooling/asset_pack.rb
|
|
361
|
+
- lib/milk_tea/tooling/bindgen_cli.rb
|
|
364
362
|
- lib/milk_tea/tooling/build.rb
|
|
365
363
|
- lib/milk_tea/tooling/build_cache.rb
|
|
366
364
|
- lib/milk_tea/tooling/cli.rb
|
|
365
|
+
- lib/milk_tea/tooling/cli/commands/bindgen.rb
|
|
366
|
+
- lib/milk_tea/tooling/cli/commands/build.rb
|
|
367
|
+
- lib/milk_tea/tooling/cli/commands/cache.rb
|
|
368
|
+
- lib/milk_tea/tooling/cli/commands/check.rb
|
|
369
|
+
- lib/milk_tea/tooling/cli/commands/command_base.rb
|
|
370
|
+
- lib/milk_tea/tooling/cli/commands/completions.rb
|
|
371
|
+
- lib/milk_tea/tooling/cli/commands/dap.rb
|
|
372
|
+
- lib/milk_tea/tooling/cli/commands/debug.rb
|
|
373
|
+
- lib/milk_tea/tooling/cli/commands/deps.rb
|
|
374
|
+
- lib/milk_tea/tooling/cli/commands/docs.rb
|
|
375
|
+
- lib/milk_tea/tooling/cli/commands/emit_c.rb
|
|
376
|
+
- lib/milk_tea/tooling/cli/commands/format.rb
|
|
377
|
+
- lib/milk_tea/tooling/cli/commands/lex.rb
|
|
378
|
+
- lib/milk_tea/tooling/cli/commands/lint.rb
|
|
379
|
+
- lib/milk_tea/tooling/cli/commands/lower.rb
|
|
380
|
+
- lib/milk_tea/tooling/cli/commands/lsp.rb
|
|
381
|
+
- lib/milk_tea/tooling/cli/commands/new.rb
|
|
382
|
+
- lib/milk_tea/tooling/cli/commands/parse.rb
|
|
383
|
+
- lib/milk_tea/tooling/cli/commands/run.rb
|
|
384
|
+
- lib/milk_tea/tooling/cli/commands/snapshot.rb
|
|
385
|
+
- lib/milk_tea/tooling/cli/commands/test.rb
|
|
386
|
+
- lib/milk_tea/tooling/cli/commands/toolchain.rb
|
|
367
387
|
- lib/milk_tea/tooling/cst_formatter.rb
|
|
368
388
|
- lib/milk_tea/tooling/debug_info_formatter.rb
|
|
369
389
|
- lib/milk_tea/tooling/debug_map.rb
|
|
@@ -605,7 +625,7 @@ metadata:
|
|
|
605
625
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
606
626
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
607
627
|
post_install_message: |
|
|
608
|
-
Milk Tea 0.3.
|
|
628
|
+
Milk Tea 0.3.20 installed!
|
|
609
629
|
|
|
610
630
|
System requirements:
|
|
611
631
|
- A C compiler (gcc or clang) must be available on PATH
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../types/layout"
|
|
4
|
-
|
|
5
|
-
module MilkTea
|
|
6
|
-
module ConstEval
|
|
7
|
-
|
|
8
|
-
def self.evaluate(expression, resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
|
|
9
|
-
Evaluator.new(
|
|
10
|
-
resolve_identifier:,
|
|
11
|
-
resolve_member_access:,
|
|
12
|
-
resolve_type_ref:,
|
|
13
|
-
resolve_call:,
|
|
14
|
-
).evaluate(expression)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.equality_result(left, right)
|
|
18
|
-
return left == right if left.is_a?(Numeric) && right.is_a?(Numeric)
|
|
19
|
-
return left == right if left.is_a?(String) && right.is_a?(String)
|
|
20
|
-
return left == right if boolean_value?(left) && boolean_value?(right)
|
|
21
|
-
return left == right if left.is_a?(Types::Base) && right.is_a?(Types::Base)
|
|
22
|
-
|
|
23
|
-
nil
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.boolean_value?(value)
|
|
27
|
-
value == true || value == false
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
class Evaluator
|
|
31
|
-
def initialize(resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
|
|
32
|
-
@resolve_identifier = resolve_identifier
|
|
33
|
-
@resolve_member_access = resolve_member_access
|
|
34
|
-
@resolve_type_ref = resolve_type_ref
|
|
35
|
-
@resolve_call = resolve_call
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def evaluate(expression)
|
|
39
|
-
case expression
|
|
40
|
-
when AST::ErrorExpr
|
|
41
|
-
nil
|
|
42
|
-
when AST::ExpressionList
|
|
43
|
-
expression.elements.filter_map { |element| evaluate(element) }
|
|
44
|
-
when AST::IntegerLiteral, AST::FloatLiteral, AST::BooleanLiteral
|
|
45
|
-
expression.value
|
|
46
|
-
when AST::StringLiteral
|
|
47
|
-
expression.value
|
|
48
|
-
when AST::Identifier
|
|
49
|
-
@resolve_identifier&.call(expression)
|
|
50
|
-
when AST::MemberAccess
|
|
51
|
-
@resolve_member_access&.call(expression)
|
|
52
|
-
when AST::Call
|
|
53
|
-
@resolve_call&.call(expression)
|
|
54
|
-
when AST::Specialization
|
|
55
|
-
@resolve_call&.call(expression)
|
|
56
|
-
when AST::SizeofExpr
|
|
57
|
-
type = resolve_layout_type(expression.type)
|
|
58
|
-
type && Layout.size_of(type)
|
|
59
|
-
when AST::AlignofExpr
|
|
60
|
-
type = resolve_layout_type(expression.type)
|
|
61
|
-
type && Layout.alignment_of(type)
|
|
62
|
-
when AST::OffsetofExpr
|
|
63
|
-
type = resolve_layout_type(expression.type)
|
|
64
|
-
if type
|
|
65
|
-
result = Layout.offset_of(type, expression.field)
|
|
66
|
-
return result if result
|
|
67
|
-
|
|
68
|
-
id_expr = AST::Identifier.new(name: expression.field)
|
|
69
|
-
value = @resolve_identifier&.call(id_expr)
|
|
70
|
-
if value.is_a?(Types::FieldHandle)
|
|
71
|
-
return Layout.offset_of(type, value.field_name)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
nil
|
|
75
|
-
when AST::UnaryOp
|
|
76
|
-
evaluate_unary(expression)
|
|
77
|
-
when AST::BinaryOp
|
|
78
|
-
evaluate_binary(expression)
|
|
79
|
-
when AST::IfExpr
|
|
80
|
-
condition = evaluate(expression.condition)
|
|
81
|
-
return unless ConstEval.boolean_value?(condition)
|
|
82
|
-
|
|
83
|
-
evaluate(condition ? expression.then_expression : expression.else_expression)
|
|
84
|
-
else
|
|
85
|
-
nil
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def resolve_layout_type(type_ref)
|
|
90
|
-
return unless @resolve_type_ref
|
|
91
|
-
|
|
92
|
-
@resolve_type_ref.call(type_ref)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def evaluate_unary(expression)
|
|
96
|
-
operand = evaluate(expression.operand)
|
|
97
|
-
|
|
98
|
-
case expression.operator
|
|
99
|
-
when "+"
|
|
100
|
-
operand.is_a?(Numeric) ? operand : nil
|
|
101
|
-
when "-"
|
|
102
|
-
operand.is_a?(Numeric) ? -operand : nil
|
|
103
|
-
when "~"
|
|
104
|
-
operand.is_a?(Integer) ? ~operand : nil
|
|
105
|
-
when "not"
|
|
106
|
-
ConstEval.boolean_value?(operand) ? !operand : nil
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def evaluate_binary(expression)
|
|
111
|
-
left = evaluate(expression.left)
|
|
112
|
-
|
|
113
|
-
case expression.operator
|
|
114
|
-
when "and"
|
|
115
|
-
return unless ConstEval.boolean_value?(left)
|
|
116
|
-
return false if left == false
|
|
117
|
-
|
|
118
|
-
right = evaluate(expression.right)
|
|
119
|
-
return right if ConstEval.boolean_value?(right)
|
|
120
|
-
|
|
121
|
-
return nil
|
|
122
|
-
when "or"
|
|
123
|
-
return unless ConstEval.boolean_value?(left)
|
|
124
|
-
return true if left == true
|
|
125
|
-
|
|
126
|
-
right = evaluate(expression.right)
|
|
127
|
-
return right if ConstEval.boolean_value?(right)
|
|
128
|
-
|
|
129
|
-
return nil
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
right = evaluate(expression.right)
|
|
133
|
-
|
|
134
|
-
case expression.operator
|
|
135
|
-
when "=="
|
|
136
|
-
ConstEval.equality_result(left, right)
|
|
137
|
-
when "!="
|
|
138
|
-
result = ConstEval.equality_result(left, right)
|
|
139
|
-
result.nil? ? nil : !result
|
|
140
|
-
when "+"
|
|
141
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left + right : nil
|
|
142
|
-
when "-"
|
|
143
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left - right : nil
|
|
144
|
-
when "*"
|
|
145
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left * right : nil
|
|
146
|
-
when "/"
|
|
147
|
-
return unless left.is_a?(Numeric) && right.is_a?(Numeric)
|
|
148
|
-
raise CompileTime::Error, "division by zero" if zero_numeric?(right)
|
|
149
|
-
|
|
150
|
-
left / right
|
|
151
|
-
when "%"
|
|
152
|
-
return unless left.is_a?(Integer) && right.is_a?(Integer)
|
|
153
|
-
raise CompileTime::Error, "modulo by zero" if right.zero?
|
|
154
|
-
|
|
155
|
-
left % right
|
|
156
|
-
when "<<"
|
|
157
|
-
left.is_a?(Integer) && right.is_a?(Integer) ? left << right : nil
|
|
158
|
-
when ">>"
|
|
159
|
-
left.is_a?(Integer) && right.is_a?(Integer) ? left >> right : nil
|
|
160
|
-
when "&"
|
|
161
|
-
left.is_a?(Integer) && right.is_a?(Integer) ? left & right : nil
|
|
162
|
-
when "|"
|
|
163
|
-
left.is_a?(Integer) && right.is_a?(Integer) ? left | right : nil
|
|
164
|
-
when "^"
|
|
165
|
-
left.is_a?(Integer) && right.is_a?(Integer) ? left ^ right : nil
|
|
166
|
-
when "<"
|
|
167
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left < right : nil
|
|
168
|
-
when "<="
|
|
169
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left <= right : nil
|
|
170
|
-
when ">"
|
|
171
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left > right : nil
|
|
172
|
-
when ">="
|
|
173
|
-
left.is_a?(Numeric) && right.is_a?(Numeric) ? left >= right : nil
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def zero_numeric?(value)
|
|
178
|
-
(value.is_a?(Integer) && value.zero?) || (value.is_a?(Float) && value.zero?)
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module MilkTea
|
|
4
|
-
class ModuleLoadError < StandardError
|
|
5
|
-
attr_reader :path, :line, :column
|
|
6
|
-
|
|
7
|
-
def initialize(message, path:, line: nil, column: nil)
|
|
8
|
-
@path = path
|
|
9
|
-
@line = line
|
|
10
|
-
@column = column
|
|
11
|
-
super("#{message}: #{path}")
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def code
|
|
15
|
-
"module/error"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class ModuleLoader
|
|
20
|
-
ImportResolution = Data.define(:modules, :errors)
|
|
21
|
-
ImportResolutionError = Data.define(:import, :error)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,156 +0,0 @@
|
|
|
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
|
-
def next_seq
|
|
95
|
-
seq = @next_seq
|
|
96
|
-
@next_seq += 1
|
|
97
|
-
seq
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def read_loop
|
|
101
|
-
loop do
|
|
102
|
-
message = @protocol.read_message
|
|
103
|
-
break if message.nil?
|
|
104
|
-
|
|
105
|
-
if message["type"] == "response"
|
|
106
|
-
queue = @pending_mutex.synchronize { @pending[message["request_seq"]] }
|
|
107
|
-
queue&.push(message)
|
|
108
|
-
elsif message["type"] == "event"
|
|
109
|
-
@on_event&.call(message)
|
|
110
|
-
elsif message["type"] == "request"
|
|
111
|
-
handle_adapter_request(message)
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
rescue StandardError
|
|
115
|
-
nil
|
|
116
|
-
ensure
|
|
117
|
-
@pending_mutex.synchronize do
|
|
118
|
-
@pending.each_value do |queue|
|
|
119
|
-
queue.push({
|
|
120
|
-
"type" => "response",
|
|
121
|
-
"success" => false,
|
|
122
|
-
"message" => "backend closed"
|
|
123
|
-
})
|
|
124
|
-
end
|
|
125
|
-
@pending.clear
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def drain_stderr
|
|
130
|
-
return unless @stderr
|
|
131
|
-
|
|
132
|
-
@stderr.each_line do |_line|
|
|
133
|
-
# Intentionally ignored in this bridge layer.
|
|
134
|
-
end
|
|
135
|
-
rescue StandardError
|
|
136
|
-
nil
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def handle_adapter_request(message)
|
|
140
|
-
response = @on_request&.call(message)
|
|
141
|
-
response ||= {
|
|
142
|
-
"type" => "response",
|
|
143
|
-
"request_seq" => message["seq"],
|
|
144
|
-
"success" => false,
|
|
145
|
-
"command" => message["command"],
|
|
146
|
-
"message" => "unsupported reverse request: #{message['command']}"
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@write_mutex.synchronize do
|
|
150
|
-
@protocol.write_message(response)
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
File without changes
|