rbs 3.9.4 → 4.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 (354) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +75 -0
  3. data/.clangd +2 -0
  4. data/.dockerignore +37 -0
  5. data/.gitattributes +1 -0
  6. data/.github/dependabot.yml +16 -14
  7. data/.github/workflows/bundle-update.yml +63 -0
  8. data/.github/workflows/c-check.yml +66 -0
  9. data/.github/workflows/changelog.yml +121 -0
  10. data/.github/workflows/comments.yml +6 -4
  11. data/.github/workflows/dependabot.yml +2 -2
  12. data/.github/workflows/jruby.yml +74 -0
  13. data/.github/workflows/release-gems.yml +234 -0
  14. data/.github/workflows/ruby.yml +86 -32
  15. data/.github/workflows/rust.yml +186 -0
  16. data/.github/workflows/truffleruby.yml +54 -0
  17. data/.github/workflows/typecheck.yml +6 -3
  18. data/.github/workflows/wasm.yml +55 -0
  19. data/.github/workflows/windows.yml +10 -4
  20. data/.gitignore +16 -0
  21. data/.rubocop.yml +1 -2
  22. data/CHANGELOG.md +502 -0
  23. data/Dockerfile.jruby +53 -0
  24. data/README.md +42 -5
  25. data/Rakefile +892 -111
  26. data/Steepfile +11 -0
  27. data/config.yml +665 -62
  28. data/core/array.rbs +541 -398
  29. data/core/basic_object.rbs +9 -8
  30. data/core/binding.rbs +0 -2
  31. data/core/builtin.rbs +9 -8
  32. data/core/class.rbs +11 -8
  33. data/core/comparable.rbs +55 -34
  34. data/core/complex.rbs +104 -78
  35. data/core/dir.rbs +61 -49
  36. data/core/encoding.rbs +12 -15
  37. data/core/enumerable.rbs +297 -196
  38. data/core/enumerator/arithmetic_sequence.rbs +70 -0
  39. data/core/enumerator/product.rbs +5 -5
  40. data/core/enumerator.rbs +91 -28
  41. data/core/errno.rbs +11 -2
  42. data/core/errors.rbs +58 -29
  43. data/core/exception.rbs +13 -13
  44. data/core/fiber.rbs +74 -54
  45. data/core/file.rbs +260 -1151
  46. data/core/file_constants.rbs +463 -0
  47. data/core/file_stat.rbs +534 -0
  48. data/core/file_test.rbs +3 -3
  49. data/core/float.rbs +257 -116
  50. data/core/gc.rbs +425 -281
  51. data/core/hash.rbs +1151 -829
  52. data/core/integer.rbs +156 -195
  53. data/core/io/buffer.rbs +53 -42
  54. data/core/io/wait.rbs +13 -35
  55. data/core/io.rbs +222 -155
  56. data/core/kernel.rbs +239 -163
  57. data/core/marshal.rbs +4 -4
  58. data/core/match_data.rbs +16 -14
  59. data/core/math.rbs +107 -66
  60. data/core/method.rbs +69 -33
  61. data/core/module.rbs +302 -150
  62. data/core/nil_class.rbs +7 -6
  63. data/core/numeric.rbs +77 -63
  64. data/core/object.rbs +9 -11
  65. data/core/object_space/weak_key_map.rbs +7 -7
  66. data/core/object_space.rbs +30 -23
  67. data/core/pathname.rbs +1312 -0
  68. data/core/proc.rbs +95 -58
  69. data/core/process.rbs +222 -202
  70. data/core/ractor.rbs +364 -518
  71. data/core/random.rbs +21 -3
  72. data/core/range.rbs +181 -79
  73. data/core/rational.rbs +60 -89
  74. data/core/rbs/ops.rbs +154 -0
  75. data/core/rbs/unnamed/argf.rbs +63 -56
  76. data/core/rbs/unnamed/env_class.rbs +19 -14
  77. data/core/rbs/unnamed/main_class.rbs +123 -0
  78. data/core/rbs/unnamed/random.rbs +11 -118
  79. data/core/regexp.rbs +258 -214
  80. data/core/ruby.rbs +53 -0
  81. data/core/ruby_vm.rbs +78 -34
  82. data/core/rubygems/config_file.rbs +5 -5
  83. data/core/rubygems/errors.rbs +6 -70
  84. data/core/rubygems/requirement.rbs +5 -15
  85. data/core/rubygems/rubygems.rbs +18 -81
  86. data/core/rubygems/specification.rbs +8 -0
  87. data/core/rubygems/version.rbs +2 -163
  88. data/core/set.rbs +493 -363
  89. data/core/signal.rbs +26 -16
  90. data/core/string.rbs +3234 -1285
  91. data/core/struct.rbs +43 -42
  92. data/core/symbol.rbs +41 -34
  93. data/core/thread.rbs +139 -83
  94. data/core/time.rbs +81 -50
  95. data/core/trace_point.rbs +41 -35
  96. data/core/true_class.rbs +2 -2
  97. data/core/unbound_method.rbs +24 -16
  98. data/core/warning.rbs +7 -7
  99. data/docs/CONTRIBUTING.md +3 -2
  100. data/docs/aliases.md +79 -0
  101. data/docs/collection.md +3 -3
  102. data/docs/config.md +171 -0
  103. data/docs/encoding.md +56 -0
  104. data/docs/gem.md +0 -1
  105. data/docs/inline.md +634 -0
  106. data/docs/rbs_by_example.md +20 -20
  107. data/docs/release.md +303 -0
  108. data/docs/rust.md +96 -0
  109. data/docs/sigs.md +3 -3
  110. data/docs/stdlib.md +8 -0
  111. data/docs/syntax.md +60 -18
  112. data/docs/type_fingerprint.md +21 -0
  113. data/docs/wasm_serialization.md +80 -0
  114. data/exe/rbs +1 -1
  115. data/ext/rbs_extension/ast_translation.c +1870 -0
  116. data/ext/rbs_extension/ast_translation.h +41 -0
  117. data/ext/rbs_extension/class_constants.c +189 -0
  118. data/{include/rbs/constants.h → ext/rbs_extension/class_constants.h} +24 -1
  119. data/ext/rbs_extension/compat.h +10 -0
  120. data/ext/rbs_extension/extconf.rb +26 -1
  121. data/ext/rbs_extension/legacy_location.c +299 -0
  122. data/ext/rbs_extension/legacy_location.h +82 -0
  123. data/ext/rbs_extension/main.c +639 -23
  124. data/ext/rbs_extension/rbs_extension.h +6 -21
  125. data/ext/rbs_extension/rbs_string_bridging.c +9 -0
  126. data/ext/rbs_extension/rbs_string_bridging.h +24 -0
  127. data/include/rbs/ast.h +1055 -0
  128. data/include/rbs/defines.h +104 -0
  129. data/include/rbs/lexer.h +208 -0
  130. data/include/rbs/location.h +40 -0
  131. data/include/rbs/parser.h +187 -0
  132. data/include/rbs/serialize.h +39 -0
  133. data/include/rbs/string.h +47 -0
  134. data/include/rbs/util/rbs_allocator.h +59 -0
  135. data/include/rbs/util/rbs_assert.h +20 -0
  136. data/include/rbs/util/rbs_buffer.h +83 -0
  137. data/include/rbs/util/rbs_constant_pool.h +6 -70
  138. data/include/rbs/util/rbs_encoding.h +282 -0
  139. data/include/rbs/util/rbs_unescape.h +24 -0
  140. data/include/rbs.h +9 -2
  141. data/lib/rbs/annotate/formatter.rb +3 -13
  142. data/lib/rbs/annotate/rdoc_annotator.rb +30 -32
  143. data/lib/rbs/annotate/rdoc_source.rb +1 -1
  144. data/lib/rbs/ast/annotation.rb +1 -1
  145. data/lib/rbs/ast/comment.rb +1 -1
  146. data/lib/rbs/ast/declarations.rb +11 -11
  147. data/lib/rbs/ast/members.rb +14 -14
  148. data/lib/rbs/ast/ruby/annotations.rb +451 -0
  149. data/lib/rbs/ast/ruby/comment_block.rb +247 -0
  150. data/lib/rbs/ast/ruby/declarations.rb +291 -0
  151. data/lib/rbs/ast/ruby/helpers/constant_helper.rb +28 -0
  152. data/lib/rbs/ast/ruby/helpers/location_helper.rb +15 -0
  153. data/lib/rbs/ast/ruby/members.rb +762 -0
  154. data/lib/rbs/ast/type_param.rb +25 -5
  155. data/lib/rbs/buffer.rb +142 -20
  156. data/lib/rbs/cli/diff.rb +16 -15
  157. data/lib/rbs/cli/validate.rb +63 -126
  158. data/lib/rbs/cli.rb +59 -29
  159. data/lib/rbs/collection/config/lockfile_generator.rb +28 -3
  160. data/lib/rbs/collection/sources/git.rb +7 -0
  161. data/lib/rbs/definition.rb +6 -1
  162. data/lib/rbs/definition_builder/ancestor_builder.rb +129 -70
  163. data/lib/rbs/definition_builder/method_builder.rb +74 -33
  164. data/lib/rbs/definition_builder.rb +181 -21
  165. data/lib/rbs/diff.rb +7 -1
  166. data/lib/rbs/environment/class_entry.rb +81 -0
  167. data/lib/rbs/environment/module_entry.rb +91 -0
  168. data/lib/rbs/environment.rb +410 -215
  169. data/lib/rbs/environment_loader.rb +2 -8
  170. data/lib/rbs/errors.rb +31 -21
  171. data/lib/rbs/inline_parser/comment_association.rb +117 -0
  172. data/lib/rbs/inline_parser.rb +568 -0
  173. data/lib/rbs/location_aux.rb +36 -4
  174. data/lib/rbs/locator.rb +5 -1
  175. data/lib/rbs/method_type.rb +5 -3
  176. data/lib/rbs/namespace.rb +47 -18
  177. data/lib/rbs/parser_aux.rb +37 -7
  178. data/lib/rbs/prototype/helpers.rb +24 -0
  179. data/lib/rbs/prototype/rb.rb +3 -28
  180. data/lib/rbs/prototype/rbi.rb +196 -45
  181. data/lib/rbs/prototype/runtime/value_object_generator.rb +0 -1
  182. data/lib/rbs/prototype/runtime.rb +13 -3
  183. data/lib/rbs/resolver/constant_resolver.rb +2 -2
  184. data/lib/rbs/resolver/type_name_resolver.rb +120 -44
  185. data/lib/rbs/rewriter.rb +70 -0
  186. data/lib/rbs/source.rb +99 -0
  187. data/lib/rbs/subtractor.rb +7 -4
  188. data/lib/rbs/test/type_check.rb +25 -3
  189. data/lib/rbs/type_name.rb +34 -21
  190. data/lib/rbs/types.rb +135 -81
  191. data/lib/rbs/unit_test/convertibles.rb +1 -0
  192. data/lib/rbs/unit_test/type_assertions.rb +47 -11
  193. data/lib/rbs/validator.rb +2 -2
  194. data/lib/rbs/version.rb +1 -1
  195. data/lib/rbs/wasm/deserializer.rb +213 -0
  196. data/lib/rbs/wasm/location.rb +61 -0
  197. data/lib/rbs/wasm/parser.rb +174 -0
  198. data/lib/rbs/wasm/runtime.rb +211 -0
  199. data/lib/rbs/wasm/serialization_schema.rb +111 -0
  200. data/lib/rbs.rb +25 -2
  201. data/lib/rbs_jars.rb +39 -0
  202. data/lib/rdoc/discover.rb +1 -1
  203. data/lib/rdoc_plugin/parser.rb +8 -3
  204. data/rbs.gemspec +34 -6
  205. data/schema/function.json +12 -1
  206. data/schema/typeParam.json +17 -1
  207. data/sig/ancestor_builder.rbs +1 -1
  208. data/sig/annotate/formatter.rbs +2 -2
  209. data/sig/annotate/rdoc_annotater.rbs +13 -10
  210. data/sig/ast/ruby/annotations.rbs +470 -0
  211. data/sig/ast/ruby/comment_block.rbs +127 -0
  212. data/sig/ast/ruby/declarations.rbs +158 -0
  213. data/sig/ast/ruby/helpers/constant_helper.rbs +11 -0
  214. data/sig/ast/ruby/helpers/location_helper.rbs +15 -0
  215. data/sig/ast/ruby/members.rbs +198 -0
  216. data/sig/buffer.rbs +81 -5
  217. data/sig/cli/diff.rbs +5 -11
  218. data/sig/cli/validate.rbs +12 -8
  219. data/sig/cli.rbs +18 -18
  220. data/sig/collection/config/lockfile_generator.rbs +2 -0
  221. data/sig/definition.rbs +6 -0
  222. data/sig/definition_builder.rbs +3 -1
  223. data/sig/environment/class_entry.rbs +56 -0
  224. data/sig/environment/module_entry.rbs +65 -0
  225. data/sig/environment.rbs +94 -87
  226. data/sig/errors.rbs +26 -20
  227. data/sig/inline_parser/comment_association.rbs +71 -0
  228. data/sig/inline_parser.rbs +126 -0
  229. data/sig/location.rbs +32 -7
  230. data/sig/locator.rbs +0 -2
  231. data/sig/manifest.yaml +0 -2
  232. data/sig/method_builder.rbs +9 -4
  233. data/sig/namespace.rbs +20 -5
  234. data/sig/parser.rbs +79 -15
  235. data/sig/prototype/helpers.rbs +2 -0
  236. data/sig/prototype/rbi.rbs +33 -4
  237. data/sig/resolver/type_name_resolver.rbs +36 -10
  238. data/sig/rewriter.rbs +45 -0
  239. data/sig/source.rbs +48 -0
  240. data/sig/type_param.rbs +13 -8
  241. data/sig/typename.rbs +15 -5
  242. data/sig/types.rbs +21 -9
  243. data/sig/unit_test/spy.rbs +0 -8
  244. data/sig/unit_test/type_assertions.rbs +17 -2
  245. data/sig/wasm/deserializer.rbs +66 -0
  246. data/sig/wasm/serialization_schema.rbs +13 -0
  247. data/src/ast.c +1644 -0
  248. data/src/lexer.c +3223 -0
  249. data/src/lexer.re +187 -0
  250. data/src/lexstate.c +222 -0
  251. data/src/location.c +31 -0
  252. data/src/parser.c +4318 -0
  253. data/src/serialize.c +965 -0
  254. data/src/string.c +41 -0
  255. data/src/util/rbs_allocator.c +171 -0
  256. data/src/util/rbs_assert.c +19 -0
  257. data/src/util/rbs_buffer.c +54 -0
  258. data/src/util/rbs_constant_pool.c +18 -92
  259. data/src/util/rbs_encoding.c +21454 -0
  260. data/src/util/rbs_unescape.c +167 -0
  261. data/stdlib/abbrev/0/array.rbs +1 -1
  262. data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
  263. data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
  264. data/stdlib/cgi/0/core.rbs +9 -393
  265. data/stdlib/cgi/0/manifest.yaml +1 -0
  266. data/stdlib/cgi-escape/0/escape.rbs +171 -0
  267. data/stdlib/coverage/0/coverage.rbs +7 -4
  268. data/stdlib/csv/0/csv.rbs +5 -5
  269. data/stdlib/date/0/date.rbs +92 -79
  270. data/stdlib/date/0/date_time.rbs +25 -24
  271. data/stdlib/delegate/0/delegator.rbs +11 -7
  272. data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
  273. data/stdlib/digest/0/digest.rbs +117 -1
  274. data/stdlib/erb/0/erb.rbs +754 -353
  275. data/stdlib/etc/0/etc.rbs +73 -54
  276. data/stdlib/fileutils/0/fileutils.rbs +179 -160
  277. data/stdlib/forwardable/0/forwardable.rbs +13 -10
  278. data/stdlib/io-console/0/io-console.rbs +2 -2
  279. data/stdlib/ipaddr/0/ipaddr.rbs +0 -5
  280. data/stdlib/json/0/json.rbs +232 -185
  281. data/stdlib/monitor/0/monitor.rbs +9 -9
  282. data/stdlib/net-http/0/net-http.rbs +162 -134
  283. data/stdlib/objspace/0/objspace.rbs +17 -34
  284. data/stdlib/open-uri/0/open-uri.rbs +48 -8
  285. data/stdlib/open3/0/open3.rbs +469 -10
  286. data/stdlib/openssl/0/openssl.rbs +521 -397
  287. data/stdlib/optparse/0/optparse.rbs +26 -17
  288. data/stdlib/pathname/0/pathname.rbs +11 -1381
  289. data/stdlib/pp/0/pp.rbs +9 -8
  290. data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
  291. data/stdlib/pstore/0/pstore.rbs +35 -30
  292. data/stdlib/psych/0/psych.rbs +65 -12
  293. data/stdlib/psych/0/store.rbs +2 -4
  294. data/stdlib/pty/0/pty.rbs +9 -6
  295. data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
  296. data/stdlib/rdoc/0/code_object.rbs +4 -3
  297. data/stdlib/rdoc/0/comment.rbs +2 -0
  298. data/stdlib/rdoc/0/options.rbs +76 -0
  299. data/stdlib/rdoc/0/parser.rbs +1 -1
  300. data/stdlib/rdoc/0/rdoc.rbs +7 -5
  301. data/stdlib/rdoc/0/store.rbs +2 -2
  302. data/stdlib/resolv/0/resolv.rbs +26 -69
  303. data/stdlib/ripper/0/ripper.rbs +25 -19
  304. data/stdlib/securerandom/0/manifest.yaml +2 -0
  305. data/stdlib/securerandom/0/securerandom.rbs +7 -20
  306. data/stdlib/shellwords/0/shellwords.rbs +3 -3
  307. data/stdlib/singleton/0/singleton.rbs +6 -0
  308. data/stdlib/socket/0/addrinfo.rbs +9 -9
  309. data/stdlib/socket/0/basic_socket.rbs +3 -3
  310. data/stdlib/socket/0/ip_socket.rbs +10 -8
  311. data/stdlib/socket/0/socket.rbs +23 -10
  312. data/stdlib/socket/0/tcp_server.rbs +1 -1
  313. data/stdlib/socket/0/tcp_socket.rbs +11 -3
  314. data/stdlib/socket/0/udp_socket.rbs +1 -1
  315. data/stdlib/socket/0/unix_server.rbs +1 -1
  316. data/stdlib/stringio/0/stringio.rbs +1211 -96
  317. data/stdlib/strscan/0/string_scanner.rbs +101 -80
  318. data/stdlib/tempfile/0/manifest.yaml +3 -0
  319. data/stdlib/tempfile/0/tempfile.rbs +25 -21
  320. data/stdlib/time/0/time.rbs +8 -6
  321. data/stdlib/timeout/0/timeout.rbs +58 -7
  322. data/stdlib/tsort/0/cyclic.rbs +4 -1
  323. data/stdlib/tsort/0/interfaces.rbs +8 -8
  324. data/stdlib/tsort/0/tsort.rbs +16 -15
  325. data/stdlib/uri/0/common.rbs +42 -20
  326. data/stdlib/uri/0/file.rbs +3 -3
  327. data/stdlib/uri/0/generic.rbs +21 -18
  328. data/stdlib/uri/0/http.rbs +2 -2
  329. data/stdlib/uri/0/ldap.rbs +2 -2
  330. data/stdlib/uri/0/mailto.rbs +3 -3
  331. data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
  332. data/stdlib/zlib/0/deflate.rbs +4 -3
  333. data/stdlib/zlib/0/gzip_file.rbs +1 -1
  334. data/stdlib/zlib/0/gzip_reader.rbs +8 -8
  335. data/stdlib/zlib/0/gzip_writer.rbs +16 -13
  336. data/stdlib/zlib/0/inflate.rbs +1 -1
  337. data/stdlib/zlib/0/need_dict.rbs +1 -1
  338. data/wasm/README.md +109 -0
  339. data/wasm/rbs_wasm.c +479 -0
  340. metadata +133 -19
  341. data/ext/rbs_extension/lexer.c +0 -2728
  342. data/ext/rbs_extension/lexer.h +0 -179
  343. data/ext/rbs_extension/lexer.re +0 -147
  344. data/ext/rbs_extension/lexstate.c +0 -175
  345. data/ext/rbs_extension/location.c +0 -325
  346. data/ext/rbs_extension/location.h +0 -85
  347. data/ext/rbs_extension/parser.c +0 -2982
  348. data/ext/rbs_extension/parser.h +0 -18
  349. data/ext/rbs_extension/parserstate.c +0 -411
  350. data/ext/rbs_extension/parserstate.h +0 -163
  351. data/ext/rbs_extension/unescape.c +0 -32
  352. data/include/rbs/ruby_objs.h +0 -72
  353. data/src/constants.c +0 -153
  354. data/src/ruby_objs.c +0 -799
data/wasm/rbs_wasm.c ADDED
@@ -0,0 +1,479 @@
1
+ /**
2
+ * @file rbs_wasm.c
3
+ *
4
+ * WebAssembly entry points for the RBS parser.
5
+ *
6
+ * The parser in `src/` is plain, self-contained C with no dependency on the
7
+ * Ruby C API, so it compiles to WebAssembly as-is. This file exposes a small,
8
+ * stable ABI so the parser can be driven from a WebAssembly host (a JVM-based
9
+ * runtime running under JRuby).
10
+ *
11
+ * The flow is: the host writes a UTF-8 source string into linear memory
12
+ * (`rbs_wasm_alloc`), calls one of the `rbs_wasm_parse_*` functions, and reads
13
+ * the result back out (`rbs_wasm_result_ptr` / `rbs_wasm_result_len`). On
14
+ * success the result is the serialized AST (see `rbs_serialize_node` and
15
+ * `docs/wasm_serialization.md`); on a parse error it is an error blob (see
16
+ * `set_error_result`). `RBS::WASM` on the Ruby side decodes both.
17
+ *
18
+ * Built as a "reactor": no `main`, and the host calls `_initialize` once before
19
+ * invoking any export.
20
+ */
21
+
22
+ #include <stdint.h>
23
+ #include <stdlib.h>
24
+ #include <string.h>
25
+
26
+ #include "rbs/parser.h"
27
+ #include "rbs/serialize.h"
28
+ #include "rbs/string.h"
29
+ #include "rbs/util/rbs_buffer.h"
30
+ #include "rbs/util/rbs_encoding.h"
31
+
32
+ // Status returned by the parse entry points.
33
+ //
34
+ // A negative status is about the range the caller asked for rather than the
35
+ // source text, and leaves the result empty: `RBS_WASM_INVALID_START_POS` is
36
+ // the `NULL` `rbs_parser_new` returns for a byte position no character starts
37
+ // at -- inside a character, or past the end of the buffer. `RBS::Parser`
38
+ // raises ArgumentError for both, as the C extension does for the same `NULL`
39
+ // (main.c).
40
+ #define RBS_WASM_INVALID_START_POS (-2)
41
+ #define RBS_WASM_INVALID_RANGE (-1)
42
+ #define RBS_WASM_PARSE_ERROR 0
43
+ #define RBS_WASM_OK 1
44
+
45
+ // The result of the most recent parse, living in linear memory until the next
46
+ // call replaces it. WebAssembly is little-endian, so the multi-byte integers
47
+ // written below match the little-endian format the Ruby decoder expects.
48
+ static char *result_buffer = NULL;
49
+ static int32_t result_length = 0;
50
+
51
+ // Replace the current result with a fresh `length`-byte buffer and return a
52
+ // pointer to it for the caller to fill in.
53
+ static char *allocate_result(size_t length) {
54
+ free(result_buffer);
55
+ result_buffer = (char *) malloc(length == 0 ? 1 : length);
56
+ result_length = (int32_t) length;
57
+ return result_buffer;
58
+ }
59
+
60
+ /**
61
+ * Allocate `size` bytes in linear memory and return the offset. The host uses
62
+ * this to reserve space for an input string before calling a parse function.
63
+ */
64
+ __attribute__((export_name("rbs_wasm_alloc"))) void *rbs_wasm_alloc(size_t size) {
65
+ return malloc(size);
66
+ }
67
+
68
+ /**
69
+ * Free a region previously returned by `rbs_wasm_alloc`.
70
+ */
71
+ __attribute__((export_name("rbs_wasm_free"))) void rbs_wasm_free(void *ptr) {
72
+ free(ptr);
73
+ }
74
+
75
+ /**
76
+ * Offset of the most recent parse result in linear memory.
77
+ */
78
+ __attribute__((export_name("rbs_wasm_result_ptr")))
79
+ int32_t
80
+ rbs_wasm_result_ptr(void) {
81
+ return (int32_t) (intptr_t) result_buffer;
82
+ }
83
+
84
+ /**
85
+ * Length, in bytes, of the most recent parse result.
86
+ */
87
+ __attribute__((export_name("rbs_wasm_result_len")))
88
+ int32_t
89
+ rbs_wasm_result_len(void) {
90
+ return result_length;
91
+ }
92
+
93
+ // Encode the parser's error into the result buffer:
94
+ //
95
+ // [i32 start_char][i32 end_char][u8 syntax_error]
96
+ // [u32 token_type_len][token_type bytes][u32 message_len][message bytes]
97
+ //
98
+ // Always returns RBS_WASM_PARSE_ERROR, the failure status for the parse functions.
99
+ static int set_error_result(rbs_parser_t *parser) {
100
+ rbs_error_t *error = parser->error;
101
+ const char *token_type = rbs_token_type_str(error->token.type);
102
+ const char *message = error->message;
103
+ uint32_t token_type_len = (uint32_t) strlen(token_type);
104
+ uint32_t message_len = (uint32_t) strlen(message);
105
+
106
+ int32_t start_char = error->token.range.start.char_pos;
107
+ int32_t end_char = error->token.range.end.char_pos;
108
+ uint8_t syntax_error = error->syntax_error ? 1 : 0;
109
+
110
+ size_t total = 4 + 4 + 1 + 4 + token_type_len + 4 + message_len;
111
+ char *p = allocate_result(total);
112
+
113
+ memcpy(p, &start_char, 4);
114
+ p += 4;
115
+ memcpy(p, &end_char, 4);
116
+ p += 4;
117
+ *p++ = (char) syntax_error;
118
+ memcpy(p, &token_type_len, 4);
119
+ p += 4;
120
+ memcpy(p, token_type, token_type_len);
121
+ p += token_type_len;
122
+ memcpy(p, &message_len, 4);
123
+ p += 4;
124
+ memcpy(p, message, message_len);
125
+
126
+ return RBS_WASM_PARSE_ERROR;
127
+ }
128
+
129
+ static int set_serialized_result(rbs_parser_t *parser, rbs_node_t *node) {
130
+ rbs_string_t bytes = rbs_serialize_node(parser->allocator, &parser->constant_pool, node);
131
+ size_t length = rbs_string_len(bytes);
132
+ memcpy(allocate_result(length), bytes.start, length);
133
+ return RBS_WASM_OK;
134
+ }
135
+
136
+ // A negative or reversed range is the caller's mistake rather than anything
137
+ // about the source text. Hosts are expected to reject it too (RBS::Parser
138
+ // raises on bad ranges), but the ABI is public, so check here as well.
139
+ static bool range_is_valid(int start_pos, int end_pos) {
140
+ return start_pos >= 0 && end_pos >= 0 && start_pos <= end_pos;
141
+ }
142
+
143
+ // An `end_pos` past the end of the buffer is how a caller clamps without
144
+ // measuring, and the lexer stops at the end of the input on its own -- but it
145
+ // only recognises the end where it can read a NUL. The C extension has the
146
+ // Ruby string's terminator for that; a buffer the host wrote into linear
147
+ // memory has nothing behind it, so its size is where lexing has to stop.
148
+ static int clamp_end_pos(int end_pos, int length) {
149
+ return end_pos < length ? end_pos : length;
150
+ }
151
+
152
+ // Resolve a Ruby encoding name (e.g. "UTF-8", "EUC-JP") to an rbs encoding,
153
+ // falling back to UTF-8 when none is given or the name is not recognised.
154
+ static const rbs_encoding_t *resolve_encoding(const char *name, int name_length) {
155
+ if (name_length > 0) {
156
+ const rbs_encoding_t *encoding = rbs_encoding_find((const uint8_t *) name, (const uint8_t *) (name + name_length));
157
+ if (encoding != NULL) return encoding;
158
+ }
159
+ return RBS_ENCODING_UTF_8_ENTRY;
160
+ }
161
+
162
+ // Declare type variables from a buffer of newline-separated names. A negative
163
+ // length means "no variables given" (the parser keeps its default table).
164
+ static void declare_variables(rbs_parser_t *parser, const char *variables, int variables_length) {
165
+ if (variables_length < 0) return;
166
+
167
+ rbs_parser_push_typevar_table(parser, true);
168
+
169
+ const char *cursor = variables;
170
+ const char *end = variables + variables_length;
171
+ const char *name_start = cursor;
172
+
173
+ while (cursor <= end) {
174
+ if (cursor == end || *cursor == '\n') {
175
+ size_t name_length = (size_t) (cursor - name_start);
176
+ if (name_length > 0) {
177
+ uint8_t *copied = (uint8_t *) malloc(name_length);
178
+ memcpy(copied, name_start, name_length);
179
+ rbs_constant_id_t id = rbs_constant_pool_insert_owned(&parser->constant_pool, copied, name_length);
180
+ (void) rbs_parser_insert_typevar(parser, id);
181
+ }
182
+ name_start = cursor + 1;
183
+ }
184
+ cursor++;
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Parse an RBS signature from a source buffer.
190
+ *
191
+ * `source`/`length` is the whole buffer content; `encoding`/`encoding_length` is
192
+ * its Ruby encoding name; `start_pos`/`end_pos` are the character range within it
193
+ * to parse, so reported locations are absolute (this mirrors
194
+ * RBS::Parser._parse_signature).
195
+ *
196
+ * @return RBS_WASM_OK on success (result is the serialized AST),
197
+ * RBS_WASM_PARSE_ERROR on a parse error (result is an error blob), or
198
+ * a negative status for a range the parser will not take.
199
+ */
200
+ __attribute__((export_name("rbs_wasm_parse_signature"))) int rbs_wasm_parse_signature(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos) {
201
+ if (!range_is_valid(start_pos, end_pos)) {
202
+ allocate_result(0);
203
+ return RBS_WASM_INVALID_RANGE;
204
+ }
205
+
206
+ rbs_string_t string = rbs_string_new(source, source + length);
207
+ rbs_parser_t *parser = rbs_parser_new(string, resolve_encoding(encoding, encoding_length), start_pos, clamp_end_pos(end_pos, length));
208
+ if (parser == NULL) {
209
+ allocate_result(0);
210
+ return RBS_WASM_INVALID_START_POS;
211
+ }
212
+
213
+ rbs_signature_t *signature = NULL;
214
+ rbs_parse_signature(parser, &signature);
215
+
216
+ int status;
217
+ if (parser->error == NULL) {
218
+ status = set_serialized_result(parser, (rbs_node_t *) signature);
219
+ } else {
220
+ status = set_error_result(parser);
221
+ }
222
+
223
+ rbs_parser_free(parser);
224
+ return status;
225
+ }
226
+
227
+ /**
228
+ * Parse a single RBS type.
229
+ *
230
+ * @param variables Newline-separated type variable names (length < 0 for none).
231
+ * @return RBS_WASM_OK on success, RBS_WASM_PARSE_ERROR on a parse error, or a
232
+ * negative status for a range the parser will not take. On success
233
+ * with an empty result (`rbs_wasm_result_len` == 0), the input was
234
+ * empty (`nil`).
235
+ */
236
+ __attribute__((export_name("rbs_wasm_parse_type"))) int rbs_wasm_parse_type(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos, const char *variables, int variables_length, int require_eof, int void_allowed, int self_allowed, int classish_allowed) {
237
+ if (!range_is_valid(start_pos, end_pos)) {
238
+ allocate_result(0);
239
+ return RBS_WASM_INVALID_RANGE;
240
+ }
241
+
242
+ rbs_string_t string = rbs_string_new(source, source + length);
243
+ rbs_parser_t *parser = rbs_parser_new(string, resolve_encoding(encoding, encoding_length), start_pos, clamp_end_pos(end_pos, length));
244
+ if (parser == NULL) {
245
+ allocate_result(0);
246
+ return RBS_WASM_INVALID_START_POS;
247
+ }
248
+
249
+ declare_variables(parser, variables, variables_length);
250
+
251
+ int status;
252
+ if (parser->next_token.type == pEOF) {
253
+ allocate_result(0);
254
+ status = RBS_WASM_OK;
255
+ } else {
256
+ rbs_node_t *type = NULL;
257
+ rbs_parse_type(parser, &type, void_allowed != 0, self_allowed != 0, classish_allowed != 0);
258
+
259
+ if (parser->error == NULL && require_eof) {
260
+ rbs_parser_advance(parser);
261
+ if (parser->current_token.type != pEOF) {
262
+ rbs_parser_set_error(parser, parser->current_token, true, "expected a token `%s`", rbs_token_type_str(pEOF));
263
+ }
264
+ }
265
+
266
+ status = parser->error == NULL ? set_serialized_result(parser, type) : set_error_result(parser);
267
+ }
268
+
269
+ rbs_parser_free(parser);
270
+ return status;
271
+ }
272
+
273
+ /**
274
+ * Parse a single RBS method type.
275
+ *
276
+ * @param variables Newline-separated type variable names (length < 0 for none).
277
+ * @return RBS_WASM_OK on success, RBS_WASM_PARSE_ERROR on a parse error, or a
278
+ * negative status for a range the parser will not take. On success
279
+ * with an empty result, the input was empty (`nil`).
280
+ */
281
+ __attribute__((export_name("rbs_wasm_parse_method_type"))) int rbs_wasm_parse_method_type(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos, const char *variables, int variables_length, int require_eof) {
282
+ if (!range_is_valid(start_pos, end_pos)) {
283
+ allocate_result(0);
284
+ return RBS_WASM_INVALID_RANGE;
285
+ }
286
+
287
+ rbs_string_t string = rbs_string_new(source, source + length);
288
+ rbs_parser_t *parser = rbs_parser_new(string, resolve_encoding(encoding, encoding_length), start_pos, clamp_end_pos(end_pos, length));
289
+ if (parser == NULL) {
290
+ allocate_result(0);
291
+ return RBS_WASM_INVALID_START_POS;
292
+ }
293
+
294
+ declare_variables(parser, variables, variables_length);
295
+
296
+ int status;
297
+ if (parser->next_token.type == pEOF) {
298
+ allocate_result(0);
299
+ status = RBS_WASM_OK;
300
+ } else {
301
+ rbs_method_type_t *method_type = NULL;
302
+ rbs_parse_method_type(parser, &method_type, require_eof != 0, true);
303
+
304
+ status = parser->error == NULL ? set_serialized_result(parser, (rbs_node_t *) method_type) : set_error_result(parser);
305
+ }
306
+
307
+ rbs_parser_free(parser);
308
+ return status;
309
+ }
310
+
311
+ /**
312
+ * Parse a type parameter list (e.g. `[T < Comparable]`). On success the result
313
+ * is a serialized node list; an empty result means the input was empty (`nil`).
314
+ */
315
+ __attribute__((export_name("rbs_wasm_parse_type_params"))) int rbs_wasm_parse_type_params(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos, int module_type_params) {
316
+ if (!range_is_valid(start_pos, end_pos)) {
317
+ allocate_result(0);
318
+ return RBS_WASM_INVALID_RANGE;
319
+ }
320
+
321
+ rbs_string_t string = rbs_string_new(source, source + length);
322
+ rbs_parser_t *parser = rbs_parser_new(string, resolve_encoding(encoding, encoding_length), start_pos, clamp_end_pos(end_pos, length));
323
+ if (parser == NULL) {
324
+ allocate_result(0);
325
+ return RBS_WASM_INVALID_START_POS;
326
+ }
327
+
328
+ int status;
329
+ if (parser->next_token.type == pEOF) {
330
+ allocate_result(0);
331
+ status = RBS_WASM_OK;
332
+ } else {
333
+ rbs_node_list_t *params = NULL;
334
+ rbs_parse_type_params(parser, module_type_params != 0, &params);
335
+
336
+ if (parser->error == NULL) {
337
+ rbs_string_t bytes = rbs_serialize_node_list(parser->allocator, &parser->constant_pool, params);
338
+ size_t n = rbs_string_len(bytes);
339
+ memcpy(allocate_result(n), bytes.start, n);
340
+ status = RBS_WASM_OK;
341
+ } else {
342
+ status = set_error_result(parser);
343
+ }
344
+ }
345
+
346
+ rbs_parser_free(parser);
347
+ return status;
348
+ }
349
+
350
+ // Shared body for the leading/trailing inline annotation parsers.
351
+ static int parse_inline_annotation(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos, const char *variables, int variables_length, bool leading) {
352
+ if (!range_is_valid(start_pos, end_pos)) {
353
+ allocate_result(0);
354
+ return RBS_WASM_INVALID_RANGE;
355
+ }
356
+
357
+ rbs_string_t string = rbs_string_new(source, source + length);
358
+ rbs_parser_t *parser = rbs_parser_new(string, resolve_encoding(encoding, encoding_length), start_pos, clamp_end_pos(end_pos, length));
359
+ if (parser == NULL) {
360
+ allocate_result(0);
361
+ return RBS_WASM_INVALID_START_POS;
362
+ }
363
+
364
+ declare_variables(parser, variables, variables_length);
365
+
366
+ rbs_ast_ruby_annotations_t *annotation = NULL;
367
+ bool success = leading ? rbs_parse_inline_leading_annotation(parser, &annotation) : rbs_parse_inline_trailing_annotation(parser, &annotation);
368
+
369
+ int status;
370
+ if (parser->error != NULL) {
371
+ status = set_error_result(parser);
372
+ } else if (!success || annotation == NULL) {
373
+ allocate_result(0);
374
+ status = RBS_WASM_OK;
375
+ } else {
376
+ status = set_serialized_result(parser, (rbs_node_t *) annotation);
377
+ }
378
+
379
+ rbs_parser_free(parser);
380
+ return status;
381
+ }
382
+
383
+ /**
384
+ * Parse an inline leading annotation. On success the result is a serialized
385
+ * node; an empty result means there was no annotation (`nil`).
386
+ */
387
+ __attribute__((export_name("rbs_wasm_parse_inline_leading_annotation"))) int rbs_wasm_parse_inline_leading_annotation(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos, const char *variables, int variables_length) {
388
+ return parse_inline_annotation(source, length, encoding, encoding_length, start_pos, end_pos, variables, variables_length, true);
389
+ }
390
+
391
+ /**
392
+ * Parse an inline trailing annotation. See rbs_wasm_parse_inline_leading_annotation.
393
+ */
394
+ __attribute__((export_name("rbs_wasm_parse_inline_trailing_annotation"))) int rbs_wasm_parse_inline_trailing_annotation(const char *source, int length, const char *encoding, int encoding_length, int start_pos, int end_pos, const char *variables, int variables_length) {
395
+ return parse_inline_annotation(source, length, encoding, encoding_length, start_pos, end_pos, variables, variables_length, false);
396
+ }
397
+
398
+ static void w_lex_u32(rbs_allocator_t *allocator, rbs_buffer_t *buffer, uint32_t value) {
399
+ unsigned char bytes[4] = {
400
+ (unsigned char) (value & 0xff),
401
+ (unsigned char) ((value >> 8) & 0xff),
402
+ (unsigned char) ((value >> 16) & 0xff),
403
+ (unsigned char) ((value >> 24) & 0xff),
404
+ };
405
+ rbs_buffer_append_string(allocator, buffer, (const char *) bytes, 4);
406
+ }
407
+
408
+ /**
409
+ * Lex the source into tokens. The result is a sequence of records, with no
410
+ * leading count (the host reads until the buffer is exhausted):
411
+ *
412
+ * [u32 type_name_len][type_name bytes][i32 start_char][i32 end_char]
413
+ *
414
+ * The final token is always pEOF, mirroring RBS::Parser._lex.
415
+ *
416
+ * @return RBS_WASM_OK, or RBS_WASM_INVALID_RANGE for a negative `end_pos`
417
+ * (lexing does not report parse errors here).
418
+ */
419
+ __attribute__((export_name("rbs_wasm_lex"))) int rbs_wasm_lex(const char *source, int length, const char *encoding, int encoding_length, int end_pos) {
420
+ if (!range_is_valid(0, end_pos)) {
421
+ allocate_result(0);
422
+ return RBS_WASM_INVALID_RANGE;
423
+ }
424
+
425
+ rbs_allocator_t *allocator = rbs_allocator_init();
426
+ // Byte 0 is always a position the lexer can start on, so this is never NULL.
427
+ rbs_lexer_t *lexer = rbs_lexer_new(allocator, rbs_string_new(source, source + length), resolve_encoding(encoding, encoding_length), 0, clamp_end_pos(end_pos, length));
428
+
429
+ rbs_buffer_t buffer;
430
+ rbs_buffer_init(allocator, &buffer);
431
+
432
+ rbs_token_t token = NullToken;
433
+ while (token.type != pEOF) {
434
+ token = rbs_lexer_next_token(lexer);
435
+
436
+ const char *type_name = rbs_token_type_str(token.type);
437
+ uint32_t type_name_length = (uint32_t) strlen(type_name);
438
+ w_lex_u32(allocator, &buffer, type_name_length);
439
+ rbs_buffer_append_string(allocator, &buffer, type_name, type_name_length);
440
+ w_lex_u32(allocator, &buffer, (uint32_t) token.range.start.char_pos);
441
+ w_lex_u32(allocator, &buffer, (uint32_t) token.range.end.char_pos);
442
+ }
443
+
444
+ rbs_string_t bytes = rbs_buffer_to_string(&buffer);
445
+ size_t n = rbs_string_len(bytes);
446
+ memcpy(allocate_result(n), bytes.start, n);
447
+
448
+ rbs_allocator_free(allocator);
449
+ return RBS_WASM_OK;
450
+ }
451
+
452
+ /**
453
+ * Parse a small, fixed RBS document, used as a build smoke test
454
+ * (`wasmtime run --invoke rbs_wasm_selftest rbs_parser.wasm`).
455
+ *
456
+ * @return 1 if the sample parsed successfully, 0 otherwise.
457
+ */
458
+ // Internal: defined in rbs_allocator.c, not declared in the public header.
459
+ extern size_t rbs_allocator_normalize_page_size(long raw);
460
+
461
+ __attribute__((export_name("rbs_wasm_selftest"))) int rbs_wasm_selftest(void) {
462
+ // Regression test: normalize_page_size must return a safe value
463
+ // (>= sizeof(rbs_allocator_page_t)) for inputs that would underflow
464
+ // payload_size. On WASI in a Rust cdylib, sysconf(_SC_PAGESIZE)
465
+ // returns 0; the normalization must catch that.
466
+ if (rbs_allocator_normalize_page_size(-1) != 4096) return 0;
467
+ if (rbs_allocator_normalize_page_size(0) != 4096) return 0;
468
+ if (rbs_allocator_normalize_page_size(1) != 4096) return 0;
469
+ if (rbs_allocator_normalize_page_size(65536) != 65536) return 0;
470
+
471
+ static const char source[] =
472
+ "class User\n"
473
+ " attr_reader name: String\n"
474
+ " def initialize: (String name) -> void\n"
475
+ "end\n";
476
+
477
+ int length = (int) (sizeof(source) - 1);
478
+ return rbs_wasm_parse_signature(source, length, "UTF-8", 5, 0, length);
479
+ }