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,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module LowererScans
5
+ private
6
+
7
+ def collect_structs
8
+ @ctx.ast.declarations.each do |decl|
9
+ case decl
10
+ when AST::WhenStmt
11
+ body = lower_when_chosen_body(decl)
12
+ body&.each { |nested| collect_struct_from_decl(nested) }
13
+ when AST::OpaqueDecl
14
+ @ctx.opaque_types[decl.name] = @ctx.types.fetch(decl.name)
15
+ when AST::StructDecl
16
+ @ctx.struct_types[decl.name] = @ctx.types.fetch(decl.name)
17
+ collect_nested_structs(decl)
18
+ when AST::UnionDecl
19
+ @ctx.union_types[decl.name] = @ctx.types.fetch(decl.name)
20
+ end
21
+ end
22
+ end
23
+
24
+ def collect_struct_from_decl(decl)
25
+ case decl
26
+ when AST::OpaqueDecl
27
+ @ctx.opaque_types[decl.name] = @ctx.types.fetch(decl.name)
28
+ when AST::StructDecl
29
+ @ctx.struct_types[decl.name] = @ctx.types.fetch(decl.name)
30
+ collect_nested_structs(decl)
31
+ when AST::UnionDecl
32
+ @ctx.union_types[decl.name] = @ctx.types.fetch(decl.name)
33
+ when AST::WhenStmt
34
+ body = lower_when_chosen_body(decl)
35
+ body&.each { |nested| collect_struct_from_decl(nested) }
36
+ end
37
+ end
38
+
39
+ def lower_when_chosen_body(decl)
40
+ val = compile_time_const_value(decl.discriminant)
41
+ return nil if val.nil?
42
+
43
+ chosen = decl.branches.find { |b| val == compile_time_const_value(b.pattern) }
44
+ chosen&.body || decl.else_body
45
+ end
46
+
47
+ def collect_nested_structs(parent_decl, parent_name: parent_decl.name)
48
+ parent_decl.nested_types.each do |nested|
49
+ qualified_name = "#{parent_name}.#{nested.name}"
50
+ @ctx.struct_types[qualified_name] = @ctx.types.fetch(qualified_name)
51
+ collect_nested_structs(nested, parent_name: qualified_name)
52
+ end
53
+ end
54
+
55
+ def collect_includes
56
+ headers = ["<stdbool.h>", "<stdint.h>", "<string.h>"]
57
+ headers << "<stddef.h>" if program_uses_offsetof?
58
+ headers << "<stdio.h>" if program_uses_fatal?
59
+
60
+ each_raw_module_analysis do |analysis|
61
+ analysis.directives.grep(AST::IncludeDirective).each do |directive|
62
+ headers << normalized_include_header(directive.value)
63
+ end
64
+ end
65
+
66
+ headers.uniq.map { |header| IR::Include.new(header:) }
67
+ end
68
+
69
+ def normalized_include_header(header_name)
70
+ return "<#{header_name}>" if standard_c_runtime_header?(header_name)
71
+
72
+ %("#{header_name}")
73
+ end
74
+
75
+ def standard_c_runtime_header?(header_name)
76
+ %w[stdbool.h stdint.h stdlib.h string.h stddef.h stdio.h time.h].include?(header_name)
77
+ end
78
+
79
+ def program_uses_fatal?
80
+ each_non_raw_module_analysis.any? do |analysis|
81
+ analysis_uses_fatal?(analysis)
82
+ end
83
+ end
84
+
85
+ def program_uses_offsetof?
86
+ each_non_raw_module_analysis.any? do |analysis|
87
+ analysis_uses_offsetof?(analysis)
88
+ end
89
+ end
90
+
91
+ def analysis_uses_fatal?(analysis)
92
+ analysis.ast.declarations.any? do |decl|
93
+ case decl
94
+ when AST::FunctionDef
95
+ block_uses_fatal?(decl.body)
96
+ when AST::ExtendingBlock
97
+ decl.methods.any? { |method| block_uses_fatal?(method.body) }
98
+ else
99
+ false
100
+ end
101
+ end
102
+ end
103
+
104
+ def analysis_uses_offsetof?(analysis)
105
+ analysis.ast.declarations.any? do |decl|
106
+ case decl
107
+ when AST::FunctionDef
108
+ block_uses_offsetof?(decl.body)
109
+ when AST::ExtendingBlock
110
+ decl.methods.any? { |method| block_uses_offsetof?(method.body) }
111
+ else
112
+ false
113
+ end
114
+ end
115
+ end
116
+
117
+ def block_uses_fatal?(statements)
118
+ block_uses_expression_pattern?(statements) { |expression| fatal_expression?(expression) }
119
+ end
120
+
121
+ def block_uses_offsetof?(statements)
122
+ block_uses_expression_pattern?(statements) { |expression| offsetof_expression?(expression) }
123
+ end
124
+
125
+ def block_uses_expression_pattern?(statements, &predicate)
126
+ statements.any? { |statement| statement_uses_expression_pattern?(statement, &predicate) }
127
+ end
128
+
129
+ def statement_uses_expression_pattern?(statement, &predicate)
130
+ case statement
131
+ when AST::LocalDecl
132
+ expression_uses_pattern?(statement.value, &predicate)
133
+ when AST::Assignment
134
+ expression_uses_pattern?(statement.target, &predicate) || expression_uses_pattern?(statement.value, &predicate)
135
+ when AST::IfStmt
136
+ statement.branches.any? { |branch| expression_uses_pattern?(branch.condition, &predicate) || block_uses_expression_pattern?(branch.body, &predicate) } ||
137
+ (statement.else_body && block_uses_expression_pattern?(statement.else_body, &predicate))
138
+ when AST::MatchStmt
139
+ expression_uses_pattern?(statement.expression, &predicate) || statement.arms.any? { |arm| expression_uses_pattern?(arm.pattern, &predicate) || block_uses_expression_pattern?(arm.body, &predicate) }
140
+ when AST::StaticAssert
141
+ expression_uses_pattern?(statement.condition, &predicate) || expression_uses_pattern?(statement.message, &predicate)
142
+ when AST::ForStmt
143
+ statement.iterables.any? { |iterable| expression_uses_pattern?(iterable, &predicate) } || block_uses_expression_pattern?(statement.body, &predicate)
144
+ when AST::UnsafeStmt, AST::WhileStmt
145
+ expression = statement.is_a?(AST::WhileStmt) ? statement.condition : nil
146
+ (expression && expression_uses_pattern?(expression, &predicate)) || block_uses_expression_pattern?(statement.body, &predicate)
147
+ when AST::ReturnStmt
148
+ statement.value && expression_uses_pattern?(statement.value, &predicate)
149
+ when AST::DeferStmt, AST::ExpressionStmt
150
+ expression_uses_pattern?(statement.expression, &predicate)
151
+ else
152
+ false
153
+ end
154
+ end
155
+
156
+ def fatal_expression?(expression)
157
+ expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier) && expression.callee.name == "fatal"
158
+ end
159
+
160
+ def offsetof_expression?(expression)
161
+ expression.is_a?(AST::OffsetofExpr)
162
+ end
163
+
164
+ def expression_uses_pattern?(expression, &predicate)
165
+ return false unless expression
166
+ return true if predicate.call(expression)
167
+
168
+ case expression
169
+ when AST::AwaitExpr
170
+ expression_uses_pattern?(expression.expression, &predicate)
171
+ when AST::Call
172
+ expression_uses_pattern?(expression.callee, &predicate) || expression.arguments.any? { |argument| expression_uses_pattern?(argument.value, &predicate) }
173
+ when AST::BinaryOp
174
+ expression_uses_pattern?(expression.left, &predicate) || expression_uses_pattern?(expression.right, &predicate)
175
+ when AST::RangeExpr
176
+ expression_uses_pattern?(expression.start_expr, &predicate) || expression_uses_pattern?(expression.end_expr, &predicate)
177
+ when AST::IfExpr
178
+ expression_uses_pattern?(expression.condition, &predicate) || expression_uses_pattern?(expression.then_expression, &predicate) || expression_uses_pattern?(expression.else_expression, &predicate)
179
+ when AST::MatchExpr
180
+ expression_uses_pattern?(expression.expression, &predicate) || expression.arms.any? { |arm| expression_uses_pattern?(arm.pattern, &predicate) || expression_uses_pattern?(arm.value, &predicate) }
181
+ when AST::UnsafeExpr
182
+ expression_uses_pattern?(expression.expression, &predicate)
183
+ when AST::PrefixCast
184
+ expression_uses_pattern?(expression.expression, &predicate)
185
+ when AST::UnaryOp
186
+ expression_uses_pattern?(expression.operand, &predicate)
187
+ when AST::MemberAccess
188
+ expression_uses_pattern?(expression.receiver, &predicate)
189
+ when AST::IndexAccess
190
+ expression_uses_pattern?(expression.receiver, &predicate) || expression_uses_pattern?(expression.index, &predicate)
191
+ when AST::Specialization
192
+ expression_uses_pattern?(expression.callee, &predicate) || expression.arguments.any? { |argument| expression_uses_pattern?(argument.value, &predicate) }
193
+ else
194
+ false
195
+ end
196
+ end
197
+
198
+ def prepare_analysis(analysis, source_path: nil)
199
+ @ctx.install(analysis)
200
+ @ctx.current_analysis_path = source_path
201
+ @ctx.module_prefix = module_c_prefix(@ctx.module_name)
202
+ end
203
+
204
+ private def sanitize_type_name_for_tuple(type)
205
+ type.to_s.gsub(/[^a-zA-Z0-9]/, "_").gsub(/_+/, "_").gsub(/^_|_$/, "")
206
+ end
207
+
208
+ def build_method_definitions
209
+ @program.analyses_by_path.values.each_with_object({}) do |analysis, definitions|
210
+ analysis.ast.declarations.grep(AST::ExtendingBlock).each do |extending_block|
211
+ receiver_type = resolve_extending_receiver_type(analysis, extending_block.type_name)
212
+ extending_block.methods.each do |method|
213
+ method_key = method.kind == :static ? "static:#{method.name}" : method.name
214
+ definitions[[receiver_type, method_key]] = [analysis, method]
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module LowererStrBuffer
5
+ private
6
+
7
+
8
+ def str_buffer_method_kind(receiver_type, name)
9
+ return unless str_buffer_type?(receiver_type)
10
+
11
+ case name
12
+ when "clear"
13
+ :str_buffer_clear
14
+ when "assign"
15
+ :str_buffer_assign
16
+ when "append"
17
+ :str_buffer_append
18
+ when "assign_format"
19
+ :str_buffer_assign_format
20
+ when "append_format"
21
+ :str_buffer_append_format
22
+ when "len"
23
+ :str_buffer_len
24
+ when "capacity"
25
+ :str_buffer_capacity
26
+ when "as_str"
27
+ :str_buffer_as_str
28
+ when "as_cstr"
29
+ :str_buffer_as_cstr
30
+ end
31
+ end
32
+
33
+ def str_buffer_method_type(kind, receiver_type)
34
+ return_type, params = case kind
35
+ when :str_buffer_clear
36
+ [@ctx.types.fetch("void"), []]
37
+ when :str_buffer_assign, :str_buffer_append, :str_buffer_assign_format, :str_buffer_append_format
38
+ [@ctx.types.fetch("void"), [Types::Registry.parameter("value", @ctx.types.fetch("str"))]]
39
+ when :str_buffer_len, :str_buffer_capacity
40
+ [@ctx.types.fetch("ptr_uint"), []]
41
+ when :str_buffer_as_str
42
+ [@ctx.types.fetch("str"), []]
43
+ when :str_buffer_as_cstr
44
+ [@ctx.types.fetch("cstr"), []]
45
+ else
46
+ raise LoweringError, "unsupported str_buffer method #{kind}"
47
+ end
48
+
49
+ Types::Registry.function(
50
+ kind.to_s,
51
+ params:,
52
+ return_type:,
53
+ receiver_type:,
54
+ receiver_editable: %i[str_buffer_clear str_buffer_assign str_buffer_append str_buffer_assign_format str_buffer_append_format].include?(kind),
55
+ external: false,
56
+ )
57
+ end
58
+
59
+ def lower_char_array_data_pointer(expression, env:)
60
+ lowered_receiver = lower_expression(expression, env:)
61
+ IR::AddressOf.new(
62
+ expression: IR::Index.new(
63
+ receiver: lowered_receiver,
64
+ index: IR::IntegerLiteral.new(value: 0, type: @ctx.types.fetch("ptr_uint")),
65
+ type: @ctx.types.fetch("char"),
66
+ ),
67
+ type: pointer_to(@ctx.types.fetch("char")),
68
+ )
69
+ end
70
+
71
+ def lower_str_buffer_data_pointer(expression, env:)
72
+ lower_str_buffer_data_pointer_from_lowered(lower_expression(expression, env:))
73
+ end
74
+
75
+ def lower_str_buffer_data_pointer_from_lowered(lowered_receiver)
76
+ IR::AddressOf.new(
77
+ expression: IR::Index.new(
78
+ receiver: IR::Member.new(
79
+ receiver: lowered_receiver,
80
+ member: "data",
81
+ type: Types::Registry.generic_instance(
82
+ "array",
83
+ [@ctx.types.fetch("char"), Types::LiteralTypeArg.new(str_buffer_storage_capacity(lowered_receiver.type))],
84
+ ),
85
+ ),
86
+ index: IR::IntegerLiteral.new(value: 0, type: @ctx.types.fetch("ptr_uint")),
87
+ type: @ctx.types.fetch("char"),
88
+ ),
89
+ type: pointer_to(@ctx.types.fetch("char")),
90
+ )
91
+ end
92
+
93
+ def lower_str_buffer_len_pointer(expression, env:)
94
+ lower_str_buffer_len_pointer_from_lowered(lower_expression(expression, env:))
95
+ end
96
+
97
+ def lower_str_buffer_len_pointer_from_lowered(lowered_receiver)
98
+ IR::AddressOf.new(
99
+ expression: IR::Member.new(receiver: lowered_receiver, member: "len", type: @ctx.types.fetch("ptr_uint")),
100
+ type: pointer_to(@ctx.types.fetch("ptr_uint")),
101
+ )
102
+ end
103
+
104
+ def lower_str_buffer_dirty_pointer(expression, env:)
105
+ lower_str_buffer_dirty_pointer_from_lowered(lower_expression(expression, env:))
106
+ end
107
+
108
+ def lower_str_buffer_dirty_pointer_from_lowered(lowered_receiver)
109
+ IR::AddressOf.new(
110
+ expression: IR::Member.new(receiver: lowered_receiver, member: "dirty", type: @ctx.types.fetch("bool")),
111
+ type: pointer_to(@ctx.types.fetch("bool")),
112
+ )
113
+ end
114
+
115
+ def str_buffer_args(receiver, env:)
116
+ receiver_type = infer_expression_type(receiver, env:)
117
+ [
118
+ lower_str_buffer_data_pointer(receiver, env:),
119
+ IR::IntegerLiteral.new(value: str_buffer_capacity(receiver_type), type: @ctx.types.fetch("ptr_uint")),
120
+ lower_str_buffer_len_pointer(receiver, env:),
121
+ lower_str_buffer_dirty_pointer(receiver, env:),
122
+ ]
123
+ end
124
+ end
125
+ end