mt-lang 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/AUTHORS +3 -0
  4. data/Gemfile +19 -0
  5. data/Gemfile.lock +82 -0
  6. data/LICENSE +21 -0
  7. data/README.md +1208 -0
  8. data/Rakefile +332 -0
  9. data/bin/mtc +8 -0
  10. data/bin/profile-mtc-checks +133 -0
  11. data/bin/tracy-profiler +0 -0
  12. data/docs/build-guide.md +536 -0
  13. data/docs/index.html +2778 -0
  14. data/docs/language-design.md +1519 -0
  15. data/docs/language-manual.md +1534 -0
  16. data/lib/milk_tea/base.rb +49 -0
  17. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
  18. data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
  19. data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
  20. data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
  21. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
  22. data/lib/milk_tea/bindings/bindgen.rb +207 -0
  23. data/lib/milk_tea/bindings/cli.rb +121 -0
  24. data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
  25. data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
  26. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
  27. data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
  28. data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
  29. data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
  30. data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
  31. data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
  32. data/lib/milk_tea/bindings/steamworks.rb +629 -0
  33. data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
  34. data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
  35. data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
  36. data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
  37. data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
  38. data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
  39. data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
  40. data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
  41. data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
  42. data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
  43. data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
  44. data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
  45. data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
  46. data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
  47. data/lib/milk_tea/bindings.rb +23 -0
  48. data/lib/milk_tea/core/ast.rb +311 -0
  49. data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
  50. data/lib/milk_tea/core/binding_types.rb +18 -0
  51. data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
  52. data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
  53. data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
  54. data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
  55. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
  56. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
  57. data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
  58. data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
  59. data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
  60. data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
  61. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
  62. data/lib/milk_tea/core/c_backend/statements.rb +563 -0
  63. data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
  64. data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
  65. data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
  66. data/lib/milk_tea/core/c_backend.rb +287 -0
  67. data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
  68. data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
  69. data/lib/milk_tea/core/compile_time.rb +329 -0
  70. data/lib/milk_tea/core/control_flow/builder.rb +582 -0
  71. data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
  72. data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
  73. data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
  74. data/lib/milk_tea/core/control_flow/graph.rb +90 -0
  75. data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
  76. data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
  77. data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
  78. data/lib/milk_tea/core/control_flow/termination.rb +31 -0
  79. data/lib/milk_tea/core/control_flow.rb +34 -0
  80. data/lib/milk_tea/core/cst.rb +48 -0
  81. data/lib/milk_tea/core/cst_builder.rb +19 -0
  82. data/lib/milk_tea/core/ir.rb +85 -0
  83. data/lib/milk_tea/core/keywords.rb +97 -0
  84. data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
  85. data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
  86. data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
  87. data/lib/milk_tea/core/lexer/indentation.rb +62 -0
  88. data/lib/milk_tea/core/lexer/numbers.rb +96 -0
  89. data/lib/milk_tea/core/lexer/recovery.rb +32 -0
  90. data/lib/milk_tea/core/lexer/strings.rb +167 -0
  91. data/lib/milk_tea/core/lexer/symbols.rb +71 -0
  92. data/lib/milk_tea/core/lexer/trivia.rb +53 -0
  93. data/lib/milk_tea/core/lexer.rb +430 -0
  94. data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
  95. data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
  96. data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
  97. data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
  98. data/lib/milk_tea/core/lowering/async.rb +714 -0
  99. data/lib/milk_tea/core/lowering/block.rb +1052 -0
  100. data/lib/milk_tea/core/lowering/calls.rb +1565 -0
  101. data/lib/milk_tea/core/lowering/declarations.rb +214 -0
  102. data/lib/milk_tea/core/lowering/dyn.rb +206 -0
  103. data/lib/milk_tea/core/lowering/events.rb +1054 -0
  104. data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
  105. data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
  106. data/lib/milk_tea/core/lowering/functions.rb +242 -0
  107. data/lib/milk_tea/core/lowering/loops.rb +1087 -0
  108. data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
  109. data/lib/milk_tea/core/lowering/proc.rb +419 -0
  110. data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
  111. data/lib/milk_tea/core/lowering/scans.rb +220 -0
  112. data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
  113. data/lib/milk_tea/core/lowering/utils.rb +1453 -0
  114. data/lib/milk_tea/core/lowering.rb +378 -0
  115. data/lib/milk_tea/core/module_binder.rb +181 -0
  116. data/lib/milk_tea/core/module_loader/errors.rb +21 -0
  117. data/lib/milk_tea/core/module_loader.rb +479 -0
  118. data/lib/milk_tea/core/module_path_resolver.rb +153 -0
  119. data/lib/milk_tea/core/module_roots.rb +88 -0
  120. data/lib/milk_tea/core/parser/attributes.rb +71 -0
  121. data/lib/milk_tea/core/parser/blocks.rb +119 -0
  122. data/lib/milk_tea/core/parser/declarations.rb +749 -0
  123. data/lib/milk_tea/core/parser/expressions.rb +624 -0
  124. data/lib/milk_tea/core/parser/recovery.rb +131 -0
  125. data/lib/milk_tea/core/parser/statements.rb +756 -0
  126. data/lib/milk_tea/core/parser/types.rb +271 -0
  127. data/lib/milk_tea/core/parser.rb +400 -0
  128. data/lib/milk_tea/core/prelude_installer.rb +29 -0
  129. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
  130. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
  131. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
  132. data/lib/milk_tea/core/pretty_printer.rb +17 -0
  133. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
  134. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
  135. data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
  136. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
  137. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
  138. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
  139. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
  140. data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
  141. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
  142. data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
  143. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
  144. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
  145. data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
  146. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
  147. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
  148. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
  149. data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
  150. data/lib/milk_tea/core/token.rb +26 -0
  151. data/lib/milk_tea/core/token_stream.rb +30 -0
  152. data/lib/milk_tea/core/types/layout.rb +243 -0
  153. data/lib/milk_tea/core/types/predicates.rb +609 -0
  154. data/lib/milk_tea/core/types/registry.rb +83 -0
  155. data/lib/milk_tea/core/types/types.rb +1696 -0
  156. data/lib/milk_tea/core/types/visitor.rb +442 -0
  157. data/lib/milk_tea/core.rb +25 -0
  158. data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
  159. data/lib/milk_tea/dap/protocol.rb +58 -0
  160. data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
  161. data/lib/milk_tea/dap/server/debug_map.rb +291 -0
  162. data/lib/milk_tea/dap/server/handlers.rb +374 -0
  163. data/lib/milk_tea/dap/server/launch.rb +261 -0
  164. data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
  165. data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
  166. data/lib/milk_tea/dap/server/utilities.rb +160 -0
  167. data/lib/milk_tea/dap/server/wire.rb +55 -0
  168. data/lib/milk_tea/dap/server.rb +131 -0
  169. data/lib/milk_tea/dap/session.rb +152 -0
  170. data/lib/milk_tea/dap.rb +6 -0
  171. data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
  172. data/lib/milk_tea/lsp/diagnostics.rb +611 -0
  173. data/lib/milk_tea/lsp/protocol.rb +104 -0
  174. data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
  175. data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
  176. data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
  177. data/lib/milk_tea/lsp/server/completion.rb +1099 -0
  178. data/lib/milk_tea/lsp/server/configuration.rb +167 -0
  179. data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
  180. data/lib/milk_tea/lsp/server/definition.rb +779 -0
  181. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
  182. data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
  183. data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
  184. data/lib/milk_tea/lsp/server/formatting.rb +575 -0
  185. data/lib/milk_tea/lsp/server/hover.rb +1465 -0
  186. data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
  187. data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
  188. data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
  189. data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
  190. data/lib/milk_tea/lsp/server/progress.rb +47 -0
  191. data/lib/milk_tea/lsp/server/references.rb +433 -0
  192. data/lib/milk_tea/lsp/server/rename.rb +598 -0
  193. data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
  194. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
  195. data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
  196. data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
  197. data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
  198. data/lib/milk_tea/lsp/server/utilities.rb +520 -0
  199. data/lib/milk_tea/lsp/server.rb +415 -0
  200. data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
  201. data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
  202. data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
  203. data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
  204. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
  205. data/lib/milk_tea/lsp/workspace/store.rb +154 -0
  206. data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
  207. data/lib/milk_tea/lsp/workspace.rb +127 -0
  208. data/lib/milk_tea/lsp.rb +13 -0
  209. data/lib/milk_tea/packages/atomic_write.rb +63 -0
  210. data/lib/milk_tea/packages/dependency_solver.rb +194 -0
  211. data/lib/milk_tea/packages/graph.rb +139 -0
  212. data/lib/milk_tea/packages/lock.rb +421 -0
  213. data/lib/milk_tea/packages/manager_cli.rb +485 -0
  214. data/lib/milk_tea/packages/manifest.rb +356 -0
  215. data/lib/milk_tea/packages/manifest_editor.rb +134 -0
  216. data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
  217. data/lib/milk_tea/packages/registry_store.rb +420 -0
  218. data/lib/milk_tea/packages/services.rb +41 -0
  219. data/lib/milk_tea/packages/source_cache.rb +71 -0
  220. data/lib/milk_tea/packages/source_fetcher.rb +124 -0
  221. data/lib/milk_tea/packages/source_resolver.rb +389 -0
  222. data/lib/milk_tea/packages/version.rb +164 -0
  223. data/lib/milk_tea/packages.rb +16 -0
  224. data/lib/milk_tea/tooling/asset_pack.rb +141 -0
  225. data/lib/milk_tea/tooling/build.rb +1124 -0
  226. data/lib/milk_tea/tooling/build_cache.rb +240 -0
  227. data/lib/milk_tea/tooling/cli.rb +2688 -0
  228. data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
  229. data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
  230. data/lib/milk_tea/tooling/debug_map.rb +248 -0
  231. data/lib/milk_tea/tooling/docs_app.rb +369 -0
  232. data/lib/milk_tea/tooling/error_formatter.rb +86 -0
  233. data/lib/milk_tea/tooling/formatter.rb +787 -0
  234. data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
  235. data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
  236. data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
  237. data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
  238. data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
  239. data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
  240. data/lib/milk_tea/tooling/linter/rules.rb +593 -0
  241. data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
  242. data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
  243. data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
  244. data/lib/milk_tea/tooling/linter.rb +798 -0
  245. data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
  246. data/lib/milk_tea/tooling/public/css/docs.css +166 -0
  247. data/lib/milk_tea/tooling/public/js/docs.js +94 -0
  248. data/lib/milk_tea/tooling/run.rb +408 -0
  249. data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
  250. data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
  251. data/lib/milk_tea/tooling/views/404.erb +7 -0
  252. data/lib/milk_tea/tooling/views/index.erb +87 -0
  253. data/lib/milk_tea/tooling/views/layout.erb +69 -0
  254. data/lib/milk_tea/tooling/views/module.erb +97 -0
  255. data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
  256. data/lib/milk_tea/tooling.rb +20 -0
  257. data/lib/milk_tea.rb +8 -0
  258. metadata +426 -0
@@ -0,0 +1,1696 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fiddle"
4
+ require_relative "registry"
5
+ require_relative "visitor"
6
+
7
+ module MilkTea
8
+ module Types
9
+ BUILTIN_PRIMITIVE_NAMES = MilkTea::BUILTIN_PRIMITIVE_NAMES
10
+ RESERVED_VALUE_TYPE_NAMES = MilkTea::RESERVED_VALUE_TYPE_NAMES
11
+ RESERVED_IMPORT_ALIAS_NAMES = MilkTea::RESERVED_IMPORT_ALIAS_NAMES
12
+ BUILTIN_TYPE_NAMES = MilkTea::BUILTIN_TYPE_NAMES
13
+ RESERVED_TYPE_BINDING_NAMES = BUILTIN_TYPE_NAMES
14
+
15
+ def self.substitute_type_variables(type, substitutions)
16
+ SubstituteTypeVisitor.new(substitutions).apply(type)
17
+ end
18
+
19
+ class Base
20
+ def bitwise?
21
+ false
22
+ end
23
+
24
+ def numeric?
25
+ false
26
+ end
27
+
28
+ def integer?
29
+ false
30
+ end
31
+
32
+ def float?
33
+ false
34
+ end
35
+
36
+ def boolean?
37
+ false
38
+ end
39
+
40
+ def void?
41
+ false
42
+ end
43
+
44
+ def sendable?
45
+ SendableCheckVisitor.new.tap { |v| v.visit(self) }.sendable?
46
+ end
47
+
48
+ def field_c_name(name)
49
+ name
50
+ end
51
+
52
+ def children
53
+ []
54
+ end
55
+
56
+ def accept(visitor)
57
+ visitor.visit(self)
58
+ end
59
+ end
60
+
61
+ class ReflectionHandleType < Base
62
+ attr_reader :name
63
+
64
+ def initialize(name)
65
+ @name = name
66
+ @hash = [self.class, name].hash
67
+ freeze
68
+ end
69
+
70
+ def eql?(other)
71
+ other.is_a?(ReflectionHandleType) && other.name == name
72
+ end
73
+
74
+ alias == eql?
75
+
76
+ attr_reader :hash
77
+
78
+
79
+ def to_s
80
+ name
81
+ end
82
+ end
83
+
84
+ BUILTIN_STRUCT_HANDLE_TYPE = ReflectionHandleType.new("struct_handle")
85
+ BUILTIN_FIELD_HANDLE_TYPE = ReflectionHandleType.new("field_handle")
86
+ BUILTIN_CALLABLE_HANDLE_TYPE = ReflectionHandleType.new("callable_handle")
87
+ BUILTIN_ATTRIBUTE_HANDLE_TYPE = ReflectionHandleType.new("attribute_handle")
88
+ BUILTIN_MEMBER_HANDLE_TYPE = ReflectionHandleType.new("member_handle")
89
+
90
+ class TypeType < Base
91
+ def initialize
92
+ freeze
93
+ end
94
+
95
+ def eql?(other)
96
+ other.is_a?(TypeType)
97
+ end
98
+
99
+ alias == eql?
100
+
101
+ def hash
102
+ self.class.hash
103
+ end
104
+
105
+
106
+ def to_s
107
+ "type"
108
+ end
109
+ end
110
+
111
+ BUILTIN_TYPE_META_TYPE = TypeType.new
112
+
113
+ class Primitive < Base
114
+ POINTER_INTEGER_WIDTH = Fiddle::SIZEOF_VOIDP * 8
115
+
116
+ INTEGER_NAMES = %w[byte short int long ubyte ushort uint ulong ptr_int ptr_uint].freeze
117
+ FLOAT_NAMES = %w[float double].freeze
118
+ FIXED_SIGNED_INTEGER_WIDTHS = {
119
+ "byte" => 8,
120
+ "short" => 16,
121
+ "int" => 32,
122
+ "long" => 64,
123
+ }.freeze
124
+ FIXED_UNSIGNED_INTEGER_WIDTHS = {
125
+ "ubyte" => 8,
126
+ "ushort" => 16,
127
+ "uint" => 32,
128
+ "ulong" => 64,
129
+ }.freeze
130
+ FLOAT_WIDTHS = {
131
+ "float" => 32,
132
+ "double" => 64,
133
+ }.freeze
134
+
135
+ attr_reader :name
136
+
137
+ def initialize(name)
138
+ @name = name
139
+ @hash = [self.class, name].hash
140
+
141
+ # Precompute classification flags: `name` is immutable and these
142
+ # predicates are called constantly during type checking, so resolve
143
+ # them once instead of rescanning arrays/hashes on every call.
144
+ @integer = INTEGER_NAMES.include?(name)
145
+ @float = FLOAT_NAMES.include?(name)
146
+ @numeric = @integer || @float
147
+ @pointer_sized_integer = name == "ptr_int" || name == "ptr_uint"
148
+ @signed_integer = FIXED_SIGNED_INTEGER_WIDTHS.key?(name) || name == "ptr_int"
149
+ @unsigned_integer = FIXED_UNSIGNED_INTEGER_WIDTHS.key?(name) || name == "ptr_uint"
150
+ @fixed_width_integer = FIXED_SIGNED_INTEGER_WIDTHS.key?(name) || FIXED_UNSIGNED_INTEGER_WIDTHS.key?(name) || @pointer_sized_integer
151
+ @integer_width = FIXED_SIGNED_INTEGER_WIDTHS[name] || FIXED_UNSIGNED_INTEGER_WIDTHS[name] || (@pointer_sized_integer ? POINTER_INTEGER_WIDTH : nil)
152
+ @float_width = FLOAT_WIDTHS[name]
153
+ @boolean = name == "bool"
154
+ @void = name == "void"
155
+
156
+ freeze
157
+ end
158
+
159
+ def eql?(other)
160
+ other.is_a?(Primitive) && other.name == name
161
+ end
162
+
163
+ alias == eql?
164
+
165
+ attr_reader :hash, :integer_width, :float_width
166
+
167
+ def numeric?
168
+ @numeric
169
+ end
170
+
171
+ def bitwise?
172
+ @integer
173
+ end
174
+
175
+ def integer?
176
+ @integer
177
+ end
178
+
179
+ def float?
180
+ @float
181
+ end
182
+
183
+ def signed_integer?
184
+ @signed_integer
185
+ end
186
+
187
+ def unsigned_integer?
188
+ @unsigned_integer
189
+ end
190
+
191
+ def fixed_width_integer?
192
+ @fixed_width_integer
193
+ end
194
+
195
+ def boolean?
196
+ @boolean
197
+ end
198
+
199
+ def void?
200
+ @void
201
+ end
202
+
203
+ def to_s
204
+ name
205
+ end
206
+ end
207
+
208
+ class Null < Base
209
+ attr_reader :target_type
210
+
211
+ def initialize(target_type = nil)
212
+ @target_type = target_type
213
+ @hash = [self.class, target_type].hash
214
+ freeze
215
+ end
216
+
217
+ def eql?(other)
218
+ other.is_a?(Null) && other.target_type == target_type
219
+ end
220
+
221
+ alias == eql?
222
+
223
+ attr_reader :hash
224
+
225
+
226
+ def to_s
227
+ target_type ? "null[#{target_type}]" : "null"
228
+ end
229
+
230
+ def children
231
+ [target_type].compact
232
+ end
233
+ end
234
+
235
+ class Error < Base
236
+ def eql?(other)
237
+ other.is_a?(Error)
238
+ end
239
+
240
+ alias == eql?
241
+
242
+ def hash
243
+ self.class.hash
244
+ end
245
+
246
+ def to_s
247
+ "<error>"
248
+ end
249
+ end
250
+
251
+ class StructHandle < Base
252
+ attr_reader :struct_type, :declaration
253
+
254
+ def initialize(struct_type, declaration)
255
+ @struct_type = struct_type
256
+ @declaration = declaration
257
+ @hash = [self.class, struct_type].hash
258
+ freeze
259
+ end
260
+
261
+ def eql?(other)
262
+ other.is_a?(StructHandle) && other.struct_type == struct_type
263
+ end
264
+
265
+ alias == eql?
266
+
267
+ attr_reader :hash
268
+
269
+
270
+ def to_s
271
+ "field target #{struct_type}"
272
+ end
273
+ end
274
+
275
+ class FieldHandle < Base
276
+ attr_reader :struct_handle, :field_name, :field_declaration
277
+
278
+ def initialize(struct_handle, field_name, field_declaration)
279
+ @struct_handle = struct_handle
280
+ @field_name = field_name
281
+ @field_declaration = field_declaration
282
+ @hash = [self.class, struct_handle, field_name].hash
283
+ freeze
284
+ end
285
+
286
+ def eql?(other)
287
+ other.is_a?(FieldHandle) && other.struct_handle == struct_handle && other.field_name == field_name
288
+ end
289
+
290
+ alias == eql?
291
+
292
+ attr_reader :hash
293
+
294
+
295
+ def to_s
296
+ "field_of(#{struct_handle.struct_type}, #{field_name})"
297
+ end
298
+ end
299
+
300
+ class CallableHandle < Base
301
+ attr_reader :display_name, :declaration
302
+
303
+ def initialize(display_name, declaration)
304
+ @display_name = display_name
305
+ @declaration = declaration
306
+ @hash = [self.class, display_name].hash
307
+ freeze
308
+ end
309
+
310
+ def eql?(other)
311
+ other.is_a?(CallableHandle) && other.display_name == display_name
312
+ end
313
+
314
+ alias == eql?
315
+
316
+ attr_reader :hash
317
+
318
+
319
+ def to_s
320
+ "callable_of(#{display_name})"
321
+ end
322
+ end
323
+
324
+ class AttributeHandle < Base
325
+ attr_reader :attribute_name, :attribute_module_name, :target, :params, :argument_values
326
+
327
+ def initialize(attribute_name, attribute_module_name, target, params, argument_values)
328
+ @attribute_name = attribute_name
329
+ @attribute_module_name = attribute_module_name
330
+ @target = target
331
+ @params = params.freeze
332
+ @argument_values = argument_values&.freeze
333
+ @hash = [self.class, attribute_module_name, attribute_name, target].hash
334
+ freeze
335
+ end
336
+
337
+ def eql?(other)
338
+ other.is_a?(AttributeHandle) &&
339
+ other.attribute_name == attribute_name &&
340
+ other.attribute_module_name == attribute_module_name &&
341
+ other.target == target
342
+ end
343
+
344
+ alias == eql?
345
+
346
+ attr_reader :hash
347
+
348
+
349
+ def to_s
350
+ qualifier = attribute_module_name ? "#{attribute_module_name}." : ""
351
+ "attribute_of(#{target}, #{qualifier}#{attribute_name})"
352
+ end
353
+ end
354
+
355
+ class MemberHandle < Base
356
+ attr_reader :enum_handle, :member_name, :member_value
357
+
358
+ def initialize(enum_handle, member_name, member_value)
359
+ @enum_handle = enum_handle
360
+ @member_name = member_name
361
+ @member_value = member_value
362
+ @hash = [self.class, enum_handle, member_name].hash
363
+ freeze
364
+ end
365
+
366
+ def name
367
+ member_name
368
+ end
369
+
370
+ def value
371
+ member_value
372
+ end
373
+
374
+ def eql?(other)
375
+ other.is_a?(MemberHandle) && other.member_name == member_name && other.enum_handle == enum_handle
376
+ end
377
+
378
+ alias == eql?
379
+
380
+ attr_reader :hash
381
+
382
+
383
+ def to_s
384
+ "member_of(#{enum_handle}, #{member_name})"
385
+ end
386
+ end
387
+
388
+ class Nullable < Base
389
+ attr_reader :base
390
+
391
+ def initialize(base)
392
+ @base = base
393
+ @hash = [self.class, base].hash
394
+ freeze
395
+ end
396
+
397
+ def eql?(other)
398
+ other.is_a?(Nullable) && other.base == base
399
+ end
400
+
401
+ alias == eql?
402
+
403
+ attr_reader :hash
404
+
405
+ def to_s
406
+ "#{base}?"
407
+ end
408
+
409
+ def children
410
+ [base]
411
+ end
412
+ end
413
+
414
+ class LiteralTypeArg
415
+ attr_reader :value
416
+
417
+ def initialize(value)
418
+ @value = value
419
+ @hash = [self.class, value].hash
420
+ freeze
421
+ end
422
+
423
+ def eql?(other)
424
+ other.is_a?(LiteralTypeArg) && other.value == value
425
+ end
426
+
427
+ alias == eql?
428
+
429
+ attr_reader :hash
430
+
431
+ def to_s
432
+ value.to_s
433
+ end
434
+ end
435
+
436
+ class GenericInstance < Base
437
+ attr_reader :name, :arguments
438
+
439
+ def initialize(name, arguments)
440
+ @name = name
441
+ @arguments = arguments.freeze
442
+ @hash = [self.class, name, @arguments].hash
443
+ freeze
444
+ end
445
+
446
+ def eql?(other)
447
+ other.is_a?(GenericInstance) && other.name == name && other.arguments == arguments
448
+ end
449
+
450
+ alias == eql?
451
+
452
+ attr_reader :hash
453
+
454
+ def to_s
455
+ "#{name}[#{arguments.join(', ')}]"
456
+ end
457
+
458
+ def children
459
+ arguments.reject { |a| a.is_a?(Types::LiteralTypeArg) }
460
+ end
461
+ end
462
+
463
+ class TypeVar < Base
464
+ attr_reader :name
465
+
466
+ def initialize(name)
467
+ @name = name
468
+ freeze
469
+ end
470
+
471
+ def eql?(other)
472
+ other.is_a?(TypeVar) && other.name == name
473
+ end
474
+
475
+ alias == eql?
476
+
477
+ def hash
478
+
479
+ @name.hash
480
+ end
481
+
482
+
483
+ def to_s
484
+ name
485
+ end
486
+ end
487
+
488
+ class LifetimeRef < Base
489
+ attr_reader :name
490
+
491
+ def initialize(name)
492
+ @name = name
493
+ freeze
494
+ end
495
+
496
+ def eql?(other)
497
+ other.is_a?(LifetimeRef) && other.name == name
498
+ end
499
+
500
+ alias == eql?
501
+
502
+ def hash
503
+ @name.hash
504
+ end
505
+
506
+
507
+ def to_s
508
+ name
509
+ end
510
+ end
511
+
512
+ class Span < Base
513
+ attr_reader :element_type
514
+
515
+ def initialize(element_type)
516
+ @element_type = element_type
517
+ @fields = {
518
+ "data" => GenericInstance.new("ptr", [element_type]),
519
+ "len" => Primitive.new("ptr_uint"),
520
+ }.freeze
521
+ @hash = [self.class, element_type].hash
522
+ freeze
523
+ end
524
+
525
+ def eql?(other)
526
+ other.is_a?(Span) && other.element_type == element_type
527
+ end
528
+
529
+ alias == eql?
530
+
531
+ attr_reader :hash
532
+
533
+ def name
534
+ to_s
535
+ end
536
+
537
+ def fields
538
+ @fields
539
+ end
540
+
541
+ def field(name)
542
+ @fields[name]
543
+ end
544
+
545
+ def to_s
546
+ "span[#{element_type}]"
547
+ end
548
+
549
+ def children
550
+ [element_type]
551
+ end
552
+ end
553
+
554
+ class StringView < Base
555
+ attr_reader :name, :module_name
556
+
557
+ def initialize
558
+ @name = "str"
559
+ @module_name = nil
560
+ @fields = {
561
+ "data" => GenericInstance.new("ptr", [Primitive.new("char")]),
562
+ "len" => Primitive.new("ptr_uint"),
563
+ }.freeze
564
+ freeze
565
+ end
566
+
567
+ def eql?(other)
568
+ other.is_a?(StringView)
569
+ end
570
+
571
+ alias == eql?
572
+
573
+ def hash
574
+ self.class.hash
575
+ end
576
+
577
+ def fields
578
+ @fields
579
+ end
580
+
581
+ def field(name)
582
+ @fields[name]
583
+ end
584
+
585
+ def to_s
586
+ "str"
587
+ end
588
+ end
589
+
590
+ class Task < Base
591
+ attr_reader :result_type
592
+
593
+ def initialize(result_type)
594
+ @result_type = result_type
595
+ void_ptr = GenericInstance.new("ptr", [Primitive.new("void")])
596
+ wake_fn = Function.new(
597
+ nil,
598
+ params: [Parameter.new("frame", void_ptr)],
599
+ return_type: Primitive.new("void"),
600
+ )
601
+ @fields = {
602
+ "frame" => void_ptr,
603
+ "ready" => Function.new(
604
+ nil,
605
+ params: [Parameter.new("frame", void_ptr)],
606
+ return_type: Primitive.new("bool"),
607
+ ),
608
+ "set_waiter" => Function.new(
609
+ nil,
610
+ params: [
611
+ Parameter.new("frame", void_ptr),
612
+ Parameter.new("waiter_frame", void_ptr),
613
+ Parameter.new("waiter", wake_fn),
614
+ ],
615
+ return_type: Primitive.new("void"),
616
+ ),
617
+ "release" => Function.new(
618
+ nil,
619
+ params: [Parameter.new("frame", void_ptr)],
620
+ return_type: Primitive.new("void"),
621
+ ),
622
+ "take_result" => Function.new(
623
+ nil,
624
+ params: [Parameter.new("frame", void_ptr)],
625
+ return_type: result_type,
626
+ ),
627
+ "cancel" => Function.new(
628
+ nil,
629
+ params: [Parameter.new("frame", void_ptr)],
630
+ return_type: Primitive.new("void"),
631
+ ),
632
+ }.freeze
633
+ @hash = [self.class, result_type].hash
634
+ freeze
635
+ end
636
+
637
+ def eql?(other)
638
+ other.is_a?(Task) && other.result_type == result_type
639
+ end
640
+
641
+ alias == eql?
642
+
643
+ attr_reader :hash
644
+
645
+ def name
646
+ to_s
647
+ end
648
+
649
+ def fields
650
+ @fields
651
+ end
652
+
653
+ def field(name)
654
+ @fields[name]
655
+ end
656
+
657
+ def to_s
658
+ "Task[#{result_type}]"
659
+ end
660
+
661
+ def children
662
+ [result_type]
663
+ end
664
+ end
665
+
666
+ class Subscription < Base
667
+ def field(name)
668
+ {
669
+ "slot" => Primitive.new("ptr_uint"),
670
+ "generation" => Primitive.new("ptr_uint"),
671
+ }.fetch(name)
672
+ end
673
+
674
+ def fields
675
+ {
676
+ "slot" => Primitive.new("ptr_uint"),
677
+ "generation" => Primitive.new("ptr_uint"),
678
+ }.freeze
679
+ end
680
+
681
+ def name
682
+ "Subscription"
683
+ end
684
+
685
+ def module_name
686
+ nil
687
+ end
688
+
689
+ def linkage_name
690
+ "mt_subscription"
691
+ end
692
+
693
+ def eql?(other)
694
+ other.is_a?(Subscription)
695
+ end
696
+
697
+ alias == eql?
698
+
699
+ def hash
700
+ self.class.hash
701
+ end
702
+
703
+
704
+ def to_s
705
+ "Subscription"
706
+ end
707
+ end
708
+
709
+ class Handle < Base
710
+ def name
711
+ "Handle"
712
+ end
713
+
714
+ def module_name
715
+ nil
716
+ end
717
+
718
+ def linkage_name
719
+ "void*"
720
+ end
721
+
722
+ def eql?(other)
723
+ other.is_a?(Handle)
724
+ end
725
+
726
+ alias == eql?
727
+
728
+ def hash
729
+ self.class.hash
730
+ end
731
+
732
+
733
+ def to_s
734
+ "Handle"
735
+ end
736
+ end
737
+
738
+ class Event < Base
739
+ attr_reader :name, :capacity, :payload_type, :module_name, :visibility, :owner_type_name, :linkage_name
740
+
741
+ def initialize(name, capacity:, payload_type: nil, module_name: nil, visibility: :private, owner_type_name: nil)
742
+ @name = name
743
+ @capacity = capacity
744
+ @payload_type = payload_type
745
+ @module_name = module_name
746
+ @visibility = visibility
747
+ @owner_type_name = owner_type_name
748
+ @linkage_name = begin
749
+ parts = ["mt_event"]
750
+ parts << module_name&.gsub(/[^A-Za-z0-9_]+/, "_")
751
+ parts << owner_type_name&.gsub(/[^A-Za-z0-9_]+/, "_")
752
+ parts << name.gsub(/[^A-Za-z0-9_]+/, "_")
753
+ parts << payload_type.to_s.gsub(/[^A-Za-z0-9_]+/, "_") if payload_type
754
+ parts << capacity.to_s
755
+ parts.compact.reject(&:empty?).join("_")
756
+ end
757
+ @hash = [self.class, name, capacity, payload_type, module_name, visibility, owner_type_name].hash
758
+ freeze
759
+ end
760
+
761
+ def eql?(other)
762
+ other.is_a?(Event) &&
763
+ other.name == name &&
764
+ other.capacity == capacity &&
765
+ other.payload_type == payload_type &&
766
+ other.module_name == module_name &&
767
+ other.visibility == visibility &&
768
+ other.owner_type_name == owner_type_name
769
+ end
770
+
771
+ alias == eql?
772
+
773
+ attr_reader :hash
774
+
775
+ def hidden_field_name
776
+ "__event_#{name}"
777
+ end
778
+
779
+ def to_s
780
+ label = owner_type_name ? "#{owner_type_name}.#{name}" : name
781
+ payload = payload_type ? "(#{payload_type})" : ""
782
+ "event #{label}[#{capacity}]#{payload}"
783
+ end
784
+
785
+ def children
786
+ [payload_type].compact
787
+ end
788
+ end
789
+
790
+ class GenericStructDefinition < Base
791
+ attr_reader :name, :type_params, :type_param_constraints, :module_name, :external, :packed, :alignment, :linkage_name, :lifetime_params
792
+ attr_accessor :ast_declaration
793
+
794
+ def initialize(name, type_params, module_name: nil, external: false, packed: false, alignment: nil, linkage_name: nil, lifetime_params: [])
795
+ @name = name
796
+ @type_params = type_params.freeze
797
+ @type_param_constraints = {}.freeze
798
+ @module_name = module_name
799
+ @external = external
800
+ @packed = packed
801
+ @alignment = alignment
802
+ @linkage_name = linkage_name
803
+ @lifetime_params = lifetime_params.freeze
804
+ @fields = {}
805
+ @events = {}
806
+ @instances = {}
807
+ @ast_declaration = nil
808
+ end
809
+
810
+ def define_fields(fields)
811
+ @fields = fields.freeze
812
+ self
813
+ end
814
+
815
+ def define_events(events)
816
+ @events = events.freeze
817
+ self
818
+ end
819
+
820
+ def define_type_param_constraints(type_param_constraints)
821
+ @type_param_constraints = type_param_constraints.freeze
822
+ self
823
+ end
824
+
825
+ def set_layout(packed:, alignment:)
826
+ @packed = packed
827
+ @alignment = alignment
828
+ @instances.each_value { |instance| instance.set_layout(packed:, alignment:) }
829
+ self
830
+ end
831
+
832
+ def fields
833
+ @fields
834
+ end
835
+
836
+ def field(name)
837
+ @fields[name]
838
+ end
839
+
840
+ def events
841
+ @events
842
+ end
843
+
844
+ def event(name)
845
+ @events[name]
846
+ end
847
+
848
+ def has_events?
849
+ !@events.empty?
850
+ end
851
+
852
+ def field_c_name(name)
853
+ stripped = name.delete_suffix("_")
854
+ return stripped if stripped != name && MilkTea::KEYWORDS.key?(stripped)
855
+
856
+ name
857
+ end
858
+
859
+ def eql?(other)
860
+ other.class == self.class &&
861
+ other.name == name &&
862
+ other.type_params == type_params &&
863
+ other.module_name == module_name &&
864
+ other.external == external &&
865
+ other.packed == packed &&
866
+ other.alignment == alignment &&
867
+ other.linkage_name == linkage_name
868
+ end
869
+
870
+ alias == eql?
871
+
872
+ def hash
873
+ [self.class, name, type_params, module_name, external, packed, alignment, linkage_name].hash
874
+ end
875
+
876
+ def instantiate(arguments)
877
+ raise ArgumentError, "#{name} expects #{type_params.length} type arguments, got #{arguments.length}" unless arguments.length == type_params.length
878
+
879
+ key = arguments.dup.freeze
880
+ return @instances[key] if @instances.key?(key)
881
+
882
+ substitutions = type_params.zip(arguments).to_h
883
+ lifetime_params.each do |lt|
884
+ substitutions[lt] = arguments.find { |a| a.is_a?(LifetimeRef) && a.name == lt } || LifetimeRef.new(lt)
885
+ end
886
+ instance = StructInstance.new(self, arguments)
887
+ @instances[key] = instance
888
+ instance.define_fields(
889
+ @fields.transform_values { |type| Types.substitute_type_variables(type, substitutions) },
890
+ ).define_events(
891
+ @events.transform_values { |type| Types.substitute_type_variables(type, substitutions) },
892
+ )
893
+ end
894
+
895
+ def to_s
896
+ module_name ? "#{module_name}.#{name}" : name
897
+ end
898
+
899
+ def children
900
+ fields.values
901
+ end
902
+ end
903
+
904
+ class Struct < Base
905
+ attr_reader :name, :module_name, :external, :packed, :alignment, :linkage_name, :lifetime_params, :nested_types
906
+ attr_accessor :ast_declaration
907
+
908
+ def initialize(name, module_name: nil, external: false, packed: false, alignment: nil, linkage_name: nil, lifetime_params: [])
909
+ @name = name
910
+ @module_name = module_name
911
+ @external = external
912
+ @packed = packed
913
+ @alignment = alignment
914
+ @linkage_name = linkage_name
915
+ @lifetime_params = lifetime_params.freeze
916
+ @fields = {}
917
+ @events = {}
918
+ @nested_types = {}
919
+ @ast_declaration = nil
920
+ end
921
+
922
+ def define_fields(fields)
923
+ @fields = fields.freeze
924
+ self
925
+ end
926
+
927
+ def define_events(events)
928
+ @events = events.freeze
929
+ self
930
+ end
931
+
932
+ def define_nested_types(nested)
933
+ @nested_types = nested.freeze
934
+ self
935
+ end
936
+
937
+ def set_layout(packed:, alignment:)
938
+ @packed = packed
939
+ @alignment = alignment
940
+ self
941
+ end
942
+
943
+ def fields
944
+ @fields
945
+ end
946
+
947
+ def field(name)
948
+ @fields[name]
949
+ end
950
+
951
+ def events
952
+ @events
953
+ end
954
+
955
+ def event(name)
956
+ @events[name]
957
+ end
958
+
959
+ def has_events?
960
+ !@events.empty?
961
+ end
962
+
963
+ def field_c_name(name)
964
+ stripped = name.delete_suffix("_")
965
+ return stripped if stripped != name && MilkTea::KEYWORDS.key?(stripped)
966
+
967
+ name
968
+ end
969
+
970
+ def eql?(other)
971
+ other.class == self.class &&
972
+ other.name == name &&
973
+ other.module_name == module_name &&
974
+ other.external == external &&
975
+ other.packed == packed &&
976
+ other.alignment == alignment &&
977
+ other.linkage_name == linkage_name
978
+ end
979
+
980
+ alias == eql?
981
+
982
+ def hash
983
+ [self.class, name, module_name, external, packed, alignment, linkage_name].hash
984
+ end
985
+
986
+ def to_s
987
+ module_name ? "#{module_name}.#{name}" : name
988
+ end
989
+
990
+ def children
991
+ fields.values
992
+ end
993
+ end
994
+
995
+ class StructInstance < Struct
996
+ attr_reader :definition, :arguments
997
+
998
+ def initialize(definition, arguments)
999
+ super(
1000
+ definition.name,
1001
+ module_name: definition.module_name,
1002
+ external: definition.external,
1003
+ packed: definition.packed,
1004
+ alignment: definition.alignment,
1005
+ linkage_name: definition.linkage_name,
1006
+ lifetime_params: definition.lifetime_params,
1007
+ )
1008
+ @definition = definition
1009
+ @arguments = arguments.freeze
1010
+ @nested_types = definition.respond_to?(:nested_types) ? definition.nested_types.dup : {}
1011
+ end
1012
+
1013
+ def eql?(other)
1014
+ other.is_a?(StructInstance) && other.definition == definition && other.arguments == arguments
1015
+ end
1016
+
1017
+ alias == eql?
1018
+
1019
+ def hash
1020
+ [self.class, definition, arguments].hash
1021
+ end
1022
+
1023
+ def to_s
1024
+ base = module_name ? "#{module_name}.#{name}" : name
1025
+ "#{base}[#{arguments.join(', ')}]"
1026
+ end
1027
+
1028
+ def children
1029
+ fields.values
1030
+ end
1031
+ end
1032
+
1033
+ class Union < Struct
1034
+ end
1035
+
1036
+ # A user-defined tagged union (discriminated union). Each arm may carry zero
1037
+ # or more named payload fields. Arms with no fields carry only the discriminant.
1038
+ class Variant < Base
1039
+ attr_reader :name, :module_name
1040
+
1041
+ def initialize(name, module_name: nil)
1042
+ @name = name
1043
+ @module_name = module_name
1044
+ @arms = {} # arm_name => { field_name => type }
1045
+ @arm_names = []
1046
+ @hash = [self.class, name, module_name].hash
1047
+ end
1048
+
1049
+ def define_arms(arms_hash)
1050
+ @arms = arms_hash.freeze
1051
+ @arm_names = arms_hash.keys.freeze
1052
+ self
1053
+ end
1054
+
1055
+ def arm(name)
1056
+ @arms[name]
1057
+ end
1058
+
1059
+ def arm_names
1060
+ @arm_names
1061
+ end
1062
+
1063
+ def has_payload?(arm_name)
1064
+ fields = @arms[arm_name]
1065
+ fields && !fields.empty?
1066
+ end
1067
+
1068
+ def eql?(other)
1069
+ other.class == self.class && other.name == name && other.module_name == module_name
1070
+ end
1071
+
1072
+ alias == eql?
1073
+
1074
+ attr_reader :hash
1075
+
1076
+ def to_s
1077
+ module_name ? "#{module_name}.#{name}" : name
1078
+ end
1079
+
1080
+ def children
1081
+ arm_names.flat_map { |a| arm(a).values }
1082
+ end
1083
+ end
1084
+
1085
+ class GenericVariantDefinition < Base
1086
+ attr_reader :name, :type_params, :type_param_constraints, :module_name
1087
+
1088
+ def initialize(name, type_params, module_name: nil)
1089
+ @name = name
1090
+ @type_params = type_params.freeze
1091
+ @type_param_constraints = {}.freeze
1092
+ @module_name = module_name
1093
+ @arms = {}
1094
+ @instances = {}
1095
+ @hash = [self.class, name, @type_params, module_name].hash
1096
+ end
1097
+
1098
+ def define_arms(arms_hash)
1099
+ @arms = arms_hash.freeze
1100
+ self
1101
+ end
1102
+
1103
+ def arms
1104
+ @arms
1105
+ end
1106
+
1107
+ def define_type_param_constraints(type_param_constraints)
1108
+ @type_param_constraints = type_param_constraints.freeze
1109
+ self
1110
+ end
1111
+
1112
+ def eql?(other)
1113
+ other.class == self.class &&
1114
+ other.name == name &&
1115
+ other.type_params == type_params &&
1116
+ other.module_name == module_name
1117
+ end
1118
+
1119
+ alias == eql?
1120
+
1121
+ attr_reader :hash
1122
+
1123
+ def instantiate(arguments)
1124
+ raise ArgumentError, "#{name} expects #{type_params.length} type arguments, got #{arguments.length}" unless arguments.length == type_params.length
1125
+
1126
+ key = arguments.dup.freeze
1127
+ return @instances[key] if @instances.key?(key)
1128
+
1129
+ substitutions = type_params.zip(arguments).to_h
1130
+ instance = VariantInstance.new(self, arguments)
1131
+ @instances[key] = instance
1132
+ instance.define_arms(
1133
+ @arms.transform_values do |fields|
1134
+ fields.transform_values { |type| Types.substitute_type_variables(type, substitutions) }
1135
+ end,
1136
+ )
1137
+ end
1138
+
1139
+ def to_s
1140
+ module_name ? "#{module_name}.#{name}" : name
1141
+ end
1142
+
1143
+ def children
1144
+ arms.values.flat_map(&:values)
1145
+ end
1146
+ end
1147
+
1148
+ class VariantInstance < Variant
1149
+ attr_reader :definition, :arguments
1150
+
1151
+ def initialize(definition, arguments)
1152
+ super(definition.name, module_name: definition.module_name)
1153
+ @definition = definition
1154
+ @arguments = arguments.freeze
1155
+ @hash = [self.class, definition, @arguments].hash
1156
+ end
1157
+
1158
+ def eql?(other)
1159
+ other.is_a?(VariantInstance) && other.definition == definition && other.arguments == arguments
1160
+ end
1161
+
1162
+ alias == eql?
1163
+
1164
+ attr_reader :hash
1165
+
1166
+ def to_s
1167
+ base = module_name ? "#{module_name}.#{name}" : name
1168
+ "#{base}[#{arguments.join(', ')}]"
1169
+ end
1170
+
1171
+ def children
1172
+ arm_names.flat_map { |a| arm(a).values }
1173
+ end
1174
+ end
1175
+
1176
+ # Synthetic struct-like type used only as the binding type for `as name` in
1177
+ # variant match arms. Never declared as a named type; lives only in scopes.
1178
+ class VariantArmPayload < Struct
1179
+ attr_reader :variant_type, :arm_name
1180
+
1181
+ def initialize(variant_type, arm_name, fields)
1182
+ super("#{variant_type.name}_#{arm_name}", module_name: variant_type.module_name)
1183
+ @variant_type = variant_type
1184
+ @arm_name = arm_name
1185
+ define_fields(fields)
1186
+ end
1187
+
1188
+ def to_s
1189
+ "#{variant_type}.#{arm_name} payload"
1190
+ end
1191
+ end
1192
+
1193
+ class Opaque < Base
1194
+ attr_reader :name, :module_name, :external, :linkage_name
1195
+
1196
+ def initialize(name, module_name: nil, external: false, linkage_name: nil)
1197
+ @name = name
1198
+ @module_name = module_name
1199
+ @external = external
1200
+ @linkage_name = linkage_name
1201
+ @hash = [self.class, name, module_name, external, linkage_name].hash
1202
+ end
1203
+
1204
+ def eql?(other)
1205
+ other.class == self.class &&
1206
+ other.name == name &&
1207
+ other.module_name == module_name &&
1208
+ other.external == external &&
1209
+ other.linkage_name == linkage_name
1210
+ end
1211
+
1212
+ alias == eql?
1213
+
1214
+ attr_reader :hash
1215
+
1216
+ def to_s
1217
+ module_name ? "#{module_name}.#{name}" : name
1218
+ end
1219
+ end
1220
+
1221
+ class EnumBase < Base
1222
+ attr_reader :name, :module_name, :backing_type, :external
1223
+
1224
+ def initialize(name, module_name: nil, external: false)
1225
+ @name = name
1226
+ @module_name = module_name
1227
+ @external = external
1228
+ @backing_type = nil
1229
+ @members = {}
1230
+ @member_values = {}
1231
+ @hash = [self.class, name, module_name, external].hash
1232
+ end
1233
+
1234
+ def define_members(backing_type, member_names)
1235
+ @backing_type = backing_type
1236
+ @members = member_names.each_with_object({}) do |member_name, members|
1237
+ members[member_name] = self
1238
+ end.freeze
1239
+ @member_values = {}
1240
+ self
1241
+ end
1242
+
1243
+ def define_member_values(member_values)
1244
+ @member_values = member_values.freeze
1245
+ self
1246
+ end
1247
+
1248
+ def member(name)
1249
+ @members[name]
1250
+ end
1251
+
1252
+ def member_value(name)
1253
+ @member_values[name]
1254
+ end
1255
+
1256
+ def members
1257
+ @members.keys
1258
+ end
1259
+
1260
+
1261
+ def eql?(other)
1262
+ other.class == self.class &&
1263
+ other.name == name &&
1264
+ other.module_name == module_name &&
1265
+ other.external == external
1266
+ end
1267
+
1268
+ alias == eql?
1269
+
1270
+ attr_reader :hash
1271
+
1272
+ def to_s
1273
+ module_name ? "#{module_name}.#{name}" : name
1274
+ end
1275
+ end
1276
+
1277
+ class Enum < EnumBase
1278
+ end
1279
+
1280
+ class Flags < EnumBase
1281
+ def bitwise?
1282
+ true
1283
+ end
1284
+ end
1285
+
1286
+ class Parameter
1287
+ attr_reader :name, :type, :mutable, :passing_mode, :boundary_type
1288
+
1289
+ def initialize(name, type, mutable: false, passing_mode: :plain, boundary_type: nil)
1290
+ @name = name
1291
+ @type = type
1292
+ @mutable = mutable
1293
+ @passing_mode = passing_mode
1294
+ @boundary_type = boundary_type
1295
+ @hash = [self.class, type, mutable, passing_mode, boundary_type].hash
1296
+ freeze
1297
+ end
1298
+
1299
+ def to_s
1300
+ "#{name}: #{type}"
1301
+ end
1302
+
1303
+ def eql?(other)
1304
+ other.is_a?(Parameter) &&
1305
+ other.type == type &&
1306
+ other.mutable == mutable &&
1307
+ other.passing_mode == passing_mode &&
1308
+ other.boundary_type == boundary_type
1309
+ end
1310
+
1311
+ alias == eql?
1312
+
1313
+ attr_reader :hash
1314
+
1315
+ def children
1316
+ [type, boundary_type].compact
1317
+ end
1318
+ end
1319
+
1320
+ class Function < Base
1321
+ attr_reader :name, :params, :return_type, :receiver_type, :receiver_editable, :variadic, :external
1322
+
1323
+ def initialize(name, params:, return_type:, receiver_type: nil, receiver_editable: false, variadic: false, external: false)
1324
+ @name = name
1325
+ @params = params.freeze
1326
+ @return_type = return_type
1327
+ @receiver_type = receiver_type
1328
+ @receiver_editable = receiver_editable
1329
+ @variadic = variadic
1330
+ @external = external
1331
+ @hash = [self.class, @params, return_type, receiver_type, receiver_editable, variadic].hash
1332
+ freeze
1333
+ end
1334
+
1335
+ def eql?(other)
1336
+ other.is_a?(Function) &&
1337
+ other.params == params &&
1338
+ other.return_type == return_type &&
1339
+ other.receiver_type == receiver_type &&
1340
+ other.receiver_editable == receiver_editable &&
1341
+ other.variadic == variadic
1342
+ end
1343
+
1344
+ alias == eql?
1345
+
1346
+ attr_reader :hash
1347
+
1348
+
1349
+ def to_s
1350
+ pieces = []
1351
+ pieces << receiver_type.to_s if receiver_type
1352
+ pieces << name if name
1353
+ "fn #{pieces.join('.')}"
1354
+ end
1355
+
1356
+ def children
1357
+ result = params.flat_map { |p| [p.type, p.boundary_type].compact }
1358
+ result << return_type
1359
+ result << receiver_type if receiver_type
1360
+ result
1361
+ end
1362
+ end
1363
+
1364
+ class Proc < Base
1365
+ attr_reader :params, :return_type
1366
+
1367
+ def initialize(params:, return_type:)
1368
+ @params = params.freeze
1369
+ @return_type = return_type
1370
+ @hash = [self.class, @params, return_type].hash
1371
+ freeze
1372
+ end
1373
+
1374
+ def eql?(other)
1375
+ other.is_a?(Proc) && other.params == params && other.return_type == return_type
1376
+ end
1377
+
1378
+ alias == eql?
1379
+
1380
+ attr_reader :hash
1381
+
1382
+ def to_s
1383
+ "proc(#{params.map(&:type).join(', ')}) -> #{return_type}"
1384
+ end
1385
+
1386
+ def children
1387
+ params.map(&:type) + [return_type]
1388
+ end
1389
+ end
1390
+
1391
+ BUILTIN_VECTOR_ELEMENT = Primitive.new("float")
1392
+ BUILTIN_IVECTOR_ELEMENT = Primitive.new("int")
1393
+
1394
+ class Vector < Base
1395
+ attr_reader :name, :element_type, :width, :module_name
1396
+
1397
+ FIELD_NAMES = %w[x y z w].freeze
1398
+
1399
+ def initialize(name, element_type:, width:)
1400
+ @name = name
1401
+ @element_type = element_type
1402
+ @width = width
1403
+ @module_name = nil
1404
+ @fields = FIELD_NAMES.first(width).each_with_object({}) do |fname, h|
1405
+ h[fname] = element_type
1406
+ end.freeze
1407
+ @hash = [self.class, name, element_type].hash
1408
+ freeze
1409
+ end
1410
+
1411
+ def eql?(other)
1412
+ other.is_a?(Vector) && other.name == name && other.element_type == element_type
1413
+ end
1414
+
1415
+ alias == eql?
1416
+
1417
+ attr_reader :hash
1418
+
1419
+ def fields
1420
+ @fields
1421
+ end
1422
+
1423
+ def field(name)
1424
+ @fields[name]
1425
+ end
1426
+
1427
+ def numeric?
1428
+ true
1429
+ end
1430
+
1431
+
1432
+ def to_s
1433
+ name
1434
+ end
1435
+ end
1436
+
1437
+ class Matrix < Base
1438
+ attr_reader :name, :dim, :module_name
1439
+
1440
+ def initialize(name, dim:)
1441
+ @name = name
1442
+ @dim = dim
1443
+ @module_name = nil
1444
+ col_type = Vector.new("vec#{dim}", element_type: BUILTIN_VECTOR_ELEMENT, width: dim)
1445
+ @fields = (0...dim).each_with_object({}) do |i, h|
1446
+ h["col#{i}"] = col_type
1447
+ end.freeze
1448
+ @hash = [self.class, name].hash
1449
+ freeze
1450
+ end
1451
+
1452
+ def eql?(other)
1453
+ other.is_a?(Matrix) && other.name == name
1454
+ end
1455
+
1456
+ alias == eql?
1457
+
1458
+ attr_reader :hash
1459
+
1460
+ def fields
1461
+ @fields
1462
+ end
1463
+
1464
+ def field(name)
1465
+ @fields[name]
1466
+ end
1467
+
1468
+ def numeric?
1469
+ true
1470
+ end
1471
+
1472
+
1473
+ def to_s
1474
+ name
1475
+ end
1476
+ end
1477
+
1478
+ class Quaternion < Base
1479
+ attr_reader :name, :module_name
1480
+
1481
+ FIELD_NAMES = %w[x y z w].freeze
1482
+
1483
+ def initialize(name)
1484
+ @name = name
1485
+ @module_name = nil
1486
+ @fields = FIELD_NAMES.each_with_object({}) do |fname, h|
1487
+ h[fname] = BUILTIN_VECTOR_ELEMENT
1488
+ end.freeze
1489
+ @hash = [self.class, name].hash
1490
+ freeze
1491
+ end
1492
+
1493
+ def eql?(other)
1494
+ other.is_a?(Quaternion) && other.name == name
1495
+ end
1496
+
1497
+ alias == eql?
1498
+
1499
+ attr_reader :hash
1500
+
1501
+ def fields
1502
+ @fields
1503
+ end
1504
+
1505
+ def field(name)
1506
+ @fields[name]
1507
+ end
1508
+
1509
+ def numeric?
1510
+ true
1511
+ end
1512
+
1513
+
1514
+ def to_s
1515
+ name
1516
+ end
1517
+ end
1518
+
1519
+ class SoA < Base
1520
+ attr_reader :name, :element_type, :count, :module_name
1521
+
1522
+ def initialize(element_type, count:)
1523
+ @name = "SoA[#{element_type}, #{count}]"
1524
+ @element_type = element_type
1525
+ @count = count
1526
+ @module_name = nil
1527
+ @fields = if element_type.respond_to?(:fields) && element_type.fields
1528
+ element_type.fields.each_with_object({}) do |(fname, ftype), h|
1529
+ h[fname] = GenericInstance.new("array", [ftype, LiteralTypeArg.new(count)])
1530
+ end
1531
+ else
1532
+ {}.freeze
1533
+ end.freeze
1534
+ @hash = [self.class, element_type, count].hash
1535
+ freeze
1536
+ end
1537
+
1538
+ def eql?(other)
1539
+ other.is_a?(SoA) && other.element_type == element_type && other.count == count
1540
+ end
1541
+
1542
+ alias == eql?
1543
+
1544
+ attr_reader :hash
1545
+
1546
+ def fields
1547
+ @fields
1548
+ end
1549
+
1550
+ def field(name)
1551
+ @fields[name]
1552
+ end
1553
+
1554
+ def to_s
1555
+ @name
1556
+ end
1557
+
1558
+ def children
1559
+ [element_type]
1560
+ end
1561
+ end
1562
+
1563
+ class Tuple < Base
1564
+ attr_reader :element_types, :field_names
1565
+
1566
+ def initialize(element_types, field_names: nil)
1567
+ @element_types = element_types.freeze
1568
+ @field_names = (field_names || element_types.each_with_index.map { |_, i| "_#{i}" }).freeze
1569
+ @fields = @field_names.each_with_index.each_with_object({}) do |(name, index), h|
1570
+ h[name] = element_types[index]
1571
+ end.freeze
1572
+ @hash = [self.class, @element_types, @field_names].hash
1573
+ freeze
1574
+ end
1575
+
1576
+ def eql?(other)
1577
+ other.is_a?(Tuple) && other.element_types == element_types && other.field_names == field_names
1578
+ end
1579
+
1580
+ alias == eql?
1581
+
1582
+ attr_reader :hash
1583
+
1584
+ def fields
1585
+ @fields
1586
+ end
1587
+
1588
+ def field(name)
1589
+ @fields[name]
1590
+ end
1591
+
1592
+ def to_s
1593
+ if field_names == element_types.each_with_index.map { |_, i| "_#{i}" }
1594
+ "(#{element_types.map(&:to_s).join(', ')})"
1595
+ else
1596
+ fields_parts = field_names.each_with_index.map { |n, i| "#{n}: #{element_types[i]}" }
1597
+ "(#{fields_parts.join(', ')})"
1598
+ end
1599
+ end
1600
+
1601
+ def children
1602
+ element_types
1603
+ end
1604
+ end
1605
+
1606
+ class Dyn < Base
1607
+ attr_reader :interface_binding, :type_arguments
1608
+
1609
+ def initialize(interface_binding, type_arguments = [])
1610
+ @interface_binding = interface_binding
1611
+ @type_arguments = type_arguments
1612
+ @hash = [self.class, interface_binding, type_arguments].hash
1613
+ freeze
1614
+ end
1615
+
1616
+ def eql?(other)
1617
+ other.is_a?(Dyn) && other.interface_binding == interface_binding && other.type_arguments == type_arguments
1618
+ end
1619
+
1620
+ alias == eql?
1621
+
1622
+ attr_reader :hash
1623
+
1624
+ def to_s
1625
+ if type_arguments.any?
1626
+ "dyn[#{interface_binding.name}[#{type_arguments.map(&:to_s).join(', ')}]]"
1627
+ else
1628
+ "dyn[#{interface_binding.name}]"
1629
+ end
1630
+ end
1631
+
1632
+ def field(name)
1633
+ void_ptr = GenericInstance.new("ptr", [Primitive.new("void")])
1634
+ { "data" => void_ptr, "vtable" => void_ptr }[name]
1635
+ end
1636
+
1637
+ def children
1638
+ type_arguments
1639
+ end
1640
+ end
1641
+
1642
+ class DynVtable < Base
1643
+ attr_reader :linkage_name, :interface_name, :fields
1644
+
1645
+ def initialize(interface_name, fields = {})
1646
+ @interface_name = interface_name
1647
+ @linkage_name = "mt_vtable_#{interface_name}"
1648
+ @fields = fields
1649
+ @hash = [self.class, @linkage_name].hash
1650
+ freeze
1651
+ end
1652
+
1653
+ def eql?(other)
1654
+ other.is_a?(DynVtable) && other.linkage_name == linkage_name
1655
+ end
1656
+
1657
+ alias == eql?
1658
+
1659
+ attr_reader :hash
1660
+
1661
+ def to_s
1662
+ linkage_name
1663
+ end
1664
+
1665
+ def field(name)
1666
+ @fields[name]
1667
+ end
1668
+ end
1669
+
1670
+ BUILTIN_OPTION_TYPE = GenericVariantDefinition.new("Option", ["T"]).define_arms(
1671
+ "some" => { "value" => TypeVar.new("T") },
1672
+ "none" => {},
1673
+ )
1674
+
1675
+ BUILTIN_RESULT_TYPE = GenericVariantDefinition.new("Result", ["T", "E"]).define_arms(
1676
+ "success" => { "value" => TypeVar.new("T") },
1677
+ "failure" => { "error" => TypeVar.new("E") },
1678
+ )
1679
+
1680
+ def self.pointer_to(type)
1681
+ GenericInstance.new("ptr", [type])
1682
+ end
1683
+
1684
+ def self.integer_type?(type)
1685
+ type.is_a?(Primitive) && %w[int ptr_uint i8 i16 i32 i64 u8 u16 u32 u64].include?(type.name)
1686
+ end
1687
+
1688
+ def self.array_type?(type)
1689
+ type.is_a?(GenericInstance) && type.name == "array" && type.arguments.length == 2
1690
+ end
1691
+
1692
+ def self.str_buffer_type?(type)
1693
+ type.is_a?(GenericInstance) && type.name == "str_buffer" && type.arguments.length == 1
1694
+ end
1695
+ end
1696
+ end