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,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "c_backend/aggregate_utils"
4
+ require_relative "c_backend/type_system"
5
+ require_relative "c_backend/reachability"
6
+ require_relative "c_backend/feature_detection"
7
+ require_relative "c_backend/type_collectors"
8
+ require_relative "c_backend/statements"
9
+ require_relative "c_backend/control_flow_emission"
10
+ require_relative "c_backend/runtime_helpers"
11
+ require_relative "c_backend/type_declaration"
12
+ require_relative "c_backend/expressions"
13
+ require_relative "c_backend/reinterpret"
14
+
15
+ module MilkTea
16
+ class CBackendError < StandardError
17
+ attr_reader :line, :column, :path
18
+
19
+ def initialize(msg = nil, line: nil, column: nil, path: nil)
20
+ super(msg)
21
+ @line = line
22
+ @column = column
23
+ @path = path
24
+ end
25
+
26
+ def code
27
+ "backend/internal"
28
+ end
29
+ end
30
+
31
+ class CBackend
32
+ INDENT = " "
33
+ ARRAY_OUT_PARAM_NAME = "__mt_out"
34
+
35
+ # Max iterations for loop guard counters before aborting.
36
+ # Set high enough that legitimate data-bound loops (e.g. is_valid_utf8
37
+ # scanning a 600 KB source file) never trigger a false positive, yet low
38
+ # enough that a genuinely infinite loop fires a clear fatal within ~1 s.
39
+ LOOP_GUARD_MAX_ITERATIONS = 50_000_000
40
+
41
+ def self.emit(program, emit_line_directives: true, debug_guards: false)
42
+ new(program, emit_line_directives:, debug_guards:).emit
43
+ end
44
+
45
+ def self.generate_c(ir_program, emit_line_directives: true, debug_guards: false)
46
+ emit(ir_program, emit_line_directives:, debug_guards:)
47
+ end
48
+
49
+ def initialize(program, emit_line_directives: true, debug_guards: false)
50
+ @program = program
51
+ @emit_line_directives = emit_line_directives
52
+ @debug_guards = debug_guards
53
+ @checked_index_alias_stack = []
54
+ @checked_index_alias_id = 0
55
+ @loop_guard_id = 0
56
+ @emitted_span_type_names = Set.new
57
+ end
58
+
59
+ def emit
60
+ lines = []
61
+ constants = emitted_constants
62
+ headers = @program.includes.map(&:header)
63
+ if headers.include?("\"fs_support.h\"") || headers.include?("\"tls_support.h\"") || uses_parallel_for_helper? || uses_spawn_all_helper? || uses_detach_helper?
64
+ lines << "#ifndef _GNU_SOURCE"
65
+ lines << "#define _GNU_SOURCE"
66
+ lines << "#endif"
67
+ lines << "#ifndef _POSIX_C_SOURCE"
68
+ lines << "#define _POSIX_C_SOURCE 200809L"
69
+ lines << "#endif"
70
+ lines << ""
71
+ end
72
+ if uses_fatal_helper? || uses_format_helpers?
73
+ headers << "<stdio.h>"
74
+ end
75
+ if uses_fatal_helper? || uses_format_helpers? || uses_async_memory_helpers? || uses_foreign_temp_cstr_helpers? || uses_detach_helper?
76
+ headers << "<stdlib.h>"
77
+ end
78
+ if uses_parallel_for_helper? || uses_spawn_all_helper? || uses_detach_helper?
79
+ headers << "\"uv.h\""
80
+ end
81
+ headers.uniq.each do |header|
82
+ lines << "#include #{header}"
83
+ end
84
+ lines << ""
85
+
86
+ if uses_string_view?
87
+ lines.concat(emit_string_type)
88
+ lines << ""
89
+ end
90
+
91
+ if uses_vector_math_types?
92
+ lines.concat(emit_vector_math_types)
93
+ lines << ""
94
+ end
95
+
96
+ if uses_fatal_helper?
97
+ lines.concat(emit_fatal_helper)
98
+ lines << ""
99
+ end
100
+
101
+ if uses_format_helpers?
102
+ lines.concat(emit_format_helpers)
103
+ lines << ""
104
+ end
105
+
106
+ if uses_fmt_builder?
107
+ lines.concat(emit_fmt_builder_helpers)
108
+ lines << ""
109
+ end
110
+
111
+ if uses_str_equality_helper?
112
+ lines.concat(emit_str_equality_helper)
113
+ lines << ""
114
+ end
115
+
116
+ if uses_text_buffer_helpers?
117
+ lines.concat(emit_text_buffer_helpers)
118
+ lines << ""
119
+ end
120
+
121
+ if uses_async_memory_helpers?
122
+ lines.concat(emit_async_memory_helpers)
123
+ lines << ""
124
+ end
125
+
126
+ if uses_parallel_for_helper?
127
+ lines.concat(emit_parallel_for_helper)
128
+ lines << ""
129
+ end
130
+
131
+ if uses_spawn_all_helper?
132
+ lines.concat(emit_spawn_all_helper)
133
+ lines << ""
134
+ end
135
+
136
+ if uses_detach_helper?
137
+ lines.concat(emit_detach_helpers)
138
+ lines << ""
139
+ end
140
+
141
+ opaque_decls = @program.opaques
142
+ aggregate_decls = sort_aggregate_decls(
143
+ emitted_aggregate_structs + collect_generic_struct_decls + collect_task_decls + collect_proc_decls + collect_dyn_decls + collect_str_buffer_decls + collect_nullable_opt_decls,
144
+ emitted_aggregate_unions,
145
+ emitted_aggregate_variants + collect_generic_variant_decls,
146
+ )
147
+
148
+ forward_declarations = emit_forward_declarations(opaque_decls, aggregate_decls)
149
+ unless forward_declarations.empty?
150
+ lines.concat(forward_declarations)
151
+ lines << ""
152
+ end
153
+
154
+ @program.enums.each do |enum_decl|
155
+ lines.concat(emit_enum(enum_decl))
156
+ lines << ""
157
+ end
158
+
159
+ collect_span_types.each do |type|
160
+ span_name = span_type_name(type)
161
+ next if @emitted_span_type_names.include?(span_name)
162
+ @emitted_span_type_names.add(span_name)
163
+ lines.concat(emit_span_type(type))
164
+ lines << ""
165
+ end
166
+
167
+ collect_soa_types.each do |type|
168
+ lines.concat(emit_soa_type(type))
169
+ lines << ""
170
+ end
171
+
172
+ if uses_entrypoint_argv_helpers?
173
+ lines.concat(emit_entrypoint_argv_helpers)
174
+ lines << ""
175
+ end
176
+
177
+ if uses_foreign_temp_cstr_helpers?
178
+ lines.concat(emit_foreign_temp_cstr_helpers)
179
+ lines << ""
180
+ end
181
+
182
+ if uses_str_buffer_helpers?
183
+ lines.concat(emit_str_buffer_helpers)
184
+ lines << ""
185
+ end
186
+
187
+ aggregate_decls.each do |aggregate_decl|
188
+ case aggregate_decl
189
+ when IR::StructDecl
190
+ lines.concat(emit_struct(aggregate_decl))
191
+ when IR::UnionDecl
192
+ lines.concat(emit_union(aggregate_decl))
193
+ when IR::VariantDecl
194
+ lines.concat(emit_variant(aggregate_decl))
195
+ end
196
+ lines << ""
197
+ end
198
+
199
+ if uses_variant_equality_helper?
200
+ lines.concat(emit_str_equality_helper) unless uses_str_equality_helper?
201
+ lines.concat(emit_variant_equality_helpers)
202
+ lines << ""
203
+ end
204
+
205
+ function_declarations = emit_function_declarations(emitted_functions)
206
+ unless function_declarations.empty?
207
+ lines.concat(function_declarations)
208
+ lines << ""
209
+ end
210
+
211
+ constants.each do |constant|
212
+ lines << "#{constant_storage(constant.type)} #{c_declaration(constant.type, constant.linkage_name)} = #{emit_initializer(constant.value)};"
213
+ end
214
+ @program.globals.each do |global|
215
+ next unless emitted_globals.include?(global)
216
+ lines << "#{global_storage(global.type)} #{c_declaration(global.type, global.linkage_name)} = #{emit_initializer(global.value)};"
217
+ end
218
+ lines << "" unless constants.empty? && @program.globals.empty?
219
+
220
+ @program.static_asserts.each do |statement|
221
+ lines << emit_static_assert(statement)
222
+ end
223
+ lines << "" unless @program.static_asserts.empty?
224
+
225
+ reinterpret_helpers = collect_reinterpret_helpers
226
+ reinterpret_helpers.each do |helper|
227
+ lines.concat(emit_reinterpret_helper(helper))
228
+ lines << ""
229
+ end
230
+
231
+ checked_array_index_types = collect_checked_array_index_types
232
+ checked_array_index_types.each do |type|
233
+ lines.concat(emit_checked_array_index_helper(type))
234
+ lines << ""
235
+ end
236
+
237
+ checked_span_index_types = collect_checked_span_index_types
238
+ checked_span_index_types.each do |type|
239
+ lines.concat(emit_checked_span_index_helper(type))
240
+ lines << ""
241
+ end
242
+
243
+ nullable_array_index_types = collect_checked_array_index_types(nullable_only: true)
244
+ nullable_array_index_types.each do |type|
245
+ lines.concat(emit_nullable_array_index_helper(type))
246
+ lines << ""
247
+ end
248
+
249
+ nullable_span_index_types = collect_checked_span_index_types(nullable_only: true)
250
+ nullable_span_index_types.each do |type|
251
+ lines.concat(emit_nullable_span_index_helper(type))
252
+ lines << ""
253
+ end
254
+
255
+ str_literals = collect_str_literals
256
+ unless str_literals.empty?
257
+ @str_literal_map = {}
258
+ str_literals.each_with_index { |value, i| @str_literal_map[value] = str_literal_name(i) }
259
+ lines.concat(emit_str_literal_constants(str_literals))
260
+ lines << ""
261
+ end
262
+
263
+ emitted_functions.each do |function|
264
+ lines.concat(emit_function(function))
265
+ lines << ""
266
+ end
267
+
268
+ lines.join("\n").rstrip + "\n"
269
+ end
270
+
271
+ private
272
+
273
+ EQUALITY_OPERATORS = ["==", "!="].freeze
274
+
275
+ include AggregateUtils
276
+ include TypeSystem
277
+ include Reachability
278
+ include FeatureDetection
279
+ include TypeCollectors
280
+ include Statements
281
+ include ControlFlowEmission
282
+ include RuntimeHelpers
283
+ include TypeDeclaration
284
+ include Expressions
285
+ include Reinterpret
286
+ end
287
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "types/predicates"
4
+
5
+ module MilkTea
6
+ module CompatibilityHelpers
7
+ include TypePredicates
8
+
9
+ BUILTIN_CSTR = Types::Registry.primitive("cstr")
10
+
11
+ EVENT_METHOD_KINDS = {
12
+ "subscribe" => :event_subscribe,
13
+ "subscribe_once" => :event_subscribe_once,
14
+ "unsubscribe" => :event_unsubscribe,
15
+ "emit" => :event_emit,
16
+ "wait" => :event_wait,
17
+ }.freeze
18
+
19
+ EVENT_METHOD_NAMES = EVENT_METHOD_KINDS.invert.freeze
20
+
21
+ STR_BUFFER_METHOD_KINDS = {
22
+ "clear" => :str_buffer_clear,
23
+ "assign" => :str_buffer_assign,
24
+ "append" => :str_buffer_append,
25
+ "assign_format" => :str_buffer_assign_format,
26
+ "append_format" => :str_buffer_append_format,
27
+ "len" => :str_buffer_len,
28
+ "capacity" => :str_buffer_capacity,
29
+ "as_str" => :str_buffer_as_str,
30
+ "as_cstr" => :str_buffer_as_cstr,
31
+ }.freeze
32
+
33
+ STR_BUFFER_METHOD_NAMES = STR_BUFFER_METHOD_KINDS.invert.freeze
34
+
35
+ ATOMIC_METHOD_KINDS = {
36
+ "load" => :atomic_load,
37
+ "store" => :atomic_store,
38
+ "add" => :atomic_add,
39
+ "sub" => :atomic_sub,
40
+ "exchange" => :atomic_exchange,
41
+ "compare_exchange" => :atomic_compare_exchange,
42
+ }.freeze
43
+
44
+ def type_ref_from_specialization(expression)
45
+ case expression.callee
46
+ when AST::Identifier
47
+ return nil if %w[zero default reinterpret].include?(expression.callee.name)
48
+
49
+ AST::TypeRef.new(name: AST::QualifiedName.new(parts: [expression.callee.name]), arguments: expression.arguments, nullable: false)
50
+ when AST::MemberAccess
51
+ return nil unless expression.callee.receiver.is_a?(AST::Identifier)
52
+
53
+ AST::TypeRef.new(
54
+ name: AST::QualifiedName.new(parts: [expression.callee.receiver.name, expression.callee.member]),
55
+ arguments: expression.arguments,
56
+ nullable: false,
57
+ )
58
+ end
59
+ end
60
+
61
+ def event_subscription_result_type
62
+ @ctx.types.fetch("Result").instantiate([@ctx.types.fetch("Subscription"), @ctx.types.fetch("EventError")])
63
+ end
64
+
65
+ def event_wait_result_type(event_type)
66
+ @ctx.types.fetch("Result").instantiate([event_type.payload_type || @ctx.types.fetch("void"), @ctx.types.fetch("EventError")])
67
+ end
68
+
69
+ def range_expr?(expression)
70
+ expression.is_a?(AST::RangeExpr)
71
+ end
72
+
73
+ private
74
+
75
+ def string_literal_cstr_compatibility?(expression, expected_type)
76
+ expression.is_a?(AST::StringLiteral) && !expression.cstring && expected_type == BUILTIN_CSTR
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../types/layout"
4
+
5
+ module MilkTea
6
+ module ConstEval
7
+ module_function
8
+
9
+ def evaluate(expression, resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
10
+ Evaluator.new(
11
+ resolve_identifier:,
12
+ resolve_member_access:,
13
+ resolve_type_ref:,
14
+ resolve_call:,
15
+ ).evaluate(expression)
16
+ end
17
+
18
+ def equality_result(left, right)
19
+ return left == right if left.is_a?(Numeric) && right.is_a?(Numeric)
20
+ return left == right if left.is_a?(String) && right.is_a?(String)
21
+ return left == right if boolean_value?(left) && boolean_value?(right)
22
+ return left == right if left.is_a?(Types::Base) && right.is_a?(Types::Base)
23
+
24
+ nil
25
+ end
26
+
27
+ def boolean_value?(value)
28
+ value == true || value == false
29
+ end
30
+
31
+ class Evaluator
32
+ include Layout
33
+
34
+ def initialize(resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
35
+ @resolve_identifier = resolve_identifier
36
+ @resolve_member_access = resolve_member_access
37
+ @resolve_type_ref = resolve_type_ref
38
+ @resolve_call = resolve_call
39
+ end
40
+
41
+ def evaluate(expression)
42
+ case expression
43
+ when AST::ErrorExpr
44
+ nil
45
+ when AST::ExpressionList
46
+ expression.elements.filter_map { |element| evaluate(element) }
47
+ when AST::IntegerLiteral, AST::FloatLiteral, AST::BooleanLiteral
48
+ expression.value
49
+ when AST::StringLiteral
50
+ expression.value
51
+ when AST::Identifier
52
+ @resolve_identifier&.call(expression)
53
+ when AST::MemberAccess
54
+ @resolve_member_access&.call(expression)
55
+ when AST::Call
56
+ @resolve_call&.call(expression)
57
+ when AST::Specialization
58
+ @resolve_call&.call(expression)
59
+ when AST::SizeofExpr
60
+ type = resolve_layout_type(expression.type)
61
+ type && size_of(type)
62
+ when AST::AlignofExpr
63
+ type = resolve_layout_type(expression.type)
64
+ type && alignment_of(type)
65
+ when AST::OffsetofExpr
66
+ type = resolve_layout_type(expression.type)
67
+ if type
68
+ result = offset_of(type, expression.field)
69
+ return result if result
70
+
71
+ id_expr = AST::Identifier.new(name: expression.field)
72
+ value = @resolve_identifier&.call(id_expr)
73
+ if value.is_a?(Types::FieldHandle)
74
+ return offset_of(type, value.field_name)
75
+ end
76
+ end
77
+ nil
78
+ when AST::UnaryOp
79
+ evaluate_unary(expression)
80
+ when AST::BinaryOp
81
+ evaluate_binary(expression)
82
+ when AST::IfExpr
83
+ condition = evaluate(expression.condition)
84
+ return unless ConstEval.boolean_value?(condition)
85
+
86
+ evaluate(condition ? expression.then_expression : expression.else_expression)
87
+ else
88
+ nil
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def resolve_layout_type(type_ref)
95
+ return unless @resolve_type_ref
96
+
97
+ @resolve_type_ref.call(type_ref)
98
+ end
99
+
100
+ def evaluate_unary(expression)
101
+ operand = evaluate(expression.operand)
102
+
103
+ case expression.operator
104
+ when "+"
105
+ operand.is_a?(Numeric) ? operand : nil
106
+ when "-"
107
+ operand.is_a?(Numeric) ? -operand : nil
108
+ when "~"
109
+ operand.is_a?(Integer) ? ~operand : nil
110
+ when "not"
111
+ ConstEval.boolean_value?(operand) ? !operand : nil
112
+ end
113
+ end
114
+
115
+ def evaluate_binary(expression)
116
+ left = evaluate(expression.left)
117
+
118
+ case expression.operator
119
+ when "and"
120
+ return unless ConstEval.boolean_value?(left)
121
+ return false if left == false
122
+
123
+ right = evaluate(expression.right)
124
+ return right if ConstEval.boolean_value?(right)
125
+
126
+ return nil
127
+ when "or"
128
+ return unless ConstEval.boolean_value?(left)
129
+ return true if left == true
130
+
131
+ right = evaluate(expression.right)
132
+ return right if ConstEval.boolean_value?(right)
133
+
134
+ return nil
135
+ end
136
+
137
+ right = evaluate(expression.right)
138
+
139
+ case expression.operator
140
+ when "=="
141
+ ConstEval.equality_result(left, right)
142
+ when "!="
143
+ result = ConstEval.equality_result(left, right)
144
+ result.nil? ? nil : !result
145
+ when "+"
146
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left + right : nil
147
+ when "-"
148
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left - right : nil
149
+ when "*"
150
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left * right : nil
151
+ when "/"
152
+ return unless left.is_a?(Numeric) && right.is_a?(Numeric)
153
+ raise CompileTime::Error, "division by zero" if zero_numeric?(right)
154
+
155
+ left / right
156
+ when "%"
157
+ return unless left.is_a?(Integer) && right.is_a?(Integer)
158
+ raise CompileTime::Error, "modulo by zero" if right.zero?
159
+
160
+ left % right
161
+ when "<<"
162
+ left.is_a?(Integer) && right.is_a?(Integer) ? left << right : nil
163
+ when ">>"
164
+ left.is_a?(Integer) && right.is_a?(Integer) ? left >> right : nil
165
+ when "&"
166
+ left.is_a?(Integer) && right.is_a?(Integer) ? left & right : nil
167
+ when "|"
168
+ left.is_a?(Integer) && right.is_a?(Integer) ? left | right : nil
169
+ when "^"
170
+ left.is_a?(Integer) && right.is_a?(Integer) ? left ^ right : nil
171
+ when "<"
172
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left < right : nil
173
+ when "<="
174
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left <= right : nil
175
+ when ">"
176
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left > right : nil
177
+ when ">="
178
+ left.is_a?(Numeric) && right.is_a?(Numeric) ? left >= right : nil
179
+ end
180
+ end
181
+
182
+ def zero_numeric?(value)
183
+ (value.is_a?(Integer) && value.zero?) || (value.is_a?(Float) && value.zero?)
184
+ end
185
+ end
186
+ end
187
+ end