rbs 3.9.4 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.clang-format +75 -0
- data/.clangd +2 -0
- data/.dockerignore +37 -0
- data/.gitattributes +1 -0
- data/.github/dependabot.yml +16 -14
- data/.github/workflows/bundle-update.yml +63 -0
- data/.github/workflows/c-check.yml +66 -0
- data/.github/workflows/changelog.yml +121 -0
- data/.github/workflows/comments.yml +6 -4
- data/.github/workflows/dependabot.yml +2 -2
- data/.github/workflows/jruby.yml +74 -0
- data/.github/workflows/release-gems.yml +234 -0
- data/.github/workflows/ruby.yml +86 -32
- data/.github/workflows/rust.yml +186 -0
- data/.github/workflows/truffleruby.yml +54 -0
- data/.github/workflows/typecheck.yml +6 -3
- data/.github/workflows/wasm.yml +55 -0
- data/.github/workflows/windows.yml +10 -4
- data/.gitignore +16 -0
- data/.rubocop.yml +1 -2
- data/CHANGELOG.md +502 -0
- data/Dockerfile.jruby +53 -0
- data/README.md +42 -5
- data/Rakefile +892 -111
- data/Steepfile +11 -0
- data/config.yml +665 -62
- data/core/array.rbs +541 -398
- data/core/basic_object.rbs +9 -8
- data/core/binding.rbs +0 -2
- data/core/builtin.rbs +9 -8
- data/core/class.rbs +11 -8
- data/core/comparable.rbs +55 -34
- data/core/complex.rbs +104 -78
- data/core/dir.rbs +61 -49
- data/core/encoding.rbs +12 -15
- data/core/enumerable.rbs +297 -196
- data/core/enumerator/arithmetic_sequence.rbs +70 -0
- data/core/enumerator/product.rbs +5 -5
- data/core/enumerator.rbs +91 -28
- data/core/errno.rbs +11 -2
- data/core/errors.rbs +58 -29
- data/core/exception.rbs +13 -13
- data/core/fiber.rbs +74 -54
- data/core/file.rbs +260 -1151
- data/core/file_constants.rbs +463 -0
- data/core/file_stat.rbs +534 -0
- data/core/file_test.rbs +3 -3
- data/core/float.rbs +257 -116
- data/core/gc.rbs +425 -281
- data/core/hash.rbs +1151 -829
- data/core/integer.rbs +156 -195
- data/core/io/buffer.rbs +53 -42
- data/core/io/wait.rbs +13 -35
- data/core/io.rbs +222 -155
- data/core/kernel.rbs +239 -163
- data/core/marshal.rbs +4 -4
- data/core/match_data.rbs +16 -14
- data/core/math.rbs +107 -66
- data/core/method.rbs +69 -33
- data/core/module.rbs +302 -150
- data/core/nil_class.rbs +7 -6
- data/core/numeric.rbs +77 -63
- data/core/object.rbs +9 -11
- data/core/object_space/weak_key_map.rbs +7 -7
- data/core/object_space.rbs +30 -23
- data/core/pathname.rbs +1312 -0
- data/core/proc.rbs +95 -58
- data/core/process.rbs +222 -202
- data/core/ractor.rbs +364 -518
- data/core/random.rbs +21 -3
- data/core/range.rbs +181 -79
- data/core/rational.rbs +60 -89
- data/core/rbs/ops.rbs +154 -0
- data/core/rbs/unnamed/argf.rbs +63 -56
- data/core/rbs/unnamed/env_class.rbs +19 -14
- data/core/rbs/unnamed/main_class.rbs +123 -0
- data/core/rbs/unnamed/random.rbs +11 -118
- data/core/regexp.rbs +258 -214
- data/core/ruby.rbs +53 -0
- data/core/ruby_vm.rbs +78 -34
- data/core/rubygems/config_file.rbs +5 -5
- data/core/rubygems/errors.rbs +6 -70
- data/core/rubygems/requirement.rbs +5 -15
- data/core/rubygems/rubygems.rbs +18 -81
- data/core/rubygems/specification.rbs +8 -0
- data/core/rubygems/version.rbs +2 -163
- data/core/set.rbs +493 -363
- data/core/signal.rbs +26 -16
- data/core/string.rbs +3234 -1285
- data/core/struct.rbs +43 -42
- data/core/symbol.rbs +41 -34
- data/core/thread.rbs +139 -83
- data/core/time.rbs +81 -50
- data/core/trace_point.rbs +41 -35
- data/core/true_class.rbs +2 -2
- data/core/unbound_method.rbs +24 -16
- data/core/warning.rbs +7 -7
- data/docs/CONTRIBUTING.md +3 -2
- data/docs/aliases.md +79 -0
- data/docs/collection.md +3 -3
- data/docs/config.md +171 -0
- data/docs/encoding.md +56 -0
- data/docs/gem.md +0 -1
- data/docs/inline.md +634 -0
- data/docs/rbs_by_example.md +20 -20
- data/docs/release.md +303 -0
- data/docs/rust.md +96 -0
- data/docs/sigs.md +3 -3
- data/docs/stdlib.md +8 -0
- data/docs/syntax.md +60 -18
- data/docs/type_fingerprint.md +21 -0
- data/docs/wasm_serialization.md +80 -0
- data/exe/rbs +1 -1
- data/ext/rbs_extension/ast_translation.c +1870 -0
- data/ext/rbs_extension/ast_translation.h +41 -0
- data/ext/rbs_extension/class_constants.c +189 -0
- data/{include/rbs/constants.h → ext/rbs_extension/class_constants.h} +24 -1
- data/ext/rbs_extension/compat.h +10 -0
- data/ext/rbs_extension/extconf.rb +26 -1
- data/ext/rbs_extension/legacy_location.c +299 -0
- data/ext/rbs_extension/legacy_location.h +82 -0
- data/ext/rbs_extension/main.c +639 -23
- data/ext/rbs_extension/rbs_extension.h +6 -21
- data/ext/rbs_extension/rbs_string_bridging.c +9 -0
- data/ext/rbs_extension/rbs_string_bridging.h +24 -0
- data/include/rbs/ast.h +1055 -0
- data/include/rbs/defines.h +104 -0
- data/include/rbs/lexer.h +208 -0
- data/include/rbs/location.h +40 -0
- data/include/rbs/parser.h +187 -0
- data/include/rbs/serialize.h +39 -0
- data/include/rbs/string.h +47 -0
- data/include/rbs/util/rbs_allocator.h +59 -0
- data/include/rbs/util/rbs_assert.h +20 -0
- data/include/rbs/util/rbs_buffer.h +83 -0
- data/include/rbs/util/rbs_constant_pool.h +6 -70
- data/include/rbs/util/rbs_encoding.h +282 -0
- data/include/rbs/util/rbs_unescape.h +24 -0
- data/include/rbs.h +9 -2
- data/lib/rbs/annotate/formatter.rb +3 -13
- data/lib/rbs/annotate/rdoc_annotator.rb +30 -32
- data/lib/rbs/annotate/rdoc_source.rb +1 -1
- data/lib/rbs/ast/annotation.rb +1 -1
- data/lib/rbs/ast/comment.rb +1 -1
- data/lib/rbs/ast/declarations.rb +11 -11
- data/lib/rbs/ast/members.rb +14 -14
- data/lib/rbs/ast/ruby/annotations.rb +451 -0
- data/lib/rbs/ast/ruby/comment_block.rb +247 -0
- data/lib/rbs/ast/ruby/declarations.rb +291 -0
- data/lib/rbs/ast/ruby/helpers/constant_helper.rb +28 -0
- data/lib/rbs/ast/ruby/helpers/location_helper.rb +15 -0
- data/lib/rbs/ast/ruby/members.rb +762 -0
- data/lib/rbs/ast/type_param.rb +25 -5
- data/lib/rbs/buffer.rb +142 -20
- data/lib/rbs/cli/diff.rb +16 -15
- data/lib/rbs/cli/validate.rb +63 -126
- data/lib/rbs/cli.rb +59 -29
- data/lib/rbs/collection/config/lockfile_generator.rb +28 -3
- data/lib/rbs/collection/sources/git.rb +7 -0
- data/lib/rbs/definition.rb +6 -1
- data/lib/rbs/definition_builder/ancestor_builder.rb +129 -70
- data/lib/rbs/definition_builder/method_builder.rb +74 -33
- data/lib/rbs/definition_builder.rb +181 -21
- data/lib/rbs/diff.rb +7 -1
- data/lib/rbs/environment/class_entry.rb +81 -0
- data/lib/rbs/environment/module_entry.rb +91 -0
- data/lib/rbs/environment.rb +410 -215
- data/lib/rbs/environment_loader.rb +2 -8
- data/lib/rbs/errors.rb +31 -21
- data/lib/rbs/inline_parser/comment_association.rb +117 -0
- data/lib/rbs/inline_parser.rb +568 -0
- data/lib/rbs/location_aux.rb +36 -4
- data/lib/rbs/locator.rb +5 -1
- data/lib/rbs/method_type.rb +5 -3
- data/lib/rbs/namespace.rb +47 -18
- data/lib/rbs/parser_aux.rb +37 -7
- data/lib/rbs/prototype/helpers.rb +24 -0
- data/lib/rbs/prototype/rb.rb +3 -28
- data/lib/rbs/prototype/rbi.rb +196 -45
- data/lib/rbs/prototype/runtime/value_object_generator.rb +0 -1
- data/lib/rbs/prototype/runtime.rb +13 -3
- data/lib/rbs/resolver/constant_resolver.rb +2 -2
- data/lib/rbs/resolver/type_name_resolver.rb +120 -44
- data/lib/rbs/rewriter.rb +70 -0
- data/lib/rbs/source.rb +99 -0
- data/lib/rbs/subtractor.rb +7 -4
- data/lib/rbs/test/type_check.rb +25 -3
- data/lib/rbs/type_name.rb +34 -21
- data/lib/rbs/types.rb +135 -81
- data/lib/rbs/unit_test/convertibles.rb +1 -0
- data/lib/rbs/unit_test/type_assertions.rb +47 -11
- data/lib/rbs/validator.rb +2 -2
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/wasm/deserializer.rb +213 -0
- data/lib/rbs/wasm/location.rb +61 -0
- data/lib/rbs/wasm/parser.rb +174 -0
- data/lib/rbs/wasm/runtime.rb +211 -0
- data/lib/rbs/wasm/serialization_schema.rb +111 -0
- data/lib/rbs.rb +25 -2
- data/lib/rbs_jars.rb +39 -0
- data/lib/rdoc/discover.rb +1 -1
- data/lib/rdoc_plugin/parser.rb +8 -3
- data/rbs.gemspec +34 -6
- data/schema/function.json +12 -1
- data/schema/typeParam.json +17 -1
- data/sig/ancestor_builder.rbs +1 -1
- data/sig/annotate/formatter.rbs +2 -2
- data/sig/annotate/rdoc_annotater.rbs +13 -10
- data/sig/ast/ruby/annotations.rbs +470 -0
- data/sig/ast/ruby/comment_block.rbs +127 -0
- data/sig/ast/ruby/declarations.rbs +158 -0
- data/sig/ast/ruby/helpers/constant_helper.rbs +11 -0
- data/sig/ast/ruby/helpers/location_helper.rbs +15 -0
- data/sig/ast/ruby/members.rbs +198 -0
- data/sig/buffer.rbs +81 -5
- data/sig/cli/diff.rbs +5 -11
- data/sig/cli/validate.rbs +12 -8
- data/sig/cli.rbs +18 -18
- data/sig/collection/config/lockfile_generator.rbs +2 -0
- data/sig/definition.rbs +6 -0
- data/sig/definition_builder.rbs +3 -1
- data/sig/environment/class_entry.rbs +56 -0
- data/sig/environment/module_entry.rbs +65 -0
- data/sig/environment.rbs +94 -87
- data/sig/errors.rbs +26 -20
- data/sig/inline_parser/comment_association.rbs +71 -0
- data/sig/inline_parser.rbs +126 -0
- data/sig/location.rbs +32 -7
- data/sig/locator.rbs +0 -2
- data/sig/manifest.yaml +0 -2
- data/sig/method_builder.rbs +9 -4
- data/sig/namespace.rbs +20 -5
- data/sig/parser.rbs +79 -15
- data/sig/prototype/helpers.rbs +2 -0
- data/sig/prototype/rbi.rbs +33 -4
- data/sig/resolver/type_name_resolver.rbs +36 -10
- data/sig/rewriter.rbs +45 -0
- data/sig/source.rbs +48 -0
- data/sig/type_param.rbs +13 -8
- data/sig/typename.rbs +15 -5
- data/sig/types.rbs +21 -9
- data/sig/unit_test/spy.rbs +0 -8
- data/sig/unit_test/type_assertions.rbs +17 -2
- data/sig/wasm/deserializer.rbs +66 -0
- data/sig/wasm/serialization_schema.rbs +13 -0
- data/src/ast.c +1644 -0
- data/src/lexer.c +3223 -0
- data/src/lexer.re +187 -0
- data/src/lexstate.c +222 -0
- data/src/location.c +31 -0
- data/src/parser.c +4318 -0
- data/src/serialize.c +965 -0
- data/src/string.c +41 -0
- data/src/util/rbs_allocator.c +171 -0
- data/src/util/rbs_assert.c +19 -0
- data/src/util/rbs_buffer.c +54 -0
- data/src/util/rbs_constant_pool.c +18 -92
- data/src/util/rbs_encoding.c +21454 -0
- data/src/util/rbs_unescape.c +167 -0
- data/stdlib/abbrev/0/array.rbs +1 -1
- data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
- data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
- data/stdlib/cgi/0/core.rbs +9 -393
- data/stdlib/cgi/0/manifest.yaml +1 -0
- data/stdlib/cgi-escape/0/escape.rbs +171 -0
- data/stdlib/coverage/0/coverage.rbs +7 -4
- data/stdlib/csv/0/csv.rbs +5 -5
- data/stdlib/date/0/date.rbs +92 -79
- data/stdlib/date/0/date_time.rbs +25 -24
- data/stdlib/delegate/0/delegator.rbs +11 -7
- data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
- data/stdlib/digest/0/digest.rbs +117 -1
- data/stdlib/erb/0/erb.rbs +754 -353
- data/stdlib/etc/0/etc.rbs +73 -54
- data/stdlib/fileutils/0/fileutils.rbs +179 -160
- data/stdlib/forwardable/0/forwardable.rbs +13 -10
- data/stdlib/io-console/0/io-console.rbs +2 -2
- data/stdlib/ipaddr/0/ipaddr.rbs +0 -5
- data/stdlib/json/0/json.rbs +232 -185
- data/stdlib/monitor/0/monitor.rbs +9 -9
- data/stdlib/net-http/0/net-http.rbs +162 -134
- data/stdlib/objspace/0/objspace.rbs +17 -34
- data/stdlib/open-uri/0/open-uri.rbs +48 -8
- data/stdlib/open3/0/open3.rbs +469 -10
- data/stdlib/openssl/0/openssl.rbs +521 -397
- data/stdlib/optparse/0/optparse.rbs +26 -17
- data/stdlib/pathname/0/pathname.rbs +11 -1381
- data/stdlib/pp/0/pp.rbs +9 -8
- data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
- data/stdlib/pstore/0/pstore.rbs +35 -30
- data/stdlib/psych/0/psych.rbs +65 -12
- data/stdlib/psych/0/store.rbs +2 -4
- data/stdlib/pty/0/pty.rbs +9 -6
- data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
- data/stdlib/rdoc/0/code_object.rbs +4 -3
- data/stdlib/rdoc/0/comment.rbs +2 -0
- data/stdlib/rdoc/0/options.rbs +76 -0
- data/stdlib/rdoc/0/parser.rbs +1 -1
- data/stdlib/rdoc/0/rdoc.rbs +7 -5
- data/stdlib/rdoc/0/store.rbs +2 -2
- data/stdlib/resolv/0/resolv.rbs +26 -69
- data/stdlib/ripper/0/ripper.rbs +25 -19
- data/stdlib/securerandom/0/manifest.yaml +2 -0
- data/stdlib/securerandom/0/securerandom.rbs +7 -20
- data/stdlib/shellwords/0/shellwords.rbs +3 -3
- data/stdlib/singleton/0/singleton.rbs +6 -0
- data/stdlib/socket/0/addrinfo.rbs +9 -9
- data/stdlib/socket/0/basic_socket.rbs +3 -3
- data/stdlib/socket/0/ip_socket.rbs +10 -8
- data/stdlib/socket/0/socket.rbs +23 -10
- data/stdlib/socket/0/tcp_server.rbs +1 -1
- data/stdlib/socket/0/tcp_socket.rbs +11 -3
- data/stdlib/socket/0/udp_socket.rbs +1 -1
- data/stdlib/socket/0/unix_server.rbs +1 -1
- data/stdlib/stringio/0/stringio.rbs +1211 -96
- data/stdlib/strscan/0/string_scanner.rbs +101 -80
- data/stdlib/tempfile/0/manifest.yaml +3 -0
- data/stdlib/tempfile/0/tempfile.rbs +25 -21
- data/stdlib/time/0/time.rbs +8 -6
- data/stdlib/timeout/0/timeout.rbs +58 -7
- data/stdlib/tsort/0/cyclic.rbs +4 -1
- data/stdlib/tsort/0/interfaces.rbs +8 -8
- data/stdlib/tsort/0/tsort.rbs +16 -15
- data/stdlib/uri/0/common.rbs +42 -20
- data/stdlib/uri/0/file.rbs +3 -3
- data/stdlib/uri/0/generic.rbs +21 -18
- data/stdlib/uri/0/http.rbs +2 -2
- data/stdlib/uri/0/ldap.rbs +2 -2
- data/stdlib/uri/0/mailto.rbs +3 -3
- data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
- data/stdlib/zlib/0/deflate.rbs +4 -3
- data/stdlib/zlib/0/gzip_file.rbs +1 -1
- data/stdlib/zlib/0/gzip_reader.rbs +8 -8
- data/stdlib/zlib/0/gzip_writer.rbs +16 -13
- data/stdlib/zlib/0/inflate.rbs +1 -1
- data/stdlib/zlib/0/need_dict.rbs +1 -1
- data/wasm/README.md +109 -0
- data/wasm/rbs_wasm.c +479 -0
- metadata +133 -19
- data/ext/rbs_extension/lexer.c +0 -2728
- data/ext/rbs_extension/lexer.h +0 -179
- data/ext/rbs_extension/lexer.re +0 -147
- data/ext/rbs_extension/lexstate.c +0 -175
- data/ext/rbs_extension/location.c +0 -325
- data/ext/rbs_extension/location.h +0 -85
- data/ext/rbs_extension/parser.c +0 -2982
- data/ext/rbs_extension/parser.h +0 -18
- data/ext/rbs_extension/parserstate.c +0 -411
- data/ext/rbs_extension/parserstate.h +0 -163
- data/ext/rbs_extension/unescape.c +0 -32
- data/include/rbs/ruby_objs.h +0 -72
- data/src/constants.c +0 -153
- data/src/ruby_objs.c +0 -799
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "serialization_schema"
|
|
4
|
+
|
|
5
|
+
module RBS
|
|
6
|
+
module WASM
|
|
7
|
+
# Rebuilds RBS::AST objects from the binary buffer produced by
|
|
8
|
+
# `rbs_serialize_node` (src/serialize.c), driven by the generated
|
|
9
|
+
# SerializationSchema. This is the pure-Ruby counterpart of the C extension's
|
|
10
|
+
# ast_translation.c, used when the parser runs inside WebAssembly (JRuby).
|
|
11
|
+
#
|
|
12
|
+
# All locations are reconstructed through the public RBS::Location API, so the
|
|
13
|
+
# same code works whether RBS::Location is backed by the C extension (CRuby)
|
|
14
|
+
# or by a pure-Ruby implementation (JRuby).
|
|
15
|
+
class Deserializer
|
|
16
|
+
# Deserialize a buffer produced for a whole signature, returning
|
|
17
|
+
# `[directives, declarations]` to match RBS::Parser._parse_signature.
|
|
18
|
+
def self.deserialize(bytes, buffer)
|
|
19
|
+
new(bytes, buffer).read_node
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Deserialize a bare node list (rbs_serialize_node_list), e.g. the result
|
|
23
|
+
# of RBS::Parser._parse_type_params.
|
|
24
|
+
def self.deserialize_node_list(bytes, buffer)
|
|
25
|
+
new(bytes, buffer).read_node_list
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Deserialize the token stream produced by rbs_wasm_lex into the
|
|
29
|
+
# [type, location] pairs RBS::Parser._lex returns.
|
|
30
|
+
def self.deserialize_tokens(bytes, buffer)
|
|
31
|
+
new(bytes, buffer).read_tokens
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def initialize(bytes, buffer)
|
|
35
|
+
@bytes = bytes
|
|
36
|
+
@buffer = buffer
|
|
37
|
+
# Symbols and rbs_string fields (comments, annotations) inherit the
|
|
38
|
+
# source encoding, matching ast_translation.c. String/Integer literal
|
|
39
|
+
# nodes are always UTF-8 (see read_node).
|
|
40
|
+
@encoding = buffer.content.encoding
|
|
41
|
+
@pos = 0
|
|
42
|
+
@class_cache = {} #: Hash[String, untyped]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def read_node
|
|
46
|
+
tag = read_u8
|
|
47
|
+
return nil if tag == 0
|
|
48
|
+
return read_string(@encoding).to_sym if tag == SerializationSchema::SYMBOL_TAG
|
|
49
|
+
|
|
50
|
+
entry = SerializationSchema::SCHEMA[tag] or raise "Unknown node tag: #{tag}"
|
|
51
|
+
|
|
52
|
+
case entry[0]
|
|
53
|
+
when :node then read_struct(entry)
|
|
54
|
+
when :bool then read_u8 != 0
|
|
55
|
+
when :integer then read_string(Encoding::UTF_8).to_i
|
|
56
|
+
when :string_value then read_string(Encoding::UTF_8)
|
|
57
|
+
when :record_field then [read_node, read_u8 != 0]
|
|
58
|
+
when :signature then [read_node_list, read_node_list]
|
|
59
|
+
when :namespace then RBS::Namespace[read_node_list, read_u8 != 0]
|
|
60
|
+
when :type_name then RBS::TypeName[read_node, read_node]
|
|
61
|
+
else raise "Unknown schema entry kind: #{entry[0].inspect}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def read_node_list
|
|
66
|
+
Array.new(read_count) { read_node }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The lex stream has no leading count: read records until the buffer is
|
|
70
|
+
# exhausted. Each is a token type name followed by its character range.
|
|
71
|
+
def read_tokens
|
|
72
|
+
tokens = [] #: Array[[ Symbol, Location ]]
|
|
73
|
+
until @pos >= @bytes.bytesize
|
|
74
|
+
type = read_string(Encoding::UTF_8).to_sym
|
|
75
|
+
start_char = read_i32
|
|
76
|
+
end_char = read_i32
|
|
77
|
+
tokens << [type, RBS::Location.new(@buffer, start_char, end_char)]
|
|
78
|
+
end
|
|
79
|
+
tokens
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def read_struct(entry)
|
|
85
|
+
_, class_name, expose_location, loc_children, fields, resolve_type_params = entry
|
|
86
|
+
|
|
87
|
+
location = read_location(loc_children) if expose_location
|
|
88
|
+
|
|
89
|
+
kwargs = {} #: Hash[Symbol, untyped]
|
|
90
|
+
(fields || []).each do |name, reader|
|
|
91
|
+
kwargs[name] = read_field(reader)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
RBS::AST::TypeParam.resolve_variables(kwargs[:type_params]) if resolve_type_params
|
|
95
|
+
|
|
96
|
+
klass = class_for(class_name)
|
|
97
|
+
if expose_location
|
|
98
|
+
klass.new(location: location, **kwargs)
|
|
99
|
+
else
|
|
100
|
+
klass.new(**kwargs)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def read_field(reader)
|
|
105
|
+
case reader
|
|
106
|
+
when :node then read_node
|
|
107
|
+
when :node_list then read_node_list
|
|
108
|
+
when :hash then read_hash
|
|
109
|
+
when :string then read_string(@encoding)
|
|
110
|
+
when :bool then read_u8 != 0
|
|
111
|
+
when :location_range then read_location_value
|
|
112
|
+
when :location_range_list then read_location_value_list
|
|
113
|
+
when :attr_ivar_name then read_attr_ivar_name
|
|
114
|
+
else # [:enum, [value_or_nil, ...]]
|
|
115
|
+
reader[1][read_u8]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def read_hash
|
|
120
|
+
hash = {} #: Hash[untyped, untyped]
|
|
121
|
+
read_count.times do
|
|
122
|
+
key = read_node
|
|
123
|
+
hash[key] = read_node
|
|
124
|
+
end
|
|
125
|
+
hash
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# A count of nested items. Each item is at least one byte, so a count that
|
|
129
|
+
# exceeds the bytes remaining signals the cursor has drifted out of sync.
|
|
130
|
+
def read_count
|
|
131
|
+
count = read_u32
|
|
132
|
+
if count > @bytes.bytesize - @pos
|
|
133
|
+
raise "Corrupt buffer: count #{count} exceeds #{@bytes.bytesize - @pos} remaining bytes at offset #{@pos}"
|
|
134
|
+
end
|
|
135
|
+
count
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# The base location of a node, followed by its named child ranges.
|
|
139
|
+
def read_location(loc_children)
|
|
140
|
+
base = read_range
|
|
141
|
+
children = (loc_children || []).map { |name, required| [name, required, read_range] }
|
|
142
|
+
|
|
143
|
+
return nil unless base
|
|
144
|
+
|
|
145
|
+
location = RBS::Location.new(@buffer, base[0], base[1])
|
|
146
|
+
children.each do |name, required, range|
|
|
147
|
+
if required
|
|
148
|
+
location.add_required_child(name, range[0]...range[1]) if range
|
|
149
|
+
else
|
|
150
|
+
location.add_optional_child(name, range ? (range[0]...range[1]) : nil)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
location
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# A standalone location range field: nil or an RBS::Location without children.
|
|
157
|
+
def read_location_value
|
|
158
|
+
range = read_range
|
|
159
|
+
range && RBS::Location.new(@buffer, range[0], range[1])
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def read_location_value_list
|
|
163
|
+
Array.new(read_count) { read_location_value }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def read_attr_ivar_name
|
|
167
|
+
case read_u8
|
|
168
|
+
when 0 then nil # inferred instance variable
|
|
169
|
+
when 1 then false # no instance variable
|
|
170
|
+
else read_string(@encoding).to_sym
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Reads a presence byte and, when present, the start/end character positions.
|
|
175
|
+
def read_range
|
|
176
|
+
return nil if read_u8 == 0
|
|
177
|
+
|
|
178
|
+
start_char = read_i32
|
|
179
|
+
end_char = read_i32
|
|
180
|
+
[start_char, end_char]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def read_u8
|
|
184
|
+
byte = @bytes.getbyte(@pos) or raise "Unexpected end of buffer"
|
|
185
|
+
@pos += 1
|
|
186
|
+
byte
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def read_u32
|
|
190
|
+
value = @bytes.unpack1("L<", offset: @pos) #: Integer
|
|
191
|
+
@pos += 4
|
|
192
|
+
value
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def read_i32
|
|
196
|
+
value = @bytes.unpack1("l<", offset: @pos) #: Integer
|
|
197
|
+
@pos += 4
|
|
198
|
+
value
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def read_string(encoding)
|
|
202
|
+
length = read_u32
|
|
203
|
+
string = @bytes.byteslice(@pos, length) or raise "Unexpected end of buffer"
|
|
204
|
+
@pos += length
|
|
205
|
+
string.force_encoding(encoding)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def class_for(name)
|
|
209
|
+
@class_cache[name] ||= Object.const_get(name)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBS
|
|
4
|
+
# Pure-Ruby implementation of the primitives that back RBS::Location.
|
|
5
|
+
#
|
|
6
|
+
# On CRuby these come from the C extension (ext/rbs_extension/legacy_location.c).
|
|
7
|
+
# JRuby loads this instead, before rbs/location_aux.rb layers the public API on
|
|
8
|
+
# top, so RBS::Location behaves identically without the native extension.
|
|
9
|
+
class Location
|
|
10
|
+
attr_reader :buffer
|
|
11
|
+
|
|
12
|
+
def initialize(buffer, start_pos, end_pos)
|
|
13
|
+
@buffer = buffer
|
|
14
|
+
@start_pos = start_pos
|
|
15
|
+
@end_pos = end_pos
|
|
16
|
+
@required_children = {} #: Hash[Symbol, [ Integer, Integer ]]
|
|
17
|
+
@optional_children = {} #: Hash[Symbol, [ Integer, Integer ]?]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def _start_pos
|
|
21
|
+
@start_pos
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def _end_pos
|
|
25
|
+
@end_pos
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def _add_required_child(name, start_pos, end_pos)
|
|
29
|
+
@required_children[name] = [start_pos, end_pos]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def _add_optional_child(name, start_pos, end_pos)
|
|
33
|
+
@optional_children[name] = [start_pos, end_pos]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _add_optional_no_child(name)
|
|
37
|
+
@optional_children[name] = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def _required_keys
|
|
41
|
+
@required_children.keys
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def _optional_keys
|
|
45
|
+
@optional_children.keys
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def [](name)
|
|
49
|
+
if (range = @required_children[name])
|
|
50
|
+
return Location.new(@buffer, range[0], range[1])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if @optional_children.key?(name)
|
|
54
|
+
range = @optional_children[name]
|
|
55
|
+
return range && Location.new(@buffer, range[0], range[1])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
raise "Unknown child name given: #{name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "runtime"
|
|
4
|
+
require_relative "deserializer"
|
|
5
|
+
|
|
6
|
+
module RBS
|
|
7
|
+
# WebAssembly-backed implementation of the parser primitives.
|
|
8
|
+
#
|
|
9
|
+
# On CRuby these come from the C extension (ext/rbs_extension/main.c). JRuby
|
|
10
|
+
# loads this instead: it runs the parser inside WebAssembly, then rebuilds the
|
|
11
|
+
# AST with RBS::WASM::Deserializer. rbs/parser_aux.rb layers the public
|
|
12
|
+
# RBS::Parser API on top, exactly as it does for the C extension.
|
|
13
|
+
class Parser
|
|
14
|
+
class << self
|
|
15
|
+
def _parse_signature(buffer, start_pos, end_pos, enable_forwarding_params)
|
|
16
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
17
|
+
validate_parser_options(enable_forwarding_params)
|
|
18
|
+
encoding = buffer.content.encoding.name
|
|
19
|
+
status, bytes = WASM::Runtime.instance.parse_signature(buffer.content, encoding, start_pos, end_pos)
|
|
20
|
+
raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
|
|
21
|
+
|
|
22
|
+
WASM::Deserializer.deserialize(bytes, buffer)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def _parse_type(buffer, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
|
|
26
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
27
|
+
validate_variables(variables)
|
|
28
|
+
encoding = buffer.content.encoding.name
|
|
29
|
+
status, bytes = WASM::Runtime.instance.parse_type(buffer.content, encoding, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
|
|
30
|
+
raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
|
|
31
|
+
|
|
32
|
+
deserialize_or_nil(bytes, buffer)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def _parse_method_type(buffer, start_pos, end_pos, variables, require_eof, enable_forwarding_params)
|
|
36
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
37
|
+
validate_variables(variables)
|
|
38
|
+
validate_parser_options(enable_forwarding_params)
|
|
39
|
+
encoding = buffer.content.encoding.name
|
|
40
|
+
status, bytes = WASM::Runtime.instance.parse_method_type(buffer.content, encoding, start_pos, end_pos, variables, require_eof)
|
|
41
|
+
raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
|
|
42
|
+
|
|
43
|
+
deserialize_or_nil(bytes, buffer)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def _parse_type_params(buffer, start_pos, end_pos, module_type_params)
|
|
47
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
48
|
+
encoding = buffer.content.encoding.name
|
|
49
|
+
status, bytes = WASM::Runtime.instance.parse_type_params(buffer.content, encoding, start_pos, end_pos, module_type_params)
|
|
50
|
+
raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
|
|
51
|
+
|
|
52
|
+
bytes.empty? ? nil : WASM::Deserializer.deserialize_node_list(bytes, buffer)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def _lex(buffer, end_pos)
|
|
56
|
+
encoding = buffer.content.encoding.name
|
|
57
|
+
_status, bytes = WASM::Runtime.instance.lex(buffer.content, encoding, end_pos)
|
|
58
|
+
|
|
59
|
+
WASM::Deserializer.deserialize_tokens(bytes, buffer)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def _parse_inline_leading_annotation(buffer, start_pos, end_pos, variables)
|
|
63
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
64
|
+
validate_variables(variables)
|
|
65
|
+
encoding = buffer.content.encoding.name
|
|
66
|
+
status, bytes = WASM::Runtime.instance.parse_inline_leading_annotation(buffer.content, encoding, start_pos, end_pos, variables)
|
|
67
|
+
raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
|
|
68
|
+
|
|
69
|
+
deserialize_or_nil(bytes, buffer)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def _parse_inline_trailing_annotation(buffer, start_pos, end_pos, variables)
|
|
73
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
74
|
+
validate_variables(variables)
|
|
75
|
+
encoding = buffer.content.encoding.name
|
|
76
|
+
status, bytes = WASM::Runtime.instance.parse_inline_trailing_annotation(buffer.content, encoding, start_pos, end_pos, variables)
|
|
77
|
+
raise_parse_failure(buffer, status, bytes, start_pos, end_pos) unless status == WASM::Runtime::OK
|
|
78
|
+
|
|
79
|
+
deserialize_or_nil(bytes, buffer)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
# Reject the position ranges the parser cannot take, matching
|
|
85
|
+
# validate_position_range in the C extension (main.c).
|
|
86
|
+
#
|
|
87
|
+
# `end_pos` past the end of the buffer is fine: clamping with a large
|
|
88
|
+
# number instead of measuring the buffer is ordinary, and the lexer stops
|
|
89
|
+
# at the end of the input on its own.
|
|
90
|
+
def validate_position_range(buffer, start_pos, end_pos)
|
|
91
|
+
if start_pos < 0 || end_pos < 0
|
|
92
|
+
raise ArgumentError, "negative position range: #{start_pos}...#{end_pos}"
|
|
93
|
+
end
|
|
94
|
+
if start_pos > end_pos
|
|
95
|
+
raise ArgumentError, "invalid position range: #{start_pos}...#{end_pos}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
size = buffer.content.bytesize
|
|
99
|
+
if start_pos > size
|
|
100
|
+
raise ArgumentError, "position range starts past the end of the buffer: #{start_pos}...#{end_pos}, buffer is #{size} bytes"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# The WebAssembly entry points (rbs_wasm.c) build their parsers with the
|
|
105
|
+
# default options, so the optional syntax the C extension can enable is
|
|
106
|
+
# not reachable here. The public RBS::Parser API never enables it.
|
|
107
|
+
def validate_parser_options(enable_forwarding_params)
|
|
108
|
+
if enable_forwarding_params
|
|
109
|
+
raise NotImplementedError, "forwarding parameter syntax is not supported by the WebAssembly parser"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Reject anything that is not nil or an Array of Symbols, matching
|
|
114
|
+
# declare_type_variables in the C extension (main.c).
|
|
115
|
+
def validate_variables(variables)
|
|
116
|
+
return if variables.nil?
|
|
117
|
+
|
|
118
|
+
unless variables.is_a?(Array)
|
|
119
|
+
raise TypeError, "wrong argument type #{variables.class} (must be an Array of Symbols or nil)"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
variables.each do |variable|
|
|
123
|
+
unless variable.is_a?(Symbol)
|
|
124
|
+
raise TypeError, "Type variables Array contains invalid value #{variable.inspect} of type #{variable.class} (must be an Array of Symbols or nil)"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# An empty result means the parser reached EOF immediately (`nil`).
|
|
130
|
+
def deserialize_or_nil(bytes, buffer)
|
|
131
|
+
bytes.empty? ? nil : WASM::Deserializer.deserialize(bytes, buffer)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Raise for a status other than OK (see rbs_wasm.c).
|
|
135
|
+
#
|
|
136
|
+
# A negative status is about the range rather than the source text, so it
|
|
137
|
+
# comes with an empty result and an ArgumentError, as in the C extension
|
|
138
|
+
# (main.c). Starting past the end of the buffer is plain from the
|
|
139
|
+
# buffer's size and rejected above, so a start position that comes back
|
|
140
|
+
# rejected can only be one inside a character.
|
|
141
|
+
def raise_parse_failure(buffer, status, bytes, start_pos, end_pos)
|
|
142
|
+
case status
|
|
143
|
+
when WASM::Runtime::INVALID_START_POS
|
|
144
|
+
raise ArgumentError, "position range starts inside a character: #{start_pos}...#{end_pos}"
|
|
145
|
+
when WASM::Runtime::INVALID_RANGE
|
|
146
|
+
raise ArgumentError, "invalid position range: #{start_pos}...#{end_pos}"
|
|
147
|
+
else
|
|
148
|
+
raise_parsing_error(buffer, bytes)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Decodes the error blob written by set_error_result (rbs_wasm.c) and raises
|
|
153
|
+
# the same error the C extension would (see raise_error in main.c).
|
|
154
|
+
def raise_parsing_error(buffer, blob)
|
|
155
|
+
start_char, end_char, syntax_error = blob.unpack("l<l<C")
|
|
156
|
+
|
|
157
|
+
raise "Unexpected error" if syntax_error.zero?
|
|
158
|
+
|
|
159
|
+
offset = 9
|
|
160
|
+
token_type_length = blob.unpack1("L<", offset: offset)
|
|
161
|
+
offset += 4
|
|
162
|
+
token_type = blob.byteslice(offset, token_type_length).to_s.force_encoding(Encoding::UTF_8)
|
|
163
|
+
offset += token_type_length
|
|
164
|
+
|
|
165
|
+
message_length = blob.unpack1("L<", offset: offset)
|
|
166
|
+
offset += 4
|
|
167
|
+
message = blob.byteslice(offset, message_length).to_s.force_encoding(Encoding::UTF_8)
|
|
168
|
+
|
|
169
|
+
location = Location.new(buffer, start_char, end_char)
|
|
170
|
+
raise ParsingError.new(location, message, token_type)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "java"
|
|
4
|
+
require "monitor"
|
|
5
|
+
|
|
6
|
+
module RBS
|
|
7
|
+
module WASM
|
|
8
|
+
# Loads rbs_parser.wasm into a JVM WebAssembly runtime (Chicory) and drives
|
|
9
|
+
# it. This is the JRuby counterpart of the C extension's main.c: it copies a
|
|
10
|
+
# source string into the module's linear memory, runs the parser, and returns
|
|
11
|
+
# the serialized result for RBS::WASM::Deserializer to rebuild.
|
|
12
|
+
#
|
|
13
|
+
# Chicory is a pure-Java runtime, so there is no native dependency. The
|
|
14
|
+
# `.wasm` ships in the gem; the Chicory jars are fetched from Maven by
|
|
15
|
+
# jar-dependencies (see lib/rbs_jars.rb and rbs.gemspec).
|
|
16
|
+
class Runtime
|
|
17
|
+
include MonitorMixin
|
|
18
|
+
|
|
19
|
+
# Statuses the parse entry points return (see rbs_wasm.c). A negative one
|
|
20
|
+
# is about the range the caller asked for rather than the source text,
|
|
21
|
+
# and comes with an empty result.
|
|
22
|
+
INVALID_START_POS = -2
|
|
23
|
+
INVALID_RANGE = -1
|
|
24
|
+
PARSE_ERROR = 0
|
|
25
|
+
OK = 1
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
def instance
|
|
29
|
+
@instance ||= new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def wasm_path
|
|
33
|
+
ENV["RBS_WASM_PARSER"] || File.expand_path("rbs_parser.wasm", __dir__)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def initialize
|
|
38
|
+
super()
|
|
39
|
+
# rbs_jars.rb require_jars the Chicory/ASM jars from the local Maven
|
|
40
|
+
# repository (~/.m2), where jar-dependencies puts them at gem install (or
|
|
41
|
+
# `rake wasm:install_jars` when running from source).
|
|
42
|
+
require "rbs_jars"
|
|
43
|
+
@wasm = build_instance
|
|
44
|
+
@memory = @wasm.memory
|
|
45
|
+
@alloc = @wasm.export("rbs_wasm_alloc")
|
|
46
|
+
@free = @wasm.export("rbs_wasm_free")
|
|
47
|
+
@result_ptr = @wasm.export("rbs_wasm_result_ptr")
|
|
48
|
+
@result_len = @wasm.export("rbs_wasm_result_len")
|
|
49
|
+
@parse_signature = @wasm.export("rbs_wasm_parse_signature")
|
|
50
|
+
@parse_type = @wasm.export("rbs_wasm_parse_type")
|
|
51
|
+
@parse_method_type = @wasm.export("rbs_wasm_parse_method_type")
|
|
52
|
+
@parse_type_params = @wasm.export("rbs_wasm_parse_type_params")
|
|
53
|
+
@parse_inline_leading_annotation = @wasm.export("rbs_wasm_parse_inline_leading_annotation")
|
|
54
|
+
@parse_inline_trailing_annotation = @wasm.export("rbs_wasm_parse_inline_trailing_annotation")
|
|
55
|
+
@lex = @wasm.export("rbs_wasm_lex")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# `content` is the whole buffer; `start_pos`/`end_pos` are the character
|
|
59
|
+
# range within it to parse. Each method returns [status, bytes]: with OK
|
|
60
|
+
# `bytes` is the serialized AST, with PARSE_ERROR it is the error blob (see
|
|
61
|
+
# set_error_result in rbs_wasm.c), and with a negative status it is empty.
|
|
62
|
+
|
|
63
|
+
def parse_signature(content, encoding, start_pos, end_pos)
|
|
64
|
+
run(content, encoding) { |ptr, len, enc_ptr, enc_len| @parse_signature.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos)[0] }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def parse_type(content, encoding, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
|
|
68
|
+
with_variables(variables) do |vars_ptr, vars_len|
|
|
69
|
+
run(content, encoding) do |ptr, len, enc_ptr, enc_len|
|
|
70
|
+
@parse_type.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos, vars_ptr, vars_len, bool(require_eof), bool(void_allowed), bool(self_allowed), bool(classish_allowed))[0]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def parse_method_type(content, encoding, start_pos, end_pos, variables, require_eof)
|
|
76
|
+
with_variables(variables) do |vars_ptr, vars_len|
|
|
77
|
+
run(content, encoding) do |ptr, len, enc_ptr, enc_len|
|
|
78
|
+
@parse_method_type.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos, vars_ptr, vars_len, bool(require_eof))[0]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def parse_type_params(content, encoding, start_pos, end_pos, module_type_params)
|
|
84
|
+
run(content, encoding) do |ptr, len, enc_ptr, enc_len|
|
|
85
|
+
@parse_type_params.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos, bool(module_type_params))[0]
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def parse_inline_leading_annotation(content, encoding, start_pos, end_pos, variables)
|
|
90
|
+
with_variables(variables) do |vars_ptr, vars_len|
|
|
91
|
+
run(content, encoding) do |ptr, len, enc_ptr, enc_len|
|
|
92
|
+
@parse_inline_leading_annotation.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos, vars_ptr, vars_len)[0]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def parse_inline_trailing_annotation(content, encoding, start_pos, end_pos, variables)
|
|
98
|
+
with_variables(variables) do |vars_ptr, vars_len|
|
|
99
|
+
run(content, encoding) do |ptr, len, enc_ptr, enc_len|
|
|
100
|
+
@parse_inline_trailing_annotation.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos, vars_ptr, vars_len)[0]
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def lex(content, encoding, end_pos)
|
|
106
|
+
run(content, encoding) do |ptr, len, enc_ptr, enc_len|
|
|
107
|
+
@lex.apply(ptr, len, enc_ptr, enc_len, end_pos)[0]
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
# Copies `source` and its encoding name into linear memory, yields their
|
|
114
|
+
# pointers/lengths to the block (which invokes the parser and returns its
|
|
115
|
+
# status), then reads the result back out. Serialized through the monitor
|
|
116
|
+
# because the module keeps its result in a single shared location.
|
|
117
|
+
def run(source, encoding)
|
|
118
|
+
synchronize do
|
|
119
|
+
bytes = source.b
|
|
120
|
+
length = bytes.bytesize
|
|
121
|
+
name = encoding.to_s.b
|
|
122
|
+
name_length = name.bytesize
|
|
123
|
+
source_ptr = @alloc.apply(length)[0]
|
|
124
|
+
name_ptr = @alloc.apply(name_length)[0]
|
|
125
|
+
begin
|
|
126
|
+
@memory.write(source_ptr, bytes.to_java_bytes)
|
|
127
|
+
@memory.write(name_ptr, name.to_java_bytes) unless name_length.zero?
|
|
128
|
+
status = yield(source_ptr, length, name_ptr, name_length)
|
|
129
|
+
[i32(status), read_result]
|
|
130
|
+
ensure
|
|
131
|
+
@free.apply(source_ptr)
|
|
132
|
+
@free.apply(name_ptr)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def read_result
|
|
138
|
+
pointer = @result_ptr.apply[0]
|
|
139
|
+
length = @result_len.apply[0]
|
|
140
|
+
return "".b if length.zero?
|
|
141
|
+
|
|
142
|
+
String.from_java_bytes(@memory.read_bytes(pointer, length)).b
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Allocates a buffer of newline-separated variable names and yields its
|
|
146
|
+
# pointer/length. A nil `variables` is passed as length -1 ("no variables").
|
|
147
|
+
def with_variables(variables)
|
|
148
|
+
names = variables&.map(&:to_s)&.join("\n")
|
|
149
|
+
|
|
150
|
+
if names.nil? || names.empty?
|
|
151
|
+
return yield(0, variables.nil? ? -1 : 0)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
bytes = names.b
|
|
155
|
+
length = bytes.bytesize
|
|
156
|
+
synchronize do
|
|
157
|
+
pointer = @alloc.apply(length)[0]
|
|
158
|
+
begin
|
|
159
|
+
@memory.write(pointer, bytes.to_java_bytes)
|
|
160
|
+
yield(pointer, length)
|
|
161
|
+
ensure
|
|
162
|
+
@free.apply(pointer)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# A WebAssembly i32 comes back in a JVM long, so read the low 32 bits as
|
|
168
|
+
# signed: the negative statuses have to stay negative on this side.
|
|
169
|
+
def i32(value)
|
|
170
|
+
value &= 0xFFFF_FFFF
|
|
171
|
+
value >= 0x8000_0000 ? value - 0x1_0000_0000 : value
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def bool(value)
|
|
175
|
+
value ? 1 : 0
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def build_instance
|
|
179
|
+
parser = Java::ComDylibsoChicoryWasm::Parser
|
|
180
|
+
instance_class = Java::ComDylibsoChicoryRuntime::Instance
|
|
181
|
+
import_values = Java::ComDylibsoChicoryRuntime::ImportValues
|
|
182
|
+
wasi_preview1 = Java::ComDylibsoChicoryWasi::WasiPreview1
|
|
183
|
+
wasi_options = Java::ComDylibsoChicoryWasi::WasiOptions
|
|
184
|
+
|
|
185
|
+
wasm_module = parser.parse(java.io.File.new(self.class.wasm_path))
|
|
186
|
+
wasi = wasi_preview1.builder.with_options(wasi_options.builder.build).build
|
|
187
|
+
imports = import_values.builder.add_function(wasi.to_host_functions).build
|
|
188
|
+
|
|
189
|
+
builder = instance_class.builder(wasm_module).with_import_values(imports)
|
|
190
|
+
if (factory = machine_factory(wasm_module))
|
|
191
|
+
builder = builder.with_machine_factory(factory)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
wasm = builder.build
|
|
195
|
+
wasm.export("_initialize").apply
|
|
196
|
+
wasm
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Chicory's AOT compiler when its jars are present and usable, otherwise nil
|
|
200
|
+
# (the builder then uses the interpreter). NameError covers a missing
|
|
201
|
+
# compiler class; LinkageError covers an incompatible/missing ASM (so a bad
|
|
202
|
+
# jar set degrades to the interpreter instead of crashing).
|
|
203
|
+
def machine_factory(wasm_module)
|
|
204
|
+
Java::ComDylibsoChicoryCompiler::MachineFactoryCompiler.compile(wasm_module)
|
|
205
|
+
rescue NameError, Java::JavaLang::LinkageError
|
|
206
|
+
nil
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|