rbs 4.1.3-java → 4.2.0-java
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/.gitattributes +1 -0
- data/.github/workflows/bundle-update.yml +2 -2
- data/.github/workflows/c-check.yml +2 -2
- data/.github/workflows/changelog.yml +121 -0
- data/.github/workflows/comments.yml +2 -2
- data/.github/workflows/dependabot.yml +1 -1
- data/.github/workflows/jruby.yml +3 -3
- data/.github/workflows/release-gems.yml +6 -7
- data/.github/workflows/ruby.yml +6 -6
- data/.github/workflows/rust.yml +12 -12
- data/.github/workflows/truffleruby.yml +2 -2
- data/.github/workflows/typecheck.yml +2 -2
- data/.github/workflows/wasm.yml +3 -3
- data/.github/workflows/windows.yml +2 -2
- data/.rubocop.yml +0 -1
- data/CHANGELOG.md +50 -0
- data/Rakefile +50 -21
- data/config.yml +5 -0
- data/core/io.rbs +2 -1
- data/docs/CONTRIBUTING.md +1 -1
- data/docs/release.md +57 -1
- data/docs/stdlib.md +8 -0
- data/docs/syntax.md +12 -0
- data/ext/rbs_extension/ast_translation.c +15 -0
- data/ext/rbs_extension/class_constants.c +2 -0
- data/ext/rbs_extension/class_constants.h +1 -0
- data/ext/rbs_extension/main.c +55 -19
- data/include/rbs/ast.h +21 -13
- data/include/rbs/defines.h +2 -2
- data/include/rbs/lexer.h +13 -12
- data/include/rbs/parser.h +37 -3
- data/lib/rbs/ast/declarations.rb +1 -1
- data/lib/rbs/ast/type_param.rb +1 -1
- data/lib/rbs/definition_builder/ancestor_builder.rb +8 -5
- data/lib/rbs/definition_builder/method_builder.rb +4 -4
- data/lib/rbs/definition_builder.rb +5 -2
- data/lib/rbs/environment/class_entry.rb +12 -0
- data/lib/rbs/environment/module_entry.rb +26 -1
- data/lib/rbs/parser_aux.rb +2 -2
- data/lib/rbs/prototype/helpers.rb +19 -52
- data/lib/rbs/prototype/runtime/value_object_generator.rb +0 -1
- data/lib/rbs/prototype/runtime.rb +1 -1
- data/lib/rbs/types.rb +44 -2
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/wasm/parser.rb +62 -25
- data/lib/rbs/wasm/rbs_parser.wasm +0 -0
- data/lib/rbs/wasm/runtime.rb +19 -4
- data/lib/rbs/wasm/serialization_schema.rb +3 -2
- data/rbs.gemspec +1 -5
- data/schema/function.json +12 -1
- data/sig/environment/class_entry.rbs +6 -0
- data/sig/environment/module_entry.rbs +15 -0
- data/sig/parser.rbs +4 -4
- data/sig/types.rbs +11 -1
- data/src/ast.c +17 -1
- data/src/lexer.c +1562 -1560
- data/src/lexer.re +50 -18
- data/src/lexstate.c +2 -1
- data/src/parser.c +130 -70
- data/src/serialize.c +20 -13
- data/src/util/rbs_encoding.c +195 -49
- data/stdlib/erb/0/erb.rbs +4 -4
- data/stdlib/monitor/0/monitor.rbs +4 -4
- data/stdlib/singleton/0/singleton.rbs +3 -0
- data/stdlib/stringio/0/stringio.rbs +2 -1
- data/stdlib/zlib/0/gzip_file.rbs +1 -1
- data/stdlib/zlib/0/gzip_writer.rbs +2 -1
- data/wasm/README.md +20 -4
- data/wasm/rbs_wasm.c +93 -37
- metadata +5 -3
|
@@ -124,10 +124,13 @@ module RBS
|
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
entry = env.class_decls[type_name] or raise "Unknown name for build_instance: #{type_name}"
|
|
127
|
-
args = entry.type_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
|
|
128
127
|
|
|
129
128
|
entry.each_decl do |decl|
|
|
130
|
-
|
|
129
|
+
if align_params = entry.align_params(decl)
|
|
130
|
+
subst_ = subst + align_params
|
|
131
|
+
else
|
|
132
|
+
subst_ = subst
|
|
133
|
+
end
|
|
131
134
|
|
|
132
135
|
decl.members.each do |member|
|
|
133
136
|
case member
|
|
@@ -64,6 +64,18 @@ module RBS
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
|
+
|
|
68
|
+
def align_params(decl)
|
|
69
|
+
entry_params = type_params
|
|
70
|
+
decl_param_names = decl.type_params.map(&:name)
|
|
71
|
+
|
|
72
|
+
return nil if decl_param_names == entry_params.map(&:name)
|
|
73
|
+
|
|
74
|
+
Substitution.build(
|
|
75
|
+
decl_param_names,
|
|
76
|
+
entry_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
|
|
77
|
+
)
|
|
78
|
+
end
|
|
67
79
|
end
|
|
68
80
|
end
|
|
69
81
|
end
|
|
@@ -42,10 +42,35 @@ module RBS
|
|
|
42
42
|
|
|
43
43
|
def self_types
|
|
44
44
|
each_decl.flat_map do |decl|
|
|
45
|
-
decl.self_types
|
|
45
|
+
self_types = decl.self_types
|
|
46
|
+
subst = align_params(decl)
|
|
47
|
+
|
|
48
|
+
if self_types.empty? || subst.nil?
|
|
49
|
+
self_types
|
|
50
|
+
else
|
|
51
|
+
self_types.map do |self_type|
|
|
52
|
+
AST::Declarations::Module::Self.new(
|
|
53
|
+
name: self_type.name,
|
|
54
|
+
args: self_type.args.map {|type| type.sub(subst) },
|
|
55
|
+
location: self_type.location
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
46
59
|
end.uniq
|
|
47
60
|
end
|
|
48
61
|
|
|
62
|
+
def align_params(decl)
|
|
63
|
+
entry_params = type_params
|
|
64
|
+
decl_param_names = decl.type_params.map(&:name)
|
|
65
|
+
|
|
66
|
+
return nil if decl_param_names == entry_params.map(&:name)
|
|
67
|
+
|
|
68
|
+
Substitution.build(
|
|
69
|
+
decl_param_names,
|
|
70
|
+
entry_params.map {|param| Types::Variable.new(name: param.name, location: param.location) }
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
49
74
|
def validate_type_params
|
|
50
75
|
unless context_decls.empty?
|
|
51
76
|
first_decl, *rest_decls = each_decl.to_a
|
data/lib/rbs/parser_aux.rb
CHANGED
|
@@ -14,7 +14,7 @@ module RBS
|
|
|
14
14
|
def self.parse_method_type(source, range: nil, byte_range: 0..., variables: [], require_eof: false)
|
|
15
15
|
buf = buffer(source)
|
|
16
16
|
byte_range = byte_range(range, buf.content) if range
|
|
17
|
-
_parse_method_type(buf, byte_range.begin || 0, byte_range.end || buf.content.bytesize, variables, require_eof)
|
|
17
|
+
_parse_method_type(buf, byte_range.begin || 0, byte_range.end || buf.content.bytesize, variables, require_eof, false)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def self.parse_signature(source)
|
|
@@ -28,7 +28,7 @@ module RBS
|
|
|
28
28
|
0
|
|
29
29
|
end
|
|
30
30
|
content = buf.content
|
|
31
|
-
dirs, decls = _parse_signature(buf, start_pos, content.bytesize)
|
|
31
|
+
dirs, decls = _parse_signature(buf, start_pos, content.bytesize, false)
|
|
32
32
|
|
|
33
33
|
if resolved
|
|
34
34
|
dirs = dirs.dup if dirs.frozen?
|
|
@@ -5,58 +5,25 @@ module RBS
|
|
|
5
5
|
module Helpers
|
|
6
6
|
private
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else
|
|
28
|
-
hash[line] = comment
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
else
|
|
34
|
-
require "ripper"
|
|
35
|
-
def parse_comments(string, include_trailing:)
|
|
36
|
-
Ripper.lex(string).yield_self do |tokens|
|
|
37
|
-
code_lines = {} #: Hash[Integer, bool]
|
|
38
|
-
tokens.each.with_object({}) do |token, hash| #$ Hash[Integer, AST::Comment]
|
|
39
|
-
case token[1]
|
|
40
|
-
when :on_sp, :on_ignored_nl
|
|
41
|
-
# skip
|
|
42
|
-
when :on_comment
|
|
43
|
-
line = token[0][0]
|
|
44
|
-
# skip like `module Foo # :nodoc:`
|
|
45
|
-
next if code_lines[line] && !include_trailing
|
|
46
|
-
body = token[2][2..-1] or raise
|
|
47
|
-
|
|
48
|
-
body = "\n" if body.empty?
|
|
49
|
-
|
|
50
|
-
comment = AST::Comment.new(string: body, location: nil)
|
|
51
|
-
if prev_comment = hash.delete(line - 1)
|
|
52
|
-
hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
|
|
53
|
-
location: nil)
|
|
54
|
-
else
|
|
55
|
-
hash[line] = comment
|
|
56
|
-
end
|
|
57
|
-
else
|
|
58
|
-
code_lines[token[0][0]] = true
|
|
59
|
-
end
|
|
8
|
+
def parse_comments(string, include_trailing:)
|
|
9
|
+
Prism.parse_comments(string, version: "current").yield_self do |prism_comments| # steep:ignore UnexpectedKeywordArgument
|
|
10
|
+
prism_comments.each_with_object({}) do |comment, hash| #$ Hash[Integer, AST::Comment]
|
|
11
|
+
# Skip EmbDoc comments
|
|
12
|
+
next unless comment.is_a?(Prism::InlineComment)
|
|
13
|
+
# skip like `module Foo # :nodoc:`
|
|
14
|
+
next if comment.trailing? && !include_trailing
|
|
15
|
+
|
|
16
|
+
line = comment.location.start_line
|
|
17
|
+
body = "#{comment.location.slice}\n"
|
|
18
|
+
body = body[2..-1] or raise
|
|
19
|
+
body = "\n" if body.empty?
|
|
20
|
+
|
|
21
|
+
comment = AST::Comment.new(string: body, location: nil)
|
|
22
|
+
if prev_comment = hash.delete(line - 1)
|
|
23
|
+
hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
|
|
24
|
+
location: nil)
|
|
25
|
+
else
|
|
26
|
+
hash[line] = comment
|
|
60
27
|
end
|
|
61
28
|
end
|
|
62
29
|
end
|
|
@@ -212,7 +212,6 @@ module RBS
|
|
|
212
212
|
|
|
213
213
|
class DataGenerator < ValueObjectBase
|
|
214
214
|
def self.generatable?(target)
|
|
215
|
-
return false unless RUBY_VERSION >= '3.2'
|
|
216
215
|
return false unless target < Data
|
|
217
216
|
# Avoid direct inherited class like `class Option < Data`
|
|
218
217
|
return false unless target.respond_to?(:members)
|
|
@@ -527,7 +527,7 @@ module RBS
|
|
|
527
527
|
|
|
528
528
|
generate_mixin(mod, decl, type_name, type_name_absolute)
|
|
529
529
|
|
|
530
|
-
unless mod < Struct ||
|
|
530
|
+
unless mod < Struct || mod < Data
|
|
531
531
|
generate_methods(mod, type_name, decl.members) unless outline
|
|
532
532
|
end
|
|
533
533
|
|
data/lib/rbs/types.rb
CHANGED
|
@@ -959,6 +959,33 @@ module RBS
|
|
|
959
959
|
end
|
|
960
960
|
end
|
|
961
961
|
|
|
962
|
+
class ForwardingParam
|
|
963
|
+
attr_reader :location
|
|
964
|
+
|
|
965
|
+
def initialize(location:)
|
|
966
|
+
@location = location
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
def ==(other)
|
|
970
|
+
other.is_a?(ForwardingParam)
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
alias eql? ==
|
|
974
|
+
|
|
975
|
+
def hash
|
|
976
|
+
self.class.hash
|
|
977
|
+
end
|
|
978
|
+
|
|
979
|
+
def to_json(state = nil)
|
|
980
|
+
json = {} #: Hash[Symbol, untyped]
|
|
981
|
+
json.to_json(state)
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
def to_s
|
|
985
|
+
"..."
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
|
|
962
989
|
attr_reader :required_positionals
|
|
963
990
|
attr_reader :optional_positionals
|
|
964
991
|
attr_reader :rest_positionals
|
|
@@ -966,9 +993,10 @@ module RBS
|
|
|
966
993
|
attr_reader :required_keywords
|
|
967
994
|
attr_reader :optional_keywords
|
|
968
995
|
attr_reader :rest_keywords
|
|
996
|
+
attr_reader :forwarding
|
|
969
997
|
attr_reader :return_type
|
|
970
998
|
|
|
971
|
-
def initialize(required_positionals:, optional_positionals:, rest_positionals:, trailing_positionals:, required_keywords:, optional_keywords:, rest_keywords:, return_type:)
|
|
999
|
+
def initialize(required_positionals:, optional_positionals:, rest_positionals:, trailing_positionals:, required_keywords:, optional_keywords:, rest_keywords:, return_type:, forwarding: nil)
|
|
972
1000
|
@return_type = return_type
|
|
973
1001
|
@required_positionals = required_positionals
|
|
974
1002
|
@optional_positionals = optional_positionals
|
|
@@ -977,6 +1005,7 @@ module RBS
|
|
|
977
1005
|
@required_keywords = required_keywords
|
|
978
1006
|
@optional_keywords = optional_keywords
|
|
979
1007
|
@rest_keywords = rest_keywords
|
|
1008
|
+
@forwarding = forwarding
|
|
980
1009
|
end
|
|
981
1010
|
|
|
982
1011
|
def ==(other)
|
|
@@ -988,6 +1017,7 @@ module RBS
|
|
|
988
1017
|
other.required_keywords == required_keywords &&
|
|
989
1018
|
other.optional_keywords == optional_keywords &&
|
|
990
1019
|
other.rest_keywords == rest_keywords &&
|
|
1020
|
+
other.forwarding == forwarding &&
|
|
991
1021
|
other.return_type == return_type
|
|
992
1022
|
end
|
|
993
1023
|
|
|
@@ -1002,6 +1032,7 @@ module RBS
|
|
|
1002
1032
|
required_keywords.hash ^
|
|
1003
1033
|
optional_keywords.hash ^
|
|
1004
1034
|
rest_keywords.hash ^
|
|
1035
|
+
forwarding.hash ^
|
|
1005
1036
|
return_type.hash
|
|
1006
1037
|
end
|
|
1007
1038
|
|
|
@@ -1043,6 +1074,7 @@ module RBS
|
|
|
1043
1074
|
required_keywords: hmapv(required_keywords) {|param| param.map_type(&block) },
|
|
1044
1075
|
optional_keywords: hmapv(optional_keywords) {|param| param.map_type(&block) },
|
|
1045
1076
|
rest_keywords: rest_keywords&.yield_self {|param| param.map_type(&block) },
|
|
1077
|
+
forwarding: forwarding,
|
|
1046
1078
|
return_type: yield(return_type)
|
|
1047
1079
|
)
|
|
1048
1080
|
else
|
|
@@ -1110,6 +1142,7 @@ module RBS
|
|
|
1110
1142
|
required_keywords: required_keywords,
|
|
1111
1143
|
optional_keywords: optional_keywords,
|
|
1112
1144
|
rest_keywords: rest_keywords,
|
|
1145
|
+
forwarding: forwarding,
|
|
1113
1146
|
return_type: return_type
|
|
1114
1147
|
}.to_json(state)
|
|
1115
1148
|
end
|
|
@@ -1129,6 +1162,7 @@ module RBS
|
|
|
1129
1162
|
required_keywords: {},
|
|
1130
1163
|
optional_keywords: {},
|
|
1131
1164
|
rest_keywords: nil,
|
|
1165
|
+
forwarding: nil,
|
|
1132
1166
|
return_type: return_type
|
|
1133
1167
|
)
|
|
1134
1168
|
end
|
|
@@ -1142,12 +1176,13 @@ module RBS
|
|
|
1142
1176
|
required_keywords: required_keywords,
|
|
1143
1177
|
optional_keywords: optional_keywords,
|
|
1144
1178
|
rest_keywords: rest_keywords,
|
|
1179
|
+
forwarding: forwarding,
|
|
1145
1180
|
return_type: type
|
|
1146
1181
|
)
|
|
1147
1182
|
end
|
|
1148
1183
|
|
|
1149
1184
|
def update(required_positionals: self.required_positionals, optional_positionals: self.optional_positionals, rest_positionals: self.rest_positionals, trailing_positionals: self.trailing_positionals,
|
|
1150
|
-
required_keywords: self.required_keywords, optional_keywords: self.optional_keywords, rest_keywords: self.rest_keywords, return_type: self.return_type)
|
|
1185
|
+
required_keywords: self.required_keywords, optional_keywords: self.optional_keywords, rest_keywords: self.rest_keywords, forwarding: self.forwarding, return_type: self.return_type)
|
|
1151
1186
|
Function.new(
|
|
1152
1187
|
required_positionals: required_positionals,
|
|
1153
1188
|
optional_positionals: optional_positionals,
|
|
@@ -1156,6 +1191,7 @@ module RBS
|
|
|
1156
1191
|
required_keywords: required_keywords,
|
|
1157
1192
|
optional_keywords: optional_keywords,
|
|
1158
1193
|
rest_keywords: rest_keywords,
|
|
1194
|
+
forwarding: forwarding,
|
|
1159
1195
|
return_type: return_type
|
|
1160
1196
|
)
|
|
1161
1197
|
end
|
|
@@ -1167,6 +1203,7 @@ module RBS
|
|
|
1167
1203
|
trailing_positionals.empty? &&
|
|
1168
1204
|
required_keywords.empty? &&
|
|
1169
1205
|
optional_keywords.empty? &&
|
|
1206
|
+
!forwarding? &&
|
|
1170
1207
|
!rest_keywords
|
|
1171
1208
|
end
|
|
1172
1209
|
|
|
@@ -1175,6 +1212,7 @@ module RBS
|
|
|
1175
1212
|
params = []
|
|
1176
1213
|
|
|
1177
1214
|
params.push(*required_positionals.map(&:to_s))
|
|
1215
|
+
params.push(forwarding.to_s) if forwarding
|
|
1178
1216
|
params.push(*optional_positionals.map {|p| "?#{p}"})
|
|
1179
1217
|
params.push("*#{rest_positionals}") if rest_positionals
|
|
1180
1218
|
params.push(*trailing_positionals.map(&:to_s))
|
|
@@ -1185,6 +1223,10 @@ module RBS
|
|
|
1185
1223
|
params.join(", ")
|
|
1186
1224
|
end
|
|
1187
1225
|
|
|
1226
|
+
def forwarding?
|
|
1227
|
+
!forwarding.nil?
|
|
1228
|
+
end
|
|
1229
|
+
|
|
1188
1230
|
def return_to_s
|
|
1189
1231
|
return_type.to_s(1)
|
|
1190
1232
|
end
|
data/lib/rbs/version.rb
CHANGED
data/lib/rbs/wasm/parser.rb
CHANGED
|
@@ -12,83 +12,102 @@ module RBS
|
|
|
12
12
|
# RBS::Parser API on top, exactly as it does for the C extension.
|
|
13
13
|
class Parser
|
|
14
14
|
class << self
|
|
15
|
-
def _parse_signature(buffer, start_pos, end_pos)
|
|
16
|
-
validate_position_range(start_pos, end_pos)
|
|
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)
|
|
17
18
|
encoding = buffer.content.encoding.name
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
20
21
|
|
|
21
22
|
WASM::Deserializer.deserialize(bytes, buffer)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def _parse_type(buffer, start_pos, end_pos, variables, require_eof, void_allowed, self_allowed, classish_allowed)
|
|
25
|
-
validate_position_range(start_pos, end_pos)
|
|
26
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
26
27
|
validate_variables(variables)
|
|
27
28
|
encoding = buffer.content.encoding.name
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
30
31
|
|
|
31
32
|
deserialize_or_nil(bytes, buffer)
|
|
32
33
|
end
|
|
33
34
|
|
|
34
|
-
def _parse_method_type(buffer, start_pos, end_pos, variables, require_eof)
|
|
35
|
-
validate_position_range(start_pos, end_pos)
|
|
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)
|
|
36
37
|
validate_variables(variables)
|
|
38
|
+
validate_parser_options(enable_forwarding_params)
|
|
37
39
|
encoding = buffer.content.encoding.name
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
40
42
|
|
|
41
43
|
deserialize_or_nil(bytes, buffer)
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
def _parse_type_params(buffer, start_pos, end_pos, module_type_params)
|
|
45
|
-
validate_position_range(start_pos, end_pos)
|
|
47
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
46
48
|
encoding = buffer.content.encoding.name
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
49
51
|
|
|
50
52
|
bytes.empty? ? nil : WASM::Deserializer.deserialize_node_list(bytes, buffer)
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
def _lex(buffer, end_pos)
|
|
54
56
|
encoding = buffer.content.encoding.name
|
|
55
|
-
|
|
57
|
+
_status, bytes = WASM::Runtime.instance.lex(buffer.content, encoding, end_pos)
|
|
56
58
|
|
|
57
59
|
WASM::Deserializer.deserialize_tokens(bytes, buffer)
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def _parse_inline_leading_annotation(buffer, start_pos, end_pos, variables)
|
|
61
|
-
validate_position_range(start_pos, end_pos)
|
|
63
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
62
64
|
validate_variables(variables)
|
|
63
65
|
encoding = buffer.content.encoding.name
|
|
64
|
-
|
|
65
|
-
|
|
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
|
|
66
68
|
|
|
67
69
|
deserialize_or_nil(bytes, buffer)
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
def _parse_inline_trailing_annotation(buffer, start_pos, end_pos, variables)
|
|
71
|
-
validate_position_range(start_pos, end_pos)
|
|
73
|
+
validate_position_range(buffer, start_pos, end_pos)
|
|
72
74
|
validate_variables(variables)
|
|
73
75
|
encoding = buffer.content.encoding.name
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
76
78
|
|
|
77
79
|
deserialize_or_nil(bytes, buffer)
|
|
78
80
|
end
|
|
79
81
|
|
|
80
82
|
private
|
|
81
83
|
|
|
82
|
-
# Reject
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
|
|
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)
|
|
86
91
|
if start_pos < 0 || end_pos < 0
|
|
87
92
|
raise ArgumentError, "negative position range: #{start_pos}...#{end_pos}"
|
|
88
93
|
end
|
|
89
94
|
if start_pos > end_pos
|
|
90
95
|
raise ArgumentError, "invalid position range: #{start_pos}...#{end_pos}"
|
|
91
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
|
|
92
111
|
end
|
|
93
112
|
|
|
94
113
|
# Reject anything that is not nil or an Array of Symbols, matching
|
|
@@ -112,6 +131,24 @@ module RBS
|
|
|
112
131
|
bytes.empty? ? nil : WASM::Deserializer.deserialize(bytes, buffer)
|
|
113
132
|
end
|
|
114
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
|
+
|
|
115
152
|
# Decodes the error blob written by set_error_result (rbs_wasm.c) and raises
|
|
116
153
|
# the same error the C extension would (see raise_error in main.c).
|
|
117
154
|
def raise_parsing_error(buffer, blob)
|
|
Binary file
|
data/lib/rbs/wasm/runtime.rb
CHANGED
|
@@ -16,6 +16,14 @@ module RBS
|
|
|
16
16
|
class Runtime
|
|
17
17
|
include MonitorMixin
|
|
18
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
|
+
|
|
19
27
|
class << self
|
|
20
28
|
def instance
|
|
21
29
|
@instance ||= new
|
|
@@ -48,9 +56,9 @@ module RBS
|
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
# `content` is the whole buffer; `start_pos`/`end_pos` are the character
|
|
51
|
-
# range within it to parse. Each method returns [
|
|
52
|
-
# `bytes` is the serialized AST,
|
|
53
|
-
# set_error_result in rbs_wasm.c).
|
|
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.
|
|
54
62
|
|
|
55
63
|
def parse_signature(content, encoding, start_pos, end_pos)
|
|
56
64
|
run(content, encoding) { |ptr, len, enc_ptr, enc_len| @parse_signature.apply(ptr, len, enc_ptr, enc_len, start_pos, end_pos)[0] }
|
|
@@ -118,7 +126,7 @@ module RBS
|
|
|
118
126
|
@memory.write(source_ptr, bytes.to_java_bytes)
|
|
119
127
|
@memory.write(name_ptr, name.to_java_bytes) unless name_length.zero?
|
|
120
128
|
status = yield(source_ptr, length, name_ptr, name_length)
|
|
121
|
-
[status
|
|
129
|
+
[i32(status), read_result]
|
|
122
130
|
ensure
|
|
123
131
|
@free.apply(source_ptr)
|
|
124
132
|
@free.apply(name_ptr)
|
|
@@ -156,6 +164,13 @@ module RBS
|
|
|
156
164
|
end
|
|
157
165
|
end
|
|
158
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
|
+
|
|
159
174
|
def bool(value)
|
|
160
175
|
value ? 1 : 0
|
|
161
176
|
end
|
|
@@ -23,7 +23,7 @@ module RBS
|
|
|
23
23
|
# :bool, :location_range, :location_range_list, :attr_ivar_name, or
|
|
24
24
|
# [:enum, [value_or_nil, ...]].
|
|
25
25
|
module SerializationSchema
|
|
26
|
-
SYMBOL_TAG =
|
|
26
|
+
SYMBOL_TAG = 79
|
|
27
27
|
|
|
28
28
|
SCHEMA = [
|
|
29
29
|
nil, # tag 0 is reserved for NULL
|
|
@@ -91,7 +91,8 @@ module RBS
|
|
|
91
91
|
[:node, "RBS::Types::Block", true, nil, [[:type, :node], [:required, :bool], [:self_type, :node]], false],
|
|
92
92
|
[:node, "RBS::Types::ClassInstance", true, [[:name, true], [:args, false]], [[:name, :node], [:args, :node_list]], false],
|
|
93
93
|
[:node, "RBS::Types::ClassSingleton", true, [[:name, true], [:args, false]], [[:name, :node], [:args, :node_list]], false],
|
|
94
|
-
[:node, "RBS::Types::Function", false, nil, [[:required_positionals, :node_list], [:optional_positionals, :node_list], [:rest_positionals, :node], [:trailing_positionals, :node_list], [:required_keywords, :hash], [:optional_keywords, :hash], [:rest_keywords, :node], [:return_type, :node]], false],
|
|
94
|
+
[:node, "RBS::Types::Function", false, nil, [[:required_positionals, :node_list], [:optional_positionals, :node_list], [:rest_positionals, :node], [:trailing_positionals, :node_list], [:required_keywords, :hash], [:optional_keywords, :hash], [:rest_keywords, :node], [:forwarding, :node], [:return_type, :node]], false],
|
|
95
|
+
[:node, "RBS::Types::Function::ForwardingParam", true, nil, nil, false],
|
|
95
96
|
[:node, "RBS::Types::Function::Param", true, [[:name, false]], [[:type, :node], [:name, :node]], false],
|
|
96
97
|
[:node, "RBS::Types::Interface", true, [[:name, true], [:args, false]], [[:name, :node], [:args, :node_list]], false],
|
|
97
98
|
[:node, "RBS::Types::Intersection", true, nil, [[:types, :node_list]], false],
|
data/rbs.gemspec
CHANGED
|
@@ -67,14 +67,10 @@ Gem::Specification.new do |spec|
|
|
|
67
67
|
spec.extensions = %w{ext/rbs_extension/extconf.rb}
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
if false
|
|
71
|
-
spec.required_ruby_version = ">= 3.4"
|
|
72
|
-
end
|
|
73
|
-
|
|
74
70
|
spec.bindir = "exe"
|
|
75
71
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
76
72
|
spec.require_paths = ["lib"]
|
|
77
|
-
spec.required_ruby_version = ">= 3.
|
|
73
|
+
spec.required_ruby_version = ">= 3.3"
|
|
78
74
|
spec.add_dependency "logger"
|
|
79
75
|
spec.add_dependency "prism", ">= 1.6.0"
|
|
80
76
|
spec.add_dependency "tsort"
|
data/schema/function.json
CHANGED
|
@@ -78,10 +78,21 @@
|
|
|
78
78
|
}
|
|
79
79
|
]
|
|
80
80
|
},
|
|
81
|
+
"forwarding": {
|
|
82
|
+
"title": "Forwarding parameter",
|
|
83
|
+
"oneOf": [
|
|
84
|
+
{
|
|
85
|
+
"type": "object"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"type": "null"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
81
92
|
"return_type": {
|
|
82
93
|
"title": "Return type of a function",
|
|
83
94
|
"$ref": "types.json"
|
|
84
95
|
}
|
|
85
96
|
},
|
|
86
|
-
"required": ["required_positionals", "optional_positionals", "rest_positionals", "trailing_positionals", "required_keywords", "optional_keywords", "rest_keywords", "return_type"]
|
|
97
|
+
"required": ["required_positionals", "optional_positionals", "rest_positionals", "trailing_positionals", "required_keywords", "optional_keywords", "rest_keywords", "forwarding", "return_type"]
|
|
87
98
|
}
|
|
@@ -45,6 +45,12 @@ module RBS
|
|
|
45
45
|
# * Raises `GenericParameterMismatchError` if incompatible declaration is detected.
|
|
46
46
|
#
|
|
47
47
|
def validate_type_params: () -> void
|
|
48
|
+
|
|
49
|
+
# Returns a substitution that renames the type parameters of the declaration to the entry's type parameters (`#type_params`)
|
|
50
|
+
#
|
|
51
|
+
# Returns `nil` if the declaration uses the same type parameter names as `#type_params`.
|
|
52
|
+
#
|
|
53
|
+
def align_params: (declaration | ModuleEntry::declaration) -> Substitution?
|
|
48
54
|
end
|
|
49
55
|
end
|
|
50
56
|
end
|
|
@@ -44,7 +44,22 @@ module RBS
|
|
|
44
44
|
#
|
|
45
45
|
def validate_type_params: () -> void
|
|
46
46
|
|
|
47
|
+
# Returns the self types of the declarations
|
|
48
|
+
#
|
|
49
|
+
# The type variables in the self types are aligned to `#type_params`,
|
|
50
|
+
# so that the self types from declarations with different type parameter
|
|
51
|
+
# names can be compared and used with `#type_params`.
|
|
52
|
+
#
|
|
53
|
+
# Note that the returned objects may be different from the ones in the
|
|
54
|
+
# declarations, but `#location` points to the original declaration.
|
|
55
|
+
#
|
|
47
56
|
def self_types: () -> Array[AST::Declarations::Module::Self]
|
|
57
|
+
|
|
58
|
+
# Returns a substitution that renames the type parameters of the declaration to the entry's type parameters (`#type_params`)
|
|
59
|
+
#
|
|
60
|
+
# Returns `nil` if the declaration uses the same type parameter names as `#type_params`.
|
|
61
|
+
#
|
|
62
|
+
def align_params: (declaration | ClassEntry::declaration) -> Substitution?
|
|
48
63
|
end
|
|
49
64
|
end
|
|
50
65
|
end
|