rbs 3.8.0 → 3.9.0.dev.1
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/.github/workflows/comments.yml +3 -3
- data/.github/workflows/dependabot.yml +1 -1
- data/.github/workflows/ruby.yml +7 -7
- data/.github/workflows/typecheck.yml +2 -0
- data/.github/workflows/windows.yml +15 -0
- data/.rubocop.yml +20 -1
- data/CHANGELOG.md +14 -0
- data/Rakefile +5 -2
- data/config.yml +6 -0
- data/core/data.rbs +1 -1
- data/core/enumerator.rbs +14 -2
- data/core/exception.rbs +148 -39
- data/core/gc.rbs +2 -2
- data/core/io.rbs +7 -3
- data/core/kernel.rbs +58 -16
- data/core/method.rbs +2 -2
- data/core/module.rbs +3 -3
- data/core/proc.rbs +2 -2
- data/core/ractor.rbs +4 -1
- data/core/rbs/unnamed/argf.rbs +3 -3
- data/core/regexp.rbs +4 -2
- data/core/ruby_vm.rbs +8 -8
- data/core/rubygems/version.rbs +2 -2
- data/core/string.rbs +1 -1
- data/core/time.rbs +1 -1
- data/core/unbound_method.rbs +1 -1
- data/docs/syntax.md +10 -5
- data/ext/rbs_extension/extconf.rb +2 -1
- data/ext/rbs_extension/location.c +32 -10
- data/ext/rbs_extension/location.h +4 -3
- data/ext/rbs_extension/main.c +22 -1
- data/ext/rbs_extension/parser.c +144 -136
- data/ext/rbs_extension/parserstate.c +40 -9
- data/ext/rbs_extension/parserstate.h +6 -4
- data/include/rbs/ruby_objs.h +6 -6
- data/include/rbs/util/rbs_constant_pool.h +219 -0
- data/lib/rbs/ast/declarations.rb +9 -4
- data/lib/rbs/ast/directives.rb +10 -0
- data/lib/rbs/ast/members.rb +2 -0
- data/lib/rbs/ast/type_param.rb +2 -2
- data/lib/rbs/cli/validate.rb +1 -0
- data/lib/rbs/cli.rb +3 -3
- data/lib/rbs/collection/config/lockfile_generator.rb +28 -7
- data/lib/rbs/collection/sources/rubygems.rb +1 -1
- data/lib/rbs/definition.rb +46 -31
- data/lib/rbs/definition_builder/ancestor_builder.rb +2 -0
- data/lib/rbs/definition_builder.rb +86 -30
- data/lib/rbs/environment.rb +33 -18
- data/lib/rbs/errors.rb +23 -0
- data/lib/rbs/locator.rb +2 -0
- data/lib/rbs/method_type.rb +2 -0
- data/lib/rbs/parser_aux.rb +38 -1
- data/lib/rbs/subtractor.rb +3 -3
- data/lib/rbs/test/hook.rb +2 -2
- data/lib/rbs/test/type_check.rb +7 -5
- data/lib/rbs/types.rb +44 -5
- data/lib/rbs/unit_test/spy.rb +4 -2
- data/lib/rbs/unit_test/type_assertions.rb +17 -11
- data/lib/rbs/validator.rb +4 -0
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +10 -5
- data/lib/rbs.rb +1 -0
- data/rbs.gemspec +1 -1
- data/sig/collection/config/lockfile_generator.rbs +1 -1
- data/sig/declarations.rbs +10 -3
- data/sig/definition.rbs +67 -14
- data/sig/definition_builder.rbs +17 -3
- data/sig/directives.rbs +17 -1
- data/sig/environment.rbs +2 -0
- data/sig/errors.rbs +16 -0
- data/sig/parser.rbs +5 -1
- data/sig/subtractor.rbs +1 -1
- data/sig/test/type_check.rbs +2 -2
- data/sig/type_param.rbs +1 -1
- data/sig/types.rbs +3 -0
- data/sig/unit_test/spy.rbs +2 -0
- data/sig/unit_test/type_assertions.rbs +2 -0
- data/sig/validator.rbs +4 -0
- data/sig/writer.rbs +1 -1
- data/src/ruby_objs.c +12 -6
- data/src/util/rbs_constant_pool.c +342 -0
- data/stdlib/cgi/0/core.rbs +10 -0
- data/stdlib/json/0/json.rbs +52 -50
- data/stdlib/monitor/0/monitor.rbs +13 -4
- data/stdlib/net-http/0/net-http.rbs +2 -2
- data/stdlib/openssl/0/openssl.rbs +73 -73
- data/stdlib/resolv/0/resolv.rbs +8 -8
- data/stdlib/socket/0/addrinfo.rbs +1 -1
- data/stdlib/socket/0/unix_socket.rbs +4 -2
- data/stdlib/stringio/0/stringio.rbs +1 -1
- data/stdlib/uri/0/common.rbs +17 -0
- metadata +4 -7
- data/templates/include/rbs/constants.h.erb +0 -20
- data/templates/include/rbs/ruby_objs.h.erb +0 -10
- data/templates/src/constants.c.erb +0 -36
- data/templates/src/ruby_objs.c.erb +0 -27
- data/templates/template.rb +0 -122
    
        data/sig/test/type_check.rbs
    CHANGED
    
    | @@ -7,12 +7,12 @@ module RBS | |
| 7 7 | 
             
                  #
         | 
| 8 8 | 
             
                  # Returns an array with detected errors.
         | 
| 9 9 | 
             
                  #
         | 
| 10 | 
            -
                  def method_call: (Symbol, MethodType, CallTrace, errors: Array[Errors::t]) -> Array[Errors::t]
         | 
| 10 | 
            +
                  def method_call: (Symbol, MethodType, CallTrace, errors: Array[Errors::t], ?annotations: Array[AST::Annotation]) -> Array[Errors::t]
         | 
| 11 11 |  | 
| 12 12 | 
             
                  # Test if given `value` is compatible to type
         | 
| 13 13 | 
             
                  #
         | 
| 14 14 | 
             
                  # Returns `true` if the value has the type.
         | 
| 15 | 
            -
                  # | 
| 15 | 
            +
                  #
         | 
| 16 16 | 
             
                  def value: (untyped value, Types::t) -> bool
         | 
| 17 17 | 
             
                end
         | 
| 18 18 | 
             
              end
         | 
    
        data/sig/type_param.rbs
    CHANGED
    
    | @@ -26,7 +26,7 @@ module RBS | |
| 26 26 |  | 
| 27 27 | 
             
                  attr_reader default_type: Types::t?
         | 
| 28 28 |  | 
| 29 | 
            -
                  def initialize: (name: Symbol, variance: variance, upper_bound: Types::t?, location: loc?, ?default_type: Types::t?) -> void
         | 
| 29 | 
            +
                  def initialize: (name: Symbol, variance: variance, upper_bound: Types::t?, location: loc?, ?default_type: Types::t?, ?unchecked: bool) -> void
         | 
| 30 30 |  | 
| 31 31 | 
             
                  include _ToJson
         | 
| 32 32 |  | 
    
        data/sig/types.rbs
    CHANGED
    
    
    
        data/sig/unit_test/spy.rbs
    CHANGED
    
    
    
        data/sig/validator.rbs
    CHANGED
    
    | @@ -49,6 +49,10 @@ module RBS | |
| 49 49 | 
             
                #
         | 
| 50 50 | 
             
                def validate_class_alias: (entry: Environment::ClassAliasEntry | Environment::ModuleAliasEntry) -> void
         | 
| 51 51 |  | 
| 52 | 
            +
                # Validates instance/class-instance/class variables.
         | 
| 53 | 
            +
                #
         | 
| 54 | 
            +
                def validate_variable: (AST::Members::Var) -> void
         | 
| 55 | 
            +
             | 
| 52 56 | 
             
                private
         | 
| 53 57 |  | 
| 54 58 | 
             
                # Resolves relative type names to absolute type names in given context.
         | 
    
        data/sig/writer.rbs
    CHANGED
    
    
    
        data/src/ruby_objs.c
    CHANGED
    
    | @@ -71,12 +71,13 @@ VALUE rbs_ast_decl_class_super(VALUE name, VALUE args, VALUE location) { | |
| 71 71 | 
             
              );
         | 
| 72 72 | 
             
            }
         | 
| 73 73 |  | 
| 74 | 
            -
            VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment) {
         | 
| 74 | 
            +
            VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment, VALUE annotations) {
         | 
| 75 75 | 
             
              VALUE _init_kwargs = rb_hash_new();
         | 
| 76 76 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("new_name")), new_name);
         | 
| 77 77 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("old_name")), old_name);
         | 
| 78 78 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location);
         | 
| 79 79 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment);
         | 
| 80 | 
            +
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations);
         | 
| 80 81 |  | 
| 81 82 | 
             
              return CLASS_NEW_INSTANCE(
         | 
| 82 83 | 
             
                RBS_AST_Declarations_ClassAlias,
         | 
| @@ -85,12 +86,13 @@ VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, V | |
| 85 86 | 
             
              );
         | 
| 86 87 | 
             
            }
         | 
| 87 88 |  | 
| 88 | 
            -
            VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE comment) {
         | 
| 89 | 
            +
            VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE comment, VALUE annotations) {
         | 
| 89 90 | 
             
              VALUE _init_kwargs = rb_hash_new();
         | 
| 90 91 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("name")), name);
         | 
| 91 92 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("type")), type);
         | 
| 92 93 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location);
         | 
| 93 94 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment);
         | 
| 95 | 
            +
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations);
         | 
| 94 96 |  | 
| 95 97 | 
             
              return CLASS_NEW_INSTANCE(
         | 
| 96 98 | 
             
                RBS_AST_Declarations_Constant,
         | 
| @@ -99,12 +101,13 @@ VALUE rbs_ast_decl_constant(VALUE name, VALUE type, VALUE location, VALUE commen | |
| 99 101 | 
             
              );
         | 
| 100 102 | 
             
            }
         | 
| 101 103 |  | 
| 102 | 
            -
            VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment) {
         | 
| 104 | 
            +
            VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment, VALUE annotations) {
         | 
| 103 105 | 
             
              VALUE _init_kwargs = rb_hash_new();
         | 
| 104 106 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("name")), name);
         | 
| 105 107 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("type")), type);
         | 
| 106 108 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location);
         | 
| 107 109 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment);
         | 
| 110 | 
            +
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations);
         | 
| 108 111 |  | 
| 109 112 | 
             
              return CLASS_NEW_INSTANCE(
         | 
| 110 113 | 
             
                RBS_AST_Declarations_Global,
         | 
| @@ -159,12 +162,13 @@ VALUE rbs_ast_decl_module_self(VALUE name, VALUE args, VALUE location) { | |
| 159 162 | 
             
              );
         | 
| 160 163 | 
             
            }
         | 
| 161 164 |  | 
| 162 | 
            -
            VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment) {
         | 
| 165 | 
            +
            VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment, VALUE annotations) {
         | 
| 163 166 | 
             
              VALUE _init_kwargs = rb_hash_new();
         | 
| 164 167 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("new_name")), new_name);
         | 
| 165 168 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("old_name")), old_name);
         | 
| 166 169 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location);
         | 
| 167 170 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("comment")), comment);
         | 
| 171 | 
            +
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("annotations")), annotations);
         | 
| 168 172 |  | 
| 169 173 | 
             
              return CLASS_NEW_INSTANCE(
         | 
| 170 174 | 
             
                RBS_AST_Declarations_ModuleAlias,
         | 
| @@ -435,12 +439,13 @@ VALUE rbs_ast_members_public(VALUE location) { | |
| 435 439 | 
             
              );
         | 
| 436 440 | 
             
            }
         | 
| 437 441 |  | 
| 438 | 
            -
            VALUE rbs_ast_type_param(VALUE name, VALUE variance, VALUE upper_bound, VALUE default_type, VALUE location) {
         | 
| 442 | 
            +
            VALUE rbs_ast_type_param(VALUE name, VALUE variance, VALUE upper_bound, VALUE default_type, VALUE unchecked, VALUE location) {
         | 
| 439 443 | 
             
              VALUE _init_kwargs = rb_hash_new();
         | 
| 440 444 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("name")), name);
         | 
| 441 445 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("variance")), variance);
         | 
| 442 446 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("upper_bound")), upper_bound);
         | 
| 443 447 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("default_type")), default_type);
         | 
| 448 | 
            +
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("unchecked")), unchecked);
         | 
| 444 449 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location);
         | 
| 445 450 |  | 
| 446 451 | 
             
              return CLASS_NEW_INSTANCE(
         | 
| @@ -501,8 +506,9 @@ VALUE rbs_alias(VALUE name, VALUE args, VALUE location) { | |
| 501 506 | 
             
              );
         | 
| 502 507 | 
             
            }
         | 
| 503 508 |  | 
| 504 | 
            -
            VALUE rbs_bases_any(VALUE location) {
         | 
| 509 | 
            +
            VALUE rbs_bases_any(VALUE todo, VALUE location) {
         | 
| 505 510 | 
             
              VALUE _init_kwargs = rb_hash_new();
         | 
| 511 | 
            +
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("todo")), todo);
         | 
| 506 512 | 
             
              rb_hash_aset(_init_kwargs, ID2SYM(rb_intern("location")), location);
         | 
| 507 513 |  | 
| 508 514 | 
             
              return CLASS_NEW_INSTANCE(
         | 
| @@ -0,0 +1,342 @@ | |
| 1 | 
            +
            #include "rbs/util/rbs_constant_pool.h"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            /**
         | 
| 4 | 
            +
             * Initialize a list of constant ids.
         | 
| 5 | 
            +
             */
         | 
| 6 | 
            +
            void
         | 
| 7 | 
            +
            rbs_constant_id_list_init(rbs_constant_id_list_t *list) {
         | 
| 8 | 
            +
                list->ids = NULL;
         | 
| 9 | 
            +
                list->size = 0;
         | 
| 10 | 
            +
                list->capacity = 0;
         | 
| 11 | 
            +
            }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            /**
         | 
| 14 | 
            +
             * Initialize a list of constant ids with a given capacity.
         | 
| 15 | 
            +
             */
         | 
| 16 | 
            +
            void
         | 
| 17 | 
            +
            rbs_constant_id_list_init_capacity(rbs_constant_id_list_t *list, size_t capacity) {
         | 
| 18 | 
            +
                list->ids = calloc(capacity, sizeof(rbs_constant_id_t));
         | 
| 19 | 
            +
                if (list->ids == NULL) abort();
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                list->size = 0;
         | 
| 22 | 
            +
                list->capacity = capacity;
         | 
| 23 | 
            +
            }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            /**
         | 
| 26 | 
            +
             * Append a constant id to a list of constant ids. Returns false if any
         | 
| 27 | 
            +
             * potential reallocations fail.
         | 
| 28 | 
            +
             */
         | 
| 29 | 
            +
            bool
         | 
| 30 | 
            +
            rbs_constant_id_list_append(rbs_constant_id_list_t *list, rbs_constant_id_t id) {
         | 
| 31 | 
            +
                if (list->size >= list->capacity) {
         | 
| 32 | 
            +
                    list->capacity = list->capacity == 0 ? 8 : list->capacity * 2;
         | 
| 33 | 
            +
                    list->ids = (rbs_constant_id_t *) realloc(list->ids, sizeof(rbs_constant_id_t) * list->capacity);
         | 
| 34 | 
            +
                    if (list->ids == NULL) return false;
         | 
| 35 | 
            +
                }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                list->ids[list->size++] = id;
         | 
| 38 | 
            +
                return true;
         | 
| 39 | 
            +
            }
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            /**
         | 
| 42 | 
            +
             * Insert a constant id into a list of constant ids at the specified index.
         | 
| 43 | 
            +
             */
         | 
| 44 | 
            +
            void
         | 
| 45 | 
            +
            rbs_constant_id_list_insert(rbs_constant_id_list_t *list, size_t index, rbs_constant_id_t id) {
         | 
| 46 | 
            +
                assert(index < list->capacity);
         | 
| 47 | 
            +
                assert(list->ids[index] == RBS_CONSTANT_ID_UNSET);
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                list->ids[index] = id;
         | 
| 50 | 
            +
                list->size++;
         | 
| 51 | 
            +
            }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            /**
         | 
| 54 | 
            +
             * Checks if the current constant id list includes the given constant id.
         | 
| 55 | 
            +
             */
         | 
| 56 | 
            +
            bool
         | 
| 57 | 
            +
            rbs_constant_id_list_includes(rbs_constant_id_list_t *list, rbs_constant_id_t id) {
         | 
| 58 | 
            +
                for (size_t index = 0; index < list->size; index++) {
         | 
| 59 | 
            +
                    if (list->ids[index] == id) return true;
         | 
| 60 | 
            +
                }
         | 
| 61 | 
            +
                return false;
         | 
| 62 | 
            +
            }
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            /**
         | 
| 65 | 
            +
             * Free the memory associated with a list of constant ids.
         | 
| 66 | 
            +
             */
         | 
| 67 | 
            +
            void
         | 
| 68 | 
            +
            rbs_constant_id_list_free(rbs_constant_id_list_t *list) {
         | 
| 69 | 
            +
                if (list->ids != NULL) {
         | 
| 70 | 
            +
                    free(list->ids);
         | 
| 71 | 
            +
                }
         | 
| 72 | 
            +
            }
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            /**
         | 
| 75 | 
            +
             * A relatively simple hash function (djb2) that is used to hash strings. We are
         | 
| 76 | 
            +
             * optimizing here for simplicity and speed.
         | 
| 77 | 
            +
             */
         | 
| 78 | 
            +
            static inline uint32_t
         | 
| 79 | 
            +
            rbs_constant_pool_hash(const uint8_t *start, size_t length) {
         | 
| 80 | 
            +
                // This is a prime number used as the initial value for the hash function.
         | 
| 81 | 
            +
                uint32_t value = 5381;
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                for (size_t index = 0; index < length; index++) {
         | 
| 84 | 
            +
                    value = ((value << 5) + value) + start[index];
         | 
| 85 | 
            +
                }
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                return value;
         | 
| 88 | 
            +
            }
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            /**
         | 
| 91 | 
            +
             * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
         | 
| 92 | 
            +
             */
         | 
| 93 | 
            +
            static uint32_t
         | 
| 94 | 
            +
            next_power_of_two(uint32_t v) {
         | 
| 95 | 
            +
                // Avoid underflow in subtraction on next line.
         | 
| 96 | 
            +
                if (v == 0) {
         | 
| 97 | 
            +
                    // 1 is the nearest power of 2 to 0 (2^0)
         | 
| 98 | 
            +
                    return 1;
         | 
| 99 | 
            +
                }
         | 
| 100 | 
            +
                v--;
         | 
| 101 | 
            +
                v |= v >> 1;
         | 
| 102 | 
            +
                v |= v >> 2;
         | 
| 103 | 
            +
                v |= v >> 4;
         | 
| 104 | 
            +
                v |= v >> 8;
         | 
| 105 | 
            +
                v |= v >> 16;
         | 
| 106 | 
            +
                v++;
         | 
| 107 | 
            +
                return v;
         | 
| 108 | 
            +
            }
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            #ifndef NDEBUG
         | 
| 111 | 
            +
            static bool
         | 
| 112 | 
            +
            is_power_of_two(uint32_t size) {
         | 
| 113 | 
            +
                return (size & (size - 1)) == 0;
         | 
| 114 | 
            +
            }
         | 
| 115 | 
            +
            #endif
         | 
| 116 | 
            +
             | 
| 117 | 
            +
            /**
         | 
| 118 | 
            +
             * Resize a constant pool to a given capacity.
         | 
| 119 | 
            +
             */
         | 
| 120 | 
            +
            static inline bool
         | 
| 121 | 
            +
            rbs_constant_pool_resize(rbs_constant_pool_t *pool) {
         | 
| 122 | 
            +
                assert(is_power_of_two(pool->capacity));
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                uint32_t next_capacity = pool->capacity * 2;
         | 
| 125 | 
            +
                if (next_capacity < pool->capacity) return false;
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                const uint32_t mask = next_capacity - 1;
         | 
| 128 | 
            +
                const size_t element_size = sizeof(rbs_constant_pool_bucket_t) + sizeof(rbs_constant_t);
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                void *next = calloc(next_capacity, element_size);
         | 
| 131 | 
            +
                if (next == NULL) return false;
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                rbs_constant_pool_bucket_t *next_buckets = next;
         | 
| 134 | 
            +
                rbs_constant_t *next_constants = (void *)(((char *) next) + next_capacity * sizeof(rbs_constant_pool_bucket_t));
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                // For each bucket in the current constant pool, find the index in the
         | 
| 137 | 
            +
                // next constant pool, and insert it.
         | 
| 138 | 
            +
                for (uint32_t index = 0; index < pool->capacity; index++) {
         | 
| 139 | 
            +
                    rbs_constant_pool_bucket_t *bucket = &pool->buckets[index];
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                    // If an id is set on this constant, then we know we have content here.
         | 
| 142 | 
            +
                    // In this case we need to insert it into the next constant pool.
         | 
| 143 | 
            +
                    if (bucket->id != RBS_CONSTANT_ID_UNSET) {
         | 
| 144 | 
            +
                        uint32_t next_index = bucket->hash & mask;
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                        // This implements linear scanning to find the next available slot
         | 
| 147 | 
            +
                        // in case this index is already taken. We don't need to bother
         | 
| 148 | 
            +
                        // comparing the values since we know that the hash is unique.
         | 
| 149 | 
            +
                        while (next_buckets[next_index].id != RBS_CONSTANT_ID_UNSET) {
         | 
| 150 | 
            +
                            next_index = (next_index + 1) & mask;
         | 
| 151 | 
            +
                        }
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                        // Here we copy over the entire bucket, which includes the id so
         | 
| 154 | 
            +
                        // that they are consistent between resizes.
         | 
| 155 | 
            +
                        next_buckets[next_index] = *bucket;
         | 
| 156 | 
            +
                    }
         | 
| 157 | 
            +
                }
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                // The constants are stable with respect to hash table resizes.
         | 
| 160 | 
            +
                memcpy(next_constants, pool->constants, pool->size * sizeof(rbs_constant_t));
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                // pool->constants and pool->buckets are allocated out of the same chunk
         | 
| 163 | 
            +
                // of memory, with the buckets coming first.
         | 
| 164 | 
            +
                free(pool->buckets);
         | 
| 165 | 
            +
                pool->constants = next_constants;
         | 
| 166 | 
            +
                pool->buckets = next_buckets;
         | 
| 167 | 
            +
                pool->capacity = next_capacity;
         | 
| 168 | 
            +
                return true;
         | 
| 169 | 
            +
            }
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            // This storage is initialized by `Init_rbs_extension()` in `main.c`.
         | 
| 172 | 
            +
            static rbs_constant_pool_t RBS_GLOBAL_CONSTANT_POOL_STORAGE = {};
         | 
| 173 | 
            +
            rbs_constant_pool_t *RBS_GLOBAL_CONSTANT_POOL = &RBS_GLOBAL_CONSTANT_POOL_STORAGE;
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            /**
         | 
| 176 | 
            +
             * Initialize a new constant pool with a given capacity.
         | 
| 177 | 
            +
             */
         | 
| 178 | 
            +
            bool
         | 
| 179 | 
            +
            rbs_constant_pool_init(rbs_constant_pool_t *pool, uint32_t capacity) {
         | 
| 180 | 
            +
                const uint32_t maximum = (~((uint32_t) 0));
         | 
| 181 | 
            +
                if (capacity >= ((maximum / 2) + 1)) return false;
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                capacity = next_power_of_two(capacity);
         | 
| 184 | 
            +
                const size_t element_size = sizeof(rbs_constant_pool_bucket_t) + sizeof(rbs_constant_t);
         | 
| 185 | 
            +
                void *memory = calloc(capacity, element_size);
         | 
| 186 | 
            +
                if (memory == NULL) return false;
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                pool->buckets = memory;
         | 
| 189 | 
            +
                pool->constants = (void *)(((char *)memory) + capacity * sizeof(rbs_constant_pool_bucket_t));
         | 
| 190 | 
            +
                pool->size = 0;
         | 
| 191 | 
            +
                pool->capacity = capacity;
         | 
| 192 | 
            +
                return true;
         | 
| 193 | 
            +
            }
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            /**
         | 
| 196 | 
            +
             * Return a pointer to the constant indicated by the given constant id.
         | 
| 197 | 
            +
             */
         | 
| 198 | 
            +
            rbs_constant_t *
         | 
| 199 | 
            +
            rbs_constant_pool_id_to_constant(const rbs_constant_pool_t *pool, rbs_constant_id_t constant_id) {
         | 
| 200 | 
            +
                assert(constant_id != RBS_CONSTANT_ID_UNSET && constant_id <= pool->size);
         | 
| 201 | 
            +
                return &pool->constants[constant_id - 1];
         | 
| 202 | 
            +
            }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
            /**
         | 
| 205 | 
            +
             * Find a constant in a constant pool. Returns the id of the constant, or 0 if
         | 
| 206 | 
            +
             * the constant is not found.
         | 
| 207 | 
            +
             */
         | 
| 208 | 
            +
            rbs_constant_id_t
         | 
| 209 | 
            +
            rbs_constant_pool_find(const rbs_constant_pool_t *pool, const uint8_t *start, size_t length) {
         | 
| 210 | 
            +
                assert(is_power_of_two(pool->capacity));
         | 
| 211 | 
            +
                const uint32_t mask = pool->capacity - 1;
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                uint32_t hash = rbs_constant_pool_hash(start, length);
         | 
| 214 | 
            +
                uint32_t index = hash & mask;
         | 
| 215 | 
            +
                rbs_constant_pool_bucket_t *bucket;
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                while (bucket = &pool->buckets[index], bucket->id != RBS_CONSTANT_ID_UNSET) {
         | 
| 218 | 
            +
                    rbs_constant_t *constant = &pool->constants[bucket->id - 1];
         | 
| 219 | 
            +
                    if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
         | 
| 220 | 
            +
                        return bucket->id;
         | 
| 221 | 
            +
                    }
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                    index = (index + 1) & mask;
         | 
| 224 | 
            +
                }
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                return RBS_CONSTANT_ID_UNSET;
         | 
| 227 | 
            +
            }
         | 
| 228 | 
            +
             | 
| 229 | 
            +
            /**
         | 
| 230 | 
            +
             * Insert a constant into a constant pool and return its index in the pool.
         | 
| 231 | 
            +
             */
         | 
| 232 | 
            +
            static inline rbs_constant_id_t
         | 
| 233 | 
            +
            rbs_constant_pool_insert(rbs_constant_pool_t *pool, const uint8_t *start, size_t length, rbs_constant_pool_bucket_type_t type) {
         | 
| 234 | 
            +
                if (pool->size >= (pool->capacity / 4 * 3)) {
         | 
| 235 | 
            +
                    if (!rbs_constant_pool_resize(pool)) return RBS_CONSTANT_ID_UNSET;
         | 
| 236 | 
            +
                }
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                assert(is_power_of_two(pool->capacity));
         | 
| 239 | 
            +
                const uint32_t mask = pool->capacity - 1;
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                uint32_t hash = rbs_constant_pool_hash(start, length);
         | 
| 242 | 
            +
                uint32_t index = hash & mask;
         | 
| 243 | 
            +
                rbs_constant_pool_bucket_t *bucket;
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                while (bucket = &pool->buckets[index], bucket->id != RBS_CONSTANT_ID_UNSET) {
         | 
| 246 | 
            +
                    // If there is a collision, then we need to check if the content is the
         | 
| 247 | 
            +
                    // same as the content we are trying to insert. If it is, then we can
         | 
| 248 | 
            +
                    // return the id of the existing constant.
         | 
| 249 | 
            +
                    rbs_constant_t *constant = &pool->constants[bucket->id - 1];
         | 
| 250 | 
            +
             | 
| 251 | 
            +
                    if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
         | 
| 252 | 
            +
                        // Since we have found a match, we need to check if this is
         | 
| 253 | 
            +
                        // attempting to insert a shared or an owned constant. We want to
         | 
| 254 | 
            +
                        // prefer shared constants since they don't require allocations.
         | 
| 255 | 
            +
                        if (type == RBS_CONSTANT_POOL_BUCKET_OWNED) {
         | 
| 256 | 
            +
                            // If we're attempting to insert an owned constant and we have
         | 
| 257 | 
            +
                            // an existing constant, then either way we don't want the given
         | 
| 258 | 
            +
                            // memory. Either it's duplicated with the existing constant or
         | 
| 259 | 
            +
                            // it's not necessary because we have a shared version.
         | 
| 260 | 
            +
                            free((void *) start);
         | 
| 261 | 
            +
                        } else if (bucket->type == RBS_CONSTANT_POOL_BUCKET_OWNED) {
         | 
| 262 | 
            +
                            // If we're attempting to insert a shared constant and the
         | 
| 263 | 
            +
                            // existing constant is owned, then we can free the owned
         | 
| 264 | 
            +
                            // constant and replace it with the shared constant.
         | 
| 265 | 
            +
                            free((void *) constant->start);
         | 
| 266 | 
            +
                            constant->start = start;
         | 
| 267 | 
            +
                            bucket->type = (unsigned int) (RBS_CONSTANT_POOL_BUCKET_DEFAULT & 0x3);
         | 
| 268 | 
            +
                        }
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                        return bucket->id;
         | 
| 271 | 
            +
                    }
         | 
| 272 | 
            +
             | 
| 273 | 
            +
                    index = (index + 1) & mask;
         | 
| 274 | 
            +
                }
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                // IDs are allocated starting at 1, since the value 0 denotes a non-existent
         | 
| 277 | 
            +
                // constant.
         | 
| 278 | 
            +
                uint32_t id = ++pool->size;
         | 
| 279 | 
            +
                assert(pool->size < ((uint32_t) (1 << 30)));
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                *bucket = (rbs_constant_pool_bucket_t) {
         | 
| 282 | 
            +
                    .id = (unsigned int) (id & 0x3fffffff),
         | 
| 283 | 
            +
                    .type = (unsigned int) (type & 0x3),
         | 
| 284 | 
            +
                    .hash = hash
         | 
| 285 | 
            +
                };
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                pool->constants[id - 1] = (rbs_constant_t) {
         | 
| 288 | 
            +
                    .start = start,
         | 
| 289 | 
            +
                    .length = length,
         | 
| 290 | 
            +
                };
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                return id;
         | 
| 293 | 
            +
            }
         | 
| 294 | 
            +
             | 
| 295 | 
            +
            /**
         | 
| 296 | 
            +
             * Insert a constant into a constant pool. Returns the id of the constant, or
         | 
| 297 | 
            +
             * RBS_CONSTANT_ID_UNSET if any potential calls to resize fail.
         | 
| 298 | 
            +
             */
         | 
| 299 | 
            +
            rbs_constant_id_t
         | 
| 300 | 
            +
            rbs_constant_pool_insert_shared(rbs_constant_pool_t *pool, const uint8_t *start, size_t length) {
         | 
| 301 | 
            +
                return rbs_constant_pool_insert(pool, start, length, RBS_CONSTANT_POOL_BUCKET_DEFAULT);
         | 
| 302 | 
            +
            }
         | 
| 303 | 
            +
             | 
| 304 | 
            +
            /**
         | 
| 305 | 
            +
             * Insert a constant into a constant pool from memory that is now owned by the
         | 
| 306 | 
            +
             * constant pool. Returns the id of the constant, or RBS_CONSTANT_ID_UNSET if any
         | 
| 307 | 
            +
             * potential calls to resize fail.
         | 
| 308 | 
            +
             */
         | 
| 309 | 
            +
            rbs_constant_id_t
         | 
| 310 | 
            +
            rbs_constant_pool_insert_owned(rbs_constant_pool_t *pool, uint8_t *start, size_t length) {
         | 
| 311 | 
            +
                return rbs_constant_pool_insert(pool, start, length, RBS_CONSTANT_POOL_BUCKET_OWNED);
         | 
| 312 | 
            +
            }
         | 
| 313 | 
            +
             | 
| 314 | 
            +
            /**
         | 
| 315 | 
            +
             * Insert a constant into a constant pool from memory that is constant. Returns
         | 
| 316 | 
            +
             * the id of the constant, or RBS_CONSTANT_ID_UNSET if any potential calls to
         | 
| 317 | 
            +
             * resize fail.
         | 
| 318 | 
            +
             */
         | 
| 319 | 
            +
            rbs_constant_id_t
         | 
| 320 | 
            +
            rbs_constant_pool_insert_constant(rbs_constant_pool_t *pool, const uint8_t *start, size_t length) {
         | 
| 321 | 
            +
                return rbs_constant_pool_insert(pool, start, length, RBS_CONSTANT_POOL_BUCKET_CONSTANT);
         | 
| 322 | 
            +
            }
         | 
| 323 | 
            +
             | 
| 324 | 
            +
            /**
         | 
| 325 | 
            +
             * Free the memory associated with a constant pool.
         | 
| 326 | 
            +
             */
         | 
| 327 | 
            +
            void
         | 
| 328 | 
            +
            rbs_constant_pool_free(rbs_constant_pool_t *pool) {
         | 
| 329 | 
            +
                // For each constant in the current constant pool, free the contents if the
         | 
| 330 | 
            +
                // contents are owned.
         | 
| 331 | 
            +
                for (uint32_t index = 0; index < pool->capacity; index++) {
         | 
| 332 | 
            +
                    rbs_constant_pool_bucket_t *bucket = &pool->buckets[index];
         | 
| 333 | 
            +
             | 
| 334 | 
            +
                    // If an id is set on this constant, then we know we have content here.
         | 
| 335 | 
            +
                    if (bucket->id != RBS_CONSTANT_ID_UNSET && bucket->type == RBS_CONSTANT_POOL_BUCKET_OWNED) {
         | 
| 336 | 
            +
                        rbs_constant_t *constant = &pool->constants[bucket->id - 1];
         | 
| 337 | 
            +
                        free((void *) constant->start);
         | 
| 338 | 
            +
                    }
         | 
| 339 | 
            +
                }
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                free(pool->buckets);
         | 
| 342 | 
            +
            }
         | 
    
        data/stdlib/cgi/0/core.rbs
    CHANGED
    
    | @@ -931,6 +931,11 @@ class CGI | |
| 931 931 | 
             
                #
         | 
| 932 932 | 
             
                def escapeURIComponent: (string) -> String
         | 
| 933 933 |  | 
| 934 | 
            +
                # <!-- rdoc-file=ext/cgi/escape/escape.c -->
         | 
| 935 | 
            +
                # Returns URL-escaped string following RFC 3986.
         | 
| 936 | 
            +
                #
         | 
| 937 | 
            +
                alias escape_uri_component escapeURIComponent
         | 
| 938 | 
            +
             | 
| 934 939 | 
             
                # <!--
         | 
| 935 940 | 
             
                #   rdoc-file=ext/cgi/escape/escape.c
         | 
| 936 941 | 
             
                #   - CGI.unescape(string, encoding=@@accept_charset) -> string
         | 
| @@ -954,6 +959,11 @@ class CGI | |
| 954 959 | 
             
                # Returns URL-unescaped string following RFC 3986.
         | 
| 955 960 | 
             
                #
         | 
| 956 961 | 
             
                def unescapeURIComponent: (string) -> String
         | 
| 962 | 
            +
             | 
| 963 | 
            +
                # <!-- rdoc-file=ext/cgi/escape/escape.c -->
         | 
| 964 | 
            +
                # Returns URL-unescaped string following RFC 3986.
         | 
| 965 | 
            +
                #
         | 
| 966 | 
            +
                alias unescape_uri_component unescapeURIComponent
         | 
| 957 967 | 
             
              end
         | 
| 958 968 |  | 
| 959 969 | 
             
              # <!-- rdoc-file=lib/cgi/core.rb -->
         |