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,482 +3,495 @@
3
3
  module MilkTea
4
4
  class CBackend
5
5
  module Expressions
6
- private
7
-
8
-
9
- def emit_expression(expression)
10
- case expression
11
- when IR::Name
12
- expression.name
13
- when IR::Member
14
- operator = pointer_member_receiver?(expression.receiver) ? "->" : "."
15
- member = "#{wrap_member_receiver(expression.receiver)}#{operator}#{sanitize_c_identifier(expression.member)}"
16
- expression.type.is_a?(Types::Primitive) && expression.type.void? ? "((void)(#{member}))" : member
17
- when IR::Index
18
- "#{wrap_index_receiver(expression.receiver)}[#{emit_expression(expression.index)}]"
19
- when IR::CheckedIndex
20
- if (alias_name = checked_index_alias(expression))
21
- "(*#{alias_name})"
22
- else
23
- "(*#{checked_array_index_helper_name(expression.receiver_type)}(#{emit_address_of_operand(expression.receiver)}, #{emit_expression(expression.index)}))"
24
- end
25
- when IR::CheckedSpanIndex
26
- if (alias_name = checked_index_alias(expression))
27
- "(*#{alias_name})"
28
- else
29
- "(*#{checked_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)}))"
30
- end
31
- when IR::NullableIndex
32
- "#{nullable_array_index_helper_name(expression.receiver_type)}(#{emit_address_of_operand(expression.receiver)}, #{emit_expression(expression.index)})"
33
- when IR::NullableSpanIndex
34
- "#{nullable_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)})"
35
- when IR::Call
36
- if array_type?(expression.type)
37
- location = [@source_path, @current_line && "line #{@current_line}"].compact.join(" ")
38
- msg = "array-return call must be materialized before C emission"
39
- msg += " (#{location})" unless location.empty?
40
- raise CBackendError.new(msg, line: @current_line, path: @source_path)
41
- end
42
-
43
- emit_call_expression(expression)
44
- when IR::Unary
45
- if expression.operator == "not"
46
- "!#{wrap_expression(expression.operand)}"
47
- else
48
- "#{expression.operator}#{wrap_expression(expression.operand)}"
49
- end
50
- when IR::Binary
51
- return emit_str_equality_expression(expression) if str_equality_expression?(expression)
52
- return emit_variant_equality_expression(expression) if variant_equality_expression?(expression)
53
- return emit_nullable_null_comparison(expression) if nullable_null_comparison?(expression)
54
-
55
- emit_binary_expression(expression)
56
- when IR::Conditional
57
- emit_conditional_expression(expression)
58
- when IR::ReinterpretExpr
59
- if no_op_reinterpret?(expression.target_type, expression.source_type)
60
- emit_expression(expression.expression)
61
- else
62
- "#{reinterpret_helper_name(expression.target_type, expression.source_type)}(#{emit_expression(expression.expression)})"
63
- end
64
- when IR::SizeofExpr
65
- "sizeof(#{layout_type_expression(expression.target_type)})"
66
- when IR::AlignofExpr
67
- "_Alignof(#{layout_type_expression(expression.target_type)})"
68
- when IR::OffsetofExpr
69
- "offsetof(#{layout_type_expression(expression.target_type)}, #{sanitize_c_identifier(expression.field)})"
70
- when IR::IntegerLiteral
71
- expression.value.to_s
72
- when IR::FloatLiteral
73
- emit_float_literal(expression)
74
- when IR::StringLiteral
75
- expression.type.is_a?(Types::StringView) ? emit_str_literal(expression) : expression.value.inspect
76
- when IR::BooleanLiteral
77
- expression.value ? "true" : "false"
78
- when IR::NullLiteral
79
- nullable_value_type?(expression.type) ? emit_zero_expression(expression.type) : "NULL"
80
- when IR::ZeroInit
81
- emit_zero_expression(expression.type)
82
- when IR::AddressOf
83
- case expression.expression
84
- when IR::CheckedIndex
85
- alias_name = checked_index_alias(expression.expression)
86
- alias_name || "#{checked_array_index_helper_name(expression.expression.receiver_type)}(#{emit_address_of_operand(expression.expression.receiver)}, #{emit_expression(expression.expression.index)})"
87
- when IR::CheckedSpanIndex
88
- alias_name = checked_index_alias(expression.expression)
89
- alias_name || "#{checked_span_index_helper_name(expression.expression.receiver_type)}(#{emit_expression(expression.expression.receiver)}, #{emit_expression(expression.expression.index)})"
90
- else
91
- emit_address_of_operand(expression.expression)
92
- end
93
- when IR::Cast
94
- if no_op_cast?(expression)
95
- emit_expression(expression.expression)
96
- else
97
- "(#{c_type(expression.target_type)}) #{emit_cast_operand(expression.expression)}"
98
- end
99
- when IR::AggregateLiteral
100
- emit_aggregate_literal(expression)
101
- when IR::ArrayLiteral
102
- emit_array_compound_literal(expression)
103
- when IR::SimdLaneWith
104
- emit_simd_lane_with(expression)
105
- when IR::VariantLiteral
106
- emit_variant_literal(expression)
107
- else
108
- raise CBackendError.new("unsupported IR expression #{expression.class.name}", line: 0, column: 0, path: @path)
109
- end
110
- end
111
-
112
- def str_equality_expression?(expression)
113
- EQUALITY_OPERATORS.include?(expression.operator) && expression.left.type.is_a?(Types::StringView) && expression.right.type.is_a?(Types::StringView)
114
- end
115
-
116
- def emit_binary_expression(expression)
117
- parent_precedence = binary_precedence(expression.operator)
118
- left = emit_binary_operand(expression.left, parent_precedence, side: :left)
119
- right = emit_binary_operand(expression.right, parent_precedence, side: :right)
120
- "#{left} #{c_operator(expression.operator)} #{right}"
121
- end
122
-
123
- def emit_binary_operand(expression, parent_precedence, side:)
124
- text = emit_expression(expression)
125
-
126
- case expression
127
- when IR::Conditional
128
- "(#{text})"
129
- when IR::Binary
130
- child_precedence = binary_precedence(expression.operator)
131
- if child_precedence < parent_precedence || (side == :right && child_precedence == parent_precedence)
132
- "(#{text})"
133
- else
134
- text
135
- end
136
- else
137
- text
138
- end
139
- end
140
-
141
- def emit_conditional_expression(expression)
142
- condition = emit_conditional_condition(expression.condition)
143
- then_expression = emit_expression(expression.then_expression)
144
- else_expression = emit_expression(expression.else_expression)
145
- "#{condition} ? #{then_expression} : #{else_expression}"
146
- end
147
-
148
- def emit_conditional_condition(expression)
149
- text = emit_expression(expression)
150
- expression.is_a?(IR::Conditional) ? "(#{text})" : text
151
- end
152
-
153
- def binary_precedence(operator)
154
- case operator
155
- when "or" then 1
156
- when "and" then 2
157
- when "|" then 3
158
- when "^" then 4
159
- when "&" then 5
160
- when "==", "!=" then 6
161
- when "<", "<=", ">", ">=" then 7
162
- when "<<", ">>" then 8
163
- when "+", "-" then 9
164
- when "*", "/", "%" then 10
165
- else
166
- raise CBackendError.new("unsupported binary operator #{operator}", line: 0, column: 0, path: @path)
167
- end
168
- end
169
-
170
- def emit_str_equality_expression(expression)
171
- call = "mt_str_equal(#{emit_expression(expression.left)}, #{emit_expression(expression.right)})"
172
- expression.operator == "!=" ? "!#{call}" : call
173
- end
174
-
175
- def variant_equality_expression?(expression)
176
- EQUALITY_OPERATORS.include?(expression.operator) &&
177
- (expression.left.type.is_a?(Types::Variant) || expression.left.type.is_a?(Types::VariantArmPayload))
178
- end
179
-
180
- def emit_variant_equality_expression(expression)
181
- helper_name = variant_equality_helper_name(expression.left.type)
182
- call = "#{helper_name}(#{emit_expression(expression.left)}, #{emit_expression(expression.right)})"
183
- expression.operator == "!=" ? "!#{call}" : call
184
- end
185
-
186
- def variant_equality_helper_name(type)
187
- variant = type.is_a?(Types::VariantArmPayload) ? type.variant_type : type
188
- "mt_variant_eq_#{named_type_c_name(variant)}"
189
- end
190
-
191
- def nullable_value_type?(type)
192
- type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(type.base)
193
- end
194
-
195
- def nullable_null_comparison?(expression)
196
- return false unless EQUALITY_OPERATORS.include?(expression.operator)
197
-
198
- (nullable_value_type?(expression.left.type) && expression.right.is_a?(IR::NullLiteral)) ||
199
- (nullable_value_type?(expression.right.type) && expression.left.is_a?(IR::NullLiteral))
200
- end
201
-
202
- def emit_nullable_null_comparison(expression)
203
- operand = expression.left.is_a?(IR::NullLiteral) ? expression.right : expression.left
204
- access = "#{wrap_member_receiver(operand)}.has_value"
205
- expression.operator == "==" ? "!#{access}" : access
206
- end
207
-
208
- def emit_initializer(expression)
209
- case expression
210
- when IR::ArrayLiteral
211
- emit_array_initializer(expression)
212
- when IR::AggregateLiteral
213
- emit_aggregate_initializer(expression)
214
- when IR::VariantLiteral
215
- emit_variant_initializer(expression)
216
- when IR::StringLiteral
217
- expression.type.is_a?(Types::StringView) ? emit_str_initializer(expression) : emit_expression(expression)
218
- when IR::ZeroInit
219
- emit_zero_initializer(expression.type)
220
- else
221
- emit_expression(expression)
222
- end
223
- end
224
-
225
- def emit_aggregate_initializer(expression)
226
- return emit_zero_initializer(expression.type) if expression.fields.empty?
227
-
228
- fields = expression.fields.map do |field|
229
- ".#{sanitize_c_identifier(field.name)} = #{emit_aggregate_field_initializer(expression.type, field)}"
230
- end.join(", ")
231
- "{ #{fields} }"
232
- end
233
-
234
- def emit_variant_initializer(expression)
235
- outer_c = named_type_c_name(expression.type)
236
- kind_constant = "#{outer_c}_kind_#{expression.arm_name}"
237
- if expression.fields.empty?
238
- "{ .kind = #{kind_constant} }"
239
- else
240
- payload_fields = expression.fields.map { |field| ".#{sanitize_c_identifier(field.name)} = #{emit_variant_field_initializer(expression.type, expression.arm_name, field)}" }.join(", ")
241
- "{ .kind = #{kind_constant}, .data.#{sanitize_c_identifier(expression.arm_name)} = { #{payload_fields} } }"
242
- end
243
- end
244
-
245
- def emit_str_initializer(expression)
246
- if @str_literal_map && @str_literal_map[expression.value]
247
- @str_literal_map[expression.value]
248
- else
249
- "{ .data = #{expression.value.inspect}, .len = #{expression.value.bytesize} }"
250
- end
251
- end
252
-
253
- def emit_aggregate_literal(expression)
254
- return emit_zero_expression(expression.type) if expression.fields.empty?
255
-
256
- fields = expression.fields.map do |field|
257
- ".#{sanitize_c_identifier(field.name)} = #{emit_aggregate_field_initializer(expression.type, field)}"
258
- end.join(", ")
259
- "(#{c_type(expression.type)}){ #{fields} }"
260
- end
261
-
262
- def emit_variant_literal(expression)
263
- outer_c = named_type_c_name(expression.type)
264
- kind_constant = "#{outer_c}_kind_#{expression.arm_name}"
265
- if expression.fields.empty?
266
- "(#{outer_c}){ .kind = #{kind_constant} }"
267
- else
268
- arm_c = "#{outer_c}_#{expression.arm_name}"
269
- payload_fields = expression.fields.map { |field| ".#{sanitize_c_identifier(field.name)} = #{emit_variant_field_initializer(expression.type, expression.arm_name, field)}" }.join(", ")
270
- "(#{outer_c}){ .kind = #{kind_constant}, .data.#{sanitize_c_identifier(expression.arm_name)} = (struct #{arm_c}){ #{payload_fields} } }"
271
- end
272
- end
273
-
274
- def emit_call_expression(expression, array_out_argument: nil)
275
- callee = expression.callee.is_a?(String) ? expression.callee : emit_call_callee(expression.callee)
276
- omit_receiver = omitted_method_receiver_call?(expression)
277
- arguments = []
278
- arguments << array_out_argument if array_out_argument
279
- arguments.concat(expression.arguments.drop(omit_receiver ? 1 : 0).map { |argument| emit_expression(argument) })
280
- call = "#{callee}(#{arguments.join(', ')})"
281
- return call unless omit_receiver && expression.arguments.any?
282
- return call if side_effect_free_expression?(expression.arguments.first)
283
-
284
- "(#{discarded_expression(expression.arguments.first)}, #{call})"
285
- end
286
-
287
- def emit_array_call_statement(expression, out_argument, indent)
288
- "#{indent}#{emit_call_expression(expression, array_out_argument: out_argument)};"
289
- end
290
-
291
- def emit_array_copy_statement(destination, source, indent)
292
- "#{indent}memcpy(#{destination}, #{emit_expression(source)}, sizeof(#{destination}));"
293
- end
294
-
295
- def emit_array_return(expression, indent)
296
- if expression.is_a?(IR::Call) && array_type?(expression.type)
297
- return [emit_array_call_statement(expression, ARRAY_OUT_PARAM_NAME, indent), "#{indent}return;"]
298
- end
299
-
300
- [
301
- emit_array_copy_statement("*#{ARRAY_OUT_PARAM_NAME}", expression, indent),
302
- "#{indent}return;",
303
- ]
304
- end
305
-
306
- def emitted_function_params(function)
307
- omitted_method_receiver_function?(function) ? function.params.drop(1) : function.params
308
- end
309
-
310
- def omitted_method_receiver_call?(expression)
311
- expression.callee.is_a?(String) && omitted_method_receiver_function_names.key?(expression.callee)
312
- end
313
-
314
- def omitted_method_receiver_function_names
315
- @omitted_method_receiver_function_names ||= emitted_functions.each_with_object({}) do |function, omitted|
316
- omitted[function.linkage_name] = true if omitted_method_receiver_function?(function)
317
- end
318
- end
319
-
320
- def omitted_method_receiver_function?(function)
321
- function.method_receiver_param &&
322
- function.params.first &&
323
- name_reference_count_in_statements(function.body, function.params.first.linkage_name).zero?
324
- end
325
-
326
- def discarded_expression(expression)
327
- "(void)#{wrap_expression(expression)}"
328
- end
329
-
330
- def emit_address_of_operand(expression)
331
- return emit_expression(expression.operand) if expression.is_a?(IR::Unary) && expression.operator == "*"
332
-
333
- "&#{wrap_expression(expression)}"
334
- end
335
-
336
- def emit_cast_operand(expression)
337
- case expression
338
- when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr, IR::AddressOf, IR::Cast, IR::Unary
339
- emit_expression(expression)
340
- else
341
- "(#{emit_expression(expression)})"
342
- end
343
- end
344
-
345
- def emit_call_callee(expression)
346
- case expression
347
- when IR::Name, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call
348
- emit_expression(expression)
349
- else
350
- wrap_expression(expression)
351
- end
352
- end
353
-
354
- def emit_array_out_argument(destination)
355
- "&#{destination}"
356
- end
357
-
358
- def emit_array_initializer(expression)
359
- return "{ 0 }" if expression.elements.empty?
360
-
361
- elements = expression.elements.map { |element| emit_initializer(element) }.join(", ")
362
- "{ #{elements} }"
363
- end
364
-
365
- def emit_array_compound_literal(expression)
366
- "(#{c_declaration(expression.type, '')}) #{emit_array_initializer(expression)}"
367
- end
368
-
369
- def emit_simd_lane_with(expression)
370
- simd_type = expression.type
371
- elem_c = primitive_c_type(simd_type.element_type.name)
372
- src = wrap_expression(expression.src)
373
- idx = emit_expression(expression.index)
374
- val = wrap_expression(expression.value)
375
- "({ #{c_type(simd_type)} _mt_with = #{src}; ((#{elem_c}*)&_mt_with)[#{idx}] = #{val}; _mt_with; })"
376
- end
377
-
378
- def emit_zero_initializer(type)
379
- return "{ 0 }" if type.is_a?(Types::StringView)
380
- return "{ 0 }" if array_type?(type)
381
- return "NULL" if type.is_a?(Types::Nullable) && c_backend_pointer_like_type?(type.base)
382
- return "{ 0 }" if type.is_a?(Types::Nullable)
383
- return "NULL" if raw_pointer_type?(type) || ref_type?(type)
384
- return "NULL" if type.is_a?(Types::Opaque) && !type.external
385
- return "false" if type.is_a?(Types::Primitive) && type.boolean?
386
- return "0.0" if type.is_a?(Types::Primitive) && type.float?
387
- return "0" if type.is_a?(Types::Primitive) && !type.void?
388
- return "(#{c_type(type)}) 0" if type.is_a?(Types::EnumBase)
389
-
390
- "{ 0 }"
391
- end
392
-
393
- def emit_zero_expression(type)
394
- return "(#{c_type(type)}) #{emit_zero_initializer(type)}" if type.is_a?(Types::StringView)
395
- return "NULL" if type.is_a?(Types::Nullable) && c_backend_pointer_like_type?(type.base)
396
- return "(#{c_type(type)}){ 0 }" if type.is_a?(Types::Nullable)
397
- return emit_zero_initializer(type) if type.is_a?(Types::Primitive)
398
- return emit_zero_initializer(type) if type.is_a?(Types::EnumBase)
399
-
400
- "(#{c_declaration(type, '')}) #{emit_zero_initializer(type)}"
401
- end
402
-
403
- def aggregate_field_type(type, field_name)
404
- return proc_field_types(type).fetch(field_name) if type.is_a?(Types::Proc)
405
- if type.is_a?(Types::Nullable)
406
- return Types::Registry.primitive("bool") if field_name == "has_value"
407
- return type.base if field_name == "value"
408
- end
409
- return type.field(field_name) if type.respond_to?(:field)
410
-
411
- raise CBackendError.new("unsupported aggregate field lookup for #{type}", line: 0, column: 0, path: @path)
412
- end
413
-
414
- def emit_aggregate_field_initializer(type, field)
415
- field_type = aggregate_field_type(type, field.name)
416
- if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
417
- emit_nullable_some_initializer(field_type, field.value)
418
- elsif void_storage_field?(field_type)
419
- emit_void_field_initializer(field.value)
420
- else
421
- emit_initializer(field.value)
422
- end
423
- end
424
-
425
- def emit_nullable_some_initializer(nullable_type, value)
426
- "(#{c_type(nullable_type)}){ .has_value = true, .value = #{emit_initializer(value)} }"
427
- end
428
-
429
- def emit_variant_field_initializer(type, arm_name, field)
430
- field_type = type.arm(arm_name).fetch(field.name)
431
- if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
432
- emit_nullable_some_initializer(field_type, field.value)
433
- elsif field.value.is_a?(IR::AddressOf) && !field_type.is_a?(Types::Nullable)
434
- c_type_name = named_type_c_name(field_type)
435
- inner = field.value.expression
436
- "((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))"
437
- elsif void_storage_field?(field_type)
438
- emit_void_field_initializer(field.value)
439
- else
440
- emit_initializer(field.value)
441
- end
442
- end
443
-
444
- def emit_void_field_initializer(expression)
445
- "(#{emit_expression(expression)}, 0)"
446
- end
447
-
448
- def void_storage_field?(type)
449
- type.is_a?(Types::Primitive) && type.void?
450
- end
451
-
452
- def emit_str_literal(expression)
453
- if @str_literal_map && @str_literal_map[expression.value]
454
- @str_literal_map[expression.value]
455
- else
456
- "(mt_str){ .data = #{expression.value.inspect}, .len = #{expression.value.bytesize} }"
457
- end
458
- end
459
-
460
- def emit_float_literal(expression)
461
- value = expression.value
462
- literal = if value.finite? && value == value.to_i
463
- format("%.1f", value)
464
- else
465
- value.to_s
466
- end
467
- expression.type.name == "float" ? "#{literal}f" : literal
468
- end
469
-
470
- def wrap_expression(expression)
471
- case expression
472
- when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr
473
- emit_expression(expression)
474
- else
475
- "(#{emit_expression(expression)})"
476
- end
477
- end
478
-
479
- def layout_type_expression(type)
480
- c_declaration(type, "")
481
- end
6
+ def emit_expression(expression)
7
+ case expression
8
+ when IR::Name
9
+ expression.name
10
+ when IR::Member
11
+ operator = pointer_member_receiver?(expression.receiver) ? "->" : "."
12
+ member = "#{wrap_member_receiver(expression.receiver)}#{operator}#{sanitize_c_identifier(expression.member)}"
13
+ expression.type.is_a?(Types::Primitive) && expression.type.void? ? "((void)(#{member}))" : member
14
+ when IR::Index
15
+ "#{wrap_index_receiver(expression.receiver)}[#{emit_expression(expression.index)}]"
16
+ when IR::CheckedIndex
17
+ if (alias_name = checked_index_alias(expression))
18
+ "(*#{alias_name})"
19
+ else
20
+ "(*#{checked_array_index_helper_name(expression.receiver_type)}(#{emit_address_of_operand(expression.receiver)}, #{emit_expression(expression.index)}))"
21
+ end
22
+ when IR::CheckedSpanIndex
23
+ if (alias_name = checked_index_alias(expression))
24
+ "(*#{alias_name})"
25
+ else
26
+ "(*#{checked_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)}))"
27
+ end
28
+ when IR::NullableIndex
29
+ "#{nullable_array_index_helper_name(expression.receiver_type)}(#{emit_address_of_operand(expression.receiver)}, #{emit_expression(expression.index)})"
30
+ when IR::NullableSpanIndex
31
+ "#{nullable_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)})"
32
+ when IR::Call
33
+ if array_type?(expression.type)
34
+ location = [@source_path, @current_line && "line #{@current_line}"].compact.join(" ")
35
+ msg = "array-return call must be materialized before C emission"
36
+ msg += " (#{location})" unless location.empty?
37
+ raise CBackendError.new(msg, line: @current_line, path: @source_path)
38
+ end
39
+
40
+ emit_call_expression(expression)
41
+ when IR::Unary
42
+ if expression.operator == "not"
43
+ "!#{wrap_expression(expression.operand)}"
44
+ else
45
+ "#{expression.operator}#{wrap_expression(expression.operand)}"
46
+ end
47
+ when IR::Binary
48
+ return emit_str_equality_expression(expression) if str_equality_expression?(expression)
49
+ return emit_variant_equality_expression(expression) if variant_equality_expression?(expression)
50
+ return emit_nullable_null_comparison(expression) if nullable_null_comparison?(expression)
51
+
52
+ emit_binary_expression(expression)
53
+ when IR::Conditional
54
+ emit_conditional_expression(expression)
55
+ when IR::ReinterpretExpr
56
+ if no_op_reinterpret?(expression.target_type, expression.source_type)
57
+ emit_expression(expression.expression)
58
+ else
59
+ "#{reinterpret_helper_name(expression.target_type, expression.source_type)}(#{emit_expression(expression.expression)})"
60
+ end
61
+ when IR::SizeofExpr
62
+ "sizeof(#{layout_type_expression(expression.target_type)})"
63
+ when IR::AlignofExpr
64
+ "_Alignof(#{layout_type_expression(expression.target_type)})"
65
+ when IR::OffsetofExpr
66
+ "offsetof(#{layout_type_expression(expression.target_type)}, #{sanitize_c_identifier(expression.field)})"
67
+ when IR::IntegerLiteral
68
+ expression.value.to_s
69
+ when IR::FloatLiteral
70
+ emit_float_literal(expression)
71
+ when IR::StringLiteral
72
+ expression.type.is_a?(Types::StringView) ? emit_str_literal(expression) : expression.value.inspect
73
+ when IR::BooleanLiteral
74
+ expression.value ? "true" : "false"
75
+ when IR::NullLiteral
76
+ nullable_value_type?(expression.type) ? emit_zero_expression(expression.type) : "NULL"
77
+ when IR::ZeroInit
78
+ emit_zero_expression(expression.type)
79
+ when IR::AddressOf
80
+ case expression.expression
81
+ when IR::CheckedIndex
82
+ alias_name = checked_index_alias(expression.expression)
83
+ alias_name || "#{checked_array_index_helper_name(expression.expression.receiver_type)}(#{emit_address_of_operand(expression.expression.receiver)}, #{emit_expression(expression.expression.index)})"
84
+ when IR::CheckedSpanIndex
85
+ alias_name = checked_index_alias(expression.expression)
86
+ alias_name || "#{checked_span_index_helper_name(expression.expression.receiver_type)}(#{emit_expression(expression.expression.receiver)}, #{emit_expression(expression.expression.index)})"
87
+ else
88
+ emit_address_of_operand(expression.expression)
89
+ end
90
+ when IR::Cast
91
+ if no_op_cast?(expression)
92
+ emit_expression(expression.expression)
93
+ else
94
+ "(#{c_type(expression.target_type)}) #{emit_cast_operand(expression.expression)}"
95
+ end
96
+ when IR::AggregateLiteral
97
+ emit_aggregate_literal(expression)
98
+ when IR::ArrayLiteral
99
+ emit_array_compound_literal(expression)
100
+ when IR::SimdLaneWith
101
+ emit_simd_lane_with(expression)
102
+ when IR::VariantLiteral
103
+ emit_variant_literal(expression)
104
+ else
105
+ raise CBackendError.new("unsupported IR expression #{expression.class.name}", line: 0, column: 0, path: @path)
106
+ end
107
+ end
108
+
109
+ def str_equality_expression?(expression)
110
+ EQUALITY_OPERATORS.include?(expression.operator) && expression.left.type.is_a?(Types::StringView) && expression.right.type.is_a?(Types::StringView)
111
+ end
112
+
113
+ def emit_binary_expression(expression)
114
+ parent_precedence = binary_precedence(expression.operator)
115
+ left = emit_binary_operand(expression.left, parent_precedence, side: :left)
116
+ right = emit_binary_operand(expression.right, parent_precedence, side: :right)
117
+ "#{left} #{c_operator(expression.operator)} #{right}"
118
+ end
119
+
120
+ def emit_binary_operand(expression, parent_precedence, side:)
121
+ text = emit_expression(expression)
122
+
123
+ case expression
124
+ when IR::Conditional
125
+ "(#{text})"
126
+ when IR::Binary
127
+ child_precedence = binary_precedence(expression.operator)
128
+ if child_precedence < parent_precedence || (side == :right && child_precedence == parent_precedence)
129
+ "(#{text})"
130
+ else
131
+ text
132
+ end
133
+ else
134
+ text
135
+ end
136
+ end
137
+
138
+ def emit_conditional_expression(expression)
139
+ condition = emit_conditional_condition(expression.condition)
140
+ then_expression = emit_expression(expression.then_expression)
141
+ else_expression = emit_expression(expression.else_expression)
142
+ "#{condition} ? #{then_expression} : #{else_expression}"
143
+ end
144
+
145
+ def emit_conditional_condition(expression)
146
+ text = emit_expression(expression)
147
+ expression.is_a?(IR::Conditional) ? "(#{text})" : text
148
+ end
149
+
150
+ def binary_precedence(operator)
151
+ case operator
152
+ when "or" then 1
153
+ when "and" then 2
154
+ when "|" then 3
155
+ when "^" then 4
156
+ when "&" then 5
157
+ when "==", "!=" then 6
158
+ when "<", "<=", ">", ">=" then 7
159
+ when "<<", ">>" then 8
160
+ when "+", "-" then 9
161
+ when "*", "/", "%" then 10
162
+ else
163
+ raise CBackendError.new("unsupported binary operator #{operator}", line: 0, column: 0, path: @path)
164
+ end
165
+ end
166
+
167
+ def emit_str_equality_expression(expression)
168
+ call = "mt_str_equal(#{emit_expression(expression.left)}, #{emit_expression(expression.right)})"
169
+ expression.operator == "!=" ? "!#{call}" : call
170
+ end
171
+
172
+ def variant_equality_expression?(expression)
173
+ EQUALITY_OPERATORS.include?(expression.operator) &&
174
+ (expression.left.type.is_a?(Types::Variant) || expression.left.type.is_a?(Types::VariantArmPayload))
175
+ end
176
+
177
+ def emit_variant_equality_expression(expression)
178
+ helper_name = variant_equality_helper_name(expression.left.type)
179
+ call = "#{helper_name}(#{emit_expression(expression.left)}, #{emit_expression(expression.right)})"
180
+ expression.operator == "!=" ? "!#{call}" : call
181
+ end
182
+
183
+ def variant_equality_helper_name(type)
184
+ variant = type.is_a?(Types::VariantArmPayload) ? type.variant_type : type
185
+ "mt_variant_eq_#{named_type_c_name(variant)}"
186
+ end
187
+
188
+ def nullable_value_type?(type)
189
+ type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(type.base)
190
+ end
191
+
192
+ def nullable_null_comparison?(expression)
193
+ return false unless EQUALITY_OPERATORS.include?(expression.operator)
194
+
195
+ (nullable_value_type?(expression.left.type) && expression.right.is_a?(IR::NullLiteral)) ||
196
+ (nullable_value_type?(expression.right.type) && expression.left.is_a?(IR::NullLiteral))
197
+ end
198
+
199
+ def emit_nullable_null_comparison(expression)
200
+ operand = expression.left.is_a?(IR::NullLiteral) ? expression.right : expression.left
201
+ access = "#{wrap_member_receiver(operand)}.has_value"
202
+ expression.operator == "==" ? "!#{access}" : access
203
+ end
204
+
205
+ def emit_initializer(expression)
206
+ case expression
207
+ when IR::ArrayLiteral
208
+ emit_array_initializer(expression)
209
+ when IR::AggregateLiteral
210
+ emit_aggregate_initializer(expression)
211
+ when IR::VariantLiteral
212
+ emit_variant_initializer(expression)
213
+ when IR::StringLiteral
214
+ expression.type.is_a?(Types::StringView) ? emit_str_initializer(expression) : emit_expression(expression)
215
+ when IR::ZeroInit
216
+ emit_zero_initializer(expression.type)
217
+ else
218
+ emit_expression(expression)
219
+ end
220
+ end
221
+
222
+ def emit_aggregate_initializer(expression)
223
+ return emit_zero_initializer(expression.type) if expression.fields.empty?
224
+
225
+ fields = expression.fields.map do |field|
226
+ ".#{sanitize_c_identifier(field.name)} = #{emit_aggregate_field_initializer(expression.type, field)}"
227
+ end.join(", ")
228
+ "{ #{fields} }"
229
+ end
230
+
231
+ def emit_variant_initializer(expression)
232
+ outer_c = named_type_c_name(expression.type)
233
+ kind_constant = "#{outer_c}_kind_#{expression.arm_name}"
234
+ if expression.fields.empty?
235
+ "{ .kind = #{kind_constant} }"
236
+ else
237
+ payload_fields = expression.fields.map { |field| ".#{sanitize_c_identifier(field.name)} = #{emit_variant_field_initializer(expression.type, expression.arm_name, field)}" }.join(", ")
238
+ "{ .kind = #{kind_constant}, .data.#{sanitize_c_identifier(expression.arm_name)} = { #{payload_fields} } }"
239
+ end
240
+ end
241
+
242
+ def emit_str_initializer(expression)
243
+ if @str_literal_map && @str_literal_map[expression.value]
244
+ @str_literal_map[expression.value]
245
+ else
246
+ "{ .data = #{expression.value.inspect}, .len = #{expression.value.bytesize} }"
247
+ end
248
+ end
249
+
250
+ def emit_aggregate_literal(expression)
251
+ return emit_zero_expression(expression.type) if expression.fields.empty?
252
+
253
+ fields = expression.fields.map do |field|
254
+ ".#{sanitize_c_identifier(field.name)} = #{emit_aggregate_field_initializer(expression.type, field)}"
255
+ end.join(", ")
256
+ "(#{c_type(expression.type)}){ #{fields} }"
257
+ end
258
+
259
+ def emit_variant_literal(expression)
260
+ outer_c = named_type_c_name(expression.type)
261
+ kind_constant = "#{outer_c}_kind_#{expression.arm_name}"
262
+ if expression.fields.empty?
263
+ "(#{outer_c}){ .kind = #{kind_constant} }"
264
+ else
265
+ arm_c = "#{outer_c}_#{expression.arm_name}"
266
+ payload_fields = expression.fields.map { |field| ".#{sanitize_c_identifier(field.name)} = #{emit_variant_field_initializer(expression.type, expression.arm_name, field)}" }.join(", ")
267
+ "(#{outer_c}){ .kind = #{kind_constant}, .data.#{sanitize_c_identifier(expression.arm_name)} = (struct #{arm_c}){ #{payload_fields} } }"
268
+ end
269
+ end
270
+
271
+ def emit_call_expression(expression, array_out_argument: nil)
272
+ callee = expression.callee.is_a?(String) ? expression.callee : emit_call_callee(expression.callee)
273
+ omit_receiver = omitted_method_receiver_call?(expression)
274
+ arguments = []
275
+ arguments << array_out_argument if array_out_argument
276
+ arguments.concat(expression.arguments.drop(omit_receiver ? 1 : 0).map { |argument| emit_expression(argument) })
277
+ call = "#{callee}(#{arguments.join(', ')})"
278
+ return call unless omit_receiver && expression.arguments.any?
279
+ return call if side_effect_free_expression?(expression.arguments.first)
280
+
281
+ "(#{discarded_expression(expression.arguments.first)}, #{call})"
282
+ end
283
+
284
+ def emit_array_call_statement(expression, out_argument, indent)
285
+ "#{indent}#{emit_call_expression(expression, array_out_argument: out_argument)};"
286
+ end
287
+
288
+ def emit_array_copy_statement(destination, source, indent)
289
+ "#{indent}memcpy(#{destination}, #{emit_expression(source)}, sizeof(#{destination}));"
290
+ end
291
+
292
+ def emit_array_return(expression, indent)
293
+ if expression.is_a?(IR::Call) && array_type?(expression.type)
294
+ return [emit_array_call_statement(expression, ARRAY_OUT_PARAM_NAME, indent), "#{indent}return;"]
295
+ end
296
+
297
+ [
298
+ emit_array_copy_statement("*#{ARRAY_OUT_PARAM_NAME}", expression, indent),
299
+ "#{indent}return;",
300
+ ]
301
+ end
302
+
303
+ def emitted_function_params(function)
304
+ omitted_method_receiver_function?(function) ? function.params.drop(1) : function.params
305
+ end
306
+
307
+ def omitted_method_receiver_call?(expression)
308
+ expression.callee.is_a?(String) && omitted_method_receiver_function_names.key?(expression.callee)
309
+ end
310
+
311
+ def omitted_method_receiver_function_names
312
+ @omitted_method_receiver_function_names ||= emitted_functions.each_with_object({}) do |function, omitted|
313
+ omitted[function.linkage_name] = true if omitted_method_receiver_function?(function)
314
+ end
315
+ end
316
+
317
+ def omitted_method_receiver_function?(function)
318
+ function.method_receiver_param &&
319
+ function.params.first &&
320
+ name_reference_count_in_statements(function.body, function.params.first.linkage_name).zero?
321
+ end
322
+
323
+ def discarded_expression(expression)
324
+ "(void)#{wrap_expression(expression)}"
325
+ end
326
+
327
+ def emit_address_of_operand(expression)
328
+ return emit_expression(expression.operand) if expression.is_a?(IR::Unary) && expression.operator == "*"
329
+
330
+ "&#{wrap_expression(expression)}"
331
+ end
332
+
333
+ def emit_cast_operand(expression)
334
+ case expression
335
+ when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr, IR::AddressOf, IR::Cast, IR::Unary
336
+ emit_expression(expression)
337
+ else
338
+ "(#{emit_expression(expression)})"
339
+ end
340
+ end
341
+
342
+ def emit_call_callee(expression)
343
+ case expression
344
+ when IR::Name, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call
345
+ emit_expression(expression)
346
+ else
347
+ wrap_expression(expression)
348
+ end
349
+ end
350
+
351
+ def emit_array_out_argument(destination)
352
+ "&#{destination}"
353
+ end
354
+
355
+ def emit_array_initializer(expression)
356
+ return "{ 0 }" if expression.elements.empty?
357
+
358
+ elements = expression.elements.map { |element| emit_initializer(element) }.join(", ")
359
+ "{ #{elements} }"
360
+ end
361
+
362
+ def emit_array_compound_literal(expression)
363
+ "(#{c_declaration(expression.type, '')}) #{emit_array_initializer(expression)}"
364
+ end
365
+
366
+ def emit_simd_lane_with(expression)
367
+ simd_type = expression.type
368
+ elem_c = primitive_c_type(simd_type.element_type.name)
369
+ src = wrap_expression(expression.src)
370
+ idx = emit_expression(expression.index)
371
+ val = wrap_expression(expression.value)
372
+ "({ #{c_type(simd_type)} _mt_with = #{src}; ((#{elem_c}*)&_mt_with)[#{idx}] = #{val}; _mt_with; })"
373
+ end
374
+
375
+ def emit_zero_initializer(type)
376
+ return "{ 0 }" if type.is_a?(Types::StringView)
377
+ return "{ 0 }" if array_type?(type)
378
+ return "NULL" if type.is_a?(Types::Nullable) && c_backend_pointer_like_type?(type.base)
379
+ return "{ 0 }" if type.is_a?(Types::Nullable)
380
+ return "NULL" if raw_pointer_type?(type) || ref_type?(type)
381
+ return "NULL" if type.is_a?(Types::Opaque) && !type.external
382
+ return "false" if type.is_a?(Types::Primitive) && type.boolean?
383
+ return "0.0" if type.is_a?(Types::Primitive) && type.float?
384
+ return "0" if type.is_a?(Types::Primitive) && !type.void?
385
+ return "(#{c_type(type)}) 0" if type.is_a?(Types::EnumBase)
386
+
387
+ "{ 0 }"
388
+ end
389
+
390
+ def emit_zero_expression(type)
391
+ return "(#{c_type(type)}) #{emit_zero_initializer(type)}" if type.is_a?(Types::StringView)
392
+ return "NULL" if type.is_a?(Types::Nullable) && c_backend_pointer_like_type?(type.base)
393
+ return "(#{c_type(type)}){ 0 }" if type.is_a?(Types::Nullable)
394
+ return emit_zero_initializer(type) if type.is_a?(Types::Primitive)
395
+ return emit_zero_initializer(type) if type.is_a?(Types::EnumBase)
396
+
397
+ "(#{c_declaration(type, '')}) #{emit_zero_initializer(type)}"
398
+ end
399
+
400
+ def aggregate_field_type(type, field_name)
401
+ return proc_field_types(type).fetch(field_name) if type.is_a?(Types::Proc)
402
+ if type.is_a?(Types::Nullable)
403
+ return Types::Registry.primitive("bool") if field_name == "has_value"
404
+ return type.base if field_name == "value"
405
+ end
406
+ return type.field(field_name) if type.respond_to?(:field)
407
+
408
+ raise CBackendError.new("unsupported aggregate field lookup for #{type}", line: 0, column: 0, path: @path)
409
+ end
410
+
411
+ def emit_aggregate_field_initializer(type, field)
412
+ field_type = aggregate_field_type(type, field.name)
413
+ if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
414
+ emit_nullable_some_initializer(field_type, field.value)
415
+ elsif void_storage_field?(field_type)
416
+ emit_void_field_initializer(field.value)
417
+ else
418
+ emit_initializer(field.value)
419
+ end
420
+ end
421
+
422
+ def emit_nullable_some_initializer(nullable_type, value)
423
+ "(#{c_type(nullable_type)}){ .has_value = true, .value = #{emit_initializer(value)} }"
424
+ end
425
+
426
+ def emit_variant_field_initializer(type, arm_name, field)
427
+ field_type = type.arm(arm_name).fetch(field.name)
428
+ if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
429
+ emit_nullable_some_initializer(field_type, field.value)
430
+ elsif field.value.is_a?(IR::AddressOf) && !field_type.is_a?(Types::Nullable)
431
+ c_type_name = named_type_c_name(field_type)
432
+ inner = field.value.expression
433
+ "((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))"
434
+ elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
435
+ array_type?(field_type)
436
+ elem_c_name = c_type(array_element_type(field_type))
437
+ elem_count = array_length(field_type)
438
+ elements = field.value.is_a?(IR::ArrayLiteral) ? field.value.elements.map { |e| emit_initializer(e) }.join(", ") : ""
439
+ "((#{elem_c_name}*)memcpy(malloc(#{elem_count} * sizeof(#{elem_c_name})), &(#{elem_c_name}[#{elem_count}]){ #{elements} }, #{elem_count} * sizeof(#{elem_c_name})))"
440
+ elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
441
+ !field_type.is_a?(Types::GenericInstance)
442
+ field_c_name = named_type_c_name(field_type)
443
+ init = emit_initializer(field.value)
444
+ source_expr = if init.start_with?("{")
445
+ "&(#{c_type(field_type)})#{init}"
446
+ else
447
+ "&(#{init})"
448
+ end
449
+ "((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
450
+ elsif void_storage_field?(field_type)
451
+ emit_void_field_initializer(field.value)
452
+ else
453
+ emit_initializer(field.value)
454
+ end
455
+ end
456
+
457
+ def emit_void_field_initializer(expression)
458
+ "(#{emit_expression(expression)}, 0)"
459
+ end
460
+
461
+ def void_storage_field?(type)
462
+ type.is_a?(Types::Primitive) && type.void?
463
+ end
464
+
465
+ def emit_str_literal(expression)
466
+ if @str_literal_map && @str_literal_map[expression.value]
467
+ @str_literal_map[expression.value]
468
+ else
469
+ "(mt_str){ .data = #{expression.value.inspect}, .len = #{expression.value.bytesize} }"
470
+ end
471
+ end
472
+
473
+ def emit_float_literal(expression)
474
+ value = expression.value
475
+ literal = if value.finite? && value == value.to_i
476
+ format("%.1f", value)
477
+ else
478
+ value.to_s
479
+ end
480
+ expression.type.name == "float" ? "#{literal}f" : literal
481
+ end
482
+
483
+ def wrap_expression(expression)
484
+ case expression
485
+ when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr
486
+ emit_expression(expression)
487
+ else
488
+ "(#{emit_expression(expression)})"
489
+ end
490
+ end
491
+
492
+ def layout_type_expression(type)
493
+ c_declaration(type, "")
494
+ end
482
495
  end
483
496
  end
484
497
  end