diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index acb66d1e4d..032eb81d2a 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -83,6 +83,37 @@ jobs: - name: Run test run: | bundle exec rake ${{ matrix.job }} + ffi_backend: + runs-on: "ubuntu-latest" + strategy: + fail-fast: false + matrix: + include: + # The FFI backend on MRI, forced with RBS_FFI_BACKEND=1. This is + # the cheap lane that catches most FFI backend regressions. + - ruby: "4.0" + rbs_ffi_backend: "1" + # The FFI backend on JRuby, where it is the only backend. + - ruby: jruby + rbs_ffi_backend: "" + env: + RBS_FFI_BACKEND: ${{ matrix.rbs_ffi_backend }} + # The main Gemfile pulls in development gems whose C extensions cannot + # be built on JRuby; this lane only needs the parser test subset. + BUNDLE_GEMFILE: gemfiles/ffi_backend.gemfile + steps: + - uses: actions/checkout@v6 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler: none + - name: Set working directory as safe + run: git config --global --add safe.directory $(pwd) + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + - name: Run parser tests + run: bundle exec rake test:parser + C99_compile: runs-on: macos-latest strategy: diff --git a/.gitignore b/.gitignore index 3d723e6d4b..9d69830780 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ lib/**/*.bundle lib/**/*.so lib/**/*.dll +lib/**/*.dylib doc/ **/*.gem @@ -29,3 +30,4 @@ ext/rbs_extension/.cache # Rust crate vendored RBS source (managed by rake rust:rbs:sync or rust:rbs:symlink) rust/ruby-rbs-sys/vendor/rbs/ rust/ruby-rbs/vendor/rbs/ +gemfiles/*.gemfile.lock diff --git a/Gemfile b/Gemfile index d35624b748..d6d754c172 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,9 @@ gem "activesupport", "~> 7.0" gem "extconf_compile_commands_json" gem "irb" +# FFI parser backend (non-MRI implementations, or RBS_FFI_BACKEND=1 on MRI) +gem "ffi", require: false + group :libs do # Libraries required for stdlib test gem "abbrev" diff --git a/Gemfile.lock b/Gemfile.lock index 0d48270be9..7581d7c27a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -204,6 +204,7 @@ DEPENDENCIES dbm digest extconf_compile_commands_json + ffi fileutils goodcheck irb diff --git a/Rakefile b/Rakefile index 5a2e13af78..53b0173589 100644 --- a/Rakefile +++ b/Rakefile @@ -37,6 +37,37 @@ Rake::TestTask.new(test: :compile, &test_config) multitask :default => [:test, :stdlib_test, :typecheck_test, :rubocop, :validate, :test_doc] +namespace :compile do + desc "Build the core parser as a shared library (librbs) for the FFI backend" + task :librbs do + require "tmpdir" + extconf = File.join(__dir__, "ext/rbs_extension/extconf.rb") + Dir.mktmpdir do |dir| + Dir.chdir(dir) do + sh({ "RBS_FFI_BACKEND" => "1" }, ruby, extconf) + end + end + end +end + +# The parser-focused test subset, used as the acceptance suite for the FFI +# backend (RBS_FFI_BACKEND=1 on MRI, or non-MRI implementations). +Rake::TestTask.new(:"test:parser") do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList[ + "test/rbs/buffer_test.rb", + "test/rbs/location_test.rb", + "test/rbs/parser_test.rb", + "test/rbs/type_parsing_test.rb", + "test/rbs/method_type_parsing_test.rb", + "test/rbs/signature_parsing_test.rb", + "test/rbs/inline_annotation_parsing_test.rb", + "test/rbs/inline_parser_test.rb", + ] +end +task :"test:parser" => (RUBY_ENGINE != "ruby" || !ENV["RBS_FFI_BACKEND"].to_s.empty? ? :"compile:librbs" : :compile) + task :lexer do sh "re2c -W --no-generation-date -o src/lexer.c src/lexer.re" sh "clang-format -i -style=file src/lexer.c" @@ -48,8 +79,8 @@ task :confirm_lexer => :lexer do end task :confirm_templates => :templates do - puts "Testing if generated code under include and src is updated with respect to templates" - sh "git diff --exit-code -- include src" + puts "Testing if generated code under include, src and lib is updated with respect to templates" + sh "git diff --exit-code -- include src lib/rbs/parser/deserializer.rb" end # Task to format C code using clang-format @@ -160,6 +191,9 @@ task :templates do sh "#{ruby} templates/template.rb include/rbs/ast.h" sh "#{ruby} templates/template.rb src/ast.c" + sh "#{ruby} templates/template.rb src/serializer.c" + sh "#{ruby} templates/template.rb lib/rbs/parser/deserializer.rb" + # Format the generated files Rake::Task["format:c"].invoke end diff --git a/Steepfile b/Steepfile index b00e4542b0..80126f9c3d 100644 --- a/Steepfile +++ b/Steepfile @@ -6,6 +6,13 @@ target :lib do ignore( "lib/rbs/test", # "lib/rbs/test.rb" + + # The FFI backend depends on the ffi gem, which has no RBS signatures, + # and the deserializer is generated code. The pure-Ruby Location mirrors + # the C extension implementation, which is not type checked either. + "lib/rbs/parser/ffi.rb", + "lib/rbs/parser/deserializer.rb", + "lib/rbs/location.rb", ) library "pathname", "json", "logger", "monitor", "tsort", "uri", 'dbm', 'pstore', 'singleton', 'shellwords', 'fileutils', 'find', 'digest', 'prettyprint', 'yaml', "psych", "securerandom" diff --git a/ext/rbs_extension/extconf.rb b/ext/rbs_extension/extconf.rb index 0977b8c4ab..232e3a564e 100644 --- a/ext/rbs_extension/extconf.rb +++ b/ext/rbs_extension/extconf.rb @@ -1,40 +1,88 @@ -require 'mkmf' +if RUBY_ENGINE == "ruby" && ENV["RBS_FFI_BACKEND"].to_s.empty? + require 'mkmf' -$INCFLAGS << " -I$(top_srcdir)" if $extmk -$INCFLAGS << " -I$(srcdir)/../../include" + $INCFLAGS << " -I$(top_srcdir)" if $extmk + $INCFLAGS << " -I$(srcdir)/../../include" -$VPATH << "$(srcdir)/../../src" -$VPATH << "$(srcdir)/../../src/util" -$VPATH << "$(srcdir)/ext/rbs_extension" + $VPATH << "$(srcdir)/../../src" + $VPATH << "$(srcdir)/../../src/util" + $VPATH << "$(srcdir)/ext/rbs_extension" -root_dir = File.expand_path('../../../', __FILE__) -$srcs = Dir.glob("#{root_dir}/src/**/*.c") + - Dir.glob("#{root_dir}/ext/rbs_extension/*.c") + root_dir = File.expand_path('../../../', __FILE__) + $srcs = Dir.glob("#{root_dir}/src/**/*.c") + + Dir.glob("#{root_dir}/ext/rbs_extension/*.c") -append_cflags [ - '-std=gnu99', - '-Wimplicit-fallthrough', - '-Wunused-result', - '-Wc++-compat', - '-Wnullable-to-nonnull-conversion', -] + append_cflags [ + '-std=gnu99', + '-Wimplicit-fallthrough', + '-Wunused-result', + '-Wc++-compat', + '-Wnullable-to-nonnull-conversion', + ] -if ENV['DEBUG'] - append_cflags ['-O0', '-pg'] + if ENV['DEBUG'] + append_cflags ['-O0', '-pg'] + else + append_cflags ['-DNDEBUG'] + end + if ENV["TEST_NO_C23"] + puts "Adding -Wc2x-extensions to CFLAGS" + $CFLAGS << " -Werror -Wc2x-extensions" + end + + create_makefile 'rbs_extension' + + # Only generate compile_commands.json when compiling through Rake tasks + # This is to avoid adding extconf_compile_commands_json as a runtime dependency + if ENV["COMPILE_COMMANDS_JSON"] + require 'extconf_compile_commands_json' + ExtconfCompileCommandsJson.generate! + ExtconfCompileCommandsJson.symlink! + end else - append_cflags ['-DNDEBUG'] -end -if ENV["TEST_NO_C23"] - puts "Adding -Wc2x-extensions to CFLAGS" - $CFLAGS << " -Werror -Wc2x-extensions" -end + # Non-MRI implementations (JRuby, TruffleRuby) cannot load MRI C extensions. + # Instead, build the Ruby-independent core parser (src/ only, no + # ext/rbs_extension/ sources) as a plain shared library, loaded at runtime + # through the ffi gem by lib/rbs/parser/ffi.rb. + # + # Setting RBS_FFI_BACKEND=1 forces this path on MRI, which is how the FFI + # backend is developed and tested without a JRuby installation. + require 'rbconfig' + + root_dir = File.expand_path('../../../', __FILE__) + + soext = RbConfig::CONFIG["SOEXT"] || + (RbConfig::CONFIG["host_os"] =~ /darwin/ ? "dylib" : "so") + cc = RbConfig::CONFIG["CC"] || ENV["CC"] || "cc" + output = File.join(root_dir, "lib", "rbs", "librbs.#{soext}") + + sources = Dir.glob("#{root_dir}/src/**/*.c") + + command = [ + cc, + "-O2", + "-fPIC", + "-std=gnu99", + "-fvisibility=default", + "-DNDEBUG", + "-I#{root_dir}/include", + "-shared", + "-o", output, + *sources, + ] -create_makefile 'rbs_extension' + puts "Building librbs for the FFI backend: #{output}" + puts command.join(" ") + system(*command) or raise "Failed to build librbs with: #{command.join(" ")}" -# Only generate compile_commands.json when compiling through Rake tasks -# This is to avoid adding extconf_compile_commands_json as a runtime dependency -if ENV["COMPILE_COMMANDS_JSON"] - require 'extconf_compile_commands_json' - ExtconfCompileCommandsJson.generate! - ExtconfCompileCommandsJson.symlink! + # RubyGems expects extconf.rb to produce a Makefile; librbs is already + # built at this point, so all targets are no-ops. + File.write("Makefile", <<~MAKEFILE) + all: + \t@true + install: + \t@true + clean: + \t@true + MAKEFILE end diff --git a/gemfiles/ffi_backend.gemfile b/gemfiles/ffi_backend.gemfile new file mode 100644 index 0000000000..9ea40c02db --- /dev/null +++ b/gemfiles/ffi_backend.gemfile @@ -0,0 +1,19 @@ +# Minimal Gemfile for the FFI parser backend CI lane (`rake test:parser` on +# JRuby, or on MRI with RBS_FFI_BACKEND=1). +# +# The main Gemfile pulls in development gems whose C extensions cannot be +# built on JRuby (e.g. zlib via rubocop-on-rbs, bigdecimal via +# activesupport), so this lane installs only what the parser test subset +# needs. + +source "https://rubygems.org" + +gemspec path: "../" + +gem "rake" +gem "rake-compiler" # Required by the Rakefile (rake/extensiontask) +gem "test-unit" + +# Used by the backend when forced on MRI with RBS_FFI_BACKEND=1; JRuby and +# TruffleRuby bundle ffi as a default gem. +gem "ffi", require: false diff --git a/include/rbs/serializer.h b/include/rbs/serializer.h new file mode 100644 index 0000000000..b427583afe --- /dev/null +++ b/include/rbs/serializer.h @@ -0,0 +1,40 @@ +#ifndef RBS__SERIALIZER_H +#define RBS__SERIALIZER_H + +#include "rbs/ast.h" +#include "rbs/util/rbs_buffer.h" +#include "rbs/util/rbs_constant_pool.h" + +/** + * Serializes AST nodes into a compact binary format, consumed by the + * pure-Ruby deserializer of the FFI parser backend + * (lib/rbs/parser/deserializer.rb). + * + * The format is private to RBS: it is produced and consumed by the same gem + * version, with both sides generated from config.yml, and carries no + * versioning or compatibility guarantees. All integers are little-endian, + * independent of the host platform. + */ +typedef struct { + rbs_allocator_t *allocator; + rbs_buffer_t *buffer; + const rbs_constant_pool_t *constant_pool; +} rbs_serializer_t; + +void rbs_serializer_write_u8(rbs_serializer_t *serializer, uint8_t value); +void rbs_serializer_write_u32(rbs_serializer_t *serializer, uint32_t value); +void rbs_serializer_write_i32(rbs_serializer_t *serializer, int32_t value); +void rbs_serializer_write_string(rbs_serializer_t *serializer, rbs_string_t string); + +/** + * Writes the serialized representation of the given node (or 0 for NULL) + * into the serializer's buffer. + */ +void rbs_serializer_write_node(rbs_serializer_t *serializer, const rbs_node_t *node); + +/** + * Writes a node list: u32 element count followed by each node. + */ +void rbs_serializer_write_node_list(rbs_serializer_t *serializer, rbs_node_list_t *list); + +#endif diff --git a/lib/rbs.rb b/lib/rbs.rb index bbc8c8382c..7b633339b3 100644 --- a/lib/rbs.rb +++ b/lib/rbs.rb @@ -69,7 +69,14 @@ require "rbs/type_alias_regularity" require "rbs/collection" -require "rbs_extension" +if RUBY_ENGINE == "ruby" && ENV["RBS_FFI_BACKEND"].to_s.empty? + require "rbs_extension" +else + # Non-MRI implementations cannot load the C extension. Load the FFI-based + # parser backend and the pure-Ruby RBS::Location instead. + require "rbs/location" + require "rbs/parser/ffi" +end require "rbs/parser_aux" require "rbs/location_aux" diff --git a/lib/rbs/location.rb b/lib/rbs/location.rb new file mode 100644 index 0000000000..297dec4368 --- /dev/null +++ b/lib/rbs/location.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +# Pure-Ruby implementation of RBS::Location, used by the FFI backend on +# non-MRI Ruby implementations. On MRI the same class is implemented by the +# C extension (ext/rbs_extension/legacy_location.c); this file must match its +# behavior exactly. Common convenience methods live in location_aux.rb, which +# is loaded on top of either implementation. + +module RBS + class Location + private def initialize(buffer, start_pos, end_pos) + @buffer = buffer + @rg_start = start_pos + @rg_end = end_pos + @children = nil + end + + private def initialize_copy(other) + @buffer = other.buffer + @rg_start = other._start_pos + @rg_end = other._end_pos + @children = other.instance_variable_get(:@children)&.map(&:dup) + nil + end + + attr_reader :buffer + + def _start_pos + @rg_start + end + + def _end_pos + @rg_end + end + + # Children are stored as a flat ordered list of + # `[name, start_pos, end_pos, required]` entries that permits duplicate + # names; `[]` returns the first match in insertion order. + + private def _add_required_child(name, start_pos, end_pos) + (@children ||= []) << [name, start_pos, end_pos, true] + nil + end + + private def _add_optional_child(name, start_pos, end_pos) + (@children ||= []) << [name, start_pos, end_pos, false] + nil + end + + private def _add_optional_no_child(name) + (@children ||= []) << [name, -1, -1, false] + nil + end + + private def _optional_keys + children = @children or return [] + children.reject {|child| child[3] }.map {|child| child[0] } + end + + private def _required_keys + children = @children or return [] + children.select {|child| child[3] }.map {|child| child[0] } + end + + def [](name) + if children = @children + children.each do |child| + if child[0] == name + if !child[3] && child[1] == -1 + return nil + else + return Location.new(@buffer, child[1], child[2]) + end + end + end + end + + raise "Unknown child name given: #{name}" + end + end +end diff --git a/lib/rbs/parser/deserializer.rb b/lib/rbs/parser/deserializer.rb new file mode 100644 index 0000000000..aaab0c09e6 --- /dev/null +++ b/lib/rbs/parser/deserializer.rb @@ -0,0 +1,1366 @@ +# frozen_string_literal: true + +#------------------------------------------------------------------------------ +# This file is generated by the templates/template.rb script and should not +# be modified manually. +# To change the template see +# templates/lib/rbs/parser/deserializer.rb.erb +#------------------------------------------------------------------------------ + +module RBS + class Parser + # Decodes the binary AST representation produced by src/serializer.c + # (generated from templates/src/serializer.c.erb) into Ruby AST objects, + # mirroring the translation done in C by + # ext/rbs_extension/ast_translation.c for the MRI extension. + # + # Used by the FFI parser backend (lib/rbs/parser/ffi.rb) on non-MRI Ruby + # implementations. + class Deserializer + EMPTY_ARRAY = [].freeze + EMPTY_HASH = {}.freeze + + ATTRIBUTE_VISIBILITY = [nil, :public, :private].freeze + ATTRIBUTE_KIND = [:instance, :singleton].freeze + ALIAS_KIND = [:instance, :singleton].freeze + METHOD_DEFINITION_KIND = [:instance, :singleton, :singleton_instance].freeze + METHOD_DEFINITION_VISIBILITY = [nil, :public, :private].freeze + TYPE_PARAM_VARIANCE = [:invariant, :covariant, :contravariant].freeze + + def initialize(buffer:, reader:) + @buffer = buffer + @reader = reader + @encoding = buffer.content.encoding + end + + def read_node + tag = @reader.read_u8 + case tag + when 0 + nil + when 1 # RBS::AST::Annotation + read_rbs_ast_annotation + when 2 # RBS::AST::Bool + read_rbs_ast_bool + when 3 # RBS::AST::Comment + read_rbs_ast_comment + when 4 # RBS::AST::Declarations::Class + read_rbs_ast_declarations_class + when 5 # RBS::AST::Declarations::Class::Super + read_rbs_ast_declarations_class_super + when 6 # RBS::AST::Declarations::ClassAlias + read_rbs_ast_declarations_class_alias + when 7 # RBS::AST::Declarations::Constant + read_rbs_ast_declarations_constant + when 8 # RBS::AST::Declarations::Global + read_rbs_ast_declarations_global + when 9 # RBS::AST::Declarations::Interface + read_rbs_ast_declarations_interface + when 10 # RBS::AST::Declarations::Module + read_rbs_ast_declarations_module + when 11 # RBS::AST::Declarations::Module::Self + read_rbs_ast_declarations_module_self + when 12 # RBS::AST::Declarations::ModuleAlias + read_rbs_ast_declarations_module_alias + when 13 # RBS::AST::Declarations::TypeAlias + read_rbs_ast_declarations_type_alias + when 14 # RBS::AST::Directives::Use + read_rbs_ast_directives_use + when 15 # RBS::AST::Directives::Use::SingleClause + read_rbs_ast_directives_use_single_clause + when 16 # RBS::AST::Directives::Use::WildcardClause + read_rbs_ast_directives_use_wildcard_clause + when 17 # RBS::AST::Integer + read_rbs_ast_integer + when 18 # RBS::AST::Members::Alias + read_rbs_ast_members_alias + when 19 # RBS::AST::Members::AttrAccessor + read_rbs_ast_members_attr_accessor + when 20 # RBS::AST::Members::AttrReader + read_rbs_ast_members_attr_reader + when 21 # RBS::AST::Members::AttrWriter + read_rbs_ast_members_attr_writer + when 22 # RBS::AST::Members::ClassInstanceVariable + read_rbs_ast_members_class_instance_variable + when 23 # RBS::AST::Members::ClassVariable + read_rbs_ast_members_class_variable + when 24 # RBS::AST::Members::Extend + read_rbs_ast_members_extend + when 25 # RBS::AST::Members::Include + read_rbs_ast_members_include + when 26 # RBS::AST::Members::InstanceVariable + read_rbs_ast_members_instance_variable + when 27 # RBS::AST::Members::MethodDefinition + read_rbs_ast_members_method_definition + when 28 # RBS::AST::Members::MethodDefinition::Overload + read_rbs_ast_members_method_definition_overload + when 29 # RBS::AST::Members::Prepend + read_rbs_ast_members_prepend + when 30 # RBS::AST::Members::Private + read_rbs_ast_members_private + when 31 # RBS::AST::Members::Public + read_rbs_ast_members_public + when 32 # RBS::AST::Ruby::Annotations::BlockParamTypeAnnotation + read_rbs_ast_ruby_annotations_block_param_type_annotation + when 33 # RBS::AST::Ruby::Annotations::ClassAliasAnnotation + read_rbs_ast_ruby_annotations_class_alias_annotation + when 34 # RBS::AST::Ruby::Annotations::ColonMethodTypeAnnotation + read_rbs_ast_ruby_annotations_colon_method_type_annotation + when 35 # RBS::AST::Ruby::Annotations::DoubleSplatParamTypeAnnotation + read_rbs_ast_ruby_annotations_double_splat_param_type_annotation + when 36 # RBS::AST::Ruby::Annotations::InstanceVariableAnnotation + read_rbs_ast_ruby_annotations_instance_variable_annotation + when 37 # RBS::AST::Ruby::Annotations::MethodTypesAnnotation + read_rbs_ast_ruby_annotations_method_types_annotation + when 38 # RBS::AST::Ruby::Annotations::ModuleAliasAnnotation + read_rbs_ast_ruby_annotations_module_alias_annotation + when 39 # RBS::AST::Ruby::Annotations::ModuleSelfAnnotation + read_rbs_ast_ruby_annotations_module_self_annotation + when 40 # RBS::AST::Ruby::Annotations::NodeTypeAssertion + read_rbs_ast_ruby_annotations_node_type_assertion + when 41 # RBS::AST::Ruby::Annotations::ParamTypeAnnotation + read_rbs_ast_ruby_annotations_param_type_annotation + when 42 # RBS::AST::Ruby::Annotations::ReturnTypeAnnotation + read_rbs_ast_ruby_annotations_return_type_annotation + when 43 # RBS::AST::Ruby::Annotations::SkipAnnotation + read_rbs_ast_ruby_annotations_skip_annotation + when 44 # RBS::AST::Ruby::Annotations::SplatParamTypeAnnotation + read_rbs_ast_ruby_annotations_splat_param_type_annotation + when 45 # RBS::AST::Ruby::Annotations::TypeApplicationAnnotation + read_rbs_ast_ruby_annotations_type_application_annotation + when 46 # RBS::AST::String + read_rbs_ast_string + when 47 # RBS::AST::TypeParam + read_rbs_ast_type_param + when 48 # RBS::MethodType + read_rbs_method_type + when 49 # RBS::Namespace + read_rbs_namespace + when 50 # RBS::Signature + read_rbs_signature + when 51 # RBS::TypeName + read_rbs_type_name + when 52 # RBS::Types::Alias + read_rbs_types_alias + when 53 # RBS::Types::Bases::Any + read_rbs_types_bases_any + when 54 # RBS::Types::Bases::Bool + read_rbs_types_bases_bool + when 55 # RBS::Types::Bases::Bottom + read_rbs_types_bases_bottom + when 56 # RBS::Types::Bases::Class + read_rbs_types_bases_class + when 57 # RBS::Types::Bases::Instance + read_rbs_types_bases_instance + when 58 # RBS::Types::Bases::Nil + read_rbs_types_bases_nil + when 59 # RBS::Types::Bases::Self + read_rbs_types_bases_self + when 60 # RBS::Types::Bases::Top + read_rbs_types_bases_top + when 61 # RBS::Types::Bases::Void + read_rbs_types_bases_void + when 62 # RBS::Types::Block + read_rbs_types_block + when 63 # RBS::Types::ClassInstance + read_rbs_types_class_instance + when 64 # RBS::Types::ClassSingleton + read_rbs_types_class_singleton + when 65 # RBS::Types::Function + read_rbs_types_function + when 66 # RBS::Types::Function::Param + read_rbs_types_function_param + when 67 # RBS::Types::Interface + read_rbs_types_interface + when 68 # RBS::Types::Intersection + read_rbs_types_intersection + when 69 # RBS::Types::Literal + read_rbs_types_literal + when 70 # RBS::Types::Optional + read_rbs_types_optional + when 71 # RBS::Types::Proc + read_rbs_types_proc + when 72 # RBS::Types::Record + read_rbs_types_record + when 73 # RBS::Types::Record::FieldType + read_rbs_types_record_field_type + when 74 # RBS::Types::Tuple + read_rbs_types_tuple + when 75 # RBS::Types::Union + read_rbs_types_union + when 76 # RBS::Types::UntypedFunction + read_rbs_types_untyped_function + when 77 # RBS::Types::Variable + read_rbs_types_variable + when 78 # Symbol + read_symbol + else + raise "Unknown node tag: #{tag}" + end + end + + def read_node_list + Array.new(@reader.read_u32) { read_node } + end + + private + + def read_symbol + @reader.read_string.force_encoding(@encoding).to_sym + end + + def read_location + start_char = @reader.read_i32 + end_char = @reader.read_i32 + if start_char == -1 + nil + else + Location.new(@buffer, start_char, end_char) + end + end + + def add_required_child(location, name) + start_char = @reader.read_i32 + end_char = @reader.read_i32 + location.add_required_child(name, start_char...end_char) + end + + def add_optional_child(location, name) + start_char = @reader.read_i32 + end_char = @reader.read_i32 + if start_char == -1 + location.add_optional_child(name, nil) + else + location.add_optional_child(name, start_char...end_char) + end + end + + def read_hash + count = @reader.read_u32 + if count == 0 + EMPTY_HASH + else + hash = {} + count.times do + key = read_node + hash[key] = read_node + end + hash + end + end + + def read_location_range_list + if @reader.read_u8 == 0 + EMPTY_ARRAY + else + Array.new(@reader.read_u32) { read_location } + end + end + + def read_ivar_name + case @reader.read_u8 + when 0 # unspecified + nil + when 1 # empty + false + else + read_symbol + end + end + + def read_rbs_ast_annotation + location = read_location + string = @reader.read_string.force_encoding(@encoding) + RBS::AST::Annotation.new( + location: location, + string: string, + ) + end + + def read_rbs_ast_bool + @reader.read_u8 != 0 + end + + def read_rbs_ast_comment + location = read_location + string = @reader.read_string.force_encoding(@encoding) + RBS::AST::Comment.new( + location: location, + string: string, + ) + end + + def read_rbs_ast_declarations_class + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :end) + add_optional_child(location, :type_params) + add_optional_child(location, :lt) + name = read_node # rbs_type_name + type_params = read_node_list + super_class = read_node # rbs_ast_declarations_class_super + members = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + AST::TypeParam.resolve_variables(type_params) + RBS::AST::Declarations::Class.new( + location: location, + name: name, + type_params: type_params, + super_class: super_class, + members: members, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_declarations_class_super + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + RBS::AST::Declarations::Class::Super.new( + location: location, + name: name, + args: args, + ) + end + + def read_rbs_ast_declarations_class_alias + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :new_name) + add_required_child(location, :eq) + add_required_child(location, :old_name) + new_name = read_node # rbs_type_name + old_name = read_node # rbs_type_name + comment = read_node # rbs_ast_comment + annotations = read_node_list + RBS::AST::Declarations::ClassAlias.new( + location: location, + new_name: new_name, + old_name: old_name, + comment: comment, + annotations: annotations, + ) + end + + def read_rbs_ast_declarations_constant + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :colon) + name = read_node # rbs_type_name + type = read_node # rbs_node + comment = read_node # rbs_ast_comment + annotations = read_node_list + RBS::AST::Declarations::Constant.new( + location: location, + name: name, + type: type, + comment: comment, + annotations: annotations, + ) + end + + def read_rbs_ast_declarations_global + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :colon) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + comment = read_node # rbs_ast_comment + annotations = read_node_list + RBS::AST::Declarations::Global.new( + location: location, + name: name, + type: type, + comment: comment, + annotations: annotations, + ) + end + + def read_rbs_ast_declarations_interface + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :end) + add_optional_child(location, :type_params) + name = read_node # rbs_type_name + type_params = read_node_list + members = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + AST::TypeParam.resolve_variables(type_params) + RBS::AST::Declarations::Interface.new( + location: location, + name: name, + type_params: type_params, + members: members, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_declarations_module + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :end) + add_optional_child(location, :type_params) + add_optional_child(location, :colon) + add_optional_child(location, :self_types) + name = read_node # rbs_type_name + type_params = read_node_list + self_types = read_node_list + members = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + AST::TypeParam.resolve_variables(type_params) + RBS::AST::Declarations::Module.new( + location: location, + name: name, + type_params: type_params, + self_types: self_types, + members: members, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_declarations_module_self + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + RBS::AST::Declarations::Module::Self.new( + location: location, + name: name, + args: args, + ) + end + + def read_rbs_ast_declarations_module_alias + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :new_name) + add_required_child(location, :eq) + add_required_child(location, :old_name) + new_name = read_node # rbs_type_name + old_name = read_node # rbs_type_name + comment = read_node # rbs_ast_comment + annotations = read_node_list + RBS::AST::Declarations::ModuleAlias.new( + location: location, + new_name: new_name, + old_name: old_name, + comment: comment, + annotations: annotations, + ) + end + + def read_rbs_ast_declarations_type_alias + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :eq) + add_optional_child(location, :type_params) + name = read_node # rbs_type_name + type_params = read_node_list + type = read_node # rbs_node + annotations = read_node_list + comment = read_node # rbs_ast_comment + AST::TypeParam.resolve_variables(type_params) + RBS::AST::Declarations::TypeAlias.new( + location: location, + name: name, + type_params: type_params, + type: type, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_directives_use + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + clauses = read_node_list + RBS::AST::Directives::Use.new( + location: location, + clauses: clauses, + ) + end + + def read_rbs_ast_directives_use_single_clause + location = read_location + raise "location is missing" unless location + add_required_child(location, :type_name) + add_optional_child(location, :keyword) + add_optional_child(location, :new_name) + type_name = read_node # rbs_type_name + new_name = read_node # rbs_ast_symbol + RBS::AST::Directives::Use::SingleClause.new( + location: location, + type_name: type_name, + new_name: new_name, + ) + end + + def read_rbs_ast_directives_use_wildcard_clause + location = read_location + raise "location is missing" unless location + add_required_child(location, :namespace) + add_required_child(location, :star) + namespace = read_node # rbs_namespace + RBS::AST::Directives::Use::WildcardClause.new( + location: location, + namespace: namespace, + ) + end + + def read_rbs_ast_integer + @reader.read_string.force_encoding(Encoding::UTF_8).to_i + end + + def read_rbs_ast_members_alias + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :new_name) + add_required_child(location, :old_name) + add_optional_child(location, :new_kind) + add_optional_child(location, :old_kind) + new_name = read_node # rbs_ast_symbol + old_name = read_node # rbs_ast_symbol + kind = ALIAS_KIND.fetch(@reader.read_u8) + annotations = read_node_list + comment = read_node # rbs_ast_comment + RBS::AST::Members::Alias.new( + location: location, + new_name: new_name, + old_name: old_name, + kind: kind, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_members_attr_accessor + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :colon) + add_optional_child(location, :kind) + add_optional_child(location, :ivar) + add_optional_child(location, :ivar_name) + add_optional_child(location, :visibility) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + ivar_name = read_ivar_name + kind = ATTRIBUTE_KIND.fetch(@reader.read_u8) + annotations = read_node_list + comment = read_node # rbs_ast_comment + visibility = ATTRIBUTE_VISIBILITY.fetch(@reader.read_u8) + RBS::AST::Members::AttrAccessor.new( + location: location, + name: name, + type: type, + ivar_name: ivar_name, + kind: kind, + annotations: annotations, + comment: comment, + visibility: visibility, + ) + end + + def read_rbs_ast_members_attr_reader + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :colon) + add_optional_child(location, :kind) + add_optional_child(location, :ivar) + add_optional_child(location, :ivar_name) + add_optional_child(location, :visibility) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + ivar_name = read_ivar_name + kind = ATTRIBUTE_KIND.fetch(@reader.read_u8) + annotations = read_node_list + comment = read_node # rbs_ast_comment + visibility = ATTRIBUTE_VISIBILITY.fetch(@reader.read_u8) + RBS::AST::Members::AttrReader.new( + location: location, + name: name, + type: type, + ivar_name: ivar_name, + kind: kind, + annotations: annotations, + comment: comment, + visibility: visibility, + ) + end + + def read_rbs_ast_members_attr_writer + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_required_child(location, :colon) + add_optional_child(location, :kind) + add_optional_child(location, :ivar) + add_optional_child(location, :ivar_name) + add_optional_child(location, :visibility) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + ivar_name = read_ivar_name + kind = ATTRIBUTE_KIND.fetch(@reader.read_u8) + annotations = read_node_list + comment = read_node # rbs_ast_comment + visibility = ATTRIBUTE_VISIBILITY.fetch(@reader.read_u8) + RBS::AST::Members::AttrWriter.new( + location: location, + name: name, + type: type, + ivar_name: ivar_name, + kind: kind, + annotations: annotations, + comment: comment, + visibility: visibility, + ) + end + + def read_rbs_ast_members_class_instance_variable + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :colon) + add_optional_child(location, :kind) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + comment = read_node # rbs_ast_comment + RBS::AST::Members::ClassInstanceVariable.new( + location: location, + name: name, + type: type, + comment: comment, + ) + end + + def read_rbs_ast_members_class_variable + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :colon) + add_optional_child(location, :kind) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + comment = read_node # rbs_ast_comment + RBS::AST::Members::ClassVariable.new( + location: location, + name: name, + type: type, + comment: comment, + ) + end + + def read_rbs_ast_members_extend + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :keyword) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + RBS::AST::Members::Extend.new( + location: location, + name: name, + args: args, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_members_include + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :keyword) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + RBS::AST::Members::Include.new( + location: location, + name: name, + args: args, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_members_instance_variable + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :colon) + add_optional_child(location, :kind) + name = read_node # rbs_ast_symbol + type = read_node # rbs_node + comment = read_node # rbs_ast_comment + RBS::AST::Members::InstanceVariable.new( + location: location, + name: name, + type: type, + comment: comment, + ) + end + + def read_rbs_ast_members_method_definition + location = read_location + raise "location is missing" unless location + add_required_child(location, :keyword) + add_required_child(location, :name) + add_optional_child(location, :kind) + add_optional_child(location, :overloading) + add_optional_child(location, :visibility) + name = read_node # rbs_ast_symbol + kind = METHOD_DEFINITION_KIND.fetch(@reader.read_u8) + overloads = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + overloading = @reader.read_u8 != 0 + visibility = METHOD_DEFINITION_VISIBILITY.fetch(@reader.read_u8) + RBS::AST::Members::MethodDefinition.new( + location: location, + name: name, + kind: kind, + overloads: overloads, + annotations: annotations, + comment: comment, + overloading: overloading, + visibility: visibility, + ) + end + + def read_rbs_ast_members_method_definition_overload + annotations = read_node_list + method_type = read_node # rbs_node + RBS::AST::Members::MethodDefinition::Overload.new( + annotations: annotations, + method_type: method_type, + ) + end + + def read_rbs_ast_members_prepend + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_required_child(location, :keyword) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + annotations = read_node_list + comment = read_node # rbs_ast_comment + RBS::AST::Members::Prepend.new( + location: location, + name: name, + args: args, + annotations: annotations, + comment: comment, + ) + end + + def read_rbs_ast_members_private + location = read_location + RBS::AST::Members::Private.new( + location: location, + ) + end + + def read_rbs_ast_members_public + location = read_location + RBS::AST::Members::Public.new( + location: location, + ) + end + + def read_rbs_ast_ruby_annotations_block_param_type_annotation + location = read_location + prefix_location = read_location + ampersand_location = read_location + name_location = read_location + colon_location = read_location + question_location = read_location + type_location = read_location + type = read_node # rbs_node + comment_location = read_location + RBS::AST::Ruby::Annotations::BlockParamTypeAnnotation.new( + location: location, + prefix_location: prefix_location, + ampersand_location: ampersand_location, + name_location: name_location, + colon_location: colon_location, + question_location: question_location, + type_location: type_location, + type: type, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_class_alias_annotation + location = read_location + prefix_location = read_location + keyword_location = read_location + type_name = read_node # rbs_type_name + type_name_location = read_location + RBS::AST::Ruby::Annotations::ClassAliasAnnotation.new( + location: location, + prefix_location: prefix_location, + keyword_location: keyword_location, + type_name: type_name, + type_name_location: type_name_location, + ) + end + + def read_rbs_ast_ruby_annotations_colon_method_type_annotation + location = read_location + prefix_location = read_location + annotations = read_node_list + method_type = read_node # rbs_node + RBS::AST::Ruby::Annotations::ColonMethodTypeAnnotation.new( + location: location, + prefix_location: prefix_location, + annotations: annotations, + method_type: method_type, + ) + end + + def read_rbs_ast_ruby_annotations_double_splat_param_type_annotation + location = read_location + prefix_location = read_location + star2_location = read_location + name_location = read_location + colon_location = read_location + param_type = read_node # rbs_node + comment_location = read_location + RBS::AST::Ruby::Annotations::DoubleSplatParamTypeAnnotation.new( + location: location, + prefix_location: prefix_location, + star2_location: star2_location, + name_location: name_location, + colon_location: colon_location, + param_type: param_type, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_instance_variable_annotation + location = read_location + prefix_location = read_location + ivar_name = read_node # rbs_ast_symbol + ivar_name_location = read_location + colon_location = read_location + type = read_node # rbs_node + comment_location = read_location + RBS::AST::Ruby::Annotations::InstanceVariableAnnotation.new( + location: location, + prefix_location: prefix_location, + ivar_name: ivar_name, + ivar_name_location: ivar_name_location, + colon_location: colon_location, + type: type, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_method_types_annotation + location = read_location + prefix_location = read_location + overloads = read_node_list + vertical_bar_locations = read_location_range_list + dot3_location = read_location + RBS::AST::Ruby::Annotations::MethodTypesAnnotation.new( + location: location, + prefix_location: prefix_location, + overloads: overloads, + vertical_bar_locations: vertical_bar_locations, + dot3_location: dot3_location, + ) + end + + def read_rbs_ast_ruby_annotations_module_alias_annotation + location = read_location + prefix_location = read_location + keyword_location = read_location + type_name = read_node # rbs_type_name + type_name_location = read_location + RBS::AST::Ruby::Annotations::ModuleAliasAnnotation.new( + location: location, + prefix_location: prefix_location, + keyword_location: keyword_location, + type_name: type_name, + type_name_location: type_name_location, + ) + end + + def read_rbs_ast_ruby_annotations_module_self_annotation + location = read_location + prefix_location = read_location + keyword_location = read_location + colon_location = read_location + name = read_node # rbs_type_name + args = read_node_list + open_bracket_location = read_location + close_bracket_location = read_location + args_comma_locations = read_location_range_list + comment_location = read_location + RBS::AST::Ruby::Annotations::ModuleSelfAnnotation.new( + location: location, + prefix_location: prefix_location, + keyword_location: keyword_location, + colon_location: colon_location, + name: name, + args: args, + open_bracket_location: open_bracket_location, + close_bracket_location: close_bracket_location, + args_comma_locations: args_comma_locations, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_node_type_assertion + location = read_location + prefix_location = read_location + type = read_node # rbs_node + RBS::AST::Ruby::Annotations::NodeTypeAssertion.new( + location: location, + prefix_location: prefix_location, + type: type, + ) + end + + def read_rbs_ast_ruby_annotations_param_type_annotation + location = read_location + prefix_location = read_location + name_location = read_location + colon_location = read_location + param_type = read_node # rbs_node + comment_location = read_location + RBS::AST::Ruby::Annotations::ParamTypeAnnotation.new( + location: location, + prefix_location: prefix_location, + name_location: name_location, + colon_location: colon_location, + param_type: param_type, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_return_type_annotation + location = read_location + prefix_location = read_location + return_location = read_location + colon_location = read_location + return_type = read_node # rbs_node + comment_location = read_location + RBS::AST::Ruby::Annotations::ReturnTypeAnnotation.new( + location: location, + prefix_location: prefix_location, + return_location: return_location, + colon_location: colon_location, + return_type: return_type, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_skip_annotation + location = read_location + prefix_location = read_location + skip_location = read_location + comment_location = read_location + RBS::AST::Ruby::Annotations::SkipAnnotation.new( + location: location, + prefix_location: prefix_location, + skip_location: skip_location, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_splat_param_type_annotation + location = read_location + prefix_location = read_location + star_location = read_location + name_location = read_location + colon_location = read_location + param_type = read_node # rbs_node + comment_location = read_location + RBS::AST::Ruby::Annotations::SplatParamTypeAnnotation.new( + location: location, + prefix_location: prefix_location, + star_location: star_location, + name_location: name_location, + colon_location: colon_location, + param_type: param_type, + comment_location: comment_location, + ) + end + + def read_rbs_ast_ruby_annotations_type_application_annotation + location = read_location + prefix_location = read_location + type_args = read_node_list + close_bracket_location = read_location + comma_locations = read_location_range_list + RBS::AST::Ruby::Annotations::TypeApplicationAnnotation.new( + location: location, + prefix_location: prefix_location, + type_args: type_args, + close_bracket_location: close_bracket_location, + comma_locations: comma_locations, + ) + end + + def read_rbs_ast_string + @reader.read_string.force_encoding(Encoding::UTF_8) + end + + def read_rbs_ast_type_param + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :variance) + add_optional_child(location, :unchecked) + add_optional_child(location, :upper_bound) + add_optional_child(location, :lower_bound) + add_optional_child(location, :default) + name = read_node # rbs_ast_symbol + variance = TYPE_PARAM_VARIANCE.fetch(@reader.read_u8) + upper_bound = read_node # rbs_node + lower_bound = read_node # rbs_node + default_type = read_node # rbs_node + unchecked = @reader.read_u8 != 0 + RBS::AST::TypeParam.new( + location: location, + name: name, + variance: variance, + upper_bound: upper_bound, + lower_bound: lower_bound, + default_type: default_type, + unchecked: unchecked, + ) + end + + def read_rbs_method_type + location = read_location + raise "location is missing" unless location + add_required_child(location, :type) + add_optional_child(location, :type_params) + type_params = read_node_list + type = read_node # rbs_node + block = read_node # rbs_types_block + AST::TypeParam.resolve_variables(type_params) + RBS::MethodType.new( + location: location, + type_params: type_params, + type: type, + block: block, + ) + end + + def read_rbs_namespace + path = read_node_list + absolute = @reader.read_u8 != 0 + Namespace[path, absolute] + end + + def read_rbs_signature + directives = read_node_list + declarations = read_node_list + [directives, declarations] + end + + def read_rbs_type_name + namespace = read_node + name = read_node + TypeName[namespace, name] + end + + def read_rbs_types_alias + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + RBS::Types::Alias.new( + location: location, + name: name, + args: args, + ) + end + + def read_rbs_types_bases_any + location = read_location + todo = @reader.read_u8 != 0 + RBS::Types::Bases::Any.new( + location: location, + todo: todo, + ) + end + + def read_rbs_types_bases_bool + location = read_location + RBS::Types::Bases::Bool.new( + location: location, + ) + end + + def read_rbs_types_bases_bottom + location = read_location + RBS::Types::Bases::Bottom.new( + location: location, + ) + end + + def read_rbs_types_bases_class + location = read_location + RBS::Types::Bases::Class.new( + location: location, + ) + end + + def read_rbs_types_bases_instance + location = read_location + RBS::Types::Bases::Instance.new( + location: location, + ) + end + + def read_rbs_types_bases_nil + location = read_location + RBS::Types::Bases::Nil.new( + location: location, + ) + end + + def read_rbs_types_bases_self + location = read_location + RBS::Types::Bases::Self.new( + location: location, + ) + end + + def read_rbs_types_bases_top + location = read_location + RBS::Types::Bases::Top.new( + location: location, + ) + end + + def read_rbs_types_bases_void + location = read_location + RBS::Types::Bases::Void.new( + location: location, + ) + end + + def read_rbs_types_block + location = read_location + type = read_node # rbs_node + required = @reader.read_u8 != 0 + self_type = read_node # rbs_node + RBS::Types::Block.new( + location: location, + type: type, + required: required, + self_type: self_type, + ) + end + + def read_rbs_types_class_instance + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + RBS::Types::ClassInstance.new( + location: location, + name: name, + args: args, + ) + end + + def read_rbs_types_class_singleton + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + RBS::Types::ClassSingleton.new( + location: location, + name: name, + args: args, + ) + end + + def read_rbs_types_function + required_positionals = read_node_list + optional_positionals = read_node_list + rest_positionals = read_node # rbs_node + trailing_positionals = read_node_list + required_keywords = read_hash + optional_keywords = read_hash + rest_keywords = read_node # rbs_node + return_type = read_node # rbs_node + RBS::Types::Function.new( + required_positionals: required_positionals, + optional_positionals: optional_positionals, + rest_positionals: rest_positionals, + trailing_positionals: trailing_positionals, + required_keywords: required_keywords, + optional_keywords: optional_keywords, + rest_keywords: rest_keywords, + return_type: return_type, + ) + end + + def read_rbs_types_function_param + location = read_location + raise "location is missing" unless location + add_optional_child(location, :name) + type = read_node # rbs_node + name = read_node # rbs_ast_symbol + RBS::Types::Function::Param.new( + location: location, + type: type, + name: name, + ) + end + + def read_rbs_types_interface + location = read_location + raise "location is missing" unless location + add_required_child(location, :name) + add_optional_child(location, :args) + name = read_node # rbs_type_name + args = read_node_list + RBS::Types::Interface.new( + location: location, + name: name, + args: args, + ) + end + + def read_rbs_types_intersection + location = read_location + types = read_node_list + RBS::Types::Intersection.new( + location: location, + types: types, + ) + end + + def read_rbs_types_literal + location = read_location + literal = read_node # rbs_node + RBS::Types::Literal.new( + location: location, + literal: literal, + ) + end + + def read_rbs_types_optional + location = read_location + type = read_node # rbs_node + RBS::Types::Optional.new( + location: location, + type: type, + ) + end + + def read_rbs_types_proc + location = read_location + type = read_node # rbs_node + block = read_node # rbs_types_block + self_type = read_node # rbs_node + RBS::Types::Proc.new( + location: location, + type: type, + block: block, + self_type: self_type, + ) + end + + def read_rbs_types_record + location = read_location + all_fields = read_hash + RBS::Types::Record.new( + location: location, + all_fields: all_fields, + ) + end + + def read_rbs_types_record_field_type + type = read_node + required = @reader.read_u8 != 0 + [type, required] + end + + def read_rbs_types_tuple + location = read_location + types = read_node_list + RBS::Types::Tuple.new( + location: location, + types: types, + ) + end + + def read_rbs_types_union + location = read_location + types = read_node_list + RBS::Types::Union.new( + location: location, + types: types, + ) + end + + def read_rbs_types_untyped_function + return_type = read_node # rbs_node + RBS::Types::UntypedFunction.new( + return_type: return_type, + ) + end + + def read_rbs_types_variable + location = read_location + name = read_node # rbs_ast_symbol + RBS::Types::Variable.new( + location: location, + name: name, + ) + end + + end + end +end diff --git a/lib/rbs/parser/ffi.rb b/lib/rbs/parser/ffi.rb new file mode 100644 index 0000000000..025105e4a6 --- /dev/null +++ b/lib/rbs/parser/ffi.rb @@ -0,0 +1,220 @@ +# frozen_string_literal: true + +# FFI backend for non-MRI Ruby implementations (JRuby, TruffleRuby). +# +# This file defines the same `RBS::Parser._parse_*` / `._lex` singleton +# methods as the C extension (ext/rbs_extension/main.c), backed by the core +# parser built as a plain shared library (librbs, see +# ext/rbs_extension/extconf.rb). Results cross the FFI boundary as a +# serialized byte buffer produced by src/ffi_entry.c, which is decoded here +# and by RBS::Parser::Deserializer. +# +# Set RBS_FFI_BACKEND=1 to use this backend on MRI for development/testing. + +require "ffi" +require "rbs/parser/deserializer" + +module RBS + class Parser + module FFIBackend + extend ::FFI::Library + + STATUS_SUCCESS = 0 + STATUS_ERROR = 1 + STATUS_NIL = 2 + + soext = RbConfig::CONFIG["SOEXT"] || + (RbConfig::CONFIG["host_os"] =~ /darwin/ ? "dylib" : "so") + ffi_lib File.expand_path("../librbs.#{soext}", __dir__) + + attach_function :rbs_ffi_lex, [:pointer, :size_t, :string, :int], :pointer + attach_function :rbs_ffi_parse_type, [:pointer, :size_t, :string, :int, :int, :pointer, :bool, :bool, :bool, :bool], :pointer + attach_function :rbs_ffi_parse_method_type, [:pointer, :size_t, :string, :int, :int, :pointer, :bool], :pointer + attach_function :rbs_ffi_parse_signature, [:pointer, :size_t, :string, :int, :int], :pointer + attach_function :rbs_ffi_parse_type_params, [:pointer, :size_t, :string, :int, :int, :bool], :pointer + attach_function :rbs_ffi_parse_inline_leading_annotation, [:pointer, :size_t, :string, :int, :int, :pointer], :pointer + attach_function :rbs_ffi_parse_inline_trailing_annotation, [:pointer, :size_t, :string, :int, :int, :pointer], :pointer + attach_function :rbs_ffi_result_bytes, [:pointer], :pointer + attach_function :rbs_ffi_result_length, [:pointer], :size_t + attach_function :rbs_ffi_result_free, [:pointer], :void + + # Calls the named one-shot entry point with the buffer content and + # returns the serialized result as a binary String. The native result + # is released before returning. + def self.fetch_result(name, content, *args) + source = ::FFI::MemoryPointer.from_string(content) + result = public_send(name, source, content.bytesize, content.encoding.name, *args) + begin + rbs_ffi_result_bytes(result).read_string(rbs_ffi_result_length(result)) + ensure + rbs_ffi_result_free(result) + end + end + + # Mirrors `validate_position_range()` in ext/rbs_extension/main.c. + def self.validate_position_range(start_pos, end_pos) + if start_pos < 0 || end_pos < 0 + raise ArgumentError, "negative position range: #{start_pos}...#{end_pos}" + end + if start_pos > end_pos + raise ArgumentError, "invalid position range: #{start_pos}...#{end_pos}" + end + end + + # Packs an array of type variable Symbols into the binary layout + # consumed by `declare_type_variables()` in src/ffi_entry.c: u32 count, + # then (u32 length, bytes) per name. Returns nil for nil input. + # Type checks mirror `declare_type_variables()` in + # ext/rbs_extension/main.c. + def self.pack_variables(variables) + return nil if variables.nil? + + unless variables.is_a?(Array) + raise TypeError, "wrong argument type #{variables.class} (must be an Array of Symbols or nil)" + end + + packed = [variables.size].pack("L<") + variables.each do |variable| + unless variable.is_a?(Symbol) + raise TypeError, "Type variables Array contains invalid value #{variable.inspect} of type #{variable.class} (must be an Array of Symbols or nil)" + end + + name = variable.to_s + packed << [name.bytesize].pack("L<") << name.b + end + + ::FFI::MemoryPointer.from_string(packed) + end + + # Decodes a serialized parse result: returns the deserialized node (or + # node list with list: true) on success, nil for the nil status, and + # raises RBS::ParsingError for parse errors. + def self.decode(buffer, bytes, list: false) + reader = Reader.new(bytes) + + case reader.read_u8 + when STATUS_SUCCESS + deserializer = Deserializer.new(buffer: buffer, reader: reader) + list ? deserializer.read_node_list : deserializer.read_node + when STATUS_NIL + nil + when STATUS_ERROR + raise_error(buffer, reader) + end + end + + # Mirrors `raise_error()` in ext/rbs_extension/main.c. + def self.raise_error(buffer, reader) + syntax_error = reader.read_u8 != 0 + message = reader.read_string.force_encoding(Encoding::UTF_8) + token_type = reader.read_string.force_encoding(Encoding::UTF_8) + start_char = reader.read_i32 + end_char = reader.read_i32 + + raise "Unexpected error" unless syntax_error + + location = Location.new(buffer, start_char, end_char) + raise ParsingError.new(location, message, token_type) + end + + # Sequential decoder for the byte format written by src/ffi_entry.c and + # src/serializer.c. All integers are little-endian. + class Reader + def initialize(bytes) + @bytes = bytes + @pos = 0 + end + + def read_u8 + value = @bytes.getbyte(@pos) or raise "Unexpected end of serialized parser result" + @pos += 1 + value + end + + def read_u32 + raw = @bytes.byteslice(@pos, 4) or raise "Unexpected end of serialized parser result" + @pos += 4 + raw.unpack1("L<") + end + + def read_i32 + raw = @bytes.byteslice(@pos, 4) or raise "Unexpected end of serialized parser result" + @pos += 4 + raw.unpack1("l<") + end + + def read_string + length = read_u32 + value = @bytes.byteslice(@pos, length) or raise "Unexpected end of serialized parser result" + @pos += length + value + end + end + end + + def self._lex(buffer, end_pos) + content = buffer.content + reader = FFIBackend::Reader.new(FFIBackend.fetch_result(:rbs_ffi_lex, content, end_pos)) + + reader.read_u8 # status: lexing always succeeds + + Array.new(reader.read_u32) do + type = reader.read_string.to_sym + start_char = reader.read_i32 + end_char = reader.read_i32 + [type, Location.new(buffer, start_char, end_char)] + end + end + + def self._parse_type(buffer, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed) + FFIBackend.validate_position_range(start_pos, end_pos) + vars = FFIBackend.pack_variables(variables) + bytes = FFIBackend.fetch_result( + :rbs_ffi_parse_type, buffer.content, start_pos, end_pos, vars, + !!require_eof, !!void_allowed, !!self_allowed, !!classish_allowed + ) + FFIBackend.decode(buffer, bytes) + end + + def self._parse_method_type(buffer, start_pos, end_pos, variables, require_eof) + FFIBackend.validate_position_range(start_pos, end_pos) + vars = FFIBackend.pack_variables(variables) + bytes = FFIBackend.fetch_result( + :rbs_ffi_parse_method_type, buffer.content, start_pos, end_pos, vars, !!require_eof + ) + FFIBackend.decode(buffer, bytes) + end + + def self._parse_signature(buffer, start_pos, end_pos) + FFIBackend.validate_position_range(start_pos, end_pos) + bytes = FFIBackend.fetch_result(:rbs_ffi_parse_signature, buffer.content, start_pos, end_pos) + FFIBackend.decode(buffer, bytes) + end + + def self._parse_type_params(buffer, start_pos, end_pos, module_type_params) + FFIBackend.validate_position_range(start_pos, end_pos) + bytes = FFIBackend.fetch_result( + :rbs_ffi_parse_type_params, buffer.content, start_pos, end_pos, !!module_type_params + ) + FFIBackend.decode(buffer, bytes, list: true) + end + + def self._parse_inline_leading_annotation(buffer, start_pos, end_pos, variables) + FFIBackend.validate_position_range(start_pos, end_pos) + vars = FFIBackend.pack_variables(variables) + bytes = FFIBackend.fetch_result( + :rbs_ffi_parse_inline_leading_annotation, buffer.content, start_pos, end_pos, vars + ) + FFIBackend.decode(buffer, bytes) + end + + def self._parse_inline_trailing_annotation(buffer, start_pos, end_pos, variables) + FFIBackend.validate_position_range(start_pos, end_pos) + vars = FFIBackend.pack_variables(variables) + bytes = FFIBackend.fetch_result( + :rbs_ffi_parse_inline_trailing_annotation, buffer.content, start_pos, end_pos, vars + ) + FFIBackend.decode(buffer, bytes) + end + end +end diff --git a/sig/location.rbs b/sig/location.rbs index d27bb616b0..30440baa6d 100644 --- a/sig/location.rbs +++ b/sig/location.rbs @@ -130,6 +130,15 @@ module RBS def _optional_keys: () -> Array[Symbol] def _required_keys: () -> Array[Symbol] + def initialize_copy: (instance) -> void + + # Instance variables of the pure-Ruby implementation (lib/rbs/location.rb), + # which is loaded instead of the C extension on non-MRI Ruby implementations. + @buffer: Buffer + @rg_start: Integer + @rg_end: Integer + @children: Array[[Symbol, Integer, Integer, bool]]? + WithChildren: singleton(Location) end end diff --git a/src/ast.c b/src/ast.c index 7e52681910..aa49b9d7df 100644 --- a/src/ast.c +++ b/src/ast.c @@ -271,6 +271,8 @@ void rbs_hash_set(rbs_hash_t *RBS_NONNULL hash, rbs_node_t *RBS_NONNULL key, rbs hash->tail->next = new_node; hash->tail = new_node; } + + hash->length++; } rbs_node_t *RBS_NULLABLE rbs_hash_get(rbs_hash_t *RBS_NONNULL hash, rbs_node_t *RBS_NONNULL key) { @@ -292,7 +294,7 @@ rbs_ast_symbol_t *RBS_NONNULL rbs_ast_symbol_new(rbs_allocator_t *RBS_NONNULL al return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_annotation_t *RBS_NONNULL rbs_ast_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_string_t string) { rbs_ast_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_annotation_t); @@ -306,7 +308,7 @@ rbs_ast_annotation_t *RBS_NONNULL rbs_ast_annotation_new(rbs_allocator_t *RBS_NO return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_bool_t *RBS_NONNULL rbs_ast_bool_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, bool value) { rbs_ast_bool_t *instance = rbs_allocator_alloc(allocator, rbs_ast_bool_t); @@ -320,7 +322,7 @@ rbs_ast_bool_t *RBS_NONNULL rbs_ast_bool_new(rbs_allocator_t *RBS_NONNULL alloca return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_comment_t *RBS_NONNULL rbs_ast_comment_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_string_t string) { rbs_ast_comment_t *instance = rbs_allocator_alloc(allocator, rbs_ast_comment_t); @@ -334,7 +336,7 @@ rbs_ast_comment_t *RBS_NONNULL rbs_ast_comment_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_class_t *RBS_NONNULL rbs_ast_declarations_class_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL type_params, rbs_ast_declarations_class_super_t *RBS_NULLABLE super_class, rbs_node_list_t *RBS_NONNULL members, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range end_range) { rbs_ast_declarations_class_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_class_t); @@ -358,7 +360,7 @@ rbs_ast_declarations_class_t *RBS_NONNULL rbs_ast_declarations_class_new(rbs_all return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_class_super_t *RBS_NONNULL rbs_ast_declarations_class_super_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range) { rbs_ast_declarations_class_super_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_class_super_t); @@ -375,7 +377,7 @@ rbs_ast_declarations_class_super_t *RBS_NONNULL rbs_ast_declarations_class_super return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_class_alias_t *RBS_NONNULL rbs_ast_declarations_class_alias_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL new_name, rbs_type_name_t *RBS_NONNULL old_name, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_node_list_t *RBS_NONNULL annotations, rbs_location_range keyword_range, rbs_location_range new_name_range, rbs_location_range eq_range, rbs_location_range old_name_range) { rbs_ast_declarations_class_alias_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_class_alias_t); @@ -396,7 +398,7 @@ rbs_ast_declarations_class_alias_t *RBS_NONNULL rbs_ast_declarations_class_alias return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_constant_t *RBS_NONNULL rbs_ast_declarations_constant_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_node_list_t *RBS_NONNULL annotations, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_declarations_constant_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_constant_t); @@ -415,7 +417,7 @@ rbs_ast_declarations_constant_t *RBS_NONNULL rbs_ast_declarations_constant_new(r return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_global_t *RBS_NONNULL rbs_ast_declarations_global_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_node_list_t *RBS_NONNULL annotations, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_declarations_global_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_global_t); @@ -434,7 +436,7 @@ rbs_ast_declarations_global_t *RBS_NONNULL rbs_ast_declarations_global_new(rbs_a return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_interface_t *RBS_NONNULL rbs_ast_declarations_interface_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL type_params, rbs_node_list_t *RBS_NONNULL members, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range end_range) { rbs_ast_declarations_interface_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_interface_t); @@ -456,7 +458,7 @@ rbs_ast_declarations_interface_t *RBS_NONNULL rbs_ast_declarations_interface_new return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_module_t *RBS_NONNULL rbs_ast_declarations_module_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL type_params, rbs_node_list_t *RBS_NONNULL self_types, rbs_node_list_t *RBS_NONNULL members, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range end_range) { rbs_ast_declarations_module_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_module_t); @@ -481,7 +483,7 @@ rbs_ast_declarations_module_t *RBS_NONNULL rbs_ast_declarations_module_new(rbs_a return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_module_self_t *RBS_NONNULL rbs_ast_declarations_module_self_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range) { rbs_ast_declarations_module_self_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_module_self_t); @@ -498,7 +500,7 @@ rbs_ast_declarations_module_self_t *RBS_NONNULL rbs_ast_declarations_module_self return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_module_alias_t *RBS_NONNULL rbs_ast_declarations_module_alias_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL new_name, rbs_type_name_t *RBS_NONNULL old_name, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_node_list_t *RBS_NONNULL annotations, rbs_location_range keyword_range, rbs_location_range new_name_range, rbs_location_range eq_range, rbs_location_range old_name_range) { rbs_ast_declarations_module_alias_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_module_alias_t); @@ -519,7 +521,7 @@ rbs_ast_declarations_module_alias_t *RBS_NONNULL rbs_ast_declarations_module_ali return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_declarations_type_alias_t *RBS_NONNULL rbs_ast_declarations_type_alias_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL type_params, rbs_node_t *RBS_NONNULL type, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range eq_range) { rbs_ast_declarations_type_alias_t *instance = rbs_allocator_alloc(allocator, rbs_ast_declarations_type_alias_t); @@ -541,7 +543,7 @@ rbs_ast_declarations_type_alias_t *RBS_NONNULL rbs_ast_declarations_type_alias_n return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_directives_use_t *RBS_NONNULL rbs_ast_directives_use_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL clauses, rbs_location_range keyword_range) { rbs_ast_directives_use_t *instance = rbs_allocator_alloc(allocator, rbs_ast_directives_use_t); @@ -556,7 +558,7 @@ rbs_ast_directives_use_t *RBS_NONNULL rbs_ast_directives_use_new(rbs_allocator_t return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_directives_use_single_clause_t *RBS_NONNULL rbs_ast_directives_use_single_clause_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL type_name, rbs_ast_symbol_t *RBS_NULLABLE new_name, rbs_location_range type_name_range) { rbs_ast_directives_use_single_clause_t *instance = rbs_allocator_alloc(allocator, rbs_ast_directives_use_single_clause_t); @@ -574,7 +576,7 @@ rbs_ast_directives_use_single_clause_t *RBS_NONNULL rbs_ast_directives_use_singl return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_directives_use_wildcard_clause_t *RBS_NONNULL rbs_ast_directives_use_wildcard_clause_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_namespace_t *RBS_NONNULL rbs_namespace, rbs_location_range namespace_range, rbs_location_range star_range) { rbs_ast_directives_use_wildcard_clause_t *instance = rbs_allocator_alloc(allocator, rbs_ast_directives_use_wildcard_clause_t); @@ -590,7 +592,7 @@ rbs_ast_directives_use_wildcard_clause_t *RBS_NONNULL rbs_ast_directives_use_wil return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_integer_t *RBS_NONNULL rbs_ast_integer_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_string_t string_representation) { rbs_ast_integer_t *instance = rbs_allocator_alloc(allocator, rbs_ast_integer_t); @@ -604,7 +606,7 @@ rbs_ast_integer_t *RBS_NONNULL rbs_ast_integer_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_alias_t *RBS_NONNULL rbs_ast_members_alias_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL new_name, rbs_ast_symbol_t *RBS_NONNULL old_name, enum rbs_alias_kind kind, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range keyword_range, rbs_location_range new_name_range, rbs_location_range old_name_range) { rbs_ast_members_alias_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_alias_t); @@ -627,7 +629,7 @@ rbs_ast_members_alias_t *RBS_NONNULL rbs_ast_members_alias_new(rbs_allocator_t * return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_attr_accessor_t *RBS_NONNULL rbs_ast_members_attr_accessor_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_attr_ivar_name_t ivar_name, enum rbs_attribute_kind kind, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, enum rbs_attribute_visibility visibility, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_members_attr_accessor_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_attr_accessor_t); @@ -654,7 +656,7 @@ rbs_ast_members_attr_accessor_t *RBS_NONNULL rbs_ast_members_attr_accessor_new(r return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_attr_reader_t *RBS_NONNULL rbs_ast_members_attr_reader_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_attr_ivar_name_t ivar_name, enum rbs_attribute_kind kind, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, enum rbs_attribute_visibility visibility, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_members_attr_reader_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_attr_reader_t); @@ -681,7 +683,7 @@ rbs_ast_members_attr_reader_t *RBS_NONNULL rbs_ast_members_attr_reader_new(rbs_a return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_attr_writer_t *RBS_NONNULL rbs_ast_members_attr_writer_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_attr_ivar_name_t ivar_name, enum rbs_attribute_kind kind, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, enum rbs_attribute_visibility visibility, rbs_location_range keyword_range, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_members_attr_writer_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_attr_writer_t); @@ -708,7 +710,7 @@ rbs_ast_members_attr_writer_t *RBS_NONNULL rbs_ast_members_attr_writer_new(rbs_a return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_class_instance_variable_t *RBS_NONNULL rbs_ast_members_class_instance_variable_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_members_class_instance_variable_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_class_instance_variable_t); @@ -727,7 +729,7 @@ rbs_ast_members_class_instance_variable_t *RBS_NONNULL rbs_ast_members_class_ins return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_class_variable_t *RBS_NONNULL rbs_ast_members_class_variable_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_members_class_variable_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_class_variable_t); @@ -746,7 +748,7 @@ rbs_ast_members_class_variable_t *RBS_NONNULL rbs_ast_members_class_variable_new return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_extend_t *RBS_NONNULL rbs_ast_members_extend_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range name_range, rbs_location_range keyword_range) { rbs_ast_members_extend_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_extend_t); @@ -766,7 +768,7 @@ rbs_ast_members_extend_t *RBS_NONNULL rbs_ast_members_extend_new(rbs_allocator_t return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_include_t *RBS_NONNULL rbs_ast_members_include_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range name_range, rbs_location_range keyword_range) { rbs_ast_members_include_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_include_t); @@ -786,7 +788,7 @@ rbs_ast_members_include_t *RBS_NONNULL rbs_ast_members_include_new(rbs_allocator return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_instance_variable_t *RBS_NONNULL rbs_ast_members_instance_variable_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, rbs_node_t *RBS_NONNULL type, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range name_range, rbs_location_range colon_range) { rbs_ast_members_instance_variable_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_instance_variable_t); @@ -805,7 +807,7 @@ rbs_ast_members_instance_variable_t *RBS_NONNULL rbs_ast_members_instance_variab return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_method_definition_t *RBS_NONNULL rbs_ast_members_method_definition_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, enum rbs_method_definition_kind kind, rbs_node_list_t *RBS_NONNULL overloads, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, bool overloading, enum rbs_method_definition_visibility visibility, rbs_location_range keyword_range, rbs_location_range name_range) { rbs_ast_members_method_definition_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_method_definition_t); @@ -830,7 +832,7 @@ rbs_ast_members_method_definition_t *RBS_NONNULL rbs_ast_members_method_definiti return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_method_definition_overload_t *RBS_NONNULL rbs_ast_members_method_definition_overload_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL annotations, rbs_node_t *RBS_NONNULL method_type) { rbs_ast_members_method_definition_overload_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_method_definition_overload_t); @@ -845,7 +847,7 @@ rbs_ast_members_method_definition_overload_t *RBS_NONNULL rbs_ast_members_method return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_prepend_t *RBS_NONNULL rbs_ast_members_prepend_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_node_list_t *RBS_NONNULL annotations, rbs_ast_comment_t *RBS_NULLABLE comment, rbs_location_range name_range, rbs_location_range keyword_range) { rbs_ast_members_prepend_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_prepend_t); @@ -865,7 +867,7 @@ rbs_ast_members_prepend_t *RBS_NONNULL rbs_ast_members_prepend_new(rbs_allocator return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_private_t *RBS_NONNULL rbs_ast_members_private_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_ast_members_private_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_private_t); @@ -878,7 +880,7 @@ rbs_ast_members_private_t *RBS_NONNULL rbs_ast_members_private_new(rbs_allocator return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_members_public_t *RBS_NONNULL rbs_ast_members_public_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_ast_members_public_t *instance = rbs_allocator_alloc(allocator, rbs_ast_members_public_t); @@ -891,7 +893,7 @@ rbs_ast_members_public_t *RBS_NONNULL rbs_ast_members_public_new(rbs_allocator_t return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_block_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_block_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range ampersand_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_location_range question_location, rbs_location_range type_location, rbs_node_t *RBS_NONNULL type_, rbs_location_range comment_location) { rbs_ast_ruby_annotations_block_param_type_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_block_param_type_annotation_t); @@ -912,7 +914,7 @@ rbs_ast_ruby_annotations_block_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_class_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_class_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NONNULL type_name, rbs_location_range type_name_location) { rbs_ast_ruby_annotations_class_alias_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_class_alias_annotation_t); @@ -929,7 +931,7 @@ rbs_ast_ruby_annotations_class_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_anno return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_colon_method_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_colon_method_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_list_t *RBS_NONNULL annotations, rbs_node_t *RBS_NONNULL method_type) { rbs_ast_ruby_annotations_colon_method_type_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_colon_method_type_annotation_t); @@ -945,7 +947,7 @@ rbs_ast_ruby_annotations_colon_method_type_annotation_t *RBS_NONNULL rbs_ast_rub return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_double_splat_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range star2_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL param_type, rbs_location_range comment_location) { rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_double_splat_param_type_annotation_t); @@ -964,7 +966,7 @@ rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *RBS_NONNULL rbs_a return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_instance_variable_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_instance_variable_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_ast_symbol_t *RBS_NONNULL ivar_name, rbs_location_range ivar_name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL type, rbs_location_range comment_location) { rbs_ast_ruby_annotations_instance_variable_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_instance_variable_annotation_t); @@ -983,7 +985,7 @@ rbs_ast_ruby_annotations_instance_variable_annotation_t *RBS_NONNULL rbs_ast_rub return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_method_types_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_method_types_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_list_t *RBS_NONNULL overloads, rbs_location_range_list_t *RBS_NONNULL vertical_bar_locations, rbs_location_range dot3_location) { rbs_ast_ruby_annotations_method_types_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_method_types_annotation_t); @@ -1000,7 +1002,7 @@ rbs_ast_ruby_annotations_method_types_annotation_t *RBS_NONNULL rbs_ast_ruby_ann return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_module_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_alias_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_type_name_t *RBS_NONNULL type_name, rbs_location_range type_name_location) { rbs_ast_ruby_annotations_module_alias_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_module_alias_annotation_t); @@ -1017,7 +1019,7 @@ rbs_ast_ruby_annotations_module_alias_annotation_t *RBS_NONNULL rbs_ast_ruby_ann return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_module_self_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_module_self_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range keyword_location, rbs_location_range colon_location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range open_bracket_location, rbs_location_range close_bracket_location, rbs_location_range_list_t *RBS_NONNULL args_comma_locations, rbs_location_range comment_location) { rbs_ast_ruby_annotations_module_self_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_module_self_annotation_t); @@ -1039,7 +1041,7 @@ rbs_ast_ruby_annotations_module_self_annotation_t *RBS_NONNULL rbs_ast_ruby_anno return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_node_type_assertion_t *RBS_NONNULL rbs_ast_ruby_annotations_node_type_assertion_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_t *RBS_NONNULL type) { rbs_ast_ruby_annotations_node_type_assertion_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_node_type_assertion_t); @@ -1054,7 +1056,7 @@ rbs_ast_ruby_annotations_node_type_assertion_t *RBS_NONNULL rbs_ast_ruby_annotat return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL param_type, rbs_location_range comment_location) { rbs_ast_ruby_annotations_param_type_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_param_type_annotation_t); @@ -1072,7 +1074,7 @@ rbs_ast_ruby_annotations_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annot return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_return_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_return_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range return_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL return_type, rbs_location_range comment_location) { rbs_ast_ruby_annotations_return_type_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_return_type_annotation_t); @@ -1090,7 +1092,7 @@ rbs_ast_ruby_annotations_return_type_annotation_t *RBS_NONNULL rbs_ast_ruby_anno return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_skip_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_skip_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range skip_location, rbs_location_range comment_location) { rbs_ast_ruby_annotations_skip_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_skip_annotation_t); @@ -1106,7 +1108,7 @@ rbs_ast_ruby_annotations_skip_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_splat_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_splat_param_type_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_location_range star_location, rbs_location_range name_location, rbs_location_range colon_location, rbs_node_t *RBS_NONNULL param_type, rbs_location_range comment_location) { rbs_ast_ruby_annotations_splat_param_type_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_splat_param_type_annotation_t); @@ -1125,7 +1127,7 @@ rbs_ast_ruby_annotations_splat_param_type_annotation_t *RBS_NONNULL rbs_ast_ruby return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_ruby_annotations_type_application_annotation_t *RBS_NONNULL rbs_ast_ruby_annotations_type_application_annotation_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_location_range prefix_location, rbs_node_list_t *RBS_NONNULL type_args, rbs_location_range close_bracket_location, rbs_location_range_list_t *RBS_NONNULL comma_locations) { rbs_ast_ruby_annotations_type_application_annotation_t *instance = rbs_allocator_alloc(allocator, rbs_ast_ruby_annotations_type_application_annotation_t); @@ -1142,7 +1144,7 @@ rbs_ast_ruby_annotations_type_application_annotation_t *RBS_NONNULL rbs_ast_ruby return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_string_t *RBS_NONNULL rbs_ast_string_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_string_t string) { rbs_ast_string_t *instance = rbs_allocator_alloc(allocator, rbs_ast_string_t); @@ -1156,7 +1158,7 @@ rbs_ast_string_t *RBS_NONNULL rbs_ast_string_new(rbs_allocator_t *RBS_NONNULL al return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_ast_type_param_t *RBS_NONNULL rbs_ast_type_param_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name, enum rbs_type_param_variance variance, rbs_node_t *RBS_NULLABLE upper_bound, rbs_node_t *RBS_NULLABLE lower_bound, rbs_node_t *RBS_NULLABLE default_type, bool unchecked, rbs_location_range name_range) { rbs_ast_type_param_t *instance = rbs_allocator_alloc(allocator, rbs_ast_type_param_t); @@ -1181,7 +1183,7 @@ rbs_ast_type_param_t *RBS_NONNULL rbs_ast_type_param_new(rbs_allocator_t *RBS_NO return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_method_type_t *RBS_NONNULL rbs_method_type_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL type_params, rbs_node_t *RBS_NONNULL type, rbs_types_block_t *RBS_NULLABLE block, rbs_location_range type_range) { rbs_method_type_t *instance = rbs_allocator_alloc(allocator, rbs_method_type_t); @@ -1199,7 +1201,7 @@ rbs_method_type_t *RBS_NONNULL rbs_method_type_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_namespace_t *RBS_NONNULL rbs_namespace_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL path, bool absolute) { rbs_namespace_t *instance = rbs_allocator_alloc(allocator, rbs_namespace_t); @@ -1214,7 +1216,7 @@ rbs_namespace_t *RBS_NONNULL rbs_namespace_new(rbs_allocator_t *RBS_NONNULL allo return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_signature_t *RBS_NONNULL rbs_signature_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL directives, rbs_node_list_t *RBS_NONNULL declarations) { rbs_signature_t *instance = rbs_allocator_alloc(allocator, rbs_signature_t); @@ -1229,7 +1231,7 @@ rbs_signature_t *RBS_NONNULL rbs_signature_new(rbs_allocator_t *RBS_NONNULL allo return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_type_name_t *RBS_NONNULL rbs_type_name_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_namespace_t *RBS_NONNULL rbs_namespace, rbs_ast_symbol_t *RBS_NONNULL name) { rbs_type_name_t *instance = rbs_allocator_alloc(allocator, rbs_type_name_t); @@ -1244,7 +1246,7 @@ rbs_type_name_t *RBS_NONNULL rbs_type_name_new(rbs_allocator_t *RBS_NONNULL allo return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_alias_t *RBS_NONNULL rbs_types_alias_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range) { rbs_types_alias_t *instance = rbs_allocator_alloc(allocator, rbs_types_alias_t); @@ -1261,7 +1263,7 @@ rbs_types_alias_t *RBS_NONNULL rbs_types_alias_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_any_t *RBS_NONNULL rbs_types_bases_any_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, bool todo) { rbs_types_bases_any_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_any_t); @@ -1275,7 +1277,7 @@ rbs_types_bases_any_t *RBS_NONNULL rbs_types_bases_any_new(rbs_allocator_t *RBS_ return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_bool_t *RBS_NONNULL rbs_types_bases_bool_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_bool_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_bool_t); @@ -1288,7 +1290,7 @@ rbs_types_bases_bool_t *RBS_NONNULL rbs_types_bases_bool_new(rbs_allocator_t *RB return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_bottom_t *RBS_NONNULL rbs_types_bases_bottom_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_bottom_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_bottom_t); @@ -1301,7 +1303,7 @@ rbs_types_bases_bottom_t *RBS_NONNULL rbs_types_bases_bottom_new(rbs_allocator_t return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_class_t *RBS_NONNULL rbs_types_bases_class_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_class_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_class_t); @@ -1314,7 +1316,7 @@ rbs_types_bases_class_t *RBS_NONNULL rbs_types_bases_class_new(rbs_allocator_t * return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_instance_t *RBS_NONNULL rbs_types_bases_instance_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_instance_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_instance_t); @@ -1327,7 +1329,7 @@ rbs_types_bases_instance_t *RBS_NONNULL rbs_types_bases_instance_new(rbs_allocat return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_nil_t *RBS_NONNULL rbs_types_bases_nil_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_nil_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_nil_t); @@ -1340,7 +1342,7 @@ rbs_types_bases_nil_t *RBS_NONNULL rbs_types_bases_nil_new(rbs_allocator_t *RBS_ return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_self_t *RBS_NONNULL rbs_types_bases_self_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_self_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_self_t); @@ -1353,7 +1355,7 @@ rbs_types_bases_self_t *RBS_NONNULL rbs_types_bases_self_new(rbs_allocator_t *RB return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_top_t *RBS_NONNULL rbs_types_bases_top_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_top_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_top_t); @@ -1366,7 +1368,7 @@ rbs_types_bases_top_t *RBS_NONNULL rbs_types_bases_top_new(rbs_allocator_t *RBS_ return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_bases_void_t *RBS_NONNULL rbs_types_bases_void_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location) { rbs_types_bases_void_t *instance = rbs_allocator_alloc(allocator, rbs_types_bases_void_t); @@ -1379,7 +1381,7 @@ rbs_types_bases_void_t *RBS_NONNULL rbs_types_bases_void_new(rbs_allocator_t *RB return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_block_t *RBS_NONNULL rbs_types_block_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type, bool required, rbs_node_t *RBS_NULLABLE self_type) { rbs_types_block_t *instance = rbs_allocator_alloc(allocator, rbs_types_block_t); @@ -1395,7 +1397,7 @@ rbs_types_block_t *RBS_NONNULL rbs_types_block_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_class_instance_t *RBS_NONNULL rbs_types_class_instance_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range) { rbs_types_class_instance_t *instance = rbs_allocator_alloc(allocator, rbs_types_class_instance_t); @@ -1412,7 +1414,7 @@ rbs_types_class_instance_t *RBS_NONNULL rbs_types_class_instance_new(rbs_allocat return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_class_singleton_t *RBS_NONNULL rbs_types_class_singleton_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range) { rbs_types_class_singleton_t *instance = rbs_allocator_alloc(allocator, rbs_types_class_singleton_t); @@ -1429,7 +1431,7 @@ rbs_types_class_singleton_t *RBS_NONNULL rbs_types_class_singleton_new(rbs_alloc return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_function_t *RBS_NONNULL rbs_types_function_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL required_positionals, rbs_node_list_t *RBS_NONNULL optional_positionals, rbs_node_t *RBS_NULLABLE rest_positionals, rbs_node_list_t *RBS_NONNULL trailing_positionals, rbs_hash_t *RBS_NONNULL required_keywords, rbs_hash_t *RBS_NONNULL optional_keywords, rbs_node_t *RBS_NULLABLE rest_keywords, rbs_node_t *RBS_NONNULL return_type) { rbs_types_function_t *instance = rbs_allocator_alloc(allocator, rbs_types_function_t); @@ -1450,7 +1452,7 @@ rbs_types_function_t *RBS_NONNULL rbs_types_function_new(rbs_allocator_t *RBS_NO return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_function_param_t *RBS_NONNULL rbs_types_function_param_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type, rbs_ast_symbol_t *RBS_NULLABLE name) { rbs_types_function_param_t *instance = rbs_allocator_alloc(allocator, rbs_types_function_param_t); @@ -1466,7 +1468,7 @@ rbs_types_function_param_t *RBS_NONNULL rbs_types_function_param_new(rbs_allocat return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_interface_t *RBS_NONNULL rbs_types_interface_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_type_name_t *RBS_NONNULL name, rbs_node_list_t *RBS_NONNULL args, rbs_location_range name_range) { rbs_types_interface_t *instance = rbs_allocator_alloc(allocator, rbs_types_interface_t); @@ -1483,7 +1485,7 @@ rbs_types_interface_t *RBS_NONNULL rbs_types_interface_new(rbs_allocator_t *RBS_ return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_intersection_t *RBS_NONNULL rbs_types_intersection_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL types) { rbs_types_intersection_t *instance = rbs_allocator_alloc(allocator, rbs_types_intersection_t); @@ -1497,7 +1499,7 @@ rbs_types_intersection_t *RBS_NONNULL rbs_types_intersection_new(rbs_allocator_t return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_literal_t *RBS_NONNULL rbs_types_literal_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL literal) { rbs_types_literal_t *instance = rbs_allocator_alloc(allocator, rbs_types_literal_t); @@ -1511,7 +1513,7 @@ rbs_types_literal_t *RBS_NONNULL rbs_types_literal_new(rbs_allocator_t *RBS_NONN return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_optional_t *RBS_NONNULL rbs_types_optional_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type) { rbs_types_optional_t *instance = rbs_allocator_alloc(allocator, rbs_types_optional_t); @@ -1525,7 +1527,7 @@ rbs_types_optional_t *RBS_NONNULL rbs_types_optional_new(rbs_allocator_t *RBS_NO return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_proc_t *RBS_NONNULL rbs_types_proc_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type, rbs_types_block_t *RBS_NULLABLE block, rbs_node_t *RBS_NULLABLE self_type) { rbs_types_proc_t *instance = rbs_allocator_alloc(allocator, rbs_types_proc_t); @@ -1541,7 +1543,7 @@ rbs_types_proc_t *RBS_NONNULL rbs_types_proc_new(rbs_allocator_t *RBS_NONNULL al return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_record_t *RBS_NONNULL rbs_types_record_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_hash_t *RBS_NONNULL all_fields) { rbs_types_record_t *instance = rbs_allocator_alloc(allocator, rbs_types_record_t); @@ -1555,7 +1557,7 @@ rbs_types_record_t *RBS_NONNULL rbs_types_record_new(rbs_allocator_t *RBS_NONNUL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_record_field_type_t *RBS_NONNULL rbs_types_record_field_type_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL type, bool required) { rbs_types_record_field_type_t *instance = rbs_allocator_alloc(allocator, rbs_types_record_field_type_t); @@ -1570,7 +1572,7 @@ rbs_types_record_field_type_t *RBS_NONNULL rbs_types_record_field_type_new(rbs_a return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_tuple_t *RBS_NONNULL rbs_types_tuple_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL types) { rbs_types_tuple_t *instance = rbs_allocator_alloc(allocator, rbs_types_tuple_t); @@ -1584,7 +1586,7 @@ rbs_types_tuple_t *RBS_NONNULL rbs_types_tuple_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_union_t *RBS_NONNULL rbs_types_union_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_list_t *RBS_NONNULL types) { rbs_types_union_t *instance = rbs_allocator_alloc(allocator, rbs_types_union_t); @@ -1598,7 +1600,7 @@ rbs_types_union_t *RBS_NONNULL rbs_types_union_new(rbs_allocator_t *RBS_NONNULL return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_untyped_function_t *RBS_NONNULL rbs_types_untyped_function_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_node_t *RBS_NONNULL return_type) { rbs_types_untyped_function_t *instance = rbs_allocator_alloc(allocator, rbs_types_untyped_function_t); @@ -1612,7 +1614,7 @@ rbs_types_untyped_function_t *RBS_NONNULL rbs_types_untyped_function_new(rbs_all return instance; } -#line 140 "templates/src/ast.c.erb" +#line 142 "templates/src/ast.c.erb" rbs_types_variable_t *RBS_NONNULL rbs_types_variable_new(rbs_allocator_t *RBS_NONNULL allocator, rbs_location_range location, rbs_ast_symbol_t *RBS_NONNULL name) { rbs_types_variable_t *instance = rbs_allocator_alloc(allocator, rbs_types_variable_t); diff --git a/src/ffi_entry.c b/src/ffi_entry.c new file mode 100644 index 0000000000..a55650e176 --- /dev/null +++ b/src/ffi_entry.c @@ -0,0 +1,447 @@ +/** + * FFI entry points for non-MRI Ruby implementations (JRuby, TruffleRuby). + * + * These functions provide a one-shot, Ruby-independent API on top of the + * core parser. Each call parses (or lexes) the given source and returns an + * `rbs_ffi_result_t` holding a serialized byte buffer. The caller reads the + * bytes with `rbs_ffi_result_bytes()` / `rbs_ffi_result_length()` and then + * releases everything with `rbs_ffi_result_free()`. + * + * Each entry point mirrors the control flow of the corresponding + * `rbsparser_*` function in ext/rbs_extension/main.c. + * + * The byte format is private to RBS: it is produced and consumed by the same + * gem version (see lib/rbs/parser/ffi.rb and + * lib/rbs/parser/deserializer.rb), so it carries no versioning or + * compatibility guarantees. + * + * All integers are encoded in little-endian byte order, independent of the + * host platform. + */ + +#include "rbs.h" +#include "rbs/serializer.h" +#include "rbs/util/rbs_buffer.h" +#include "rbs/util/rbs_encoding.h" + +#include +#include +#include + +typedef struct rbs_ffi_result { + rbs_allocator_t *allocator; + rbs_buffer_t buffer; +} rbs_ffi_result_t; + +/* Status bytes prefixed to every result. */ +enum { + RBS_FFI_STATUS_SUCCESS = 0, + RBS_FFI_STATUS_ERROR = 1, + RBS_FFI_STATUS_NIL = 2, +}; + +static rbs_ffi_result_t *rbs_ffi_result_new(void) { + rbs_allocator_t *allocator = rbs_allocator_init(); + rbs_ffi_result_t *result = (rbs_ffi_result_t *) malloc(sizeof(rbs_ffi_result_t)); + result->allocator = allocator; + rbs_buffer_init(allocator, &result->buffer); + return result; +} + +const char *rbs_ffi_result_bytes(const rbs_ffi_result_t *result) { + return rbs_buffer_value(&result->buffer); +} + +size_t rbs_ffi_result_length(const rbs_ffi_result_t *result) { + return rbs_buffer_length(&result->buffer); +} + +void rbs_ffi_result_free(rbs_ffi_result_t *result) { + rbs_allocator_free(result->allocator); + free(result); +} + +static rbs_serializer_t result_serializer(rbs_ffi_result_t *result, const rbs_parser_t *parser) { + return (rbs_serializer_t) { + .allocator = result->allocator, + .buffer = &result->buffer, + .constant_pool = parser ? &parser->constant_pool : NULL, + }; +} + +static void append_u8(rbs_ffi_result_t *result, uint8_t value) { + rbs_buffer_append_string(result->allocator, &result->buffer, (const char *) &value, 1); +} + +static void append_u32(rbs_ffi_result_t *result, uint32_t value) { + char bytes[4] = { + (char) (value & 0xff), + (char) ((value >> 8) & 0xff), + (char) ((value >> 16) & 0xff), + (char) ((value >> 24) & 0xff), + }; + rbs_buffer_append_string(result->allocator, &result->buffer, bytes, 4); +} + +static void append_i32(rbs_ffi_result_t *result, int32_t value) { + append_u32(result, (uint32_t) value); +} + +static void append_str(rbs_ffi_result_t *result, const char *value, size_t length) { + append_u32(result, (uint32_t) length); + rbs_buffer_append_string(result->allocator, &result->buffer, value, length); +} + +static void append_cstr(rbs_ffi_result_t *result, const char *value) { + append_str(result, value, strlen(value)); +} + +static const rbs_encoding_t *find_encoding(const char *enc_name) { + const rbs_encoding_t *encoding = rbs_encoding_find( + (const uint8_t *) enc_name, + (const uint8_t *) (enc_name + strlen(enc_name)) + ); + if (encoding == NULL) { + encoding = &rbs_encodings[RBS_ENCODING_UTF_8]; + } + return encoding; +} + +/** + * Serializes the parser's error: + * + * u8 status (RBS_FFI_STATUS_ERROR) + * u8 syntax error flag + * u32 length + bytes of message + * u32 length + bytes of token type name + * i32 token start char, i32 token end char + */ +static void serialize_error(rbs_ffi_result_t *result, const rbs_error_t *error) { + append_u8(result, RBS_FFI_STATUS_ERROR); + append_u8(result, error->syntax_error ? 1 : 0); + append_cstr(result, error->message); + append_cstr(result, rbs_token_type_str(error->token.type)); + append_i32(result, error->token.range.start.char_pos); + append_i32(result, error->token.range.end.char_pos); +} + +static uint32_t read_u32le(const char *bytes) { + return (uint32_t) (uint8_t) bytes[0] | + ((uint32_t) (uint8_t) bytes[1] << 8) | + ((uint32_t) (uint8_t) bytes[2] << 16) | + ((uint32_t) (uint8_t) bytes[3] << 24); +} + +/** + * Declares type variables in the parser, replicating + * `declare_type_variables()` in ext/rbs_extension/main.c. + * + * `vars` is a packed buffer: u32 count, then (u32 length, bytes) per + * variable name. May be NULL when there are no variables. + * + * Returns false when insertion fails, with the error serialized into the + * result. + */ +static bool declare_type_variables(rbs_parser_t *parser, const char *vars, rbs_ffi_result_t *result) { + if (vars == NULL) return true; + + rbs_parser_push_typevar_table(parser, true); + + const char *cursor = vars; + uint32_t count = read_u32le(cursor); + cursor += 4; + + for (uint32_t i = 0; i < count; i++) { + uint32_t length = read_u32le(cursor); + cursor += 4; + + uint8_t *copied_name = (uint8_t *) malloc(length); + memcpy(copied_name, cursor, length); + cursor += length; + + rbs_constant_id_t id = rbs_constant_pool_insert_owned( + &parser->constant_pool, + copied_name, + length + ); + + if (!rbs_parser_insert_typevar(parser, id)) { + serialize_error(result, parser->error); + return false; + } + } + + return true; +} + +/** + * Lexes the given source and serializes the resulting token list: + * + * u8 status (RBS_FFI_STATUS_SUCCESS) + * u32 token count + * tokens: (u32 length + bytes of token type name, i32 start char, i32 end char)* + * + * The token list includes the trailing pEOF token, mirroring + * `RBS::Parser._lex` in ext/rbs_extension/main.c. + */ +rbs_ffi_result_t *rbs_ffi_lex(const char *src, size_t len, const char *enc_name, int end_pos) { + rbs_ffi_result_t *result = rbs_ffi_result_new(); + + rbs_allocator_t *allocator = rbs_allocator_init(); + rbs_string_t string = rbs_string_new(src, src + len); + rbs_lexer_t *lexer = rbs_lexer_new(allocator, string, find_encoding(enc_name), 0, end_pos); + + append_u8(result, RBS_FFI_STATUS_SUCCESS); + + /* Reserve the count slot; patched after the token loop below. */ + size_t count_offset = rbs_buffer_length(&result->buffer); + append_u32(result, 0); + + uint32_t count = 0; + rbs_token_t token = NullToken; + while (token.type != pEOF) { + token = rbs_lexer_next_token(lexer); + append_cstr(result, rbs_token_type_str(token.type)); + append_i32(result, token.range.start.char_pos); + append_i32(result, token.range.end.char_pos); + count++; + } + + char *count_slot = rbs_buffer_value(&result->buffer) + count_offset; + count_slot[0] = (char) (count & 0xff); + count_slot[1] = (char) ((count >> 8) & 0xff); + count_slot[2] = (char) ((count >> 16) & 0xff); + count_slot[3] = (char) ((count >> 24) & 0xff); + + rbs_allocator_free(allocator); + + return result; +} + +rbs_ffi_result_t *rbs_ffi_parse_type( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos, + const char *vars, + bool require_eof, + bool void_allowed, + bool self_allowed, + bool classish_allowed +) { + rbs_ffi_result_t *result = rbs_ffi_result_new(); + + rbs_string_t string = rbs_string_new(src, src + len); + rbs_parser_t *parser = rbs_parser_new(string, find_encoding(enc_name), start_pos, end_pos); + + if (!declare_type_variables(parser, vars, result)) { + rbs_parser_free(parser); + return result; + } + + if (parser->next_token.type == pEOF) { + append_u8(result, RBS_FFI_STATUS_NIL); + rbs_parser_free(parser); + return result; + } + + rbs_node_t *type; + rbs_parse_type(parser, &type, void_allowed, self_allowed, classish_allowed); + + if (parser->error != NULL) { + serialize_error(result, parser->error); + rbs_parser_free(parser); + return result; + } + + if (require_eof) { + rbs_parser_advance(parser); + if (parser->current_token.type != pEOF) { + rbs_parser_set_error(parser, parser->current_token, true, "expected a token `%s`", rbs_token_type_str(pEOF)); + serialize_error(result, parser->error); + rbs_parser_free(parser); + return result; + } + } + + append_u8(result, RBS_FFI_STATUS_SUCCESS); + rbs_serializer_t serializer = result_serializer(result, parser); + rbs_serializer_write_node(&serializer, type); + + rbs_parser_free(parser); + return result; +} + +rbs_ffi_result_t *rbs_ffi_parse_method_type( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos, + const char *vars, + bool require_eof +) { + rbs_ffi_result_t *result = rbs_ffi_result_new(); + + rbs_string_t string = rbs_string_new(src, src + len); + rbs_parser_t *parser = rbs_parser_new(string, find_encoding(enc_name), start_pos, end_pos); + + if (!declare_type_variables(parser, vars, result)) { + rbs_parser_free(parser); + return result; + } + + if (parser->next_token.type == pEOF) { + append_u8(result, RBS_FFI_STATUS_NIL); + rbs_parser_free(parser); + return result; + } + + rbs_method_type_t *method_type = NULL; + rbs_parse_method_type(parser, &method_type, require_eof, true); + + if (parser->error != NULL) { + serialize_error(result, parser->error); + rbs_parser_free(parser); + return result; + } + + append_u8(result, RBS_FFI_STATUS_SUCCESS); + rbs_serializer_t serializer = result_serializer(result, parser); + rbs_serializer_write_node(&serializer, (rbs_node_t *) method_type); + + rbs_parser_free(parser); + return result; +} + +rbs_ffi_result_t *rbs_ffi_parse_signature( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos +) { + rbs_ffi_result_t *result = rbs_ffi_result_new(); + + rbs_string_t string = rbs_string_new(src, src + len); + rbs_parser_t *parser = rbs_parser_new(string, find_encoding(enc_name), start_pos, end_pos); + + rbs_signature_t *signature = NULL; + rbs_parse_signature(parser, &signature); + + if (parser->error != NULL) { + serialize_error(result, parser->error); + rbs_parser_free(parser); + return result; + } + + append_u8(result, RBS_FFI_STATUS_SUCCESS); + rbs_serializer_t serializer = result_serializer(result, parser); + rbs_serializer_write_node(&serializer, (rbs_node_t *) signature); + + rbs_parser_free(parser); + return result; +} + +rbs_ffi_result_t *rbs_ffi_parse_type_params( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos, + bool module_type_params +) { + rbs_ffi_result_t *result = rbs_ffi_result_new(); + + rbs_string_t string = rbs_string_new(src, src + len); + rbs_parser_t *parser = rbs_parser_new(string, find_encoding(enc_name), start_pos, end_pos); + + if (parser->next_token.type == pEOF) { + append_u8(result, RBS_FFI_STATUS_NIL); + rbs_parser_free(parser); + return result; + } + + rbs_node_list_t *params = NULL; + rbs_parse_type_params(parser, module_type_params, ¶ms); + + if (parser->error != NULL) { + serialize_error(result, parser->error); + rbs_parser_free(parser); + return result; + } + + append_u8(result, RBS_FFI_STATUS_SUCCESS); + rbs_serializer_t serializer = result_serializer(result, parser); + rbs_serializer_write_node_list(&serializer, params); + + rbs_parser_free(parser); + return result; +} + +typedef bool (*rbs_parse_inline_annotation_func)(rbs_parser_t *, rbs_ast_ruby_annotations_t **); + +static rbs_ffi_result_t *parse_inline_annotation( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos, + const char *vars, + rbs_parse_inline_annotation_func parse +) { + rbs_ffi_result_t *result = rbs_ffi_result_new(); + + rbs_string_t string = rbs_string_new(src, src + len); + rbs_parser_t *parser = rbs_parser_new(string, find_encoding(enc_name), start_pos, end_pos); + + if (!declare_type_variables(parser, vars, result)) { + rbs_parser_free(parser); + return result; + } + + rbs_ast_ruby_annotations_t *annotation = NULL; + bool success = parse(parser, &annotation); + + if (parser->error != NULL) { + serialize_error(result, parser->error); + rbs_parser_free(parser); + return result; + } + + if (!success || annotation == NULL) { + append_u8(result, RBS_FFI_STATUS_NIL); + rbs_parser_free(parser); + return result; + } + + append_u8(result, RBS_FFI_STATUS_SUCCESS); + rbs_serializer_t serializer = result_serializer(result, parser); + rbs_serializer_write_node(&serializer, (rbs_node_t *) annotation); + + rbs_parser_free(parser); + return result; +} + +rbs_ffi_result_t *rbs_ffi_parse_inline_leading_annotation( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos, + const char *vars +) { + return parse_inline_annotation(src, len, enc_name, start_pos, end_pos, vars, rbs_parse_inline_leading_annotation); +} + +rbs_ffi_result_t *rbs_ffi_parse_inline_trailing_annotation( + const char *src, + size_t len, + const char *enc_name, + int start_pos, + int end_pos, + const char *vars +) { + return parse_inline_annotation(src, len, enc_name, start_pos, end_pos, vars, rbs_parse_inline_trailing_annotation); +} diff --git a/src/serializer.c b/src/serializer.c new file mode 100644 index 0000000000..759ef8938e --- /dev/null +++ b/src/serializer.c @@ -0,0 +1,803 @@ +/*----------------------------------------------------------------------------*/ +/* This file is generated by the templates/template.rb script and should not */ +/* be modified manually. */ +/* To change the template see */ +/* templates/src/serializer.c.erb */ +/*----------------------------------------------------------------------------*/ + +#include "rbs/serializer.h" + +#include "rbs/util/rbs_assert.h" + +#include + +void rbs_serializer_write_u8(rbs_serializer_t *serializer, uint8_t value) { + rbs_buffer_append_string(serializer->allocator, serializer->buffer, (const char *) &value, 1); +} + +void rbs_serializer_write_u32(rbs_serializer_t *serializer, uint32_t value) { + char bytes[4] = { + (char) (value & 0xff), + (char) ((value >> 8) & 0xff), + (char) ((value >> 16) & 0xff), + (char) ((value >> 24) & 0xff), + }; + rbs_buffer_append_string(serializer->allocator, serializer->buffer, bytes, 4); +} + +void rbs_serializer_write_i32(rbs_serializer_t *serializer, int32_t value) { + rbs_serializer_write_u32(serializer, (uint32_t) value); +} + +void rbs_serializer_write_string(rbs_serializer_t *serializer, rbs_string_t string) { + size_t length = rbs_string_len(string); + rbs_serializer_write_u32(serializer, (uint32_t) length); + rbs_buffer_append_string(serializer->allocator, serializer->buffer, string.start, length); +} + +static void write_constant(rbs_serializer_t *serializer, rbs_constant_id_t id) { + rbs_constant_t *constant = rbs_constant_pool_id_to_constant((rbs_constant_pool_t *) serializer->constant_pool, id); + RBS_ASSERT(constant != NULL, "constant is NULL"); + RBS_ASSERT(constant->start != NULL, "constant->start is NULL"); + + rbs_serializer_write_u32(serializer, (uint32_t) constant->length); + rbs_buffer_append_string(serializer->allocator, serializer->buffer, (const char *) constant->start, constant->length); +} + +/* A location range is encoded as its character positions only, which is all + * the Ruby side consumes. A null range is encoded as (-1, -1). */ +static void write_range(rbs_serializer_t *serializer, rbs_location_range range) { + rbs_serializer_write_i32(serializer, range.start_char); + rbs_serializer_write_i32(serializer, range.end_char); +} + +void rbs_serializer_write_node_list(rbs_serializer_t *serializer, rbs_node_list_t *list) { + rbs_serializer_write_u32(serializer, (uint32_t) list->length); + for (rbs_node_list_node_t *n = list->head; n != NULL; n = n->next) { + rbs_serializer_write_node(serializer, n->node); + } +} + +static void write_hash(rbs_serializer_t *serializer, rbs_hash_t *hash) { + rbs_serializer_write_u32(serializer, (uint32_t) hash->length); + for (rbs_hash_node_t *n = hash->head; n != NULL; n = n->next) { + rbs_serializer_write_node(serializer, n->key); + rbs_serializer_write_node(serializer, n->value); + } +} + +/* The leading byte distinguishes a NULL list (0) from a present list (1): + * the Ruby side maps NULL to a shared frozen empty array, mirroring + * ext/rbs_extension/ast_translation.c. */ +static void write_range_list(rbs_serializer_t *serializer, rbs_location_range_list_t *list) { + if (list == NULL) { + rbs_serializer_write_u8(serializer, 0); + return; + } + + rbs_serializer_write_u8(serializer, 1); + rbs_serializer_write_u32(serializer, (uint32_t) list->length); + for (rbs_location_range_list_node_t *n = list->head; n != NULL; n = n->next) { + write_range(serializer, n->range); + } +} + +static void write_ivar_name(rbs_serializer_t *serializer, rbs_attr_ivar_name_t ivar_name) { + rbs_serializer_write_u8(serializer, (uint8_t) ivar_name.tag); + if (ivar_name.tag == RBS_ATTR_IVAR_NAME_TAG_NAME) { + write_constant(serializer, ivar_name.name); + } +} + +void rbs_serializer_write_node(rbs_serializer_t *serializer, const rbs_node_t *instance) { + if (instance == NULL) { + rbs_serializer_write_u8(serializer, 0); + return; + } + + /* Node tags are the `enum rbs_node_type` values; the deserializer derives + * the same numbering from config.yml. */ + rbs_serializer_write_u8(serializer, (uint8_t) instance->type); + + switch (instance->type) { + case RBS_AST_ANNOTATION: { + rbs_ast_annotation_t *node = (rbs_ast_annotation_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_string(serializer, node->string); + break; + } + case RBS_AST_BOOL: { + rbs_serializer_write_u8(serializer, ((rbs_ast_bool_t *) instance)->value ? 1 : 0); + break; + } + case RBS_AST_COMMENT: { + rbs_ast_comment_t *node = (rbs_ast_comment_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_string(serializer, node->string); + break; + } + case RBS_AST_DECLARATIONS_CLASS: { + rbs_ast_declarations_class_t *node = (rbs_ast_declarations_class_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->end_range); + write_range(serializer, node->type_params_range); + write_range(serializer, node->lt_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->type_params); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->super_class); /* rbs_ast_declarations_class_super */ + rbs_serializer_write_node_list(serializer, node->members); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_DECLARATIONS_CLASS_SUPER: { + rbs_ast_declarations_class_super_t *node = (rbs_ast_declarations_class_super_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + break; + } + case RBS_AST_DECLARATIONS_CLASS_ALIAS: { + rbs_ast_declarations_class_alias_t *node = (rbs_ast_declarations_class_alias_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->new_name_range); + write_range(serializer, node->eq_range); + write_range(serializer, node->old_name_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->new_name); /* rbs_type_name */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->old_name); /* rbs_type_name */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_node_list(serializer, node->annotations); + break; + } + case RBS_AST_DECLARATIONS_CONSTANT: { + rbs_ast_declarations_constant_t *node = (rbs_ast_declarations_constant_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_node_list(serializer, node->annotations); + break; + } + case RBS_AST_DECLARATIONS_GLOBAL: { + rbs_ast_declarations_global_t *node = (rbs_ast_declarations_global_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_node_list(serializer, node->annotations); + break; + } + case RBS_AST_DECLARATIONS_INTERFACE: { + rbs_ast_declarations_interface_t *node = (rbs_ast_declarations_interface_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->end_range); + write_range(serializer, node->type_params_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->type_params); + rbs_serializer_write_node_list(serializer, node->members); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_DECLARATIONS_MODULE: { + rbs_ast_declarations_module_t *node = (rbs_ast_declarations_module_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->end_range); + write_range(serializer, node->type_params_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->self_types_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->type_params); + rbs_serializer_write_node_list(serializer, node->self_types); + rbs_serializer_write_node_list(serializer, node->members); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_DECLARATIONS_MODULE_SELF: { + rbs_ast_declarations_module_self_t *node = (rbs_ast_declarations_module_self_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + break; + } + case RBS_AST_DECLARATIONS_MODULE_ALIAS: { + rbs_ast_declarations_module_alias_t *node = (rbs_ast_declarations_module_alias_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->new_name_range); + write_range(serializer, node->eq_range); + write_range(serializer, node->old_name_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->new_name); /* rbs_type_name */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->old_name); /* rbs_type_name */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_node_list(serializer, node->annotations); + break; + } + case RBS_AST_DECLARATIONS_TYPE_ALIAS: { + rbs_ast_declarations_type_alias_t *node = (rbs_ast_declarations_type_alias_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->eq_range); + write_range(serializer, node->type_params_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->type_params); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_DIRECTIVES_USE: { + rbs_ast_directives_use_t *node = (rbs_ast_directives_use_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + rbs_serializer_write_node_list(serializer, node->clauses); + break; + } + case RBS_AST_DIRECTIVES_USE_SINGLE_CLAUSE: { + rbs_ast_directives_use_single_clause_t *node = (rbs_ast_directives_use_single_clause_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->type_name_range); + write_range(serializer, node->keyword_range); + write_range(serializer, node->new_name_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type_name); /* rbs_type_name */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->new_name); /* rbs_ast_symbol */ + break; + } + case RBS_AST_DIRECTIVES_USE_WILDCARD_CLAUSE: { + rbs_ast_directives_use_wildcard_clause_t *node = (rbs_ast_directives_use_wildcard_clause_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->namespace_range); + write_range(serializer, node->star_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->rbs_namespace); /* rbs_namespace */ + break; + } + case RBS_AST_INTEGER: { + rbs_serializer_write_string(serializer, ((rbs_ast_integer_t *) instance)->string_representation); + break; + } + case RBS_AST_MEMBERS_ALIAS: { + rbs_ast_members_alias_t *node = (rbs_ast_members_alias_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->new_name_range); + write_range(serializer, node->old_name_range); + write_range(serializer, node->new_kind_range); + write_range(serializer, node->old_kind_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->new_name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->old_name); /* rbs_ast_symbol */ + rbs_serializer_write_u8(serializer, (uint8_t) node->kind); /* alias_kind */ + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_ATTR_ACCESSOR: { + rbs_ast_members_attr_accessor_t *node = (rbs_ast_members_attr_accessor_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->kind_range); + write_range(serializer, node->ivar_range); + write_range(serializer, node->ivar_name_range); + write_range(serializer, node->visibility_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + write_ivar_name(serializer, node->ivar_name); + rbs_serializer_write_u8(serializer, (uint8_t) node->kind); /* attribute_kind */ + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_u8(serializer, (uint8_t) node->visibility); /* attribute_visibility */ + break; + } + case RBS_AST_MEMBERS_ATTR_READER: { + rbs_ast_members_attr_reader_t *node = (rbs_ast_members_attr_reader_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->kind_range); + write_range(serializer, node->ivar_range); + write_range(serializer, node->ivar_name_range); + write_range(serializer, node->visibility_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + write_ivar_name(serializer, node->ivar_name); + rbs_serializer_write_u8(serializer, (uint8_t) node->kind); /* attribute_kind */ + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_u8(serializer, (uint8_t) node->visibility); /* attribute_visibility */ + break; + } + case RBS_AST_MEMBERS_ATTR_WRITER: { + rbs_ast_members_attr_writer_t *node = (rbs_ast_members_attr_writer_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->kind_range); + write_range(serializer, node->ivar_range); + write_range(serializer, node->ivar_name_range); + write_range(serializer, node->visibility_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + write_ivar_name(serializer, node->ivar_name); + rbs_serializer_write_u8(serializer, (uint8_t) node->kind); /* attribute_kind */ + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_u8(serializer, (uint8_t) node->visibility); /* attribute_visibility */ + break; + } + case RBS_AST_MEMBERS_CLASS_INSTANCE_VARIABLE: { + rbs_ast_members_class_instance_variable_t *node = (rbs_ast_members_class_instance_variable_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->kind_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_CLASS_VARIABLE: { + rbs_ast_members_class_variable_t *node = (rbs_ast_members_class_variable_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->kind_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_EXTEND: { + rbs_ast_members_extend_t *node = (rbs_ast_members_extend_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->keyword_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_INCLUDE: { + rbs_ast_members_include_t *node = (rbs_ast_members_include_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->keyword_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_INSTANCE_VARIABLE: { + rbs_ast_members_instance_variable_t *node = (rbs_ast_members_instance_variable_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->colon_range); + write_range(serializer, node->kind_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_METHOD_DEFINITION: { + rbs_ast_members_method_definition_t *node = (rbs_ast_members_method_definition_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->keyword_range); + write_range(serializer, node->name_range); + write_range(serializer, node->kind_range); + write_range(serializer, node->overloading_range); + write_range(serializer, node->visibility_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_u8(serializer, (uint8_t) node->kind); /* method_definition_kind */ + rbs_serializer_write_node_list(serializer, node->overloads); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + rbs_serializer_write_u8(serializer, node->overloading ? 1 : 0); + rbs_serializer_write_u8(serializer, (uint8_t) node->visibility); /* method_definition_visibility */ + break; + } + case RBS_AST_MEMBERS_METHOD_DEFINITION_OVERLOAD: { + rbs_ast_members_method_definition_overload_t *node = (rbs_ast_members_method_definition_overload_t *) instance; + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->method_type); /* rbs_node */ + break; + } + case RBS_AST_MEMBERS_PREPEND: { + rbs_ast_members_prepend_t *node = (rbs_ast_members_prepend_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->keyword_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->comment); /* rbs_ast_comment */ + break; + } + case RBS_AST_MEMBERS_PRIVATE: { + write_range(serializer, instance->location); + break; + } + case RBS_AST_MEMBERS_PUBLIC: { + write_range(serializer, instance->location); + break; + } + case RBS_AST_RUBY_ANNOTATIONS_BLOCK_PARAM_TYPE_ANNOTATION: { + rbs_ast_ruby_annotations_block_param_type_annotation_t *node = (rbs_ast_ruby_annotations_block_param_type_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->ampersand_location); + write_range(serializer, node->name_location); /* optional */ + write_range(serializer, node->colon_location); + write_range(serializer, node->question_location); /* optional */ + write_range(serializer, node->type_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type_); /* rbs_node */ + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_CLASS_ALIAS_ANNOTATION: { + rbs_ast_ruby_annotations_class_alias_annotation_t *node = (rbs_ast_ruby_annotations_class_alias_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->keyword_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type_name); /* rbs_type_name */ + write_range(serializer, node->type_name_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_COLON_METHOD_TYPE_ANNOTATION: { + rbs_ast_ruby_annotations_colon_method_type_annotation_t *node = (rbs_ast_ruby_annotations_colon_method_type_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + rbs_serializer_write_node_list(serializer, node->annotations); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->method_type); /* rbs_node */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_DOUBLE_SPLAT_PARAM_TYPE_ANNOTATION: { + rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *node = (rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->star2_location); + write_range(serializer, node->name_location); /* optional */ + write_range(serializer, node->colon_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->param_type); /* rbs_node */ + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_INSTANCE_VARIABLE_ANNOTATION: { + rbs_ast_ruby_annotations_instance_variable_annotation_t *node = (rbs_ast_ruby_annotations_instance_variable_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->ivar_name); /* rbs_ast_symbol */ + write_range(serializer, node->ivar_name_location); + write_range(serializer, node->colon_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_METHOD_TYPES_ANNOTATION: { + rbs_ast_ruby_annotations_method_types_annotation_t *node = (rbs_ast_ruby_annotations_method_types_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + rbs_serializer_write_node_list(serializer, node->overloads); + write_range_list(serializer, node->vertical_bar_locations); + write_range(serializer, node->dot3_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_MODULE_ALIAS_ANNOTATION: { + rbs_ast_ruby_annotations_module_alias_annotation_t *node = (rbs_ast_ruby_annotations_module_alias_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->keyword_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type_name); /* rbs_type_name */ + write_range(serializer, node->type_name_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION: { + rbs_ast_ruby_annotations_module_self_annotation_t *node = (rbs_ast_ruby_annotations_module_self_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->keyword_location); + write_range(serializer, node->colon_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + write_range(serializer, node->open_bracket_location); /* optional */ + write_range(serializer, node->close_bracket_location); /* optional */ + write_range_list(serializer, node->args_comma_locations); + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION: { + rbs_ast_ruby_annotations_node_type_assertion_t *node = (rbs_ast_ruby_annotations_node_type_assertion_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_PARAM_TYPE_ANNOTATION: { + rbs_ast_ruby_annotations_param_type_annotation_t *node = (rbs_ast_ruby_annotations_param_type_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->name_location); + write_range(serializer, node->colon_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->param_type); /* rbs_node */ + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_RETURN_TYPE_ANNOTATION: { + rbs_ast_ruby_annotations_return_type_annotation_t *node = (rbs_ast_ruby_annotations_return_type_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->return_location); + write_range(serializer, node->colon_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->return_type); /* rbs_node */ + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_SKIP_ANNOTATION: { + rbs_ast_ruby_annotations_skip_annotation_t *node = (rbs_ast_ruby_annotations_skip_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->skip_location); + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_SPLAT_PARAM_TYPE_ANNOTATION: { + rbs_ast_ruby_annotations_splat_param_type_annotation_t *node = (rbs_ast_ruby_annotations_splat_param_type_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + write_range(serializer, node->star_location); + write_range(serializer, node->name_location); /* optional */ + write_range(serializer, node->colon_location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->param_type); /* rbs_node */ + write_range(serializer, node->comment_location); /* optional */ + break; + } + case RBS_AST_RUBY_ANNOTATIONS_TYPE_APPLICATION_ANNOTATION: { + rbs_ast_ruby_annotations_type_application_annotation_t *node = (rbs_ast_ruby_annotations_type_application_annotation_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->prefix_location); + rbs_serializer_write_node_list(serializer, node->type_args); + write_range(serializer, node->close_bracket_location); + write_range_list(serializer, node->comma_locations); + break; + } + case RBS_AST_STRING: { + rbs_serializer_write_string(serializer, ((rbs_ast_string_t *) instance)->string); + break; + } + case RBS_AST_TYPE_PARAM: { + rbs_ast_type_param_t *node = (rbs_ast_type_param_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->variance_range); + write_range(serializer, node->unchecked_range); + write_range(serializer, node->upper_bound_range); + write_range(serializer, node->lower_bound_range); + write_range(serializer, node->default_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + rbs_serializer_write_u8(serializer, (uint8_t) node->variance); /* type_param_variance */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->upper_bound); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->lower_bound); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->default_type); /* rbs_node */ + rbs_serializer_write_u8(serializer, node->unchecked ? 1 : 0); + break; + } + case RBS_METHOD_TYPE: { + rbs_method_type_t *node = (rbs_method_type_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->type_range); + write_range(serializer, node->type_params_range); + rbs_serializer_write_node_list(serializer, node->type_params); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->block); /* rbs_types_block */ + break; + } + case RBS_NAMESPACE: { + rbs_namespace_t *node = (rbs_namespace_t *) instance; + rbs_serializer_write_node_list(serializer, node->path); + rbs_serializer_write_u8(serializer, node->absolute ? 1 : 0); + break; + } + case RBS_SIGNATURE: { + rbs_signature_t *node = (rbs_signature_t *) instance; + rbs_serializer_write_node_list(serializer, node->directives); + rbs_serializer_write_node_list(serializer, node->declarations); + break; + } + case RBS_TYPE_NAME: { + rbs_type_name_t *node = (rbs_type_name_t *) instance; + rbs_serializer_write_node(serializer, (rbs_node_t *) node->rbs_namespace); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); + break; + } + case RBS_TYPES_ALIAS: { + rbs_types_alias_t *node = (rbs_types_alias_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + break; + } + case RBS_TYPES_BASES_ANY: { + rbs_types_bases_any_t *node = (rbs_types_bases_any_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_u8(serializer, node->todo ? 1 : 0); + break; + } + case RBS_TYPES_BASES_BOOL: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_BOTTOM: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_CLASS: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_INSTANCE: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_NIL: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_SELF: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_TOP: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BASES_VOID: { + write_range(serializer, instance->location); + break; + } + case RBS_TYPES_BLOCK: { + rbs_types_block_t *node = (rbs_types_block_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_u8(serializer, node->required ? 1 : 0); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->self_type); /* rbs_node */ + break; + } + case RBS_TYPES_CLASS_INSTANCE: { + rbs_types_class_instance_t *node = (rbs_types_class_instance_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + break; + } + case RBS_TYPES_CLASS_SINGLETON: { + rbs_types_class_singleton_t *node = (rbs_types_class_singleton_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + break; + } + case RBS_TYPES_FUNCTION: { + rbs_types_function_t *node = (rbs_types_function_t *) instance; + rbs_serializer_write_node_list(serializer, node->required_positionals); + rbs_serializer_write_node_list(serializer, node->optional_positionals); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->rest_positionals); /* rbs_node */ + rbs_serializer_write_node_list(serializer, node->trailing_positionals); + write_hash(serializer, node->required_keywords); + write_hash(serializer, node->optional_keywords); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->rest_keywords); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->return_type); /* rbs_node */ + break; + } + case RBS_TYPES_FUNCTION_PARAM: { + rbs_types_function_param_t *node = (rbs_types_function_param_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + break; + } + case RBS_TYPES_INTERFACE: { + rbs_types_interface_t *node = (rbs_types_interface_t *) instance; + write_range(serializer, instance->location); + write_range(serializer, node->name_range); + write_range(serializer, node->args_range); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_type_name */ + rbs_serializer_write_node_list(serializer, node->args); + break; + } + case RBS_TYPES_INTERSECTION: { + rbs_types_intersection_t *node = (rbs_types_intersection_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node_list(serializer, node->types); + break; + } + case RBS_TYPES_LITERAL: { + rbs_types_literal_t *node = (rbs_types_literal_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->literal); /* rbs_node */ + break; + } + case RBS_TYPES_OPTIONAL: { + rbs_types_optional_t *node = (rbs_types_optional_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + break; + } + case RBS_TYPES_PROC: { + rbs_types_proc_t *node = (rbs_types_proc_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->type); /* rbs_node */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->block); /* rbs_types_block */ + rbs_serializer_write_node(serializer, (rbs_node_t *) node->self_type); /* rbs_node */ + break; + } + case RBS_TYPES_RECORD: { + rbs_types_record_t *node = (rbs_types_record_t *) instance; + write_range(serializer, instance->location); + write_hash(serializer, node->all_fields); + break; + } + case RBS_TYPES_RECORD_FIELD_TYPE: { + rbs_types_record_field_type_t *node = (rbs_types_record_field_type_t *) instance; + rbs_serializer_write_node(serializer, node->type); + rbs_serializer_write_u8(serializer, node->required ? 1 : 0); + break; + } + case RBS_TYPES_TUPLE: { + rbs_types_tuple_t *node = (rbs_types_tuple_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node_list(serializer, node->types); + break; + } + case RBS_TYPES_UNION: { + rbs_types_union_t *node = (rbs_types_union_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node_list(serializer, node->types); + break; + } + case RBS_TYPES_UNTYPED_FUNCTION: { + rbs_types_untyped_function_t *node = (rbs_types_untyped_function_t *) instance; + rbs_serializer_write_node(serializer, (rbs_node_t *) node->return_type); /* rbs_node */ + break; + } + case RBS_TYPES_VARIABLE: { + rbs_types_variable_t *node = (rbs_types_variable_t *) instance; + write_range(serializer, instance->location); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); /* rbs_ast_symbol */ + break; + } + case RBS_AST_SYMBOL: { + write_constant(serializer, ((rbs_ast_symbol_t *) instance)->constant_id); + break; + } + } +} diff --git a/templates/lib/rbs/parser/deserializer.rb.erb b/templates/lib/rbs/parser/deserializer.rb.erb new file mode 100644 index 0000000000..d4438dbdba --- /dev/null +++ b/templates/lib/rbs/parser/deserializer.rb.erb @@ -0,0 +1,190 @@ +module RBS + class Parser + # Decodes the binary AST representation produced by src/serializer.c + # (generated from templates/src/serializer.c.erb) into Ruby AST objects, + # mirroring the translation done in C by + # ext/rbs_extension/ast_translation.c for the MRI extension. + # + # Used by the FFI parser backend (lib/rbs/parser/ffi.rb) on non-MRI Ruby + # implementations. + class Deserializer + EMPTY_ARRAY = [].freeze + EMPTY_HASH = {}.freeze + + <%- enums.each do |enum| -%> + <%= enum.name.upcase %> = [<%= enum.symbols.each_with_index.map {|sym, index| (enum.optional? && index == 0) ? "nil" : sym.to_sym.inspect }.join(", ") %>].freeze + <%- end -%> + + def initialize(buffer:, reader:) + @buffer = buffer + @reader = reader + @encoding = buffer.content.encoding + end + + def read_node + tag = @reader.read_u8 + case tag + when 0 + nil + <%- nodes.each_with_index do |node, index| -%> + when <%= index + 1 %> # <%= node.ruby_full_name %> + read_<%= node.c_name %> + <%- end -%> + when <%= nodes.size + 1 %> # Symbol + read_symbol + else + raise "Unknown node tag: #{tag}" + end + end + + def read_node_list + Array.new(@reader.read_u32) { read_node } + end + + private + + def read_symbol + @reader.read_string.force_encoding(@encoding).to_sym + end + + def read_location + start_char = @reader.read_i32 + end_char = @reader.read_i32 + if start_char == -1 + nil + else + Location.new(@buffer, start_char, end_char) + end + end + + def add_required_child(location, name) + start_char = @reader.read_i32 + end_char = @reader.read_i32 + location.add_required_child(name, start_char...end_char) + end + + def add_optional_child(location, name) + start_char = @reader.read_i32 + end_char = @reader.read_i32 + if start_char == -1 + location.add_optional_child(name, nil) + else + location.add_optional_child(name, start_char...end_char) + end + end + + def read_hash + count = @reader.read_u32 + if count == 0 + EMPTY_HASH + else + hash = {} + count.times do + key = read_node + hash[key] = read_node + end + hash + end + end + + def read_location_range_list + if @reader.read_u8 == 0 + EMPTY_ARRAY + else + Array.new(@reader.read_u32) { read_location } + end + end + + def read_ivar_name + case @reader.read_u8 + when 0 # unspecified + nil + when 1 # empty + false + else + read_symbol + end + end + + <%- nodes.each do |node| -%> + def read_<%= node.c_name %> + <%- case node.ruby_full_name -%> + <%- when "RBS::AST::Bool" -%> + @reader.read_u8 != 0 + <%- when "RBS::AST::Integer" -%> + @reader.read_string.force_encoding(Encoding::UTF_8).to_i + <%- when "RBS::AST::String" -%> + @reader.read_string.force_encoding(Encoding::UTF_8) + <%- when "RBS::Types::Record::FieldType" -%> + type = read_node + required = @reader.read_u8 != 0 + [type, required] + <%- when "RBS::Signature" -%> + directives = read_node_list + declarations = read_node_list + [directives, declarations] + <%- when "RBS::Namespace" -%> + path = read_node_list + absolute = @reader.read_u8 != 0 + Namespace[path, absolute] + <%- when "RBS::TypeName" -%> + namespace = read_node + name = read_node + TypeName[namespace, name] + <%- else -%> + <%- if node.expose_location? -%> + location = read_location + <%- end -%> + <%- if node.locations -%> + raise "location is missing" unless location + <%- node.locations.each do |location_field| -%> + <%- if location_field.required? -%> + add_required_child(location, :<%= location_field.name %>) + <%- else -%> + add_optional_child(location, :<%= location_field.name %>) + <%- end -%> + <%- end -%> + <%- end -%> + <%- node.fields.each do |field| -%> + <%- case field.type.name -%> + <%- when "rbs_node_list" -%> + <%= field.name %> = read_node_list + <%- when "rbs_hash" -%> + <%= field.name %> = read_hash + <%- when "rbs_string" -%> + <%= field.name %> = @reader.read_string.force_encoding(@encoding) + <%- when "bool" -%> + <%= field.name %> = @reader.read_u8 != 0 + <%- when "rbs_location_range" -%> + <%= field.name %> = read_location + <%- when "rbs_location_range_list" -%> + <%= field.name %> = read_location_range_list + <%- when "rbs_attr_ivar_name" -%> + <%= field.name %> = read_ivar_name + <%- else -%> + <%- if field.type.is_a?(RBS::Template::EnumType) -%> + <%= field.name %> = <%= field.type.descr.name.upcase %>.fetch(@reader.read_u8) + <%- else -%> + <%= field.name %> = read_node # <%= field.type.c_name %> + <%- end -%> + <%- end -%> + <%- end -%> + <%- case node.ruby_full_name -%> + <%- when "RBS::AST::Declarations::Class", "RBS::AST::Declarations::Module", "RBS::AST::Declarations::Interface", "RBS::AST::Declarations::TypeAlias", "RBS::MethodType" -%> + AST::TypeParam.resolve_variables(type_params) + <%- end -%> + <%= node.ruby_full_name %>.new( + <%- if node.expose_location? -%> + location: location, + <%- end -%> + <%- node.fields.each do |field| -%> + <%= field.name %>: <%= field.name %>, + <%- end -%> + ) + <%- end -%> + end + + <%- end -%> + end + end +end diff --git a/templates/src/ast.c.erb b/templates/src/ast.c.erb index 99c3eab706..d7b354d64e 100644 --- a/templates/src/ast.c.erb +++ b/templates/src/ast.c.erb @@ -114,6 +114,8 @@ void rbs_hash_set(rbs_hash_t *RBS_NONNULL hash, rbs_node_t *RBS_NONNULL key, rbs hash->tail->next = new_node; hash->tail = new_node; } + + hash->length++; } rbs_node_t *RBS_NULLABLE rbs_hash_get(rbs_hash_t *RBS_NONNULL hash, rbs_node_t *RBS_NONNULL key) { diff --git a/templates/src/serializer.c.erb b/templates/src/serializer.c.erb new file mode 100644 index 0000000000..11482ef38d --- /dev/null +++ b/templates/src/serializer.c.erb @@ -0,0 +1,165 @@ +#include "rbs/serializer.h" + +#include "rbs/util/rbs_assert.h" + +#include + +void rbs_serializer_write_u8(rbs_serializer_t *serializer, uint8_t value) { + rbs_buffer_append_string(serializer->allocator, serializer->buffer, (const char *) &value, 1); +} + +void rbs_serializer_write_u32(rbs_serializer_t *serializer, uint32_t value) { + char bytes[4] = { + (char) (value & 0xff), + (char) ((value >> 8) & 0xff), + (char) ((value >> 16) & 0xff), + (char) ((value >> 24) & 0xff), + }; + rbs_buffer_append_string(serializer->allocator, serializer->buffer, bytes, 4); +} + +void rbs_serializer_write_i32(rbs_serializer_t *serializer, int32_t value) { + rbs_serializer_write_u32(serializer, (uint32_t) value); +} + +void rbs_serializer_write_string(rbs_serializer_t *serializer, rbs_string_t string) { + size_t length = rbs_string_len(string); + rbs_serializer_write_u32(serializer, (uint32_t) length); + rbs_buffer_append_string(serializer->allocator, serializer->buffer, string.start, length); +} + +static void write_constant(rbs_serializer_t *serializer, rbs_constant_id_t id) { + rbs_constant_t *constant = rbs_constant_pool_id_to_constant((rbs_constant_pool_t *) serializer->constant_pool, id); + RBS_ASSERT(constant != NULL, "constant is NULL"); + RBS_ASSERT(constant->start != NULL, "constant->start is NULL"); + + rbs_serializer_write_u32(serializer, (uint32_t) constant->length); + rbs_buffer_append_string(serializer->allocator, serializer->buffer, (const char *) constant->start, constant->length); +} + +/* A location range is encoded as its character positions only, which is all + * the Ruby side consumes. A null range is encoded as (-1, -1). */ +static void write_range(rbs_serializer_t *serializer, rbs_location_range range) { + rbs_serializer_write_i32(serializer, range.start_char); + rbs_serializer_write_i32(serializer, range.end_char); +} + +void rbs_serializer_write_node_list(rbs_serializer_t *serializer, rbs_node_list_t *list) { + rbs_serializer_write_u32(serializer, (uint32_t) list->length); + for (rbs_node_list_node_t *n = list->head; n != NULL; n = n->next) { + rbs_serializer_write_node(serializer, n->node); + } +} + +static void write_hash(rbs_serializer_t *serializer, rbs_hash_t *hash) { + rbs_serializer_write_u32(serializer, (uint32_t) hash->length); + for (rbs_hash_node_t *n = hash->head; n != NULL; n = n->next) { + rbs_serializer_write_node(serializer, n->key); + rbs_serializer_write_node(serializer, n->value); + } +} + +/* The leading byte distinguishes a NULL list (0) from a present list (1): + * the Ruby side maps NULL to a shared frozen empty array, mirroring + * ext/rbs_extension/ast_translation.c. */ +static void write_range_list(rbs_serializer_t *serializer, rbs_location_range_list_t *list) { + if (list == NULL) { + rbs_serializer_write_u8(serializer, 0); + return; + } + + rbs_serializer_write_u8(serializer, 1); + rbs_serializer_write_u32(serializer, (uint32_t) list->length); + for (rbs_location_range_list_node_t *n = list->head; n != NULL; n = n->next) { + write_range(serializer, n->range); + } +} + +static void write_ivar_name(rbs_serializer_t *serializer, rbs_attr_ivar_name_t ivar_name) { + rbs_serializer_write_u8(serializer, (uint8_t) ivar_name.tag); + if (ivar_name.tag == RBS_ATTR_IVAR_NAME_TAG_NAME) { + write_constant(serializer, ivar_name.name); + } +} + +void rbs_serializer_write_node(rbs_serializer_t *serializer, const rbs_node_t *instance) { + if (instance == NULL) { + rbs_serializer_write_u8(serializer, 0); + return; + } + + /* Node tags are the `enum rbs_node_type` values; the deserializer derives + * the same numbering from config.yml. */ + rbs_serializer_write_u8(serializer, (uint8_t) instance->type); + + switch (instance->type) { + <%- nodes.each do |node| -%> + case <%= node.c_node_enum_name %>: { + <%- case node.ruby_full_name -%> + <%- when "RBS::AST::Bool" -%> + rbs_serializer_write_u8(serializer, ((rbs_ast_bool_t *) instance)->value ? 1 : 0); + <%- when "RBS::AST::Integer" -%> + rbs_serializer_write_string(serializer, ((rbs_ast_integer_t *) instance)->string_representation); + <%- when "RBS::AST::String" -%> + rbs_serializer_write_string(serializer, ((rbs_ast_string_t *) instance)->string); + <%- when "RBS::Types::Record::FieldType" -%> + rbs_types_record_field_type_t *node = (rbs_types_record_field_type_t *) instance; + rbs_serializer_write_node(serializer, node->type); + rbs_serializer_write_u8(serializer, node->required ? 1 : 0); + <%- when "RBS::Signature" -%> + rbs_signature_t *node = (rbs_signature_t *) instance; + rbs_serializer_write_node_list(serializer, node->directives); + rbs_serializer_write_node_list(serializer, node->declarations); + <%- when "RBS::Namespace" -%> + rbs_namespace_t *node = (rbs_namespace_t *) instance; + rbs_serializer_write_node_list(serializer, node->path); + rbs_serializer_write_u8(serializer, node->absolute ? 1 : 0); + <%- when "RBS::TypeName" -%> + rbs_type_name_t *node = (rbs_type_name_t *) instance; + rbs_serializer_write_node(serializer, (rbs_node_t *) node->rbs_namespace); + rbs_serializer_write_node(serializer, (rbs_node_t *) node->name); + <%- else -%> + <%- needs_cast = !node.fields.empty? || node.locations -%> + <%- if needs_cast -%> + <%= node.c_type_name %> *node = (<%= node.c_type_name %> *) instance; + <%- end -%> + <%- if node.expose_location? -%> + write_range(serializer, instance->location); + <%- end -%> + <%- node.locations&.each do |location_field| -%> + write_range(serializer, node-><%= location_field.attribute_name %>); + <%- end -%> + <%- node.fields.each do |field| -%> + <%- case field.type.name -%> + <%- when "rbs_node_list" -%> + rbs_serializer_write_node_list(serializer, node-><%= field.c_name %>); + <%- when "rbs_hash" -%> + write_hash(serializer, node-><%= field.c_name %>); + <%- when "rbs_string" -%> + rbs_serializer_write_string(serializer, node-><%= field.c_name %>); + <%- when "bool" -%> + rbs_serializer_write_u8(serializer, node-><%= field.c_name %> ? 1 : 0); + <%- when "rbs_location_range" -%> + write_range(serializer, node-><%= field.name %>);<%= field.optional? ? " /* optional */" : "" %> + <%- when "rbs_location_range_list" -%> + write_range_list(serializer, node-><%= field.name %>); + <%- when "rbs_attr_ivar_name" -%> + write_ivar_name(serializer, node-><%= field.c_name %>); + <%- else -%> + <%- if field.type.is_a?(RBS::Template::EnumType) -%> + rbs_serializer_write_u8(serializer, (uint8_t) node-><%= field.c_name %>); /* <%= field.type.name %> */ + <%- else -%> + rbs_serializer_write_node(serializer, (rbs_node_t *) node-><%= field.c_name %>); /* <%= field.type.c_name %> */ + <%- end -%> + <%- end -%> + <%- end -%> + <%- end -%> + break; + } + <%- end -%> + case RBS_AST_SYMBOL: { + write_constant(serializer, ((rbs_ast_symbol_t *) instance)->constant_id); + break; + } + } +} diff --git a/templates/template.rb b/templates/template.rb index b581ddbd74..e6c469723a 100644 --- a/templates/template.rb +++ b/templates/template.rb @@ -281,14 +281,28 @@ def render(out_file) erb = read_template(template) extension = File.extname(filepath.gsub(".erb", "")) - heading = <<~HEADING - /*----------------------------------------------------------------------------*/ - /* This file is generated by the templates/template.rb script and should not */ - /* be modified manually. */ - /* To change the template see */ - /* #{filepath + " " * (74 - filepath.size) } */ - /*----------------------------------------------------------------------------*/ - HEADING + heading = + if extension == ".rb" + <<~HEADING + # frozen_string_literal: true + + #------------------------------------------------------------------------------ + # This file is generated by the templates/template.rb script and should not + # be modified manually. + # To change the template see + # #{filepath} + #------------------------------------------------------------------------------ + HEADING + else + <<~HEADING + /*----------------------------------------------------------------------------*/ + /* This file is generated by the templates/template.rb script and should not */ + /* be modified manually. */ + /* To change the template see */ + /* #{filepath + " " * (74 - filepath.size) } */ + /*----------------------------------------------------------------------------*/ + HEADING + end write_to = File.expand_path("../#{out_file}", __dir__) contents = heading + "\n" + erb.result_with_hash(locals) diff --git a/test/test_helper.rb b/test/test_helper.rb index 9a077b1c08..94f0885ff7 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,7 +6,12 @@ require "bundler" # Explicitly require bundler because ruby CI runs without bundler require "rbs" -require "rbs/annotate" +begin + require "rbs/annotate" +rescue LoadError + # rbs/annotate needs rdoc, which is not installed in the FFI backend CI + # lane (gemfiles/ffi_backend.gemfile). The parser tests don't use it. +end require "test_skip" unless ENV["XDG_CACHE_HOME"]