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
data/Rakefile ADDED
@@ -0,0 +1,332 @@
1
+ require 'fileutils'
2
+ require 'open3'
3
+ require 'rake/testtask'
4
+ require_relative 'lib/milk_tea'
5
+ require_relative 'lib/milk_tea/bindings'
6
+
7
+ RAW_BINDINGS = MilkTea::RawBindings.default_registry(root: MilkTea.root)
8
+ IMPORTED_BINDINGS = MilkTea::ImportedBindings.default_registry(root: MilkTea.root)
9
+ ALL_TEST_PATTERN = '{test/compiler,test/tooling,test/std,test/bindings,test/packages}/**/*_test.rb'
10
+ COVERAGE_DIR = File.expand_path('coverage/minitest', __dir__)
11
+ COVERAGE_BASELINE_PATH = File.join(COVERAGE_DIR, 'baseline.json')
12
+ COVERAGE_TESTS_PATH = File.join(COVERAGE_DIR, 'tests.json')
13
+ COVERAGE_REPORT_PATH = File.join(COVERAGE_DIR, 'report.txt')
14
+ RAW_COVERAGE_DIR = File.expand_path('coverage/raw', __dir__)
15
+ RAW_COVERAGE_JSON_PATH = File.join(RAW_COVERAGE_DIR, 'coverage.json')
16
+ RAW_COVERAGE_SUMMARY_PATH = File.join(RAW_COVERAGE_DIR, 'summary.txt')
17
+ GENERATED_FIXTURE_FILE = File.expand_path('test/fixtures/language_fixture.mt', __dir__)
18
+ GENERATED_FIXTURE_DIR = File.expand_path('test/fixtures/language_fixture', __dir__)
19
+ GENERATED_FIXTURE_ROOT = File.expand_path('test/fixtures', __dir__)
20
+
21
+ task default: :test
22
+ task verify: [:test, *RAW_BINDINGS.check_task_names, *IMPORTED_BINDINGS.check_task_names]
23
+
24
+ desc 'Run all tests'
25
+ Rake::TestTask.new do |t|
26
+ t.libs << '.'
27
+ t.libs << 'test'
28
+ t.loader = :direct
29
+ t.test_files = FileList[ALL_TEST_PATTERN].sort.map { |path| File.expand_path(path) }
30
+ end
31
+
32
+ namespace :test do
33
+ {
34
+ compiler: 'test/compiler/**/*_test.rb',
35
+ tooling: 'test/tooling/**/*_test.rb',
36
+ std: 'test/std/**/*_test.rb',
37
+ packages: 'test/packages/**/*_test.rb',
38
+ }.each do |name, pattern|
39
+ desc "Run #{name} tests"
40
+ Rake::TestTask.new(name) do |t|
41
+ t.libs << 'test'
42
+ t.pattern = pattern
43
+ end
44
+ end
45
+ end
46
+
47
+ namespace :coverage do
48
+ def coverage_test_files
49
+ Rake::FileList[ALL_TEST_PATTERN].sort
50
+ end
51
+
52
+ def cleanup_generated_fixture_artifacts
53
+ FileUtils.rm_f(GENERATED_FIXTURE_FILE)
54
+ FileUtils.rm_rf(GENERATED_FIXTURE_DIR)
55
+ Dir.rmdir(GENERATED_FIXTURE_ROOT) if Dir.exist?(GENERATED_FIXTURE_ROOT) && Dir.empty?(GENERATED_FIXTURE_ROOT)
56
+ end
57
+
58
+ def move_coverage_output(destination)
59
+ source = File.expand_path('coverage.json', __dir__)
60
+ raise 'minitest-coverage did not write coverage.json' unless File.file?(source)
61
+
62
+ FileUtils.mkdir_p(File.dirname(destination))
63
+ FileUtils.rm_f(destination)
64
+ FileUtils.mv(source, destination)
65
+ end
66
+
67
+ desc 'Generate the minitest-coverage baseline for the current implementation'
68
+ task :baseline do
69
+ FileUtils.mkdir_p(COVERAGE_DIR)
70
+ FileUtils.rm_f(File.expand_path('coverage.json', __dir__))
71
+ cleanup_generated_fixture_artifacts
72
+ sh 'bundle', 'exec', 'minitest_coverage_baseline'
73
+ move_coverage_output(COVERAGE_BASELINE_PATH)
74
+ end
75
+
76
+ desc 'Run the full test suite under minitest-coverage'
77
+ task full: :baseline do
78
+ files = coverage_test_files
79
+ raise "no tests matched #{ALL_TEST_PATTERN}" if files.empty?
80
+
81
+ FileUtils.rm_f(File.expand_path('coverage.json', __dir__))
82
+ begin
83
+ sh 'bundle', 'exec', 'minitest_coverage', "--coverage=#{COVERAGE_BASELINE_PATH}", *files
84
+ move_coverage_output(COVERAGE_TESTS_PATH)
85
+ ensure
86
+ cleanup_generated_fixture_artifacts
87
+ end
88
+ end
89
+
90
+ desc 'Generate and save the minitest-coverage report for the full test suite'
91
+ task report: :full do
92
+ FileUtils.mkdir_p(COVERAGE_DIR)
93
+ output, status = Open3.capture2e('bundle', 'exec', 'minitest_coverage_report', COVERAGE_BASELINE_PATH, COVERAGE_TESTS_PATH)
94
+ raise 'minitest-coverage report failed' unless status.success?
95
+
96
+ File.write(COVERAGE_REPORT_PATH, output)
97
+ puts output
98
+ end
99
+
100
+ desc 'Generate a plain Ruby Coverage line report for the full test suite'
101
+ task :raw do
102
+ files = coverage_test_files
103
+ raise "no tests matched #{ALL_TEST_PATTERN}" if files.empty?
104
+
105
+ begin
106
+ cleanup_generated_fixture_artifacts
107
+ sh(
108
+ {
109
+ 'MILK_TEA_RAW_COVERAGE_JSON_PATH' => RAW_COVERAGE_JSON_PATH,
110
+ 'MILK_TEA_RAW_COVERAGE_SUMMARY_PATH' => RAW_COVERAGE_SUMMARY_PATH,
111
+ },
112
+ 'bundle', 'exec', 'ruby', 'test/raw_coverage_runner.rb', *files,
113
+ )
114
+ ensure
115
+ cleanup_generated_fixture_artifacts
116
+ end
117
+ end
118
+
119
+ desc 'Remove generated minitest coverage artifacts'
120
+ task :clean do
121
+ FileUtils.rm_rf(COVERAGE_DIR)
122
+ FileUtils.rm_rf(RAW_COVERAGE_DIR)
123
+ FileUtils.rm_f(File.expand_path('coverage.json', __dir__))
124
+ cleanup_generated_fixture_artifacts
125
+ end
126
+ end
127
+
128
+ desc 'Generate the minitest-coverage report for the full suite'
129
+ task coverage: 'coverage:report'
130
+
131
+ namespace :deps do
132
+ desc 'Ensure vendored third_party upstream folders are present at the pinned revisions'
133
+ task :bootstrap do
134
+ MilkTea::UpstreamSources.bootstrap_all!.each do |result|
135
+ verb = result.status == :present ? 'kept' : 'bootstrapped'
136
+ puts "#{verb} #{result.source.name} -> #{result.path}"
137
+ end
138
+ end
139
+
140
+ desc 'Resolve a git tag or branch to a commit hash for an upstream source'
141
+ task :resolve, [:source, :ref] do |_t, args|
142
+ source_name = args[:source]
143
+ ref = args[:ref]
144
+ unless source_name && ref
145
+ puts "usage: rake deps:resolve[source_name,tag_or_branch]"
146
+ puts "example: rake deps:resolve[raylib,v5.5]"
147
+ exit 1
148
+ end
149
+
150
+ source = MilkTea::UpstreamSources.find_source(source_name)
151
+ unless source
152
+ known = MilkTea::UpstreamSources.default_sources.map(&:name).join(", ")
153
+ puts "unknown upstream source: #{source_name}"
154
+ puts "known sources: #{known}"
155
+ exit 1
156
+ end
157
+
158
+ hash = MilkTea::UpstreamSources.resolve_ref(source.repository_url, ref)
159
+ puts "#{source_name}: #{ref.inspect} → #{hash}"
160
+ end
161
+
162
+ desc 'Pin an upstream source to a new revision (tag, branch, or commit hash)'
163
+ task :bump, [:source, :version] do |_t, args|
164
+ source_name = args[:source]
165
+ version = args[:version]
166
+ unless source_name && version
167
+ puts "usage: rake deps:bump[source_name,version]"
168
+ puts " version may be a tag (v6.0.0), branch, or full commit hash"
169
+ puts "example: rake deps:bump[raylib,v6.0.0]"
170
+ exit 1
171
+ end
172
+
173
+ source = MilkTea::UpstreamSources.find_source(source_name)
174
+ unless source
175
+ known = MilkTea::UpstreamSources.default_sources.map(&:name).join(", ")
176
+ puts "error: unknown upstream source: #{source_name}"
177
+ puts "known sources: #{known}"
178
+ exit 1
179
+ end
180
+
181
+ hash = MilkTea::UpstreamSources.resolve_ref(source.repository_url, version)
182
+ MilkTea::UpstreamSources.write_version_override(source_name, hash)
183
+ puts "pinned #{source_name} to #{hash} (resolved from #{version.inspect})"
184
+ puts "updated config/upstream_versions.yml"
185
+ end
186
+
187
+ desc 'Upgrade an upstream C library: bump revision, rebootstrap, regenerate all bindings'
188
+ task :upgrade, [:source, :version] do |_t, args|
189
+ source_name = args[:source]
190
+ version = args[:version]
191
+ unless source_name && version
192
+ puts "usage: rake deps:upgrade[source_name,version]"
193
+ puts " version may be a tag (v6.0.0), branch, or full commit hash"
194
+ puts "example: rake deps:upgrade[raylib,v6.0.0]"
195
+ puts ""
196
+ puts "this runs: bump → bootstrap → bindgen:all → imported_bindings:all → verify"
197
+ exit 1
198
+ end
199
+
200
+ source = MilkTea::UpstreamSources.find_source(source_name)
201
+ unless source
202
+ known = MilkTea::UpstreamSources.default_sources.map(&:name).join(", ")
203
+ puts "error: unknown upstream source: #{source_name}"
204
+ puts "known sources: #{known}"
205
+ exit 1
206
+ end
207
+
208
+ puts "=== Step 1/5: bump #{source_name} to #{version.inspect} ==="
209
+ hash = MilkTea::UpstreamSources.resolve_ref(source.repository_url, version)
210
+ MilkTea::UpstreamSources.write_version_override(source_name, hash)
211
+ puts "pinned #{source_name} → #{hash}"
212
+
213
+ puts ""
214
+ puts "=== Step 2/5: bootstrap #{source_name} ==="
215
+ result = MilkTea::UpstreamSources.bootstrap_one(source_name)
216
+ puts "#{result.status == :present ? 'kept' : 'bootstrapped'} #{source_name} -> #{result.path}"
217
+
218
+ puts ""
219
+ puts "=== Step 3/5: regenerate raw bindings (bindgen:all) ==="
220
+ Rake::Task["bindgen:all"].invoke
221
+
222
+ puts ""
223
+ puts "=== Step 4/5: regenerate imported bindings (imported_bindings:all) ==="
224
+ Rake::Task["imported_bindings:all"].invoke
225
+
226
+ puts ""
227
+ puts "=== Step 5/5: verify bindings up-to-date ==="
228
+ Rake::Task["bindgen:check:all"].invoke rescue nil
229
+ Rake::Task["imported_bindings:check:all"].invoke rescue nil
230
+
231
+ puts ""
232
+ puts "done. #{source_name} upgraded to #{hash}."
233
+ puts "review changes with: git diff std/"
234
+ end
235
+
236
+ desc 'List all upstream sources and their current pinned revisions'
237
+ task :list do
238
+ overrides = MilkTea::UpstreamSources.load_version_overrides
239
+ MilkTea::UpstreamSources.default_sources.each do |source|
240
+ overridden = overrides.key?(source.name)
241
+ marker = overridden ? " [OVERRIDDEN]" : ""
242
+ puts "#{source.name}: #{source.revision}#{marker}"
243
+ end
244
+ end
245
+
246
+ desc 'Remove a version override, reverting to the hardcoded default revision'
247
+ task :revert, [:source] do |_t, args|
248
+ source_name = args[:source]
249
+ unless source_name
250
+ puts "usage: rake deps:revert[source_name]"
251
+ exit 1
252
+ end
253
+
254
+ MilkTea::UpstreamSources.remove_version_override(source_name)
255
+ puts "removed override for #{source_name} — next bootstrap will use hardcoded default revision"
256
+ end
257
+ end
258
+
259
+ namespace :tools do
260
+ desc 'Build all vendored tool binaries (e.g. tracy-profiler) and install into bin/'
261
+ task :build do
262
+ results = MilkTea::VendoredTools.build_all!(root: MilkTea.root)
263
+ results.each do |result|
264
+ puts "built #{result[:tool].name} -> #{result[:binary]}"
265
+ end
266
+ end
267
+ end
268
+
269
+ namespace :imported_bindings do
270
+ desc 'Regenerate all checked-in imported binding modules'
271
+ task all: IMPORTED_BINDINGS.task_names
272
+
273
+ namespace :check do
274
+ desc 'Check all checked-in imported binding modules'
275
+ task all: IMPORTED_BINDINGS.check_task_names
276
+ end
277
+
278
+ IMPORTED_BINDINGS.each do |binding|
279
+ desc "Regenerate #{binding.binding_path} from #{binding.raw_module_name} and #{binding.policy_path}"
280
+ task binding.name.to_sym do
281
+ raw_module_path = binding.write!
282
+ puts "generated #{raw_module_path} + #{binding.policy_path} -> #{binding.binding_path}"
283
+ end
284
+
285
+ namespace :check do
286
+ desc "Check that #{binding.binding_path} matches the current imported binding policy"
287
+ task binding.name.to_sym do
288
+ raw_module_path = binding.check!
289
+ puts "verified #{binding.binding_path} matches #{raw_module_path} + #{binding.policy_path}"
290
+ end
291
+ end
292
+ end
293
+ end
294
+
295
+ namespace :release do
296
+ desc "Build and publish the gem to RubyGems.org"
297
+ task :push do
298
+ sh "gem build milk_tea.gemspec"
299
+ gem_file = Dir["milk_tea-*.gem"].sort_by { |f| File.mtime(f) }.last
300
+ sh "gem push #{gem_file}"
301
+ end
302
+ end
303
+
304
+ namespace :bindgen do
305
+ desc 'Regenerate all checked-in raw binding modules'
306
+ task all: RAW_BINDINGS.task_names
307
+
308
+ namespace :check do
309
+ desc 'Check all checked-in raw binding modules'
310
+ task all: RAW_BINDINGS.check_task_names
311
+ end
312
+
313
+ RAW_BINDINGS.each do |binding|
314
+ desc "Regenerate #{binding.binding_path} from the installed #{binding.header_label}"
315
+ task binding.name.to_sym do
316
+ header_path = binding.write!
317
+ report_path = binding.write_nullable_policy_report!(env: ENV, header_path: header_path)
318
+ puts "generated #{header_path} -> #{binding.binding_path}"
319
+ puts "nullable report #{header_path} -> #{report_path}"
320
+ end
321
+
322
+ namespace :check do
323
+ desc "Check that #{binding.binding_path} matches current bindgen output"
324
+ task binding.name.to_sym do
325
+ header_path = binding.check!
326
+ puts "verified #{binding.binding_path} matches bindgen output from #{header_path}"
327
+ end
328
+ end
329
+
330
+ task "check_#{binding.name}".to_sym => binding.check_task_name
331
+ end
332
+ end
data/bin/mtc ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
+
6
+ require "milk_tea"
7
+
8
+ exit(MilkTea::CLI.start(ARGV))
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "English"
5
+
6
+ DEFAULT_PATTERNS = [
7
+ "projects/**/*.mt",
8
+ ].freeze
9
+
10
+ def usage(io)
11
+ io.puts <<~TEXT
12
+ Usage: ruby bin/profile-mtc-checks [--start-after PATH] [--report-all] [--summary PATH] [PATH_OR_GLOB ...]
13
+
14
+ Run `bin/mtc check` over the matched files, printing elapsed time for each file.
15
+ Defaults to:
16
+ projects/**/*.mt
17
+ TEXT
18
+ end
19
+
20
+ def parse_arguments(argv)
21
+ patterns = []
22
+ start_after = nil
23
+ report_all = false
24
+ summary_path = nil
25
+
26
+ until argv.empty?
27
+ argument = argv.shift
28
+
29
+ case argument
30
+ when "-h", "--help"
31
+ usage($stdout)
32
+ exit(0)
33
+ when "--start-after"
34
+ abort("missing path after --start-after") if argv.empty?
35
+
36
+ start_after = argv.shift
37
+ when /\A--start-after=(.+)\z/
38
+ start_after = Regexp.last_match(1)
39
+ when "--report-all"
40
+ report_all = true
41
+ when "--summary"
42
+ abort("missing path after --summary") if argv.empty?
43
+
44
+ summary_path = argv.shift
45
+ when /\A--summary=(.+)\z/
46
+ summary_path = Regexp.last_match(1)
47
+ else
48
+ patterns << argument
49
+ end
50
+ end
51
+
52
+ [
53
+ start_after,
54
+ report_all,
55
+ summary_path,
56
+ patterns.empty? ? DEFAULT_PATTERNS : patterns,
57
+ ]
58
+ end
59
+
60
+ def expand_files(patterns)
61
+ patterns.flat_map { |pattern| Dir.glob(pattern) }
62
+ .select { |path| File.file?(path) }
63
+ .uniq
64
+ .sort
65
+ end
66
+
67
+ def resume_from(files, start_after)
68
+ return files if start_after.nil?
69
+
70
+ start_index = files.index(start_after)
71
+ abort("start-after path not found in selected files: #{start_after}") if start_index.nil?
72
+
73
+ files[(start_index + 1)..] || []
74
+ end
75
+
76
+ def write_summary(summary_path, failures)
77
+ return if summary_path.nil?
78
+
79
+ File.write(
80
+ summary_path,
81
+ failures.map { |failure| "#{failure[:path]}\t#{failure[:exitstatus]}" }.join("\n") + (failures.empty? ? "" : "\n"),
82
+ )
83
+ end
84
+
85
+ start_after, report_all, summary_path, patterns = parse_arguments(ARGV.dup)
86
+ files = resume_from(expand_files(patterns), start_after)
87
+
88
+ abort("no files matched the selected paths") if files.empty?
89
+
90
+ total_started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
91
+ failures = []
92
+
93
+ files.each_with_index do |path, index|
94
+ current = index + 1
95
+ total = files.length
96
+ puts(format("[start %03d/%03d] %s", current, total, path))
97
+
98
+ started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
99
+ success = system("ruby", "bin/mtc", "check", path)
100
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at
101
+
102
+ puts(format("[done %03d/%03d] %7.3fs %s", current, total, elapsed, path))
103
+
104
+ next if success
105
+
106
+ puts("FAILED:#{path}")
107
+
108
+ failures << {
109
+ path: path,
110
+ exitstatus: $CHILD_STATUS&.exitstatus || 1,
111
+ }
112
+
113
+ unless report_all
114
+ write_summary(summary_path, failures)
115
+ exit(failures.first[:exitstatus])
116
+ end
117
+ end
118
+
119
+ total_elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - total_started_at
120
+ puts(format("[total] %7.3fs %d files", total_elapsed, files.length))
121
+
122
+ if failures.empty?
123
+ write_summary(summary_path, failures)
124
+ exit(0)
125
+ end
126
+
127
+ puts(format("[failures] %d", failures.length))
128
+ failures.each do |failure|
129
+ puts(format("[failure] exit=%d %s", failure[:exitstatus], failure[:path]))
130
+ end
131
+
132
+ write_summary(summary_path, failures)
133
+ exit(failures.first[:exitstatus])
Binary file