rbs 4.0.0.dev.4 → 4.1.0.pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.clang-format +1 -0
- data/.github/dependabot.yml +16 -14
- data/.github/workflows/bundle-update.yml +63 -0
- data/.github/workflows/c-check.yml +21 -11
- data/.github/workflows/comments.yml +5 -3
- data/.github/workflows/dependabot.yml +2 -2
- data/.github/workflows/jruby.yml +67 -0
- data/.github/workflows/milestone.yml +83 -0
- data/.github/workflows/ruby.yml +63 -24
- data/.github/workflows/rust.yml +184 -0
- data/.github/workflows/truffleruby.yml +54 -0
- data/.github/workflows/typecheck.yml +5 -2
- data/.github/workflows/wasm.yml +53 -0
- data/.github/workflows/windows.yml +8 -2
- data/.gitignore +11 -0
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +357 -0
- data/README.md +4 -4
- data/Rakefile +365 -33
- data/Steepfile +8 -0
- data/config.yml +450 -24
- data/core/array.rbs +443 -363
- data/core/basic_object.rbs +9 -8
- data/core/binding.rbs +0 -2
- data/core/builtin.rbs +9 -8
- data/core/class.rbs +11 -8
- data/core/comparable.rbs +55 -34
- data/core/complex.rbs +104 -78
- data/core/dir.rbs +61 -49
- data/core/encoding.rbs +12 -15
- data/core/enumerable.rbs +288 -196
- data/core/enumerator/arithmetic_sequence.rbs +70 -0
- data/core/enumerator/product.rbs +5 -5
- data/core/enumerator.rbs +91 -28
- data/core/errno.rbs +11 -2
- data/core/errors.rbs +58 -29
- data/core/exception.rbs +13 -13
- data/core/fiber.rbs +74 -54
- data/core/file.rbs +260 -1151
- data/core/file_constants.rbs +463 -0
- data/core/file_stat.rbs +534 -0
- data/core/file_test.rbs +3 -3
- data/core/float.rbs +257 -92
- data/core/gc.rbs +425 -281
- data/core/hash.rbs +1151 -829
- data/core/integer.rbs +156 -195
- data/core/io/buffer.rbs +53 -42
- data/core/io/wait.rbs +13 -35
- data/core/io.rbs +216 -150
- data/core/kernel.rbs +239 -163
- data/core/marshal.rbs +4 -4
- data/core/match_data.rbs +15 -13
- data/core/math.rbs +107 -66
- data/core/method.rbs +69 -33
- data/core/module.rbs +302 -150
- data/core/nil_class.rbs +7 -6
- data/core/numeric.rbs +77 -63
- data/core/object.rbs +9 -11
- data/core/object_space/weak_key_map.rbs +7 -7
- data/core/object_space.rbs +30 -23
- data/core/pathname.rbs +1322 -0
- data/core/proc.rbs +95 -58
- data/core/process.rbs +222 -202
- data/core/ractor.rbs +371 -515
- data/core/random.rbs +21 -3
- data/core/range.rbs +181 -79
- data/core/rational.rbs +60 -89
- data/core/rbs/ops.rbs +154 -0
- data/core/rbs/unnamed/argf.rbs +63 -56
- data/core/rbs/unnamed/env_class.rbs +19 -14
- data/core/rbs/unnamed/main_class.rbs +123 -0
- data/core/rbs/unnamed/random.rbs +11 -118
- data/core/regexp.rbs +258 -214
- data/core/ruby.rbs +53 -0
- data/core/ruby_vm.rbs +78 -34
- data/core/rubygems/config_file.rbs +5 -5
- data/core/rubygems/errors.rbs +4 -71
- data/core/rubygems/requirement.rbs +5 -5
- data/core/rubygems/rubygems.rbs +16 -82
- data/core/rubygems/version.rbs +2 -3
- data/core/set.rbs +493 -363
- data/core/signal.rbs +26 -16
- data/core/string.rbs +3234 -1285
- data/core/struct.rbs +43 -42
- data/core/symbol.rbs +41 -34
- data/core/thread.rbs +141 -73
- data/core/time.rbs +81 -50
- data/core/trace_point.rbs +41 -35
- data/core/true_class.rbs +2 -2
- data/core/unbound_method.rbs +24 -16
- data/core/warning.rbs +7 -7
- data/docs/CONTRIBUTING.md +2 -1
- data/docs/aliases.md +79 -0
- data/docs/collection.md +3 -3
- data/docs/config.md +171 -0
- data/docs/encoding.md +56 -0
- data/docs/gem.md +0 -1
- data/docs/inline.md +634 -0
- data/docs/rbs_by_example.md +20 -20
- data/docs/rust.md +96 -0
- data/docs/sigs.md +3 -3
- data/docs/syntax.md +48 -18
- data/docs/type_fingerprint.md +21 -0
- data/docs/wasm_serialization.md +80 -0
- data/exe/rbs +1 -1
- data/ext/rbs_extension/ast_translation.c +1441 -671
- data/ext/rbs_extension/ast_translation.h +7 -0
- data/ext/rbs_extension/class_constants.c +18 -2
- data/ext/rbs_extension/class_constants.h +9 -0
- data/ext/rbs_extension/extconf.rb +6 -1
- data/ext/rbs_extension/legacy_location.c +33 -56
- data/ext/rbs_extension/legacy_location.h +37 -0
- data/ext/rbs_extension/main.c +183 -39
- data/include/rbs/ast.h +597 -297
- data/include/rbs/defines.h +40 -0
- data/include/rbs/lexer.h +31 -11
- data/include/rbs/location.h +25 -44
- data/include/rbs/parser.h +6 -6
- data/include/rbs/serialize.h +39 -0
- data/include/rbs/string.h +0 -2
- data/include/rbs/util/rbs_allocator.h +34 -13
- data/include/rbs/util/rbs_assert.h +12 -1
- data/include/rbs/util/rbs_constant_pool.h +0 -3
- data/include/rbs/util/rbs_encoding.h +2 -0
- data/include/rbs/util/rbs_unescape.h +2 -1
- data/include/rbs.h +8 -0
- data/lib/rbs/annotate/rdoc_annotator.rb +27 -31
- data/lib/rbs/ast/annotation.rb +1 -1
- data/lib/rbs/ast/comment.rb +1 -1
- data/lib/rbs/ast/declarations.rb +10 -10
- data/lib/rbs/ast/members.rb +14 -14
- data/lib/rbs/ast/ruby/annotations.rb +335 -3
- data/lib/rbs/ast/ruby/comment_block.rb +30 -4
- data/lib/rbs/ast/ruby/declarations.rb +209 -4
- data/lib/rbs/ast/ruby/helpers/constant_helper.rb +4 -0
- data/lib/rbs/ast/ruby/helpers/location_helper.rb +1 -1
- data/lib/rbs/ast/ruby/members.rb +571 -22
- data/lib/rbs/ast/type_param.rb +24 -4
- data/lib/rbs/buffer.rb +66 -24
- data/lib/rbs/cli/diff.rb +16 -15
- data/lib/rbs/cli/validate.rb +38 -106
- data/lib/rbs/cli.rb +55 -24
- data/lib/rbs/collection/config/lockfile_generator.rb +28 -3
- data/lib/rbs/collection/sources/git.rb +7 -0
- data/lib/rbs/definition.rb +1 -1
- data/lib/rbs/definition_builder/ancestor_builder.rb +62 -9
- data/lib/rbs/definition_builder/method_builder.rb +32 -6
- data/lib/rbs/definition_builder.rb +147 -25
- data/lib/rbs/diff.rb +7 -1
- data/lib/rbs/environment.rb +235 -75
- data/lib/rbs/environment_loader.rb +0 -6
- data/lib/rbs/errors.rb +27 -18
- data/lib/rbs/inline_parser.rb +377 -15
- data/lib/rbs/location_aux.rb +1 -1
- data/lib/rbs/locator.rb +5 -1
- data/lib/rbs/method_type.rb +5 -3
- data/lib/rbs/namespace.rb +47 -11
- data/lib/rbs/parser_aux.rb +20 -7
- data/lib/rbs/prototype/helpers.rb +57 -0
- data/lib/rbs/prototype/rb.rb +3 -28
- data/lib/rbs/prototype/rbi.rb +3 -20
- data/lib/rbs/prototype/runtime.rb +10 -0
- data/lib/rbs/resolver/constant_resolver.rb +2 -2
- data/lib/rbs/resolver/type_name_resolver.rb +120 -44
- data/lib/rbs/rewriter.rb +70 -0
- data/lib/rbs/subtractor.rb +3 -1
- data/lib/rbs/test/type_check.rb +25 -3
- data/lib/rbs/type_name.rb +34 -14
- data/lib/rbs/types.rb +88 -78
- data/lib/rbs/unit_test/type_assertions.rb +44 -8
- data/lib/rbs/validator.rb +2 -2
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/wasm/deserializer.rb +213 -0
- data/lib/rbs/wasm/location.rb +61 -0
- data/lib/rbs/wasm/parser.rb +137 -0
- data/lib/rbs/wasm/runtime.rb +217 -0
- data/lib/rbs/wasm/serialization_schema.rb +110 -0
- data/lib/rbs.rb +13 -2
- data/lib/rdoc/discover.rb +1 -1
- data/lib/rdoc_plugin/parser.rb +1 -1
- data/rbs.gemspec +24 -6
- data/schema/typeParam.json +17 -1
- data/sig/annotate/rdoc_annotater.rbs +12 -9
- data/sig/ast/ruby/annotations.rbs +364 -4
- data/sig/ast/ruby/comment_block.rbs +8 -0
- data/sig/ast/ruby/declarations.rbs +102 -4
- data/sig/ast/ruby/members.rbs +128 -2
- data/sig/buffer.rbs +19 -1
- data/sig/cli/diff.rbs +5 -11
- data/sig/cli/validate.rbs +12 -8
- data/sig/cli.rbs +18 -18
- data/sig/collection/config/lockfile_generator.rbs +2 -0
- data/sig/definition.rbs +6 -1
- data/sig/definition_builder.rbs +2 -0
- data/sig/environment.rbs +70 -12
- data/sig/errors.rbs +13 -14
- data/sig/inline_parser.rbs +41 -2
- data/sig/locator.rbs +0 -2
- data/sig/manifest.yaml +0 -2
- data/sig/method_builder.rbs +3 -1
- data/sig/namespace.rbs +20 -0
- data/sig/parser.rbs +41 -13
- data/sig/prototype/helpers.rbs +2 -0
- data/sig/resolver/type_name_resolver.rbs +36 -10
- data/sig/rewriter.rbs +45 -0
- data/sig/source.rbs +3 -3
- data/sig/type_param.rbs +13 -8
- data/sig/typename.rbs +15 -0
- data/sig/types.rbs +6 -7
- data/sig/unit_test/spy.rbs +0 -8
- data/sig/unit_test/type_assertions.rbs +15 -0
- data/sig/wasm/deserializer.rbs +66 -0
- data/sig/wasm/serialization_schema.rbs +13 -0
- data/src/ast.c +443 -162
- data/src/lexer.c +1415 -1313
- data/src/lexer.re +4 -0
- data/src/lexstate.c +63 -37
- data/src/location.c +7 -47
- data/src/parser.c +1032 -521
- data/src/serialize.c +958 -0
- data/src/string.c +0 -48
- data/src/util/rbs_allocator.c +89 -74
- data/src/util/rbs_assert.c +1 -1
- data/src/util/rbs_buffer.c +2 -2
- data/src/util/rbs_constant_pool.c +10 -14
- data/src/util/rbs_encoding.c +4 -8
- data/src/util/rbs_unescape.c +56 -20
- data/stdlib/abbrev/0/array.rbs +1 -1
- data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
- data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
- data/stdlib/cgi/0/core.rbs +9 -393
- data/stdlib/cgi/0/manifest.yaml +1 -0
- data/stdlib/cgi-escape/0/escape.rbs +171 -0
- data/stdlib/coverage/0/coverage.rbs +7 -4
- data/stdlib/csv/0/csv.rbs +5 -5
- data/stdlib/date/0/date.rbs +92 -79
- data/stdlib/date/0/date_time.rbs +25 -24
- data/stdlib/delegate/0/delegator.rbs +10 -7
- data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
- data/stdlib/digest/0/digest.rbs +111 -1
- data/stdlib/erb/0/erb.rbs +748 -347
- data/stdlib/etc/0/etc.rbs +73 -54
- data/stdlib/fileutils/0/fileutils.rbs +179 -160
- data/stdlib/forwardable/0/forwardable.rbs +13 -10
- data/stdlib/io-console/0/io-console.rbs +2 -2
- data/stdlib/json/0/json.rbs +223 -142
- data/stdlib/monitor/0/monitor.rbs +3 -3
- data/stdlib/net-http/0/net-http.rbs +162 -134
- data/stdlib/objspace/0/objspace.rbs +17 -34
- data/stdlib/open-uri/0/open-uri.rbs +48 -8
- data/stdlib/open3/0/open3.rbs +469 -10
- data/stdlib/openssl/0/openssl.rbs +482 -364
- data/stdlib/optparse/0/optparse.rbs +26 -17
- data/stdlib/pathname/0/pathname.rbs +11 -1381
- data/stdlib/pp/0/pp.rbs +9 -8
- data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
- data/stdlib/pstore/0/pstore.rbs +35 -30
- data/stdlib/psych/0/psych.rbs +65 -12
- data/stdlib/psych/0/store.rbs +2 -4
- data/stdlib/pty/0/pty.rbs +9 -6
- data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
- data/stdlib/rdoc/0/code_object.rbs +2 -1
- data/stdlib/rdoc/0/parser.rbs +1 -1
- data/stdlib/rdoc/0/rdoc.rbs +1 -1
- data/stdlib/rdoc/0/store.rbs +1 -1
- data/stdlib/resolv/0/resolv.rbs +26 -69
- data/stdlib/ripper/0/ripper.rbs +22 -19
- data/stdlib/securerandom/0/manifest.yaml +2 -0
- data/stdlib/securerandom/0/securerandom.rbs +7 -20
- data/stdlib/shellwords/0/shellwords.rbs +3 -3
- data/stdlib/singleton/0/singleton.rbs +3 -0
- data/stdlib/socket/0/addrinfo.rbs +7 -7
- data/stdlib/socket/0/basic_socket.rbs +3 -3
- data/stdlib/socket/0/ip_socket.rbs +10 -8
- data/stdlib/socket/0/socket.rbs +23 -10
- data/stdlib/socket/0/tcp_server.rbs +1 -1
- data/stdlib/socket/0/tcp_socket.rbs +11 -3
- data/stdlib/socket/0/udp_socket.rbs +1 -1
- data/stdlib/socket/0/unix_server.rbs +1 -1
- data/stdlib/stringio/0/stringio.rbs +1209 -95
- data/stdlib/strscan/0/string_scanner.rbs +101 -80
- data/stdlib/tempfile/0/tempfile.rbs +25 -21
- data/stdlib/time/0/time.rbs +8 -6
- data/stdlib/timeout/0/timeout.rbs +63 -7
- data/stdlib/tsort/0/cyclic.rbs +4 -1
- data/stdlib/tsort/0/interfaces.rbs +8 -8
- data/stdlib/tsort/0/tsort.rbs +16 -15
- data/stdlib/uri/0/common.rbs +42 -20
- data/stdlib/uri/0/file.rbs +3 -3
- data/stdlib/uri/0/generic.rbs +26 -18
- data/stdlib/uri/0/http.rbs +2 -2
- data/stdlib/uri/0/ldap.rbs +2 -2
- data/stdlib/uri/0/mailto.rbs +3 -3
- data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
- data/stdlib/zlib/0/deflate.rbs +4 -3
- data/stdlib/zlib/0/gzip_reader.rbs +8 -8
- data/stdlib/zlib/0/gzip_writer.rbs +14 -12
- data/stdlib/zlib/0/inflate.rbs +1 -1
- data/stdlib/zlib/0/need_dict.rbs +1 -1
- data/stdlib/zlib/0/zstream.rbs +1 -0
- data/wasm/README.md +59 -0
- data/wasm/rbs_wasm.c +411 -0
- metadata +56 -8
- data/.vscode/extensions.json +0 -5
- data/.vscode/settings.json +0 -19
data/include/rbs/defines.h
CHANGED
|
@@ -32,6 +32,24 @@
|
|
|
32
32
|
#define RBS_ATTRIBUTE_FORMAT(string_index, argument_index)
|
|
33
33
|
#endif
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Support RBS_LIKELY and RBS_UNLIKELY to help the compiler optimize its
|
|
37
|
+
* branch predication.
|
|
38
|
+
*/
|
|
39
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
40
|
+
/** The compiler should predicate that this branch will be taken. */
|
|
41
|
+
#define RBS_LIKELY(x) __builtin_expect(!!(x), 1)
|
|
42
|
+
|
|
43
|
+
/** The compiler should predicate that this branch will not be taken. */
|
|
44
|
+
#define RBS_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
|
45
|
+
#else
|
|
46
|
+
/** Void because this platform does not support branch prediction hints. */
|
|
47
|
+
#define RBS_LIKELY(x) (x)
|
|
48
|
+
|
|
49
|
+
/** Void because this platform does not support branch prediction hints. */
|
|
50
|
+
#define RBS_UNLIKELY(x) (x)
|
|
51
|
+
#endif
|
|
52
|
+
|
|
35
53
|
/**
|
|
36
54
|
* We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
|
|
37
55
|
* Use RBS_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
|
|
@@ -56,4 +74,26 @@
|
|
|
56
74
|
#define NODISCARD __attribute__((warn_unused_result))
|
|
57
75
|
#endif
|
|
58
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Mark a function or variable as potentially unused to suppress compiler warnings.
|
|
79
|
+
*/
|
|
80
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
81
|
+
#define RBS_ATTRIBUTE_UNUSED __attribute__((unused))
|
|
82
|
+
#else
|
|
83
|
+
#define RBS_ATTRIBUTE_UNUSED
|
|
84
|
+
#endif
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Nullability annotations for pointer types.
|
|
88
|
+
* Clang supports _Nullable and _Nonnull to indicate whether a pointer may be NULL.
|
|
89
|
+
* On other compilers, these expand to nothing.
|
|
90
|
+
*/
|
|
91
|
+
#ifdef __clang__
|
|
92
|
+
#define RBS_NULLABLE _Nullable
|
|
93
|
+
#define RBS_NONNULL _Nonnull
|
|
94
|
+
#else
|
|
95
|
+
#define RBS_NULLABLE
|
|
96
|
+
#define RBS_NONNULL
|
|
97
|
+
#endif
|
|
98
|
+
|
|
59
99
|
#endif
|
data/include/rbs/lexer.h
CHANGED
|
@@ -30,6 +30,7 @@ enum RBSTokenType {
|
|
|
30
30
|
pBANG, /* ! */
|
|
31
31
|
pQUESTION, /* ? */
|
|
32
32
|
pLT, /* < */
|
|
33
|
+
pGT, /* > */
|
|
33
34
|
pEQ, /* = */
|
|
34
35
|
|
|
35
36
|
kALIAS, /* alias */
|
|
@@ -39,6 +40,7 @@ enum RBSTokenType {
|
|
|
39
40
|
kBOOL, /* bool */
|
|
40
41
|
kBOT, /* bot */
|
|
41
42
|
kCLASS, /* class */
|
|
43
|
+
kCLASSALIAS, /* class-alias */
|
|
42
44
|
kDEF, /* def */
|
|
43
45
|
kEND, /* end */
|
|
44
46
|
kEXTEND, /* extend */
|
|
@@ -48,6 +50,7 @@ enum RBSTokenType {
|
|
|
48
50
|
kINSTANCE, /* instance */
|
|
49
51
|
kINTERFACE, /* interface */
|
|
50
52
|
kMODULE, /* module */
|
|
53
|
+
kMODULEALIAS, /* module-alias */
|
|
51
54
|
kNIL, /* nil */
|
|
52
55
|
kOUT, /* out */
|
|
53
56
|
kPREPEND, /* prepend */
|
|
@@ -67,6 +70,7 @@ enum RBSTokenType {
|
|
|
67
70
|
kATRBS, /* @rbs */
|
|
68
71
|
kSKIP, /* skip */
|
|
69
72
|
kRETURN, /* return */
|
|
73
|
+
kMODULESELF, /* module-self */
|
|
70
74
|
|
|
71
75
|
tLIDENT, /* Identifiers starting with lower case */
|
|
72
76
|
tUIDENT, /* Identifiers starting with upper case */
|
|
@@ -123,20 +127,26 @@ typedef struct {
|
|
|
123
127
|
* The lexer state is the curren token.
|
|
124
128
|
*
|
|
125
129
|
* ```
|
|
126
|
-
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
+
#. 0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6
|
|
131
|
+
* ... " a s t r i n g t o k e n "
|
|
132
|
+
* ^ start position (0)
|
|
133
|
+
* ^ current position (6)
|
|
134
|
+
* ^ current character ('i', bytes = 1)
|
|
135
|
+
* ~~~~~~~~~~~ Token => "a str
|
|
130
136
|
* ```
|
|
131
137
|
* */
|
|
132
138
|
typedef struct {
|
|
133
139
|
rbs_string_t string;
|
|
134
|
-
int start_pos;
|
|
135
|
-
int end_pos;
|
|
136
|
-
rbs_position_t current;
|
|
137
|
-
rbs_position_t start;
|
|
140
|
+
int start_pos; /* The byte position that defines the start of the input */
|
|
141
|
+
int end_pos; /* The byte position that defines the end of the input */
|
|
142
|
+
rbs_position_t current; /* The current position: just before the current_character */
|
|
143
|
+
rbs_position_t start; /* The start position of the current token */
|
|
144
|
+
|
|
145
|
+
unsigned int current_code_point; /* Current character code point */
|
|
146
|
+
size_t current_character_bytes; /* Current character byte length (0 or 1~4) */
|
|
147
|
+
|
|
138
148
|
bool first_token_of_line; /* This flag is used for tLINECOMMENT */
|
|
139
|
-
|
|
149
|
+
|
|
140
150
|
const rbs_encoding_t *encoding;
|
|
141
151
|
} rbs_lexer_t;
|
|
142
152
|
|
|
@@ -156,15 +166,23 @@ int rbs_token_bytes(rbs_token_t tok);
|
|
|
156
166
|
const char *rbs_token_type_str(enum RBSTokenType type);
|
|
157
167
|
|
|
158
168
|
/**
|
|
159
|
-
*
|
|
169
|
+
* Returns the next character.
|
|
160
170
|
* */
|
|
161
171
|
unsigned int rbs_peek(rbs_lexer_t *lexer);
|
|
162
172
|
|
|
163
173
|
/**
|
|
164
|
-
*
|
|
174
|
+
* Advances the current position by one character.
|
|
165
175
|
* */
|
|
166
176
|
void rbs_skip(rbs_lexer_t *lexer);
|
|
167
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Read next character and store the codepoint and byte length to the given pointers.
|
|
180
|
+
*
|
|
181
|
+
* This doesn't update the lexer state.
|
|
182
|
+
* Returns `true` if succeeded, or `false` if reached to EOF.
|
|
183
|
+
* */
|
|
184
|
+
bool rbs_next_char(rbs_lexer_t *lexer, unsigned int *codepoint, size_t *bytes);
|
|
185
|
+
|
|
168
186
|
/**
|
|
169
187
|
* Skip n characters.
|
|
170
188
|
* */
|
|
@@ -184,4 +202,6 @@ rbs_token_t rbs_lexer_next_token(rbs_lexer_t *lexer);
|
|
|
184
202
|
|
|
185
203
|
void rbs_print_token(rbs_token_t tok);
|
|
186
204
|
|
|
205
|
+
void rbs_print_lexer(rbs_lexer_t *lexer);
|
|
206
|
+
|
|
187
207
|
#endif
|
data/include/rbs/location.h
CHANGED
|
@@ -1,59 +1,40 @@
|
|
|
1
1
|
#ifndef RBS__RBS_LOCATION_H
|
|
2
2
|
#define RBS__RBS_LOCATION_H
|
|
3
3
|
|
|
4
|
-
#include "lexer.h"
|
|
5
|
-
|
|
6
|
-
#include "rbs/util/rbs_constant_pool.h"
|
|
7
4
|
#include "rbs/util/rbs_allocator.h"
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
#define RBS_LOCATION_NULL_RANGE ((rbs_location_range) { -1, -1, -1, -1 })
|
|
7
|
+
#define RBS_LOCATION_NULL_RANGE_P(rg) ((rg).start_char == -1)
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Converts a lexer range (rbs_range_t) to an AST location range (rbs_location_range) by extracting character and byte positions.
|
|
11
|
+
*/
|
|
12
|
+
#define RBS_RANGE_LEX2AST(rg) ((rbs_location_range) { .start_char = (rg).start.char_pos, .start_byte = (rg).start.byte_pos, .end_char = (rg).end.char_pos, .end_byte = (rg).end.byte_pos })
|
|
13
13
|
|
|
14
14
|
typedef struct {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} rbs_loc_entry;
|
|
15
|
+
int start_char;
|
|
16
|
+
int start_byte;
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
int end_char;
|
|
19
|
+
int end_byte;
|
|
20
|
+
} rbs_location_range;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
rbs_loc_entry entries[1];
|
|
28
|
-
} rbs_loc_children;
|
|
29
|
-
|
|
30
|
-
typedef struct rbs_location {
|
|
31
|
-
rbs_range_t rg;
|
|
32
|
-
rbs_loc_children *children;
|
|
33
|
-
} rbs_location_t;
|
|
34
|
-
|
|
35
|
-
typedef struct rbs_location_list_node {
|
|
36
|
-
rbs_location_t *loc;
|
|
37
|
-
struct rbs_location_list_node *next;
|
|
38
|
-
} rbs_location_list_node_t;
|
|
39
|
-
|
|
40
|
-
typedef struct rbs_location_list {
|
|
22
|
+
typedef struct rbs_location_range_list_node {
|
|
23
|
+
rbs_location_range range;
|
|
24
|
+
struct rbs_location_range_list_node *next;
|
|
25
|
+
} rbs_location_range_list_node_t;
|
|
26
|
+
|
|
27
|
+
typedef struct rbs_location_range_list {
|
|
41
28
|
rbs_allocator_t *allocator;
|
|
42
|
-
|
|
43
|
-
|
|
29
|
+
struct rbs_location_range_list_node *head;
|
|
30
|
+
struct rbs_location_range_list_node *tail;
|
|
44
31
|
size_t length;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
void rbs_loc_alloc_children(rbs_allocator_t *, rbs_location_t *loc, size_t capacity);
|
|
48
|
-
void rbs_loc_add_required_child(rbs_location_t *loc, rbs_constant_id_t name, rbs_range_t r);
|
|
49
|
-
void rbs_loc_add_optional_child(rbs_location_t *loc, rbs_constant_id_t name, rbs_range_t r);
|
|
32
|
+
} rbs_location_range_list_t;
|
|
50
33
|
|
|
51
34
|
/**
|
|
52
|
-
* Allocate new
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
rbs_location_list_t *rbs_location_list_new(rbs_allocator_t *allocator);
|
|
57
|
-
void rbs_location_list_append(rbs_location_list_t *list, rbs_location_t *loc);
|
|
35
|
+
* Allocate new rbs_location_range_list_t object through the given allocator.
|
|
36
|
+
*/
|
|
37
|
+
rbs_location_range_list_t *rbs_location_range_list_new(rbs_allocator_t *allocator);
|
|
38
|
+
void rbs_location_range_list_append(rbs_location_range_list_t *list, rbs_location_range range);
|
|
58
39
|
|
|
59
40
|
#endif
|
data/include/rbs/parser.h
CHANGED
|
@@ -27,9 +27,9 @@ typedef struct rbs_comment_t {
|
|
|
27
27
|
rbs_position_t start;
|
|
28
28
|
rbs_position_t end;
|
|
29
29
|
|
|
30
|
-
size_t
|
|
31
|
-
size_t
|
|
32
|
-
rbs_token_t *
|
|
30
|
+
size_t line_tokens_capacity;
|
|
31
|
+
size_t line_tokens_count;
|
|
32
|
+
rbs_token_t *line_tokens;
|
|
33
33
|
|
|
34
34
|
struct rbs_comment_t *next_comment;
|
|
35
35
|
} rbs_comment_t;
|
|
@@ -44,7 +44,7 @@ typedef struct rbs_error_t {
|
|
|
44
44
|
* An RBS parser is a LL(3) parser.
|
|
45
45
|
* */
|
|
46
46
|
typedef struct {
|
|
47
|
-
rbs_lexer_t *
|
|
47
|
+
rbs_lexer_t *lexer;
|
|
48
48
|
|
|
49
49
|
rbs_token_t current_token;
|
|
50
50
|
rbs_token_t next_token; /* The first lookahead token */
|
|
@@ -126,8 +126,8 @@ rbs_ast_comment_t *rbs_parser_get_comment(rbs_parser_t *parser, int subject_line
|
|
|
126
126
|
|
|
127
127
|
void rbs_parser_set_error(rbs_parser_t *parser, rbs_token_t tok, bool syntax_error, const char *fmt, ...) RBS_ATTRIBUTE_FORMAT(4, 5);
|
|
128
128
|
|
|
129
|
-
bool rbs_parse_type(rbs_parser_t *parser, rbs_node_t **type);
|
|
130
|
-
bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type);
|
|
129
|
+
bool rbs_parse_type(rbs_parser_t *parser, rbs_node_t **type, bool void_allowed, bool self_allowed, bool classish_allowed);
|
|
130
|
+
bool rbs_parse_method_type(rbs_parser_t *parser, rbs_method_type_t **method_type, bool require_eof, bool classish_allowed);
|
|
131
131
|
bool rbs_parse_signature(rbs_parser_t *parser, rbs_signature_t **signature);
|
|
132
132
|
|
|
133
133
|
bool rbs_parse_type_params(rbs_parser_t *parser, bool module_type_params, rbs_node_list_t **params);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*----------------------------------------------------------------------------*/
|
|
2
|
+
/* This file is generated by the templates/template.rb script and should not */
|
|
3
|
+
/* be modified manually. */
|
|
4
|
+
/* To change the template see */
|
|
5
|
+
/* templates/include/rbs/serialize.h.erb */
|
|
6
|
+
/*----------------------------------------------------------------------------*/
|
|
7
|
+
|
|
8
|
+
#ifndef RBS__SERIALIZE_H
|
|
9
|
+
#define RBS__SERIALIZE_H
|
|
10
|
+
|
|
11
|
+
#include "rbs/ast.h"
|
|
12
|
+
#include "rbs/string.h"
|
|
13
|
+
#include "rbs/util/rbs_allocator.h"
|
|
14
|
+
#include "rbs/util/rbs_constant_pool.h"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Serialize a parsed AST node into a compact, portable binary buffer.
|
|
18
|
+
*
|
|
19
|
+
* The format is consumed by RBS::WASM::Deserializer on the Ruby side, which
|
|
20
|
+
* rebuilds the same `RBS::AST` objects that the C extension would have built
|
|
21
|
+
* directly. This is what lets RBS run on Ruby implementations that cannot load
|
|
22
|
+
* the C extension (notably JRuby): the parser runs inside WebAssembly, produces
|
|
23
|
+
* this buffer, and the host reconstructs the tree in pure Ruby.
|
|
24
|
+
*
|
|
25
|
+
* The buffer is allocated from `allocator`, so its lifetime is tied to that
|
|
26
|
+
* allocator. `constant_pool` must be the pool the node was parsed with; it is
|
|
27
|
+
* used to resolve interned symbol/identifier ids back into their bytes.
|
|
28
|
+
*
|
|
29
|
+
* See `docs/wasm_serialization.md` for the wire format.
|
|
30
|
+
*/
|
|
31
|
+
rbs_string_t rbs_serialize_node(rbs_allocator_t *allocator, rbs_constant_pool_t *constant_pool, rbs_node_t *node);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Like rbs_serialize_node, but for a bare node list (e.g. the result of
|
|
35
|
+
* rbs_parse_type_params). Decoded by RBS::WASM::Deserializer.deserialize_node_list.
|
|
36
|
+
*/
|
|
37
|
+
rbs_string_t rbs_serialize_node_list(rbs_allocator_t *allocator, rbs_constant_pool_t *constant_pool, rbs_node_list_t *list);
|
|
38
|
+
|
|
39
|
+
#endif
|
data/include/rbs/string.h
CHANGED
|
@@ -3,19 +3,40 @@
|
|
|
3
3
|
|
|
4
4
|
#include <stddef.h>
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
#if defined(
|
|
8
|
-
#
|
|
6
|
+
/* Include stdalign.h for C11 and later for alignof support */
|
|
7
|
+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
|
8
|
+
#include <stdalign.h>
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Define a portable alignment macro that works across all supported environments
|
|
13
|
+
*/
|
|
14
|
+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
|
15
|
+
/* C11 or later - use _Alignof directly (always available in C11+) */
|
|
16
|
+
#define rbs_alignof(type) _Alignof(type)
|
|
17
|
+
#elif defined(__cplusplus) && __cplusplus >= 201103L
|
|
18
|
+
/* C++11 or later has alignof keyword */
|
|
19
|
+
#define rbs_alignof(type) alignof(type)
|
|
20
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
21
|
+
/* GCC and Clang provide __alignof__ */
|
|
22
|
+
#define rbs_alignof(type) __alignof__(type)
|
|
9
23
|
#elif defined(_MSC_VER)
|
|
10
|
-
|
|
24
|
+
/* MSVC provides __alignof */
|
|
25
|
+
#define rbs_alignof(type) __alignof(type)
|
|
11
26
|
#else
|
|
12
|
-
|
|
13
|
-
#define
|
|
14
|
-
|
|
27
|
+
/* Fallback using offset trick for other compilers */
|
|
28
|
+
#define rbs_alignof(type) offsetof( \
|
|
29
|
+
struct { char c; type member; }, \
|
|
30
|
+
member \
|
|
31
|
+
)
|
|
15
32
|
#endif
|
|
16
33
|
|
|
17
|
-
struct rbs_allocator
|
|
18
|
-
|
|
34
|
+
typedef struct rbs_allocator {
|
|
35
|
+
// The head of a linked list of pages, starting with the most recently allocated page.
|
|
36
|
+
struct rbs_allocator_page *page;
|
|
37
|
+
|
|
38
|
+
size_t default_page_payload_size;
|
|
39
|
+
} rbs_allocator_t;
|
|
19
40
|
|
|
20
41
|
rbs_allocator_t *rbs_allocator_init(void);
|
|
21
42
|
void rbs_allocator_free(rbs_allocator_t *);
|
|
@@ -26,13 +47,13 @@ void *rbs_allocator_calloc_impl(rbs_allocator_t *, size_t count, size_t size, si
|
|
|
26
47
|
void *rbs_allocator_realloc_impl(rbs_allocator_t *, void *ptr, size_t old_size, size_t new_size, size_t alignment);
|
|
27
48
|
|
|
28
49
|
// Use this when allocating memory for a single instance of a type.
|
|
29
|
-
#define rbs_allocator_alloc(allocator, type) ((type *) rbs_allocator_malloc_impl((allocator), sizeof(type),
|
|
50
|
+
#define rbs_allocator_alloc(allocator, type) ((type *) rbs_allocator_malloc_impl((allocator), sizeof(type), rbs_alignof(type)))
|
|
30
51
|
// Use this when allocating memory that will be immediately written to in full.
|
|
31
52
|
// Such as allocating strings
|
|
32
|
-
#define rbs_allocator_alloc_many(allocator, count, type) ((type *) rbs_allocator_malloc_many_impl((allocator), (count), sizeof(type),
|
|
53
|
+
#define rbs_allocator_alloc_many(allocator, count, type) ((type *) rbs_allocator_malloc_many_impl((allocator), (count), sizeof(type), rbs_alignof(type)))
|
|
33
54
|
// Use this when allocating memory that will NOT be immediately written to in full.
|
|
34
55
|
// Such as allocating buffers
|
|
35
|
-
#define rbs_allocator_calloc(allocator, count, type) ((type *) rbs_allocator_calloc_impl((allocator), (count), sizeof(type),
|
|
36
|
-
#define rbs_allocator_realloc(allocator, ptr, old_size, new_size, type) ((type *) rbs_allocator_realloc_impl((allocator), (ptr), (old_size), (new_size),
|
|
56
|
+
#define rbs_allocator_calloc(allocator, count, type) ((type *) rbs_allocator_calloc_impl((allocator), (count), sizeof(type), rbs_alignof(type)))
|
|
57
|
+
#define rbs_allocator_realloc(allocator, ptr, old_size, new_size, type) ((type *) rbs_allocator_realloc_impl((allocator), (ptr), (old_size), (new_size), rbs_alignof(type)))
|
|
37
58
|
|
|
38
59
|
#endif
|
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
#include "rbs/defines.h"
|
|
5
5
|
#include <stdbool.h>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* RBS_ASSERT macro that calls rbs_assert in debug builds and is removed in release builds.
|
|
9
|
+
* In debug mode, it forwards all arguments to the rbs_assert function.
|
|
10
|
+
* In release mode, it expands to nothing.
|
|
11
|
+
*/
|
|
12
|
+
#ifdef NDEBUG
|
|
13
|
+
#define RBS_ASSERT(condition, ...) ((void) 0)
|
|
14
|
+
#else
|
|
15
|
+
#define RBS_ASSERT(condition, ...) rbs_assert_impl(condition, __VA_ARGS__)
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
void rbs_assert_impl(bool condition, const char *fmt, ...) RBS_ATTRIBUTE_FORMAT(2, 3);
|
|
8
19
|
|
|
9
20
|
#endif
|
|
@@ -81,9 +81,6 @@ typedef struct {
|
|
|
81
81
|
uint32_t capacity;
|
|
82
82
|
} rbs_constant_pool_t;
|
|
83
83
|
|
|
84
|
-
// A global constant pool for storing permenant keywords, such as the names of location children in `parser.c`.
|
|
85
|
-
extern rbs_constant_pool_t *RBS_GLOBAL_CONSTANT_POOL;
|
|
86
|
-
|
|
87
84
|
/**
|
|
88
85
|
* Initialize a new constant pool with a given capacity.
|
|
89
86
|
*
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include <stddef.h>
|
|
5
5
|
#include "rbs/util/rbs_allocator.h"
|
|
6
6
|
#include "rbs/string.h"
|
|
7
|
+
#include "rbs/util/rbs_encoding.h"
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Receives `rbs_parser_t` and `range`, which represents a string token or symbol token, and returns a string VALUE.
|
|
@@ -18,6 +19,6 @@
|
|
|
18
19
|
*
|
|
19
20
|
* @returns A new owned string that will be freed when the allocator is freed.
|
|
20
21
|
* */
|
|
21
|
-
rbs_string_t rbs_unquote_string(rbs_allocator_t *, const rbs_string_t input);
|
|
22
|
+
rbs_string_t rbs_unquote_string(rbs_allocator_t *, const rbs_string_t input, const rbs_encoding_t *encoding);
|
|
22
23
|
|
|
23
24
|
#endif // RBS_RBS_UNESCAPE_H
|
data/include/rbs.h
CHANGED
|
@@ -13,25 +13,22 @@ module RBS
|
|
|
13
13
|
@include_filename = true
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def annotate_file(path, preserve:)
|
|
17
|
-
|
|
16
|
+
def annotate_file(path, preserve: true)
|
|
17
|
+
buffer, _, decls = Parser.parse_signature(path.read())
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
rewriter = Rewriter.new(buffer)
|
|
20
|
+
annotate_decls(decls, rewriter)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
path.open("w") do |io|
|
|
24
|
-
Writer.new(out: io).preserve!(preserve: preserve).write(decls)
|
|
25
|
-
end
|
|
22
|
+
path.write(rewriter.string)
|
|
26
23
|
end
|
|
27
24
|
|
|
28
|
-
def annotate_decls(decls, outer: [])
|
|
25
|
+
def annotate_decls(decls, rewriter, outer: [])
|
|
29
26
|
decls.each do |decl|
|
|
30
27
|
case decl
|
|
31
28
|
when AST::Declarations::Class, AST::Declarations::Module
|
|
32
|
-
annotate_class(decl, outer: outer)
|
|
29
|
+
annotate_class(decl, rewriter, outer: outer)
|
|
33
30
|
when AST::Declarations::Constant
|
|
34
|
-
annotate_constant(decl, outer: outer)
|
|
31
|
+
annotate_constant(decl, rewriter, outer: outer)
|
|
35
32
|
end
|
|
36
33
|
end
|
|
37
34
|
end
|
|
@@ -244,7 +241,7 @@ module RBS
|
|
|
244
241
|
end
|
|
245
242
|
end
|
|
246
243
|
|
|
247
|
-
def annotate_class(decl, outer:)
|
|
244
|
+
def annotate_class(decl, rewriter, outer:)
|
|
248
245
|
annots = annotations(decl)
|
|
249
246
|
|
|
250
247
|
full_name = resolve_name(decl.name, outer: outer)
|
|
@@ -252,7 +249,7 @@ module RBS
|
|
|
252
249
|
text = resolve_doc_source(annots.copy_annotation, tester: annots) { doc_for_class(full_name, tester: annots) }
|
|
253
250
|
end
|
|
254
251
|
|
|
255
|
-
replace_comment(decl, text)
|
|
252
|
+
replace_comment(decl, text, rewriter)
|
|
256
253
|
|
|
257
254
|
unless annots.skip_all?
|
|
258
255
|
outer_ = outer + [decl.name.to_namespace]
|
|
@@ -260,28 +257,28 @@ module RBS
|
|
|
260
257
|
decl.each_member do |member|
|
|
261
258
|
case member
|
|
262
259
|
when AST::Members::MethodDefinition
|
|
263
|
-
annotate_method(full_name, member)
|
|
260
|
+
annotate_method(full_name, member, rewriter)
|
|
264
261
|
when AST::Members::Alias
|
|
265
|
-
annotate_alias(full_name, member)
|
|
262
|
+
annotate_alias(full_name, member, rewriter)
|
|
266
263
|
when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter
|
|
267
|
-
annotate_attribute(full_name, member)
|
|
264
|
+
annotate_attribute(full_name, member, rewriter)
|
|
268
265
|
end
|
|
269
266
|
end
|
|
270
267
|
|
|
271
|
-
annotate_decls(decl.each_decl.to_a, outer: outer_)
|
|
268
|
+
annotate_decls(decl.each_decl.to_a, rewriter, outer: outer_)
|
|
272
269
|
end
|
|
273
270
|
end
|
|
274
271
|
|
|
275
|
-
def annotate_constant(const, outer:)
|
|
272
|
+
def annotate_constant(const, rewriter, outer:)
|
|
276
273
|
annots = Annotations.new([])
|
|
277
274
|
|
|
278
275
|
full_name = resolve_name(const.name, outer: outer)
|
|
279
276
|
text = doc_for_constant(full_name, tester: annots)
|
|
280
277
|
|
|
281
|
-
replace_comment(const, text)
|
|
278
|
+
replace_comment(const, text, rewriter)
|
|
282
279
|
end
|
|
283
280
|
|
|
284
|
-
def annotate_alias(typename, als)
|
|
281
|
+
def annotate_alias(typename, als, rewriter)
|
|
285
282
|
annots = annotations(als)
|
|
286
283
|
|
|
287
284
|
unless annots.skip?
|
|
@@ -295,7 +292,7 @@ module RBS
|
|
|
295
292
|
end
|
|
296
293
|
end
|
|
297
294
|
|
|
298
|
-
replace_comment(als, text)
|
|
295
|
+
replace_comment(als, text, rewriter)
|
|
299
296
|
end
|
|
300
297
|
|
|
301
298
|
def join_docs(docs, separator: "----")
|
|
@@ -311,7 +308,7 @@ module RBS
|
|
|
311
308
|
end
|
|
312
309
|
end
|
|
313
310
|
|
|
314
|
-
def annotate_method(typename, method)
|
|
311
|
+
def annotate_method(typename, method, rewriter)
|
|
315
312
|
annots = annotations(method)
|
|
316
313
|
|
|
317
314
|
unless annots.skip?
|
|
@@ -337,10 +334,10 @@ module RBS
|
|
|
337
334
|
}
|
|
338
335
|
end
|
|
339
336
|
|
|
340
|
-
replace_comment(method, text)
|
|
337
|
+
replace_comment(method, text, rewriter)
|
|
341
338
|
end
|
|
342
339
|
|
|
343
|
-
def annotate_attribute(typename, attr)
|
|
340
|
+
def annotate_attribute(typename, attr, rewriter)
|
|
344
341
|
annots = annotations(attr)
|
|
345
342
|
|
|
346
343
|
unless annots.skip?
|
|
@@ -368,18 +365,17 @@ module RBS
|
|
|
368
365
|
end
|
|
369
366
|
end
|
|
370
367
|
|
|
371
|
-
replace_comment(attr, text)
|
|
368
|
+
replace_comment(attr, text, rewriter)
|
|
372
369
|
end
|
|
373
370
|
|
|
374
|
-
def replace_comment(commented, string)
|
|
371
|
+
def replace_comment(commented, string, rewriter)
|
|
375
372
|
if string
|
|
376
373
|
if string.empty?
|
|
377
|
-
commented.
|
|
374
|
+
rewriter.delete_comment(commented.comment) if commented.comment
|
|
375
|
+
elsif commented.comment
|
|
376
|
+
rewriter.replace_comment(commented.comment, content: string)
|
|
378
377
|
else
|
|
379
|
-
commented.
|
|
380
|
-
:@comment,
|
|
381
|
-
AST::Comment.new(location: nil, string: string)
|
|
382
|
-
)
|
|
378
|
+
rewriter.add_comment(commented.location || raise, *commented.annotations.filter_map(&:location), content: string)
|
|
383
379
|
end
|
|
384
380
|
end
|
|
385
381
|
end
|
data/lib/rbs/ast/annotation.rb
CHANGED