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.
- checksums.yaml +7 -0
- data/BSDmakefile +58 -0
- data/CHANGELOG.md +870 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/CONTRIBUTING.md +58 -0
- data/LICENSE.md +7 -0
- data/Makefile +145 -0
- data/README.md +81 -0
- data/config.yml +4752 -0
- data/docs/build_system.md +119 -0
- data/docs/configuration.md +69 -0
- data/docs/cruby_compilation.md +27 -0
- data/docs/design.md +53 -0
- data/docs/encoding.md +121 -0
- data/docs/fuzzing.md +81 -0
- data/docs/heredocs.md +36 -0
- data/docs/javascript.md +133 -0
- data/docs/local_variable_depth.md +229 -0
- data/docs/mapping.md +117 -0
- data/docs/parser_translation.md +24 -0
- data/docs/parsing_rules.md +22 -0
- data/docs/releasing.md +147 -0
- data/docs/relocation.md +32 -0
- data/docs/ripper_translation.md +63 -0
- data/docs/ruby_api.md +45 -0
- data/docs/ruby_parser_translation.md +19 -0
- data/docs/serialization.md +230 -0
- data/docs/testing.md +72 -0
- data/ext/prism/api_node.c +7005 -0
- data/ext/prism/extconf.rb +126 -0
- data/ext/prism/extension.c +1783 -0
- data/ext/prism/extension.h +19 -0
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +10371 -0
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +24 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -0
- data/include/prism/compiler/exported.h +24 -0
- data/include/prism/compiler/fallthrough.h +22 -0
- data/include/prism/compiler/filesystem.h +32 -0
- data/include/prism/compiler/flex_array.h +19 -0
- data/include/prism/compiler/force_inline.h +21 -0
- data/include/prism/compiler/format.h +25 -0
- data/include/prism/compiler/inline.h +17 -0
- data/include/prism/compiler/nodiscard.h +22 -0
- data/include/prism/compiler/nonnull.h +18 -0
- data/include/prism/compiler/unused.h +18 -0
- data/include/prism/constant_pool.h +81 -0
- data/include/prism/diagnostic.h +93 -0
- data/include/prism/errors_format.h +53 -0
- data/include/prism/excludes.h +29 -0
- data/include/prism/integer.h +41 -0
- data/include/prism/internal/allocator.h +68 -0
- data/include/prism/internal/allocator_debug.h +88 -0
- data/include/prism/internal/arena.h +108 -0
- data/include/prism/internal/bit.h +42 -0
- data/include/prism/internal/buffer.h +91 -0
- data/include/prism/internal/char.h +145 -0
- data/include/prism/internal/comments.h +53 -0
- data/include/prism/internal/constant_pool.h +152 -0
- data/include/prism/internal/diagnostic.h +389 -0
- data/include/prism/internal/encoding.h +242 -0
- data/include/prism/internal/integer.h +68 -0
- data/include/prism/internal/isinf.h +16 -0
- data/include/prism/internal/line_offset_list.h +34 -0
- data/include/prism/internal/list.h +62 -0
- data/include/prism/internal/magic_comments.h +23 -0
- data/include/prism/internal/memchr.h +15 -0
- data/include/prism/internal/node.h +38 -0
- data/include/prism/internal/options.h +232 -0
- data/include/prism/internal/parser.h +984 -0
- data/include/prism/internal/regexp.h +26 -0
- data/include/prism/internal/serialize.h +39 -0
- data/include/prism/internal/source.h +72 -0
- data/include/prism/internal/static_literals.h +100 -0
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/internal/strncasecmp.h +18 -0
- data/include/prism/internal/strpbrk.h +33 -0
- data/include/prism/internal/tokens.h +11 -0
- data/include/prism/json.h +32 -0
- data/include/prism/line_offset_list.h +61 -0
- data/include/prism/magic_comments.h +35 -0
- data/include/prism/node.h +94 -0
- data/include/prism/options.h +354 -0
- data/include/prism/parser.h +404 -0
- data/include/prism/prettyprint.h +31 -0
- data/include/prism/serialize.h +115 -0
- data/include/prism/source.h +155 -0
- data/include/prism/stream.h +28 -0
- data/include/prism/string_query.h +63 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +38 -0
- data/include/prism.h +131 -0
- data/lib/prism/3.3/prism.bundle +0 -0
- data/lib/prism/3.4/prism.bundle +0 -0
- data/lib/prism/4.0/prism.bundle +0 -0
- data/lib/prism/compiler.rb +815 -0
- data/lib/prism/desugar_compiler.rb +463 -0
- data/lib/prism/dispatcher.rb +2383 -0
- data/lib/prism/dot_visitor.rb +4848 -0
- data/lib/prism/dsl.rb +1369 -0
- data/lib/prism/ffi.rb +740 -0
- data/lib/prism/inspect_visitor.rb +2425 -0
- data/lib/prism/lex_compat.rb +953 -0
- data/lib/prism/mutation_compiler.rb +780 -0
- data/lib/prism/node.rb +33204 -0
- data/lib/prism/node_ext.rb +504 -0
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +72 -0
- data/lib/prism/parse_result/newlines.rb +423 -0
- data/lib/prism/parse_result.rb +1221 -0
- data/lib/prism/pattern.rb +314 -0
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/byteindex.rb +13 -0
- data/lib/prism/polyfill/scan_byte.rb +14 -0
- data/lib/prism/polyfill/unpack1.rb +14 -0
- data/lib/prism/polyfill/warn.rb +36 -0
- data/lib/prism/reflection.rb +427 -0
- data/lib/prism/relocation.rb +567 -0
- data/lib/prism/serialize.rb +5308 -0
- data/lib/prism/string_query.rb +46 -0
- data/lib/prism/translation/parser/builder.rb +70 -0
- data/lib/prism/translation/parser/compiler.rb +2226 -0
- data/lib/prism/translation/parser/lexer.rb +769 -0
- data/lib/prism/translation/parser.rb +376 -0
- data/lib/prism/translation/parser_current.rb +26 -0
- data/lib/prism/translation/parser_versions.rb +36 -0
- data/lib/prism/translation/ripper/filter.rb +53 -0
- data/lib/prism/translation/ripper/lexer.rb +133 -0
- data/lib/prism/translation/ripper/sexp.rb +118 -0
- data/lib/prism/translation/ripper/shim.rb +7 -0
- data/lib/prism/translation/ripper.rb +4278 -0
- data/lib/prism/translation/ruby_parser.rb +1721 -0
- data/lib/prism/translation.rb +20 -0
- data/lib/prism/visitor.rb +1440 -0
- data/lib/prism.rb +168 -0
- data/prism.gemspec +234 -0
- data/rbi/generated/prism/compiler.rbi +489 -0
- data/rbi/generated/prism/desugar_compiler.rbi +306 -0
- data/rbi/generated/prism/dispatcher.rbi +1138 -0
- data/rbi/generated/prism/dot_visitor.rbi +618 -0
- data/rbi/generated/prism/dsl.rbi +751 -0
- data/rbi/generated/prism/inspect_visitor.rbi +503 -0
- data/rbi/generated/prism/lex_compat.rbi +162 -0
- data/rbi/generated/prism/mutation_compiler.rbi +464 -0
- data/rbi/generated/prism/node.rbi +13681 -0
- data/rbi/generated/prism/node_ext.rbi +259 -0
- data/rbi/generated/prism/node_find.rbi +79 -0
- data/rbi/generated/prism/parse_result/errors.rbi +21 -0
- data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
- data/rbi/generated/prism/parse_result.rbi +764 -0
- data/rbi/generated/prism/pattern.rbi +134 -0
- data/rbi/generated/prism/reflection.rbi +89 -0
- data/rbi/generated/prism/relocation.rbi +329 -0
- data/rbi/generated/prism/serialize.rbi +181 -0
- data/rbi/generated/prism/string_query.rbi +36 -0
- data/rbi/generated/prism/translation.rbi +7 -0
- data/rbi/generated/prism/visitor.rbi +650 -0
- data/rbi/generated/prism.rbi +86 -0
- data/rbi/prism/translation/parser.rbi +11 -0
- data/rbi/prism/translation/parser_versions.rbi +28 -0
- data/rbi/prism/translation/ripper.rbi +15 -0
- data/rbi/rubyvm/node_find.rbi +14 -0
- data/sig/generated/prism/compiler.rbs +492 -0
- data/sig/generated/prism/desugar_compiler.rbs +305 -0
- data/sig/generated/prism/dispatcher.rbs +1292 -0
- data/sig/generated/prism/dot_visitor.rbs +635 -0
- data/sig/generated/prism/dsl.rbs +928 -0
- data/sig/generated/prism/inspect_visitor.rbs +509 -0
- data/sig/generated/prism/lex_compat.rbs +166 -0
- data/sig/generated/prism/mutation_compiler.rbs +464 -0
- data/sig/generated/prism/node.rbs +20160 -0
- data/sig/generated/prism/node_ext.rbs +290 -0
- data/sig/generated/prism/node_find.rbs +90 -0
- data/sig/generated/prism/parse_result/errors.rbs +22 -0
- data/sig/generated/prism/parse_result/newlines.rbs +223 -0
- data/sig/generated/prism/parse_result.rbs +859 -0
- data/sig/generated/prism/pattern.rbs +156 -0
- data/sig/generated/prism/reflection.rbs +101 -0
- data/sig/generated/prism/relocation.rbs +428 -0
- data/sig/generated/prism/serialize.rbs +195 -0
- data/sig/generated/prism/string_query.rbs +36 -0
- data/sig/generated/prism/translation.rbs +8 -0
- data/sig/generated/prism/visitor.rbs +1111 -0
- data/sig/generated/prism.rbs +84 -0
- data/sig/manifest.yaml +2 -0
- data/src/arena.c +117 -0
- data/src/buffer.c +380 -0
- data/src/char.c +289 -0
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +886 -0
- data/src/encoding.c +5345 -0
- data/src/errors_format.c +519 -0
- data/src/integer.c +681 -0
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/memchr.c +37 -0
- data/src/node.c +4515 -0
- data/src/options.c +451 -0
- data/src/parser.c +349 -0
- data/src/prettyprint.c +9024 -0
- data/src/prism.c +23739 -0
- data/src/regexp.c +1706 -0
- data/src/serialize.c +2309 -0
- data/src/source.c +518 -0
- data/src/static_literals.c +685 -0
- data/src/string_query.c +166 -0
- data/src/stringy.c +91 -0
- data/src/strncasecmp.c +37 -0
- data/src/strpbrk.c +447 -0
- data/src/tokens.c +724 -0
- 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
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
|
+
}
|