Class: RBS::WASM::Deserializer
| Relationships & Source Files | |
| Inherits: | Object |
| Defined in: | lib/rbs/wasm/deserializer.rb |
Overview
Rebuilds ::RBS::AST objects from the binary buffer produced by
rbs_serialize_node (src/serialize.c), driven by the generated
SerializationSchema. This is the pure-Ruby counterpart of the C extension's
ast_translation.c, used when the parser runs inside WebAssembly (JRuby).
All locations are reconstructed through the public ::RBS::Location API, so the
same code works whether ::RBS::Location is backed by the C extension (CRuby)
or by a pure-Ruby implementation (JRuby).
Class Method Summary
-
.deserialize(bytes, buffer)
Deserialize a buffer produced for a whole signature, returning
[directives, declarations]to match Parser._parse_signature. -
.deserialize_node_list(bytes, buffer)
Deserialize a bare node list (rbs_serialize_node_list), e.g.
-
.deserialize_tokens(bytes, buffer)
Deserialize the token stream produced by rbs_wasm_lex into the [type, location] pairs Parser._lex returns.
- .new(bytes, buffer) ⇒ Deserializer constructor
Instance Method Summary
- #read_node
- #read_node_list
-
#read_tokens
The lex stream has no leading count: read records until the buffer is exhausted.
- #class_for(name) private
- #read_attr_ivar_name private
-
#read_count
private
A count of nested items.
- #read_field(reader) private
- #read_hash private
- #read_i32 private
-
#read_location(loc_children)
private
The base location of a node, followed by its named child ranges.
-
#read_location_value
private
A standalone location range field: nil or an
::RBS::Locationwithout children. - #read_location_value_list private
-
#read_range
private
Reads a presence byte and, when present, the start/end character positions.
- #read_string(encoding) private
- #read_struct(entry) private
- #read_u32 private
- #read_u8 private
Constructor Details
.new(bytes, buffer) ⇒ Deserializer
# File 'lib/rbs/wasm/deserializer.rb', line 34
def initialize(bytes, buffer) @bytes = bytes @buffer = buffer # Symbols and rbs_string fields (comments, annotations) inherit the # source encoding, matching ast_translation.c. String/Integer literal # nodes are always UTF-8 (see read_node). @encoding = buffer.content.encoding @pos = 0 @class_cache = {} #: Hash[String, untyped] end
Class Method Details
.deserialize(bytes, buffer)
Deserialize a buffer produced for a whole signature, returning
[directives, declarations] to match Parser._parse_signature.
.deserialize_node_list(bytes, buffer)
Deserialize a bare node list (rbs_serialize_node_list), e.g. the result of Parser._parse_type_params.
# File 'lib/rbs/wasm/deserializer.rb', line 24
def self.deserialize_node_list(bytes, buffer) new(bytes, buffer).read_node_list end
.deserialize_tokens(bytes, buffer)
Deserialize the token stream produced by rbs_wasm_lex into the [type, location] pairs Parser._lex returns.
# File 'lib/rbs/wasm/deserializer.rb', line 30
def self.deserialize_tokens(bytes, buffer) new(bytes, buffer).read_tokens end
Instance Method Details
#class_for(name) (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 208
def class_for(name) @class_cache[name] ||= Object.const_get(name) end
#read_attr_ivar_name (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 166
def read_attr_ivar_name case read_u8 when 0 then nil # inferred instance variable when 1 then false # no instance variable else read_string(@encoding).to_sym end end
#read_count (private)
A count of nested items. Each item is at least one byte, so a count that exceeds the bytes remaining signals the cursor has drifted out of sync.
# File 'lib/rbs/wasm/deserializer.rb', line 130
def read_count count = read_u32 if count > @bytes.bytesize - @pos raise "Corrupt buffer: count #{count} exceeds #{@bytes.bytesize - @pos} remaining bytes at offset #{@pos}" end count end
#read_field(reader) (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 104
def read_field(reader) case reader when :node then read_node when :node_list then read_node_list when :hash then read_hash when :string then read_string(@encoding) when :bool then read_u8 != 0 when :location_range then read_location_value when :location_range_list then read_location_value_list when :attr_ivar_name then read_attr_ivar_name else # [:enum, [value_or_nil, ...]] reader[1][read_u8] end end
#read_hash (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 119
def read_hash hash = {} #: Hash[untyped, untyped] read_count.times do key = read_node hash[key] = read_node end hash end
#read_i32 (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 195
def read_i32 value = @bytes.unpack1("l<", offset: @pos) #: Integer @pos += 4 value end
#read_location(loc_children) (private)
The base location of a node, followed by its named child ranges.
# File 'lib/rbs/wasm/deserializer.rb', line 139
def read_location(loc_children) base = read_range children = (loc_children || []).map { |name, required| [name, required, read_range] } return nil unless base location = RBS::Location.new(@buffer, base[0], base[1]) children.each do |name, required, range| if required location.add_required_child(name, range[0]...range[1]) if range else location.add_optional_child(name, range ? (range[0]...range[1]) : nil) end end location end
#read_location_value (private)
A standalone location range field: nil or an ::RBS::Location without children.
# File 'lib/rbs/wasm/deserializer.rb', line 157
def read_location_value range = read_range range && RBS::Location.new(@buffer, range[0], range[1]) end
#read_location_value_list (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 162
def read_location_value_list Array.new(read_count) { read_location_value } end
#read_node
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 45
def read_node tag = read_u8 return nil if tag == 0 return read_string(@encoding).to_sym if tag == SerializationSchema::SYMBOL_TAG entry = SerializationSchema::SCHEMA[tag] or raise "Unknown node tag: #{tag}" case entry[0] when :node then read_struct(entry) when :bool then read_u8 != 0 when :integer then read_string(Encoding::UTF_8).to_i when :string_value then read_string(Encoding::UTF_8) when :record_field then [read_node, read_u8 != 0] when :signature then [read_node_list, read_node_list] when :namespace then RBS::Namespace[read_node_list, read_u8 != 0] when :type_name then RBS::TypeName[read_node, read_node] else raise "Unknown schema entry kind: #{entry[0].inspect}" end end
#read_node_list
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 65
def read_node_list Array.new(read_count) { read_node } end
#read_range (private)
Reads a presence byte and, when present, the start/end character positions.
#read_string(encoding) (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 201
def read_string(encoding) length = read_u32 string = @bytes.byteslice(@pos, length) or raise "Unexpected end of buffer" @pos += length string.force_encoding(encoding) end
#read_struct(entry) (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 84
def read_struct(entry) _, class_name, expose_location, loc_children, fields, resolve_type_params = entry location = read_location(loc_children) if expose_location kwargs = {} #: Hash[Symbol, untyped] (fields || []).each do |name, reader| kwargs[name] = read_field(reader) end RBS::AST::TypeParam.resolve_variables(kwargs[:type_params]) if resolve_type_params klass = class_for(class_name) if expose_location klass.new(location: location, **kwargs) else klass.new(**kwargs) end end
#read_tokens
The lex stream has no leading count: read records until the buffer is exhausted. Each is a token type name followed by its character range.
# File 'lib/rbs/wasm/deserializer.rb', line 71
def read_tokens tokens = [] #: Array[[ Symbol, Location ]] until @pos >= @bytes.bytesize type = read_string(Encoding::UTF_8).to_sym start_char = read_i32 end_char = read_i32 tokens << [type, RBS::Location.new(@buffer, start_char, end_char)] end tokens end
#read_u32 (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 189
def read_u32 value = @bytes.unpack1("L<", offset: @pos) #: Integer @pos += 4 value end
#read_u8 (private)
[ GitHub ]# File 'lib/rbs/wasm/deserializer.rb', line 183
def read_u8 byte = @bytes.getbyte(@pos) or raise "Unexpected end of buffer" @pos += 1 byte end