rbs 4.0.0.dev.4 → 4.1.0.pre.2

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 (306) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +1 -0
  3. data/.github/dependabot.yml +16 -14
  4. data/.github/workflows/bundle-update.yml +63 -0
  5. data/.github/workflows/c-check.yml +21 -11
  6. data/.github/workflows/comments.yml +5 -3
  7. data/.github/workflows/dependabot.yml +2 -2
  8. data/.github/workflows/jruby.yml +67 -0
  9. data/.github/workflows/milestone.yml +83 -0
  10. data/.github/workflows/ruby.yml +63 -24
  11. data/.github/workflows/rust.yml +184 -0
  12. data/.github/workflows/truffleruby.yml +54 -0
  13. data/.github/workflows/typecheck.yml +5 -2
  14. data/.github/workflows/wasm.yml +53 -0
  15. data/.github/workflows/windows.yml +8 -2
  16. data/.gitignore +11 -0
  17. data/.rubocop.yml +1 -1
  18. data/CHANGELOG.md +357 -0
  19. data/README.md +4 -4
  20. data/Rakefile +365 -33
  21. data/Steepfile +8 -0
  22. data/config.yml +450 -24
  23. data/core/array.rbs +443 -363
  24. data/core/basic_object.rbs +9 -8
  25. data/core/binding.rbs +0 -2
  26. data/core/builtin.rbs +9 -8
  27. data/core/class.rbs +11 -8
  28. data/core/comparable.rbs +55 -34
  29. data/core/complex.rbs +104 -78
  30. data/core/dir.rbs +61 -49
  31. data/core/encoding.rbs +12 -15
  32. data/core/enumerable.rbs +288 -196
  33. data/core/enumerator/arithmetic_sequence.rbs +70 -0
  34. data/core/enumerator/product.rbs +5 -5
  35. data/core/enumerator.rbs +91 -28
  36. data/core/errno.rbs +11 -2
  37. data/core/errors.rbs +58 -29
  38. data/core/exception.rbs +13 -13
  39. data/core/fiber.rbs +74 -54
  40. data/core/file.rbs +260 -1151
  41. data/core/file_constants.rbs +463 -0
  42. data/core/file_stat.rbs +534 -0
  43. data/core/file_test.rbs +3 -3
  44. data/core/float.rbs +257 -92
  45. data/core/gc.rbs +425 -281
  46. data/core/hash.rbs +1151 -829
  47. data/core/integer.rbs +156 -195
  48. data/core/io/buffer.rbs +53 -42
  49. data/core/io/wait.rbs +13 -35
  50. data/core/io.rbs +216 -150
  51. data/core/kernel.rbs +239 -163
  52. data/core/marshal.rbs +4 -4
  53. data/core/match_data.rbs +15 -13
  54. data/core/math.rbs +107 -66
  55. data/core/method.rbs +69 -33
  56. data/core/module.rbs +302 -150
  57. data/core/nil_class.rbs +7 -6
  58. data/core/numeric.rbs +77 -63
  59. data/core/object.rbs +9 -11
  60. data/core/object_space/weak_key_map.rbs +7 -7
  61. data/core/object_space.rbs +30 -23
  62. data/core/pathname.rbs +1322 -0
  63. data/core/proc.rbs +95 -58
  64. data/core/process.rbs +222 -202
  65. data/core/ractor.rbs +371 -515
  66. data/core/random.rbs +21 -3
  67. data/core/range.rbs +181 -79
  68. data/core/rational.rbs +60 -89
  69. data/core/rbs/ops.rbs +154 -0
  70. data/core/rbs/unnamed/argf.rbs +63 -56
  71. data/core/rbs/unnamed/env_class.rbs +19 -14
  72. data/core/rbs/unnamed/main_class.rbs +123 -0
  73. data/core/rbs/unnamed/random.rbs +11 -118
  74. data/core/regexp.rbs +258 -214
  75. data/core/ruby.rbs +53 -0
  76. data/core/ruby_vm.rbs +78 -34
  77. data/core/rubygems/config_file.rbs +5 -5
  78. data/core/rubygems/errors.rbs +4 -71
  79. data/core/rubygems/requirement.rbs +5 -5
  80. data/core/rubygems/rubygems.rbs +16 -82
  81. data/core/rubygems/version.rbs +2 -3
  82. data/core/set.rbs +493 -363
  83. data/core/signal.rbs +26 -16
  84. data/core/string.rbs +3234 -1285
  85. data/core/struct.rbs +43 -42
  86. data/core/symbol.rbs +41 -34
  87. data/core/thread.rbs +141 -73
  88. data/core/time.rbs +81 -50
  89. data/core/trace_point.rbs +41 -35
  90. data/core/true_class.rbs +2 -2
  91. data/core/unbound_method.rbs +24 -16
  92. data/core/warning.rbs +7 -7
  93. data/docs/CONTRIBUTING.md +2 -1
  94. data/docs/aliases.md +79 -0
  95. data/docs/collection.md +3 -3
  96. data/docs/config.md +171 -0
  97. data/docs/encoding.md +56 -0
  98. data/docs/gem.md +0 -1
  99. data/docs/inline.md +634 -0
  100. data/docs/rbs_by_example.md +20 -20
  101. data/docs/rust.md +96 -0
  102. data/docs/sigs.md +3 -3
  103. data/docs/syntax.md +48 -18
  104. data/docs/type_fingerprint.md +21 -0
  105. data/docs/wasm_serialization.md +80 -0
  106. data/exe/rbs +1 -1
  107. data/ext/rbs_extension/ast_translation.c +1441 -671
  108. data/ext/rbs_extension/ast_translation.h +7 -0
  109. data/ext/rbs_extension/class_constants.c +18 -2
  110. data/ext/rbs_extension/class_constants.h +9 -0
  111. data/ext/rbs_extension/extconf.rb +6 -1
  112. data/ext/rbs_extension/legacy_location.c +33 -56
  113. data/ext/rbs_extension/legacy_location.h +37 -0
  114. data/ext/rbs_extension/main.c +183 -39
  115. data/include/rbs/ast.h +597 -297
  116. data/include/rbs/defines.h +40 -0
  117. data/include/rbs/lexer.h +31 -11
  118. data/include/rbs/location.h +25 -44
  119. data/include/rbs/parser.h +6 -6
  120. data/include/rbs/serialize.h +39 -0
  121. data/include/rbs/string.h +0 -2
  122. data/include/rbs/util/rbs_allocator.h +34 -13
  123. data/include/rbs/util/rbs_assert.h +12 -1
  124. data/include/rbs/util/rbs_constant_pool.h +0 -3
  125. data/include/rbs/util/rbs_encoding.h +2 -0
  126. data/include/rbs/util/rbs_unescape.h +2 -1
  127. data/include/rbs.h +8 -0
  128. data/lib/rbs/annotate/rdoc_annotator.rb +27 -31
  129. data/lib/rbs/ast/annotation.rb +1 -1
  130. data/lib/rbs/ast/comment.rb +1 -1
  131. data/lib/rbs/ast/declarations.rb +10 -10
  132. data/lib/rbs/ast/members.rb +14 -14
  133. data/lib/rbs/ast/ruby/annotations.rb +335 -3
  134. data/lib/rbs/ast/ruby/comment_block.rb +30 -4
  135. data/lib/rbs/ast/ruby/declarations.rb +209 -4
  136. data/lib/rbs/ast/ruby/helpers/constant_helper.rb +4 -0
  137. data/lib/rbs/ast/ruby/helpers/location_helper.rb +1 -1
  138. data/lib/rbs/ast/ruby/members.rb +571 -22
  139. data/lib/rbs/ast/type_param.rb +24 -4
  140. data/lib/rbs/buffer.rb +66 -24
  141. data/lib/rbs/cli/diff.rb +16 -15
  142. data/lib/rbs/cli/validate.rb +38 -106
  143. data/lib/rbs/cli.rb +55 -24
  144. data/lib/rbs/collection/config/lockfile_generator.rb +28 -3
  145. data/lib/rbs/collection/sources/git.rb +7 -0
  146. data/lib/rbs/definition.rb +1 -1
  147. data/lib/rbs/definition_builder/ancestor_builder.rb +62 -9
  148. data/lib/rbs/definition_builder/method_builder.rb +32 -6
  149. data/lib/rbs/definition_builder.rb +147 -25
  150. data/lib/rbs/diff.rb +7 -1
  151. data/lib/rbs/environment.rb +235 -75
  152. data/lib/rbs/environment_loader.rb +0 -6
  153. data/lib/rbs/errors.rb +27 -18
  154. data/lib/rbs/inline_parser.rb +377 -15
  155. data/lib/rbs/location_aux.rb +1 -1
  156. data/lib/rbs/locator.rb +5 -1
  157. data/lib/rbs/method_type.rb +5 -3
  158. data/lib/rbs/namespace.rb +47 -11
  159. data/lib/rbs/parser_aux.rb +20 -7
  160. data/lib/rbs/prototype/helpers.rb +57 -0
  161. data/lib/rbs/prototype/rb.rb +3 -28
  162. data/lib/rbs/prototype/rbi.rb +3 -20
  163. data/lib/rbs/prototype/runtime.rb +10 -0
  164. data/lib/rbs/resolver/constant_resolver.rb +2 -2
  165. data/lib/rbs/resolver/type_name_resolver.rb +120 -44
  166. data/lib/rbs/rewriter.rb +70 -0
  167. data/lib/rbs/subtractor.rb +3 -1
  168. data/lib/rbs/test/type_check.rb +25 -3
  169. data/lib/rbs/type_name.rb +34 -14
  170. data/lib/rbs/types.rb +88 -78
  171. data/lib/rbs/unit_test/type_assertions.rb +44 -8
  172. data/lib/rbs/validator.rb +2 -2
  173. data/lib/rbs/version.rb +1 -1
  174. data/lib/rbs/wasm/deserializer.rb +213 -0
  175. data/lib/rbs/wasm/location.rb +61 -0
  176. data/lib/rbs/wasm/parser.rb +137 -0
  177. data/lib/rbs/wasm/runtime.rb +217 -0
  178. data/lib/rbs/wasm/serialization_schema.rb +110 -0
  179. data/lib/rbs.rb +13 -2
  180. data/lib/rdoc/discover.rb +1 -1
  181. data/lib/rdoc_plugin/parser.rb +1 -1
  182. data/rbs.gemspec +24 -6
  183. data/schema/typeParam.json +17 -1
  184. data/sig/annotate/rdoc_annotater.rbs +12 -9
  185. data/sig/ast/ruby/annotations.rbs +364 -4
  186. data/sig/ast/ruby/comment_block.rbs +8 -0
  187. data/sig/ast/ruby/declarations.rbs +102 -4
  188. data/sig/ast/ruby/members.rbs +128 -2
  189. data/sig/buffer.rbs +19 -1
  190. data/sig/cli/diff.rbs +5 -11
  191. data/sig/cli/validate.rbs +12 -8
  192. data/sig/cli.rbs +18 -18
  193. data/sig/collection/config/lockfile_generator.rbs +2 -0
  194. data/sig/definition.rbs +6 -1
  195. data/sig/definition_builder.rbs +2 -0
  196. data/sig/environment.rbs +70 -12
  197. data/sig/errors.rbs +13 -14
  198. data/sig/inline_parser.rbs +41 -2
  199. data/sig/locator.rbs +0 -2
  200. data/sig/manifest.yaml +0 -2
  201. data/sig/method_builder.rbs +3 -1
  202. data/sig/namespace.rbs +20 -0
  203. data/sig/parser.rbs +41 -13
  204. data/sig/prototype/helpers.rbs +2 -0
  205. data/sig/resolver/type_name_resolver.rbs +36 -10
  206. data/sig/rewriter.rbs +45 -0
  207. data/sig/source.rbs +3 -3
  208. data/sig/type_param.rbs +13 -8
  209. data/sig/typename.rbs +15 -0
  210. data/sig/types.rbs +6 -7
  211. data/sig/unit_test/spy.rbs +0 -8
  212. data/sig/unit_test/type_assertions.rbs +15 -0
  213. data/sig/wasm/deserializer.rbs +66 -0
  214. data/sig/wasm/serialization_schema.rbs +13 -0
  215. data/src/ast.c +443 -162
  216. data/src/lexer.c +1415 -1313
  217. data/src/lexer.re +4 -0
  218. data/src/lexstate.c +63 -37
  219. data/src/location.c +7 -47
  220. data/src/parser.c +1032 -521
  221. data/src/serialize.c +958 -0
  222. data/src/string.c +0 -48
  223. data/src/util/rbs_allocator.c +89 -74
  224. data/src/util/rbs_assert.c +1 -1
  225. data/src/util/rbs_buffer.c +2 -2
  226. data/src/util/rbs_constant_pool.c +10 -14
  227. data/src/util/rbs_encoding.c +4 -8
  228. data/src/util/rbs_unescape.c +56 -20
  229. data/stdlib/abbrev/0/array.rbs +1 -1
  230. data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
  231. data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
  232. data/stdlib/cgi/0/core.rbs +9 -393
  233. data/stdlib/cgi/0/manifest.yaml +1 -0
  234. data/stdlib/cgi-escape/0/escape.rbs +171 -0
  235. data/stdlib/coverage/0/coverage.rbs +7 -4
  236. data/stdlib/csv/0/csv.rbs +5 -5
  237. data/stdlib/date/0/date.rbs +92 -79
  238. data/stdlib/date/0/date_time.rbs +25 -24
  239. data/stdlib/delegate/0/delegator.rbs +10 -7
  240. data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
  241. data/stdlib/digest/0/digest.rbs +111 -1
  242. data/stdlib/erb/0/erb.rbs +748 -347
  243. data/stdlib/etc/0/etc.rbs +73 -54
  244. data/stdlib/fileutils/0/fileutils.rbs +179 -160
  245. data/stdlib/forwardable/0/forwardable.rbs +13 -10
  246. data/stdlib/io-console/0/io-console.rbs +2 -2
  247. data/stdlib/json/0/json.rbs +223 -142
  248. data/stdlib/monitor/0/monitor.rbs +3 -3
  249. data/stdlib/net-http/0/net-http.rbs +162 -134
  250. data/stdlib/objspace/0/objspace.rbs +17 -34
  251. data/stdlib/open-uri/0/open-uri.rbs +48 -8
  252. data/stdlib/open3/0/open3.rbs +469 -10
  253. data/stdlib/openssl/0/openssl.rbs +482 -364
  254. data/stdlib/optparse/0/optparse.rbs +26 -17
  255. data/stdlib/pathname/0/pathname.rbs +11 -1381
  256. data/stdlib/pp/0/pp.rbs +9 -8
  257. data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
  258. data/stdlib/pstore/0/pstore.rbs +35 -30
  259. data/stdlib/psych/0/psych.rbs +65 -12
  260. data/stdlib/psych/0/store.rbs +2 -4
  261. data/stdlib/pty/0/pty.rbs +9 -6
  262. data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
  263. data/stdlib/rdoc/0/code_object.rbs +2 -1
  264. data/stdlib/rdoc/0/parser.rbs +1 -1
  265. data/stdlib/rdoc/0/rdoc.rbs +1 -1
  266. data/stdlib/rdoc/0/store.rbs +1 -1
  267. data/stdlib/resolv/0/resolv.rbs +26 -69
  268. data/stdlib/ripper/0/ripper.rbs +22 -19
  269. data/stdlib/securerandom/0/manifest.yaml +2 -0
  270. data/stdlib/securerandom/0/securerandom.rbs +7 -20
  271. data/stdlib/shellwords/0/shellwords.rbs +3 -3
  272. data/stdlib/singleton/0/singleton.rbs +3 -0
  273. data/stdlib/socket/0/addrinfo.rbs +7 -7
  274. data/stdlib/socket/0/basic_socket.rbs +3 -3
  275. data/stdlib/socket/0/ip_socket.rbs +10 -8
  276. data/stdlib/socket/0/socket.rbs +23 -10
  277. data/stdlib/socket/0/tcp_server.rbs +1 -1
  278. data/stdlib/socket/0/tcp_socket.rbs +11 -3
  279. data/stdlib/socket/0/udp_socket.rbs +1 -1
  280. data/stdlib/socket/0/unix_server.rbs +1 -1
  281. data/stdlib/stringio/0/stringio.rbs +1209 -95
  282. data/stdlib/strscan/0/string_scanner.rbs +101 -80
  283. data/stdlib/tempfile/0/tempfile.rbs +25 -21
  284. data/stdlib/time/0/time.rbs +8 -6
  285. data/stdlib/timeout/0/timeout.rbs +63 -7
  286. data/stdlib/tsort/0/cyclic.rbs +4 -1
  287. data/stdlib/tsort/0/interfaces.rbs +8 -8
  288. data/stdlib/tsort/0/tsort.rbs +16 -15
  289. data/stdlib/uri/0/common.rbs +42 -20
  290. data/stdlib/uri/0/file.rbs +3 -3
  291. data/stdlib/uri/0/generic.rbs +26 -18
  292. data/stdlib/uri/0/http.rbs +2 -2
  293. data/stdlib/uri/0/ldap.rbs +2 -2
  294. data/stdlib/uri/0/mailto.rbs +3 -3
  295. data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
  296. data/stdlib/zlib/0/deflate.rbs +4 -3
  297. data/stdlib/zlib/0/gzip_reader.rbs +8 -8
  298. data/stdlib/zlib/0/gzip_writer.rbs +14 -12
  299. data/stdlib/zlib/0/inflate.rbs +1 -1
  300. data/stdlib/zlib/0/need_dict.rbs +1 -1
  301. data/stdlib/zlib/0/zstream.rbs +1 -0
  302. data/wasm/README.md +59 -0
  303. data/wasm/rbs_wasm.c +411 -0
  304. metadata +56 -8
  305. data/.vscode/extensions.json +0 -5
  306. data/.vscode/settings.json +0 -19
data/Rakefile CHANGED
@@ -25,22 +25,23 @@ test_config = lambda do |t|
25
25
  t.test_files = FileList["test/**/*_test.rb"].reject do |path|
26
26
  path =~ %r{test/stdlib/}
27
27
  end
28
- end
29
-
30
- Rake::TestTask.new(test: :compile, &test_config)
31
-
32
- unless Gem.win_platform?
33
- begin
34
- require "ruby_memcheck"
35
-
36
- namespace :test do
37
- RubyMemcheck::TestTask.new(valgrind: :compile, &test_config)
28
+ if defined?(RubyMemcheck)
29
+ if t.is_a?(RubyMemcheck::TestTask)
30
+ t.verbose = true
31
+ t.options = '-v'
38
32
  end
39
- rescue LoadError => exn
40
- STDERR.puts "🚨🚨🚨🚨 Skipping RubyMemcheck: #{exn.inspect} 🚨🚨🚨🚨"
41
33
  end
42
34
  end
43
35
 
36
+ if RUBY_ENGINE == "jruby"
37
+ # JRuby runs the parser in WebAssembly instead of the C extension, so there is
38
+ # nothing to compile. The wasm runtime must be assembled first with
39
+ # `rake wasm:jruby_setup` (which needs CRuby + the WASI SDK).
40
+ Rake::TestTask.new(:test, &test_config)
41
+ else
42
+ Rake::TestTask.new(test: :compile, &test_config)
43
+ end
44
+
44
45
  multitask :default => [:test, :stdlib_test, :typecheck_test, :rubocop, :validate, :test_doc]
45
46
 
46
47
  task :lexer do
@@ -166,6 +167,10 @@ task :templates do
166
167
  sh "#{ruby} templates/template.rb include/rbs/ast.h"
167
168
  sh "#{ruby} templates/template.rb src/ast.c"
168
169
 
170
+ sh "#{ruby} templates/template.rb include/rbs/serialize.h"
171
+ sh "#{ruby} templates/template.rb src/serialize.c"
172
+ sh "#{ruby} templates/template.rb lib/rbs/wasm/serialization_schema.rb"
173
+
169
174
  # Format the generated files
170
175
  Rake::Task["format:c"].invoke
171
176
  end
@@ -185,7 +190,7 @@ end
185
190
  task :validate => :compile do
186
191
  require 'yaml'
187
192
 
188
- sh "#{ruby} #{rbs} validate --exit-error-on-syntax-error"
193
+ sh "#{ruby} #{rbs} validate"
189
194
 
190
195
  libs = FileList["stdlib/*"].map {|path| File.basename(path).to_s }
191
196
 
@@ -205,8 +210,18 @@ task :validate => :compile do
205
210
  libs << "rbs"
206
211
  end
207
212
 
213
+ libs.delete("bigdecimal-math") or raise
214
+ libs.delete("bigdecimal") or raise
215
+
208
216
  libs.each do |lib|
209
- sh "#{ruby} #{rbs} -r #{lib} validate --exit-error-on-syntax-error"
217
+ args = ["-r", lib]
218
+
219
+ if lib == "rbs"
220
+ args << "-r" << "prism"
221
+ args << "-r" << "logger"
222
+ end
223
+
224
+ sh "#{ruby} #{rbs} #{args.join(' ')} validate"
210
225
  end
211
226
  end
212
227
 
@@ -218,7 +233,7 @@ end
218
233
 
219
234
  task :stdlib_test => :compile do
220
235
  test_files = FileList["test/stdlib/**/*_test.rb"].reject do |path|
221
- path =~ %r{Ractor} || path =~ %r{Encoding} || path =~ %r{CGI_test}
236
+ path =~ %r{Ractor} || path =~ %r{Encoding} || path =~ %r{CGI-escape_test}
222
237
  end
223
238
 
224
239
  if ENV["RANDOMIZE_STDLIB_TEST_ORDER"] == "true"
@@ -227,27 +242,22 @@ task :stdlib_test => :compile do
227
242
 
228
243
  sh "#{ruby} -Ilib #{bin}/test_runner.rb #{test_files.join(' ')}"
229
244
  # TODO: Ractor tests need to be run in a separate process
230
- sh "#{ruby} -Ilib #{bin}/test_runner.rb test/stdlib/CGI_test.rb"
245
+ sh "#{ruby} -Ilib #{bin}/test_runner.rb test/stdlib/CGI-escape_test.rb"
231
246
  sh "#{ruby} -Ilib #{bin}/test_runner.rb test/stdlib/Ractor_test.rb"
232
247
  sh "#{ruby} -Ilib #{bin}/test_runner.rb test/stdlib/Encoding_test.rb"
233
248
  end
234
249
 
235
250
  task :typecheck_test => :compile do
236
- puts
237
- puts
238
- puts "⛔️⛔️⛔️⛔️⛔️⛔️ Skipping type check test because RBS is incompatible with Steep (#{__FILE__}:#{__LINE__})"
239
- puts
240
- puts
241
- # FileList["test/typecheck/*"].each do |test|
242
- # Dir.chdir(test) do
243
- # expectations = File.join(test, "steep_expectations.yml")
244
- # if File.exist?(expectations)
245
- # sh "steep check --with_expectations"
246
- # else
247
- # sh "steep check"
248
- # end
249
- # end
250
- # end
251
+ FileList["test/typecheck/*"].each do |test|
252
+ Dir.chdir(test) do
253
+ expectations = File.join(test, "steep_expectations.yml")
254
+ if File.exist?(expectations)
255
+ sh "steep check --with_expectations"
256
+ else
257
+ sh "steep check"
258
+ end
259
+ end
260
+ end
251
261
  end
252
262
 
253
263
  task :raap => :compile do
@@ -325,7 +335,7 @@ namespace :generate do
325
335
  class <%= target %>SingletonTest < Test::Unit::TestCase
326
336
  include TestHelper
327
337
 
328
- # library "pathname", "securerandom" # Declare library signatures to load
338
+ # library "logger", "securerandom" # Declare library signatures to load
329
339
  testing "singleton(::<%= target %>)"
330
340
 
331
341
  <%- class_methods.each do |method_name, definition| -%>
@@ -344,7 +354,7 @@ namespace :generate do
344
354
  class <%= target %>Test < Test::Unit::TestCase
345
355
  include TestHelper
346
356
 
347
- # library "pathname", "securerandom" # Declare library signatures to load
357
+ # library "logger", "securerandom" # Declare library signatures to load
348
358
  testing "::<%= target %>"
349
359
 
350
360
  <%- instance_methods.each do |method_name, definition| -%>
@@ -535,3 +545,325 @@ task :compile_c99 do
535
545
  ensure
536
546
  ENV.delete("TEST_NO_C23")
537
547
  end
548
+
549
+ task :prepare_bench do
550
+ ENV.delete("DEBUG")
551
+ Rake::Task[:"clobber"].invoke
552
+ Rake::Task[:"templates"].invoke
553
+ Rake::Task[:"compile"].invoke
554
+ end
555
+
556
+ task :prepare_profiling do
557
+ ENV["DEBUG"] = "1"
558
+ Rake::Task[:"clobber"].invoke
559
+ Rake::Task[:"templates"].invoke
560
+ Rake::Task[:"compile"].invoke
561
+ end
562
+
563
+ namespace :wasm do
564
+ WASM_DIR = File.expand_path("wasm", __dir__)
565
+ WASM_OUTPUT = File.join(WASM_DIR, "rbs_parser.wasm")
566
+
567
+ # The parser under src/ is plain, self-contained C with no dependency on the
568
+ # Ruby C API, so it can be compiled to WebAssembly as-is. The only extra
569
+ # translation unit is the entry-point shim under wasm/.
570
+ def wasm_source_files
571
+ Dir.glob(File.join(__dir__, "src/**/*.c")).sort + [File.join(WASM_DIR, "rbs_wasm.c")]
572
+ end
573
+
574
+ # Locate the clang shipped with the WASI SDK.
575
+ #
576
+ # The system clang can target wasm32, but the WASI SDK additionally provides
577
+ # the wasi-libc sysroot and the wasm32 compiler-rt builtins that the link
578
+ # step needs, so we require it explicitly.
579
+ def wasi_clang
580
+ sdk = ENV["WASI_SDK_PATH"]
581
+ if sdk.nil? || sdk.empty?
582
+ raise <<~MSG
583
+ WASI_SDK_PATH is not set.
584
+
585
+ Install the WASI SDK from https://github.com/WebAssembly/wasi-sdk/releases
586
+ and point WASI_SDK_PATH at the extracted directory, for example:
587
+
588
+ export WASI_SDK_PATH=/opt/wasi-sdk
589
+ rake wasm:build
590
+ MSG
591
+ end
592
+
593
+ clang = File.join(sdk, "bin", "clang")
594
+ raise "clang not found at #{clang} (is WASI_SDK_PATH correct?)" unless File.executable?(clang)
595
+
596
+ clang
597
+ end
598
+
599
+ desc "Build the RBS parser as a WebAssembly module (requires WASI_SDK_PATH)"
600
+ task :build do
601
+ mkdir_p WASM_DIR
602
+ sh wasi_clang,
603
+ "--target=wasm32-wasip1",
604
+ # No `main`; the host calls `_initialize` and then the exported functions.
605
+ "-mexec-model=reactor",
606
+ "-std=gnu11",
607
+ "-O2",
608
+ "-Wno-unused-parameter",
609
+ "-I#{File.join(__dir__, "include")}",
610
+ "-o", WASM_OUTPUT,
611
+ *wasm_source_files
612
+ puts "Built #{WASM_OUTPUT}"
613
+ end
614
+
615
+ desc "Build and smoke-test the WebAssembly module (requires wasmtime)"
616
+ task :check => :build do
617
+ wasmtime = ENV["WASMTIME"] || "wasmtime"
618
+
619
+ # `rbs_wasm_selftest` parses a small fixed signature and returns 1 on
620
+ # success. `--invoke` prints the return value to stdout.
621
+ output = IO.popen([wasmtime, "run", "--invoke", "rbs_wasm_selftest", WASM_OUTPUT], err: File::NULL, &:read).to_s.strip
622
+
623
+ if output == "1"
624
+ puts "WebAssembly selftest passed."
625
+ else
626
+ raise "WebAssembly selftest failed: rbs_wasm_selftest returned #{output.inspect} (expected \"1\")"
627
+ end
628
+ end
629
+
630
+ # Where the runtime looks for the module and jars by default (see
631
+ # RBS::WASM::Runtime). These are build artifacts, bundled into the JRuby gem.
632
+ JRUBY_WASM_DIR = File.expand_path("lib/rbs/wasm", __dir__)
633
+ CHICORY_VERSION = ENV.fetch("CHICORY_VERSION", "1.7.5")
634
+ # `compiler` is Chicory's AOT compiler (wasm -> JVM bytecode); the asm* jars
635
+ # are the ow2 ASM libraries it depends on. Keep ASM_VERSION in sync with what
636
+ # the pinned Chicory release declares.
637
+ CHICORY_JARS = %w[wasm runtime log wasi compiler].freeze
638
+ ASM_VERSION = ENV.fetch("ASM_VERSION", "9.9.1")
639
+ ASM_JARS = %w[asm asm-tree asm-util asm-commons asm-analysis].freeze
640
+
641
+ desc "Download the Chicory and ASM jars the JRuby runtime needs into lib/rbs/wasm/jars"
642
+ task :vendor_jars do
643
+ require "open-uri"
644
+ require "fileutils"
645
+
646
+ jars_dir = File.join(JRUBY_WASM_DIR, "jars")
647
+ FileUtils.mkdir_p(jars_dir)
648
+
649
+ downloads = CHICORY_JARS.map { |name| ["#{name}.jar", "https://repo1.maven.org/maven2/com/dylibso/chicory/#{name}/#{CHICORY_VERSION}/#{name}-#{CHICORY_VERSION}.jar"] }
650
+ downloads += ASM_JARS.map { |name| ["#{name}.jar", "https://repo1.maven.org/maven2/org/ow2/asm/#{name}/#{ASM_VERSION}/#{name}-#{ASM_VERSION}.jar"] }
651
+
652
+ downloads.each do |filename, url|
653
+ puts "Downloading #{url}"
654
+ URI.open(url) { |io| File.binwrite(File.join(jars_dir, filename), io.read) } # steep:ignore
655
+ end
656
+
657
+ puts "Vendored Chicory #{CHICORY_VERSION} + ASM #{ASM_VERSION} into #{jars_dir}"
658
+ end
659
+
660
+ desc "Assemble everything the JRuby gem needs: the .wasm and the Chicory jars"
661
+ task :jruby_setup => [:build, :vendor_jars] do
662
+ cp WASM_OUTPUT, File.join(JRUBY_WASM_DIR, "rbs_parser.wasm")
663
+ puts "JRuby runtime is ready under #{JRUBY_WASM_DIR}"
664
+ end
665
+ end
666
+
667
+ namespace :rust do
668
+ namespace :rbs do
669
+ RUST_DIR = File.expand_path("rust", __dir__)
670
+ RBS_VERSION_FILE = File.join(RUST_DIR, "rbs_version")
671
+
672
+ VENDOR_TARGETS = {
673
+ "ruby-rbs-sys" => %w[include src],
674
+ "ruby-rbs" => %w[config.yml],
675
+ }
676
+
677
+ desc "Sync vendored RBS source from the pinned version"
678
+ task :sync do
679
+ unless File.exist?(RBS_VERSION_FILE)
680
+ raise "#{RBS_VERSION_FILE} not found. Run `rake rust:rbs:pin[VERSION]` first."
681
+ end
682
+
683
+ version = File.read(RBS_VERSION_FILE).strip
684
+ raise "#{RBS_VERSION_FILE} is empty" if version.empty?
685
+
686
+ puts "Syncing vendor/rbs/ from #{version}..."
687
+
688
+ VENDOR_TARGETS.each do |crate, entries|
689
+ vendor_dir = File.join(RUST_DIR, crate, "vendor", "rbs")
690
+
691
+ puts " Copying files for #{crate}:"
692
+ chmod_R "u+w", vendor_dir, verbose: false if File.exist?(vendor_dir)
693
+ rm_rf vendor_dir, verbose: false
694
+ mkdir_p vendor_dir, verbose: false
695
+
696
+ entries.each do |entry|
697
+ target = File.join(vendor_dir, entry)
698
+
699
+ # Extract the entry from the pinned git tag using git archive
700
+ IO.popen(["git", "archive", "--format=tar", version, "--", entry], "rb") do |tar|
701
+ IO.popen(["tar", "xf", "-", "-C", vendor_dir], "wb") do |extract|
702
+ IO.copy_stream(tar, extract)
703
+ end
704
+ end
705
+
706
+ raise "Failed to extract #{entry} from #{version}" unless File.exist?(target)
707
+ puts " #{entry}"
708
+ end
709
+
710
+ # Make files read-only to prevent accidental edits
711
+ chmod_R "a-w", vendor_dir, verbose: false
712
+ end
713
+
714
+ puts "📦 Synced vendor/rbs/ from #{version} (read-only)"
715
+ end
716
+
717
+ desc "Pin a specific RBS version for Rust crates (e.g., rake rust:rbs:pin[v4.0.3])"
718
+ task :pin, [:version] do |_t, args|
719
+ version = args[:version] or raise "Usage: rake rust:rbs:pin[VERSION]"
720
+
721
+ # Verify the tag exists
722
+ unless system("git", "rev-parse", "--verify", "#{version}^{commit}", out: File::NULL, err: File::NULL)
723
+ raise "Tag #{version} not found"
724
+ end
725
+
726
+ File.write(RBS_VERSION_FILE, "#{version}\n")
727
+ puts "📌 Pinned RBS version to #{version}"
728
+
729
+ Rake::Task["rust:rbs:sync"].invoke
730
+ end
731
+
732
+ desc "Create symlinks from vendor/rbs/ to the repository root (for development/CI)"
733
+ task :symlink do
734
+ VENDOR_TARGETS.each do |crate, entries|
735
+ vendor_dir = File.join(RUST_DIR, crate, "vendor", "rbs")
736
+
737
+ puts "Setting up symlinks for #{crate}..."
738
+ entries.each do |entry|
739
+ puts " #{entry} -> repository root"
740
+ end
741
+
742
+ chmod_R "u+w", vendor_dir, verbose: false if File.exist?(vendor_dir)
743
+ rm_rf vendor_dir, verbose: false
744
+ mkdir_p vendor_dir, verbose: false
745
+
746
+ entries.each do |entry|
747
+ ln_s File.join("..", "..", "..", "..", entry), File.join(vendor_dir, entry), verbose: false
748
+ end
749
+ end
750
+
751
+ puts "🔗 Symlinked vendor/rbs/ to repository root"
752
+ end
753
+ end
754
+
755
+ namespace :publish do
756
+ def self.prepare_publish_branch(crate_name)
757
+ dry_run = ENV["RBS_RUST_PUBLISH_DRY_RUN"]
758
+
759
+ version_file = File.join(RUST_DIR, "rbs_version")
760
+
761
+ unless File.exist?(version_file)
762
+ raise "#{version_file} not found. Run `rake rust:rbs:pin[VERSION]` first."
763
+ end
764
+
765
+ rbs_version = File.read(version_file).strip
766
+ raise "#{version_file} is empty" if rbs_version.empty?
767
+
768
+ crate_version = File.read(File.join(RUST_DIR, crate_name, "Cargo.toml"))[/^version\s*=\s*"(.+)"/, 1]
769
+ release_branch = "rust/release-#{crate_name}-#{Time.now.strftime('%Y%m%d%H%M%S')}"
770
+
771
+ puts "=" * 60
772
+ puts "Rust crate publish: #{crate_name}#{dry_run ? " (DRY RUN)" : ""}"
773
+ puts "=" * 60
774
+ puts " RBS source version: #{rbs_version}"
775
+ puts " #{crate_name}: #{crate_version} (tag: #{crate_name}-v#{crate_version})"
776
+ puts " Release branch: #{release_branch}"
777
+ puts "=" * 60
778
+
779
+ # Check that vendor dirs contain real files, not symlinks
780
+ entries = VENDOR_TARGETS.fetch(crate_name)
781
+ entries.each do |entry|
782
+ path = File.join(RUST_DIR, crate_name, "vendor", "rbs", entry)
783
+ if File.symlink?(path)
784
+ raise "#{path} is a symlink. Run `rake rust:rbs:sync` first."
785
+ end
786
+ unless File.exist?(path)
787
+ raise "#{path} does not exist. Run `rake rust:rbs:sync` first."
788
+ end
789
+ end
790
+
791
+ # Ensure working tree is clean before publishing
792
+ unless `git status --porcelain`.strip.empty?
793
+ raise "💢 Working tree is dirty. Please commit or stash your changes before publishing."
794
+ end
795
+
796
+ # Create a release branch with vendor files committed
797
+ original_branch = `git rev-parse --abbrev-ref HEAD`.strip
798
+
799
+ sh "git", "checkout", "-b", release_branch, verbose: false
800
+ vendor_path = File.join("rust", crate_name, "vendor", "rbs")
801
+ sh "git", "add", "-f", vendor_path, verbose: false
802
+ sh "git", "commit", "-m", "Publish #{crate_name} (RBS #{rbs_version})", verbose: false
803
+
804
+ [dry_run, crate_version, original_branch]
805
+ end
806
+
807
+ desc "Publish ruby-rbs-sys crate to crates.io (set RBS_RUST_PUBLISH_DRY_RUN=1 for dry-run only)"
808
+ task :"ruby-rbs-sys" do
809
+ crate_name = "ruby-rbs-sys"
810
+ dry_run, crate_version, original_branch = prepare_publish_branch(crate_name)
811
+
812
+ begin
813
+ puts "🔰 Dry-run publishing..."
814
+
815
+ Dir.chdir(File.join(RUST_DIR, crate_name)) do
816
+ sh "cargo", "publish", "--dry-run"
817
+ end
818
+
819
+ puts "✅ Dry-run succeeded!"
820
+
821
+ unless dry_run
822
+ puts "💪 Publishing #{crate_name} for real..."
823
+
824
+ Dir.chdir(File.join(RUST_DIR, crate_name)) do
825
+ sh "cargo", "publish"
826
+ end
827
+
828
+ sh "git", "tag", "#{crate_name}-v#{crate_version}"
829
+ sh "git", "push", "origin", "#{crate_name}-v#{crate_version}"
830
+
831
+ puts "🎉 Published #{crate_name} successfully!"
832
+ end
833
+ ensure
834
+ sh "git", "checkout", original_branch, verbose: false
835
+ end
836
+ end
837
+
838
+ desc "Publish ruby-rbs crate to crates.io (set RBS_RUST_PUBLISH_DRY_RUN=1 for dry-run only)"
839
+ task :"ruby-rbs" do
840
+ crate_name = "ruby-rbs"
841
+ dry_run, crate_version, original_branch = prepare_publish_branch(crate_name)
842
+
843
+ begin
844
+ puts "🔰 Dry-run publishing..."
845
+
846
+ Dir.chdir(File.join(RUST_DIR, crate_name)) do
847
+ sh "cargo", "publish", "--dry-run", "--no-verify"
848
+ end
849
+
850
+ puts "✅ Dry-run succeeded!"
851
+
852
+ unless dry_run
853
+ puts "💪 Publishing #{crate_name} for real..."
854
+
855
+ Dir.chdir(File.join(RUST_DIR, crate_name)) do
856
+ sh "cargo", "publish"
857
+ end
858
+
859
+ sh "git", "tag", "#{crate_name}-v#{crate_version}"
860
+ sh "git", "push", "origin", "#{crate_name}-v#{crate_version}"
861
+
862
+ puts "🎉 Published #{crate_name} successfully!"
863
+ end
864
+ ensure
865
+ sh "git", "checkout", original_branch, verbose: false
866
+ end
867
+ end
868
+ end
869
+ end
data/Steepfile CHANGED
@@ -6,6 +6,13 @@ target :lib do
6
6
  ignore(
7
7
  "lib/rbs/test",
8
8
  # "lib/rbs/test.rb"
9
+
10
+ # JRuby-only implementations of RBS::Location and RBS::Parser. Like the C
11
+ # extension, these implement interfaces already described in sig/, and
12
+ # runtime.rb is Java interop, so they are not type-checked here.
13
+ "lib/rbs/wasm/location.rb",
14
+ "lib/rbs/wasm/runtime.rb",
15
+ "lib/rbs/wasm/parser.rb",
9
16
  )
10
17
 
11
18
  library "pathname", "json", "logger", "monitor", "tsort", "uri", 'dbm', 'pstore', 'singleton', 'shellwords', 'fileutils', 'find', 'digest', 'prettyprint', 'yaml', "psych", "securerandom"
@@ -15,6 +22,7 @@ target :lib do
15
22
  signature "stdlib/rdoc/0/"
16
23
  signature "stdlib/ripper/0"
17
24
  signature "stdlib/pp/0"
25
+ signature "steep/patch.rbs"
18
26
 
19
27
  # configure_code_diagnostics do |config|
20
28
  # config[D::Ruby::MethodDefinitionMissing] = :hint