prism 2.0.0.rc1-arm64-darwin

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 (216) hide show
  1. checksums.yaml +7 -0
  2. data/BSDmakefile +58 -0
  3. data/CHANGELOG.md +870 -0
  4. data/CODE_OF_CONDUCT.md +76 -0
  5. data/CONTRIBUTING.md +58 -0
  6. data/LICENSE.md +7 -0
  7. data/Makefile +145 -0
  8. data/README.md +81 -0
  9. data/config.yml +4752 -0
  10. data/docs/build_system.md +119 -0
  11. data/docs/configuration.md +69 -0
  12. data/docs/cruby_compilation.md +27 -0
  13. data/docs/design.md +53 -0
  14. data/docs/encoding.md +121 -0
  15. data/docs/fuzzing.md +81 -0
  16. data/docs/heredocs.md +36 -0
  17. data/docs/javascript.md +133 -0
  18. data/docs/local_variable_depth.md +229 -0
  19. data/docs/mapping.md +117 -0
  20. data/docs/parser_translation.md +24 -0
  21. data/docs/parsing_rules.md +22 -0
  22. data/docs/releasing.md +147 -0
  23. data/docs/relocation.md +32 -0
  24. data/docs/ripper_translation.md +63 -0
  25. data/docs/ruby_api.md +45 -0
  26. data/docs/ruby_parser_translation.md +19 -0
  27. data/docs/serialization.md +230 -0
  28. data/docs/testing.md +72 -0
  29. data/ext/prism/api_node.c +7005 -0
  30. data/ext/prism/extconf.rb +126 -0
  31. data/ext/prism/extension.c +1783 -0
  32. data/ext/prism/extension.h +19 -0
  33. data/include/prism/arena.h +37 -0
  34. data/include/prism/ast.h +10371 -0
  35. data/include/prism/buffer.h +52 -0
  36. data/include/prism/comments.h +55 -0
  37. data/include/prism/compiler/accel.h +24 -0
  38. data/include/prism/compiler/align.h +36 -0
  39. data/include/prism/compiler/assume.h +25 -0
  40. data/include/prism/compiler/exported.h +24 -0
  41. data/include/prism/compiler/fallthrough.h +22 -0
  42. data/include/prism/compiler/filesystem.h +32 -0
  43. data/include/prism/compiler/flex_array.h +19 -0
  44. data/include/prism/compiler/force_inline.h +21 -0
  45. data/include/prism/compiler/format.h +25 -0
  46. data/include/prism/compiler/inline.h +17 -0
  47. data/include/prism/compiler/nodiscard.h +22 -0
  48. data/include/prism/compiler/nonnull.h +18 -0
  49. data/include/prism/compiler/unused.h +18 -0
  50. data/include/prism/constant_pool.h +81 -0
  51. data/include/prism/diagnostic.h +93 -0
  52. data/include/prism/errors_format.h +53 -0
  53. data/include/prism/excludes.h +29 -0
  54. data/include/prism/integer.h +41 -0
  55. data/include/prism/internal/allocator.h +68 -0
  56. data/include/prism/internal/allocator_debug.h +88 -0
  57. data/include/prism/internal/arena.h +108 -0
  58. data/include/prism/internal/bit.h +42 -0
  59. data/include/prism/internal/buffer.h +91 -0
  60. data/include/prism/internal/char.h +145 -0
  61. data/include/prism/internal/comments.h +53 -0
  62. data/include/prism/internal/constant_pool.h +152 -0
  63. data/include/prism/internal/diagnostic.h +389 -0
  64. data/include/prism/internal/encoding.h +242 -0
  65. data/include/prism/internal/integer.h +68 -0
  66. data/include/prism/internal/isinf.h +16 -0
  67. data/include/prism/internal/line_offset_list.h +34 -0
  68. data/include/prism/internal/list.h +62 -0
  69. data/include/prism/internal/magic_comments.h +23 -0
  70. data/include/prism/internal/memchr.h +15 -0
  71. data/include/prism/internal/node.h +38 -0
  72. data/include/prism/internal/options.h +232 -0
  73. data/include/prism/internal/parser.h +984 -0
  74. data/include/prism/internal/regexp.h +26 -0
  75. data/include/prism/internal/serialize.h +39 -0
  76. data/include/prism/internal/source.h +72 -0
  77. data/include/prism/internal/static_literals.h +100 -0
  78. data/include/prism/internal/stringy.h +35 -0
  79. data/include/prism/internal/strncasecmp.h +18 -0
  80. data/include/prism/internal/strpbrk.h +33 -0
  81. data/include/prism/internal/tokens.h +11 -0
  82. data/include/prism/json.h +32 -0
  83. data/include/prism/line_offset_list.h +61 -0
  84. data/include/prism/magic_comments.h +35 -0
  85. data/include/prism/node.h +94 -0
  86. data/include/prism/options.h +354 -0
  87. data/include/prism/parser.h +404 -0
  88. data/include/prism/prettyprint.h +31 -0
  89. data/include/prism/serialize.h +115 -0
  90. data/include/prism/source.h +155 -0
  91. data/include/prism/stream.h +28 -0
  92. data/include/prism/string_query.h +63 -0
  93. data/include/prism/stringy.h +72 -0
  94. data/include/prism/version.h +38 -0
  95. data/include/prism.h +131 -0
  96. data/lib/prism/3.3/prism.bundle +0 -0
  97. data/lib/prism/3.4/prism.bundle +0 -0
  98. data/lib/prism/4.0/prism.bundle +0 -0
  99. data/lib/prism/compiler.rb +815 -0
  100. data/lib/prism/desugar_compiler.rb +463 -0
  101. data/lib/prism/dispatcher.rb +2383 -0
  102. data/lib/prism/dot_visitor.rb +4848 -0
  103. data/lib/prism/dsl.rb +1369 -0
  104. data/lib/prism/ffi.rb +740 -0
  105. data/lib/prism/inspect_visitor.rb +2425 -0
  106. data/lib/prism/lex_compat.rb +953 -0
  107. data/lib/prism/mutation_compiler.rb +780 -0
  108. data/lib/prism/node.rb +33204 -0
  109. data/lib/prism/node_ext.rb +504 -0
  110. data/lib/prism/node_find.rb +215 -0
  111. data/lib/prism/parse_result/errors.rb +72 -0
  112. data/lib/prism/parse_result/newlines.rb +423 -0
  113. data/lib/prism/parse_result.rb +1221 -0
  114. data/lib/prism/pattern.rb +314 -0
  115. data/lib/prism/polyfill/append_as_bytes.rb +15 -0
  116. data/lib/prism/polyfill/byteindex.rb +13 -0
  117. data/lib/prism/polyfill/scan_byte.rb +14 -0
  118. data/lib/prism/polyfill/unpack1.rb +14 -0
  119. data/lib/prism/polyfill/warn.rb +36 -0
  120. data/lib/prism/reflection.rb +427 -0
  121. data/lib/prism/relocation.rb +567 -0
  122. data/lib/prism/serialize.rb +5308 -0
  123. data/lib/prism/string_query.rb +46 -0
  124. data/lib/prism/translation/parser/builder.rb +70 -0
  125. data/lib/prism/translation/parser/compiler.rb +2226 -0
  126. data/lib/prism/translation/parser/lexer.rb +769 -0
  127. data/lib/prism/translation/parser.rb +376 -0
  128. data/lib/prism/translation/parser_current.rb +26 -0
  129. data/lib/prism/translation/parser_versions.rb +36 -0
  130. data/lib/prism/translation/ripper/filter.rb +53 -0
  131. data/lib/prism/translation/ripper/lexer.rb +133 -0
  132. data/lib/prism/translation/ripper/sexp.rb +118 -0
  133. data/lib/prism/translation/ripper/shim.rb +7 -0
  134. data/lib/prism/translation/ripper.rb +4278 -0
  135. data/lib/prism/translation/ruby_parser.rb +1721 -0
  136. data/lib/prism/translation.rb +20 -0
  137. data/lib/prism/visitor.rb +1440 -0
  138. data/lib/prism.rb +168 -0
  139. data/prism.gemspec +234 -0
  140. data/rbi/generated/prism/compiler.rbi +489 -0
  141. data/rbi/generated/prism/desugar_compiler.rbi +306 -0
  142. data/rbi/generated/prism/dispatcher.rbi +1138 -0
  143. data/rbi/generated/prism/dot_visitor.rbi +618 -0
  144. data/rbi/generated/prism/dsl.rbi +751 -0
  145. data/rbi/generated/prism/inspect_visitor.rbi +503 -0
  146. data/rbi/generated/prism/lex_compat.rbi +162 -0
  147. data/rbi/generated/prism/mutation_compiler.rbi +464 -0
  148. data/rbi/generated/prism/node.rbi +13681 -0
  149. data/rbi/generated/prism/node_ext.rbi +259 -0
  150. data/rbi/generated/prism/node_find.rbi +79 -0
  151. data/rbi/generated/prism/parse_result/errors.rbi +21 -0
  152. data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
  153. data/rbi/generated/prism/parse_result.rbi +764 -0
  154. data/rbi/generated/prism/pattern.rbi +134 -0
  155. data/rbi/generated/prism/reflection.rbi +89 -0
  156. data/rbi/generated/prism/relocation.rbi +329 -0
  157. data/rbi/generated/prism/serialize.rbi +181 -0
  158. data/rbi/generated/prism/string_query.rbi +36 -0
  159. data/rbi/generated/prism/translation.rbi +7 -0
  160. data/rbi/generated/prism/visitor.rbi +650 -0
  161. data/rbi/generated/prism.rbi +86 -0
  162. data/rbi/prism/translation/parser.rbi +11 -0
  163. data/rbi/prism/translation/parser_versions.rbi +28 -0
  164. data/rbi/prism/translation/ripper.rbi +15 -0
  165. data/rbi/rubyvm/node_find.rbi +14 -0
  166. data/sig/generated/prism/compiler.rbs +492 -0
  167. data/sig/generated/prism/desugar_compiler.rbs +305 -0
  168. data/sig/generated/prism/dispatcher.rbs +1292 -0
  169. data/sig/generated/prism/dot_visitor.rbs +635 -0
  170. data/sig/generated/prism/dsl.rbs +928 -0
  171. data/sig/generated/prism/inspect_visitor.rbs +509 -0
  172. data/sig/generated/prism/lex_compat.rbs +166 -0
  173. data/sig/generated/prism/mutation_compiler.rbs +464 -0
  174. data/sig/generated/prism/node.rbs +20160 -0
  175. data/sig/generated/prism/node_ext.rbs +290 -0
  176. data/sig/generated/prism/node_find.rbs +90 -0
  177. data/sig/generated/prism/parse_result/errors.rbs +22 -0
  178. data/sig/generated/prism/parse_result/newlines.rbs +223 -0
  179. data/sig/generated/prism/parse_result.rbs +859 -0
  180. data/sig/generated/prism/pattern.rbs +156 -0
  181. data/sig/generated/prism/reflection.rbs +101 -0
  182. data/sig/generated/prism/relocation.rbs +428 -0
  183. data/sig/generated/prism/serialize.rbs +195 -0
  184. data/sig/generated/prism/string_query.rbs +36 -0
  185. data/sig/generated/prism/translation.rbs +8 -0
  186. data/sig/generated/prism/visitor.rbs +1111 -0
  187. data/sig/generated/prism.rbs +84 -0
  188. data/sig/manifest.yaml +2 -0
  189. data/src/arena.c +117 -0
  190. data/src/buffer.c +380 -0
  191. data/src/char.c +289 -0
  192. data/src/comments.c +454 -0
  193. data/src/constant_pool.c +406 -0
  194. data/src/diagnostic.c +886 -0
  195. data/src/encoding.c +5345 -0
  196. data/src/errors_format.c +519 -0
  197. data/src/integer.c +681 -0
  198. data/src/json.c +5733 -0
  199. data/src/line_offset_list.c +100 -0
  200. data/src/list.c +24 -0
  201. data/src/memchr.c +37 -0
  202. data/src/node.c +4515 -0
  203. data/src/options.c +451 -0
  204. data/src/parser.c +349 -0
  205. data/src/prettyprint.c +9024 -0
  206. data/src/prism.c +23739 -0
  207. data/src/regexp.c +1706 -0
  208. data/src/serialize.c +2309 -0
  209. data/src/source.c +518 -0
  210. data/src/static_literals.c +685 -0
  211. data/src/string_query.c +166 -0
  212. data/src/stringy.c +91 -0
  213. data/src/strncasecmp.c +37 -0
  214. data/src/strpbrk.c +447 -0
  215. data/src/tokens.c +724 -0
  216. metadata +259 -0
@@ -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
+ }
data/src/buffer.c ADDED
@@ -0,0 +1,380 @@
1
+ #include "prism/internal/buffer.h"
2
+
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>
13
+
14
+ /**
15
+ * Initialize a pm_buffer_t with the given capacity.
16
+ */
17
+ void
18
+ pm_buffer_init(pm_buffer_t *buffer, size_t capacity) {
19
+ buffer->length = 0;
20
+ buffer->capacity = capacity;
21
+
22
+ buffer->value = (char *) xmalloc(capacity);
23
+ if (buffer->value == NULL) abort();
24
+ }
25
+
26
+ /**
27
+ * Allocate and initialize a new buffer.
28
+ */
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;
36
+ }
37
+
38
+ /**
39
+ * Return the value of the buffer.
40
+ */
41
+ char *
42
+ pm_buffer_value(const pm_buffer_t *buffer) {
43
+ return buffer->value;
44
+ }
45
+
46
+ /**
47
+ * Return the length of the buffer.
48
+ */
49
+ size_t
50
+ pm_buffer_length(const pm_buffer_t *buffer) {
51
+ return buffer->length;
52
+ }
53
+
54
+ /**
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.
60
+ */
61
+ static PRISM_INLINE bool
62
+ pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
63
+ if (length == 0) return false;
64
+
65
+ size_t next_length = buffer->length + length;
66
+ const size_t original_capacity = buffer->capacity;
67
+
68
+ if (next_length > buffer->capacity) {
69
+ if (buffer->capacity == 0) {
70
+ buffer->capacity = 1;
71
+ }
72
+
73
+ while (next_length > buffer->capacity) {
74
+ buffer->capacity *= 2;
75
+ }
76
+
77
+ buffer->value = xrealloc_sized(buffer->value, buffer->capacity, original_capacity);
78
+ if (buffer->value == NULL) return false;
79
+ }
80
+
81
+ buffer->length = next_length;
82
+ return true;
83
+ }
84
+
85
+ /**
86
+ * Append a generic pointer to memory to the buffer.
87
+ */
88
+ static PRISM_INLINE void
89
+ pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) {
90
+ size_t cursor = buffer->length;
91
+ if (pm_buffer_append_length(buffer, length)) {
92
+ memcpy(buffer->value + cursor, source, length);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Append the given amount of space as zeroes to the buffer.
98
+ */
99
+ void
100
+ pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length) {
101
+ size_t cursor = buffer->length;
102
+ if (pm_buffer_append_length(buffer, length)) {
103
+ memset(buffer->value + cursor, 0, length);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Append a formatted string to the buffer.
109
+ */
110
+ void
111
+ pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) {
112
+ va_list arguments;
113
+ va_start(arguments, format);
114
+ int result = vsnprintf(NULL, 0, format, arguments);
115
+ va_end(arguments);
116
+
117
+ if (result < 0) return;
118
+ size_t length = (size_t) (result + 1);
119
+
120
+ size_t cursor = buffer->length;
121
+ if (pm_buffer_append_length(buffer, length)) {
122
+ va_start(arguments, format);
123
+ vsnprintf(buffer->value + cursor, length, format, arguments);
124
+ va_end(arguments);
125
+ buffer->length--;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Append a string to the buffer.
131
+ */
132
+ void
133
+ pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length) {
134
+ pm_buffer_append(buffer, value, length);
135
+ }
136
+
137
+ /**
138
+ * Append a list of bytes to the buffer.
139
+ */
140
+ void
141
+ pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length) {
142
+ pm_buffer_append(buffer, (const char *) value, length);
143
+ }
144
+
145
+ /**
146
+ * Append a single byte to the buffer.
147
+ */
148
+ void
149
+ pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value) {
150
+ const void *source = &value;
151
+ pm_buffer_append(buffer, source, sizeof(uint8_t));
152
+ }
153
+
154
+ /**
155
+ * Append a 32-bit unsigned integer to the buffer as a variable-length integer.
156
+ */
157
+ void
158
+ pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value) {
159
+ if (value < 128) {
160
+ pm_buffer_append_byte(buffer, (uint8_t) value);
161
+ } else {
162
+ uint32_t n = value;
163
+ while (n >= 128) {
164
+ pm_buffer_append_byte(buffer, (uint8_t) (n | 128));
165
+ n >>= 7;
166
+ }
167
+ pm_buffer_append_byte(buffer, (uint8_t) n);
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Append a 32-bit signed integer to the buffer as a variable-length integer.
173
+ */
174
+ void
175
+ pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value) {
176
+ uint32_t unsigned_int = ((uint32_t)(value) << 1) ^ ((uint32_t)(value >> 31));
177
+ pm_buffer_append_varuint(buffer, unsigned_int);
178
+ }
179
+
180
+ /**
181
+ * Append a double to the buffer.
182
+ */
183
+ void
184
+ pm_buffer_append_double(pm_buffer_t *buffer, double value) {
185
+ const void *source = &value;
186
+ pm_buffer_append(buffer, source, sizeof(double));
187
+ }
188
+
189
+ /**
190
+ * Append a unicode codepoint to the buffer.
191
+ */
192
+ bool
193
+ pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value) {
194
+ if (value <= 0x7F) {
195
+ pm_buffer_append_byte(buffer, (uint8_t) value); // 0xxxxxxx
196
+ return true;
197
+ } else if (value <= 0x7FF) {
198
+ uint8_t bytes[] = {
199
+ (uint8_t) (0xC0 | ((value >> 6) & 0x3F)), // 110xxxxx
200
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
201
+ };
202
+
203
+ pm_buffer_append_bytes(buffer, bytes, 2);
204
+ return true;
205
+ } else if (value <= 0xFFFF) {
206
+ uint8_t bytes[] = {
207
+ (uint8_t) (0xE0 | ((value >> 12) & 0x3F)), // 1110xxxx
208
+ (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
209
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
210
+ };
211
+
212
+ pm_buffer_append_bytes(buffer, bytes, 3);
213
+ return true;
214
+ } else if (value <= 0x10FFFF) {
215
+ uint8_t bytes[] = {
216
+ (uint8_t) (0xF0 | ((value >> 18) & 0x3F)), // 11110xxx
217
+ (uint8_t) (0x80 | ((value >> 12) & 0x3F)), // 10xxxxxx
218
+ (uint8_t) (0x80 | ((value >> 6) & 0x3F)), // 10xxxxxx
219
+ (uint8_t) (0x80 | (value & 0x3F)) // 10xxxxxx
220
+ };
221
+
222
+ pm_buffer_append_bytes(buffer, bytes, 4);
223
+ return true;
224
+ } else {
225
+ return false;
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Append a slice of source code to the buffer.
231
+ */
232
+ void
233
+ pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
234
+ for (size_t index = 0; index < length; index++) {
235
+ const uint8_t byte = source[index];
236
+
237
+ if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
238
+ if (escaping == PM_BUFFER_ESCAPING_RUBY) {
239
+ pm_buffer_append_format(buffer, "\\x%02X", byte);
240
+ } else {
241
+ pm_buffer_append_format(buffer, "\\u%04X", byte);
242
+ }
243
+ } else {
244
+ switch (byte) {
245
+ case '\a':
246
+ if (escaping == PM_BUFFER_ESCAPING_RUBY) {
247
+ pm_buffer_append_string(buffer, "\\a", 2);
248
+ } else {
249
+ pm_buffer_append_format(buffer, "\\u%04X", byte);
250
+ }
251
+ break;
252
+ case '\b':
253
+ pm_buffer_append_string(buffer, "\\b", 2);
254
+ break;
255
+ case '\t':
256
+ pm_buffer_append_string(buffer, "\\t", 2);
257
+ break;
258
+ case '\n':
259
+ pm_buffer_append_string(buffer, "\\n", 2);
260
+ break;
261
+ case '\v':
262
+ if (escaping == PM_BUFFER_ESCAPING_RUBY) {
263
+ pm_buffer_append_string(buffer, "\\v", 2);
264
+ } else {
265
+ pm_buffer_append_format(buffer, "\\u%04X", byte);
266
+ }
267
+ break;
268
+ case '\f':
269
+ pm_buffer_append_string(buffer, "\\f", 2);
270
+ break;
271
+ case '\r':
272
+ pm_buffer_append_string(buffer, "\\r", 2);
273
+ break;
274
+ case '"':
275
+ pm_buffer_append_string(buffer, "\\\"", 2);
276
+ break;
277
+ case '#': {
278
+ if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
279
+ const uint8_t next_byte = source[index + 1];
280
+ if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
281
+ pm_buffer_append_byte(buffer, '\\');
282
+ }
283
+ }
284
+
285
+ pm_buffer_append_byte(buffer, '#');
286
+ break;
287
+ }
288
+ case '\\':
289
+ pm_buffer_append_string(buffer, "\\\\", 2);
290
+ break;
291
+ default:
292
+ pm_buffer_append_byte(buffer, byte);
293
+ break;
294
+ }
295
+ }
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Prepend the given string to the buffer.
301
+ */
302
+ void
303
+ pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
304
+ size_t cursor = buffer->length;
305
+ if (pm_buffer_append_length(buffer, length)) {
306
+ memmove(buffer->value + length, buffer->value, cursor);
307
+ memcpy(buffer->value, value, length);
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Concatenate one buffer onto another.
313
+ */
314
+ void
315
+ pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source) {
316
+ if (source->length > 0) {
317
+ pm_buffer_append(destination, source->value, source->length);
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Clear the buffer by reducing its size to 0. This does not free the allocated
323
+ * memory, but it does allow the buffer to be reused.
324
+ */
325
+ void
326
+ pm_buffer_clear(pm_buffer_t *buffer) {
327
+ buffer->length = 0;
328
+ }
329
+
330
+ /**
331
+ * Strip the whitespace from the end of the buffer.
332
+ */
333
+ void
334
+ pm_buffer_rstrip(pm_buffer_t *buffer) {
335
+ while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
336
+ buffer->length--;
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Checks if the buffer includes the given value.
342
+ */
343
+ size_t
344
+ pm_buffer_index(const pm_buffer_t *buffer, char value) {
345
+ const char *first = memchr(buffer->value, value, buffer->length);
346
+ return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
347
+ }
348
+
349
+ /**
350
+ * Insert the given string into the buffer at the given index.
351
+ */
352
+ void
353
+ pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
354
+ assert(index <= buffer->length);
355
+
356
+ if (index == buffer->length) {
357
+ pm_buffer_append_string(buffer, value, length);
358
+ } else {
359
+ pm_buffer_append_zeroes(buffer, length);
360
+ memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
361
+ memcpy(buffer->value + index, value, length);
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Free the memory held by the buffer.
367
+ */
368
+ void
369
+ pm_buffer_cleanup(pm_buffer_t *buffer) {
370
+ xfree_sized(buffer->value, buffer->capacity);
371
+ }
372
+
373
+ /**
374
+ * Free both the memory held by the buffer and the buffer itself.
375
+ */
376
+ void
377
+ pm_buffer_free(pm_buffer_t *buffer) {
378
+ pm_buffer_cleanup(buffer);
379
+ xfree_sized(buffer, sizeof(pm_buffer_t));
380
+ }