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/src/string.c CHANGED
@@ -5,54 +5,6 @@
5
5
  #include <stdio.h>
6
6
  #include <ctype.h>
7
7
 
8
- unsigned int rbs_utf8_string_to_codepoint(const rbs_string_t string) {
9
- unsigned int codepoint = 0;
10
- int remaining_bytes = 0;
11
-
12
- const char *s = string.start;
13
- const char *end = string.end;
14
-
15
- if (s >= end) return 0; // End of string
16
-
17
- if ((*s & 0x80) == 0) {
18
- // Single byte character (0xxxxxxx)
19
- return *s;
20
- } else if ((*s & 0xE0) == 0xC0) {
21
- // Two byte character (110xxxxx 10xxxxxx)
22
- codepoint = *s & 0x1F;
23
- remaining_bytes = 1;
24
- } else if ((*s & 0xF0) == 0xE0) {
25
- // Three byte character (1110xxxx 10xxxxxx 10xxxxxx)
26
- codepoint = *s & 0x0F;
27
- remaining_bytes = 2;
28
- } else if ((*s & 0xF8) == 0xF0) {
29
- // Four byte character (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
30
- codepoint = *s & 0x07;
31
- remaining_bytes = 3;
32
- } else {
33
- // Invalid UTF-8 sequence
34
- return 0xFFFD; // Unicode replacement character
35
- }
36
-
37
- s++;
38
- while (remaining_bytes > 0 && s < end) {
39
- if ((*s & 0xC0) != 0x80) {
40
- // Invalid continuation byte
41
- return 0xFFFD;
42
- }
43
- codepoint = (codepoint << 6) | (*s & 0x3F);
44
- s++;
45
- remaining_bytes--;
46
- }
47
-
48
- if (remaining_bytes > 0) {
49
- // Incomplete sequence
50
- return 0xFFFD;
51
- }
52
-
53
- return codepoint;
54
- }
55
-
56
8
  rbs_string_t rbs_string_new(const char *start, const char *end) {
57
9
  return (rbs_string_t) {
58
10
  .start = start,
@@ -3,6 +3,14 @@
3
3
  *
4
4
  * A simple arena allocator that can be freed all at once.
5
5
  *
6
+ * This allocator maintains a linked list of pages, which come in two flavours:
7
+ * 1. Small allocation pages, which are the same size as the system page size.
8
+ * 2. Large allocation pages, which are the exact size requested, for sizes greater than the small page size.
9
+ *
10
+ * Small allocations always fit into the unused space at the end of the "head" page. If there isn't enough room, a new
11
+ * page is allocated, and the small allocation is placed at its start. This approach wastes that unused slack at the
12
+ * end of the previous page, but it means that allocations are instant and never scan the linked list to find a gap.
13
+ *
6
14
  * This allocator doesn't support freeing individual allocations. Only the whole arena can be freed at once at the end.
7
15
  */
8
16
 
@@ -17,19 +25,19 @@
17
25
  #ifdef _WIN32
18
26
  #include <windows.h>
19
27
  #else
20
- #include <unistd.h>
21
- #include <sys/types.h>
22
- #include <sys/mman.h>
28
+ #include <unistd.h> // for sysconf()
23
29
  #endif
24
30
 
25
- #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun)
26
- #define MAP_ANONYMOUS MAP_ANON
27
- #endif
31
+ typedef struct rbs_allocator_page {
32
+ // The previously allocated page, or NULL if this is the first page.
33
+ struct rbs_allocator_page *next;
28
34
 
29
- struct rbs_allocator {
30
- uintptr_t heap_ptr;
31
- uintptr_t size;
32
- };
35
+ // The size of the payload in bytes.
36
+ size_t size;
37
+
38
+ // The offset of the next available byte.
39
+ size_t used;
40
+ } rbs_allocator_page_t;
33
41
 
34
42
  static size_t get_system_page_size(void) {
35
43
  #ifdef _WIN32
@@ -43,73 +51,43 @@ static size_t get_system_page_size(void) {
43
51
  #endif
44
52
  }
45
53
 
46
- static void *map_memory(size_t size) {
47
- #ifdef _WIN32
48
- LPVOID result = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
49
- rbs_assert(result != NULL, "VirtualAlloc failed");
50
- #else
51
- void *result = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
52
- rbs_assert(result != MAP_FAILED, "mmap failed");
53
- #endif
54
- return result;
54
+ static inline uintptr_t rbs_align_up_uintptr(uintptr_t value, size_t alignment) {
55
+ // alignment must be a non-zero power of two
56
+ RBS_ASSERT(alignment != 0 && (alignment & (alignment - 1)) == 0, "alignment must be a non-zero power of two. alignment: %zu", alignment);
57
+ return (value + (alignment - 1)) & ~(uintptr_t) (alignment - 1);
55
58
  }
56
59
 
57
- static void destroy_memory(void *memory, size_t size) {
58
- #ifdef _WIN32
59
- VirtualFree(memory, 0, MEM_RELEASE);
60
- #else
61
- munmap(memory, size);
62
- #endif
63
- }
60
+ static rbs_allocator_page_t *rbs_allocator_page_new(size_t payload_size) {
61
+ const size_t page_header_size = sizeof(rbs_allocator_page_t);
64
62
 
65
- static void guard_page(void *memory, size_t page_size) {
66
- #ifdef _WIN32
67
- DWORD old_protect_;
68
- BOOL result = VirtualProtect(memory, page_size, PAGE_NOACCESS, &old_protect_);
69
- rbs_assert(result != 0, "VirtualProtect failed");
70
- #else
71
- int result = mprotect(memory, page_size, PROT_NONE);
72
- rbs_assert(result == 0, "mprotect failed");
73
- #endif
74
- }
63
+ rbs_allocator_page_t *page = (rbs_allocator_page_t *) malloc(page_header_size + payload_size);
64
+ page->size = payload_size;
65
+ page->used = 0;
75
66
 
76
- static size_t rbs_allocator_default_mem(void) {
77
- size_t kib = 1024;
78
- size_t mib = kib * 1024;
79
- size_t gib = mib * 1024;
80
- return 4 * gib;
67
+ return page;
81
68
  }
82
69
 
83
- static inline bool is_power_of_two(uintptr_t value) {
84
- return value > 0 && (value & (value - 1)) == 0;
85
- }
70
+ rbs_allocator_t *rbs_allocator_init(void) {
71
+ rbs_allocator_t *allocator = (rbs_allocator_t *) malloc(sizeof(rbs_allocator_t));
86
72
 
87
- // Align `val' to nearest multiple of `alignment'.
88
- static uintptr_t align(uintptr_t size, uintptr_t alignment) {
89
- rbs_assert(is_power_of_two(alignment), "alignment is not a power of two");
90
- return (size + alignment - 1) & ~(alignment - 1);
91
- }
73
+ const size_t system_page_size = get_system_page_size();
92
74
 
93
- rbs_allocator_t *rbs_allocator_init(void) {
94
- size_t size = rbs_allocator_default_mem();
95
- size_t page_size = get_system_page_size();
96
- size = align(size, page_size);
97
- void *mem = map_memory(size + page_size);
98
- // Guard page; remove range checks in alloc fast path and hard fail if we
99
- // consume all memory
100
- void *last_page = (char *) mem + size;
101
- guard_page(last_page, page_size);
102
- uintptr_t start = (uintptr_t) mem;
103
- rbs_allocator_t header = (rbs_allocator_t) {
104
- .heap_ptr = start + sizeof header,
105
- .size = size + page_size,
106
- };
107
- memcpy(mem, &header, sizeof header);
108
- return (rbs_allocator_t *) mem;
75
+ allocator->default_page_payload_size = system_page_size - sizeof(rbs_allocator_page_t);
76
+
77
+ allocator->page = rbs_allocator_page_new(allocator->default_page_payload_size);
78
+ allocator->page->next = NULL;
79
+
80
+ return allocator;
109
81
  }
110
82
 
111
83
  void rbs_allocator_free(rbs_allocator_t *allocator) {
112
- destroy_memory((void *) allocator, allocator->size);
84
+ rbs_allocator_page_t *page = allocator->page;
85
+ while (page) {
86
+ rbs_allocator_page_t *next = page->next;
87
+ free(page);
88
+ page = next;
89
+ }
90
+ free(allocator);
113
91
  }
114
92
 
115
93
  // Allocates `new_size` bytes from `allocator`, aligned to an `alignment`-byte boundary.
@@ -123,21 +101,58 @@ void *rbs_allocator_realloc_impl(rbs_allocator_t *allocator, void *ptr, size_t o
123
101
 
124
102
  // Allocates `size` bytes from `allocator`, aligned to an `alignment`-byte boundary.
125
103
  void *rbs_allocator_malloc_impl(rbs_allocator_t *allocator, size_t size, size_t alignment) {
126
- rbs_assert(size % alignment == 0, "size must be a multiple of the alignment. size: %zu, alignment: %zu", size, alignment);
127
- uintptr_t aligned = align(allocator->heap_ptr, alignment);
128
- allocator->heap_ptr = aligned + size;
129
- return (void *) aligned;
104
+ if (allocator->default_page_payload_size < size) { // Big allocation, give it its own page.
105
+ // Add padding to ensure we can align the start pointer within this page
106
+ rbs_allocator_page_t *new_page = rbs_allocator_page_new(size + (alignment - 1));
107
+
108
+ // This simple allocator can only put small allocations into the head page.
109
+ // Naively prepending this large allocation page to the head of the allocator before the previous head page
110
+ // would waste the remaining space in the head page.
111
+ // So instead, we'll splice in the large page *after* the head page.
112
+ //
113
+ // +-------+ +-----------+ +-----------+
114
+ // | arena | | head page | | new_page |
115
+ // |-------| |-----------+ |-----------+
116
+ // | *page |--->| size | +--->| size | +---> ... previous tail
117
+ // +-------+ | offset | | | offset | |
118
+ // | *next ----+---+ | *next ----+---+
119
+ // | ... | | ... |
120
+ // +-----------+ +-----------+
121
+ //
122
+ new_page->next = allocator->page->next;
123
+ allocator->page->next = new_page;
124
+
125
+ uintptr_t base = (uintptr_t) new_page + sizeof(rbs_allocator_page_t);
126
+ uintptr_t aligned_ptr = rbs_align_up_uintptr(base, alignment);
127
+ return (void *) aligned_ptr;
128
+ }
129
+
130
+ rbs_allocator_page_t *page = allocator->page;
131
+ uintptr_t base = (uintptr_t) page + sizeof(rbs_allocator_page_t);
132
+
133
+ // Compute aligned offset within the payload
134
+ size_t used_aligned = (size_t) (rbs_align_up_uintptr(base + page->used, alignment) - base);
135
+
136
+ if (used_aligned + size > page->size) {
137
+ // Not enough space. Allocate a new small page and prepend it to the allocator's linked list.
138
+ rbs_allocator_page_t *new_page = rbs_allocator_page_new(allocator->default_page_payload_size);
139
+ new_page->next = allocator->page;
140
+ allocator->page = new_page;
141
+ page = new_page;
142
+ base = (uintptr_t) page + sizeof(rbs_allocator_page_t);
143
+ used_aligned = (size_t) (rbs_align_up_uintptr(base, alignment) - base); // start of fresh page (usually 0 if header is aligned)
144
+ }
145
+
146
+ uintptr_t pointer = base + used_aligned;
147
+ page->used = used_aligned + size;
148
+ return (void *) pointer;
130
149
  }
131
150
 
132
151
  // Note: This will eagerly fill with zeroes, unlike `calloc()` which can map a page in a page to be zeroed lazily.
133
152
  // It's assumed that callers to this function will immediately write to the allocated memory, anyway.
134
153
  void *rbs_allocator_calloc_impl(rbs_allocator_t *allocator, size_t count, size_t size, size_t alignment) {
135
154
  void *p = rbs_allocator_malloc_many_impl(allocator, count, size, alignment);
136
- #if defined(__linux__)
137
- // mmap with MAP_ANONYMOUS gives zero-filled pages.
138
- #else
139
155
  memset(p, 0, count * size);
140
- #endif
141
156
  return p;
142
157
  }
143
158
 
@@ -5,7 +5,7 @@
5
5
  #include <stdlib.h>
6
6
  #include <stdbool.h>
7
7
 
8
- void rbs_assert(bool condition, const char *fmt, ...) {
8
+ void rbs_assert_impl(bool condition, const char *fmt, ...) {
9
9
  if (condition) {
10
10
  return;
11
11
  }
@@ -25,7 +25,7 @@ void rbs_buffer_append_string(rbs_allocator_t *allocator, rbs_buffer_t *buffer,
25
25
  if (next_length > buffer->capacity) {
26
26
  size_t old_capacity = buffer->capacity;
27
27
 
28
- rbs_assert(old_capacity != 0, "Precondition: capacity must be at least 1. Got %zu", old_capacity);
28
+ RBS_ASSERT(old_capacity != 0, "Precondition: capacity must be at least 1. Got %zu", old_capacity);
29
29
 
30
30
  size_t new_capacity = buffer->capacity * 2;
31
31
 
@@ -34,7 +34,7 @@ void rbs_buffer_append_string(rbs_allocator_t *allocator, rbs_buffer_t *buffer,
34
34
  }
35
35
 
36
36
  char *new_value = rbs_allocator_realloc(allocator, buffer->value, old_capacity, new_capacity, char);
37
- rbs_assert(new_value != NULL, "Failed to append to buffer. Old capacity: %zu, new capacity: %zu", old_capacity, new_capacity);
37
+ RBS_ASSERT(new_value != NULL, "Failed to append to buffer. Old capacity: %zu, new capacity: %zu", old_capacity, new_capacity);
38
38
 
39
39
  buffer->value = new_value;
40
40
  buffer->capacity = new_capacity;
@@ -37,7 +37,7 @@ next_power_of_two(uint32_t v) {
37
37
  return v;
38
38
  }
39
39
 
40
- static bool is_power_of_two(uint32_t size) {
40
+ RBS_ATTRIBUTE_UNUSED static bool is_power_of_two(uint32_t size) {
41
41
  return (size & (size - 1)) == 0;
42
42
  }
43
43
 
@@ -46,7 +46,7 @@ static bool is_power_of_two(uint32_t size) {
46
46
  */
47
47
  static inline bool
48
48
  rbs_constant_pool_resize(rbs_constant_pool_t *pool) {
49
- rbs_assert(is_power_of_two(pool->capacity), "pool->capacity is not a power of two. Got %i", pool->capacity);
49
+ RBS_ASSERT(is_power_of_two(pool->capacity), "pool->capacity is not a power of two. Got %i", pool->capacity);
50
50
 
51
51
  uint32_t next_capacity = pool->capacity * 2;
52
52
  if (next_capacity < pool->capacity) return false;
@@ -57,8 +57,8 @@ rbs_constant_pool_resize(rbs_constant_pool_t *pool) {
57
57
  void *next = calloc(next_capacity, element_size);
58
58
  if (next == NULL) return false;
59
59
 
60
- rbs_constant_pool_bucket_t *next_buckets = next;
61
- rbs_constant_t *next_constants = (void *) (((char *) next) + next_capacity * sizeof(rbs_constant_pool_bucket_t));
60
+ rbs_constant_pool_bucket_t *next_buckets = (rbs_constant_pool_bucket_t *) next;
61
+ rbs_constant_t *next_constants = (rbs_constant_t *) (((char *) next) + next_capacity * sizeof(rbs_constant_pool_bucket_t));
62
62
 
63
63
  // For each bucket in the current constant pool, find the index in the
64
64
  // next constant pool, and insert it.
@@ -95,10 +95,6 @@ rbs_constant_pool_resize(rbs_constant_pool_t *pool) {
95
95
  return true;
96
96
  }
97
97
 
98
- // This storage is initialized by `Init_rbs_extension()` in `main.c`.
99
- static rbs_constant_pool_t RBS_GLOBAL_CONSTANT_POOL_STORAGE = { 0 };
100
- rbs_constant_pool_t *RBS_GLOBAL_CONSTANT_POOL = &RBS_GLOBAL_CONSTANT_POOL_STORAGE;
101
-
102
98
  /**
103
99
  * Initialize a new constant pool with a given capacity.
104
100
  */
@@ -111,8 +107,8 @@ bool rbs_constant_pool_init(rbs_constant_pool_t *pool, uint32_t capacity) {
111
107
  void *memory = calloc(capacity, element_size);
112
108
  if (memory == NULL) return false;
113
109
 
114
- pool->buckets = memory;
115
- pool->constants = (void *) (((char *) memory) + capacity * sizeof(rbs_constant_pool_bucket_t));
110
+ pool->buckets = (rbs_constant_pool_bucket_t *) memory;
111
+ pool->constants = (rbs_constant_t *) (((char *) memory) + capacity * sizeof(rbs_constant_pool_bucket_t));
116
112
  pool->size = 0;
117
113
  pool->capacity = capacity;
118
114
  return true;
@@ -123,7 +119,7 @@ bool rbs_constant_pool_init(rbs_constant_pool_t *pool, uint32_t capacity) {
123
119
  */
124
120
  rbs_constant_t *
125
121
  rbs_constant_pool_id_to_constant(const rbs_constant_pool_t *pool, rbs_constant_id_t constant_id) {
126
- rbs_assert(constant_id != RBS_CONSTANT_ID_UNSET && constant_id <= pool->size, "constant_id is not valid. Got %i, pool->size: %i", constant_id, pool->size);
122
+ RBS_ASSERT(constant_id != RBS_CONSTANT_ID_UNSET && constant_id <= pool->size, "constant_id is not valid. Got %i, pool->size: %i", constant_id, pool->size);
127
123
  return &pool->constants[constant_id - 1];
128
124
  }
129
125
 
@@ -133,7 +129,7 @@ rbs_constant_pool_id_to_constant(const rbs_constant_pool_t *pool, rbs_constant_i
133
129
  */
134
130
  rbs_constant_id_t
135
131
  rbs_constant_pool_find(const rbs_constant_pool_t *pool, const uint8_t *start, size_t length) {
136
- rbs_assert(is_power_of_two(pool->capacity), "pool->capacity is not a power of two. Got %i", pool->capacity);
132
+ RBS_ASSERT(is_power_of_two(pool->capacity), "pool->capacity is not a power of two. Got %i", pool->capacity);
137
133
  const uint32_t mask = pool->capacity - 1;
138
134
 
139
135
  uint32_t hash = rbs_constant_pool_hash(start, length);
@@ -161,7 +157,7 @@ rbs_constant_pool_insert(rbs_constant_pool_t *pool, const uint8_t *start, size_t
161
157
  if (!rbs_constant_pool_resize(pool)) return RBS_CONSTANT_ID_UNSET;
162
158
  }
163
159
 
164
- rbs_assert(is_power_of_two(pool->capacity), "pool->capacity is not a power of two. Got %i", pool->capacity);
160
+ RBS_ASSERT(is_power_of_two(pool->capacity), "pool->capacity is not a power of two. Got %i", pool->capacity);
165
161
  const uint32_t mask = pool->capacity - 1;
166
162
 
167
163
  uint32_t hash = rbs_constant_pool_hash(start, length);
@@ -202,7 +198,7 @@ rbs_constant_pool_insert(rbs_constant_pool_t *pool, const uint8_t *start, size_t
202
198
  // IDs are allocated starting at 1, since the value 0 denotes a non-existent
203
199
  // constant.
204
200
  uint32_t id = ++pool->size;
205
- rbs_assert(pool->size < ((uint32_t) (1 << 30)), "pool->size is too large. Got %i", pool->size);
201
+ RBS_ASSERT(pool->size < ((uint32_t) (1 << 30)), "pool->size is too large. Got %i", pool->size);
206
202
 
207
203
  *bucket = (rbs_constant_pool_bucket_t) {
208
204
  .id = (unsigned int) (id & 0x3fffffff),
@@ -3,12 +3,6 @@
3
3
 
4
4
  #include <ctype.h>
5
5
 
6
- #if defined(__GNUC__)
7
- #define RBS_ATTRIBUTE_UNUSED __attribute__((unused))
8
- #else
9
- #define RBS_ATTRIBUTE_UNUSED
10
- #endif
11
-
12
6
  typedef uint32_t rbs_unicode_codepoint_t;
13
7
 
14
8
  #define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450
@@ -4620,6 +4614,7 @@ rbs_unicode_codepoint_match(rbs_unicode_codepoint_t codepoint, const rbs_unicode
4620
4614
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4621
4615
  * SOFTWARE.
4622
4616
  */
4617
+ // clang-format off
4623
4618
  static const uint8_t rbs_utf_8_dfa[] = {
4624
4619
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
4625
4620
  0,
@@ -4991,6 +4986,7 @@ static const uint8_t rbs_utf_8_dfa[] = {
4991
4986
  1,
4992
4987
  1, // s7..s8
4993
4988
  };
4989
+ // clang-format on
4994
4990
 
4995
4991
  /**
4996
4992
  * Given a pointer to a string and the number of bytes remaining in the string,
@@ -4999,7 +4995,7 @@ static const uint8_t rbs_utf_8_dfa[] = {
4999
4995
  */
5000
4996
  static rbs_unicode_codepoint_t
5001
4997
  rbs_utf_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
5002
- rbs_assert(n >= 0, "n must be greater than or equal to 0. Got %ti", n);
4998
+ RBS_ASSERT(n >= 0, "[rbs_unicode_codepoint_t] n must be greater than or equal to 0. Got %ti", n);
5003
4999
 
5004
5000
  size_t maximum = (n > 4) ? 4 : ((size_t) n);
5005
5001
  uint32_t codepoint;
@@ -5029,7 +5025,7 @@ rbs_utf_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
5029
5025
  */
5030
5026
  size_t
5031
5027
  rbs_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n) {
5032
- rbs_assert(n >= 0, "n must be greater than or equal to 0. Got %ti", n);
5028
+ RBS_ASSERT(n >= 0, "[rbs_encoding_utf_8_char_width] n must be greater than or equal to 0. Got %ti", n);
5033
5029
 
5034
5030
  size_t maximum = (n > 4) ? 4 : ((size_t) n);
5035
5031
  uint32_t state = 0;
@@ -1,4 +1,5 @@
1
1
  #include "rbs/util/rbs_unescape.h"
2
+ #include "rbs/util/rbs_encoding.h"
2
3
  #include <string.h>
3
4
  #include <stdlib.h>
4
5
  #include <ctype.h>
@@ -42,20 +43,44 @@ static int octal_to_int(const char *octal, int length) {
42
43
  return result;
43
44
  }
44
45
 
45
- int rbs_utf8_codelen(unsigned int c) {
46
- if (c <= 0x7F) return 1;
47
- if (c <= 0x7FF) return 2;
48
- if (c <= 0xFFFF) return 3;
49
- if (c <= 0x10FFFF) return 4;
50
- return 1; // Invalid Unicode codepoint, treat as 1 byte
46
+ // Fills buf starting at index 'start' with the UTF-8 encoding of 'codepoint'.
47
+ // Returns the number of bytes written, or 0 when the output is not changed.
48
+ //
49
+ size_t rbs_utf8_fill_codepoint(char *buf, size_t start, size_t end, unsigned int codepoint) {
50
+ if (start + 4 > end) {
51
+ return 0;
52
+ }
53
+
54
+ if (codepoint <= 0x7F) {
55
+ buf[start] = codepoint & 0x7F;
56
+ return 1;
57
+ } else if (codepoint <= 0x7FF) {
58
+ buf[start + 0] = 0xC0 | ((codepoint >> 6) & 0x1F);
59
+ buf[start + 1] = 0x80 | (codepoint & 0x3F);
60
+ return 2;
61
+ } else if (codepoint <= 0xFFFF) {
62
+ buf[start + 0] = 0xE0 | ((codepoint >> 12) & 0x0F);
63
+ buf[start + 1] = 0x80 | ((codepoint >> 6) & 0x3F);
64
+ buf[start + 2] = 0x80 | (codepoint & 0x3F);
65
+ return 3;
66
+ } else if (codepoint <= 0x10FFFF) {
67
+ buf[start + 0] = 0xF0 | ((codepoint >> 18) & 0x07);
68
+ buf[start + 1] = 0x80 | ((codepoint >> 12) & 0x3F);
69
+ buf[start + 2] = 0x80 | ((codepoint >> 6) & 0x3F);
70
+ buf[start + 3] = 0x80 | (codepoint & 0x3F);
71
+ return 4;
72
+ } else {
73
+ return 0;
74
+ }
51
75
  }
52
76
 
53
- rbs_string_t unescape_string(rbs_allocator_t *allocator, const rbs_string_t string, bool is_double_quote) {
77
+ rbs_string_t unescape_string(rbs_allocator_t *allocator, const rbs_string_t string, bool is_double_quote, bool is_unicode) {
54
78
  if (!string.start) return RBS_STRING_NULL;
55
79
 
56
80
  size_t len = string.end - string.start;
57
81
  const char *input = string.start;
58
82
 
83
+ // The output cannot be longer than the input even after unescaping.
59
84
  char *output = rbs_allocator_alloc_many(allocator, len + 1, char);
60
85
  if (!output) return RBS_STRING_NULL;
61
86
 
@@ -79,9 +104,21 @@ rbs_string_t unescape_string(rbs_allocator_t *allocator, const rbs_string_t stri
79
104
  i += hex_len + 2;
80
105
  } else if (input[i + 1] == 'u' && i + 5 < len) {
81
106
  // Unicode escape
82
- int value = hex_to_int(input + i + 2, 4);
83
- output[j++] = (char) value;
84
- i += 6;
107
+
108
+ if (is_unicode) {
109
+ // The UTF-8 representation is at most 4 bytes, shorter than the input length.
110
+ int value = hex_to_int(input + i + 2, 4);
111
+ j += rbs_utf8_fill_codepoint(output, j, len + 1, value);
112
+ i += 6;
113
+ } else {
114
+ // Copy the escape sequence as-is
115
+ output[j++] = input[i++];
116
+ output[j++] = input[i++];
117
+ output[j++] = input[i++];
118
+ output[j++] = input[i++];
119
+ output[j++] = input[i++];
120
+ output[j++] = input[i++];
121
+ }
85
122
  } else {
86
123
  // Other escapes
87
124
  int found = 0;
@@ -114,18 +151,17 @@ rbs_string_t unescape_string(rbs_allocator_t *allocator, const rbs_string_t stri
114
151
  return rbs_string_new(output, output + j);
115
152
  }
116
153
 
117
- rbs_string_t rbs_unquote_string(rbs_allocator_t *allocator, rbs_string_t input) {
118
- unsigned int first_char = rbs_utf8_string_to_codepoint(input);
119
- size_t byte_length = rbs_string_len(input);
154
+ rbs_string_t rbs_unquote_string(rbs_allocator_t *allocator, rbs_string_t input, const rbs_encoding_t *encoding) {
155
+ unsigned int first_char = input.start[0];
156
+
157
+ const char *new_start = input.start;
158
+ const char *new_end = input.end;
120
159
 
121
- ptrdiff_t start_offset = 0;
122
160
  if (first_char == '"' || first_char == '\'' || first_char == '`') {
123
- int bs = rbs_utf8_codelen(first_char);
124
- start_offset += bs;
125
- byte_length -= 2 * bs;
161
+ new_start += 1;
162
+ new_end -= 1;
126
163
  }
127
164
 
128
- const char *new_start = input.start + start_offset;
129
- rbs_string_t string = rbs_string_new(new_start, new_start + byte_length);
130
- return unescape_string(allocator, string, first_char == '"');
165
+ rbs_string_t string = rbs_string_new(new_start, new_end);
166
+ return unescape_string(allocator, string, first_char == '"', encoding == RBS_ENCODING_UTF_8_ENTRY);
131
167
  }
@@ -1,5 +1,5 @@
1
1
  %a{annotate:rdoc:skip}
2
- class Array[unchecked out Elem]
2
+ class Array[unchecked out E]
3
3
  # <!--
4
4
  # rdoc-file=lib/abbrev.rb
5
5
  # - abbrev(pattern = nil)