konpeito 0.1.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/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,2465 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Konpeito
|
|
4
|
+
module HIR
|
|
5
|
+
# Source location information for debug info
|
|
6
|
+
class SourceLocation
|
|
7
|
+
attr_reader :line, :column, :file
|
|
8
|
+
|
|
9
|
+
def initialize(line: nil, column: nil, file: nil)
|
|
10
|
+
@line = line
|
|
11
|
+
@column = column
|
|
12
|
+
@file = file
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.from_prism(prism_location, file: nil)
|
|
16
|
+
return nil unless prism_location
|
|
17
|
+
|
|
18
|
+
new(
|
|
19
|
+
line: prism_location.start_line,
|
|
20
|
+
column: prism_location.start_column,
|
|
21
|
+
file: file
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Base class for all HIR nodes
|
|
27
|
+
class Node
|
|
28
|
+
attr_reader :type # TypeChecker::Types::Type
|
|
29
|
+
attr_accessor :location # SourceLocation for debug info
|
|
30
|
+
|
|
31
|
+
def initialize(type: TypeChecker::Types::UNTYPED, location: nil)
|
|
32
|
+
@type = type
|
|
33
|
+
@location = location
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Program is the top-level container
|
|
38
|
+
class Program < Node
|
|
39
|
+
attr_reader :functions, :classes, :modules
|
|
40
|
+
|
|
41
|
+
def initialize(functions: [], classes: [], modules: [])
|
|
42
|
+
super(type: TypeChecker::Types::NIL)
|
|
43
|
+
@functions = functions
|
|
44
|
+
@classes = classes
|
|
45
|
+
@modules = modules
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Class definition
|
|
50
|
+
class ClassDef < Node
|
|
51
|
+
attr_reader :name, :superclass, :instance_vars
|
|
52
|
+
attr_accessor :method_names # Names of methods defined in this class
|
|
53
|
+
attr_accessor :included_modules # Module names included by this class
|
|
54
|
+
attr_accessor :extended_modules # Module names extended by this class
|
|
55
|
+
attr_accessor :prepended_modules # Module names prepended by this class
|
|
56
|
+
attr_accessor :private_methods # Set of private method names
|
|
57
|
+
attr_accessor :protected_methods # Set of protected method names
|
|
58
|
+
attr_accessor :aliases # Array of [new_name, old_name] pairs
|
|
59
|
+
attr_accessor :reopened # true if this is reopening an existing class
|
|
60
|
+
attr_accessor :singleton_methods # Names of class-level methods (def self.xxx or class << self)
|
|
61
|
+
attr_accessor :instance_var_types # HM-inferred ivar types: { "name" => :Integer, "age" => :String, ... }
|
|
62
|
+
|
|
63
|
+
def initialize(name:, superclass: nil, method_names: [], instance_vars: [], included_modules: [], extended_modules: [], prepended_modules: [])
|
|
64
|
+
super(type: TypeChecker::Types::NIL)
|
|
65
|
+
@name = name
|
|
66
|
+
@superclass = superclass
|
|
67
|
+
@method_names = method_names
|
|
68
|
+
@instance_vars = instance_vars
|
|
69
|
+
@included_modules = included_modules
|
|
70
|
+
@extended_modules = extended_modules
|
|
71
|
+
@prepended_modules = prepended_modules
|
|
72
|
+
@private_methods = Set.new
|
|
73
|
+
@protected_methods = Set.new
|
|
74
|
+
@aliases = []
|
|
75
|
+
@reopened = false
|
|
76
|
+
@singleton_methods = []
|
|
77
|
+
@instance_var_types = {}
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Module definition
|
|
82
|
+
class ModuleDef < Node
|
|
83
|
+
attr_reader :name, :methods, :singleton_methods, :constants
|
|
84
|
+
|
|
85
|
+
def initialize(name:, methods: [], singleton_methods: [], constants: {})
|
|
86
|
+
super(type: TypeChecker::Types::NIL)
|
|
87
|
+
@name = name
|
|
88
|
+
@methods = methods
|
|
89
|
+
@singleton_methods = singleton_methods
|
|
90
|
+
@constants = constants # Hash of name -> value
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Function/method definition
|
|
95
|
+
class Function < Node
|
|
96
|
+
attr_reader :name, :params, :body, :return_type
|
|
97
|
+
attr_accessor :is_instance_method
|
|
98
|
+
attr_accessor :owner_class # Class name this method belongs to (nil for top-level)
|
|
99
|
+
attr_accessor :owner_module # Module name this method belongs to (nil for top-level or class methods)
|
|
100
|
+
|
|
101
|
+
def initialize(name:, params: [], body: [], return_type: TypeChecker::Types::UNTYPED, is_instance_method: true, owner_class: nil, owner_module: nil, location: nil)
|
|
102
|
+
super(type: TypeChecker::Types::SYMBOL, location: location)
|
|
103
|
+
@name = name
|
|
104
|
+
@params = params
|
|
105
|
+
@body = body # Array of BasicBlock
|
|
106
|
+
@return_type = return_type
|
|
107
|
+
@is_instance_method = is_instance_method
|
|
108
|
+
@owner_class = owner_class
|
|
109
|
+
@owner_module = owner_module
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def entry_block
|
|
113
|
+
body.first
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def class_method?
|
|
117
|
+
!is_instance_method && owner_class
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Function parameter
|
|
122
|
+
class Param < Node
|
|
123
|
+
attr_reader :name, :default_value, :rest, :keyword, :keyword_rest, :block
|
|
124
|
+
|
|
125
|
+
def initialize(name:, type: TypeChecker::Types::UNTYPED, default_value: nil, rest: false, keyword: false, keyword_rest: false, block: false)
|
|
126
|
+
super(type: type)
|
|
127
|
+
@name = name
|
|
128
|
+
@default_value = default_value
|
|
129
|
+
@rest = rest
|
|
130
|
+
@keyword = keyword
|
|
131
|
+
@keyword_rest = keyword_rest # **kwargs
|
|
132
|
+
@block = block
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Basic block (sequence of instructions ending in a terminator)
|
|
137
|
+
class BasicBlock
|
|
138
|
+
attr_reader :label, :instructions, :terminator
|
|
139
|
+
|
|
140
|
+
def initialize(label:)
|
|
141
|
+
@label = label
|
|
142
|
+
@instructions = []
|
|
143
|
+
@terminator = nil
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def add_instruction(inst)
|
|
147
|
+
@instructions << inst
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def set_terminator(term)
|
|
151
|
+
@terminator = term
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Base class for instructions
|
|
156
|
+
class Instruction < Node
|
|
157
|
+
attr_reader :result_var # Variable to store result (nil if void)
|
|
158
|
+
|
|
159
|
+
def initialize(type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
160
|
+
super(type: type)
|
|
161
|
+
@result_var = result_var
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Terminators (end a basic block)
|
|
166
|
+
class Terminator < Node; end
|
|
167
|
+
|
|
168
|
+
class Return < Terminator
|
|
169
|
+
attr_reader :value
|
|
170
|
+
|
|
171
|
+
def initialize(value: nil)
|
|
172
|
+
super(type: TypeChecker::Types::BOTTOM)
|
|
173
|
+
@value = value
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
class Branch < Terminator
|
|
178
|
+
attr_reader :condition, :then_block, :else_block
|
|
179
|
+
|
|
180
|
+
def initialize(condition:, then_block:, else_block:)
|
|
181
|
+
super(type: TypeChecker::Types::BOTTOM)
|
|
182
|
+
@condition = condition
|
|
183
|
+
@then_block = then_block
|
|
184
|
+
@else_block = else_block
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
class Jump < Terminator
|
|
189
|
+
attr_reader :target
|
|
190
|
+
|
|
191
|
+
def initialize(target:)
|
|
192
|
+
super(type: TypeChecker::Types::BOTTOM)
|
|
193
|
+
@target = target
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Include statement for including modules into classes
|
|
198
|
+
class IncludeStatement < Instruction
|
|
199
|
+
attr_reader :module_name
|
|
200
|
+
|
|
201
|
+
def initialize(module_name:)
|
|
202
|
+
super(type: TypeChecker::Types::NIL)
|
|
203
|
+
@module_name = module_name
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Variable operations
|
|
208
|
+
class LocalVar < Node
|
|
209
|
+
attr_reader :name
|
|
210
|
+
|
|
211
|
+
def initialize(name:, type: TypeChecker::Types::UNTYPED)
|
|
212
|
+
super(type: type)
|
|
213
|
+
@name = name
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
class LoadLocal < Instruction
|
|
218
|
+
attr_reader :var
|
|
219
|
+
|
|
220
|
+
def initialize(var:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
221
|
+
super(type: type, result_var: result_var)
|
|
222
|
+
@var = var
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
class StoreLocal < Instruction
|
|
227
|
+
attr_reader :var, :value
|
|
228
|
+
|
|
229
|
+
def initialize(var:, value:, type: TypeChecker::Types::UNTYPED)
|
|
230
|
+
super(type: type)
|
|
231
|
+
@var = var
|
|
232
|
+
@value = value
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
class LoadInstanceVar < Instruction
|
|
237
|
+
attr_reader :name
|
|
238
|
+
|
|
239
|
+
def initialize(name:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
240
|
+
super(type: type, result_var: result_var)
|
|
241
|
+
@name = name
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
class StoreInstanceVar < Instruction
|
|
246
|
+
attr_reader :name, :value
|
|
247
|
+
|
|
248
|
+
def initialize(name:, value:, type: TypeChecker::Types::UNTYPED)
|
|
249
|
+
super(type: type)
|
|
250
|
+
@name = name
|
|
251
|
+
@value = value
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Class variable operations (@@var)
|
|
256
|
+
class LoadClassVar < Instruction
|
|
257
|
+
attr_reader :name
|
|
258
|
+
|
|
259
|
+
def initialize(name:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
260
|
+
super(type: type, result_var: result_var)
|
|
261
|
+
@name = name # e.g., "@@counter"
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
class StoreClassVar < Instruction
|
|
266
|
+
attr_reader :name, :value
|
|
267
|
+
|
|
268
|
+
def initialize(name:, value:, type: TypeChecker::Types::UNTYPED)
|
|
269
|
+
super(type: type)
|
|
270
|
+
@name = name # e.g., "@@counter"
|
|
271
|
+
@value = value
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Constant assignment: CONSTANT = value
|
|
276
|
+
class StoreConstant < Instruction
|
|
277
|
+
attr_reader :name, :value, :scope
|
|
278
|
+
|
|
279
|
+
def initialize(name:, value:, scope: nil, type: TypeChecker::Types::UNTYPED)
|
|
280
|
+
super(type: type)
|
|
281
|
+
@name = name # e.g., "VERSION"
|
|
282
|
+
@value = value # The value HIR node
|
|
283
|
+
@scope = scope # nil for top-level, module/class name otherwise
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Literals
|
|
288
|
+
class Literal < Instruction
|
|
289
|
+
attr_reader :value
|
|
290
|
+
|
|
291
|
+
def initialize(value:, type:, result_var: nil)
|
|
292
|
+
super(type: type, result_var: result_var)
|
|
293
|
+
@value = value
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
class IntegerLit < Literal
|
|
298
|
+
def initialize(value:, result_var: nil)
|
|
299
|
+
super(value: value, type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
class FloatLit < Literal
|
|
304
|
+
def initialize(value:, result_var: nil)
|
|
305
|
+
super(value: value, type: TypeChecker::Types::FLOAT, result_var: result_var)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
class StringLit < Literal
|
|
310
|
+
def initialize(value:, result_var: nil)
|
|
311
|
+
super(value: value, type: TypeChecker::Types::STRING, result_var: result_var)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# String concatenation chain optimization: a + b + c + d
|
|
316
|
+
# Instead of creating intermediate strings with rb_str_plus,
|
|
317
|
+
# we use rb_str_dup + rb_str_concat for efficiency
|
|
318
|
+
class StringConcat < Instruction
|
|
319
|
+
attr_reader :parts, :result_var
|
|
320
|
+
|
|
321
|
+
def initialize(parts:, result_var: nil)
|
|
322
|
+
@parts = parts # Array of HIR instructions representing string parts
|
|
323
|
+
@result_var = result_var
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def type
|
|
327
|
+
TypeChecker::Types::STRING
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
class SymbolLit < Literal
|
|
332
|
+
def initialize(value:, result_var: nil)
|
|
333
|
+
super(value: value, type: TypeChecker::Types::SYMBOL, result_var: result_var)
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
class RegexpLit < Instruction
|
|
338
|
+
attr_reader :pattern, :options, :result_var
|
|
339
|
+
|
|
340
|
+
def initialize(pattern:, options: 0, result_var: nil)
|
|
341
|
+
@pattern = pattern
|
|
342
|
+
@options = options # Integer: Regexp::IGNORECASE | Regexp::EXTENDED | Regexp::MULTILINE
|
|
343
|
+
@result_var = result_var
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def type
|
|
347
|
+
TypeChecker::Types::REGEXP
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
class NilLit < Literal
|
|
352
|
+
def initialize(result_var: nil)
|
|
353
|
+
super(value: nil, type: TypeChecker::Types::NIL, result_var: result_var)
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
class BoolLit < Literal
|
|
358
|
+
def initialize(value:, result_var: nil)
|
|
359
|
+
type = value ? TypeChecker::Types::TRUE_CLASS : TypeChecker::Types::FALSE_CLASS
|
|
360
|
+
super(value: value, type: type, result_var: result_var)
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# Array literal
|
|
365
|
+
class ArrayLit < Instruction
|
|
366
|
+
attr_reader :elements
|
|
367
|
+
|
|
368
|
+
def initialize(elements:, element_type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
369
|
+
super(type: TypeChecker::Types.array(element_type), result_var: result_var)
|
|
370
|
+
@elements = elements
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Hash literal
|
|
375
|
+
class HashLit < Instruction
|
|
376
|
+
attr_reader :pairs # Array of [key, value] pairs
|
|
377
|
+
|
|
378
|
+
def initialize(pairs:, key_type: TypeChecker::Types::UNTYPED, value_type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
379
|
+
super(type: TypeChecker::Types.hash_type(key_type, value_type), result_var: result_var)
|
|
380
|
+
@pairs = pairs
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Method call
|
|
385
|
+
class Call < Instruction
|
|
386
|
+
attr_reader :receiver, :method_name, :args, :block, :keyword_args, :safe_navigation
|
|
387
|
+
|
|
388
|
+
def initialize(receiver:, method_name:, args: [], block: nil, keyword_args: {}, type: TypeChecker::Types::UNTYPED, result_var: nil, safe_navigation: false)
|
|
389
|
+
super(type: type, result_var: result_var)
|
|
390
|
+
@receiver = receiver
|
|
391
|
+
@method_name = method_name
|
|
392
|
+
@args = args
|
|
393
|
+
@block = block
|
|
394
|
+
@keyword_args = keyword_args # Hash of { keyword_name => HIR instruction }
|
|
395
|
+
@safe_navigation = safe_navigation
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def has_keyword_args?
|
|
399
|
+
!@keyword_args.empty?
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Self reference
|
|
404
|
+
class SelfRef < Instruction
|
|
405
|
+
def initialize(type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
406
|
+
super(type: type, result_var: result_var)
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Range literal
|
|
411
|
+
class RangeLit < Instruction
|
|
412
|
+
attr_reader :left, :right, :exclusive
|
|
413
|
+
|
|
414
|
+
def initialize(left:, right:, exclusive:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
415
|
+
super(type: type, result_var: result_var)
|
|
416
|
+
@left = left
|
|
417
|
+
@right = right
|
|
418
|
+
@exclusive = exclusive
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Global variable read
|
|
423
|
+
class LoadGlobalVar < Instruction
|
|
424
|
+
attr_reader :name
|
|
425
|
+
|
|
426
|
+
def initialize(name:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
427
|
+
super(type: type, result_var: result_var)
|
|
428
|
+
@name = name
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Global variable write
|
|
433
|
+
class StoreGlobalVar < Instruction
|
|
434
|
+
attr_reader :name, :value
|
|
435
|
+
|
|
436
|
+
def initialize(name:, value:, type: TypeChecker::Types::UNTYPED)
|
|
437
|
+
super(type: type)
|
|
438
|
+
@name = name
|
|
439
|
+
@value = value
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Splat argument at call site
|
|
444
|
+
class SplatArg < Instruction
|
|
445
|
+
attr_reader :expression
|
|
446
|
+
|
|
447
|
+
def initialize(expression:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
448
|
+
super(type: type, result_var: result_var)
|
|
449
|
+
@expression = expression
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# defined? operator
|
|
454
|
+
class DefinedCheck < Instruction
|
|
455
|
+
attr_reader :check_type, :name
|
|
456
|
+
|
|
457
|
+
def initialize(check_type:, name:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
458
|
+
super(type: type, result_var: result_var)
|
|
459
|
+
@check_type = check_type # :local_variable, :constant, :method, :expression
|
|
460
|
+
@name = name
|
|
461
|
+
end
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
# Super method call
|
|
465
|
+
class SuperCall < Instruction
|
|
466
|
+
attr_reader :args, :forward_args
|
|
467
|
+
|
|
468
|
+
def initialize(args: [], forward_args: false, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
469
|
+
super(type: type, result_var: result_var)
|
|
470
|
+
@args = args
|
|
471
|
+
@forward_args = forward_args
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
# Multi-write array element extraction
|
|
476
|
+
class MultiWriteExtract < Instruction
|
|
477
|
+
attr_reader :array, :index
|
|
478
|
+
|
|
479
|
+
def initialize(array:, index:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
480
|
+
super(type: type, result_var: result_var)
|
|
481
|
+
@array = array
|
|
482
|
+
@index = index
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# Constant lookup
|
|
487
|
+
class ConstantLookup < Instruction
|
|
488
|
+
attr_reader :name, :scope
|
|
489
|
+
|
|
490
|
+
def initialize(name:, scope: nil, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
491
|
+
super(type: type, result_var: result_var)
|
|
492
|
+
@name = name
|
|
493
|
+
@scope = scope
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
# Captured variable from outer scope (for closures)
|
|
498
|
+
class Capture
|
|
499
|
+
attr_reader :name, :type
|
|
500
|
+
|
|
501
|
+
def initialize(name:, type:)
|
|
502
|
+
@name = name
|
|
503
|
+
@type = type
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Block/Lambda definition
|
|
508
|
+
class BlockDef < Node
|
|
509
|
+
attr_reader :params, :body, :captures, :is_lambda
|
|
510
|
+
|
|
511
|
+
def initialize(params: [], body: [], captures: [], is_lambda: false)
|
|
512
|
+
super(type: TypeChecker::Types::ClassInstance.new(:Proc))
|
|
513
|
+
@params = params
|
|
514
|
+
@body = body # Array of BasicBlock
|
|
515
|
+
@captures = captures # Array of Capture objects
|
|
516
|
+
@is_lambda = is_lambda
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
# Create a Proc/Lambda object from a block definition
|
|
521
|
+
class ProcNew < Instruction
|
|
522
|
+
attr_reader :block_def
|
|
523
|
+
|
|
524
|
+
def initialize(block_def:, result_var: nil)
|
|
525
|
+
super(type: TypeChecker::Types::ClassInstance.new(:Proc), result_var: result_var)
|
|
526
|
+
@block_def = block_def
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
# Call a Proc/Lambda object
|
|
531
|
+
class ProcCall < Instruction
|
|
532
|
+
attr_reader :proc_value, :args
|
|
533
|
+
|
|
534
|
+
def initialize(proc_value:, args: [], type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
535
|
+
super(type: type, result_var: result_var)
|
|
536
|
+
@proc_value = proc_value # HIR instruction that evaluates to the Proc
|
|
537
|
+
@args = args # Array of HIR instructions for arguments
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# ========================================
|
|
542
|
+
# Fiber operations
|
|
543
|
+
# Cooperative concurrency primitives
|
|
544
|
+
# ========================================
|
|
545
|
+
|
|
546
|
+
# Create a new Fiber from a block definition
|
|
547
|
+
# Fiber.new { |arg| ... }
|
|
548
|
+
class FiberNew < Instruction
|
|
549
|
+
attr_reader :block_def
|
|
550
|
+
|
|
551
|
+
def initialize(block_def:, result_var: nil)
|
|
552
|
+
super(type: TypeChecker::Types::FIBER, result_var: result_var)
|
|
553
|
+
@block_def = block_def # BlockDef with fiber body
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
# Resume a fiber with optional arguments
|
|
558
|
+
# fiber.resume(arg1, arg2)
|
|
559
|
+
class FiberResume < Instruction
|
|
560
|
+
attr_reader :fiber, :args
|
|
561
|
+
|
|
562
|
+
def initialize(fiber:, args: [], type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
563
|
+
super(type: type, result_var: result_var)
|
|
564
|
+
@fiber = fiber # HIR instruction evaluating to Fiber
|
|
565
|
+
@args = args # Array of HIR instructions for arguments
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# Yield from within a fiber
|
|
570
|
+
# Fiber.yield(value)
|
|
571
|
+
class FiberYield < Instruction
|
|
572
|
+
attr_reader :args
|
|
573
|
+
|
|
574
|
+
def initialize(args: [], type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
575
|
+
super(type: type, result_var: result_var)
|
|
576
|
+
@args = args # Array of HIR instructions for yield values
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# Check if fiber is alive
|
|
581
|
+
# fiber.alive?
|
|
582
|
+
class FiberAlive < Instruction
|
|
583
|
+
attr_reader :fiber
|
|
584
|
+
|
|
585
|
+
def initialize(fiber:, result_var: nil)
|
|
586
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
587
|
+
@fiber = fiber # HIR instruction evaluating to Fiber
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# Get current fiber
|
|
592
|
+
# Fiber.current
|
|
593
|
+
class FiberCurrent < Instruction
|
|
594
|
+
def initialize(result_var: nil)
|
|
595
|
+
super(type: TypeChecker::Types::FIBER, result_var: result_var)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
# ========================================
|
|
600
|
+
# Thread operations
|
|
601
|
+
# OS-level threading with GVL
|
|
602
|
+
# ========================================
|
|
603
|
+
|
|
604
|
+
# Create a new Thread from a block definition
|
|
605
|
+
# Thread.new { ... }
|
|
606
|
+
class ThreadNew < Instruction
|
|
607
|
+
attr_reader :block_def
|
|
608
|
+
|
|
609
|
+
def initialize(block_def:, result_var: nil)
|
|
610
|
+
super(type: TypeChecker::Types::THREAD, result_var: result_var)
|
|
611
|
+
@block_def = block_def # BlockDef with thread body
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
# Wait for thread completion
|
|
616
|
+
# thread.join or thread.join(timeout)
|
|
617
|
+
class ThreadJoin < Instruction
|
|
618
|
+
attr_reader :thread, :timeout
|
|
619
|
+
|
|
620
|
+
def initialize(thread:, timeout: nil, type: TypeChecker::Types::THREAD, result_var: nil)
|
|
621
|
+
super(type: type, result_var: result_var)
|
|
622
|
+
@thread = thread # HIR instruction evaluating to Thread
|
|
623
|
+
@timeout = timeout # Optional timeout value
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
# Get thread return value
|
|
628
|
+
# thread.value
|
|
629
|
+
class ThreadValue < Instruction
|
|
630
|
+
attr_reader :thread
|
|
631
|
+
|
|
632
|
+
def initialize(thread:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
633
|
+
super(type: type, result_var: result_var)
|
|
634
|
+
@thread = thread # HIR instruction evaluating to Thread
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
# Get current thread
|
|
639
|
+
# Thread.current
|
|
640
|
+
class ThreadCurrent < Instruction
|
|
641
|
+
def initialize(result_var: nil)
|
|
642
|
+
super(type: TypeChecker::Types::THREAD, result_var: result_var)
|
|
643
|
+
end
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
# ========================================
|
|
647
|
+
# Mutex operations
|
|
648
|
+
# Thread synchronization primitives
|
|
649
|
+
# ========================================
|
|
650
|
+
|
|
651
|
+
# Create a new Mutex
|
|
652
|
+
# Mutex.new
|
|
653
|
+
class MutexNew < Instruction
|
|
654
|
+
def initialize(result_var: nil)
|
|
655
|
+
super(type: TypeChecker::Types::MUTEX, result_var: result_var)
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
# Lock a mutex
|
|
660
|
+
# mutex.lock
|
|
661
|
+
class MutexLock < Instruction
|
|
662
|
+
attr_reader :mutex
|
|
663
|
+
|
|
664
|
+
def initialize(mutex:, result_var: nil)
|
|
665
|
+
super(type: TypeChecker::Types::MUTEX, result_var: result_var)
|
|
666
|
+
@mutex = mutex # HIR instruction evaluating to Mutex
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
# Unlock a mutex
|
|
671
|
+
# mutex.unlock
|
|
672
|
+
class MutexUnlock < Instruction
|
|
673
|
+
attr_reader :mutex
|
|
674
|
+
|
|
675
|
+
def initialize(mutex:, result_var: nil)
|
|
676
|
+
super(type: TypeChecker::Types::MUTEX, result_var: result_var)
|
|
677
|
+
@mutex = mutex # HIR instruction evaluating to Mutex
|
|
678
|
+
end
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
# Execute block with mutex locked
|
|
682
|
+
# mutex.synchronize { ... }
|
|
683
|
+
class MutexSynchronize < Instruction
|
|
684
|
+
attr_reader :mutex, :block_def
|
|
685
|
+
|
|
686
|
+
def initialize(mutex:, block_def:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
687
|
+
super(type: type, result_var: result_var)
|
|
688
|
+
@mutex = mutex # HIR instruction evaluating to Mutex
|
|
689
|
+
@block_def = block_def # BlockDef with synchronized body
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# ========================================
|
|
694
|
+
# Queue operations
|
|
695
|
+
# Thread-safe queue for producer/consumer
|
|
696
|
+
# ========================================
|
|
697
|
+
|
|
698
|
+
# Create a new Queue
|
|
699
|
+
# Queue.new
|
|
700
|
+
class QueueNew < Instruction
|
|
701
|
+
def initialize(result_var: nil)
|
|
702
|
+
super(type: TypeChecker::Types::QUEUE, result_var: result_var)
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
# Push value to queue
|
|
707
|
+
# queue.push(value) or queue << value
|
|
708
|
+
class QueuePush < Instruction
|
|
709
|
+
attr_reader :queue, :value
|
|
710
|
+
|
|
711
|
+
def initialize(queue:, value:, result_var: nil)
|
|
712
|
+
super(type: TypeChecker::Types::QUEUE, result_var: result_var)
|
|
713
|
+
@queue = queue # HIR instruction evaluating to Queue
|
|
714
|
+
@value = value # Value to push
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
# Pop value from queue (blocking)
|
|
719
|
+
# queue.pop or queue.pop(non_block)
|
|
720
|
+
class QueuePop < Instruction
|
|
721
|
+
attr_reader :queue, :non_block
|
|
722
|
+
|
|
723
|
+
def initialize(queue:, non_block: nil, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
724
|
+
super(type: type, result_var: result_var)
|
|
725
|
+
@queue = queue # HIR instruction evaluating to Queue
|
|
726
|
+
@non_block = non_block # Optional non-blocking flag
|
|
727
|
+
end
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
# ========================================
|
|
731
|
+
# ConditionVariable operations
|
|
732
|
+
# ========================================
|
|
733
|
+
|
|
734
|
+
# Create a new ConditionVariable
|
|
735
|
+
# ConditionVariable.new
|
|
736
|
+
class ConditionVariableNew < Instruction
|
|
737
|
+
def initialize(result_var: nil)
|
|
738
|
+
super(type: TypeChecker::Types::CONDITION_VARIABLE, result_var: result_var)
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
# Wait on condition variable (releases mutex, waits, reacquires)
|
|
743
|
+
# cv.wait(mutex) or cv.wait(mutex, timeout)
|
|
744
|
+
class ConditionVariableWait < Instruction
|
|
745
|
+
attr_reader :cv, :mutex, :timeout
|
|
746
|
+
|
|
747
|
+
def initialize(cv:, mutex:, timeout: nil, result_var: nil)
|
|
748
|
+
super(type: TypeChecker::Types::CONDITION_VARIABLE, result_var: result_var)
|
|
749
|
+
@cv = cv # HIR instruction evaluating to ConditionVariable
|
|
750
|
+
@mutex = mutex # HIR instruction evaluating to Mutex
|
|
751
|
+
@timeout = timeout # Optional timeout value
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# Signal one waiting thread
|
|
756
|
+
# cv.signal
|
|
757
|
+
class ConditionVariableSignal < Instruction
|
|
758
|
+
attr_reader :cv
|
|
759
|
+
|
|
760
|
+
def initialize(cv:, result_var: nil)
|
|
761
|
+
super(type: TypeChecker::Types::CONDITION_VARIABLE, result_var: result_var)
|
|
762
|
+
@cv = cv # HIR instruction evaluating to ConditionVariable
|
|
763
|
+
end
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
# Broadcast to all waiting threads
|
|
767
|
+
# cv.broadcast
|
|
768
|
+
class ConditionVariableBroadcast < Instruction
|
|
769
|
+
attr_reader :cv
|
|
770
|
+
|
|
771
|
+
def initialize(cv:, result_var: nil)
|
|
772
|
+
super(type: TypeChecker::Types::CONDITION_VARIABLE, result_var: result_var)
|
|
773
|
+
@cv = cv # HIR instruction evaluating to ConditionVariable
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
# ========================================
|
|
778
|
+
# SizedQueue operations
|
|
779
|
+
# ========================================
|
|
780
|
+
|
|
781
|
+
# Create a new SizedQueue with max size
|
|
782
|
+
# SizedQueue.new(max)
|
|
783
|
+
class SizedQueueNew < Instruction
|
|
784
|
+
attr_reader :max_size
|
|
785
|
+
|
|
786
|
+
def initialize(max_size:, result_var: nil)
|
|
787
|
+
super(type: TypeChecker::Types::SIZED_QUEUE, result_var: result_var)
|
|
788
|
+
@max_size = max_size # HIR instruction evaluating to max size
|
|
789
|
+
end
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
# Push to sized queue (blocks if full)
|
|
793
|
+
# sq.push(value) or sq << value
|
|
794
|
+
class SizedQueuePush < Instruction
|
|
795
|
+
attr_reader :queue, :value
|
|
796
|
+
|
|
797
|
+
def initialize(queue:, value:, result_var: nil)
|
|
798
|
+
super(type: TypeChecker::Types::SIZED_QUEUE, result_var: result_var)
|
|
799
|
+
@queue = queue # HIR instruction evaluating to SizedQueue
|
|
800
|
+
@value = value # Value to push
|
|
801
|
+
end
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
# Pop from sized queue (blocks if empty)
|
|
805
|
+
# sq.pop or sq.pop(non_block)
|
|
806
|
+
class SizedQueuePop < Instruction
|
|
807
|
+
attr_reader :queue, :non_block
|
|
808
|
+
|
|
809
|
+
def initialize(queue:, non_block: nil, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
810
|
+
super(type: type, result_var: result_var)
|
|
811
|
+
@queue = queue # HIR instruction evaluating to SizedQueue
|
|
812
|
+
@non_block = non_block # Optional non-blocking flag
|
|
813
|
+
end
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
# ========================================
|
|
817
|
+
# Ractor operations
|
|
818
|
+
# Ruby 4.0 Ractor with Port-based communication
|
|
819
|
+
# ========================================
|
|
820
|
+
|
|
821
|
+
# Create a new Ractor
|
|
822
|
+
# Ractor.new { block } or Ractor.new(name: "worker") { block }
|
|
823
|
+
class RactorNew < Instruction
|
|
824
|
+
attr_reader :block_def, :args, :name
|
|
825
|
+
|
|
826
|
+
def initialize(block_def:, args: [], name: nil, result_var: nil)
|
|
827
|
+
super(type: TypeChecker::Types::RACTOR, result_var: result_var)
|
|
828
|
+
@block_def = block_def
|
|
829
|
+
@args = args
|
|
830
|
+
@name = name # Optional name string (HIR instruction or nil)
|
|
831
|
+
end
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
# Send message to Ractor
|
|
835
|
+
# ractor.send(msg) or ractor << msg
|
|
836
|
+
class RactorSend < Instruction
|
|
837
|
+
attr_reader :ractor, :value
|
|
838
|
+
|
|
839
|
+
def initialize(ractor:, value:, result_var: nil)
|
|
840
|
+
super(type: TypeChecker::Types::RACTOR, result_var: result_var)
|
|
841
|
+
@ractor = ractor
|
|
842
|
+
@value = value
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
# Receive message on current Ractor
|
|
847
|
+
# Ractor.receive
|
|
848
|
+
class RactorReceive < Instruction
|
|
849
|
+
def initialize(type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
850
|
+
super(type: type, result_var: result_var)
|
|
851
|
+
end
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
# Wait for Ractor completion
|
|
855
|
+
# ractor.join
|
|
856
|
+
class RactorJoin < Instruction
|
|
857
|
+
attr_reader :ractor
|
|
858
|
+
|
|
859
|
+
def initialize(ractor:, result_var: nil)
|
|
860
|
+
super(type: TypeChecker::Types::RACTOR, result_var: result_var)
|
|
861
|
+
@ractor = ractor
|
|
862
|
+
end
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
# Get Ractor return value
|
|
866
|
+
# ractor.value
|
|
867
|
+
class RactorValue < Instruction
|
|
868
|
+
attr_reader :ractor
|
|
869
|
+
|
|
870
|
+
def initialize(ractor:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
871
|
+
super(type: type, result_var: result_var)
|
|
872
|
+
@ractor = ractor
|
|
873
|
+
end
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
# Close Ractor
|
|
877
|
+
# ractor.close
|
|
878
|
+
class RactorClose < Instruction
|
|
879
|
+
attr_reader :ractor
|
|
880
|
+
|
|
881
|
+
def initialize(ractor:, result_var: nil)
|
|
882
|
+
super(type: TypeChecker::Types::NIL, result_var: result_var)
|
|
883
|
+
@ractor = ractor
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
# Get current Ractor
|
|
888
|
+
# Ractor.current
|
|
889
|
+
class RactorCurrent < Instruction
|
|
890
|
+
def initialize(result_var: nil)
|
|
891
|
+
super(type: TypeChecker::Types::RACTOR, result_var: result_var)
|
|
892
|
+
end
|
|
893
|
+
end
|
|
894
|
+
|
|
895
|
+
# Get main Ractor
|
|
896
|
+
# Ractor.main
|
|
897
|
+
class RactorMain < Instruction
|
|
898
|
+
def initialize(result_var: nil)
|
|
899
|
+
super(type: TypeChecker::Types::RACTOR, result_var: result_var)
|
|
900
|
+
end
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
# Get Ractor name
|
|
904
|
+
# ractor.name
|
|
905
|
+
class RactorName < Instruction
|
|
906
|
+
attr_reader :ractor
|
|
907
|
+
|
|
908
|
+
def initialize(ractor:, result_var: nil)
|
|
909
|
+
super(type: TypeChecker::Types::STRING, result_var: result_var)
|
|
910
|
+
@ractor = ractor
|
|
911
|
+
end
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
# Ractor-local storage get
|
|
915
|
+
# Ractor[:key]
|
|
916
|
+
class RactorLocalGet < Instruction
|
|
917
|
+
attr_reader :key
|
|
918
|
+
|
|
919
|
+
def initialize(key:, result_var: nil)
|
|
920
|
+
super(type: TypeChecker::Types::UNTYPED, result_var: result_var)
|
|
921
|
+
@key = key # HIR instruction for key (SymbolLit or StringLit)
|
|
922
|
+
end
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
# Ractor-local storage set
|
|
926
|
+
# Ractor[:key] = value
|
|
927
|
+
class RactorLocalSet < Instruction
|
|
928
|
+
attr_reader :key, :value
|
|
929
|
+
|
|
930
|
+
def initialize(key:, value:, result_var: nil)
|
|
931
|
+
super(type: TypeChecker::Types::UNTYPED, result_var: result_var)
|
|
932
|
+
@key = key # HIR instruction for key
|
|
933
|
+
@value = value # HIR instruction for value
|
|
934
|
+
end
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
# Ractor.make_shareable(obj)
|
|
938
|
+
class RactorMakeSharable < Instruction
|
|
939
|
+
attr_reader :value
|
|
940
|
+
|
|
941
|
+
def initialize(value:, result_var: nil)
|
|
942
|
+
super(type: TypeChecker::Types::UNTYPED, result_var: result_var)
|
|
943
|
+
@value = value
|
|
944
|
+
end
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
# Ractor.shareable?(obj)
|
|
948
|
+
class RactorSharable < Instruction
|
|
949
|
+
attr_reader :value
|
|
950
|
+
|
|
951
|
+
def initialize(value:, result_var: nil)
|
|
952
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
953
|
+
@value = value
|
|
954
|
+
end
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
# ractor.monitor(port)
|
|
958
|
+
class RactorMonitor < Instruction
|
|
959
|
+
attr_reader :ractor, :port
|
|
960
|
+
|
|
961
|
+
def initialize(ractor:, port:, result_var: nil)
|
|
962
|
+
super(type: TypeChecker::Types::NIL, result_var: result_var)
|
|
963
|
+
@ractor = ractor
|
|
964
|
+
@port = port
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
# ractor.unmonitor(port)
|
|
969
|
+
class RactorUnmonitor < Instruction
|
|
970
|
+
attr_reader :ractor, :port
|
|
971
|
+
|
|
972
|
+
def initialize(ractor:, port:, result_var: nil)
|
|
973
|
+
super(type: TypeChecker::Types::NIL, result_var: result_var)
|
|
974
|
+
@ractor = ractor
|
|
975
|
+
@port = port
|
|
976
|
+
end
|
|
977
|
+
end
|
|
978
|
+
|
|
979
|
+
# ========================================
|
|
980
|
+
# Ractor::Port operations
|
|
981
|
+
# ========================================
|
|
982
|
+
|
|
983
|
+
# Create a new Ractor::Port
|
|
984
|
+
# Ractor::Port.new
|
|
985
|
+
class RactorPortNew < Instruction
|
|
986
|
+
def initialize(result_var: nil)
|
|
987
|
+
super(type: TypeChecker::Types::RACTOR_PORT, result_var: result_var)
|
|
988
|
+
end
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
# Send message to port
|
|
992
|
+
# port.send(msg) or port << msg
|
|
993
|
+
class RactorPortSend < Instruction
|
|
994
|
+
attr_reader :port, :value
|
|
995
|
+
|
|
996
|
+
def initialize(port:, value:, result_var: nil)
|
|
997
|
+
super(type: TypeChecker::Types::RACTOR_PORT, result_var: result_var)
|
|
998
|
+
@port = port
|
|
999
|
+
@value = value
|
|
1000
|
+
end
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
# Receive message from port
|
|
1004
|
+
# port.receive
|
|
1005
|
+
class RactorPortReceive < Instruction
|
|
1006
|
+
attr_reader :port
|
|
1007
|
+
|
|
1008
|
+
def initialize(port:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1009
|
+
super(type: type, result_var: result_var)
|
|
1010
|
+
@port = port
|
|
1011
|
+
end
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
# Close port
|
|
1015
|
+
# port.close
|
|
1016
|
+
class RactorPortClose < Instruction
|
|
1017
|
+
attr_reader :port
|
|
1018
|
+
|
|
1019
|
+
def initialize(port:, result_var: nil)
|
|
1020
|
+
super(type: TypeChecker::Types::NIL, result_var: result_var)
|
|
1021
|
+
@port = port
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
# ========================================
|
|
1026
|
+
# Ractor.select
|
|
1027
|
+
# ========================================
|
|
1028
|
+
|
|
1029
|
+
# Select from multiple ports/ractors
|
|
1030
|
+
# Ractor.select(*ports_or_ractors)
|
|
1031
|
+
class RactorSelect < Instruction
|
|
1032
|
+
attr_reader :sources
|
|
1033
|
+
|
|
1034
|
+
def initialize(sources:, result_var: nil)
|
|
1035
|
+
super(type: TypeChecker::Types::UNTYPED, result_var: result_var)
|
|
1036
|
+
@sources = sources
|
|
1037
|
+
end
|
|
1038
|
+
end
|
|
1039
|
+
|
|
1040
|
+
# Yield to block
|
|
1041
|
+
class Yield < Instruction
|
|
1042
|
+
attr_reader :args
|
|
1043
|
+
|
|
1044
|
+
def initialize(args: [], type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1045
|
+
super(type: type, result_var: result_var)
|
|
1046
|
+
@args = args
|
|
1047
|
+
end
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1050
|
+
# Exception handling
|
|
1051
|
+
class RaiseException < Terminator
|
|
1052
|
+
attr_reader :exception
|
|
1053
|
+
|
|
1054
|
+
def initialize(exception:)
|
|
1055
|
+
super(type: TypeChecker::Types::BOTTOM)
|
|
1056
|
+
@exception = exception
|
|
1057
|
+
end
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
# Rescue clause: represents a single rescue handler
|
|
1061
|
+
# rescue TypeError, ArgumentError => e
|
|
1062
|
+
# handle_error
|
|
1063
|
+
# end
|
|
1064
|
+
class RescueClause < Node
|
|
1065
|
+
attr_reader :exception_classes # Array of exception class names (e.g., ["TypeError", "ArgumentError"])
|
|
1066
|
+
attr_reader :exception_var # Local variable name for caught exception (e.g., "e"), nil if not specified
|
|
1067
|
+
attr_reader :body_blocks # Array of BasicBlock for handler body
|
|
1068
|
+
|
|
1069
|
+
def initialize(exception_classes: [], exception_var: nil, body_blocks: [])
|
|
1070
|
+
super(type: TypeChecker::Types::UNTYPED)
|
|
1071
|
+
@exception_classes = exception_classes.empty? ? ["StandardError"] : exception_classes
|
|
1072
|
+
@exception_var = exception_var
|
|
1073
|
+
@body_blocks = body_blocks
|
|
1074
|
+
end
|
|
1075
|
+
end
|
|
1076
|
+
|
|
1077
|
+
class BeginRescue < Instruction
|
|
1078
|
+
attr_reader :try_blocks, :rescue_clauses, :else_blocks, :ensure_blocks
|
|
1079
|
+
attr_accessor :non_try_instruction_ids
|
|
1080
|
+
|
|
1081
|
+
def initialize(try_blocks:, rescue_clauses: [], else_blocks: [], ensure_blocks: [], type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1082
|
+
super(type: type, result_var: result_var)
|
|
1083
|
+
@try_blocks = try_blocks
|
|
1084
|
+
@rescue_clauses = rescue_clauses # Array of RescueClause
|
|
1085
|
+
@else_blocks = else_blocks # Array of BasicBlock (runs if no exception)
|
|
1086
|
+
@ensure_blocks = ensure_blocks # Array of BasicBlock (always runs)
|
|
1087
|
+
@non_try_instruction_ids = nil # Set of object_ids for all rescue/else/ensure instructions
|
|
1088
|
+
end
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
# Case/when statement
|
|
1092
|
+
# case x
|
|
1093
|
+
# when 1 then "one"
|
|
1094
|
+
# when 2, 3 then "small"
|
|
1095
|
+
# else "other"
|
|
1096
|
+
# end
|
|
1097
|
+
class CaseStatement < Instruction
|
|
1098
|
+
attr_reader :predicate # HIR instruction for the value being matched (nil for case without predicate)
|
|
1099
|
+
attr_reader :when_clauses # Array of WhenClause
|
|
1100
|
+
attr_reader :else_body # Array of HIR instructions for else branch (nil if no else)
|
|
1101
|
+
attr_accessor :sub_instruction_ids # Set of object_ids for when/else instructions (including sub-exprs)
|
|
1102
|
+
|
|
1103
|
+
def initialize(predicate:, when_clauses: [], else_body: nil, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1104
|
+
super(type: type, result_var: result_var)
|
|
1105
|
+
@predicate = predicate
|
|
1106
|
+
@when_clauses = when_clauses
|
|
1107
|
+
@else_body = else_body
|
|
1108
|
+
@sub_instruction_ids = nil
|
|
1109
|
+
end
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
# Single when clause in a case statement
|
|
1113
|
+
# when 1, 2, 3 then body
|
|
1114
|
+
class WhenClause < Node
|
|
1115
|
+
attr_reader :conditions # Array of HIR instructions (match values/ranges/classes)
|
|
1116
|
+
attr_reader :body # Array of HIR instructions for the clause body
|
|
1117
|
+
|
|
1118
|
+
def initialize(conditions: [], body: [])
|
|
1119
|
+
super(type: TypeChecker::Types::UNTYPED)
|
|
1120
|
+
@conditions = conditions
|
|
1121
|
+
@body = body
|
|
1122
|
+
end
|
|
1123
|
+
end
|
|
1124
|
+
|
|
1125
|
+
# ========================================
|
|
1126
|
+
# Pattern Matching (case/in)
|
|
1127
|
+
# Ruby 3.0+ pattern matching support
|
|
1128
|
+
# ========================================
|
|
1129
|
+
|
|
1130
|
+
# Case/in pattern matching statement
|
|
1131
|
+
# case x
|
|
1132
|
+
# in 1 then "one"
|
|
1133
|
+
# in Integer => n then n.to_s
|
|
1134
|
+
# in [a, b] then a + b
|
|
1135
|
+
# else "other"
|
|
1136
|
+
# end
|
|
1137
|
+
class CaseMatchStatement < Instruction
|
|
1138
|
+
attr_reader :predicate # HIR instruction for the value being matched
|
|
1139
|
+
attr_reader :in_clauses # Array of InClause
|
|
1140
|
+
attr_reader :else_body # Array of HIR instructions for else branch (nil raises NoMatchingPatternError)
|
|
1141
|
+
|
|
1142
|
+
def initialize(predicate:, in_clauses: [], else_body: nil, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1143
|
+
super(type: type, result_var: result_var)
|
|
1144
|
+
@predicate = predicate
|
|
1145
|
+
@in_clauses = in_clauses
|
|
1146
|
+
@else_body = else_body
|
|
1147
|
+
end
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
# Single in clause in a case/in statement
|
|
1151
|
+
# in Pattern [if guard] then body
|
|
1152
|
+
class InClause < Node
|
|
1153
|
+
attr_reader :pattern # Pattern node
|
|
1154
|
+
attr_reader :guard # Optional guard expression (HIR instruction)
|
|
1155
|
+
attr_reader :body # Array of HIR instructions for the clause body
|
|
1156
|
+
attr_reader :bindings # Hash of { variable_name => type } for pattern variables
|
|
1157
|
+
|
|
1158
|
+
def initialize(pattern:, guard: nil, body: [], bindings: {})
|
|
1159
|
+
super(type: TypeChecker::Types::UNTYPED)
|
|
1160
|
+
@pattern = pattern
|
|
1161
|
+
@guard = guard
|
|
1162
|
+
@body = body
|
|
1163
|
+
@bindings = bindings
|
|
1164
|
+
end
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
# Base class for pattern nodes
|
|
1168
|
+
class Pattern < Node
|
|
1169
|
+
attr_reader :bindings # Hash of { variable_name => type } - variables bound by this pattern
|
|
1170
|
+
|
|
1171
|
+
def initialize(bindings: {})
|
|
1172
|
+
super(type: TypeChecker::Types::UNTYPED)
|
|
1173
|
+
@bindings = bindings
|
|
1174
|
+
end
|
|
1175
|
+
end
|
|
1176
|
+
|
|
1177
|
+
# Literal pattern: matches a specific value using ===
|
|
1178
|
+
# in 42 / in "hello" / in :symbol / in nil / in true / in false
|
|
1179
|
+
class LiteralPattern < Pattern
|
|
1180
|
+
attr_reader :value # HIR Literal node (IntegerLit, StringLit, etc.)
|
|
1181
|
+
|
|
1182
|
+
def initialize(value:, bindings: {})
|
|
1183
|
+
super(bindings: bindings)
|
|
1184
|
+
@value = value
|
|
1185
|
+
end
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
# Variable pattern: binds matched value to a variable
|
|
1189
|
+
# in x
|
|
1190
|
+
class VariablePattern < Pattern
|
|
1191
|
+
attr_reader :name # Variable name (String)
|
|
1192
|
+
attr_reader :var_type # Inferred type for the variable
|
|
1193
|
+
|
|
1194
|
+
def initialize(name:, var_type: TypeChecker::Types::UNTYPED, bindings: nil)
|
|
1195
|
+
bindings ||= { name => var_type }
|
|
1196
|
+
super(bindings: bindings)
|
|
1197
|
+
@name = name
|
|
1198
|
+
@var_type = var_type
|
|
1199
|
+
end
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
# Constant/Type pattern: matches class or constant using ===
|
|
1203
|
+
# in Integer / in String / in MyClass
|
|
1204
|
+
class ConstantPattern < Pattern
|
|
1205
|
+
attr_reader :constant_name # Constant name (String)
|
|
1206
|
+
attr_accessor :narrowed_type # Type to narrow to in the matched branch
|
|
1207
|
+
|
|
1208
|
+
def initialize(constant_name:, narrowed_type: nil, bindings: {})
|
|
1209
|
+
super(bindings: bindings)
|
|
1210
|
+
@constant_name = constant_name
|
|
1211
|
+
@narrowed_type = narrowed_type
|
|
1212
|
+
end
|
|
1213
|
+
end
|
|
1214
|
+
|
|
1215
|
+
# Alternation pattern: matches any of several patterns
|
|
1216
|
+
# in 1 | 2 | 3 / in Integer | String
|
|
1217
|
+
class AlternationPattern < Pattern
|
|
1218
|
+
attr_reader :alternatives # Array of Pattern nodes
|
|
1219
|
+
|
|
1220
|
+
def initialize(alternatives:, bindings: {})
|
|
1221
|
+
super(bindings: bindings)
|
|
1222
|
+
@alternatives = alternatives
|
|
1223
|
+
end
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
# Array pattern: matches Array-like objects via deconstruct
|
|
1227
|
+
# in [a, b] / in [a, *rest] / in [*pre, x, *post]
|
|
1228
|
+
# in Point[x, y]
|
|
1229
|
+
class ArrayPattern < Pattern
|
|
1230
|
+
attr_reader :constant # Optional constant for type check (String, e.g., "Point")
|
|
1231
|
+
attr_reader :requireds # Required element patterns before rest (Array of Pattern)
|
|
1232
|
+
attr_reader :rest # Rest pattern (*args), RestPattern or nil
|
|
1233
|
+
attr_reader :posts # Post-rest required patterns (Array of Pattern)
|
|
1234
|
+
|
|
1235
|
+
def initialize(constant: nil, requireds: [], rest: nil, posts: [], bindings: {})
|
|
1236
|
+
super(bindings: bindings)
|
|
1237
|
+
@constant = constant
|
|
1238
|
+
@requireds = requireds
|
|
1239
|
+
@rest = rest
|
|
1240
|
+
@posts = posts
|
|
1241
|
+
end
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
# Hash pattern: matches Hash-like objects via deconstruct_keys
|
|
1245
|
+
# in {x:, y:} / in {name: String => n}
|
|
1246
|
+
class HashPattern < Pattern
|
|
1247
|
+
attr_reader :constant # Optional constant for type check (String)
|
|
1248
|
+
attr_reader :elements # Array of HashPatternElement
|
|
1249
|
+
attr_reader :rest # Rest pattern (**rest), RestPattern or nil
|
|
1250
|
+
|
|
1251
|
+
def initialize(constant: nil, elements: [], rest: nil, bindings: {})
|
|
1252
|
+
super(bindings: bindings)
|
|
1253
|
+
@constant = constant
|
|
1254
|
+
@elements = elements
|
|
1255
|
+
@rest = rest
|
|
1256
|
+
end
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1259
|
+
# Single element in a hash pattern
|
|
1260
|
+
# x: or x: Pattern
|
|
1261
|
+
class HashPatternElement < Node
|
|
1262
|
+
attr_reader :key # Symbol key (String)
|
|
1263
|
+
attr_reader :value_pattern # Pattern for value (nil for shorthand `x:`)
|
|
1264
|
+
|
|
1265
|
+
def initialize(key:, value_pattern: nil)
|
|
1266
|
+
super(type: TypeChecker::Types::UNTYPED)
|
|
1267
|
+
@key = key
|
|
1268
|
+
@value_pattern = value_pattern
|
|
1269
|
+
end
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
# Rest pattern: captures remaining elements
|
|
1273
|
+
# *rest or **rest or * or **
|
|
1274
|
+
class RestPattern < Pattern
|
|
1275
|
+
attr_reader :name # Variable name (String), nil for anonymous * or **
|
|
1276
|
+
|
|
1277
|
+
def initialize(name: nil, bindings: nil)
|
|
1278
|
+
bindings ||= name ? { name => TypeChecker::Types::ClassInstance.new(:Array) } : {}
|
|
1279
|
+
super(bindings: bindings)
|
|
1280
|
+
@name = name
|
|
1281
|
+
end
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
# Capture pattern: matches a pattern and binds to variable
|
|
1285
|
+
# in Integer => n / in [a, b] => arr
|
|
1286
|
+
class CapturePattern < Pattern
|
|
1287
|
+
attr_reader :value_pattern # Pattern to match
|
|
1288
|
+
attr_reader :target # Variable name to bind (String)
|
|
1289
|
+
|
|
1290
|
+
def initialize(value_pattern:, target:, bindings: nil)
|
|
1291
|
+
# Merge bindings from value_pattern with the capture target
|
|
1292
|
+
pattern_bindings = value_pattern.bindings.dup
|
|
1293
|
+
pattern_bindings[target] = TypeChecker::Types::UNTYPED
|
|
1294
|
+
bindings ||= pattern_bindings
|
|
1295
|
+
super(bindings: bindings)
|
|
1296
|
+
@value_pattern = value_pattern
|
|
1297
|
+
@target = target
|
|
1298
|
+
end
|
|
1299
|
+
end
|
|
1300
|
+
|
|
1301
|
+
# Pinned variable pattern: matches against existing variable value
|
|
1302
|
+
# in ^x
|
|
1303
|
+
class PinnedPattern < Pattern
|
|
1304
|
+
attr_reader :variable_name # Variable name to match against (String)
|
|
1305
|
+
attr_reader :variable # HIR LoadLocal instruction (populated during codegen)
|
|
1306
|
+
|
|
1307
|
+
def initialize(variable_name:, variable: nil)
|
|
1308
|
+
super(bindings: {})
|
|
1309
|
+
@variable_name = variable_name
|
|
1310
|
+
@variable = variable
|
|
1311
|
+
end
|
|
1312
|
+
end
|
|
1313
|
+
|
|
1314
|
+
# Match predicate expression: expr in pattern (returns true/false)
|
|
1315
|
+
# value in [a, b]
|
|
1316
|
+
class MatchPredicate < Instruction
|
|
1317
|
+
attr_reader :value # Expression to match (HIR instruction)
|
|
1318
|
+
attr_reader :pattern # Pattern to match against
|
|
1319
|
+
|
|
1320
|
+
def initialize(value:, pattern:, result_var: nil)
|
|
1321
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
1322
|
+
@value = value
|
|
1323
|
+
@pattern = pattern
|
|
1324
|
+
end
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
# Match required expression: expr => pattern (raises NoMatchingPatternError on failure)
|
|
1328
|
+
# value => [a, b]
|
|
1329
|
+
class MatchRequired < Instruction
|
|
1330
|
+
attr_reader :value # Expression to match (HIR instruction)
|
|
1331
|
+
attr_reader :pattern # Pattern to match against
|
|
1332
|
+
|
|
1333
|
+
def initialize(value:, pattern:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1334
|
+
super(type: type, result_var: result_var)
|
|
1335
|
+
@value = value
|
|
1336
|
+
@pattern = pattern
|
|
1337
|
+
end
|
|
1338
|
+
end
|
|
1339
|
+
|
|
1340
|
+
# Phi node (for SSA form)
|
|
1341
|
+
class Phi < Instruction
|
|
1342
|
+
attr_reader :incoming # Hash of { block_label => value }
|
|
1343
|
+
|
|
1344
|
+
def initialize(incoming:, type: TypeChecker::Types::UNTYPED, result_var: nil)
|
|
1345
|
+
super(type: type, result_var: result_var)
|
|
1346
|
+
@incoming = incoming
|
|
1347
|
+
end
|
|
1348
|
+
end
|
|
1349
|
+
|
|
1350
|
+
# ========================================
|
|
1351
|
+
# NativeArray operations
|
|
1352
|
+
# Contiguous memory arrays with unboxed numeric elements
|
|
1353
|
+
# ========================================
|
|
1354
|
+
|
|
1355
|
+
# Allocate a NativeArray
|
|
1356
|
+
# NativeArray[Float64] → double* with capacity
|
|
1357
|
+
class NativeArrayAlloc < Instruction
|
|
1358
|
+
attr_reader :size, :element_type
|
|
1359
|
+
|
|
1360
|
+
def initialize(size:, element_type:, result_var: nil)
|
|
1361
|
+
array_type = TypeChecker::Types::NativeArrayType.new(element_type)
|
|
1362
|
+
super(type: array_type, result_var: result_var)
|
|
1363
|
+
@size = size # HIR value (IntegerLit or LoadLocal)
|
|
1364
|
+
@element_type = element_type # :Int64 or :Float64
|
|
1365
|
+
end
|
|
1366
|
+
end
|
|
1367
|
+
|
|
1368
|
+
# Get element from NativeArray (unboxed)
|
|
1369
|
+
# arr[i] → double or i64
|
|
1370
|
+
class NativeArrayGet < Instruction
|
|
1371
|
+
attr_reader :array, :index, :element_type
|
|
1372
|
+
|
|
1373
|
+
def initialize(array:, index:, element_type:, result_var: nil)
|
|
1374
|
+
elem_internal_type = case element_type
|
|
1375
|
+
when :Int64 then TypeChecker::Types::INTEGER
|
|
1376
|
+
when :Float64 then TypeChecker::Types::FLOAT
|
|
1377
|
+
else TypeChecker::Types::UNTYPED
|
|
1378
|
+
end
|
|
1379
|
+
super(type: elem_internal_type, result_var: result_var)
|
|
1380
|
+
@array = array # HIR value (the NativeArray)
|
|
1381
|
+
@index = index # HIR value (index)
|
|
1382
|
+
@element_type = element_type # :Int64 or :Float64
|
|
1383
|
+
end
|
|
1384
|
+
end
|
|
1385
|
+
|
|
1386
|
+
# Set element in NativeArray
|
|
1387
|
+
# arr[i] = value
|
|
1388
|
+
class NativeArraySet < Instruction
|
|
1389
|
+
attr_reader :array, :index, :value, :element_type
|
|
1390
|
+
|
|
1391
|
+
def initialize(array:, index:, value:, element_type:)
|
|
1392
|
+
super(type: TypeChecker::Types::NIL)
|
|
1393
|
+
@array = array
|
|
1394
|
+
@index = index
|
|
1395
|
+
@value = value
|
|
1396
|
+
@element_type = element_type
|
|
1397
|
+
end
|
|
1398
|
+
end
|
|
1399
|
+
|
|
1400
|
+
# Get length of NativeArray (stored with array metadata)
|
|
1401
|
+
class NativeArrayLength < Instruction
|
|
1402
|
+
attr_reader :array
|
|
1403
|
+
|
|
1404
|
+
def initialize(array:, result_var: nil)
|
|
1405
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1406
|
+
@array = array
|
|
1407
|
+
end
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1410
|
+
# ========================================
|
|
1411
|
+
# StaticArray operations
|
|
1412
|
+
# Fixed-size stack-allocated array with compile-time known size
|
|
1413
|
+
# ========================================
|
|
1414
|
+
|
|
1415
|
+
# Allocate a StaticArray on stack
|
|
1416
|
+
# StaticArray[Float, 4].new() → stack-allocated [4 x double]
|
|
1417
|
+
class StaticArrayAlloc < Instruction
|
|
1418
|
+
attr_reader :element_type, :size, :initial_value
|
|
1419
|
+
|
|
1420
|
+
def initialize(element_type:, size:, initial_value: nil, result_var: nil)
|
|
1421
|
+
array_type = TypeChecker::Types::StaticArrayType.new(element_type, size)
|
|
1422
|
+
super(type: array_type, result_var: result_var)
|
|
1423
|
+
@element_type = element_type # :Int64 or :Float64
|
|
1424
|
+
@size = size # Compile-time constant integer
|
|
1425
|
+
@initial_value = initial_value # Optional fill value (HIR value)
|
|
1426
|
+
end
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
# Get element from StaticArray (unboxed)
|
|
1430
|
+
# arr[i] → double or i64
|
|
1431
|
+
class StaticArrayGet < Instruction
|
|
1432
|
+
attr_reader :array, :index, :element_type, :size
|
|
1433
|
+
|
|
1434
|
+
def initialize(array:, index:, element_type:, size:, result_var: nil)
|
|
1435
|
+
elem_internal_type = case element_type
|
|
1436
|
+
when :Int64 then TypeChecker::Types::INTEGER
|
|
1437
|
+
when :Float64 then TypeChecker::Types::FLOAT
|
|
1438
|
+
else TypeChecker::Types::UNTYPED
|
|
1439
|
+
end
|
|
1440
|
+
super(type: elem_internal_type, result_var: result_var)
|
|
1441
|
+
@array = array # HIR value (the StaticArray pointer)
|
|
1442
|
+
@index = index # HIR value (index)
|
|
1443
|
+
@element_type = element_type # :Int64 or :Float64
|
|
1444
|
+
@size = size # Compile-time size for bounds check optimization
|
|
1445
|
+
end
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
# Set element in StaticArray
|
|
1449
|
+
# arr[i] = value
|
|
1450
|
+
class StaticArraySet < Instruction
|
|
1451
|
+
attr_reader :array, :index, :value, :element_type, :size
|
|
1452
|
+
|
|
1453
|
+
def initialize(array:, index:, value:, element_type:, size:)
|
|
1454
|
+
super(type: TypeChecker::Types::NIL)
|
|
1455
|
+
@array = array
|
|
1456
|
+
@index = index
|
|
1457
|
+
@value = value
|
|
1458
|
+
@element_type = element_type
|
|
1459
|
+
@size = size
|
|
1460
|
+
end
|
|
1461
|
+
end
|
|
1462
|
+
|
|
1463
|
+
# Get size of StaticArray (compile-time constant)
|
|
1464
|
+
# arr.size → Integer (known at compile time)
|
|
1465
|
+
class StaticArraySize < Instruction
|
|
1466
|
+
attr_reader :array, :size
|
|
1467
|
+
|
|
1468
|
+
def initialize(array:, size:, result_var: nil)
|
|
1469
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1470
|
+
@array = array
|
|
1471
|
+
@size = size # Compile-time known size
|
|
1472
|
+
end
|
|
1473
|
+
end
|
|
1474
|
+
|
|
1475
|
+
# ========================================
|
|
1476
|
+
# ByteBuffer operations
|
|
1477
|
+
# Growable byte array for efficient I/O
|
|
1478
|
+
# ========================================
|
|
1479
|
+
|
|
1480
|
+
# Allocate a new ByteBuffer
|
|
1481
|
+
# ByteBuffer.new(1024) → ptr to buffer struct
|
|
1482
|
+
class ByteBufferAlloc < Instruction
|
|
1483
|
+
attr_reader :capacity
|
|
1484
|
+
|
|
1485
|
+
def initialize(capacity:, result_var: nil)
|
|
1486
|
+
super(type: TypeChecker::Types::BYTEBUFFER, result_var: result_var)
|
|
1487
|
+
@capacity = capacity # HIR value for initial capacity
|
|
1488
|
+
end
|
|
1489
|
+
end
|
|
1490
|
+
|
|
1491
|
+
# Get byte from ByteBuffer
|
|
1492
|
+
# buf[i] → Integer (0-255)
|
|
1493
|
+
class ByteBufferGet < Instruction
|
|
1494
|
+
attr_reader :buffer, :index
|
|
1495
|
+
|
|
1496
|
+
def initialize(buffer:, index:, result_var: nil)
|
|
1497
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1498
|
+
@buffer = buffer # HIR value (the ByteBuffer)
|
|
1499
|
+
@index = index # HIR value (index)
|
|
1500
|
+
end
|
|
1501
|
+
end
|
|
1502
|
+
|
|
1503
|
+
# Set byte in ByteBuffer
|
|
1504
|
+
# buf[i] = byte
|
|
1505
|
+
class ByteBufferSet < Instruction
|
|
1506
|
+
attr_reader :buffer, :index, :byte
|
|
1507
|
+
|
|
1508
|
+
def initialize(buffer:, index:, byte:)
|
|
1509
|
+
super(type: TypeChecker::Types::INTEGER)
|
|
1510
|
+
@buffer = buffer
|
|
1511
|
+
@index = index
|
|
1512
|
+
@byte = byte # HIR value (0-255)
|
|
1513
|
+
end
|
|
1514
|
+
end
|
|
1515
|
+
|
|
1516
|
+
# Get length of ByteBuffer
|
|
1517
|
+
class ByteBufferLength < Instruction
|
|
1518
|
+
attr_reader :buffer
|
|
1519
|
+
|
|
1520
|
+
def initialize(buffer:, result_var: nil)
|
|
1521
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1522
|
+
@buffer = buffer
|
|
1523
|
+
end
|
|
1524
|
+
end
|
|
1525
|
+
|
|
1526
|
+
# Append to ByteBuffer
|
|
1527
|
+
# buf << byte, buf.write(string), buf.write_bytes(other_buf)
|
|
1528
|
+
class ByteBufferAppend < Instruction
|
|
1529
|
+
attr_reader :buffer, :value, :append_type
|
|
1530
|
+
|
|
1531
|
+
# @param append_type [:byte, :string, :buffer]
|
|
1532
|
+
def initialize(buffer:, value:, append_type:, result_var: nil)
|
|
1533
|
+
super(type: TypeChecker::Types::BYTEBUFFER, result_var: result_var)
|
|
1534
|
+
@buffer = buffer
|
|
1535
|
+
@value = value
|
|
1536
|
+
@append_type = append_type
|
|
1537
|
+
end
|
|
1538
|
+
end
|
|
1539
|
+
|
|
1540
|
+
# Search for byte or sequence in ByteBuffer
|
|
1541
|
+
# buf.index_of(32) → Integer? (finds ASCII space)
|
|
1542
|
+
# buf.index_of_seq("\r\n") → Integer?
|
|
1543
|
+
class ByteBufferIndexOf < Instruction
|
|
1544
|
+
attr_reader :buffer, :pattern, :search_type, :start_offset
|
|
1545
|
+
|
|
1546
|
+
# @param search_type [:byte, :sequence]
|
|
1547
|
+
def initialize(buffer:, pattern:, search_type:, start_offset: nil, result_var: nil)
|
|
1548
|
+
super(type: TypeChecker::Types.optional(TypeChecker::Types::INTEGER), result_var: result_var)
|
|
1549
|
+
@buffer = buffer
|
|
1550
|
+
@pattern = pattern # HIR value (byte integer or string)
|
|
1551
|
+
@search_type = search_type
|
|
1552
|
+
@start_offset = start_offset # Optional start offset for search
|
|
1553
|
+
end
|
|
1554
|
+
end
|
|
1555
|
+
|
|
1556
|
+
# Convert ByteBuffer to String
|
|
1557
|
+
# buf.to_s → String
|
|
1558
|
+
class ByteBufferToString < Instruction
|
|
1559
|
+
attr_reader :buffer, :ascii_only
|
|
1560
|
+
|
|
1561
|
+
def initialize(buffer:, ascii_only: false, result_var: nil)
|
|
1562
|
+
super(type: TypeChecker::Types::STRING, result_var: result_var)
|
|
1563
|
+
@buffer = buffer
|
|
1564
|
+
@ascii_only = ascii_only # Use faster ASCII conversion if true
|
|
1565
|
+
end
|
|
1566
|
+
end
|
|
1567
|
+
|
|
1568
|
+
# Create ByteSlice from ByteBuffer
|
|
1569
|
+
# buf.slice(start, length) → ByteSlice
|
|
1570
|
+
class ByteBufferSlice < Instruction
|
|
1571
|
+
attr_reader :buffer, :start, :length
|
|
1572
|
+
|
|
1573
|
+
def initialize(buffer:, start:, length:, result_var: nil)
|
|
1574
|
+
super(type: TypeChecker::Types::BYTESLICE, result_var: result_var)
|
|
1575
|
+
@buffer = buffer
|
|
1576
|
+
@start = start # HIR value
|
|
1577
|
+
@length = length # HIR value
|
|
1578
|
+
end
|
|
1579
|
+
end
|
|
1580
|
+
|
|
1581
|
+
# ========================================
|
|
1582
|
+
# ByteSlice operations
|
|
1583
|
+
# Zero-copy view into ByteBuffer
|
|
1584
|
+
# ========================================
|
|
1585
|
+
|
|
1586
|
+
# Get byte from ByteSlice
|
|
1587
|
+
class ByteSliceGet < Instruction
|
|
1588
|
+
attr_reader :slice, :index
|
|
1589
|
+
|
|
1590
|
+
def initialize(slice:, index:, result_var: nil)
|
|
1591
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1592
|
+
@slice = slice
|
|
1593
|
+
@index = index
|
|
1594
|
+
end
|
|
1595
|
+
end
|
|
1596
|
+
|
|
1597
|
+
# Get length of ByteSlice
|
|
1598
|
+
class ByteSliceLength < Instruction
|
|
1599
|
+
attr_reader :slice
|
|
1600
|
+
|
|
1601
|
+
def initialize(slice:, result_var: nil)
|
|
1602
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1603
|
+
@slice = slice
|
|
1604
|
+
end
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
# Convert ByteSlice to String
|
|
1608
|
+
class ByteSliceToString < Instruction
|
|
1609
|
+
attr_reader :slice
|
|
1610
|
+
|
|
1611
|
+
def initialize(slice:, result_var: nil)
|
|
1612
|
+
super(type: TypeChecker::Types::STRING, result_var: result_var)
|
|
1613
|
+
@slice = slice
|
|
1614
|
+
end
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
# ========================================
|
|
1618
|
+
# Slice[T] operations
|
|
1619
|
+
# Generic bounds-checked pointer view
|
|
1620
|
+
# ========================================
|
|
1621
|
+
|
|
1622
|
+
# Allocate a new Slice with given size
|
|
1623
|
+
# Slice.new(10) → { ptr, size }
|
|
1624
|
+
class SliceAlloc < Instruction
|
|
1625
|
+
attr_reader :size, :element_type
|
|
1626
|
+
|
|
1627
|
+
def initialize(size:, element_type:, result_var: nil)
|
|
1628
|
+
slice_type = TypeChecker::Types::SliceType.new(element_type)
|
|
1629
|
+
super(type: slice_type, result_var: result_var)
|
|
1630
|
+
@size = size # HIR value
|
|
1631
|
+
@element_type = element_type # :Int64 or :Float64
|
|
1632
|
+
end
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
# Get empty Slice singleton
|
|
1636
|
+
# Slice.empty → { null, 0 }
|
|
1637
|
+
class SliceEmpty < Instruction
|
|
1638
|
+
attr_reader :element_type
|
|
1639
|
+
|
|
1640
|
+
def initialize(element_type:, result_var: nil)
|
|
1641
|
+
slice_type = TypeChecker::Types::SliceType.new(element_type)
|
|
1642
|
+
super(type: slice_type, result_var: result_var)
|
|
1643
|
+
@element_type = element_type
|
|
1644
|
+
end
|
|
1645
|
+
end
|
|
1646
|
+
|
|
1647
|
+
# Get element from Slice (bounds-checked)
|
|
1648
|
+
# slice[i] → T
|
|
1649
|
+
class SliceGet < Instruction
|
|
1650
|
+
attr_reader :slice, :index, :element_type
|
|
1651
|
+
|
|
1652
|
+
def initialize(slice:, index:, element_type:, result_var: nil)
|
|
1653
|
+
result_type = element_type == :Int64 ? TypeChecker::Types::INTEGER : TypeChecker::Types::FLOAT
|
|
1654
|
+
super(type: result_type, result_var: result_var)
|
|
1655
|
+
@slice = slice # HIR value
|
|
1656
|
+
@index = index # HIR value
|
|
1657
|
+
@element_type = element_type
|
|
1658
|
+
end
|
|
1659
|
+
end
|
|
1660
|
+
|
|
1661
|
+
# Set element in Slice (bounds-checked)
|
|
1662
|
+
# slice[i] = value → value
|
|
1663
|
+
class SliceSet < Instruction
|
|
1664
|
+
attr_reader :slice, :index, :value, :element_type
|
|
1665
|
+
|
|
1666
|
+
def initialize(slice:, index:, value:, element_type:, result_var: nil)
|
|
1667
|
+
result_type = element_type == :Int64 ? TypeChecker::Types::INTEGER : TypeChecker::Types::FLOAT
|
|
1668
|
+
super(type: result_type, result_var: result_var)
|
|
1669
|
+
@slice = slice
|
|
1670
|
+
@index = index
|
|
1671
|
+
@value = value
|
|
1672
|
+
@element_type = element_type
|
|
1673
|
+
end
|
|
1674
|
+
end
|
|
1675
|
+
|
|
1676
|
+
# Get size of Slice
|
|
1677
|
+
# slice.size → Integer
|
|
1678
|
+
class SliceSize < Instruction
|
|
1679
|
+
attr_reader :slice
|
|
1680
|
+
|
|
1681
|
+
def initialize(slice:, result_var: nil)
|
|
1682
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1683
|
+
@slice = slice
|
|
1684
|
+
end
|
|
1685
|
+
end
|
|
1686
|
+
|
|
1687
|
+
# Create subslice (view, no copy)
|
|
1688
|
+
# slice[start, count] → Slice[T]
|
|
1689
|
+
class SliceSubslice < Instruction
|
|
1690
|
+
attr_reader :slice, :start, :count, :element_type
|
|
1691
|
+
|
|
1692
|
+
def initialize(slice:, start:, count:, element_type:, result_var: nil)
|
|
1693
|
+
slice_type = TypeChecker::Types::SliceType.new(element_type)
|
|
1694
|
+
super(type: slice_type, result_var: result_var)
|
|
1695
|
+
@slice = slice
|
|
1696
|
+
@start = start # HIR value
|
|
1697
|
+
@count = count # HIR value
|
|
1698
|
+
@element_type = element_type
|
|
1699
|
+
end
|
|
1700
|
+
end
|
|
1701
|
+
|
|
1702
|
+
# Copy elements from another Slice
|
|
1703
|
+
# slice.copy_from(source) → self
|
|
1704
|
+
class SliceCopyFrom < Instruction
|
|
1705
|
+
attr_reader :dest, :source, :element_type
|
|
1706
|
+
|
|
1707
|
+
def initialize(dest:, source:, element_type:, result_var: nil)
|
|
1708
|
+
slice_type = TypeChecker::Types::SliceType.new(element_type)
|
|
1709
|
+
super(type: slice_type, result_var: result_var)
|
|
1710
|
+
@dest = dest
|
|
1711
|
+
@source = source
|
|
1712
|
+
@element_type = element_type
|
|
1713
|
+
end
|
|
1714
|
+
end
|
|
1715
|
+
|
|
1716
|
+
# Fill Slice with a value
|
|
1717
|
+
# slice.fill(value) → self
|
|
1718
|
+
class SliceFill < Instruction
|
|
1719
|
+
attr_reader :slice, :value, :element_type
|
|
1720
|
+
|
|
1721
|
+
def initialize(slice:, value:, element_type:, result_var: nil)
|
|
1722
|
+
slice_type = TypeChecker::Types::SliceType.new(element_type)
|
|
1723
|
+
super(type: slice_type, result_var: result_var)
|
|
1724
|
+
@slice = slice
|
|
1725
|
+
@value = value # HIR value
|
|
1726
|
+
@element_type = element_type
|
|
1727
|
+
end
|
|
1728
|
+
end
|
|
1729
|
+
|
|
1730
|
+
# Convert NativeArray or StaticArray to Slice (zero-copy view)
|
|
1731
|
+
# array.to_slice → Slice[T]
|
|
1732
|
+
class ToSlice < Instruction
|
|
1733
|
+
attr_reader :source, :element_type, :source_kind
|
|
1734
|
+
|
|
1735
|
+
# @param source [HIR value] NativeArray or StaticArray
|
|
1736
|
+
# @param element_type [Symbol] :Int64 or :Float64
|
|
1737
|
+
# @param source_kind [Symbol] :native_array or :static_array
|
|
1738
|
+
def initialize(source:, element_type:, source_kind:, result_var: nil)
|
|
1739
|
+
slice_type = TypeChecker::Types::SliceType.new(element_type)
|
|
1740
|
+
super(type: slice_type, result_var: result_var)
|
|
1741
|
+
@source = source
|
|
1742
|
+
@element_type = element_type
|
|
1743
|
+
@source_kind = source_kind
|
|
1744
|
+
end
|
|
1745
|
+
end
|
|
1746
|
+
|
|
1747
|
+
# ========================================
|
|
1748
|
+
# StringBuffer operations
|
|
1749
|
+
# Efficient string building
|
|
1750
|
+
# ========================================
|
|
1751
|
+
|
|
1752
|
+
# Allocate a new StringBuffer
|
|
1753
|
+
# StringBuffer.new(256) → VALUE (rb_str_buf_new result)
|
|
1754
|
+
class StringBufferAlloc < Instruction
|
|
1755
|
+
attr_reader :capacity
|
|
1756
|
+
|
|
1757
|
+
def initialize(capacity:, result_var: nil)
|
|
1758
|
+
super(type: TypeChecker::Types::STRINGBUFFER, result_var: result_var)
|
|
1759
|
+
@capacity = capacity # HIR value (nil for default)
|
|
1760
|
+
end
|
|
1761
|
+
end
|
|
1762
|
+
|
|
1763
|
+
# Append to StringBuffer
|
|
1764
|
+
# buf << string
|
|
1765
|
+
class StringBufferAppend < Instruction
|
|
1766
|
+
attr_reader :buffer, :value
|
|
1767
|
+
|
|
1768
|
+
def initialize(buffer:, value:, result_var: nil)
|
|
1769
|
+
super(type: TypeChecker::Types::STRINGBUFFER, result_var: result_var)
|
|
1770
|
+
@buffer = buffer
|
|
1771
|
+
@value = value # HIR value (string to append)
|
|
1772
|
+
end
|
|
1773
|
+
end
|
|
1774
|
+
|
|
1775
|
+
# Get current length of StringBuffer
|
|
1776
|
+
class StringBufferLength < Instruction
|
|
1777
|
+
attr_reader :buffer
|
|
1778
|
+
|
|
1779
|
+
def initialize(buffer:, result_var: nil)
|
|
1780
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1781
|
+
@buffer = buffer
|
|
1782
|
+
end
|
|
1783
|
+
end
|
|
1784
|
+
|
|
1785
|
+
# Convert StringBuffer to String (returns the internal string)
|
|
1786
|
+
class StringBufferToString < Instruction
|
|
1787
|
+
attr_reader :buffer
|
|
1788
|
+
|
|
1789
|
+
def initialize(buffer:, result_var: nil)
|
|
1790
|
+
super(type: TypeChecker::Types::STRING, result_var: result_var)
|
|
1791
|
+
@buffer = buffer
|
|
1792
|
+
end
|
|
1793
|
+
end
|
|
1794
|
+
|
|
1795
|
+
# ========================================
|
|
1796
|
+
# NativeString operations
|
|
1797
|
+
# UTF-8 native string with byte and character level operations
|
|
1798
|
+
# Memory layout: { ptr (i8*), byte_len (i64), char_len (i64), flags (i64) }
|
|
1799
|
+
# ========================================
|
|
1800
|
+
|
|
1801
|
+
# Create NativeString from Ruby String
|
|
1802
|
+
# NativeString.from(str) → NativeString
|
|
1803
|
+
class NativeStringFromRuby < Instruction
|
|
1804
|
+
attr_reader :string
|
|
1805
|
+
|
|
1806
|
+
def initialize(string:, result_var: nil)
|
|
1807
|
+
super(type: TypeChecker::Types::NATIVESTRING, result_var: result_var)
|
|
1808
|
+
@string = string # HIR value (Ruby String VALUE)
|
|
1809
|
+
end
|
|
1810
|
+
end
|
|
1811
|
+
|
|
1812
|
+
# Get byte at index (O(1))
|
|
1813
|
+
# ns.byte_at(i) → Integer (0-255)
|
|
1814
|
+
class NativeStringByteAt < Instruction
|
|
1815
|
+
attr_reader :native_string, :index
|
|
1816
|
+
|
|
1817
|
+
def initialize(native_string:, index:, result_var: nil)
|
|
1818
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1819
|
+
@native_string = native_string
|
|
1820
|
+
@index = index
|
|
1821
|
+
end
|
|
1822
|
+
end
|
|
1823
|
+
|
|
1824
|
+
# Get byte length (O(1))
|
|
1825
|
+
# ns.byte_length → Integer
|
|
1826
|
+
class NativeStringByteLength < Instruction
|
|
1827
|
+
attr_reader :native_string
|
|
1828
|
+
|
|
1829
|
+
def initialize(native_string:, result_var: nil)
|
|
1830
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1831
|
+
@native_string = native_string
|
|
1832
|
+
end
|
|
1833
|
+
end
|
|
1834
|
+
|
|
1835
|
+
# Search for byte in NativeString
|
|
1836
|
+
# ns.byte_index_of(byte) → Integer?
|
|
1837
|
+
# ns.byte_index_of(byte, start_offset) → Integer?
|
|
1838
|
+
class NativeStringByteIndexOf < Instruction
|
|
1839
|
+
attr_reader :native_string, :byte, :start_offset
|
|
1840
|
+
|
|
1841
|
+
def initialize(native_string:, byte:, start_offset: nil, result_var: nil)
|
|
1842
|
+
super(type: TypeChecker::Types.optional(TypeChecker::Types::INTEGER), result_var: result_var)
|
|
1843
|
+
@native_string = native_string
|
|
1844
|
+
@byte = byte # HIR value (0-255)
|
|
1845
|
+
@start_offset = start_offset # Optional HIR value
|
|
1846
|
+
end
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
# Create byte-level slice of NativeString
|
|
1850
|
+
# ns.byte_slice(start, length) → NativeString
|
|
1851
|
+
class NativeStringByteSlice < Instruction
|
|
1852
|
+
attr_reader :native_string, :start, :length
|
|
1853
|
+
|
|
1854
|
+
def initialize(native_string:, start:, length:, result_var: nil)
|
|
1855
|
+
super(type: TypeChecker::Types::NATIVESTRING, result_var: result_var)
|
|
1856
|
+
@native_string = native_string
|
|
1857
|
+
@start = start # HIR value (byte offset)
|
|
1858
|
+
@length = length # HIR value (byte count)
|
|
1859
|
+
end
|
|
1860
|
+
end
|
|
1861
|
+
|
|
1862
|
+
# Get character at index (UTF-8 aware, O(n) worst case)
|
|
1863
|
+
# ns.char_at(i) → String (single character)
|
|
1864
|
+
class NativeStringCharAt < Instruction
|
|
1865
|
+
attr_reader :native_string, :index
|
|
1866
|
+
|
|
1867
|
+
def initialize(native_string:, index:, result_var: nil)
|
|
1868
|
+
super(type: TypeChecker::Types::STRING, result_var: result_var)
|
|
1869
|
+
@native_string = native_string
|
|
1870
|
+
@index = index # Character index (not byte index)
|
|
1871
|
+
end
|
|
1872
|
+
end
|
|
1873
|
+
|
|
1874
|
+
# Get character length (UTF-8 aware, cached after first call)
|
|
1875
|
+
# ns.char_length → Integer
|
|
1876
|
+
class NativeStringCharLength < Instruction
|
|
1877
|
+
attr_reader :native_string
|
|
1878
|
+
|
|
1879
|
+
def initialize(native_string:, result_var: nil)
|
|
1880
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
1881
|
+
@native_string = native_string
|
|
1882
|
+
end
|
|
1883
|
+
end
|
|
1884
|
+
|
|
1885
|
+
# Search for substring in NativeString
|
|
1886
|
+
# ns.char_index_of(needle) → Integer? (character index)
|
|
1887
|
+
class NativeStringCharIndexOf < Instruction
|
|
1888
|
+
attr_reader :native_string, :needle
|
|
1889
|
+
|
|
1890
|
+
def initialize(native_string:, needle:, result_var: nil)
|
|
1891
|
+
super(type: TypeChecker::Types.optional(TypeChecker::Types::INTEGER), result_var: result_var)
|
|
1892
|
+
@native_string = native_string
|
|
1893
|
+
@needle = needle # HIR value (String to find)
|
|
1894
|
+
end
|
|
1895
|
+
end
|
|
1896
|
+
|
|
1897
|
+
# Create character-level slice of NativeString (UTF-8 aware)
|
|
1898
|
+
# ns.char_slice(start, length) → NativeString
|
|
1899
|
+
class NativeStringCharSlice < Instruction
|
|
1900
|
+
attr_reader :native_string, :start, :length
|
|
1901
|
+
|
|
1902
|
+
def initialize(native_string:, start:, length:, result_var: nil)
|
|
1903
|
+
super(type: TypeChecker::Types::NATIVESTRING, result_var: result_var)
|
|
1904
|
+
@native_string = native_string
|
|
1905
|
+
@start = start # HIR value (character offset)
|
|
1906
|
+
@length = length # HIR value (character count)
|
|
1907
|
+
end
|
|
1908
|
+
end
|
|
1909
|
+
|
|
1910
|
+
# Check if NativeString is ASCII-only (O(1) after creation)
|
|
1911
|
+
# ns.ascii_only? → bool
|
|
1912
|
+
class NativeStringAsciiOnly < Instruction
|
|
1913
|
+
attr_reader :native_string
|
|
1914
|
+
|
|
1915
|
+
def initialize(native_string:, result_var: nil)
|
|
1916
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
1917
|
+
@native_string = native_string
|
|
1918
|
+
end
|
|
1919
|
+
end
|
|
1920
|
+
|
|
1921
|
+
# Check if NativeString starts with prefix
|
|
1922
|
+
# ns.starts_with?(prefix) → bool
|
|
1923
|
+
class NativeStringStartsWith < Instruction
|
|
1924
|
+
attr_reader :native_string, :prefix
|
|
1925
|
+
|
|
1926
|
+
def initialize(native_string:, prefix:, result_var: nil)
|
|
1927
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
1928
|
+
@native_string = native_string
|
|
1929
|
+
@prefix = prefix # HIR value (String)
|
|
1930
|
+
end
|
|
1931
|
+
end
|
|
1932
|
+
|
|
1933
|
+
# Check if NativeString ends with suffix
|
|
1934
|
+
# ns.ends_with?(suffix) → bool
|
|
1935
|
+
class NativeStringEndsWith < Instruction
|
|
1936
|
+
attr_reader :native_string, :suffix
|
|
1937
|
+
|
|
1938
|
+
def initialize(native_string:, suffix:, result_var: nil)
|
|
1939
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
1940
|
+
@native_string = native_string
|
|
1941
|
+
@suffix = suffix # HIR value (String)
|
|
1942
|
+
end
|
|
1943
|
+
end
|
|
1944
|
+
|
|
1945
|
+
# Check if NativeString has valid UTF-8 encoding
|
|
1946
|
+
# ns.valid_encoding? → bool
|
|
1947
|
+
class NativeStringValidEncoding < Instruction
|
|
1948
|
+
attr_reader :native_string
|
|
1949
|
+
|
|
1950
|
+
def initialize(native_string:, result_var: nil)
|
|
1951
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
1952
|
+
@native_string = native_string
|
|
1953
|
+
end
|
|
1954
|
+
end
|
|
1955
|
+
|
|
1956
|
+
# Convert NativeString to Ruby String
|
|
1957
|
+
# ns.to_s → String
|
|
1958
|
+
class NativeStringToRuby < Instruction
|
|
1959
|
+
attr_reader :native_string
|
|
1960
|
+
|
|
1961
|
+
def initialize(native_string:, result_var: nil)
|
|
1962
|
+
super(type: TypeChecker::Types::STRING, result_var: result_var)
|
|
1963
|
+
@native_string = native_string
|
|
1964
|
+
end
|
|
1965
|
+
end
|
|
1966
|
+
|
|
1967
|
+
# Compare two NativeStrings
|
|
1968
|
+
# ns == other → bool
|
|
1969
|
+
class NativeStringCompare < Instruction
|
|
1970
|
+
attr_reader :native_string, :other
|
|
1971
|
+
|
|
1972
|
+
def initialize(native_string:, other:, result_var: nil)
|
|
1973
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
1974
|
+
@native_string = native_string
|
|
1975
|
+
@other = other # HIR value (NativeString)
|
|
1976
|
+
end
|
|
1977
|
+
end
|
|
1978
|
+
|
|
1979
|
+
# ========================================
|
|
1980
|
+
# NativeClass operations
|
|
1981
|
+
# Fixed-layout structs with unboxed numeric fields
|
|
1982
|
+
# ========================================
|
|
1983
|
+
|
|
1984
|
+
# Allocate a new NativeClass instance
|
|
1985
|
+
# Point.new → struct { double x; double y; }
|
|
1986
|
+
class NativeNew < Instruction
|
|
1987
|
+
attr_reader :class_type, :args
|
|
1988
|
+
|
|
1989
|
+
def initialize(class_type:, result_var: nil, args: [])
|
|
1990
|
+
super(type: class_type, result_var: result_var)
|
|
1991
|
+
@class_type = class_type # NativeClassType
|
|
1992
|
+
@args = args # Constructor arguments (for JVM <init>)
|
|
1993
|
+
end
|
|
1994
|
+
end
|
|
1995
|
+
|
|
1996
|
+
# Get field from NativeClass (unboxed)
|
|
1997
|
+
# point.x → double or i64
|
|
1998
|
+
class NativeFieldGet < Instruction
|
|
1999
|
+
attr_reader :object, :field_name, :class_type
|
|
2000
|
+
|
|
2001
|
+
def initialize(object:, field_name:, class_type:, result_var: nil)
|
|
2002
|
+
field_type_tag = class_type.llvm_field_type_tag(field_name)
|
|
2003
|
+
internal_type = case field_type_tag
|
|
2004
|
+
when :i64 then TypeChecker::Types::INTEGER
|
|
2005
|
+
when :double then TypeChecker::Types::FLOAT
|
|
2006
|
+
else TypeChecker::Types::UNTYPED
|
|
2007
|
+
end
|
|
2008
|
+
super(type: internal_type, result_var: result_var)
|
|
2009
|
+
@object = object # HIR value (the NativeClass instance)
|
|
2010
|
+
@field_name = field_name.to_sym
|
|
2011
|
+
@class_type = class_type # NativeClassType
|
|
2012
|
+
end
|
|
2013
|
+
end
|
|
2014
|
+
|
|
2015
|
+
# Set field in NativeClass
|
|
2016
|
+
# point.x = value
|
|
2017
|
+
class NativeFieldSet < Instruction
|
|
2018
|
+
attr_reader :object, :field_name, :value, :class_type
|
|
2019
|
+
|
|
2020
|
+
def initialize(object:, field_name:, value:, class_type:)
|
|
2021
|
+
field_type_tag = class_type.llvm_field_type_tag(field_name)
|
|
2022
|
+
internal_type = case field_type_tag
|
|
2023
|
+
when :i64 then TypeChecker::Types::INTEGER
|
|
2024
|
+
when :double then TypeChecker::Types::FLOAT
|
|
2025
|
+
else TypeChecker::Types::UNTYPED
|
|
2026
|
+
end
|
|
2027
|
+
super(type: internal_type)
|
|
2028
|
+
@object = object
|
|
2029
|
+
@field_name = field_name.to_sym
|
|
2030
|
+
@value = value
|
|
2031
|
+
@class_type = class_type
|
|
2032
|
+
end
|
|
2033
|
+
end
|
|
2034
|
+
|
|
2035
|
+
# Call a method on a NativeClass instance
|
|
2036
|
+
# Uses static dispatch (direct function call) instead of rb_funcallv
|
|
2037
|
+
# point.length_squared or point.add(other)
|
|
2038
|
+
class NativeMethodCall < Instruction
|
|
2039
|
+
attr_reader :receiver, :method_name, :args, :class_type, :method_sig, :owner_class
|
|
2040
|
+
|
|
2041
|
+
# @param receiver [Instruction] The NativeClass instance
|
|
2042
|
+
# @param method_name [Symbol] Method name
|
|
2043
|
+
# @param args [Array<Instruction>] Arguments (excluding self)
|
|
2044
|
+
# @param class_type [NativeClassType] Type of receiver
|
|
2045
|
+
# @param method_sig [NativeMethodType] Method signature
|
|
2046
|
+
# @param owner_class [NativeClassType] Class that implements the method (may be superclass)
|
|
2047
|
+
# @param result_var [String, nil] Result variable name
|
|
2048
|
+
def initialize(receiver:, method_name:, args:, class_type:,
|
|
2049
|
+
method_sig:, owner_class:, result_var: nil)
|
|
2050
|
+
# Determine return type from method signature
|
|
2051
|
+
return_type = if method_sig
|
|
2052
|
+
method_sig.return_type_as_internal
|
|
2053
|
+
else
|
|
2054
|
+
TypeChecker::Types::UNTYPED
|
|
2055
|
+
end
|
|
2056
|
+
super(type: return_type, result_var: result_var)
|
|
2057
|
+
@receiver = receiver
|
|
2058
|
+
@method_name = method_name.to_sym
|
|
2059
|
+
@args = args
|
|
2060
|
+
@class_type = class_type
|
|
2061
|
+
@method_sig = method_sig
|
|
2062
|
+
@owner_class = owner_class
|
|
2063
|
+
end
|
|
2064
|
+
end
|
|
2065
|
+
|
|
2066
|
+
# Direct call to an external C function
|
|
2067
|
+
# Bypasses Ruby method dispatch entirely
|
|
2068
|
+
# Used for @cfunc annotated methods
|
|
2069
|
+
#
|
|
2070
|
+
# Example:
|
|
2071
|
+
# # @cfunc "fast_sin" : (Float) -> Float
|
|
2072
|
+
# def self.sin: (Float) -> Float
|
|
2073
|
+
#
|
|
2074
|
+
# Generates direct C function call without rb_funcallv
|
|
2075
|
+
class CFuncCall < Instruction
|
|
2076
|
+
attr_reader :c_func_name, :args, :cfunc_type
|
|
2077
|
+
|
|
2078
|
+
# @param c_func_name [String] The C function name
|
|
2079
|
+
# @param args [Array<Instruction>] Arguments as HIR instructions
|
|
2080
|
+
# @param cfunc_type [CFuncType] The function type signature
|
|
2081
|
+
# @param result_var [String, nil] Result variable name
|
|
2082
|
+
def initialize(c_func_name:, args:, cfunc_type:, result_var: nil)
|
|
2083
|
+
return_type = cfunc_to_internal_type(cfunc_type.return_type)
|
|
2084
|
+
super(type: return_type, result_var: result_var)
|
|
2085
|
+
@c_func_name = c_func_name
|
|
2086
|
+
@args = args
|
|
2087
|
+
@cfunc_type = cfunc_type
|
|
2088
|
+
end
|
|
2089
|
+
|
|
2090
|
+
private
|
|
2091
|
+
|
|
2092
|
+
def cfunc_to_internal_type(type_sym)
|
|
2093
|
+
case type_sym
|
|
2094
|
+
when :Float then TypeChecker::Types::FLOAT
|
|
2095
|
+
when :Integer then TypeChecker::Types::INTEGER
|
|
2096
|
+
when :String then TypeChecker::Types::STRING
|
|
2097
|
+
when :Bool then TypeChecker::Types::BOOL
|
|
2098
|
+
when :void then TypeChecker::Types::NIL
|
|
2099
|
+
else TypeChecker::Types::UNTYPED
|
|
2100
|
+
end
|
|
2101
|
+
end
|
|
2102
|
+
end
|
|
2103
|
+
|
|
2104
|
+
# ========================================
|
|
2105
|
+
# Extern class operations
|
|
2106
|
+
# External C struct wrapper operations
|
|
2107
|
+
# ========================================
|
|
2108
|
+
|
|
2109
|
+
# Allocate an extern class wrapper (holds void* pointer)
|
|
2110
|
+
class ExternNew < Instruction
|
|
2111
|
+
attr_reader :extern_type
|
|
2112
|
+
|
|
2113
|
+
# @param extern_type [ExternClassType] The extern class type
|
|
2114
|
+
# @param result_var [String, nil] Result variable name
|
|
2115
|
+
def initialize(extern_type:, result_var: nil)
|
|
2116
|
+
super(type: extern_type, result_var: result_var)
|
|
2117
|
+
@extern_type = extern_type
|
|
2118
|
+
end
|
|
2119
|
+
end
|
|
2120
|
+
|
|
2121
|
+
# Call extern class constructor (singleton method returning opaque pointer)
|
|
2122
|
+
# Example: db = SQLiteDB.open("test.db")
|
|
2123
|
+
class ExternConstructorCall < Instruction
|
|
2124
|
+
attr_reader :extern_type, :c_func_name, :args, :method_sig
|
|
2125
|
+
|
|
2126
|
+
# @param extern_type [ExternClassType] The extern class type
|
|
2127
|
+
# @param c_func_name [String] C function name to call
|
|
2128
|
+
# @param args [Array<Instruction>] Arguments as HIR instructions
|
|
2129
|
+
# @param method_sig [ExternMethodType] Method signature
|
|
2130
|
+
# @param result_var [String, nil] Result variable name
|
|
2131
|
+
def initialize(extern_type:, c_func_name:, args:, method_sig:, result_var: nil)
|
|
2132
|
+
super(type: extern_type, result_var: result_var)
|
|
2133
|
+
@extern_type = extern_type
|
|
2134
|
+
@c_func_name = c_func_name
|
|
2135
|
+
@args = args
|
|
2136
|
+
@method_sig = method_sig
|
|
2137
|
+
end
|
|
2138
|
+
end
|
|
2139
|
+
|
|
2140
|
+
# Call extern class instance method (passes opaque pointer as first arg)
|
|
2141
|
+
# Example: results = db.execute("SELECT * FROM users")
|
|
2142
|
+
class ExternMethodCall < Instruction
|
|
2143
|
+
attr_reader :receiver, :c_func_name, :args, :extern_type, :method_sig
|
|
2144
|
+
|
|
2145
|
+
# @param receiver [Instruction, String] Receiver (extern class instance)
|
|
2146
|
+
# @param c_func_name [String] C function name to call
|
|
2147
|
+
# @param args [Array<Instruction>] Arguments (excluding opaque pointer)
|
|
2148
|
+
# @param extern_type [ExternClassType] The extern class type
|
|
2149
|
+
# @param method_sig [ExternMethodType] Method signature
|
|
2150
|
+
# @param result_var [String, nil] Result variable name
|
|
2151
|
+
def initialize(receiver:, c_func_name:, args:, extern_type:, method_sig:, result_var: nil)
|
|
2152
|
+
return_type = extern_to_internal_type(method_sig.return_type)
|
|
2153
|
+
super(type: return_type, result_var: result_var)
|
|
2154
|
+
@receiver = receiver
|
|
2155
|
+
@c_func_name = c_func_name
|
|
2156
|
+
@args = args
|
|
2157
|
+
@extern_type = extern_type
|
|
2158
|
+
@method_sig = method_sig
|
|
2159
|
+
end
|
|
2160
|
+
|
|
2161
|
+
private
|
|
2162
|
+
|
|
2163
|
+
def extern_to_internal_type(type_sym)
|
|
2164
|
+
case type_sym
|
|
2165
|
+
when :Float then TypeChecker::Types::FLOAT
|
|
2166
|
+
when :Integer then TypeChecker::Types::INTEGER
|
|
2167
|
+
when :String then TypeChecker::Types::STRING
|
|
2168
|
+
when :Bool then TypeChecker::Types::BOOL
|
|
2169
|
+
when :Array then TypeChecker::Types::ClassInstance.new(:Array)
|
|
2170
|
+
when :Hash then TypeChecker::Types::ClassInstance.new(:Hash)
|
|
2171
|
+
when :void then TypeChecker::Types::NIL
|
|
2172
|
+
when :ptr then TypeChecker::Types::UNTYPED
|
|
2173
|
+
else TypeChecker::Types::UNTYPED
|
|
2174
|
+
end
|
|
2175
|
+
end
|
|
2176
|
+
end
|
|
2177
|
+
|
|
2178
|
+
# ========================================
|
|
2179
|
+
# SIMD class operations
|
|
2180
|
+
# Fixed-size vector operations for @simd classes
|
|
2181
|
+
# ========================================
|
|
2182
|
+
|
|
2183
|
+
# Allocate a new SIMD class instance (zero-initialized vector)
|
|
2184
|
+
class SIMDNew < Instruction
|
|
2185
|
+
attr_reader :simd_type
|
|
2186
|
+
|
|
2187
|
+
# @param simd_type [SIMDClassType] The SIMD class type
|
|
2188
|
+
# @param result_var [String, nil] Result variable name
|
|
2189
|
+
def initialize(simd_type:, result_var: nil)
|
|
2190
|
+
super(type: simd_type, result_var: result_var)
|
|
2191
|
+
@simd_type = simd_type
|
|
2192
|
+
end
|
|
2193
|
+
end
|
|
2194
|
+
|
|
2195
|
+
# Get field from SIMD class (extract element from vector)
|
|
2196
|
+
class SIMDFieldGet < Instruction
|
|
2197
|
+
attr_reader :object, :field_name, :simd_type
|
|
2198
|
+
|
|
2199
|
+
# @param object [Instruction, String] SIMD class instance
|
|
2200
|
+
# @param field_name [Symbol] Field name (e.g., :x, :y, :z, :w)
|
|
2201
|
+
# @param simd_type [SIMDClassType] The SIMD class type
|
|
2202
|
+
# @param result_var [String, nil] Result variable name
|
|
2203
|
+
def initialize(object:, field_name:, simd_type:, result_var: nil)
|
|
2204
|
+
super(type: TypeChecker::Types::FLOAT, result_var: result_var)
|
|
2205
|
+
@object = object
|
|
2206
|
+
@field_name = field_name.to_sym
|
|
2207
|
+
@simd_type = simd_type
|
|
2208
|
+
end
|
|
2209
|
+
end
|
|
2210
|
+
|
|
2211
|
+
# Set field in SIMD class (insert element into vector)
|
|
2212
|
+
class SIMDFieldSet < Instruction
|
|
2213
|
+
attr_reader :object, :field_name, :value, :simd_type
|
|
2214
|
+
|
|
2215
|
+
# @param object [Instruction, String] SIMD class instance
|
|
2216
|
+
# @param field_name [Symbol] Field name (e.g., :x, :y, :z, :w)
|
|
2217
|
+
# @param value [Instruction, String] Value to set
|
|
2218
|
+
# @param simd_type [SIMDClassType] The SIMD class type
|
|
2219
|
+
def initialize(object:, field_name:, value:, simd_type:)
|
|
2220
|
+
super(type: TypeChecker::Types::FLOAT)
|
|
2221
|
+
@object = object
|
|
2222
|
+
@field_name = field_name.to_sym
|
|
2223
|
+
@value = value
|
|
2224
|
+
@simd_type = simd_type
|
|
2225
|
+
end
|
|
2226
|
+
end
|
|
2227
|
+
|
|
2228
|
+
# Call a method on SIMD class (vector arithmetic operation)
|
|
2229
|
+
class SIMDMethodCall < Instruction
|
|
2230
|
+
attr_reader :receiver, :method_name, :args, :simd_type, :method_sig
|
|
2231
|
+
|
|
2232
|
+
# @param receiver [Instruction, String] SIMD class instance
|
|
2233
|
+
# @param method_name [Symbol] Method name (e.g., :add, :dot, :scale)
|
|
2234
|
+
# @param args [Array<Instruction>] Arguments
|
|
2235
|
+
# @param simd_type [SIMDClassType] The SIMD class type
|
|
2236
|
+
# @param method_sig [NativeMethodType, nil] Method signature
|
|
2237
|
+
# @param result_var [String, nil] Result variable name
|
|
2238
|
+
def initialize(receiver:, method_name:, args:, simd_type:, method_sig: nil, result_var: nil)
|
|
2239
|
+
# Determine return type: scalar (Float64) or vector (Self)
|
|
2240
|
+
return_type = if method_sig&.return_type == :Float64
|
|
2241
|
+
TypeChecker::Types::FLOAT
|
|
2242
|
+
else
|
|
2243
|
+
simd_type
|
|
2244
|
+
end
|
|
2245
|
+
super(type: return_type, result_var: result_var)
|
|
2246
|
+
@receiver = receiver
|
|
2247
|
+
@method_name = method_name.to_sym
|
|
2248
|
+
@args = args
|
|
2249
|
+
@simd_type = simd_type
|
|
2250
|
+
@method_sig = method_sig
|
|
2251
|
+
end
|
|
2252
|
+
end
|
|
2253
|
+
|
|
2254
|
+
# ========================================
|
|
2255
|
+
# JSON operations (yyjson-based)
|
|
2256
|
+
# Direct JSON parsing to NativeClass without VALUE conversion overhead
|
|
2257
|
+
# ========================================
|
|
2258
|
+
|
|
2259
|
+
# Parse JSON string directly into a NativeClass
|
|
2260
|
+
# KonpeitoJSON.parse_as(json_string, User) → User (NativeClass)
|
|
2261
|
+
# Avoids VALUE conversion for unboxed fields (Integer, Float, Bool)
|
|
2262
|
+
class JSONParseAs < Instruction
|
|
2263
|
+
attr_reader :json_expr, :target_class
|
|
2264
|
+
|
|
2265
|
+
# @param json_expr [Instruction] HIR expression for JSON string
|
|
2266
|
+
# @param target_class [NativeClassType] Target NativeClass type
|
|
2267
|
+
# @param result_var [String, nil] Result variable name
|
|
2268
|
+
def initialize(json_expr:, target_class:, result_var: nil)
|
|
2269
|
+
super(type: target_class, result_var: result_var)
|
|
2270
|
+
@json_expr = json_expr
|
|
2271
|
+
@target_class = target_class
|
|
2272
|
+
end
|
|
2273
|
+
end
|
|
2274
|
+
|
|
2275
|
+
# Parse JSON array directly into a NativeArray
|
|
2276
|
+
# KonpeitoJSON.parse_array_as(json_string, User) → NativeArray[User]
|
|
2277
|
+
class JSONParseArrayAs < Instruction
|
|
2278
|
+
attr_reader :json_expr, :element_class
|
|
2279
|
+
|
|
2280
|
+
# @param json_expr [Instruction] HIR expression for JSON string
|
|
2281
|
+
# @param element_class [NativeClassType] Element NativeClass type
|
|
2282
|
+
# @param result_var [String, nil] Result variable name
|
|
2283
|
+
def initialize(json_expr:, element_class:, result_var: nil)
|
|
2284
|
+
array_type = TypeChecker::Types::NativeArrayType.new(element_class)
|
|
2285
|
+
super(type: array_type, result_var: result_var)
|
|
2286
|
+
@json_expr = json_expr
|
|
2287
|
+
@element_class = element_class
|
|
2288
|
+
end
|
|
2289
|
+
end
|
|
2290
|
+
|
|
2291
|
+
# ========================================
|
|
2292
|
+
# NativeHash operations
|
|
2293
|
+
# Generic hash with Robin Hood hashing
|
|
2294
|
+
# Memory layout: { buckets (ptr), size (i64), capacity (i64) }
|
|
2295
|
+
# Each bucket: { hash (i64), key (K), value (V), state (i8) }
|
|
2296
|
+
# ========================================
|
|
2297
|
+
|
|
2298
|
+
# Allocate a new NativeHash
|
|
2299
|
+
# NativeHashStringInteger.new(capacity) → NativeHash[String, Integer]
|
|
2300
|
+
class NativeHashAlloc < Instruction
|
|
2301
|
+
attr_reader :key_type, :value_type, :capacity
|
|
2302
|
+
|
|
2303
|
+
# @param key_type [Symbol] :String, :Symbol, or :Integer
|
|
2304
|
+
# @param value_type [Symbol, NativeClassType] Value type
|
|
2305
|
+
# @param capacity [Instruction, nil] Optional initial capacity
|
|
2306
|
+
def initialize(key_type:, value_type:, capacity: nil, result_var: nil)
|
|
2307
|
+
hash_type = TypeChecker::Types::NativeHashType.new(key_type, value_type)
|
|
2308
|
+
super(type: hash_type, result_var: result_var)
|
|
2309
|
+
@key_type = key_type
|
|
2310
|
+
@value_type = value_type
|
|
2311
|
+
@capacity = capacity # HIR value (nil for default 16)
|
|
2312
|
+
end
|
|
2313
|
+
end
|
|
2314
|
+
|
|
2315
|
+
# Get value from NativeHash
|
|
2316
|
+
# hash[key] → V | nil
|
|
2317
|
+
class NativeHashGet < Instruction
|
|
2318
|
+
attr_reader :hash_var, :key, :key_type, :value_type
|
|
2319
|
+
|
|
2320
|
+
def initialize(hash_var:, key:, key_type:, value_type:, result_var: nil)
|
|
2321
|
+
# Result is the value type (nullable)
|
|
2322
|
+
result_type = case value_type
|
|
2323
|
+
when :Integer then TypeChecker::Types::INTEGER
|
|
2324
|
+
when :Float then TypeChecker::Types::FLOAT
|
|
2325
|
+
when :Bool then TypeChecker::Types::BOOL
|
|
2326
|
+
when :String, :Object, :Array, :Hash then TypeChecker::Types::ClassInstance.new(value_type)
|
|
2327
|
+
else
|
|
2328
|
+
# NativeClass
|
|
2329
|
+
value_type
|
|
2330
|
+
end
|
|
2331
|
+
super(type: result_type, result_var: result_var)
|
|
2332
|
+
@hash_var = hash_var # HIR value
|
|
2333
|
+
@key = key # HIR value
|
|
2334
|
+
@key_type = key_type
|
|
2335
|
+
@value_type = value_type
|
|
2336
|
+
end
|
|
2337
|
+
end
|
|
2338
|
+
|
|
2339
|
+
# Set value in NativeHash
|
|
2340
|
+
# hash[key] = value → value
|
|
2341
|
+
class NativeHashSet < Instruction
|
|
2342
|
+
attr_reader :hash_var, :key, :value, :key_type, :value_type
|
|
2343
|
+
|
|
2344
|
+
def initialize(hash_var:, key:, value:, key_type:, value_type:, result_var: nil)
|
|
2345
|
+
result_type = case value_type
|
|
2346
|
+
when :Integer then TypeChecker::Types::INTEGER
|
|
2347
|
+
when :Float then TypeChecker::Types::FLOAT
|
|
2348
|
+
when :Bool then TypeChecker::Types::BOOL
|
|
2349
|
+
when :String, :Object, :Array, :Hash then TypeChecker::Types::ClassInstance.new(value_type)
|
|
2350
|
+
else
|
|
2351
|
+
value_type
|
|
2352
|
+
end
|
|
2353
|
+
super(type: result_type, result_var: result_var)
|
|
2354
|
+
@hash_var = hash_var
|
|
2355
|
+
@key = key
|
|
2356
|
+
@value = value
|
|
2357
|
+
@key_type = key_type
|
|
2358
|
+
@value_type = value_type
|
|
2359
|
+
end
|
|
2360
|
+
end
|
|
2361
|
+
|
|
2362
|
+
# Get size of NativeHash
|
|
2363
|
+
# hash.size → Integer
|
|
2364
|
+
class NativeHashSize < Instruction
|
|
2365
|
+
attr_reader :hash_var
|
|
2366
|
+
|
|
2367
|
+
def initialize(hash_var:, result_var: nil)
|
|
2368
|
+
super(type: TypeChecker::Types::INTEGER, result_var: result_var)
|
|
2369
|
+
@hash_var = hash_var
|
|
2370
|
+
end
|
|
2371
|
+
end
|
|
2372
|
+
|
|
2373
|
+
# Check if key exists in NativeHash
|
|
2374
|
+
# hash.has_key?(key) → bool
|
|
2375
|
+
class NativeHashHasKey < Instruction
|
|
2376
|
+
attr_reader :hash_var, :key, :key_type
|
|
2377
|
+
|
|
2378
|
+
def initialize(hash_var:, key:, key_type:, result_var: nil)
|
|
2379
|
+
super(type: TypeChecker::Types::BOOL, result_var: result_var)
|
|
2380
|
+
@hash_var = hash_var
|
|
2381
|
+
@key = key
|
|
2382
|
+
@key_type = key_type
|
|
2383
|
+
end
|
|
2384
|
+
end
|
|
2385
|
+
|
|
2386
|
+
# Delete key from NativeHash
|
|
2387
|
+
# hash.delete(key) → V | nil
|
|
2388
|
+
class NativeHashDelete < Instruction
|
|
2389
|
+
attr_reader :hash_var, :key, :key_type, :value_type
|
|
2390
|
+
|
|
2391
|
+
def initialize(hash_var:, key:, key_type:, value_type:, result_var: nil)
|
|
2392
|
+
result_type = case value_type
|
|
2393
|
+
when :Integer then TypeChecker::Types::INTEGER
|
|
2394
|
+
when :Float then TypeChecker::Types::FLOAT
|
|
2395
|
+
when :Bool then TypeChecker::Types::BOOL
|
|
2396
|
+
when :String, :Object, :Array, :Hash then TypeChecker::Types::ClassInstance.new(value_type)
|
|
2397
|
+
else
|
|
2398
|
+
value_type
|
|
2399
|
+
end
|
|
2400
|
+
super(type: result_type, result_var: result_var)
|
|
2401
|
+
@hash_var = hash_var
|
|
2402
|
+
@key = key
|
|
2403
|
+
@key_type = key_type
|
|
2404
|
+
@value_type = value_type
|
|
2405
|
+
end
|
|
2406
|
+
end
|
|
2407
|
+
|
|
2408
|
+
# Clear all entries from NativeHash
|
|
2409
|
+
# hash.clear → self
|
|
2410
|
+
class NativeHashClear < Instruction
|
|
2411
|
+
attr_reader :hash_var, :key_type, :value_type
|
|
2412
|
+
|
|
2413
|
+
def initialize(hash_var:, key_type:, value_type:, result_var: nil)
|
|
2414
|
+
hash_type = TypeChecker::Types::NativeHashType.new(key_type, value_type)
|
|
2415
|
+
super(type: hash_type, result_var: result_var)
|
|
2416
|
+
@hash_var = hash_var
|
|
2417
|
+
@key_type = key_type
|
|
2418
|
+
@value_type = value_type
|
|
2419
|
+
end
|
|
2420
|
+
end
|
|
2421
|
+
|
|
2422
|
+
# Get all keys from NativeHash
|
|
2423
|
+
# hash.keys → Array[K]
|
|
2424
|
+
class NativeHashKeys < Instruction
|
|
2425
|
+
attr_reader :hash_var, :key_type
|
|
2426
|
+
|
|
2427
|
+
def initialize(hash_var:, key_type:, result_var: nil)
|
|
2428
|
+
# Returns Array of keys (Ruby Array, not NativeArray)
|
|
2429
|
+
super(type: TypeChecker::Types::ClassInstance.new(:Array), result_var: result_var)
|
|
2430
|
+
@hash_var = hash_var
|
|
2431
|
+
@key_type = key_type
|
|
2432
|
+
end
|
|
2433
|
+
end
|
|
2434
|
+
|
|
2435
|
+
# Get all values from NativeHash
|
|
2436
|
+
# hash.values → Array[V]
|
|
2437
|
+
class NativeHashValues < Instruction
|
|
2438
|
+
attr_reader :hash_var, :key_type, :value_type
|
|
2439
|
+
|
|
2440
|
+
def initialize(hash_var:, key_type:, value_type:, result_var: nil)
|
|
2441
|
+
# Returns Array of values (Ruby Array)
|
|
2442
|
+
super(type: TypeChecker::Types::ClassInstance.new(:Array), result_var: result_var)
|
|
2443
|
+
@hash_var = hash_var
|
|
2444
|
+
@key_type = key_type
|
|
2445
|
+
@value_type = value_type
|
|
2446
|
+
end
|
|
2447
|
+
end
|
|
2448
|
+
|
|
2449
|
+
# Iterate over NativeHash entries
|
|
2450
|
+
# hash.each { |k, v| ... }
|
|
2451
|
+
class NativeHashEach < Instruction
|
|
2452
|
+
attr_reader :hash_var, :key_type, :value_type, :block_params, :block_body
|
|
2453
|
+
|
|
2454
|
+
def initialize(hash_var:, key_type:, value_type:, block_params:, block_body:, result_var: nil)
|
|
2455
|
+
hash_type = TypeChecker::Types::NativeHashType.new(key_type, value_type)
|
|
2456
|
+
super(type: hash_type, result_var: result_var)
|
|
2457
|
+
@hash_var = hash_var
|
|
2458
|
+
@key_type = key_type
|
|
2459
|
+
@value_type = value_type
|
|
2460
|
+
@block_params = block_params # Array of param names [key_var, value_var]
|
|
2461
|
+
@block_body = block_body # Array of BasicBlocks
|
|
2462
|
+
end
|
|
2463
|
+
end
|
|
2464
|
+
end
|
|
2465
|
+
end
|