prism 1.9.0 → 2.0.0.rc2

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 (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/LICENSE.md +1 -1
  5. data/Makefile +41 -12
  6. data/README.md +35 -97
  7. data/config.yml +174 -161
  8. data/docs/build_system.md +2 -2
  9. data/docs/configuration.md +5 -4
  10. data/docs/encoding.md +2 -2
  11. data/docs/fuzzing.md +4 -11
  12. data/docs/javascript.md +19 -4
  13. data/docs/mapping.md +1 -1
  14. data/docs/releasing.md +77 -5
  15. data/docs/relocation.md +2 -4
  16. data/docs/serialization.md +22 -24
  17. data/docs/testing.md +46 -29
  18. data/ext/prism/api_node.c +1461 -1401
  19. data/ext/prism/extconf.rb +3 -4
  20. data/ext/prism/extension.c +796 -422
  21. data/ext/prism/extension.h +3 -3
  22. data/include/prism/arena.h +37 -0
  23. data/include/prism/ast.h +2727 -610
  24. data/include/prism/buffer.h +52 -0
  25. data/include/prism/comments.h +55 -0
  26. data/include/prism/compiler/accel.h +26 -0
  27. data/include/prism/compiler/align.h +36 -0
  28. data/include/prism/compiler/assume.h +25 -0
  29. data/include/prism/compiler/bswap.h +46 -0
  30. data/include/prism/compiler/endianness.h +34 -0
  31. data/include/prism/compiler/exported.h +24 -0
  32. data/include/prism/compiler/fallthrough.h +22 -0
  33. data/include/prism/compiler/filesystem.h +32 -0
  34. data/include/prism/compiler/flex_array.h +19 -0
  35. data/include/prism/compiler/force_inline.h +21 -0
  36. data/include/prism/compiler/format.h +25 -0
  37. data/include/prism/compiler/inline.h +17 -0
  38. data/include/prism/compiler/nodiscard.h +22 -0
  39. data/include/prism/compiler/nonnull.h +18 -0
  40. data/include/prism/compiler/unused.h +18 -0
  41. data/include/prism/constant_pool.h +81 -0
  42. data/include/prism/diagnostic.h +38 -403
  43. data/include/prism/errors_format.h +53 -0
  44. data/include/prism/excludes.h +29 -0
  45. data/include/prism/integer.h +41 -0
  46. data/include/prism/internal/allocator.h +68 -0
  47. data/include/prism/internal/allocator_debug.h +88 -0
  48. data/include/prism/internal/arena.h +108 -0
  49. data/include/prism/internal/bit.h +42 -0
  50. data/include/prism/internal/buffer.h +94 -0
  51. data/include/prism/internal/char.h +145 -0
  52. data/include/prism/internal/comments.h +53 -0
  53. data/include/prism/internal/constant_pool.h +152 -0
  54. data/include/prism/internal/diagnostic.h +389 -0
  55. data/include/prism/{encoding.h → internal/encoding.h} +27 -68
  56. data/include/prism/internal/integer.h +68 -0
  57. data/include/prism/internal/isinf.h +16 -0
  58. data/include/prism/internal/line_offset_list.h +34 -0
  59. data/include/prism/{util/pm_list.h → internal/list.h} +11 -52
  60. data/include/prism/internal/magic_comments.h +23 -0
  61. data/include/prism/internal/memchr.h +15 -0
  62. data/include/prism/internal/node.h +38 -0
  63. data/include/prism/internal/options.h +232 -0
  64. data/include/prism/internal/parser.h +1004 -0
  65. data/include/prism/internal/regexp.h +26 -0
  66. data/include/prism/internal/serialize.h +39 -0
  67. data/include/prism/internal/source.h +72 -0
  68. data/include/prism/{static_literals.h → internal/static_literals.h} +26 -47
  69. data/include/prism/internal/stringy.h +35 -0
  70. data/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
  71. data/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
  72. data/include/prism/internal/tokens.h +11 -0
  73. data/include/prism/internal/xxh3.h +16 -0
  74. data/include/prism/json.h +32 -0
  75. data/include/prism/line_offset_list.h +61 -0
  76. data/include/prism/magic_comments.h +35 -0
  77. data/include/prism/node.h +18 -53
  78. data/include/prism/options.h +146 -280
  79. data/include/prism/parser.h +356 -867
  80. data/include/prism/prettyprint.h +6 -9
  81. data/include/prism/serialize.h +115 -0
  82. data/include/prism/source.h +155 -0
  83. data/include/prism/stream.h +28 -0
  84. data/include/prism/string_query.h +74 -0
  85. data/include/prism/stringy.h +72 -0
  86. data/include/prism/version.h +12 -3
  87. data/include/prism.h +43 -320
  88. data/lib/prism/compiler.rb +319 -305
  89. data/lib/prism/desugar_compiler.rb +105 -34
  90. data/lib/prism/dispatcher.rb +646 -473
  91. data/lib/prism/dot_visitor.rb +592 -511
  92. data/lib/prism/dsl.rb +391 -25
  93. data/lib/prism/ffi.rb +258 -90
  94. data/lib/prism/inspect_visitor.rb +357 -325
  95. data/lib/prism/lex_compat.rb +254 -212
  96. data/lib/prism/mutation_compiler.rb +313 -305
  97. data/lib/prism/node.rb +20966 -6992
  98. data/lib/prism/node_ext.rb +180 -187
  99. data/lib/prism/node_find.rb +215 -0
  100. data/lib/prism/parse_result/errors.rb +7 -1
  101. data/lib/prism/parse_result/newlines.rb +276 -8
  102. data/lib/prism/parse_result.rb +468 -139
  103. data/lib/prism/pattern.rb +65 -20
  104. data/lib/prism/reflection.rb +23 -12
  105. data/lib/prism/relocation.rb +149 -87
  106. data/lib/prism/serialize.rb +3460 -539
  107. data/lib/prism/string_query.rb +24 -1
  108. data/lib/prism/translation/parser/builder.rb +10 -2
  109. data/lib/prism/translation/parser/compiler.rb +44 -52
  110. data/lib/prism/translation/parser/lexer.rb +41 -92
  111. data/lib/prism/translation/parser.rb +1 -1
  112. data/lib/prism/translation/parser_current.rb +1 -1
  113. data/lib/prism/translation/ripper/lexer.rb +8 -10
  114. data/lib/prism/translation/ripper/sexp.rb +2 -10
  115. data/lib/prism/translation/ripper/shim.rb +2 -0
  116. data/lib/prism/translation/ripper.rb +967 -209
  117. data/lib/prism/translation/ruby_parser.rb +73 -316
  118. data/lib/prism/translation.rb +2 -0
  119. data/lib/prism/visitor.rb +632 -5
  120. data/lib/prism.rb +79 -9
  121. data/prism.gemspec +128 -62
  122. data/rbi/generated/prism/compiler.rbi +489 -0
  123. data/rbi/generated/prism/desugar_compiler.rbi +306 -0
  124. data/rbi/generated/prism/dispatcher.rbi +1138 -0
  125. data/rbi/generated/prism/dot_visitor.rbi +618 -0
  126. data/rbi/generated/prism/dsl.rbi +751 -0
  127. data/rbi/generated/prism/inspect_visitor.rbi +503 -0
  128. data/rbi/generated/prism/lex_compat.rbi +162 -0
  129. data/rbi/generated/prism/mutation_compiler.rbi +464 -0
  130. data/rbi/generated/prism/node.rbi +14407 -0
  131. data/rbi/generated/prism/node_ext.rbi +259 -0
  132. data/rbi/generated/prism/node_find.rbi +79 -0
  133. data/rbi/generated/prism/parse_result/errors.rbi +21 -0
  134. data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
  135. data/rbi/generated/prism/parse_result.rbi +776 -0
  136. data/rbi/generated/prism/pattern.rbi +134 -0
  137. data/rbi/generated/prism/reflection.rbi +89 -0
  138. data/rbi/generated/prism/relocation.rbi +329 -0
  139. data/rbi/generated/prism/serialize.rbi +184 -0
  140. data/rbi/generated/prism/string_query.rbi +43 -0
  141. data/rbi/generated/prism/translation.rbi +7 -0
  142. data/rbi/generated/prism/visitor.rbi +650 -0
  143. data/rbi/generated/prism.rbi +86 -0
  144. data/rbi/prism/translation/parser_versions.rbi +5 -0
  145. data/rbi/rubyvm/node_find.rbi +14 -0
  146. data/sig/generated/prism/compiler.rbs +492 -0
  147. data/sig/generated/prism/desugar_compiler.rbs +305 -0
  148. data/sig/generated/prism/dispatcher.rbs +1292 -0
  149. data/sig/generated/prism/dot_visitor.rbs +635 -0
  150. data/sig/generated/prism/dsl.rbs +928 -0
  151. data/sig/generated/prism/inspect_visitor.rbs +509 -0
  152. data/sig/generated/prism/lex_compat.rbs +166 -0
  153. data/sig/{prism → generated/prism}/mutation_compiler.rbs +309 -4
  154. data/sig/generated/prism/node.rbs +20896 -0
  155. data/sig/generated/prism/node_ext.rbs +290 -0
  156. data/sig/generated/prism/node_find.rbs +90 -0
  157. data/sig/generated/prism/parse_result/errors.rbs +22 -0
  158. data/sig/generated/prism/parse_result/newlines.rbs +223 -0
  159. data/sig/generated/prism/parse_result.rbs +871 -0
  160. data/sig/generated/prism/pattern.rbs +156 -0
  161. data/sig/generated/prism/reflection.rbs +101 -0
  162. data/sig/generated/prism/relocation.rbs +428 -0
  163. data/sig/generated/prism/serialize.rbs +198 -0
  164. data/sig/generated/prism/string_query.rbs +43 -0
  165. data/sig/generated/prism/translation.rbs +8 -0
  166. data/sig/generated/prism/visitor.rbs +1111 -0
  167. data/sig/generated/prism.rbs +84 -0
  168. data/sig/manifest.yaml +2 -0
  169. data/src/arena.c +117 -0
  170. data/src/{util/pm_buffer.c → buffer.c} +53 -21
  171. data/src/{util/pm_char.c → char.c} +28 -57
  172. data/src/comments.c +454 -0
  173. data/src/constant_pool.c +406 -0
  174. data/src/diagnostic.c +97 -65
  175. data/src/encoding.c +8 -3
  176. data/src/errors_format.c +519 -0
  177. data/src/{util/pm_integer.c → integer.c} +33 -22
  178. data/src/json.c +5733 -0
  179. data/src/line_offset_list.c +100 -0
  180. data/src/list.c +24 -0
  181. data/src/{util/pm_memchr.c → memchr.c} +8 -6
  182. data/src/node.c +3504 -7674
  183. data/src/options.c +162 -49
  184. data/src/parser.c +367 -0
  185. data/src/prettyprint.c +421 -354
  186. data/src/prism.c +8402 -7161
  187. data/src/regexp.c +961 -45
  188. data/src/serialize.c +460 -424
  189. data/src/source.c +518 -0
  190. data/src/static_literals.c +111 -43
  191. data/src/string_query.c +180 -0
  192. data/src/stringy.c +91 -0
  193. data/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
  194. data/src/strpbrk.c +447 -0
  195. data/src/{token_type.c → tokens.c} +39 -18
  196. data/src/xxh3.c +292 -0
  197. metadata +128 -63
  198. data/ext/prism/api_pack.c +0 -276
  199. data/include/prism/defines.h +0 -260
  200. data/include/prism/pack.h +0 -163
  201. data/include/prism/regexp.h +0 -43
  202. data/include/prism/util/pm_buffer.h +0 -236
  203. data/include/prism/util/pm_char.h +0 -204
  204. data/include/prism/util/pm_constant_pool.h +0 -218
  205. data/include/prism/util/pm_integer.h +0 -130
  206. data/include/prism/util/pm_memchr.h +0 -29
  207. data/include/prism/util/pm_newline_list.h +0 -113
  208. data/include/prism/util/pm_string.h +0 -200
  209. data/lib/prism/pack.rb +0 -230
  210. data/lib/prism/parse_result/comments.rb +0 -188
  211. data/rbi/prism/compiler.rbi +0 -12
  212. data/rbi/prism/dsl.rbi +0 -524
  213. data/rbi/prism/inspect_visitor.rbi +0 -12
  214. data/rbi/prism/node.rbi +0 -8750
  215. data/rbi/prism/node_ext.rbi +0 -107
  216. data/rbi/prism/parse_result.rbi +0 -404
  217. data/rbi/prism/reflection.rbi +0 -58
  218. data/rbi/prism/string_query.rbi +0 -12
  219. data/rbi/prism/visitor.rbi +0 -473
  220. data/rbi/prism.rbi +0 -63
  221. data/sig/prism/compiler.rbs +0 -9
  222. data/sig/prism/dispatcher.rbs +0 -19
  223. data/sig/prism/dot_visitor.rbs +0 -6
  224. data/sig/prism/dsl.rbs +0 -351
  225. data/sig/prism/inspect_visitor.rbs +0 -22
  226. data/sig/prism/lex_compat.rbs +0 -10
  227. data/sig/prism/node.rbs +0 -4042
  228. data/sig/prism/node_ext.rbs +0 -149
  229. data/sig/prism/pack.rbs +0 -43
  230. data/sig/prism/parse_result/comments.rbs +0 -38
  231. data/sig/prism/parse_result.rbs +0 -197
  232. data/sig/prism/pattern.rbs +0 -13
  233. data/sig/prism/reflection.rbs +0 -50
  234. data/sig/prism/relocation.rbs +0 -185
  235. data/sig/prism/serialize.rbs +0 -8
  236. data/sig/prism/string_query.rbs +0 -11
  237. data/sig/prism/visitor.rbs +0 -169
  238. data/sig/prism.rbs +0 -272
  239. data/src/pack.c +0 -509
  240. data/src/util/pm_constant_pool.c +0 -342
  241. data/src/util/pm_list.c +0 -49
  242. data/src/util/pm_newline_list.c +0 -125
  243. data/src/util/pm_string.c +0 -381
  244. data/src/util/pm_strpbrk.c +0 -206
@@ -0,0 +1,84 @@
1
+ # Generated from lib/prism.rb with RBS::Inline
2
+
3
+ # The Prism Ruby parser.
4
+ #
5
+ # "Parsing Ruby is suddenly manageable!"
6
+ # - You, hopefully
7
+ module Prism
8
+ # Raised when requested to parse as the currently running Ruby version but Prism has no support for it.
9
+ class CurrentVersionError < ArgumentError
10
+ # Initialize a new exception for the given ruby version string.
11
+ #
12
+ # : (String version) -> void
13
+ def initialize: (String version) -> void
14
+ end
15
+
16
+ # :call-seq:
17
+ # lex_compat(source, **options) -> LexCompat::Result
18
+ #
19
+ # Returns a parse result whose value is an array of tokens that closely
20
+ # resembles the return value of Ripper.lex.
21
+ #
22
+ # For supported options, see Prism.parse.
23
+ #
24
+ # : (String source, **untyped options) -> LexCompat::Result
25
+ def self.lex_compat: (String source, **untyped options) -> LexCompat::Result
26
+
27
+ # :call-seq:
28
+ # load(source, serialized, freeze) -> ParseResult
29
+ #
30
+ # Load the serialized AST using the source as a reference into a tree.
31
+ #
32
+ # : (String source, String serialized, ?bool freeze) -> ParseResult
33
+ def self.load: (String source, String serialized, ?bool freeze) -> ParseResult
34
+
35
+ # Given a Method, UnboundMethod, Proc, or Thread::Backtrace::Location,
36
+ # returns the Prism node representing it. On CRuby, this uses node_id for
37
+ # an exact match. On other implementations, it falls back to best-effort
38
+ # matching by source location line number.
39
+ #
40
+ # : (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable) -> Node?
41
+ def self.find: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable) -> Node?
42
+
43
+ VERSION: String
44
+
45
+ BACKEND: :CEXT | :FFI
46
+
47
+ interface _Stream
48
+ def gets: (?Integer integer) -> (String | nil)
49
+ end
50
+
51
+ def self.parse: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
52
+
53
+ def self.profile: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> void
54
+
55
+ def self.lex: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult
56
+
57
+ def self.parse_lex: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult
58
+
59
+ def self.dump: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> String
60
+
61
+ def self.parse_comments: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment]
62
+
63
+ def self.parse_success?: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
64
+
65
+ def self.parse_failure?: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
66
+
67
+ def self.parse_stream: (_Stream stream, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
68
+
69
+ def self.parse_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult
70
+
71
+ def self.profile_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> void
72
+
73
+ def self.lex_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult
74
+
75
+ def self.parse_lex_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult
76
+
77
+ def self.dump_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> String
78
+
79
+ def self.parse_file_comments: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment]
80
+
81
+ def self.parse_file_success?: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
82
+
83
+ def self.parse_file_failure?: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool
84
+ end
data/sig/manifest.yaml ADDED
@@ -0,0 +1,2 @@
1
+ dependencies:
2
+ - name: pp
data/src/arena.c ADDED
@@ -0,0 +1,117 @@
1
+ #include "prism/internal/arena.h"
2
+
3
+ #include "prism/internal/allocator.h"
4
+
5
+ #include <assert.h>
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+
9
+ /**
10
+ * Compute the block allocation size using offsetof so it is correct regardless
11
+ * of PM_FLEX_ARRAY_LENGTH.
12
+ */
13
+ #define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size))
14
+
15
+ /** Initial block data size: 8 KB. */
16
+ #define PM_ARENA_INITIAL_SIZE 8192
17
+
18
+ /** Double the block size every this many blocks. */
19
+ #define PM_ARENA_GROWTH_INTERVAL 8
20
+
21
+ /** Maximum block data size: 1 MB. */
22
+ #define PM_ARENA_MAX_SIZE (1024 * 1024)
23
+
24
+ /**
25
+ * Compute the data size for the next block.
26
+ */
27
+ static size_t
28
+ pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
29
+ size_t size = PM_ARENA_INITIAL_SIZE;
30
+
31
+ for (size_t exp = PM_ARENA_GROWTH_INTERVAL; exp <= arena->block_count; exp += PM_ARENA_GROWTH_INTERVAL) {
32
+ if (size < PM_ARENA_MAX_SIZE) size *= 2;
33
+ }
34
+
35
+ return size > min_size ? size : min_size;
36
+ }
37
+
38
+ /**
39
+ * Allocate a new block with the given data capacity and initial usage, link it
40
+ * into the arena, and return it. Aborts on allocation failure.
41
+ */
42
+ static pm_arena_block_t *
43
+ pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) {
44
+ assert(initial_used <= data_size);
45
+ pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size));
46
+
47
+ if (block == NULL) {
48
+ fprintf(stderr, "prism: out of memory; aborting\n");
49
+ abort();
50
+ }
51
+
52
+ block->capacity = data_size;
53
+ block->used = initial_used;
54
+ block->prev = arena->current;
55
+ arena->current = block;
56
+ arena->block_count++;
57
+
58
+ return block;
59
+ }
60
+
61
+ /**
62
+ * Ensure the arena has at least `capacity` bytes available in its current
63
+ * block, allocating a new block if necessary. This allows callers to
64
+ * pre-size the arena to avoid repeated small block allocations.
65
+ */
66
+ void
67
+ pm_arena_reserve(pm_arena_t *arena, size_t capacity) {
68
+ if (capacity <= PM_ARENA_INITIAL_SIZE) return;
69
+ if (arena->current != NULL && (arena->current->capacity - arena->current->used) >= capacity) return;
70
+ pm_arena_block_new(arena, capacity, 0);
71
+ }
72
+
73
+ /**
74
+ * Slow path for pm_arena_alloc: allocate a new block and return a pointer to
75
+ * the first `size` bytes. Called when the current block has insufficient space.
76
+ */
77
+ void *
78
+ pm_arena_alloc_slow(pm_arena_t *arena, size_t size) {
79
+ size_t block_data_size = pm_arena_next_block_size(arena, size);
80
+ pm_arena_block_t *block = pm_arena_block_new(arena, block_data_size, size);
81
+ return block->data;
82
+ }
83
+
84
+ /**
85
+ * Returns a newly allocated and initialized arena.
86
+ */
87
+ pm_arena_t *
88
+ pm_arena_new(void) {
89
+ pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t));
90
+ if (arena == NULL) abort();
91
+ return arena;
92
+ }
93
+
94
+ /**
95
+ * Free all blocks in the arena.
96
+ */
97
+ void
98
+ pm_arena_cleanup(pm_arena_t *arena) {
99
+ pm_arena_block_t *block = arena->current;
100
+
101
+ while (block != NULL) {
102
+ pm_arena_block_t *prev = block->prev;
103
+ xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity));
104
+ block = prev;
105
+ }
106
+
107
+ *arena = (pm_arena_t) { 0 };
108
+ }
109
+
110
+ /**
111
+ * Frees both the held memory and the arena itself.
112
+ */
113
+ void
114
+ pm_arena_free(pm_arena_t *arena) {
115
+ pm_arena_cleanup(arena);
116
+ xfree_sized(arena, sizeof(pm_arena_t));
117
+ }
@@ -1,31 +1,38 @@
1
- #include "prism/util/pm_buffer.h"
1
+ #include "prism/internal/buffer.h"
2
2
 
3
- /**
4
- * Return the size of the pm_buffer_t struct.
5
- */
6
- size_t
7
- pm_buffer_sizeof(void) {
8
- return sizeof(pm_buffer_t);
9
- }
3
+ #include "prism/compiler/inline.h"
4
+
5
+ #include "prism/internal/char.h"
6
+ #include "prism/internal/allocator.h"
7
+
8
+ #include <assert.h>
9
+ #include <stdarg.h>
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
10
13
 
11
14
  /**
12
15
  * Initialize a pm_buffer_t with the given capacity.
13
16
  */
14
- bool
15
- pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity) {
17
+ void
18
+ pm_buffer_init(pm_buffer_t *buffer, size_t capacity) {
16
19
  buffer->length = 0;
17
20
  buffer->capacity = capacity;
18
21
 
19
22
  buffer->value = (char *) xmalloc(capacity);
20
- return buffer->value != NULL;
23
+ if (buffer->value == NULL) abort();
21
24
  }
22
25
 
23
26
  /**
24
- * Initialize a pm_buffer_t with its default values.
27
+ * Allocate and initialize a new buffer.
25
28
  */
26
- bool
27
- pm_buffer_init(pm_buffer_t *buffer) {
28
- return pm_buffer_init_capacity(buffer, 1024);
29
+ pm_buffer_t *
30
+ pm_buffer_new(void) {
31
+ pm_buffer_t *buffer = (pm_buffer_t *) xmalloc(sizeof(pm_buffer_t));
32
+ if (buffer == NULL) abort();
33
+
34
+ pm_buffer_init(buffer, 1024);
35
+ return buffer;
29
36
  }
30
37
 
31
38
  /**
@@ -45,11 +52,18 @@ pm_buffer_length(const pm_buffer_t *buffer) {
45
52
  }
46
53
 
47
54
  /**
48
- * Append the given amount of space to the buffer.
55
+ * Append the given amount of space to the buffer. Returns false when there is
56
+ * nothing to write: either the allocation failed or the length is zero. A
57
+ * zero-initialized buffer has a NULL value until its first allocation, and
58
+ * passing NULL to memcpy/memset/memmove is undefined behavior even for zero
59
+ * bytes, so callers must not write in the zero case.
49
60
  */
50
- static inline bool
61
+ static PRISM_INLINE bool
51
62
  pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
63
+ if (length == 0) return false;
64
+
52
65
  size_t next_length = buffer->length + length;
66
+ const size_t original_capacity = buffer->capacity;
53
67
 
54
68
  if (next_length > buffer->capacity) {
55
69
  if (buffer->capacity == 0) {
@@ -60,7 +74,7 @@ pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
60
74
  buffer->capacity *= 2;
61
75
  }
62
76
 
63
- buffer->value = xrealloc(buffer->value, buffer->capacity);
77
+ buffer->value = xrealloc_sized(buffer->value, buffer->capacity, original_capacity);
64
78
  if (buffer->value == NULL) return false;
65
79
  }
66
80
 
@@ -71,7 +85,7 @@ pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
71
85
  /**
72
86
  * Append a generic pointer to memory to the buffer.
73
87
  */
74
- static inline void
88
+ static PRISM_INLINE void
75
89
  pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) {
76
90
  size_t cursor = buffer->length;
77
91
  if (pm_buffer_append_length(buffer, length)) {
@@ -172,6 +186,15 @@ pm_buffer_append_double(pm_buffer_t *buffer, double value) {
172
186
  pm_buffer_append(buffer, source, sizeof(double));
173
187
  }
174
188
 
189
+ /**
190
+ * Append a 64-bit unsigned integer to the buffer in native endian order.
191
+ */
192
+ void
193
+ pm_buffer_append_uint64(pm_buffer_t *buffer, uint64_t value) {
194
+ const void *source = &value;
195
+ pm_buffer_append(buffer, source, sizeof(uint64_t));
196
+ }
197
+
175
198
  /**
176
199
  * Append a unicode codepoint to the buffer.
177
200
  */
@@ -349,9 +372,18 @@ pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t le
349
372
  }
350
373
 
351
374
  /**
352
- * Free the memory associated with the buffer.
375
+ * Free the memory held by the buffer.
376
+ */
377
+ void
378
+ pm_buffer_cleanup(pm_buffer_t *buffer) {
379
+ xfree_sized(buffer->value, buffer->capacity);
380
+ }
381
+
382
+ /**
383
+ * Free both the memory held by the buffer and the buffer itself.
353
384
  */
354
385
  void
355
386
  pm_buffer_free(pm_buffer_t *buffer) {
356
- xfree(buffer->value);
387
+ pm_buffer_cleanup(buffer);
388
+ xfree_sized(buffer, sizeof(pm_buffer_t));
357
389
  }
@@ -1,7 +1,8 @@
1
- #include "prism/util/pm_char.h"
1
+ #include "prism/internal/char.h"
2
+
3
+ #include "prism/compiler/inline.h"
4
+ #include "prism/internal/line_offset_list.h"
2
5
 
3
- #define PRISM_CHAR_BIT_WHITESPACE (1 << 0)
4
- #define PRISM_CHAR_BIT_INLINE_WHITESPACE (1 << 1)
5
6
  #define PRISM_CHAR_BIT_REGEXP_OPTION (1 << 2)
6
7
 
7
8
  #define PRISM_NUMBER_BIT_BINARY_DIGIT (1 << 0)
@@ -13,7 +14,7 @@
13
14
  #define PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT (1 << 6)
14
15
  #define PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER (1 << 7)
15
16
 
16
- static const uint8_t pm_byte_table[256] = {
17
+ const uint8_t pm_byte_table[256] = {
17
18
  // 0 1 2 3 4 5 6 7 8 9 A B C D E F
18
19
  0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, 0, 0, // 0x
19
20
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
@@ -57,7 +58,7 @@ static const uint8_t pm_number_table[256] = {
57
58
  * Returns the number of characters at the start of the string that match the
58
59
  * given kind. Disallows searching past the given maximum number of characters.
59
60
  */
60
- static inline size_t
61
+ static PRISM_INLINE size_t
61
62
  pm_strspn_char_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
62
63
  if (length <= 0) return 0;
63
64
 
@@ -77,21 +78,36 @@ pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length) {
77
78
  return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_WHITESPACE);
78
79
  }
79
80
 
81
+ /**
82
+ * Returns the number of characters at the end of the string that are
83
+ * whitespace. Disallows searching past the given maximum number of characters.
84
+ */
85
+ size_t
86
+ pm_strrspn_whitespace(const uint8_t *string, ptrdiff_t length) {
87
+ if (length <= 0) return 0;
88
+
89
+ size_t size = 0;
90
+ size_t maximum = (size_t) length;
91
+
92
+ while (size < maximum && (pm_byte_table[string[maximum - size - 1]] & PRISM_CHAR_BIT_WHITESPACE)) size++;
93
+ return size;
94
+ }
95
+
80
96
  /**
81
97
  * Returns the number of characters at the start of the string that are
82
98
  * whitespace while also tracking the location of each newline. Disallows
83
99
  * searching past the given maximum number of characters.
84
100
  */
85
101
  size_t
86
- pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list) {
102
+ pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_arena_t *arena, pm_line_offset_list_t *line_offsets, uint32_t start_offset) {
87
103
  if (length <= 0) return 0;
88
104
 
89
- size_t size = 0;
90
- size_t maximum = (size_t) length;
105
+ uint32_t size = 0;
106
+ uint32_t maximum = (uint32_t) length;
91
107
 
92
108
  while (size < maximum && (pm_byte_table[string[size]] & PRISM_CHAR_BIT_WHITESPACE)) {
93
109
  if (string[size] == '\n') {
94
- pm_newline_list_append(newline_list, string + size);
110
+ pm_line_offset_list_append(arena, line_offsets, start_offset + size + 1);
95
111
  }
96
112
 
97
113
  size++;
@@ -100,15 +116,6 @@ pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newlin
100
116
  return size;
101
117
  }
102
118
 
103
- /**
104
- * Returns the number of characters at the start of the string that are inline
105
- * whitespace. Disallows searching past the given maximum number of characters.
106
- */
107
- size_t
108
- pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) {
109
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_INLINE_WHITESPACE);
110
- }
111
-
112
119
  /**
113
120
  * Returns the number of characters at the start of the string that are regexp
114
121
  * options. Disallows searching past the given maximum number of characters.
@@ -118,36 +125,13 @@ pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length) {
118
125
  return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_REGEXP_OPTION);
119
126
  }
120
127
 
121
- /**
122
- * Returns true if the given character matches the given kind.
123
- */
124
- static inline bool
125
- pm_char_is_char_kind(const uint8_t b, uint8_t kind) {
126
- return (pm_byte_table[b] & kind) != 0;
127
- }
128
-
129
- /**
130
- * Returns true if the given character is a whitespace character.
131
- */
132
- bool
133
- pm_char_is_whitespace(const uint8_t b) {
134
- return pm_char_is_char_kind(b, PRISM_CHAR_BIT_WHITESPACE);
135
- }
136
-
137
- /**
138
- * Returns true if the given character is an inline whitespace character.
139
- */
140
- bool
141
- pm_char_is_inline_whitespace(const uint8_t b) {
142
- return pm_char_is_char_kind(b, PRISM_CHAR_BIT_INLINE_WHITESPACE);
143
- }
144
128
 
145
129
  /**
146
130
  * Scan through the string and return the number of characters at the start of
147
131
  * the string that match the given kind. Disallows searching past the given
148
132
  * maximum number of characters.
149
133
  */
150
- static inline size_t
134
+ static PRISM_INLINE size_t
151
135
  pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
152
136
  if (length <= 0) return 0;
153
137
 
@@ -166,7 +150,7 @@ pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
166
150
  * Additionally, report the location of the last invalid underscore character
167
151
  * found in the string through the out invalid parameter.
168
152
  */
169
- static inline size_t
153
+ static PRISM_INLINE size_t
170
154
  pm_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) {
171
155
  if (length <= 0) return 0;
172
156
 
@@ -267,7 +251,7 @@ pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint
267
251
  /**
268
252
  * Returns true if the given character matches the given kind.
269
253
  */
270
- static inline bool
254
+ static PRISM_INLINE bool
271
255
  pm_char_is_number_kind(const uint8_t b, uint8_t kind) {
272
256
  return (pm_number_table[b] & kind) != 0;
273
257
  }
@@ -303,16 +287,3 @@ bool
303
287
  pm_char_is_hexadecimal_digit(const uint8_t b) {
304
288
  return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
305
289
  }
306
-
307
- #undef PRISM_CHAR_BIT_WHITESPACE
308
- #undef PRISM_CHAR_BIT_INLINE_WHITESPACE
309
- #undef PRISM_CHAR_BIT_REGEXP_OPTION
310
-
311
- #undef PRISM_NUMBER_BIT_BINARY_DIGIT
312
- #undef PRISM_NUMBER_BIT_BINARY_NUMBER
313
- #undef PRISM_NUMBER_BIT_OCTAL_DIGIT
314
- #undef PRISM_NUMBER_BIT_OCTAL_NUMBER
315
- #undef PRISM_NUMBER_BIT_DECIMAL_DIGIT
316
- #undef PRISM_NUMBER_BIT_DECIMAL_NUMBER
317
- #undef PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER
318
- #undef PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT