mt-lang 0.3.8 → 0.3.10

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -2
  3. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
  4. data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
  5. data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
  6. data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
  7. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
  8. data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
  9. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
  10. data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
  11. data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
  12. data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
  13. data/lib/milk_tea/bindings/steamworks.rb +12 -16
  14. data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
  15. data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
  16. data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
  17. data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
  18. data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
  19. data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
  20. data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
  21. data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
  22. data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
  23. data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
  24. data/lib/milk_tea/core/ast.rb +103 -45
  25. data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
  26. data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
  27. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
  28. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
  29. data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
  30. data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
  31. data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
  32. data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
  33. data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
  34. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
  35. data/lib/milk_tea/core/c_backend/statements.rb +528 -530
  36. data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
  37. data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
  38. data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
  39. data/lib/milk_tea/core/c_backend.rb +17 -9
  40. data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
  41. data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
  42. data/lib/milk_tea/core/compile_time.rb +32 -38
  43. data/lib/milk_tea/core/control_flow/builder.rb +3 -5
  44. data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
  45. data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
  46. data/lib/milk_tea/core/ir.rb +10 -10
  47. data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
  48. data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
  49. data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
  50. data/lib/milk_tea/core/lexer/indentation.rb +0 -2
  51. data/lib/milk_tea/core/lexer/numbers.rb +0 -2
  52. data/lib/milk_tea/core/lexer/recovery.rb +0 -2
  53. data/lib/milk_tea/core/lexer/strings.rb +0 -2
  54. data/lib/milk_tea/core/lexer/symbols.rb +0 -2
  55. data/lib/milk_tea/core/lexer/trivia.rb +0 -2
  56. data/lib/milk_tea/core/lexer.rb +0 -2
  57. data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
  58. data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
  59. data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
  60. data/lib/milk_tea/core/lowering/async.rb +627 -630
  61. data/lib/milk_tea/core/lowering/block.rb +413 -416
  62. data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
  63. data/lib/milk_tea/core/lowering/declarations.rb +180 -183
  64. data/lib/milk_tea/core/lowering/dyn.rb +48 -50
  65. data/lib/milk_tea/core/lowering/events.rb +983 -985
  66. data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
  67. data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
  68. data/lib/milk_tea/core/lowering/functions.rb +185 -188
  69. data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
  70. data/lib/milk_tea/core/lowering/proc.rb +363 -366
  71. data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
  72. data/lib/milk_tea/core/lowering/scans.rb +179 -181
  73. data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
  74. data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
  75. data/lib/milk_tea/core/lowering.rb +5 -7
  76. data/lib/milk_tea/core/module_binder.rb +0 -2
  77. data/lib/milk_tea/core/module_loader/errors.rb +4 -2
  78. data/lib/milk_tea/core/module_loader.rb +113 -20
  79. data/lib/milk_tea/core/module_path_resolver.rb +0 -2
  80. data/lib/milk_tea/core/module_roots.rb +6 -8
  81. data/lib/milk_tea/core/parser/attributes.rb +0 -2
  82. data/lib/milk_tea/core/parser/blocks.rb +0 -2
  83. data/lib/milk_tea/core/parser/declarations.rb +0 -2
  84. data/lib/milk_tea/core/parser/expressions.rb +31 -14
  85. data/lib/milk_tea/core/parser/recovery.rb +0 -2
  86. data/lib/milk_tea/core/parser/statements.rb +0 -2
  87. data/lib/milk_tea/core/parser/types.rb +8 -10
  88. data/lib/milk_tea/core/parser.rb +1 -3
  89. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
  90. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
  91. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
  92. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
  93. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
  94. data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
  95. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
  96. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
  97. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
  98. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
  99. data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
  100. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
  101. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
  102. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
  103. data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
  104. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
  105. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
  106. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
  107. data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
  108. data/lib/milk_tea/core/types/layout.rb +21 -22
  109. data/lib/milk_tea/core/types/predicates.rb +0 -2
  110. data/lib/milk_tea/core/types/registry.rb +16 -18
  111. data/lib/milk_tea/core/types/visitor.rb +0 -4
  112. data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
  113. data/lib/milk_tea/dap/protocol.rb +1 -1
  114. data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
  115. data/lib/milk_tea/dap/server/debug_map.rb +0 -2
  116. data/lib/milk_tea/dap/server/handlers.rb +0 -2
  117. data/lib/milk_tea/dap/server/launch.rb +0 -2
  118. data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
  119. data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
  120. data/lib/milk_tea/dap/server/utilities.rb +0 -2
  121. data/lib/milk_tea/dap/server/wire.rb +0 -2
  122. data/lib/milk_tea/dap/server.rb +0 -2
  123. data/lib/milk_tea/lsp/diagnostics.rb +16 -16
  124. data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
  125. data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
  126. data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
  127. data/lib/milk_tea/lsp/server/completion.rb +873 -875
  128. data/lib/milk_tea/lsp/server/configuration.rb +129 -131
  129. data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
  130. data/lib/milk_tea/lsp/server/definition.rb +564 -565
  131. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
  132. data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
  133. data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
  134. data/lib/milk_tea/lsp/server/formatting.rb +478 -480
  135. data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
  136. data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
  137. data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
  138. data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
  139. data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
  140. data/lib/milk_tea/lsp/server/progress.rb +0 -2
  141. data/lib/milk_tea/lsp/server/references.rb +316 -318
  142. data/lib/milk_tea/lsp/server/rename.rb +445 -447
  143. data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
  144. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
  145. data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
  146. data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
  147. data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
  148. data/lib/milk_tea/lsp/server/utilities.rb +397 -399
  149. data/lib/milk_tea/lsp/server.rb +0 -3
  150. data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
  151. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
  152. data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
  153. data/lib/milk_tea/packages/atomic_write.rb +4 -5
  154. data/lib/milk_tea/packages/dependency_solver.rb +15 -15
  155. data/lib/milk_tea/packages/lock.rb +4 -4
  156. data/lib/milk_tea/packages/manager_cli.rb +1 -1
  157. data/lib/milk_tea/packages/manifest.rb +3 -3
  158. data/lib/milk_tea/packages/registry_store.rb +4 -6
  159. data/lib/milk_tea/packages/services.rb +16 -16
  160. data/lib/milk_tea/packages/source_cache.rb +4 -6
  161. data/lib/milk_tea/packages/source_resolver.rb +44 -44
  162. data/lib/milk_tea/packages/version.rb +8 -8
  163. data/lib/milk_tea/tooling/build.rb +3 -7
  164. data/lib/milk_tea/tooling/build_cache.rb +0 -2
  165. data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
  166. data/lib/milk_tea/tooling/debug_map.rb +8 -10
  167. data/lib/milk_tea/tooling/docs_app.rb +0 -2
  168. data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
  169. data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
  170. data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
  171. data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
  172. data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
  173. data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
  174. data/lib/milk_tea/tooling/linter/rules.rb +87 -89
  175. data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
  176. data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
  177. data/lib/milk_tea/tooling/linter/visitors.rb +162 -50
  178. data/lib/milk_tea/tooling/linter.rb +0 -2
  179. data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
  180. data/lib/milk_tea/tooling/run.rb +0 -2
  181. data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
  182. data/std/cli.mt +13 -32
  183. data/std/color.mt +28 -28
  184. data/std/encoding.mt +4 -4
  185. data/std/graph.mt +1 -2
  186. data/std/hash.mt +14 -14
  187. data/std/http/server.mt +3 -3
  188. data/std/input.mt +1 -1
  189. data/std/json.mt +1 -1
  190. data/std/linear_algebra.mt +6 -6
  191. data/std/net/mux.mt +1 -1
  192. data/std/noise.mt +23 -23
  193. data/std/parse.mt +2 -2
  194. data/std/process.mt +3 -4
  195. data/std/sparse_set.mt +1 -1
  196. data/std/steering.mt +5 -5
  197. data/std/str.mt +1 -1
  198. data/std/tween.mt +4 -4
  199. data/std/utility.mt +3 -3
  200. metadata +2 -2
@@ -3,355 +3,353 @@
3
3
  module MilkTea
4
4
  class CBackend
5
5
  module TypeSystem
6
- private
7
-
8
- PRIMITIVE_C_TYPE_MAP = {
9
- "bool" => "bool",
10
- "byte" => "int8_t",
11
- "ubyte" => "uint8_t",
12
- "char" => "char",
13
- "short" => "int16_t",
14
- "ushort" => "uint16_t",
15
- "int" => "int32_t",
16
- "uint" => "uint32_t",
17
- "long" => "int64_t",
18
- "ulong" => "uint64_t",
19
- "ptr_int" => "intptr_t",
20
- "ptr_uint" => "uintptr_t",
21
- "float" => "float",
22
- "double" => "double",
23
- "void" => "void",
24
- "cstr" => "const char*",
25
- }.freeze
26
-
27
- SANITIZE_NON_ALNUM_RE = /[^A-Za-z0-9_]+/
28
- SANITIZE_UNDERSCORES_RE = /_+/
29
- SANITIZE_LEADING_UNDERSCORES_RE = /^_+/
30
- SANITIZE_TRAILING_UNDERSCORES_RE = /_+$/
31
-
32
- def c_declaration(type, name)
33
- base, declarator = c_declaration_parts(type, name)
34
- declarator.empty? ? base : "#{base} #{declarator}"
35
- end
36
-
37
- def c_field_declaration(type, name)
38
- return "uint8_t #{name}" if void_storage_field?(type)
39
-
40
- c_declaration(type, name)
41
- end
42
-
43
- def c_function_declaration(return_type, name, params)
44
- c_declaration(array_type?(return_type) ? void_type : return_type, "#{name}(#{params})")
45
- end
46
-
47
- def c_function_return_type(type)
48
- c_type(array_type?(type) ? void_type : type)
49
- end
50
-
51
- def array_out_param_declaration(type, name)
52
- c_declaration(type, "(*#{name})")
53
- end
54
-
55
- def c_declaration_parts(type, name)
56
- name = name.to_s
57
-
58
- if array_type?(type)
59
- declarator = declarator_needs_grouping?(name) ? "(#{name})" : name
60
- return c_declaration_parts(array_element_type(type), "#{declarator}[#{array_length(type)}]")
61
- end
62
-
63
- if type.is_a?(Types::Nullable) && type.base.is_a?(Types::Function)
64
- return c_declaration_parts(type.base, name)
65
- end
66
-
67
- if type.is_a?(Types::Function)
68
- params = []
69
- params << array_out_param_declaration(type.return_type, ARRAY_OUT_PARAM_NAME) if array_type?(type.return_type)
70
- params.concat(type.params.each_with_index.map do |param, index|
71
- c_declaration(param.type, param.name || "arg#{index}")
72
- end)
73
- params << "..." if type.variadic
74
- params = ["void"] if params.empty?
75
- return [c_function_return_type(type.return_type), "(*#{name})(#{params.join(', ')})"]
76
- end
77
-
78
- if type.is_a?(Types::Proc)
79
- return [proc_type_name(type), name]
80
- end
81
-
82
- if mutable_pointer_type?(type) || own_type?(type)
83
- return c_declaration_parts(type.arguments.first, "*#{name}")
84
- end
85
-
86
- if const_pointer_type?(type)
87
- return [generic_c_type(type), name]
88
- end
89
-
90
- if ref_type?(type)
91
- ref_arguments = type.arguments
92
- ref_target = ref_arguments.length == 1 ? ref_arguments.first : ref_arguments[1]
93
- return c_declaration_parts(ref_target, "*#{name}")
94
- end
95
-
96
- [c_type(type), name]
97
- end
98
-
99
- def declarator_needs_grouping?(name)
100
- !name.empty? && (name.start_with?("*") || name.include?("["))
101
- end
102
-
103
- def c_type(type, pointer: false)
104
- case type
105
- when Types::Nullable
106
- return c_type(type.base, pointer:) if type.base.is_a?(Types::Function)
107
-
108
- unless c_backend_pointer_like_type?(type.base)
109
- base = nullable_opt_type_name(type)
110
- return pointer ? "#{base}*" : base
111
- end
112
-
113
- base = c_type(type.base)
114
- base.end_with?("*") ? base : "#{base}*"
115
- when Types::StringView
116
- base = "mt_str"
117
- pointer ? "#{base}*" : base
118
- when Types::Primitive
119
- base = primitive_c_type(type.name)
120
- pointer ? "#{base}*" : base
121
- when Types::Span
122
- base = span_type_name(type)
123
- pointer ? "#{base}*" : base
124
- when Types::Task
125
- base = task_type_name(type)
126
- pointer ? "#{base}*" : base
127
- when Types::Proc
128
- base = proc_type_name(type)
129
- pointer ? "#{base}*" : base
130
- when Types::Dyn
131
- base = dyn_type_name(type)
132
- pointer ? "#{base}*" : base
133
- when Types::DynVtable
134
- base = type.linkage_name
135
- pointer ? "#{base}*" : base
136
- when Types::Function
137
- base = c_declaration(type, "")
138
- pointer ? "#{base}*" : base
139
- when Types::GenericInstance
140
- base = generic_c_type(type)
141
- pointer ? "#{base}*" : base
142
- when Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::VariantInstance, Types::VariantArmPayload, Types::Event, Types::Subscription
143
- base = named_type_c_name(type)
144
- pointer ? "#{base}*" : base
145
- when Types::Opaque
146
- if type.external
147
- base = external_opaque_c_type(type)
148
- pointer ? "#{base}*" : base
149
- else
150
- base = type.linkage_name || named_type_c_name(type)
151
- pointer ? "#{base}**" : "#{base}*"
152
- end
153
- when Types::Vector
154
- base = "mt_#{type.name}"
155
- pointer ? "#{base}*" : base
156
- when Types::Matrix
157
- base = "mt_#{type.name}"
158
- pointer ? "#{base}*" : base
159
- when Types::Quaternion
160
- base = "mt_#{type.name}"
161
- pointer ? "#{base}*" : base
162
- when Types::SoA
163
- base = soa_type_name(type)
164
- pointer ? "#{base}*" : base
165
- when Types::Simd
166
- base = simd_type_name(type)
167
- pointer ? "#{base}*" : base
168
- when Types::Tuple
169
- base = tuple_type_name(type)
170
- pointer ? "#{base}*" : base
171
- when Types::Handle
172
- "void*"
173
- else
174
- raise CBackendError.new("unsupported C type #{type.class.name}", line: 0, column: 0, path: @path)
175
- end
176
- end
177
-
178
- def constant_storage(type)
179
- return "static const" if array_type?(type)
180
-
181
- c_type(type).start_with?("const ") ? "static" : "static const"
182
- end
183
-
184
- def global_storage(_type)
185
- "static"
186
- end
187
-
188
- def span_type_name(type)
189
- "mt_span_#{sanitize_identifier(type.element_type.to_s)}"
190
- end
191
-
192
- def soa_type_name(type)
193
- element_name = sanitize_identifier(type.element_type.respond_to?(:name) ? type.element_type.name : type.element_type.to_s)
194
- "mt_soa_#{element_name}_#{type.count}"
195
- end
196
-
197
- def simd_type_name(type)
198
- element_name = sanitize_identifier(type.element_type.to_s)
199
- "mt_simd_#{element_name}x#{type.lane_count}"
200
- end
201
-
202
- def tuple_type_name(type)
203
- sanitized = type.element_types.map { |et| sanitize_identifier(et.to_s) }.join("_")
204
- base = "mt_tuple_#{sanitized}"
205
- default_names = type.element_types.each_with_index.map { |_, i| "_#{i}" }
206
- if type.field_names != default_names
207
- base << "_" << type.field_names.map { |n| sanitize_identifier(n) }.join("_")
208
- end
209
- base
210
- end
211
-
212
- def task_type_name(type)
213
- "mt_task_#{sanitize_identifier(type.result_type.to_s)}"
214
- end
215
-
216
- def proc_type_name(type)
217
- "mt_proc_#{sanitize_identifier(type.to_s)}"
218
- end
219
-
220
- def dyn_type_name(type)
221
- "mt_dyn_#{sanitize_identifier(type.interface_binding.name)}"
222
- end
223
-
224
- def nullable_opt_type_name(type)
225
- "mt_opt_#{sanitize_identifier(c_type(type.base))}"
226
- end
227
-
228
- def named_type_c_name(type)
229
- return task_type_name(type) if type.is_a?(Types::Task)
230
- if type.is_a?(Types::VariantArmPayload)
231
- return "#{named_type_c_name(type.variant_type)}_#{type.arm_name}"
232
- end
233
-
234
- if type.respond_to?(:linkage_name) && type.linkage_name
235
- return type.linkage_name
236
- end
237
-
238
- base_name = type.module_name&.start_with?("std.c.") ? type.name : type.module_name ? "#{module_c_prefix(type.module_name)}_#{type.name}" : type.name
239
- return base_name unless type.is_a?(Types::StructInstance) || type.is_a?(Types::VariantInstance)
240
-
241
- "#{base_name}_#{sanitize_identifier(type.arguments.join('_'))}"
242
- end
243
-
244
- def external_opaque_c_type(type)
245
- type.linkage_name || type.name
246
- end
247
-
248
- def sanitize_identifier(text)
249
- identifier = text.gsub(SANITIZE_NON_ALNUM_RE, "_").gsub(SANITIZE_UNDERSCORES_RE, "_").sub(SANITIZE_LEADING_UNDERSCORES_RE, "").sub(SANITIZE_TRAILING_UNDERSCORES_RE, "")
250
- identifier.empty? ? "value" : identifier
251
- end
252
-
253
- def module_c_prefix(module_name)
254
- sanitize_identifier(module_name.to_s.tr('.', '_'))
255
- end
256
-
257
- def primitive_c_type(name)
258
- PRIMITIVE_C_TYPE_MAP.fetch(name)
259
- end
260
-
261
- def generic_c_type(type)
262
- case type.name
263
- when "ptr"
264
- raise CBackendError.new("ptr requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
265
-
266
- "#{c_type(type.arguments.first)}*"
267
- when "const_ptr"
268
- raise CBackendError.new("const_ptr requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
269
-
270
- "const #{c_type(type.arguments.first)}*"
271
- when "own"
272
- raise CBackendError.new("own requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
273
-
274
- "#{c_type(type.arguments.first)}*"
275
- when "ref"
276
- raise CBackendError.new("ref requires at least one type argument", line: 0, column: 0, path: @path) unless [1, 2].include?(type.arguments.length)
277
-
278
- "#{c_type(type.arguments.length == 1 ? type.arguments.first : type.arguments[1])}*"
279
- when "array"
280
- raise CBackendError.new("array requires exactly two type arguments", line: 0, column: 0, path: @path) unless type.arguments.length == 2
281
-
282
- c_type(type.arguments.first)
283
- when "str_buffer"
284
- raise CBackendError.new("str_buffer requires exactly one type argument", line: 0, column: 0, path: @path) unless str_buffer_type?(type)
285
-
286
- str_buffer_type_name(type)
287
- when "atomic"
288
- "_Atomic #{c_type(type.arguments.first)}"
289
- else
290
- raise CBackendError.new("unsupported generic C type #{type.name}", line: 0, column: 0, path: @path)
291
- end
292
- end
293
-
294
- def mutable_pointer_type?(type)
295
- type.is_a?(Types::GenericInstance) && type.name == "ptr" && type.arguments.length == 1
296
- end
297
-
298
- def const_pointer_type?(type)
299
- type.is_a?(Types::GenericInstance) && type.name == "const_ptr" && type.arguments.length == 1
300
- end
301
-
302
- def own_type?(type)
303
- type.is_a?(Types::GenericInstance) && type.name == "own" && type.arguments.length == 1
304
- end
305
-
306
- def pointer_type?(type)
307
- mutable_pointer_type?(type)
308
- end
309
-
310
- def c_backend_pointer_like_type?(type)
311
- pointer_type?(type) || const_pointer_type?(type) || own_type?(type) || (type.is_a?(Types::Primitive) && type.name == "cstr") || type.is_a?(Types::Function) || type.is_a?(Types::Proc) || type.is_a?(Types::Opaque)
312
- end
313
-
314
- def raw_pointer_type?(type)
315
- mutable_pointer_type?(type) || const_pointer_type?(type) || own_type?(type)
316
- end
317
-
318
- def ref_type?(type)
319
- type.is_a?(Types::GenericInstance) && type.name == "ref" && [1, 2].include?(type.arguments.length)
320
- end
321
-
322
- def array_type?(type)
323
- type.is_a?(Types::GenericInstance) && type.name == "array" && type.arguments.length == 2 &&
324
- type.arguments[1].is_a?(Types::LiteralTypeArg)
325
- end
326
-
327
- def array_element_type(type)
328
- type.arguments.first
329
- end
330
-
331
- def array_length(type)
332
- type.arguments[1].value
333
- end
334
-
335
- def str_buffer_type?(type)
336
- type.is_a?(Types::GenericInstance) && type.name == "str_buffer" && type.arguments.length == 1 &&
337
- type.arguments.first.is_a?(Types::LiteralTypeArg) && type.arguments.first.value.is_a?(Integer)
338
- end
339
-
340
- def str_buffer_capacity(type)
341
- type.arguments.first.value
342
- end
343
-
344
- def str_buffer_storage_capacity(type)
345
- str_buffer_capacity(type) + 1
346
- end
347
-
348
- def str_buffer_type_name(type)
349
- "mt_str_buffer_#{str_buffer_capacity(type)}"
350
- end
351
-
352
- def pointer_to(type)
353
- Types::Registry.generic_instance("ptr", [type])
354
- end
6
+ PRIMITIVE_C_TYPE_MAP = {
7
+ "bool" => "bool",
8
+ "byte" => "int8_t",
9
+ "ubyte" => "uint8_t",
10
+ "char" => "char",
11
+ "short" => "int16_t",
12
+ "ushort" => "uint16_t",
13
+ "int" => "int32_t",
14
+ "uint" => "uint32_t",
15
+ "long" => "int64_t",
16
+ "ulong" => "uint64_t",
17
+ "ptr_int" => "intptr_t",
18
+ "ptr_uint" => "uintptr_t",
19
+ "float" => "float",
20
+ "double" => "double",
21
+ "void" => "void",
22
+ "cstr" => "const char*",
23
+ }.freeze
24
+
25
+ SANITIZE_NON_ALNUM_RE = /[^A-Za-z0-9_]+/
26
+ SANITIZE_UNDERSCORES_RE = /_+/
27
+ SANITIZE_LEADING_UNDERSCORES_RE = /^_+/
28
+ SANITIZE_TRAILING_UNDERSCORES_RE = /_+$/
29
+
30
+ def c_declaration(type, name)
31
+ base, declarator = c_declaration_parts(type, name)
32
+ declarator.empty? ? base : "#{base} #{declarator}"
33
+ end
34
+
35
+ def c_field_declaration(type, name)
36
+ return "uint8_t #{name}" if void_storage_field?(type)
37
+
38
+ c_declaration(type, name)
39
+ end
40
+
41
+ def c_function_declaration(return_type, name, params)
42
+ c_declaration(array_type?(return_type) ? void_type : return_type, "#{name}(#{params})")
43
+ end
44
+
45
+ def c_function_return_type(type)
46
+ c_type(array_type?(type) ? void_type : type)
47
+ end
48
+
49
+ def array_out_param_declaration(type, name)
50
+ c_declaration(type, "(*#{name})")
51
+ end
52
+
53
+ def c_declaration_parts(type, name)
54
+ name = name.to_s
55
+
56
+ if array_type?(type)
57
+ declarator = declarator_needs_grouping?(name) ? "(#{name})" : name
58
+ return c_declaration_parts(array_element_type(type), "#{declarator}[#{array_length(type)}]")
59
+ end
60
+
61
+ if type.is_a?(Types::Nullable) && type.base.is_a?(Types::Function)
62
+ return c_declaration_parts(type.base, name)
63
+ end
64
+
65
+ if type.is_a?(Types::Function)
66
+ params = []
67
+ params << array_out_param_declaration(type.return_type, ARRAY_OUT_PARAM_NAME) if array_type?(type.return_type)
68
+ params.concat(type.params.each_with_index.map do |param, index|
69
+ c_declaration(param.type, param.name || "arg#{index}")
70
+ end)
71
+ params << "..." if type.variadic
72
+ params = ["void"] if params.empty?
73
+ return [c_function_return_type(type.return_type), "(*#{name})(#{params.join(', ')})"]
74
+ end
75
+
76
+ if type.is_a?(Types::Proc)
77
+ return [proc_type_name(type), name]
78
+ end
79
+
80
+ if mutable_pointer_type?(type) || own_type?(type)
81
+ return c_declaration_parts(type.arguments.first, "*#{name}")
82
+ end
83
+
84
+ if const_pointer_type?(type)
85
+ return [generic_c_type(type), name]
86
+ end
87
+
88
+ if ref_type?(type)
89
+ ref_arguments = type.arguments
90
+ ref_target = ref_arguments.length == 1 ? ref_arguments.first : ref_arguments[1]
91
+ return c_declaration_parts(ref_target, "*#{name}")
92
+ end
93
+
94
+ [c_type(type), name]
95
+ end
96
+
97
+ def declarator_needs_grouping?(name)
98
+ !name.empty? && (name.start_with?("*") || name.include?("["))
99
+ end
100
+
101
+ def c_type(type, pointer: false)
102
+ case type
103
+ when Types::Nullable
104
+ return c_type(type.base, pointer:) if type.base.is_a?(Types::Function)
105
+
106
+ unless c_backend_pointer_like_type?(type.base)
107
+ base = nullable_opt_type_name(type)
108
+ return pointer ? "#{base}*" : base
109
+ end
110
+
111
+ base = c_type(type.base)
112
+ base.end_with?("*") ? base : "#{base}*"
113
+ when Types::StringView
114
+ base = "mt_str"
115
+ pointer ? "#{base}*" : base
116
+ when Types::Primitive
117
+ base = primitive_c_type(type.name)
118
+ pointer ? "#{base}*" : base
119
+ when Types::Span
120
+ base = span_type_name(type)
121
+ pointer ? "#{base}*" : base
122
+ when Types::Task
123
+ base = task_type_name(type)
124
+ pointer ? "#{base}*" : base
125
+ when Types::Proc
126
+ base = proc_type_name(type)
127
+ pointer ? "#{base}*" : base
128
+ when Types::Dyn
129
+ base = dyn_type_name(type)
130
+ pointer ? "#{base}*" : base
131
+ when Types::DynVtable
132
+ base = type.linkage_name
133
+ pointer ? "#{base}*" : base
134
+ when Types::Function
135
+ base = c_declaration(type, "")
136
+ pointer ? "#{base}*" : base
137
+ when Types::GenericInstance
138
+ base = generic_c_type(type)
139
+ pointer ? "#{base}*" : base
140
+ when Types::Struct, Types::StructInstance, Types::Union, Types::Enum, Types::Flags, Types::Variant, Types::VariantInstance, Types::VariantArmPayload, Types::Event, Types::Subscription
141
+ base = named_type_c_name(type)
142
+ pointer ? "#{base}*" : base
143
+ when Types::Opaque
144
+ if type.external
145
+ base = external_opaque_c_type(type)
146
+ pointer ? "#{base}*" : base
147
+ else
148
+ base = type.linkage_name || named_type_c_name(type)
149
+ pointer ? "#{base}**" : "#{base}*"
150
+ end
151
+ when Types::Vector
152
+ base = "mt_#{type.name}"
153
+ pointer ? "#{base}*" : base
154
+ when Types::Matrix
155
+ base = "mt_#{type.name}"
156
+ pointer ? "#{base}*" : base
157
+ when Types::Quaternion
158
+ base = "mt_#{type.name}"
159
+ pointer ? "#{base}*" : base
160
+ when Types::SoA
161
+ base = soa_type_name(type)
162
+ pointer ? "#{base}*" : base
163
+ when Types::Simd
164
+ base = simd_type_name(type)
165
+ pointer ? "#{base}*" : base
166
+ when Types::Tuple
167
+ base = tuple_type_name(type)
168
+ pointer ? "#{base}*" : base
169
+ when Types::Handle
170
+ "void*"
171
+ else
172
+ raise CBackendError.new("unsupported C type #{type.class.name}", line: 0, column: 0, path: @path)
173
+ end
174
+ end
175
+
176
+ def constant_storage(type)
177
+ return "static const" if array_type?(type)
178
+
179
+ c_type(type).start_with?("const ") ? "static" : "static const"
180
+ end
181
+
182
+ def global_storage(_type)
183
+ "static"
184
+ end
185
+
186
+ def span_type_name(type)
187
+ "mt_span_#{sanitize_identifier(type.element_type.to_s)}"
188
+ end
189
+
190
+ def soa_type_name(type)
191
+ element_name = sanitize_identifier(type.element_type.respond_to?(:name) ? type.element_type.name : type.element_type.to_s)
192
+ "mt_soa_#{element_name}_#{type.count}"
193
+ end
194
+
195
+ def simd_type_name(type)
196
+ element_name = sanitize_identifier(type.element_type.to_s)
197
+ "mt_simd_#{element_name}x#{type.lane_count}"
198
+ end
199
+
200
+ def tuple_type_name(type)
201
+ sanitized = type.element_types.map { |et| sanitize_identifier(et.to_s) }.join("_")
202
+ base = "mt_tuple_#{sanitized}"
203
+ default_names = type.element_types.each_with_index.map { |_, i| "_#{i}" }
204
+ if type.field_names != default_names
205
+ base << "_" << type.field_names.map { |n| sanitize_identifier(n) }.join("_")
206
+ end
207
+ base
208
+ end
209
+
210
+ def task_type_name(type)
211
+ "mt_task_#{sanitize_identifier(type.result_type.to_s)}"
212
+ end
213
+
214
+ def proc_type_name(type)
215
+ "mt_proc_#{sanitize_identifier(type.to_s)}"
216
+ end
217
+
218
+ def dyn_type_name(type)
219
+ "mt_dyn_#{sanitize_identifier(type.interface_binding.name)}"
220
+ end
221
+
222
+ def nullable_opt_type_name(type)
223
+ "mt_opt_#{sanitize_identifier(c_type(type.base))}"
224
+ end
225
+
226
+ def named_type_c_name(type)
227
+ return task_type_name(type) if type.is_a?(Types::Task)
228
+ if type.is_a?(Types::VariantArmPayload)
229
+ return "#{named_type_c_name(type.variant_type)}_#{type.arm_name}"
230
+ end
231
+
232
+ if type.respond_to?(:linkage_name) && type.linkage_name
233
+ return type.linkage_name
234
+ end
235
+
236
+ base_name = type.module_name&.start_with?("std.c.") ? type.name : type.module_name ? "#{module_c_prefix(type.module_name)}_#{type.name}" : type.name
237
+ return base_name unless type.is_a?(Types::StructInstance) || type.is_a?(Types::VariantInstance)
238
+
239
+ "#{base_name}_#{sanitize_identifier(type.arguments.join('_'))}"
240
+ end
241
+
242
+ def external_opaque_c_type(type)
243
+ type.linkage_name || type.name
244
+ end
245
+
246
+ def sanitize_identifier(text)
247
+ identifier = text.gsub(SANITIZE_NON_ALNUM_RE, "_").gsub(SANITIZE_UNDERSCORES_RE, "_").sub(SANITIZE_LEADING_UNDERSCORES_RE, "").sub(SANITIZE_TRAILING_UNDERSCORES_RE, "")
248
+ identifier.empty? ? "value" : identifier
249
+ end
250
+
251
+ def module_c_prefix(module_name)
252
+ sanitize_identifier(module_name.to_s.tr('.', '_'))
253
+ end
254
+
255
+ def primitive_c_type(name)
256
+ PRIMITIVE_C_TYPE_MAP.fetch(name)
257
+ end
258
+
259
+ def generic_c_type(type)
260
+ case type.name
261
+ when "ptr"
262
+ raise CBackendError.new("ptr requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
263
+
264
+ "#{c_type(type.arguments.first)}*"
265
+ when "const_ptr"
266
+ raise CBackendError.new("const_ptr requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
267
+
268
+ "const #{c_type(type.arguments.first)}*"
269
+ when "own"
270
+ raise CBackendError.new("own requires exactly one type argument", line: 0, column: 0, path: @path) unless type.arguments.length == 1
271
+
272
+ "#{c_type(type.arguments.first)}*"
273
+ when "ref"
274
+ raise CBackendError.new("ref requires at least one type argument", line: 0, column: 0, path: @path) unless [1, 2].include?(type.arguments.length)
275
+
276
+ "#{c_type(type.arguments.length == 1 ? type.arguments.first : type.arguments[1])}*"
277
+ when "array"
278
+ raise CBackendError.new("array requires exactly two type arguments", line: 0, column: 0, path: @path) unless type.arguments.length == 2
279
+
280
+ c_type(type.arguments.first)
281
+ when "str_buffer"
282
+ raise CBackendError.new("str_buffer requires exactly one type argument", line: 0, column: 0, path: @path) unless str_buffer_type?(type)
283
+
284
+ str_buffer_type_name(type)
285
+ when "atomic"
286
+ "_Atomic #{c_type(type.arguments.first)}"
287
+ else
288
+ raise CBackendError.new("unsupported generic C type #{type.name}", line: 0, column: 0, path: @path)
289
+ end
290
+ end
291
+
292
+ def mutable_pointer_type?(type)
293
+ type.is_a?(Types::GenericInstance) && type.name == "ptr" && type.arguments.length == 1
294
+ end
295
+
296
+ def const_pointer_type?(type)
297
+ type.is_a?(Types::GenericInstance) && type.name == "const_ptr" && type.arguments.length == 1
298
+ end
299
+
300
+ def own_type?(type)
301
+ type.is_a?(Types::GenericInstance) && type.name == "own" && type.arguments.length == 1
302
+ end
303
+
304
+ def pointer_type?(type)
305
+ mutable_pointer_type?(type)
306
+ end
307
+
308
+ def c_backend_pointer_like_type?(type)
309
+ pointer_type?(type) || const_pointer_type?(type) || own_type?(type) || (type.is_a?(Types::Primitive) && type.name == "cstr") || type.is_a?(Types::Function) || type.is_a?(Types::Proc) || type.is_a?(Types::Opaque)
310
+ end
311
+
312
+ def raw_pointer_type?(type)
313
+ mutable_pointer_type?(type) || const_pointer_type?(type) || own_type?(type)
314
+ end
315
+
316
+ def ref_type?(type)
317
+ type.is_a?(Types::GenericInstance) && type.name == "ref" && [1, 2].include?(type.arguments.length)
318
+ end
319
+
320
+ def array_type?(type)
321
+ type.is_a?(Types::GenericInstance) && type.name == "array" && type.arguments.length == 2 &&
322
+ type.arguments[1].is_a?(Types::LiteralTypeArg)
323
+ end
324
+
325
+ def array_element_type(type)
326
+ type.arguments.first
327
+ end
328
+
329
+ def array_length(type)
330
+ type.arguments[1].value
331
+ end
332
+
333
+ def str_buffer_type?(type)
334
+ type.is_a?(Types::GenericInstance) && type.name == "str_buffer" && type.arguments.length == 1 &&
335
+ type.arguments.first.is_a?(Types::LiteralTypeArg) && type.arguments.first.value.is_a?(Integer)
336
+ end
337
+
338
+ def str_buffer_capacity(type)
339
+ type.arguments.first.value
340
+ end
341
+
342
+ def str_buffer_storage_capacity(type)
343
+ str_buffer_capacity(type) + 1
344
+ end
345
+
346
+ def str_buffer_type_name(type)
347
+ "mt_str_buffer_#{str_buffer_capacity(type)}"
348
+ end
349
+
350
+ def pointer_to(type)
351
+ Types::Registry.generic_instance("ptr", [type])
352
+ end
355
353
  end
356
354
  end
357
355
  end