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,588 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ class SemanticAnalyzer
5
+ class Checker
6
+ private
7
+
8
+ def check_top_level_values
9
+ expanded_declarations.each do |decl|
10
+ with_error_node(decl) do
11
+ case decl
12
+ when AST::ConstDecl
13
+ begin
14
+ if decl.block_body
15
+ check_block_body_const(decl)
16
+ else
17
+ check_expr_const(decl)
18
+ end
19
+ rescue SemanticError => e
20
+ collect_structural_error(e)
21
+ end
22
+ when AST::VarDecl
23
+ binding = @ctx.top_level_values.fetch(decl.name)
24
+ if decl.value
25
+ validate_consuming_foreign_expression!(decl.value, scopes: [], root_allowed: false)
26
+ validate_hoistable_foreign_expression!(decl.value, scopes: [], root_hoistable: false)
27
+ actual_type = infer_expression(decl.value, scopes: [], expected_type: binding.type)
28
+ ensure_assignable!(
29
+ actual_type,
30
+ binding.type,
31
+ "cannot assign #{actual_type} to module variable #{decl.name}: expected #{binding.type}",
32
+ expression: decl.value,
33
+ )
34
+ validate_static_storage_initializer!(decl.value, scopes: [])
35
+ else
36
+ zero_initializable_type?(binding.type)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def check_expr_const(decl)
44
+ binding = @ctx.top_level_values.fetch(decl.name)
45
+ validate_consuming_foreign_expression!(decl.value, scopes: [], root_allowed: false)
46
+ validate_hoistable_foreign_expression!(decl.value, scopes: [], root_hoistable: false)
47
+
48
+ if binding.type == builtin_type_meta_type
49
+ evaluate_compile_time_const_value(decl.value)
50
+ return
51
+ end
52
+
53
+ actual_type = infer_expression(decl.value, scopes: [], expected_type: binding.type)
54
+ ensure_assignable!(
55
+ actual_type,
56
+ binding.type,
57
+ "cannot assign #{actual_type} to constant #{decl.name}: expected #{binding.type}",
58
+ expression: decl.value,
59
+ )
60
+ end
61
+
62
+ def check_block_body_const(decl)
63
+ return unless decl.block_body
64
+
65
+ last_stmt = decl.block_body.last
66
+ unless last_stmt.is_a?(AST::ReturnStmt) && last_stmt.value
67
+ raise_sema_error("block-bodied const must end with a return statement")
68
+ end
69
+ end
70
+
71
+ def validate_static_storage_initializer!(expression, scopes:)
72
+ case expression
73
+ when AST::ErrorExpr
74
+ return
75
+ when AST::IntegerLiteral, AST::FloatLiteral, AST::StringLiteral, AST::BooleanLiteral, AST::NullLiteral,
76
+ AST::SizeofExpr, AST::AlignofExpr, AST::OffsetofExpr
77
+ return
78
+ when AST::Identifier
79
+ if (binding = lookup_value(expression.name, scopes))
80
+ return if binding.kind == :const
81
+
82
+ raise_sema_error("module variable initializer cannot reference mutable value #{expression.name}")
83
+ end
84
+
85
+ function = @ctx.top_level_functions[expression.name]
86
+ return if function && static_storage_function_value?(function)
87
+
88
+ raise_sema_error("module variable initializer must be static-storage-safe")
89
+ when AST::MemberAccess
90
+ return if static_storage_member_initializer?(expression, scopes:)
91
+
92
+ raise_sema_error("module variable initializer must be static-storage-safe")
93
+ when AST::UnaryOp
94
+ validate_static_storage_initializer!(expression.operand, scopes:)
95
+ when AST::BinaryOp
96
+ validate_static_storage_initializer!(expression.left, scopes:)
97
+ validate_static_storage_initializer!(expression.right, scopes:)
98
+ when AST::IfExpr
99
+ validate_static_storage_initializer!(expression.condition, scopes:)
100
+ validate_static_storage_initializer!(expression.then_expression, scopes:)
101
+ validate_static_storage_initializer!(expression.else_expression, scopes:)
102
+ when AST::UnsafeExpr
103
+ validate_static_storage_initializer!(expression.expression, scopes:)
104
+ when AST::ExpressionList
105
+ expression.elements.each { |element| validate_static_storage_initializer!(element, scopes:) }
106
+ when AST::Specialization
107
+ if expression.callee.is_a?(AST::Identifier)
108
+ return if expression.callee.name == "zero"
109
+ end
110
+
111
+ raise_sema_error("module variable initializer must be static-storage-safe")
112
+ when AST::Call
113
+ validate_static_storage_call_initializer!(expression, scopes:)
114
+ when AST::ProcExpr
115
+ # Proc expressions are static-storage-safe when their body only
116
+ # references module-level constants, functions, types, and imports.
117
+ # The lowering handles capture detection; if a proc truly captures
118
+ # a local from an enclosing scope (impossible at module level),
119
+ # the sema validation above already rejects it via the
120
+ # "cannot reference mutable value" check on the proc body.
121
+ return
122
+ else
123
+ raise_sema_error("module variable initializer must be static-storage-safe")
124
+ end
125
+ end
126
+
127
+ def static_storage_member_initializer?(expression, scopes:)
128
+ if (type_expr = resolve_type_expression(expression.receiver))
129
+ return true if resolve_type_member(type_expr, expression.member)
130
+ end
131
+
132
+ return false unless expression.receiver.is_a?(AST::Identifier)
133
+ return false unless @ctx.imports.key?(expression.receiver.name)
134
+
135
+ imported_module = @ctx.imports.fetch(expression.receiver.name)
136
+ if imported_module.private_value?(expression.member) || imported_module.private_function?(expression.member) || imported_module.private_type?(expression.member)
137
+ raise_sema_error("#{expression.receiver.name}.#{expression.member} is private to module #{imported_module.name}")
138
+ end
139
+
140
+ if (binding = imported_module.values[expression.member])
141
+ return true if binding.kind == :const
142
+
143
+ raise_sema_error("module variable initializer cannot reference mutable value #{expression.receiver.name}.#{expression.member}")
144
+ end
145
+
146
+ function = imported_module.functions[expression.member]
147
+ function && static_storage_function_value?(function)
148
+ end
149
+
150
+ def validate_static_storage_call_initializer!(expression, scopes:)
151
+ expression.arguments.each do |argument|
152
+ validate_static_storage_initializer!(argument.value, scopes:)
153
+ end
154
+
155
+ callee = expression.callee
156
+ if callee.is_a?(AST::Identifier)
157
+ if (type_expr = resolve_type_expression(callee))
158
+ return if type_expr.is_a?(Types::Struct) || type_expr.is_a?(Types::StringView)
159
+ end
160
+ end
161
+
162
+ if callee.is_a?(AST::MemberAccess)
163
+ if (type_expr = resolve_type_expression(callee))
164
+ return if type_expr.is_a?(Types::Struct) || type_expr.is_a?(Types::StringView)
165
+ end
166
+ end
167
+
168
+ if callee.is_a?(AST::Specialization)
169
+ if callee.callee.is_a?(AST::Identifier)
170
+ case callee.callee.name
171
+ when "array", "span", "zero", "reinterpret"
172
+ return
173
+ end
174
+ end
175
+
176
+ if (type_ref = type_ref_from_specialization(callee))
177
+ specialized_type = resolve_type_ref(type_ref)
178
+ return if specialized_type.is_a?(Types::Struct) || result_type?(specialized_type)
179
+ end
180
+ end
181
+
182
+ raise_sema_error("module variable initializer must be static-storage-safe")
183
+ end
184
+
185
+ def static_storage_function_value?(binding)
186
+ !binding.external && binding.type_params.empty?
187
+ end
188
+
189
+ def finalize_top_level_const_values
190
+ @ctx.const_declarations.each_key { |name| evaluate_top_level_const_value(name) }
191
+ end
192
+
193
+ def evaluate_top_level_const_value(name)
194
+ return @ctx.top_level_values.fetch(name).const_value if @evaluated_const_values.key?(name)
195
+
196
+ raise_sema_error("cyclic constant value dependency involving #{name}") if @evaluating_const_values.include?(name)
197
+
198
+ decl = @ctx.const_declarations.fetch(name)
199
+ if decl.block_body
200
+ return evaluate_block_body_const(decl, name)
201
+ end
202
+
203
+ if decl.value.is_a?(AST::ErrorExpr)
204
+ @evaluated_const_values[name] = true
205
+ return nil
206
+ end
207
+
208
+ @evaluating_const_values << name
209
+ value = evaluate_compile_time_const_value(decl.value)
210
+ @evaluating_const_values.pop
211
+
212
+ if value.is_a?(Integer)
213
+ binding_ = @ctx.top_level_values.fetch(name)
214
+ check_type = binding_.type
215
+ check_type = check_type.backing_type if check_type.respond_to?(:backing_type)
216
+
217
+ if check_type.is_a?(Types::Primitive) && check_type.integer? && (width = check_type.integer_width)
218
+ max_value = if check_type.signed_integer?
219
+ (1 << (width - 1)) - 1
220
+ else
221
+ (1 << width) - 1
222
+ end
223
+ if value > max_value
224
+ raise_sema_error("constant #{name} value #{value} does not fit in type #{binding_.type}")
225
+ end
226
+ end
227
+ end
228
+
229
+ set_const_value(name, value)
230
+ value
231
+ end
232
+
233
+ def evaluate_block_body_const(decl, name)
234
+ @evaluating_const_values << name
235
+ value = evaluate_compile_time_block(decl.block_body)
236
+ @evaluating_const_values.pop
237
+ set_const_value(name, value)
238
+ value
239
+ end
240
+
241
+ def set_const_value(name, value)
242
+ binding = @ctx.top_level_values.fetch(name)
243
+ @ctx.top_level_values[name] = ValueBinding.new(
244
+ id: binding.id,
245
+ name: binding.name,
246
+ storage_type: binding.storage_type,
247
+ flow_type: binding.flow_type,
248
+ mutable: binding.mutable,
249
+ kind: binding.kind,
250
+ const_value: value,
251
+ )
252
+ @evaluated_const_values[name] = true
253
+ end
254
+
255
+ def evaluate_compile_time_block(statements, scopes: nil)
256
+ ctx = CompileTime::BlockContext.new(self)
257
+ result = ctx.evaluate_block(statements, scopes:)
258
+ result
259
+ rescue CompileTime::ReturnValue => e
260
+ e.value
261
+ rescue CompileTime::Error => e
262
+ raise_sema_error(e.message)
263
+ end
264
+
265
+ def evaluate_compile_time_const_value(expression, scopes: nil)
266
+ CompileTime.evaluate(
267
+ expression,
268
+ resolve_identifier: lambda do |identifier_expression|
269
+ if scopes
270
+ binding = lookup_value(identifier_expression.name, scopes)
271
+ return binding.const_value unless binding&.const_value.nil?
272
+ end
273
+
274
+ value = resolve_current_module_const_value(identifier_expression.name)
275
+ return value if value
276
+
277
+ # Resolve a bare type-parameter name (e.g. `T`) to its substituted
278
+ # concrete type so `inline if T == int` can fold at compile time.
279
+ current_type_params[identifier_expression.name] || @ctx.types[identifier_expression.name]
280
+ end,
281
+ resolve_member_access: lambda do |member_access_expression|
282
+ if member_access_expression.receiver.is_a?(AST::Identifier) && scopes
283
+ binding = lookup_value(member_access_expression.receiver.name, scopes)
284
+ if binding && binding.const_value
285
+ receiver_value = binding.const_value
286
+ case receiver_value
287
+ when Types::FieldHandle
288
+ case member_access_expression.member
289
+ when "name" then next receiver_value.field_name
290
+ when "type" then next receiver_value.struct_handle.struct_type.field(receiver_value.field_name)
291
+ end
292
+ when Types::MemberHandle
293
+ case member_access_expression.member
294
+ when "name" then next receiver_value.name
295
+ when "value" then next receiver_value.value
296
+ end
297
+ when Types::AttributeHandle
298
+ case member_access_expression.member
299
+ when "name" then next receiver_value.name
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ if (receiver_type = resolve_type_expression(member_access_expression.receiver))
306
+ next resolve_enum_member_const_value(receiver_type, member_access_expression.member)
307
+ end
308
+
309
+ next unless member_access_expression.receiver.is_a?(AST::Identifier)
310
+
311
+ resolve_imported_module_const_value(member_access_expression.receiver.name, member_access_expression.member)
312
+ end,
313
+ resolve_type_ref: lambda do |type_ref|
314
+ resolve_type_ref(type_ref)
315
+ end,
316
+ resolve_call: lambda do |call_expression|
317
+ evaluate_compile_time_call(call_expression, scopes:)
318
+ end,
319
+ )
320
+ rescue CompileTime::Error => e
321
+ raise_sema_error(e.message)
322
+ end
323
+
324
+ def evaluate_compile_time_call(expression, scopes: nil)
325
+ case expression.callee
326
+ when AST::Identifier
327
+ case expression.callee.name
328
+ when "field_of"
329
+ evaluate_field_of_call(expression.arguments, scopes: scopes || [])
330
+ when "fields_of"
331
+ evaluate_fields_of_call(expression.arguments)
332
+ when "callable_of"
333
+ evaluate_callable_of_call(expression.arguments, scopes: scopes || [])
334
+ when "has_attribute"
335
+ evaluate_has_attribute_call(expression.arguments, scopes: scopes || [])
336
+ when "attribute_of"
337
+ evaluate_attribute_of_call(expression.arguments, scopes: scopes || [])
338
+ when "members_of"
339
+ evaluate_members_of_call(expression.arguments)
340
+ when "attributes_of"
341
+ evaluate_attributes_of_call(expression.arguments, scopes: scopes || [])
342
+ else
343
+ func = @ctx.top_level_functions[expression.callee.name]
344
+ if func&.ast&.respond_to?(:const) && func.ast.const
345
+ evaluate_const_function_body(func, expression.arguments, scopes:)
346
+ else
347
+ evaluate_type_returning_call(expression, scopes:)
348
+ end
349
+ end
350
+ when AST::Specialization
351
+ if expression.callee.callee.is_a?(AST::Identifier) && expression.callee.callee.name == "attribute_arg"
352
+ evaluate_attribute_arg_call(expression.arguments, scopes: scopes || [])
353
+ else
354
+ callee_name = expression.callee.callee.is_a?(AST::Identifier) ? expression.callee.callee.name : nil
355
+ if callee_name
356
+ func = @ctx.top_level_functions[callee_name]
357
+ if func&.ast&.respond_to?(:const) && func.ast.const
358
+ evaluate_const_function_body(func, expression.arguments, scopes:)
359
+ else
360
+ evaluate_type_returning_call(expression, scopes:)
361
+ end
362
+ else
363
+ evaluate_type_returning_call(expression, scopes:)
364
+ end
365
+ end
366
+ else
367
+ nil
368
+ end
369
+ end
370
+
371
+ def evaluate_type_returning_call(expression, scopes:)
372
+ callee_name, type_args = extract_type_callee_info(expression)
373
+ return nil unless callee_name
374
+
375
+ CompileTime::Reflection.core_evaluate_type_returning(
376
+ callee_name, type_args,
377
+ evaluate_value: ->(v) { evaluate_compile_time_const_value(v, scopes:) },
378
+ resolve_type_ref: ->(tr) { resolve_type_ref(tr) },
379
+ pointer_to: ->(t) { pointer_to(t) },
380
+ const_pointer_to: ->(t) { const_pointer_to(t) },
381
+ top_level_functions: ->(name) { @ctx.top_level_functions[name] },
382
+ evaluate_type_returning_function_body: ->(func, targs) { evaluate_type_returning_function_body(func, targs) },
383
+ )
384
+ end
385
+
386
+ def extract_type_callee_info(expression)
387
+ if expression.is_a?(AST::Call) && expression.callee.is_a?(AST::Identifier)
388
+ [expression.callee.name, nil]
389
+ elsif expression.is_a?(AST::Specialization)
390
+ if expression.callee.is_a?(AST::Identifier)
391
+ [expression.callee.name, expression.arguments]
392
+ elsif expression.callee.is_a?(AST::Specialization) && expression.callee.callee.is_a?(AST::Identifier)
393
+ [expression.callee.callee.name, expression.callee.arguments]
394
+ end
395
+ end
396
+ end
397
+
398
+ def evaluate_type_returning_function_body(func, type_args)
399
+ value_params = func.ast.type_params.select { |p| p.is_a?(AST::ValueTypeParam) }
400
+ return nil if value_params.empty?
401
+
402
+ initial_vars = {}
403
+ value_params.zip(type_args).each do |param, arg|
404
+ arg_value = arg.value
405
+ case arg_value
406
+ when AST::IntegerLiteral
407
+ initial_vars[param.name] = arg_value.value
408
+ when AST::TypeRef
409
+ initial_vars[param.name] = resolve_type_ref(arg_value)
410
+ else
411
+ return nil
412
+ end
413
+ end
414
+
415
+ ctx = CompileTime::BlockContext.new(self, initial_variables: initial_vars)
416
+ ctx.evaluate_block(func.ast.body, scopes: nil)
417
+ rescue CompileTime::ReturnValue => e
418
+ e.value
419
+ rescue CompileTime::Error => e
420
+ raise_sema_error(e.message)
421
+ end
422
+
423
+ def evaluate_const_function_body(func, arguments, scopes:)
424
+ return nil unless func.ast.params.length == arguments.length
425
+
426
+ initial_vars = {}
427
+ func.ast.params.each_with_index do |param, idx|
428
+ arg_expr = arguments[idx].value
429
+ arg_value = if scopes
430
+ evaluate_compile_time_const_value(arg_expr, scopes:)
431
+ else
432
+ CompileTime.evaluate(
433
+ arg_expr,
434
+ resolve_identifier: lambda { |id| resolve_current_module_const_value(id.name) },
435
+ resolve_member_access: nil,
436
+ resolve_type_ref: lambda { |tr| resolve_type_ref(tr) },
437
+ resolve_call: nil,
438
+ )
439
+ end
440
+ return nil unless arg_value
441
+
442
+ initial_vars[param.name] = arg_value
443
+ end
444
+
445
+ ctx = CompileTime::BlockContext.new(self, initial_variables: initial_vars)
446
+ ctx.evaluate_block(func.ast.body, scopes: nil)
447
+ rescue CompileTime::ReturnValue => e
448
+ e.value
449
+ rescue CompileTime::Error => e
450
+ raise_sema_error(e.message)
451
+ end
452
+
453
+ def evaluate_has_attribute_call(arguments, scopes:)
454
+ target = evaluate_reflection_target_argument(arguments.first.value, scopes:)
455
+ binding = resolve_attribute_name_argument(arguments[1].value)
456
+ validate_attribute_target_compatibility!(target, binding)
457
+ !find_attribute_application(target, binding).nil?
458
+ end
459
+
460
+ def evaluate_attribute_of_call(arguments, scopes:)
461
+ target = evaluate_reflection_target_argument(arguments.first.value, scopes:)
462
+ binding = resolve_attribute_name_argument(arguments[1].value)
463
+ validate_attribute_target_compatibility!(target, binding)
464
+
465
+ application = find_attribute_application(target, binding)
466
+ return nil unless application
467
+
468
+ Types::AttributeHandle.new(
469
+ binding.name,
470
+ binding.module_name,
471
+ target,
472
+ binding.params,
473
+ application.argument_values,
474
+ )
475
+ end
476
+
477
+ def evaluate_attribute_arg_call(arguments, scopes:)
478
+ attribute_handle = evaluate_compile_time_const_value(arguments.first.value, scopes:)
479
+ return nil unless attribute_handle.is_a?(Types::AttributeHandle)
480
+
481
+ param_name = reflection_identifier_name(arguments[1].value, context: "attribute_arg")
482
+ return nil unless attribute_handle.argument_values
483
+
484
+ attribute_handle.argument_values[param_name]
485
+ end
486
+
487
+ def evaluate_reflection_target_argument(expression, scopes:)
488
+ if (type_expr = resolve_type_expression(expression))
489
+ handle = struct_handle_for_type(type_expr)
490
+ return handle if handle
491
+ end
492
+
493
+ value = evaluate_compile_time_const_value(expression, scopes:)
494
+ return value if value.is_a?(Types::FieldHandle) || value.is_a?(Types::CallableHandle)
495
+
496
+ nil
497
+ end
498
+
499
+ def evaluate_fields_of_call(arguments)
500
+ raise_sema_error("fields_of expects 1 argument") unless arguments.length == 1
501
+
502
+ type = resolve_type_expression(arguments.first.value)
503
+ raise_sema_error("fields_of requires a type argument") unless type
504
+
505
+ handle = struct_handle_for_type(type)
506
+ raise_sema_error("fields_of requires a struct type, got #{type}") unless handle
507
+
508
+ CompileTime::Reflection.core_field_handles(handle)
509
+ end
510
+
511
+ def evaluate_members_of_call(arguments)
512
+ raise_sema_error("members_of expects 1 argument") unless arguments.length == 1
513
+
514
+ type = resolve_type_expression(arguments.first.value)
515
+ raise_sema_error("members_of requires a type argument") unless type
516
+
517
+ unless type.is_a?(Types::Enum) || type.is_a?(Types::Flags)
518
+ raise_sema_error("members_of requires an enum or flags type, got #{type}")
519
+ end
520
+
521
+ CompileTime::Reflection.core_member_handles(type)
522
+ end
523
+
524
+ def evaluate_attributes_of_call(arguments, scopes:)
525
+ raise_sema_error("attributes_of expects 1 or 2 arguments") unless (1..2).include?(arguments.length)
526
+
527
+ target = evaluate_reflection_target_argument(arguments.first.value, scopes:)
528
+
529
+ if arguments.length == 2
530
+ attribute_binding = resolve_attribute_name_argument(arguments[1].value)
531
+ application = find_attribute_application(target, attribute_binding)
532
+ return [] unless application
533
+
534
+ [Types::AttributeHandle.new(
535
+ attribute_binding.name,
536
+ attribute_binding.module_name,
537
+ target,
538
+ attribute_binding.params,
539
+ application.argument_values,
540
+ )]
541
+ else
542
+ resolved_attribute_applications_for_target(target).map do |application|
543
+ Types::AttributeHandle.new(
544
+ application.binding.name,
545
+ application.binding.module_name,
546
+ target,
547
+ application.binding.params,
548
+ application.argument_values,
549
+ )
550
+ end
551
+ end
552
+ end
553
+
554
+ def evaluate_enum_member_const_value(expression, enum_type:, member_values:)
555
+ CompileTime.evaluate(
556
+ expression,
557
+ resolve_identifier: lambda do |identifier_expression|
558
+ resolve_current_module_const_value(identifier_expression.name)
559
+ end,
560
+ resolve_member_access: lambda do |member_access_expression|
561
+ if (receiver_type = resolve_type_expression(member_access_expression.receiver))
562
+ next resolve_enum_member_const_value(
563
+ receiver_type,
564
+ member_access_expression.member,
565
+ local_enum_type: enum_type,
566
+ local_member_values: member_values,
567
+ )
568
+ end
569
+
570
+ next unless member_access_expression.receiver.is_a?(AST::Identifier)
571
+
572
+ resolve_imported_module_const_value(member_access_expression.receiver.name, member_access_expression.member)
573
+ end,
574
+ resolve_type_ref: lambda do |type_ref|
575
+ resolve_type_ref(type_ref)
576
+ end,
577
+ )
578
+ end
579
+
580
+ def check_top_level_static_asserts
581
+ expanded_declarations.grep(AST::StaticAssert).each do |statement|
582
+ check_static_assert(statement, scopes: [])
583
+ end
584
+ end
585
+
586
+ end
587
+ end
588
+ end