mt-lang 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -2
  3. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
  4. data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
  5. data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
  6. data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
  7. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
  8. data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
  9. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
  10. data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
  11. data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
  12. data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
  13. data/lib/milk_tea/bindings/steamworks.rb +12 -16
  14. data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
  15. data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
  16. data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
  17. data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
  18. data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
  19. data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
  20. data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
  21. data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
  22. data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
  23. data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
  24. data/lib/milk_tea/core/ast.rb +103 -45
  25. data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
  26. data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
  27. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
  28. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
  29. data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
  30. data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
  31. data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
  32. data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
  33. data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
  34. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
  35. data/lib/milk_tea/core/c_backend/statements.rb +528 -530
  36. data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
  37. data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
  38. data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
  39. data/lib/milk_tea/core/c_backend.rb +17 -9
  40. data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
  41. data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
  42. data/lib/milk_tea/core/compile_time.rb +32 -38
  43. data/lib/milk_tea/core/control_flow/builder.rb +3 -5
  44. data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
  45. data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
  46. data/lib/milk_tea/core/ir.rb +10 -10
  47. data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
  48. data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
  49. data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
  50. data/lib/milk_tea/core/lexer/indentation.rb +0 -2
  51. data/lib/milk_tea/core/lexer/numbers.rb +0 -2
  52. data/lib/milk_tea/core/lexer/recovery.rb +0 -2
  53. data/lib/milk_tea/core/lexer/strings.rb +0 -2
  54. data/lib/milk_tea/core/lexer/symbols.rb +0 -2
  55. data/lib/milk_tea/core/lexer/trivia.rb +0 -2
  56. data/lib/milk_tea/core/lexer.rb +0 -2
  57. data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
  58. data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
  59. data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
  60. data/lib/milk_tea/core/lowering/async.rb +627 -630
  61. data/lib/milk_tea/core/lowering/block.rb +413 -416
  62. data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
  63. data/lib/milk_tea/core/lowering/declarations.rb +180 -183
  64. data/lib/milk_tea/core/lowering/dyn.rb +48 -50
  65. data/lib/milk_tea/core/lowering/events.rb +983 -985
  66. data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
  67. data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
  68. data/lib/milk_tea/core/lowering/functions.rb +185 -188
  69. data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
  70. data/lib/milk_tea/core/lowering/proc.rb +363 -366
  71. data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
  72. data/lib/milk_tea/core/lowering/scans.rb +179 -181
  73. data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
  74. data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
  75. data/lib/milk_tea/core/lowering.rb +5 -7
  76. data/lib/milk_tea/core/module_binder.rb +0 -2
  77. data/lib/milk_tea/core/module_loader/errors.rb +4 -2
  78. data/lib/milk_tea/core/module_loader.rb +113 -20
  79. data/lib/milk_tea/core/module_path_resolver.rb +0 -2
  80. data/lib/milk_tea/core/module_roots.rb +6 -8
  81. data/lib/milk_tea/core/parser/attributes.rb +0 -2
  82. data/lib/milk_tea/core/parser/blocks.rb +0 -2
  83. data/lib/milk_tea/core/parser/declarations.rb +0 -2
  84. data/lib/milk_tea/core/parser/expressions.rb +31 -14
  85. data/lib/milk_tea/core/parser/recovery.rb +0 -2
  86. data/lib/milk_tea/core/parser/statements.rb +0 -2
  87. data/lib/milk_tea/core/parser/types.rb +8 -10
  88. data/lib/milk_tea/core/parser.rb +1 -3
  89. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
  90. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
  91. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
  92. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
  93. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
  94. data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
  95. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
  96. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
  97. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
  98. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
  99. data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
  100. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
  101. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
  102. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
  103. data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
  104. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
  105. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
  106. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
  107. data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
  108. data/lib/milk_tea/core/types/layout.rb +21 -22
  109. data/lib/milk_tea/core/types/predicates.rb +0 -2
  110. data/lib/milk_tea/core/types/registry.rb +16 -18
  111. data/lib/milk_tea/core/types/visitor.rb +0 -4
  112. data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
  113. data/lib/milk_tea/dap/protocol.rb +1 -1
  114. data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
  115. data/lib/milk_tea/dap/server/debug_map.rb +0 -2
  116. data/lib/milk_tea/dap/server/handlers.rb +0 -2
  117. data/lib/milk_tea/dap/server/launch.rb +0 -2
  118. data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
  119. data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
  120. data/lib/milk_tea/dap/server/utilities.rb +0 -2
  121. data/lib/milk_tea/dap/server/wire.rb +0 -2
  122. data/lib/milk_tea/dap/server.rb +0 -2
  123. data/lib/milk_tea/lsp/diagnostics.rb +16 -16
  124. data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
  125. data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
  126. data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
  127. data/lib/milk_tea/lsp/server/completion.rb +873 -875
  128. data/lib/milk_tea/lsp/server/configuration.rb +129 -131
  129. data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
  130. data/lib/milk_tea/lsp/server/definition.rb +564 -565
  131. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
  132. data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
  133. data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
  134. data/lib/milk_tea/lsp/server/formatting.rb +478 -480
  135. data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
  136. data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
  137. data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
  138. data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
  139. data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
  140. data/lib/milk_tea/lsp/server/progress.rb +0 -2
  141. data/lib/milk_tea/lsp/server/references.rb +316 -318
  142. data/lib/milk_tea/lsp/server/rename.rb +445 -447
  143. data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
  144. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
  145. data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
  146. data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
  147. data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
  148. data/lib/milk_tea/lsp/server/utilities.rb +397 -399
  149. data/lib/milk_tea/lsp/server.rb +0 -3
  150. data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
  151. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
  152. data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
  153. data/lib/milk_tea/packages/atomic_write.rb +4 -5
  154. data/lib/milk_tea/packages/dependency_solver.rb +15 -15
  155. data/lib/milk_tea/packages/lock.rb +4 -4
  156. data/lib/milk_tea/packages/manager_cli.rb +1 -1
  157. data/lib/milk_tea/packages/manifest.rb +3 -3
  158. data/lib/milk_tea/packages/registry_store.rb +4 -6
  159. data/lib/milk_tea/packages/services.rb +16 -16
  160. data/lib/milk_tea/packages/source_cache.rb +4 -6
  161. data/lib/milk_tea/packages/source_resolver.rb +44 -44
  162. data/lib/milk_tea/packages/version.rb +8 -8
  163. data/lib/milk_tea/tooling/build.rb +3 -7
  164. data/lib/milk_tea/tooling/build_cache.rb +0 -2
  165. data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
  166. data/lib/milk_tea/tooling/debug_map.rb +8 -10
  167. data/lib/milk_tea/tooling/docs_app.rb +0 -2
  168. data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
  169. data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
  170. data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
  171. data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
  172. data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
  173. data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
  174. data/lib/milk_tea/tooling/linter/rules.rb +87 -89
  175. data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
  176. data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
  177. data/lib/milk_tea/tooling/linter/visitors.rb +162 -50
  178. data/lib/milk_tea/tooling/linter.rb +0 -2
  179. data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
  180. data/lib/milk_tea/tooling/run.rb +0 -2
  181. data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
  182. data/std/cli.mt +13 -32
  183. data/std/color.mt +28 -28
  184. data/std/encoding.mt +4 -4
  185. data/std/graph.mt +1 -2
  186. data/std/hash.mt +14 -14
  187. data/std/http/server.mt +3 -3
  188. data/std/input.mt +1 -1
  189. data/std/json.mt +1 -1
  190. data/std/linear_algebra.mt +6 -6
  191. data/std/net/mux.mt +1 -1
  192. data/std/noise.mt +23 -23
  193. data/std/parse.mt +2 -2
  194. data/std/process.mt +3 -4
  195. data/std/sparse_set.mt +1 -1
  196. data/std/steering.mt +5 -5
  197. data/std/str.mt +1 -1
  198. data/std/tween.mt +4 -4
  199. data/std/utility.mt +3 -3
  200. metadata +2 -2
@@ -5,394 +5,392 @@ require "set"
5
5
  module MilkTea
6
6
  class CBackend
7
7
  module Reachability
8
- private
9
-
10
- def emitted_constants
11
- @emitted_constants ||= begin
12
- constants_by_name = @program.constants.each_with_object({}) do |constant, result|
13
- result[constant.linkage_name] = constant
14
- end
15
- referenced_names = {}
16
- root_module_prefix = "#{module_c_prefix(@program.module_name)}_"
17
-
18
- @program.constants.each do |constant|
19
- next unless constant.linkage_name.start_with?(root_module_prefix)
20
-
21
- referenced_names[constant.linkage_name] = true
22
- collect_referenced_constant_names_from_expression(constant.value, constants_by_name, referenced_names)
23
- end
24
-
25
- @program.globals.each do |global|
26
- collect_referenced_constant_names_from_expression(global.value, constants_by_name, referenced_names)
27
- end
28
-
29
- @program.static_asserts.each do |statement|
30
- collect_referenced_constant_names_from_expression(statement.condition, constants_by_name, referenced_names)
31
- collect_referenced_constant_names_from_expression(statement.message, constants_by_name, referenced_names)
32
- end
33
-
34
- emitted_functions.each do |function|
35
- collect_referenced_constant_names_from_statements(function.body, constants_by_name, referenced_names)
36
- end
37
-
38
- @program.constants.select { |constant| referenced_names[constant.linkage_name] }
39
- end
8
+ def emitted_constants
9
+ @emitted_constants ||= begin
10
+ constants_by_name = @program.constants.each_with_object({}) do |constant, result|
11
+ result[constant.linkage_name] = constant
40
12
  end
13
+ referenced_names = {}
14
+ root_module_prefix = "#{module_c_prefix(@program.module_name)}_"
41
15
 
42
- def emitted_functions
43
- @emitted_functions ||= begin
44
- functions_by_name = @program.functions.each_with_object({}) do |function, result|
45
- result[function.linkage_name] = function
46
- end
47
-
48
- seeds = @program.functions.select(&:entry_point)
49
- if seeds.empty?
50
- root_module_prefix = "#{module_c_prefix(@program.module_name)}_"
51
- seeds = @program.functions.select { |function| function.linkage_name.start_with?(root_module_prefix) }
52
- end
53
-
54
- reachable_names = {}
55
- worklist = seeds.dup
16
+ @program.constants.each do |constant|
17
+ next unless constant.linkage_name.start_with?(root_module_prefix)
56
18
 
57
- until worklist.empty?
58
- function = worklist.shift
59
- next if reachable_names[function.linkage_name]
60
-
61
- reachable_names[function.linkage_name] = true
62
- collect_called_function_names_from_statements(function.body, functions_by_name, reachable_names, worklist)
63
- end
64
-
65
- (@program.constants + @program.globals).each do |value|
66
- collect_called_function_names_from_expression(value.value, functions_by_name, reachable_names, worklist)
67
- end
68
-
69
- until worklist.empty?
70
- function = worklist.shift
71
- next if reachable_names[function.linkage_name]
72
-
73
- reachable_names[function.linkage_name] = true
74
- collect_called_function_names_from_statements(function.body, functions_by_name, reachable_names, worklist)
75
- end
76
-
77
- @program.functions.select { |function| reachable_names[function.linkage_name] }
78
- end
19
+ referenced_names[constant.linkage_name] = true
20
+ collect_referenced_constant_names_from_expression(constant.value, constants_by_name, referenced_names)
79
21
  end
80
22
 
81
- def all_emitted_top_level_values
82
- emitted_constants + emitted_globals
23
+ @program.globals.each do |global|
24
+ collect_referenced_constant_names_from_expression(global.value, constants_by_name, referenced_names)
83
25
  end
84
26
 
85
- def collect_active_module_names
86
- active = Set.new
87
- active << @program.module_name
88
-
89
- collect_type_referenced_module_names.each { |mod| active << mod }
90
-
91
- emitted_functions.each do |fn|
92
- prefix = module_c_prefix(@program.module_name)
93
- if fn.linkage_name != prefix && !fn.linkage_name.start_with?("#{prefix}_")
94
- candidate = fn.linkage_name.split("_")
95
- candidate.pop
96
- active << candidate.join("_")
97
- end
98
- end
99
-
100
- (@program.structs + @program.unions + @program.variants + @program.opaques).each do |decl|
101
- active << decl.source_module if decl.source_module
102
- end
103
-
104
- loop do
105
- size_before = active.size
106
- (@program.structs + @program.unions).each do |decl|
107
- next unless decl.source_module
108
- next unless active.include?(decl.source_module)
109
-
110
- decl.fields.each { |f| add_type_module(f.type, active) }
111
- end
112
- @program.variants.each do |decl|
113
- next unless decl.source_module
114
- next unless active.include?(decl.source_module)
115
-
116
- decl.arms.each { |arm| arm.fields.each { |f| add_type_module(f.type, active) } }
117
- end
118
- break if active.size == size_before
119
- end
120
-
121
- active
27
+ @program.static_asserts.each do |statement|
28
+ collect_referenced_constant_names_from_expression(statement.condition, constants_by_name, referenced_names)
29
+ collect_referenced_constant_names_from_expression(statement.message, constants_by_name, referenced_names)
122
30
  end
123
31
 
124
- def collect_type_referenced_module_names
125
- modules = Set.new
126
- emitted_functions.each do |fn|
127
- fn.params.each { |p| add_type_module(p.type, modules) }
128
- add_type_module(fn.return_type, modules)
129
- fn.body.each { |stmt| add_statement_type_modules(stmt, modules) }
130
- end
131
- modules
32
+ emitted_functions.each do |function|
33
+ collect_referenced_constant_names_from_statements(function.body, constants_by_name, referenced_names)
132
34
  end
133
35
 
134
- def add_statement_type_modules(stmt, modules)
135
- case stmt
136
- when IR::LocalDecl
137
- add_type_module(stmt.type, modules)
138
- when IR::ExpressionStmt
139
- add_expr_type_module(stmt.expression, modules)
140
- when IR::Assignment
141
- add_expr_type_module(stmt.value, modules)
142
- when IR::ReturnStmt
143
- add_expr_type_module(stmt.value, modules) if stmt.value
144
- when IR::IfStmt
145
- stmt.then_body.each { |s| add_statement_type_modules(s, modules) }
146
- stmt.else_body&.each { |s| add_statement_type_modules(s, modules) }
147
- when IR::WhileStmt
148
- stmt.body.each { |s| add_statement_type_modules(s, modules) }
149
- when IR::ForStmt
150
- stmt.body.each { |s| add_statement_type_modules(s, modules) }
151
- end
152
- end
36
+ @program.constants.select { |constant| referenced_names[constant.linkage_name] }
37
+ end
38
+ end
153
39
 
154
- def add_expr_type_module(expr, modules)
155
- return unless expr
156
- add_type_module(expr.type, modules) if expr.respond_to?(:type)
157
- case expr
158
- when IR::Call
159
- expr.arguments.each { |a| add_expr_type_module(a, modules) }
160
- when IR::Binary
161
- add_expr_type_module(expr.left, modules)
162
- add_expr_type_module(expr.right, modules)
163
- when IR::AggregateLiteral
164
- expr.fields.each { |f| add_expr_type_module(f.value, modules) }
165
- when IR::VariantLiteral
166
- expr.fields.each { |f| add_expr_type_module(f.value, modules) }
167
- when IR::Conditional
168
- add_expr_type_module(expr.then_expression, modules)
169
- add_expr_type_module(expr.else_expression, modules)
170
- when IR::Cast, IR::ReinterpretExpr, IR::AddressOf
171
- add_expr_type_module(expr.expression, modules)
172
- end
40
+ def emitted_functions
41
+ @emitted_functions ||= begin
42
+ functions_by_name = @program.functions.each_with_object({}) do |function, result|
43
+ result[function.linkage_name] = function
173
44
  end
174
45
 
175
- def add_type_module(type, modules)
176
- return unless type
177
- modules << type.module_name if type.respond_to?(:module_name) && type.module_name
178
-
179
- case type
180
- when Types::Nullable
181
- add_type_module(type.base, modules)
182
- when Types::Span
183
- add_type_module(type.element_type, modules)
184
- when Types::GenericInstance
185
- type.arguments.each { |a| add_type_module(a, modules) unless a.is_a?(Types::LiteralTypeArg) }
186
- when Types::Task
187
- add_type_module(type.result_type, modules)
188
- end
46
+ seeds = @program.functions.select(&:entry_point)
47
+ if seeds.empty?
48
+ root_module_prefix = "#{module_c_prefix(@program.module_name)}_"
49
+ seeds = @program.functions.select { |function| function.linkage_name.start_with?(root_module_prefix) }
189
50
  end
190
51
 
52
+ reachable_names = {}
53
+ worklist = seeds.dup
191
54
 
192
- def emitted_aggregate_structs
193
- @emitted_aggregate_structs ||= filter_by_type_reachability(@program.structs)
55
+ until worklist.empty?
56
+ function = worklist.shift
57
+ next if reachable_names[function.linkage_name]
58
+
59
+ reachable_names[function.linkage_name] = true
60
+ collect_called_function_names_from_statements(function.body, functions_by_name, reachable_names, worklist)
194
61
  end
195
62
 
196
- def emitted_aggregate_unions
197
- @emitted_aggregate_unions ||= filter_by_type_reachability(@program.unions)
63
+ (@program.constants + @program.globals).each do |value|
64
+ collect_called_function_names_from_expression(value.value, functions_by_name, reachable_names, worklist)
198
65
  end
199
66
 
200
- def emitted_aggregate_variants
201
- @emitted_aggregate_variants ||= filter_by_type_reachability(@program.variants)
67
+ until worklist.empty?
68
+ function = worklist.shift
69
+ next if reachable_names[function.linkage_name]
70
+
71
+ reachable_names[function.linkage_name] = true
72
+ collect_called_function_names_from_statements(function.body, functions_by_name, reachable_names, worklist)
202
73
  end
203
74
 
204
- def filter_by_type_reachability(decls)
205
- return decls if decls.empty?
206
- return decls if decls.all? { |d| d.source_module.nil? }
75
+ @program.functions.select { |function| reachable_names[function.linkage_name] }
76
+ end
77
+ end
207
78
 
208
- active_modules = collect_active_module_names
209
- by_c_name = decls.each_with_object({}) { |d, h| h[d.linkage_name] = d }
79
+ def all_emitted_top_level_values
80
+ emitted_constants + emitted_globals
81
+ end
210
82
 
211
- reachable = Set.new
212
- decls.each do |decl|
213
- next unless decl.source_module.nil? || active_modules.include?(decl.source_module)
214
- reachable << decl.linkage_name
215
- end
83
+ def collect_active_module_names
84
+ active = Set.new
85
+ active << @program.module_name
216
86
 
217
- worklist = reachable.to_a
218
- until worklist.empty?
219
- linkage_name = worklist.shift
220
- decl = by_c_name[linkage_name]
221
- next unless decl
222
-
223
- deps = aggregate_decl_dependencies(decl)
224
- deps.each do |dep_name|
225
- next unless by_c_name.key?(dep_name)
226
- next if reachable.include?(dep_name)
227
- reachable << dep_name
228
- worklist << dep_name
229
- end
230
- end
87
+ collect_type_referenced_module_names.each { |mod| active << mod }
231
88
 
232
- decls.select { |d| reachable.include?(d.linkage_name) }
89
+ emitted_functions.each do |fn|
90
+ prefix = module_c_prefix(@program.module_name)
91
+ if fn.linkage_name != prefix && !fn.linkage_name.start_with?("#{prefix}_")
92
+ candidate = fn.linkage_name.split("_")
93
+ candidate.pop
94
+ active << candidate.join("_")
233
95
  end
96
+ end
234
97
 
235
- def emitted_globals
236
- @emitted_globals ||= begin
237
- root_module_prefix = "#{module_c_prefix(@program.module_name)}_"
238
- reachable_names = {}
239
- @program.globals.select { |g| g.linkage_name.start_with?(root_module_prefix) }.each { |g| reachable_names[g.linkage_name] = true }
240
-
241
- emitted_functions.each do |function|
242
- traverse_ir_statements(function.body) do |expression|
243
- next unless expression.is_a?(IR::Name)
244
- global = @program.globals.find { |g| g.linkage_name == expression.name }
245
- next unless global
246
- next if reachable_names[global.linkage_name]
247
- reachable_names[global.linkage_name] = true
248
- traverse_ir_expression(global.value) do |inner|
249
- next unless inner.is_a?(IR::Name)
250
- dep = @program.globals.find { |g| g.linkage_name == inner.name }
251
- reachable_names[dep.linkage_name] = true if dep
252
- end
253
- end
254
- end
98
+ (@program.structs + @program.unions + @program.variants + @program.opaques).each do |decl|
99
+ active << decl.source_module if decl.source_module
100
+ end
255
101
 
256
- @program.globals.each do |global|
257
- next unless reachable_names[global.linkage_name]
258
- traverse_ir_expression(global.value) do |inner|
259
- next unless inner.is_a?(IR::Name)
260
- dep = @program.globals.find { |g| g.linkage_name == inner.name }
261
- reachable_names[dep.linkage_name] = true if dep
262
- end
263
- end
102
+ loop do
103
+ size_before = active.size
104
+ (@program.structs + @program.unions).each do |decl|
105
+ next unless decl.source_module
106
+ next unless active.include?(decl.source_module)
264
107
 
265
- @program.globals.select { |g| reachable_names[g.linkage_name] }
266
- end
108
+ decl.fields.each { |f| add_type_module(f.type, active) }
267
109
  end
110
+ @program.variants.each do |decl|
111
+ next unless decl.source_module
112
+ next unless active.include?(decl.source_module)
268
113
 
269
- def collect_called_function_names_from_statements(statements, functions_by_name, reachable_names, worklist)
270
- traverse_ir_statements(statements) do |expression|
271
- case expression
272
- when IR::Name
273
- callee = functions_by_name[expression.name]
274
- worklist << callee if callee && !reachable_names[callee.linkage_name]
275
- when IR::Call
276
- next unless expression.callee.is_a?(String)
277
-
278
- callee = functions_by_name[expression.callee]
279
- worklist << callee if callee && !reachable_names[callee.linkage_name]
280
- end
281
- end
114
+ decl.arms.each { |arm| arm.fields.each { |f| add_type_module(f.type, active) } }
282
115
  end
283
-
284
- def collect_called_function_names_from_expression(expression, functions_by_name, reachable_names, worklist)
285
- traverse_ir_expression(expression) do |candidate|
286
- case candidate
287
- when IR::Name
288
- callee = functions_by_name[candidate.name]
289
- worklist << callee if callee && !reachable_names[callee.linkage_name]
290
- when IR::Call
291
- next unless candidate.callee.is_a?(String)
292
-
293
- callee = functions_by_name[candidate.callee]
294
- worklist << callee if callee && !reachable_names[callee.linkage_name]
295
- end
296
- end
116
+ break if active.size == size_before
117
+ end
118
+
119
+ active
120
+ end
121
+
122
+ def collect_type_referenced_module_names
123
+ modules = Set.new
124
+ emitted_functions.each do |fn|
125
+ fn.params.each { |p| add_type_module(p.type, modules) }
126
+ add_type_module(fn.return_type, modules)
127
+ fn.body.each { |stmt| add_statement_type_modules(stmt, modules) }
128
+ end
129
+ modules
130
+ end
131
+
132
+ def add_statement_type_modules(stmt, modules)
133
+ case stmt
134
+ when IR::LocalDecl
135
+ add_type_module(stmt.type, modules)
136
+ when IR::ExpressionStmt
137
+ add_expr_type_module(stmt.expression, modules)
138
+ when IR::Assignment
139
+ add_expr_type_module(stmt.value, modules)
140
+ when IR::ReturnStmt
141
+ add_expr_type_module(stmt.value, modules) if stmt.value
142
+ when IR::IfStmt
143
+ stmt.then_body.each { |s| add_statement_type_modules(s, modules) }
144
+ stmt.else_body&.each { |s| add_statement_type_modules(s, modules) }
145
+ when IR::WhileStmt
146
+ stmt.body.each { |s| add_statement_type_modules(s, modules) }
147
+ when IR::ForStmt
148
+ stmt.body.each { |s| add_statement_type_modules(s, modules) }
149
+ end
150
+ end
151
+
152
+ def add_expr_type_module(expr, modules)
153
+ return unless expr
154
+ add_type_module(expr.type, modules) if expr.respond_to?(:type)
155
+ case expr
156
+ when IR::Call
157
+ expr.arguments.each { |a| add_expr_type_module(a, modules) }
158
+ when IR::Binary
159
+ add_expr_type_module(expr.left, modules)
160
+ add_expr_type_module(expr.right, modules)
161
+ when IR::AggregateLiteral
162
+ expr.fields.each { |f| add_expr_type_module(f.value, modules) }
163
+ when IR::VariantLiteral
164
+ expr.fields.each { |f| add_expr_type_module(f.value, modules) }
165
+ when IR::Conditional
166
+ add_expr_type_module(expr.then_expression, modules)
167
+ add_expr_type_module(expr.else_expression, modules)
168
+ when IR::Cast, IR::ReinterpretExpr, IR::AddressOf
169
+ add_expr_type_module(expr.expression, modules)
170
+ end
171
+ end
172
+
173
+ def add_type_module(type, modules)
174
+ return unless type
175
+ modules << type.module_name if type.respond_to?(:module_name) && type.module_name
176
+
177
+ case type
178
+ when Types::Nullable
179
+ add_type_module(type.base, modules)
180
+ when Types::Span
181
+ add_type_module(type.element_type, modules)
182
+ when Types::GenericInstance
183
+ type.arguments.each { |a| add_type_module(a, modules) unless a.is_a?(Types::LiteralTypeArg) }
184
+ when Types::Task
185
+ add_type_module(type.result_type, modules)
186
+ end
187
+ end
188
+
189
+
190
+ def emitted_aggregate_structs
191
+ @emitted_aggregate_structs ||= filter_by_type_reachability(@program.structs)
192
+ end
193
+
194
+ def emitted_aggregate_unions
195
+ @emitted_aggregate_unions ||= filter_by_type_reachability(@program.unions)
196
+ end
197
+
198
+ def emitted_aggregate_variants
199
+ @emitted_aggregate_variants ||= filter_by_type_reachability(@program.variants)
200
+ end
201
+
202
+ def filter_by_type_reachability(decls)
203
+ return decls if decls.empty?
204
+ return decls if decls.all? { |d| d.source_module.nil? }
205
+
206
+ active_modules = collect_active_module_names
207
+ by_c_name = decls.each_with_object({}) { |d, h| h[d.linkage_name] = d }
208
+
209
+ reachable = Set.new
210
+ decls.each do |decl|
211
+ next unless decl.source_module.nil? || active_modules.include?(decl.source_module)
212
+ reachable << decl.linkage_name
213
+ end
214
+
215
+ worklist = reachable.to_a
216
+ until worklist.empty?
217
+ linkage_name = worklist.shift
218
+ decl = by_c_name[linkage_name]
219
+ next unless decl
220
+
221
+ deps = aggregate_decl_dependencies(decl)
222
+ deps.each do |dep_name|
223
+ next unless by_c_name.key?(dep_name)
224
+ next if reachable.include?(dep_name)
225
+ reachable << dep_name
226
+ worklist << dep_name
297
227
  end
228
+ end
298
229
 
299
- def collect_referenced_constant_names_from_statements(statements, constants_by_name, referenced_names)
300
- visitor = constant_reference_visitor(constants_by_name, referenced_names)
301
- traverse_ir_statements(statements, visit_switch_case_values: true, &visitor)
302
- end
230
+ decls.select { |d| reachable.include?(d.linkage_name) }
231
+ end
303
232
 
304
- def collect_referenced_constant_names_from_expression(expression, constants_by_name, referenced_names)
305
- visitor = constant_reference_visitor(constants_by_name, referenced_names)
306
- traverse_ir_expression(expression, &visitor)
307
- end
233
+ def emitted_globals
234
+ @emitted_globals ||= begin
235
+ root_module_prefix = "#{module_c_prefix(@program.module_name)}_"
236
+ reachable_names = {}
237
+ @program.globals.select { |g| g.linkage_name.start_with?(root_module_prefix) }.each { |g| reachable_names[g.linkage_name] = true }
308
238
 
309
- def constant_reference_visitor(constants_by_name, referenced_names)
310
- lambda do |expression|
239
+ emitted_functions.each do |function|
240
+ traverse_ir_statements(function.body) do |expression|
311
241
  next unless expression.is_a?(IR::Name)
312
-
313
- constant = constants_by_name[expression.name]
314
- next unless constant
315
- next if referenced_names[constant.linkage_name]
316
-
317
- referenced_names[constant.linkage_name] = true
318
- traverse_ir_expression(constant.value, &constant_reference_visitor(constants_by_name, referenced_names))
242
+ global = @program.globals.find { |g| g.linkage_name == expression.name }
243
+ next unless global
244
+ next if reachable_names[global.linkage_name]
245
+ reachable_names[global.linkage_name] = true
246
+ traverse_ir_expression(global.value) do |inner|
247
+ next unless inner.is_a?(IR::Name)
248
+ dep = @program.globals.find { |g| g.linkage_name == inner.name }
249
+ reachable_names[dep.linkage_name] = true if dep
250
+ end
319
251
  end
320
252
  end
321
253
 
322
- def traverse_ir_statements(statements, visit_switch_case_values: false, &expression_visitor)
323
- Array(statements).compact.each do |statement|
324
- case statement
325
- when IR::LocalDecl
326
- traverse_ir_expression(statement.value, &expression_visitor)
327
- when IR::Assignment
328
- traverse_ir_expression(statement.target, &expression_visitor)
329
- traverse_ir_expression(statement.value, &expression_visitor)
330
- when IR::BlockStmt
331
- traverse_ir_statements(statement.body, visit_switch_case_values:, &expression_visitor)
332
- when IR::WhileStmt
333
- traverse_ir_expression(statement.condition, &expression_visitor)
334
- traverse_ir_statements(statement.body, visit_switch_case_values:, &expression_visitor)
335
- when IR::ForStmt
336
- traverse_ir_statements([statement.init], visit_switch_case_values:, &expression_visitor)
337
- traverse_ir_expression(statement.condition, &expression_visitor)
338
- traverse_ir_statements(statement.body, visit_switch_case_values:, &expression_visitor)
339
- traverse_ir_statements([statement.post], visit_switch_case_values:, &expression_visitor)
340
- when IR::IfStmt
341
- traverse_ir_expression(statement.condition, &expression_visitor)
342
- traverse_ir_statements(statement.then_body, visit_switch_case_values:, &expression_visitor)
343
- traverse_ir_statements(statement.else_body, visit_switch_case_values:, &expression_visitor) if statement.else_body
344
- when IR::SwitchStmt
345
- traverse_ir_expression(statement.expression, &expression_visitor)
346
- statement.cases.each do |switch_case|
347
- if visit_switch_case_values && switch_case.is_a?(IR::SwitchCase)
348
- traverse_ir_expression(switch_case.value, &expression_visitor)
349
- end
350
- traverse_ir_statements(switch_case.body, visit_switch_case_values:, &expression_visitor)
351
- end
352
- when IR::StaticAssert
353
- traverse_ir_expression(statement.condition, &expression_visitor)
354
- traverse_ir_expression(statement.message, &expression_visitor)
355
- when IR::ReturnStmt
356
- traverse_ir_expression(statement.value, &expression_visitor) if statement.value
357
- when IR::ExpressionStmt
358
- traverse_ir_expression(statement.expression, &expression_visitor)
359
- end
254
+ @program.globals.each do |global|
255
+ next unless reachable_names[global.linkage_name]
256
+ traverse_ir_expression(global.value) do |inner|
257
+ next unless inner.is_a?(IR::Name)
258
+ dep = @program.globals.find { |g| g.linkage_name == inner.name }
259
+ reachable_names[dep.linkage_name] = true if dep
360
260
  end
361
261
  end
362
262
 
363
- def traverse_ir_expression(expression, &expression_visitor)
364
- return if expression.nil?
365
-
366
- expression_visitor.call(expression) if expression_visitor
367
-
368
- case expression
369
- when IR::Member
370
- traverse_ir_expression(expression.receiver, &expression_visitor)
371
- when IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex
372
- traverse_ir_expression(expression.receiver, &expression_visitor)
373
- traverse_ir_expression(expression.index, &expression_visitor)
374
- when IR::Call
375
- traverse_ir_expression(expression.callee, &expression_visitor) unless expression.callee.is_a?(String)
376
- expression.arguments.each { |argument| traverse_ir_expression(argument, &expression_visitor) }
377
- when IR::Unary
378
- traverse_ir_expression(expression.operand, &expression_visitor)
379
- when IR::Binary
380
- traverse_ir_expression(expression.left, &expression_visitor)
381
- traverse_ir_expression(expression.right, &expression_visitor)
382
- when IR::Conditional
383
- traverse_ir_expression(expression.condition, &expression_visitor)
384
- traverse_ir_expression(expression.then_expression, &expression_visitor)
385
- traverse_ir_expression(expression.else_expression, &expression_visitor)
386
- when IR::ReinterpretExpr, IR::AddressOf, IR::Cast
387
- traverse_ir_expression(expression.expression, &expression_visitor)
388
- when IR::AggregateLiteral
389
- expression.fields.each { |field| traverse_ir_expression(field.value, &expression_visitor) }
390
- when IR::ArrayLiteral
391
- expression.elements.each { |element| traverse_ir_expression(element, &expression_visitor) }
392
- when IR::VariantLiteral
393
- expression.fields.each { |field| traverse_ir_expression(field.value, &expression_visitor) }
263
+ @program.globals.select { |g| reachable_names[g.linkage_name] }
264
+ end
265
+ end
266
+
267
+ def collect_called_function_names_from_statements(statements, functions_by_name, reachable_names, worklist)
268
+ traverse_ir_statements(statements) do |expression|
269
+ case expression
270
+ when IR::Name
271
+ callee = functions_by_name[expression.name]
272
+ worklist << callee if callee && !reachable_names[callee.linkage_name]
273
+ when IR::Call
274
+ next unless expression.callee.is_a?(String)
275
+
276
+ callee = functions_by_name[expression.callee]
277
+ worklist << callee if callee && !reachable_names[callee.linkage_name]
278
+ end
279
+ end
280
+ end
281
+
282
+ def collect_called_function_names_from_expression(expression, functions_by_name, reachable_names, worklist)
283
+ traverse_ir_expression(expression) do |candidate|
284
+ case candidate
285
+ when IR::Name
286
+ callee = functions_by_name[candidate.name]
287
+ worklist << callee if callee && !reachable_names[callee.linkage_name]
288
+ when IR::Call
289
+ next unless candidate.callee.is_a?(String)
290
+
291
+ callee = functions_by_name[candidate.callee]
292
+ worklist << callee if callee && !reachable_names[callee.linkage_name]
293
+ end
294
+ end
295
+ end
296
+
297
+ def collect_referenced_constant_names_from_statements(statements, constants_by_name, referenced_names)
298
+ visitor = constant_reference_visitor(constants_by_name, referenced_names)
299
+ traverse_ir_statements(statements, visit_switch_case_values: true, &visitor)
300
+ end
301
+
302
+ def collect_referenced_constant_names_from_expression(expression, constants_by_name, referenced_names)
303
+ visitor = constant_reference_visitor(constants_by_name, referenced_names)
304
+ traverse_ir_expression(expression, &visitor)
305
+ end
306
+
307
+ def constant_reference_visitor(constants_by_name, referenced_names)
308
+ lambda do |expression|
309
+ next unless expression.is_a?(IR::Name)
310
+
311
+ constant = constants_by_name[expression.name]
312
+ next unless constant
313
+ next if referenced_names[constant.linkage_name]
314
+
315
+ referenced_names[constant.linkage_name] = true
316
+ traverse_ir_expression(constant.value, &constant_reference_visitor(constants_by_name, referenced_names))
317
+ end
318
+ end
319
+
320
+ def traverse_ir_statements(statements, visit_switch_case_values: false, &expression_visitor)
321
+ Array(statements).compact.each do |statement|
322
+ case statement
323
+ when IR::LocalDecl
324
+ traverse_ir_expression(statement.value, &expression_visitor)
325
+ when IR::Assignment
326
+ traverse_ir_expression(statement.target, &expression_visitor)
327
+ traverse_ir_expression(statement.value, &expression_visitor)
328
+ when IR::BlockStmt
329
+ traverse_ir_statements(statement.body, visit_switch_case_values:, &expression_visitor)
330
+ when IR::WhileStmt
331
+ traverse_ir_expression(statement.condition, &expression_visitor)
332
+ traverse_ir_statements(statement.body, visit_switch_case_values:, &expression_visitor)
333
+ when IR::ForStmt
334
+ traverse_ir_statements([statement.init], visit_switch_case_values:, &expression_visitor)
335
+ traverse_ir_expression(statement.condition, &expression_visitor)
336
+ traverse_ir_statements(statement.body, visit_switch_case_values:, &expression_visitor)
337
+ traverse_ir_statements([statement.post], visit_switch_case_values:, &expression_visitor)
338
+ when IR::IfStmt
339
+ traverse_ir_expression(statement.condition, &expression_visitor)
340
+ traverse_ir_statements(statement.then_body, visit_switch_case_values:, &expression_visitor)
341
+ traverse_ir_statements(statement.else_body, visit_switch_case_values:, &expression_visitor) if statement.else_body
342
+ when IR::SwitchStmt
343
+ traverse_ir_expression(statement.expression, &expression_visitor)
344
+ statement.cases.each do |switch_case|
345
+ if visit_switch_case_values && switch_case.is_a?(IR::SwitchCase)
346
+ traverse_ir_expression(switch_case.value, &expression_visitor)
347
+ end
348
+ traverse_ir_statements(switch_case.body, visit_switch_case_values:, &expression_visitor)
394
349
  end
350
+ when IR::StaticAssert
351
+ traverse_ir_expression(statement.condition, &expression_visitor)
352
+ traverse_ir_expression(statement.message, &expression_visitor)
353
+ when IR::ReturnStmt
354
+ traverse_ir_expression(statement.value, &expression_visitor) if statement.value
355
+ when IR::ExpressionStmt
356
+ traverse_ir_expression(statement.expression, &expression_visitor)
395
357
  end
358
+ end
359
+ end
360
+
361
+ def traverse_ir_expression(expression, &expression_visitor)
362
+ return if expression.nil?
363
+
364
+ expression_visitor.call(expression) if expression_visitor
365
+
366
+ case expression
367
+ when IR::Member
368
+ traverse_ir_expression(expression.receiver, &expression_visitor)
369
+ when IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex
370
+ traverse_ir_expression(expression.receiver, &expression_visitor)
371
+ traverse_ir_expression(expression.index, &expression_visitor)
372
+ when IR::Call
373
+ traverse_ir_expression(expression.callee, &expression_visitor) unless expression.callee.is_a?(String)
374
+ expression.arguments.each { |argument| traverse_ir_expression(argument, &expression_visitor) }
375
+ when IR::Unary
376
+ traverse_ir_expression(expression.operand, &expression_visitor)
377
+ when IR::Binary
378
+ traverse_ir_expression(expression.left, &expression_visitor)
379
+ traverse_ir_expression(expression.right, &expression_visitor)
380
+ when IR::Conditional
381
+ traverse_ir_expression(expression.condition, &expression_visitor)
382
+ traverse_ir_expression(expression.then_expression, &expression_visitor)
383
+ traverse_ir_expression(expression.else_expression, &expression_visitor)
384
+ when IR::ReinterpretExpr, IR::AddressOf, IR::Cast
385
+ traverse_ir_expression(expression.expression, &expression_visitor)
386
+ when IR::AggregateLiteral
387
+ expression.fields.each { |field| traverse_ir_expression(field.value, &expression_visitor) }
388
+ when IR::ArrayLiteral
389
+ expression.elements.each { |element| traverse_ir_expression(element, &expression_visitor) }
390
+ when IR::VariantLiteral
391
+ expression.fields.each { |field| traverse_ir_expression(field.value, &expression_visitor) }
392
+ end
393
+ end
396
394
  end
397
395
  end
398
396
  end