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,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module LowererForeignCstr
5
+ private
6
+
7
+
8
+ def lower_foreign_cstr_list_argument_value(parameter, argument_value, env:, lowered:, cleanup:)
9
+ if (direct_value = lower_direct_foreign_cstr_list_argument_value(parameter, argument_value, env:, lowered:))
10
+ return direct_value
11
+ end
12
+
13
+ public_type = parameter.type
14
+ boundary_type = parameter.boundary_type
15
+ items_type = pointer_to(pointer_to(@ctx.types.fetch("char")))
16
+ data_type = pointer_to(@ctx.types.fetch("char"))
17
+ len_type = @ctx.types.fetch("ptr_uint")
18
+ lowered_value = lower_contextual_expression(argument_value, env:, expected_type: public_type)
19
+ items_name = fresh_c_temp_name(env, "foreign_cstr_items")
20
+ data_name = fresh_c_temp_name(env, "foreign_cstr_data")
21
+ len_name = fresh_c_temp_name(env, "foreign_cstr_len")
22
+
23
+ lowered << IR::LocalDecl.new(
24
+ name: items_name,
25
+ linkage_name: items_name,
26
+ type: items_type,
27
+ value: IR::NullLiteral.new(type: items_type),
28
+ )
29
+ lowered << IR::LocalDecl.new(
30
+ name: data_name,
31
+ linkage_name: data_name,
32
+ type: data_type,
33
+ value: IR::NullLiteral.new(type: data_type),
34
+ )
35
+ lowered << IR::LocalDecl.new(
36
+ name: len_name,
37
+ linkage_name: len_name,
38
+ type: len_type,
39
+ value: IR::IntegerLiteral.new(value: 0, type: len_type),
40
+ )
41
+ lowered << IR::ExpressionStmt.new(
42
+ expression: IR::Call.new(
43
+ callee: "mt_foreign_strs_to_cstrs_temp",
44
+ arguments: [
45
+ lowered_value,
46
+ IR::AddressOf.new(expression: IR::Name.new(name: items_name, type: items_type, pointer: false), type: pointer_to(items_type)),
47
+ IR::AddressOf.new(expression: IR::Name.new(name: data_name, type: data_type, pointer: false), type: pointer_to(data_type)),
48
+ IR::AddressOf.new(expression: IR::Name.new(name: len_name, type: len_type, pointer: false), type: pointer_to(len_type)),
49
+ ],
50
+ type: @ctx.types.fetch("void"),
51
+ ),
52
+ )
53
+ cleanup << IR::ExpressionStmt.new(
54
+ expression: IR::Call.new(
55
+ callee: "mt_free_foreign_cstrs_temp",
56
+ arguments: [
57
+ IR::Name.new(name: items_name, type: items_type, pointer: false),
58
+ IR::Name.new(name: data_name, type: data_type, pointer: false),
59
+ ],
60
+ type: @ctx.types.fetch("void"),
61
+ ),
62
+ )
63
+
64
+ converted_data = foreign_identity_projection_expression(
65
+ IR::Name.new(name: items_name, type: items_type, pointer: false),
66
+ pointer_to(boundary_type.element_type),
67
+ )
68
+ raise LoweringError, "unsupported foreign boundary mapping #{public_type} as #{boundary_type}" unless converted_data
69
+
70
+ IR::AggregateLiteral.new(
71
+ type: boundary_type,
72
+ fields: [
73
+ IR::AggregateField.new(name: "data", value: converted_data),
74
+ IR::AggregateField.new(name: "len", value: IR::Name.new(name: len_name, type: len_type, pointer: false)),
75
+ ],
76
+ )
77
+ end
78
+
79
+ def lower_direct_foreign_cstr_list_argument_value(parameter, argument_value, env:, lowered:)
80
+ actual_type = infer_expression_type(argument_value, env:)
81
+ return unless array_type?(actual_type)
82
+ return unless cstr_list_backed_expression?(argument_value, env)
83
+
84
+ boundary_type = parameter.boundary_type
85
+ boundary_element_type = boundary_type.element_type
86
+ len = array_length(actual_type)
87
+ len_type = @ctx.types.fetch("ptr_uint")
88
+
89
+ if len.zero?
90
+ return IR::AggregateLiteral.new(
91
+ type: boundary_type,
92
+ fields: [
93
+ IR::AggregateField.new(name: "data", value: IR::NullLiteral.new(type: pointer_to(boundary_element_type))),
94
+ IR::AggregateField.new(name: "len", value: IR::IntegerLiteral.new(value: 0, type: len_type)),
95
+ ],
96
+ )
97
+ end
98
+
99
+ source = lower_expression(argument_value, env:, expected_type: actual_type)
100
+ item_type = array_element_type(actual_type)
101
+ items_array_type = Types::Registry.generic_instance("array", [boundary_element_type, Types::LiteralTypeArg.new(len)])
102
+ items_name = fresh_c_temp_name(env, "foreign_cstr_items")
103
+ items = (0...len).map do |index|
104
+ item = IR::Index.new(
105
+ receiver: source,
106
+ index: IR::IntegerLiteral.new(value: index, type: len_type),
107
+ type: item_type,
108
+ )
109
+ item = IR::Member.new(receiver: item, member: "data", type: pointer_to(@ctx.types.fetch("char"))) if item_type == @ctx.types.fetch("str")
110
+
111
+ converted = foreign_identity_projection_expression(item, boundary_element_type)
112
+ raise LoweringError, "unsupported foreign boundary mapping #{parameter.type} as #{boundary_type}" unless converted
113
+
114
+ converted
115
+ end
116
+
117
+ lowered << IR::LocalDecl.new(
118
+ name: items_name,
119
+ linkage_name: items_name,
120
+ type: items_array_type,
121
+ value: IR::ArrayLiteral.new(type: items_array_type, elements: items),
122
+ )
123
+
124
+ items_ref = IR::Name.new(name: items_name, type: items_array_type, pointer: false)
125
+ IR::AggregateLiteral.new(
126
+ type: boundary_type,
127
+ fields: [
128
+ IR::AggregateField.new(
129
+ name: "data",
130
+ value: IR::AddressOf.new(
131
+ expression: IR::Index.new(
132
+ receiver: items_ref,
133
+ index: IR::IntegerLiteral.new(value: 0, type: len_type),
134
+ type: boundary_element_type,
135
+ ),
136
+ type: pointer_to(boundary_element_type),
137
+ ),
138
+ ),
139
+ IR::AggregateField.new(name: "len", value: IR::IntegerLiteral.new(value: len, type: len_type)),
140
+ ],
141
+ )
142
+ end
143
+
144
+ def inlineable_foreign_argument_expression?(expression)
145
+ case expression
146
+ when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr
147
+ true
148
+ when IR::Call
149
+ return false if temporary_foreign_cstr_expression?(expression)
150
+
151
+ callee_inlineable = expression.callee.is_a?(String) || inlineable_foreign_argument_expression?(expression.callee)
152
+ callee_inlineable && expression.arguments.all? { |argument| inlineable_foreign_argument_expression?(argument) }
153
+ when IR::Member
154
+ inlineable_foreign_argument_expression?(expression.receiver)
155
+ when IR::Index
156
+ inlineable_foreign_argument_expression?(expression.receiver) && inlineable_foreign_argument_expression?(expression.index)
157
+ when IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex
158
+ inlineable_foreign_argument_expression?(expression.receiver) && inlineable_foreign_argument_expression?(expression.index)
159
+ when IR::Unary
160
+ inlineable_foreign_argument_expression?(expression.operand)
161
+ when IR::Binary
162
+ inlineable_foreign_argument_expression?(expression.left) && inlineable_foreign_argument_expression?(expression.right)
163
+ when IR::Conditional
164
+ inlineable_foreign_argument_expression?(expression.condition) &&
165
+ inlineable_foreign_argument_expression?(expression.then_expression) &&
166
+ inlineable_foreign_argument_expression?(expression.else_expression)
167
+ when IR::ReinterpretExpr, IR::Cast
168
+ inlineable_foreign_argument_expression?(expression.expression)
169
+ when IR::AddressOf
170
+ inlineable_foreign_argument_expression?(expression.expression)
171
+ when IR::AggregateLiteral
172
+ expression.fields.all? { |field| inlineable_foreign_argument_expression?(field.value) }
173
+ else
174
+ false
175
+ end
176
+ end
177
+
178
+ def lower_contextual_expression(expression, env:, expected_type:, external_numeric: false, contextual_int_to_float: false)
179
+ if string_literal_cstr_compatibility?(expression, expected_type)
180
+ return IR::StringLiteral.new(value: expression.value, type: expected_type, cstring: true)
181
+ end
182
+
183
+ lowered = lower_expression(expression, env:, expected_type: expected_type)
184
+ return lowered unless expected_type
185
+ if (materialized = materialize_pointer_backed_value(lowered, expected_type))
186
+ return materialized
187
+ end
188
+ return lowered if lowered.type == expected_type
189
+ return lower_direct_function_to_proc_expression(expression, lowered, env:, expected_type:) if direct_function_to_proc_contextual_compatibility?(expression, lowered.type, env:, expected_type:)
190
+ return lower_str_buffer_to_span_expression(lowered, expected_type) if str_buffer_to_span_compatible?(lowered.type, expected_type)
191
+ return lower_array_to_span_expression(lowered, expected_type) if array_to_span_compatible?(lowered.type, expected_type)
192
+ return cast_expression(lowered, expected_type) if contextual_numeric_compatibility?(expression, lowered.type, expected_type, env:, external_numeric:, contextual_int_to_float:)
193
+
194
+ lowered
195
+ end
196
+
197
+ def materialize_pointer_backed_value(lowered, expected_type)
198
+ return nil unless lowered.is_a?(IR::Name) && lowered.pointer
199
+ return nil unless lowered.type == expected_type
200
+ return nil if ref_type?(expected_type)
201
+ return nil if pointer_type?(expected_type)
202
+
203
+ IR::Unary.new(operator: "*", operand: lowered, type: lowered.type)
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,242 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module LowererFunctions
5
+ private
6
+
7
+
8
+ def lower_functions
9
+ lowered = []
10
+
11
+ changed = true
12
+ while changed
13
+ changed = false
14
+
15
+ expanded_declarations.each do |decl|
16
+ case decl
17
+ when AST::FunctionDef
18
+ binding = @ctx.functions.fetch(decl.name)
19
+ next if binding.body_return_type == Types::BUILTIN_TYPE_META_TYPE
20
+ if binding.type_params.any?
21
+ binding.instances.values.sort_by { |instance| instance.type_arguments.map(&:to_s).join(",") }.each do |instance|
22
+ linkage_name = function_binding_c_name(instance, module_name: @ctx.module_name)
23
+ next if @artifacts.lowered_function_linkage_names[linkage_name]
24
+
25
+ lowered << lower_function_decl(instance)
26
+ @artifacts.lowered_function_linkage_names[linkage_name] = true
27
+ changed = true
28
+ end
29
+ else
30
+ linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name)
31
+ next if @artifacts.lowered_function_linkage_names[linkage_name]
32
+
33
+ lowered << lower_function_decl(binding)
34
+ @artifacts.lowered_function_linkage_names[linkage_name] = true
35
+ if @ctx.module_name.to_s == @program.root_analysis.module_name.to_s
36
+ if (entrypoint = build_root_main_entrypoint(binding))
37
+ next if @artifacts.lowered_function_linkage_names[entrypoint.linkage_name]
38
+
39
+ lowered << entrypoint
40
+ @artifacts.lowered_function_linkage_names[entrypoint.linkage_name] = true
41
+ end
42
+ end
43
+ changed = true
44
+ end
45
+ when AST::ExtendingBlock
46
+ receiver_type = resolve_extending_receiver_type(@ctx.analysis, decl.type_name)
47
+ methods_hash = @ctx.methods[receiver_type]
48
+ unless methods_hash
49
+ methods_hash = @ctx.methods.find { |k, _| k.to_s == receiver_type.to_s }&.last
50
+ end
51
+ next unless methods_hash
52
+ decl.methods.each do |method|
53
+ binding = methods_hash[method.kind == :static ? "static:#{method.name}" : method.name]
54
+ next unless binding
55
+ if binding.type_params.any?
56
+ binding.instances.values.sort_by { |instance| instance.type_arguments.map(&:to_s).join(",") }.each do |instance|
57
+ linkage_name = function_binding_c_name(instance, module_name: @ctx.module_name, receiver_type:)
58
+ next if @artifacts.lowered_function_linkage_names[linkage_name]
59
+
60
+ lowered << lower_function_decl(instance, receiver_type:)
61
+ @artifacts.lowered_function_linkage_names[linkage_name] = true
62
+ changed = true
63
+ end
64
+ else
65
+ linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name, receiver_type:)
66
+ next if @artifacts.lowered_function_linkage_names[linkage_name]
67
+
68
+ lowered << lower_function_decl(binding, receiver_type:)
69
+ @artifacts.lowered_function_linkage_names[linkage_name] = true
70
+ changed = true
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ lowered
78
+ end
79
+
80
+ def resolve_extending_receiver_type(analysis, type_name)
81
+ if type_name.is_a?(AST::TypeRef)
82
+ generic_type = resolve_named_generic_type_for_analysis(analysis, type_name.name.parts)
83
+ if generic_type.is_a?(Types::GenericStructDefinition)
84
+ validate_methods_receiver_type_arguments!(type_name, generic_type)
85
+ return generic_type
86
+ end
87
+
88
+ begin
89
+ return resolve_type_ref_for_analysis(type_name, analysis)
90
+ rescue LoweringError => error
91
+ receiver_type_param_names = methods_receiver_type_argument_names!(type_name)
92
+ raise error if receiver_type_param_names.empty?
93
+
94
+ receiver_type_params = receiver_type_param_names.to_h { |name| [name, Types::TypeVar.new(name)] }
95
+ receiver_type = resolve_type_ref_for_analysis(type_name, analysis, type_params: receiver_type_params)
96
+ return method_dispatch_receiver_type(receiver_type)
97
+ end
98
+ end
99
+
100
+ parts = type_name.name.parts
101
+ if parts.length == 1
102
+ return types_for_module(analysis.module_name).fetch(parts.first)
103
+ end
104
+
105
+ if parts.length == 2
106
+ imported_module = imports_for_module(analysis.module_name).fetch(parts.first)
107
+ return imported_module.types.fetch(parts.last)
108
+ end
109
+
110
+ raise LoweringError, "unsupported extending target #{type_name}"
111
+ end
112
+
113
+ def lower_function_decl(binding, receiver_type: nil)
114
+ decl = binding.ast
115
+ params = []
116
+ env = empty_env
117
+ parameter_setup = []
118
+ previous_type_substitutions = @ctx.current_type_substitutions
119
+ @ctx.current_type_substitutions = binding.type_substitutions
120
+
121
+ return lower_async_function_decl(binding, receiver_type:) if binding.async
122
+
123
+ receiver_by_pointer = pointer_lowered_sync_method_receiver?(binding)
124
+
125
+ body_params = binding.body_params.dup
126
+ if binding.type.receiver_type
127
+ receiver_binding = body_params.shift
128
+ linkage_name = c_local_name(receiver_binding.name)
129
+ env[:scopes].last[receiver_binding.name] = local_binding(
130
+ type: receiver_binding.type,
131
+ linkage_name:,
132
+ mutable: receiver_binding.mutable,
133
+ pointer: receiver_by_pointer,
134
+ )
135
+ params << IR::Param.new(
136
+ name: receiver_binding.name,
137
+ linkage_name:,
138
+ type: receiver_binding.type,
139
+ pointer: receiver_by_pointer,
140
+ )
141
+ end
142
+
143
+ body_params.each_with_index do |param_binding, index|
144
+ type = param_binding.type
145
+
146
+ linkage_name = c_local_name(param_binding.name)
147
+ if array_type?(type)
148
+ input_linkage_name = "#{linkage_name}_input"
149
+ params << IR::Param.new(name: param_binding.name, linkage_name: input_linkage_name, type:, pointer: false)
150
+ env[:scopes].last[param_binding.name] = local_binding(type:, linkage_name:, mutable: false, pointer: false)
151
+ parameter_setup << IR::LocalDecl.new(
152
+ name: param_binding.name,
153
+ linkage_name:,
154
+ type:,
155
+ value: IR::Name.new(name: input_linkage_name, type:, pointer: false),
156
+ )
157
+ else
158
+ env[:scopes].last[param_binding.name] = local_binding(type:, linkage_name:, mutable: false, pointer: false)
159
+ params << IR::Param.new(name: param_binding.name, linkage_name:, type:, pointer: false)
160
+ end
161
+ end
162
+
163
+ return_type = binding.type.return_type
164
+ body = lower_block(decl.body, env:, active_defers: [], return_type:, loop_flow: nil, allow_return: true)
165
+ body = parameter_setup + body
166
+
167
+ IR::Function.new(
168
+ name: decl.name,
169
+ linkage_name: function_binding_c_name(binding, module_name: @ctx.module_name, receiver_type:),
170
+ params:,
171
+ return_type:,
172
+ body:,
173
+ entry_point: false,
174
+ method_receiver_param: !binding.type.receiver_type.nil?,
175
+ )
176
+ ensure
177
+ @ctx.current_type_substitutions = previous_type_substitutions
178
+ end
179
+
180
+ def lower_async_function_decl(binding, receiver_type: nil)
181
+ decl = binding.ast
182
+ normalized_statements = normalize_async_body(binding, decl.body)
183
+ constructor_linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name, receiver_type:)
184
+ frame_linkage_name = "#{constructor_linkage_name}__frame"
185
+ resume_linkage_name = "#{constructor_linkage_name}__resume"
186
+ ready_linkage_name = "#{constructor_linkage_name}__ready"
187
+ set_waiter_linkage_name = "#{constructor_linkage_name}__set_waiter"
188
+ release_linkage_name = "#{constructor_linkage_name}__release"
189
+ take_result_linkage_name = "#{constructor_linkage_name}__take_result"
190
+ cancel_linkage_name = "#{constructor_linkage_name}__cancel"
191
+
192
+ async_info = analyze_async_function(binding, normalized_statements)
193
+ frame_type = build_async_frame_type(frame_linkage_name, async_info)
194
+
195
+ @artifacts.synthetic_structs << IR::StructDecl.new(
196
+ name: frame_linkage_name,
197
+ linkage_name: frame_linkage_name,
198
+ fields: frame_type.fields.map { |field_name, field_type| IR::Field.new(name: field_name, type: field_type) },
199
+ packed: false,
200
+ alignment: nil,
201
+ )
202
+ @artifacts.synthetic_functions << build_async_resume_function(binding, normalized_statements, frame_type, resume_linkage_name, async_info)
203
+ @artifacts.synthetic_functions << build_async_ready_function(frame_type, ready_linkage_name, async_info)
204
+ @artifacts.synthetic_functions << build_async_set_waiter_function(frame_type, set_waiter_linkage_name, async_info)
205
+ @artifacts.synthetic_functions << build_async_release_function(frame_type, release_linkage_name, async_info)
206
+ @artifacts.synthetic_functions << build_async_take_result_function(frame_type, take_result_linkage_name, async_info)
207
+ @artifacts.synthetic_functions << build_async_cancel_function(frame_type, cancel_linkage_name, async_info)
208
+
209
+ if root_main_entrypoint_signature(binding)
210
+ @artifacts.synthetic_functions << build_async_constructor_function(
211
+ binding,
212
+ decl,
213
+ frame_type,
214
+ constructor_linkage_name,
215
+ resume_linkage_name,
216
+ ready_linkage_name,
217
+ set_waiter_linkage_name,
218
+ release_linkage_name,
219
+ take_result_linkage_name,
220
+ cancel_linkage_name,
221
+ async_info,
222
+ )
223
+
224
+ return build_async_main_entrypoint(binding, constructor_linkage_name, async_info)
225
+ end
226
+
227
+ build_async_constructor_function(
228
+ binding,
229
+ decl,
230
+ frame_type,
231
+ constructor_linkage_name,
232
+ resume_linkage_name,
233
+ ready_linkage_name,
234
+ set_waiter_linkage_name,
235
+ release_linkage_name,
236
+ take_result_linkage_name,
237
+ cancel_linkage_name,
238
+ async_info,
239
+ )
240
+ end
241
+ end
242
+ end