gloss 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +3 -0
  3. data/.github/workflows/crystal_specs.yml +26 -0
  4. data/.github/workflows/ruby_specs.yml +33 -0
  5. data/.gitignore +2 -1
  6. data/.rspec +1 -0
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +26 -34
  9. data/LICENSE +21 -0
  10. data/README.md +59 -7
  11. data/Rakefile +4 -0
  12. data/exe/gloss +15 -1
  13. data/ext/gloss/Makefile +27 -5
  14. data/ext/gloss/extconf.rb +3 -25
  15. data/ext/gloss/{src/lib → lib}/cr_ruby.cr +0 -0
  16. data/ext/gloss/lib/rbs_types.cr +3 -0
  17. data/ext/gloss/spec/parser_spec.cr +124 -0
  18. data/ext/gloss/spec/spec_helper.cr +2 -0
  19. data/ext/gloss/src/cr_ast.cr +129 -31
  20. data/ext/gloss/src/gloss.cr +12 -18
  21. data/ext/gloss/src/lexer.cr +59 -1
  22. data/ext/gloss/src/parser.cr +548 -254
  23. data/ext/gloss/src/rb_ast.cr +153 -27
  24. data/gloss.gemspec +1 -0
  25. data/lib/gloss.rb +4 -1
  26. data/lib/gloss/builder.rb +607 -409
  27. data/lib/gloss/cli.rb +64 -24
  28. data/lib/gloss/config.rb +16 -10
  29. data/lib/gloss/errors.rb +13 -7
  30. data/lib/gloss/initializer.rb +11 -6
  31. data/lib/gloss/logger.rb +34 -0
  32. data/lib/gloss/parser.rb +35 -0
  33. data/lib/gloss/scope.rb +8 -3
  34. data/lib/gloss/source.rb +18 -15
  35. data/lib/gloss/type_checker.rb +96 -0
  36. data/lib/gloss/version.rb +6 -1
  37. data/lib/gloss/watcher.rb +63 -19
  38. data/lib/gloss/writer.rb +18 -12
  39. data/sig/gloss.rbs +3 -0
  40. data/sig/listen.rbs +1 -0
  41. data/src/lib/gloss/builder.gl +546 -0
  42. data/src/lib/gloss/cli.gl +55 -0
  43. data/src/lib/gloss/config.gl +21 -0
  44. data/src/lib/gloss/errors.gl +11 -0
  45. data/src/lib/gloss/initializer.gl +20 -0
  46. data/src/lib/gloss/logger.gl +26 -0
  47. data/src/lib/gloss/parser.gl +31 -0
  48. data/src/lib/gloss/scope.gl +9 -0
  49. data/src/lib/gloss/source.gl +32 -0
  50. data/src/lib/gloss/type_checker.gl +101 -0
  51. data/src/lib/gloss/version.gl +3 -0
  52. data/src/lib/gloss/watcher.gl +67 -0
  53. data/src/lib/gloss/writer.gl +33 -0
  54. metadata +42 -6
  55. data/lib/gloss.bundle.dwarf +0 -0
  56. data/src/lib/hrb/initializer.gl +0 -22
  57. data/src/lib/hrb/watcher.gl +0 -32
@@ -43,13 +43,14 @@ module Rb
43
43
  end
44
44
 
45
45
  class Block < Node
46
- @info : NamedTuple(type: String, args: Array(Var), body: Node)
46
+ @info : NamedTuple(type: String, positional_args: Array(Var), body: Node, rest_p_args: Node?)
47
47
 
48
- def initialize(args, body)
48
+ def initialize(args, splat, body)
49
49
  @info = {
50
50
  type: self.class.name.split("::").last,
51
51
  body: body,
52
- args: args,
52
+ positional_args: args,
53
+ rest_p_args: splat
53
54
  }
54
55
  end
55
56
 
@@ -94,18 +95,31 @@ module Rb
94
95
  end
95
96
 
96
97
  class DefNode < Node
97
- @info : NamedTuple(type: String, name: String, body: Node, rp_args: Array(Arg), receiver: Node?,
98
- return_type: Node?, rest_kw_args: Arg?)
99
-
100
- def initialize(name : String, rp_args : Array(Arg), body : Node, receiver : Node?, return_type : Node?, rest_kw_args)
98
+ @info : NamedTuple(type: String, name: String, body: Node, positional_args: Array(Arg), receiver: Node?,
99
+ return_type: Node?, rest_kw_args: Arg?, rest_p_args: Arg?, block_arg: Node?, yield_arg_count: Int32?)
100
+
101
+ def initialize(
102
+ receiver : Node?,
103
+ name : String,
104
+ positional_args : Array(Arg),
105
+ splat,
106
+ rest_kw_args,
107
+ body : Node,
108
+ return_type : Node?,
109
+ yields : Int32?,
110
+ block_arg : Node?
111
+ )
101
112
  @info = {
102
- type: self.class.name.split("::").last,
103
- name: name,
104
- body: body,
105
- rp_args: rp_args,
106
- rest_kw_args: rest_kw_args,
107
- receiver: receiver,
108
- return_type: return_type,
113
+ type: self.class.name.split("::").last,
114
+ name: name,
115
+ body: body,
116
+ positional_args: positional_args,
117
+ rest_kw_args: rest_kw_args,
118
+ receiver: receiver,
119
+ return_type: return_type,
120
+ rest_p_args: splat,
121
+ yield_arg_count: yields,
122
+ block_arg: block_arg
109
123
  }
110
124
  end
111
125
 
@@ -113,16 +127,17 @@ module Rb
113
127
  end
114
128
 
115
129
  class Arg < Node
116
- @info : NamedTuple(type: String, name: String, external_name: String, default_value: Node?,
117
- restriction: Node?)
130
+ @info : NamedTuple(type: String, name: String, external_name: String, value: Node?,
131
+ restriction: Node?, keyword_arg: Bool)
118
132
 
119
- def initialize(name : String, external_name : String, restriction : Node?, default_value : Node?)
133
+ def initialize(name : String, external_name : String, restriction : Node?, value : Node?, keyword_arg)
120
134
  @info = {
121
135
  type: self.class.name.split("::").last,
122
136
  name: name,
123
137
  restriction: restriction,
124
- default_value: default_value,
138
+ value: value,
125
139
  external_name: external_name,
140
+ keyword_arg: keyword_arg,
126
141
  }
127
142
  end
128
143
 
@@ -198,7 +213,17 @@ module Rb
198
213
  delegate :to_json, to: @info
199
214
  end
200
215
 
201
- class RegexLiteral < NodeWithValue
216
+ class RegexLiteral < Node
217
+ @info : NamedTuple(type: String, value: Node)
218
+
219
+ def initialize(value)
220
+ @info = {
221
+ type: self.class.name.split("::").last,
222
+ value: value,
223
+ }
224
+ end
225
+
226
+ delegate :to_json, to: @info
202
227
  end
203
228
 
204
229
  class Nop < Node
@@ -236,6 +261,9 @@ module Rb
236
261
  class InstanceVar < Var
237
262
  end
238
263
 
264
+ class GlobalVar < Var
265
+ end
266
+
239
267
  abstract class Conditional < Node
240
268
  @info : NamedTuple(type: String, condition: Node, then: Node, else: Node)
241
269
 
@@ -303,16 +331,19 @@ module Rb
303
331
  end
304
332
 
305
333
  class Call < Node
306
- @info : NamedTuple(type: String, name: String, args: Array(Node), object: Node?, block: Block?, block_arg: Node?)
334
+ @info : NamedTuple(type: String, name: String, args: Array(Node), object: Node?, block: Block?, block_arg: Node?, named_args: Array(Arg)?, has_parentheses: Bool)
307
335
 
308
- def initialize(object : Node?, name : String, args : Array(Node), block, block_arg)
336
+ def initialize(object : Node?, name : String, args : Array(Node), named_args, block,
337
+ block_arg, has_parentheses)
309
338
  @info = {
310
- type: self.class.name.split("::").last,
311
- name: name,
312
- args: args,
313
- object: object,
314
- block: block,
315
- block_arg: block_arg,
339
+ type: self.class.name.split("::").last,
340
+ name: name,
341
+ args: args,
342
+ object: object,
343
+ block: block,
344
+ block_arg: block_arg,
345
+ named_args: named_args,
346
+ has_parentheses: has_parentheses || false,
316
347
  }
317
348
  end
318
349
 
@@ -383,6 +414,20 @@ module Rb
383
414
  delegate :to_json, to: @info
384
415
  end
385
416
 
417
+ class MultiAssign < Node
418
+ @info : NamedTuple(type: String, targets: Array(Node), values: Array(Node))
419
+
420
+ def initialize(targets, values)
421
+ @info = {
422
+ type: self.class.name.split("::").last,
423
+ targets: targets,
424
+ values: values,
425
+ }
426
+ end
427
+
428
+ delegate :to_json, to: @info
429
+ end
430
+
386
431
  class TypeDeclaration < Node
387
432
  @info : NamedTuple(type: String, var: Node, declared_type: Node, value: Node?, var_type: String)
388
433
 
@@ -487,5 +532,86 @@ module Rb
487
532
 
488
533
  delegate :to_json, to: @info
489
534
  end
535
+
536
+ class Union < Node
537
+ @info : NamedTuple(type: String, types: Array(Node))
538
+
539
+ def initialize(types)
540
+ @info = {
541
+ type: self.class.name.split("::").last,
542
+ types: types,
543
+ }
544
+ end
545
+
546
+ delegate :to_json, to: @info
547
+ end
548
+
549
+ class Generic < Node
550
+ @info : NamedTuple(type: String, name: Node, args: Array(Node))
551
+
552
+ def initialize(name, args)
553
+ @info = {
554
+ type: self.class.name.split("::").last,
555
+ name: name,
556
+ args: args,
557
+ }
558
+ end
559
+
560
+ delegate :to_json, to: @info
561
+ end
562
+
563
+ class Proc < Node
564
+ @info : NamedTuple(type: String, function: DefNode)
565
+
566
+ def initialize(function)
567
+ @info = {
568
+ type: self.class.name.split("::").last,
569
+ function: function,
570
+ }
571
+ end
572
+
573
+ delegate :to_json, to: @info
574
+ end
575
+
576
+ class NodeWithNameNode < Node
577
+ @info : NamedTuple(type: String, name: Node)
578
+
579
+ def initialize(name)
580
+ @info = {
581
+ type: self.class.name.split("::").last,
582
+ name: name,
583
+ }
584
+ end
585
+
586
+ delegate :to_json, to: @info
587
+ end
588
+
589
+ class Extend < NodeWithNameNode
590
+ end
591
+
592
+ class Include < NodeWithNameNode
593
+ end
594
+
595
+ class VisibilityModifier < Node
596
+ @info : NamedTuple(type: String, visibility: String, exp: Node)
597
+
598
+ def initialize(visibility : Crystal::Visibility, exp : Node)
599
+ vis = case visibility
600
+ when Crystal::Visibility::Public
601
+ "public"
602
+ when Crystal::Visibility::Protected
603
+ "protected"
604
+ when Crystal::Visibility::Private
605
+ "private"
606
+ end
607
+ @info = {
608
+ type: self.class.name.split("::").last,
609
+ visibility: vis.as(String),
610
+ exp: exp,
611
+ }
612
+ end
613
+
614
+ delegate :to_json, to: @info
615
+ end
490
616
  end
491
617
  end
data/gloss.gemspec CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_runtime_dependency "fast_blank"
19
19
  s.add_runtime_dependency "listen"
20
+ s.add_runtime_dependency "rbs"
20
21
  s.add_runtime_dependency "steep"
21
22
 
22
23
  s.add_development_dependency "rake-compiler"
data/lib/gloss.rb CHANGED
@@ -8,6 +8,8 @@ require "fast_blank"
8
8
  require "gloss/version"
9
9
  require "gloss/cli"
10
10
  require "gloss/watcher"
11
+ require "gloss/type_checker"
12
+ require "gloss/parser"
11
13
  require "gloss/initializer"
12
14
  require "gloss/config"
13
15
  require "gloss/writer"
@@ -15,8 +17,9 @@ require "gloss/source"
15
17
  require "gloss/scope"
16
18
  require "gloss/builder"
17
19
  require "gloss/errors"
20
+ require "gloss/logger"
18
21
 
19
- require "gloss.bundle"
22
+ require "gls" unless ENV["CI"] # a bit of a hack for now
20
23
 
21
24
  EMPTY_ARRAY = [].freeze
22
25
  EMPTY_HASH = {}.freeze
data/lib/gloss/builder.rb CHANGED
@@ -1,442 +1,640 @@
1
- # frozen_string_literal: true
1
+ # frozen_string_literal: true
2
+
3
+ ##### This file was generated by Gloss; any changes made here will be overwritten.
4
+ ##### See src/ to make changes
2
5
 
3
6
  module Gloss
7
+ module Utils
8
+ module_function
9
+ def with_file_header(str)
10
+ "#{Builder::FILE_HEADER}\n\n#{str}"
11
+ end
12
+ end
4
13
  class Builder
5
- attr_reader :tree
6
-
7
- def initialize(str)
14
+ FILE_HEADER = " #{(if Config.frozen_string_literals
15
+ "# frozen_string_literal: true\n"
16
+ end)}\n ##### This file was generated by Gloss; any changes made here will be overwritten.\n ##### See #{Config.src_dir}/ to make changes"
17
+ include Utils
18
+ attr_reader(:"tree")
19
+ def initialize(tree_hash, type_checker = nil)
8
20
  @indent_level = 0
9
21
  @inside_macro = false
10
22
  @eval_vars = false
11
- tree_json = Gloss.parse_buffer str
12
- begin
13
- @tree = JSON.parse tree_json, symbolize_names: true
14
- rescue JSON::ParserError
15
- raise Errors::ParserError, tree_json
16
- end
17
23
  @current_scope = nil
18
- @steep_target = Steep::Project::Target.new(
19
- name: "gloss",
20
- options: Steep::Project::Options.new,
21
- source_patterns: ["gloss"],
22
- ignore_patterns: [],
23
- signature_patterns: []
24
- )
25
- Dir.glob("sig/**/*.rbs").each do |fp|
26
- next if !@steep_target.possible_signature_file?(fp) || @steep_target.signature_file?(fp)
27
-
28
- Steep.logger.info { "Adding signature file: #{fp}" }
29
- @steep_target.add_signature path, (Pathname(".") + fp).cleanpath.read
30
- end
31
- @top_level_decls = {}
24
+ @tree = tree_hash
25
+ @type_checker = type_checker
32
26
  end
33
-
34
- def run
27
+ def run()
35
28
  rb_output = visit_node(@tree)
36
- rb_output = "# frozen_string_literal: true\n#{rb_output}" if Config.frozen_string_literals
37
-
38
- unless check_types(rb_output)
39
- raise Errors::TypeError,
40
- @steep_target.errors.map { |e|
41
- case e
42
- when Steep::Errors::NoMethod
43
- "Unknown method :#{e.method}, location: #{e.type.location.inspect}"
44
- when Steep::Errors::MethodBodyTypeMismatch
45
- "Invalid method body type - expected: #{e.expected}, actual: #{e.actual}"
46
- when Steep::Errors::IncompatibleArguments
47
- "Invalid argmuents - method type: #{e.method_type}, receiver type: #{e.receiver_type}"
48
- when Steep::Errors::ReturnTypeMismatch
49
- "Invalid return type - expected: #{e.expected}, actual: #{e.actual}"
50
- when Steep::Errors::IncompatibleAssignment
51
- "Invalid assignment - cannot assign #{e.rhs_type} to type #{e.lhs_type}"
52
- else
53
- e.inspect
54
- end
55
- }.join("\n")
56
- end
57
-
58
- rb_output
29
+ with_file_header(rb_output)
59
30
  end
60
-
61
- def check_types(rb_str)
62
- env_loader = RBS::EnvironmentLoader.new
63
- env = RBS::Environment.from_loader(env_loader)
64
-
65
- @top_level_decls.each do |_, decl|
66
- env << decl
67
- end
68
- env = env.resolve_type_names
69
-
70
- @steep_target.instance_variable_set("@environment", env)
71
- @steep_target.add_source("gloss", rb_str)
72
-
73
- definition_builder = RBS::DefinitionBuilder.new(env: env)
74
- factory = Steep::AST::Types::Factory.new(builder: definition_builder)
75
- check = Steep::Subtyping::Check.new(factory: factory)
76
- validator = Steep::Signature::Validator.new(checker: check)
77
- validator.validate
78
-
79
- raise Errors::TypeValidationError, validator.each_error.to_a.join("\n") unless validator.no_error?
80
-
81
- @steep_target.run_type_check(env, check, Time.now)
82
-
83
- @steep_target.status.is_a?(Steep::Project::Target::TypeCheckStatus) &&
84
- @steep_target.no_error? &&
85
- @steep_target.errors.empty?
86
- end
87
-
88
31
  def visit_node(node, scope = Scope.new)
89
32
  src = Source.new(@indent_level)
90
- case node[:type]
91
- when "ClassNode"
92
- class_name = visit_node(node[:name])
93
- superclass = if node[:superclass]
94
- @eval_vars = true
95
- visit_node(node[:superclass])
96
- @eval_vars = false
97
- else
98
- nil
99
- end
100
-
101
- src.write_ln "class #{class_name}#{" < #{superclass}" if superclass}"
102
-
103
- current_namespace = @current_scope ? @current_scope.name.to_namespace : RBS::Namespace.root
104
- class_type = RBS::AST::Declarations::Class.new(
105
- name: RBS::TypeName.new(
106
- namespace: current_namespace,
107
- name: class_name.to_sym
108
- ),
109
- type_params: RBS::AST::Declarations::ModuleTypeParams.new, # responds to #add to add params
110
- super_class: superclass ? RBS::AST::Declarations::Class::Super.new(name: RBS::Typename.new(name: super_class.to_sym, namespace: RBS::Namespace.root), args: [], location: nil) : nil,
111
- members: [],
112
- annotations: [],
113
- location: node[:location],
114
- comment: node[:comment]
115
- )
116
- old_parent_scope = @current_scope
117
- @current_scope = class_type
118
-
119
- indented(src) { src.write_ln visit_node(node[:body]) if node[:body] }
120
-
121
- src.write_ln "end"
122
-
123
- @current_scope = old_parent_scope
124
- @top_level_decls[class_type.name.name] = class_type unless @current_scope
125
- when "ModuleNode"
126
- module_name = visit_node node[:name]
127
- src.write_ln "module #{module_name}"
128
-
129
- current_namespace = RBS::Namespace.root # RBS::Namespace.new(path: [module_name.to_sym], absolute: false)
130
-
131
- module_type = RBS::AST::Declarations::Module.new(
132
- name: RBS::TypeName.new(
133
- namespace: current_namespace,
134
- name: module_name.to_sym
135
- ),
136
- type_params: RBS::AST::Declarations::ModuleTypeParams.new, # responds to #add to add params
137
- self_types: [],
138
- members: [],
139
- annotations: [],
140
- location: node[:location],
141
- comment: node[:comment]
142
- )
143
- old_parent_scope = @current_scope
144
- @current_scope = module_type
145
-
146
- indented(src) { src.write_ln visit_node(node[:body]) if node[:body] }
147
-
148
- @current_scope = old_parent_scope
149
- @top_level_decls[module_type.name.name] = module_type unless @current_scope
150
- src.write_ln "end"
151
- when "DefNode"
152
- args = render_args(node)
153
- src.write_ln "def #{node[:name]}#{args}"
154
-
155
- return_type = if node[:return_type]
156
- RBS::Types::ClassInstance.new(
157
- name: RBS::TypeName.new(
158
- name: eval(visit_node(node[:return_type])).to_s.to_sym,
159
- namespace: RBS::Namespace.root
160
- ),
161
- args: [],
162
- location: nil
163
- )
164
- else
165
- RBS::Types::Bases::Any.new(location: nil)
166
- end
167
-
168
- method_types = [
169
- RBS::MethodType.new(
170
- type_params: [],
171
- type: RBS::Types::Function.new(
172
- required_positionals: [],
173
- optional_positionals: [],
174
- rest_positionals: nil,
175
- trailing_positionals: [],
176
- required_keywords: {},
177
- optional_keywords: {},
178
- rest_keywords: node[:rest_kw_args] ?
179
- RBS::Types::Function::Param.new(
180
- name: visit_node(node[:rest_kw_args]).to_sym,
181
- type: RBS::Types::Bases::Any.new(location: nil)
182
- ) : nil,
183
- return_type: return_type
184
- ),
185
- block: nil,
186
- location: nil
187
- )
188
- ]
189
- method_definition = RBS::AST::Members::MethodDefinition.new(
190
- name: node[:name].to_sym,
191
- kind: :instance,
192
- types: method_types,
193
- annotations: [],
194
- location: node[:location],
195
- comment: node[:comment],
196
- overload: false
197
- )
198
-
199
- if @current_scope
200
- @current_scope.members << method_definition
201
- else
202
- @type_env << method_definition # should be new class declaration for Object with method_definition as private method
203
- end
204
-
205
- indented(src) { src.write_ln visit_node(node[:body]) if node[:body] }
206
-
207
- src.write_ln "end"
208
- when "CollectionNode"
209
- src.write(*node[:children].map { |a| visit_node(a, scope) })
210
- when "Call"
211
- obj = node[:object] ? "#{visit_node(node[:object], scope)}." : ""
212
- args = node[:args] || EMPTY_ARRAY
213
- args = if !args.empty? || node[:block_arg]
214
- "(#{args.map { |a| visit_node(a, scope).strip }.reject(&:blank?).join(", ")}#{"&#{visit_node(node[:block_arg]).strip}" if node[:block_arg]})"
215
- else
216
- nil
217
- end
218
- block = node[:block] ? " #{visit_node(node[:block])}" : nil
219
- src.write_ln "#{obj}#{node[:name]}#{args}#{block}"
220
-
221
- when "Block"
222
-
223
- src.write "{ |#{node[:args].map { |a| visit_node a }.join(", ")}|\n"
224
-
225
- indented(src) { src.write visit_node(node[:body]) }
226
-
227
- src.write_ln "}"
228
-
229
- when "RangeLiteral"
230
- dots = node[:exclusive] ? "..." : ".."
231
-
232
- # parentheses help the compatibility with precendence of operators in some situations
233
- # eg. (1..3).cover? 2 vs. 1..3.cover? 2
234
- src.write "(", visit_node(node[:from]), dots, visit_node(node[:to]), ")"
235
-
236
- when "LiteralNode"
237
-
238
- src.write node[:value]
239
-
240
- when "ArrayLiteral"
241
-
242
- src.write("[", *node[:elements].map { |e| visit_node e }.join(", "), "]")
243
- src.write ".freeze" if node[:frozen]
244
-
245
- when "StringInterpolation"
246
-
247
- contents = node[:contents].inject(String.new) do |str, c|
248
- str << case c[:type]
249
- when "LiteralNode"
250
- c[:value][1...-1]
251
- else
252
- "\#{#{visit_node(c).strip}}"
253
- end
254
- end
255
- src.write '"', contents, '"'
256
-
257
- when "Path"
258
-
259
- src.write node[:value]
260
-
261
- when "Require"
262
-
263
- src.write_ln %(require "#{node[:value]}")
264
-
265
- when "Assign", "OpAssign"
266
-
267
- src.write_ln "#{visit_node(node[:target])} #{node[:op]}= #{visit_node(node[:value]).strip}"
268
-
269
- when "Var"
270
-
271
- if @eval_vars
272
- src.write scope[node[:name]]
273
- else
274
- src.write node[:name]
275
- end
276
-
277
- when "InstanceVar"
278
-
279
- src.write node[:name]
280
-
281
- when "Arg"
282
-
283
- src.write node[:external_name]
284
-
285
- when "UnaryExpr"
286
-
287
- src.write "#{node[:op]}#{visit_node(node[:value]).strip}"
288
-
289
- when "BinaryOp"
290
-
291
- src.write visit_node(node[:left]).strip, " #{node[:op]} ", visit_node(node[:right]).strip
292
-
293
- when "HashLiteral"
294
-
295
- contents = node[:elements].map do |k, v|
296
- key = case k
297
- when String
298
- k.to_sym
299
- else
300
- visit_node k
301
- end
302
- value = visit_node v
303
- "#{key.inspect} => #{value}"
304
- end
305
-
306
- src.write "{#{contents.join(",\n")}}"
307
- src.write ".freeze" if node[:frozen]
308
-
309
- when "Enum"
310
- src.write_ln "module #{node[:name]}"
311
- node[:members].each_with_index do |m, i|
312
- indented(src) { src.write_ln(visit_node(m) + (!m[:value] ? " = #{i}" : "")) }
313
- end
314
- src.write_ln "end"
315
- when "If"
316
- src.write_ln "(if #{visit_node(node[:condition]).strip}"
317
-
318
- indented(src) { src.write_ln visit_node(node[:then]) }
319
-
320
- if node[:else]
321
- src.write_ln "else"
322
- indented(src) { src.write_ln visit_node(node[:else]) }
323
- end
324
-
325
- src.write_ln "end)"
326
- when "Case"
327
- src.write "case"
328
- src.write " #{visit_node(node[:condition]).strip}\n" if node[:condition]
329
- indented(src) do
330
- node[:whens].each do |w|
331
- src.write_ln visit_node(w)
33
+ case node.[](:"type")
34
+ when "ClassNode"
35
+ class_name = visit_node(node.[](:"name"))
36
+ current_namespace = (if @current_scope
37
+ @current_scope.name
38
+ .to_namespace
39
+ else
40
+ RBS::Namespace.root
41
+ end)
42
+ superclass_type = nil
43
+ superclass_output = nil
44
+ (if node.[](:"superclass")
45
+ @eval_vars = true
46
+ superclass_output = visit_node(node.[](:"superclass"))
47
+ @eval_vars = false
48
+ superclass_type = RBS::Parser.parse_type(superclass_output)
49
+ (if node.dig(:"superclass", :"type")
50
+ .==("Generic")
51
+ superclass_output = superclass_output.[](/^[^\[]+/)
52
+ end)
53
+ end)
54
+ src.write_ln("class #{class_name}#{(if superclass_output
55
+ " < #{superclass_output}"
56
+ end)}")
57
+ class_type = RBS::AST::Declarations::Class.new(name: RBS::TypeName.new(namespace: current_namespace, name: class_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, super_class: superclass_type, members: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
58
+ old_parent_scope = @current_scope
59
+ @current_scope = class_type
60
+ indented(src) { ||
61
+ (if node.[](:"body")
62
+ src.write_ln(visit_node(node.[](:"body")))
63
+ end)
64
+ }
65
+ src.write_ln("end")
66
+ @current_scope = old_parent_scope
67
+ (if @current_scope
68
+ @current_scope.members
69
+ .<<(class_type)
70
+ end)
71
+ (if @type_checker
72
+ unless @current_scope
73
+ @type_checker.top_level_decls
74
+ .[]=(class_type.name
75
+ .name, class_type)
76
+ end
77
+ end)
78
+ when "ModuleNode"
79
+ module_name = visit_node(node.[](:"name"))
80
+ src.write_ln("module #{module_name}")
81
+ current_namespace = (if @current_scope
82
+ @current_scope.name
83
+ .to_namespace
84
+ else
85
+ RBS::Namespace.root
86
+ end)
87
+ module_type = RBS::AST::Declarations::Module.new(name: RBS::TypeName.new(namespace: current_namespace, name: module_name.to_sym), type_params: RBS::AST::Declarations::ModuleTypeParams.new, self_types: Array.new, members: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
88
+ old_parent_scope = @current_scope
89
+ @current_scope = module_type
90
+ indented(src) { ||
91
+ (if node.[](:"body")
92
+ src.write_ln(visit_node(node.[](:"body")))
93
+ end)
94
+ }
95
+ @current_scope = old_parent_scope
96
+ (if @current_scope
97
+ @current_scope.members
98
+ .<<(module_type)
99
+ end)
100
+ (if @type_checker
101
+ unless @current_scope
102
+ @type_checker.top_level_decls
103
+ .[]=(module_type.name
104
+ .name, module_type)
105
+ end
106
+ end)
107
+ src.write_ln("end")
108
+ when "DefNode"
109
+ args = render_args(node)
110
+ receiver = (if node.[](:"receiver")
111
+ visit_node(node.[](:"receiver"))
112
+ else
113
+ nil
114
+ end)
115
+ src.write_ln("def #{(if receiver
116
+ "#{receiver}."
117
+ end)}#{node.[](:"name")}#{args.[](:"representation")}")
118
+ return_type = (if node.[](:"return_type")
119
+ RBS::Types::ClassInstance.new(name: RBS::TypeName.new(name: eval(visit_node(node.[](:"return_type")))
120
+ .to_s
121
+ .to_sym, namespace: RBS::Namespace.root), args: EMPTY_ARRAY, location: node.[](:"location"))
122
+ else
123
+ RBS::Types::Bases::Any.new(location: node.[](:"location"))
124
+ end)
125
+ method_types = [RBS::MethodType.new(type_params: EMPTY_ARRAY, type: RBS::Types::Function.new(required_positionals: args.dig(:"types", :"required_positionals"), optional_positionals: args.dig(:"types", :"optional_positionals"), rest_positionals: args.dig(:"types", :"rest_positionals"), trailing_positionals: args.dig(:"types", :"trailing_positionals"), required_keywords: args.dig(:"types", :"required_keywords"), optional_keywords: args.dig(:"types", :"optional_keywords"), rest_keywords: args.dig(:"types", :"rest_keywords"), return_type: return_type), block: (if node.[](:"yield_arg_count")
126
+ RBS::Types::Block.new(type: RBS::Types::Function.new(required_positionals: Array.new, optional_positionals: Array.new, rest_positionals: nil, trailing_positionals: Array.new, required_keywords: Hash.new, optional_keywords: Hash.new, rest_keywords: nil, return_type: RBS::Types::Bases::Any.new(location: node.[](:"location"))), required: !!node.[](:"block_arg") || node.[](:"yield_arg_count"))
127
+ else
128
+ nil
129
+ end), location: node.[](:"location"))]
130
+ method_definition = RBS::AST::Members::MethodDefinition.new(name: node.[](:"name")
131
+ .to_sym, kind: (if receiver
132
+ :"class"
133
+ else
134
+ :"instance"
135
+ end), types: method_types, annotations: EMPTY_ARRAY, location: node.[](:"location"), comment: node.[](:"comment"), overload: false)
136
+ (if @current_scope
137
+ @current_scope.members
138
+ .<<(method_definition)
139
+ else
140
+ (if @type_checker
141
+ @type_checker.type_env
142
+ .<<(method_definition)
143
+ end)
144
+ end)
145
+ indented(src) { ||
146
+ (if node.[](:"body")
147
+ src.write_ln(visit_node(node.[](:"body")))
148
+ end)
149
+ }
150
+ src.write_ln("end")
151
+ when "VisibilityModifier"
152
+ src.write_ln("#{node.[](:"visibility")} #{visit_node(node.[](:"exp"))}")
153
+ when "CollectionNode"
154
+ node.[](:"children")
155
+ .each() { |a|
156
+ src.write(visit_node(a, scope))
157
+ }
158
+ when "Call"
159
+ obj = (if node.[](:"object")
160
+ "#{visit_node(node.[](:"object"), scope)}."
161
+ else
162
+ ""
163
+ end)
164
+ arg_arr = node.fetch(:"args") { ||
165
+ EMPTY_ARRAY }
166
+ (if node.[](:"named_args")
167
+ arg_arr += node.[](:"named_args")
168
+ end)
169
+ args = (if !arg_arr.empty? || node.[](:"block_arg")
170
+ "#{arg_arr.map() { |a|
171
+ visit_node(a, scope)
172
+ .strip
173
+ }
174
+ .reject(&:"blank?")
175
+ .join(", ")}#{(if node.[](:"block_arg")
176
+ "&#{visit_node(node.[](:"block_arg"))
177
+ .strip}"
178
+ end)}"
179
+ else
180
+ nil
181
+ end)
182
+ block = (if node.[](:"block")
183
+ " #{visit_node(node.[](:"block"))}"
184
+ else
185
+ nil
186
+ end)
187
+ has_parens = !!node.[](:"has_parentheses") || args || block
188
+ opening_delimiter = (if has_parens
189
+ "("
190
+ else
191
+ nil
192
+ end)
193
+ call = "#{obj}#{node.[](:"name")}#{opening_delimiter}#{args}#{(if has_parens
194
+ ")"
195
+ end)}#{block}"
196
+ src.write_ln(call)
197
+ when "Block"
198
+ args = render_args(node)
199
+ src.write("{ #{args.[](:"representation")
200
+ .gsub(/(\A\(|\)\z)/, "|")}\n")
201
+ indented(src) { ||
202
+ src.write(visit_node(node.[](:"body")))
203
+ }
204
+ src.write_ln("}")
205
+ when "RangeLiteral"
206
+ dots = (if node.[](:"exclusive")
207
+ "..."
208
+ else
209
+ ".."
210
+ end)
211
+ src.write("(", "(", visit_node(node.[](:"from")), ")", dots, "(", visit_node(node.[](:"to")), ")", ")")
212
+ when "LiteralNode"
213
+ src.write(node.[](:"value"))
214
+ when "ArrayLiteral"
215
+ src.write("[", node.[](:"elements")
216
+ .map() { |e|
217
+ visit_node(e)
218
+ .strip
219
+ }
220
+ .join(", "), "]")
221
+ (if node.[](:"frozen")
222
+ src.write(".freeze")
223
+ end)
224
+ when "StringInterpolation"
225
+ contents = node.[](:"contents")
226
+ .inject(String.new) { |str, c|
227
+ str.<<(case c.[](:"type")
228
+ when "LiteralNode"
229
+ c.[](:"value")
230
+ .[](((1)...(-1)))
231
+ else
232
+ ["\#{", visit_node(c)
233
+ .strip, "}"].join
234
+ end)
235
+ }
236
+ src.write("\"", contents, "\"")
237
+ when "Path"
238
+ src.write(node.[](:"value"))
239
+ when "Require"
240
+ src.write_ln("require \"#{node.[](:"value")}\"")
241
+ when "Assign", "OpAssign"
242
+ src.write_ln("#{visit_node(node.[](:"target"))} #{node.[](:"op")}= #{visit_node(node.[](:"value"))
243
+ .strip}")
244
+ when "MultiAssign"
245
+ src.write_ln("#{node.[](:"targets")
246
+ .map() { |t|
247
+ visit_node(t)
248
+ .strip
249
+ }
250
+ .join(", ")} = #{node.[](:"values")
251
+ .map() { |v|
252
+ visit_node(v)
253
+ .strip
254
+ }
255
+ .join(", ")}")
256
+ when "Var"
257
+ (if @eval_vars
258
+ src.write(scope.[](node.[](:"name")))
259
+ else
260
+ src.write(node.[](:"name"))
261
+ end)
262
+ when "InstanceVar"
263
+ src.write(node.[](:"name"))
264
+ when "GlobalVar"
265
+ src.write(node.[](:"name"))
266
+ when "Arg"
267
+ val = node.[](:"external_name")
268
+ (if node.[](:"keyword_arg")
269
+ val += ":"
270
+ (if node.[](:"value")
271
+ val += " #{visit_node(node.[](:"value"))}"
272
+ end)
273
+ else
274
+ (if node.[](:"value")
275
+ val += " = #{visit_node(node.[](:"value"))}"
276
+ end)
277
+ end)
278
+ src.write(val)
279
+ when "UnaryExpr"
280
+ src.write("#{node.[](:"op")}#{visit_node(node.[](:"value"))
281
+ .strip}")
282
+ when "BinaryOp"
283
+ src.write(visit_node(node.[](:"left"))
284
+ .strip, " #{node.[](:"op")} ", visit_node(node.[](:"right"))
285
+ .strip)
286
+ when "HashLiteral"
287
+ contents = node.[](:"elements")
288
+ .map() { |k, v|
289
+ key = case k
290
+ when String
291
+ k.to_sym
292
+ .inspect
293
+ else
294
+ visit_node(k)
295
+ end
296
+ value = visit_node(v)
297
+ "#{key} => #{value}" }
298
+ src.write("{#{contents.join(",\n")}}")
299
+ (if node.[](:"frozen")
300
+ src.write(".freeze")
301
+ end)
302
+ when "Enum"
303
+ src.write_ln("module #{node.[](:"name")}")
304
+ node.[](:"members")
305
+ .each_with_index() { |m, i|
306
+ indented(src) { ||
307
+ src.write_ln(visit_node(m)
308
+ .+((if !m.[](:"value")
309
+ " = #{i}"
310
+ else
311
+ ""
312
+ end)))
313
+ }
314
+ }
315
+ src.write_ln("end")
316
+ when "If"
317
+ src.write_ln("(if #{visit_node(node.[](:"condition"))
318
+ .strip}")
319
+ indented(src) { ||
320
+ src.write_ln(visit_node(node.[](:"then")))
321
+ }
322
+ (if node.[](:"else")
323
+ src.write_ln("else")
324
+ indented(src) { ||
325
+ src.write_ln(visit_node(node.[](:"else")))
326
+ }
327
+ end)
328
+ src.write_ln("end)")
329
+ when "Unless"
330
+ src.write_ln("unless #{visit_node(node.[](:"condition"))}")
331
+ indented(src) { ||
332
+ src.write_ln(visit_node(node.[](:"then")))
333
+ }
334
+ (if node.[](:"else")
335
+ src.write_ln("else")
336
+ indented(src) { ||
337
+ src.write_ln(visit_node(node.[](:"else")))
338
+ }
339
+ end)
340
+ src.write_ln("end")
341
+ when "Case"
342
+ src.write("case")
343
+ (if node.[](:"condition")
344
+ src.write(" #{visit_node(node.[](:"condition"))
345
+ .strip}\n")
346
+ end)
347
+ indented(src) { ||
348
+ node.[](:"whens")
349
+ .each() { |w|
350
+ src.write_ln(visit_node(w))
351
+ }
352
+ (if node.[](:"else")
353
+ src.write_ln("else")
354
+ indented(src) { ||
355
+ src.write_ln(visit_node(node.[](:"else")))
356
+ }
357
+ end)
358
+ }
359
+ src.write_ln("end")
360
+ when "When"
361
+ src.write_ln("when #{node.[](:"conditions")
362
+ .map() { |n|
363
+ visit_node(n)
364
+ }
365
+ .join(", ")}")
366
+ indented(src) { ||
367
+ src.write_ln((if node.[](:"body")
368
+ visit_node(node.[](:"body"))
369
+ else
370
+ "# no op"
371
+ end))
372
+ }
373
+ when "MacroFor"
374
+ vars, expr, body = node.[](:"vars"), node.[](:"expr"), node.[](:"body")
375
+ var_names = vars.map() { |v|
376
+ visit_node(v)
377
+ }
378
+ @inside_macro = true
379
+ indent_level = @indent_level
380
+ unless indent_level.zero?
381
+ @indent_level -= 1
332
382
  end
333
- end
334
- src.write_ln "end"
335
- when "When"
336
- src.write_ln "when #{node[:conditions].map { |n| visit_node(n) }.join(", ")}"
337
-
338
- indented(src) { src.write_ln visit_node(node[:body]) }
339
- when "MacroFor"
340
- vars, expr, body = node[:vars], node[:expr], node[:body]
341
- var_names = vars.map { |v| visit_node v }
342
- @inside_macro = true
343
- indent_level = @indent_level
344
- @indent_level -= 1 unless indent_level.zero?
345
- expanded = eval(visit_node(expr)).map do |*a|
346
- locals = Hash[[var_names.join(%(", "))].zip(a)]
347
- locals.merge!(scope) if @inside_macro
348
- visit_node(body, locals)
349
- end.flatten
350
- @indent_level += 1 unless indent_level.zero?
351
- src.write(*expanded)
352
- @inside_macro = false
353
- when "MacroLiteral"
354
- src.write node[:value]
355
- when "MacroExpression"
356
- if node[:output]
357
- expr = visit_node node[:expr], scope
358
- val = scope[expr]
359
- src.write val
360
- end
361
- when "MacroIf"
362
- if evaluate_macro_condition(node[:condition], scope)
363
- src.write_ln visit_node(node[:then], scope) if node[:then]
383
+ # @type var expanded: Array[String]
384
+ expanded = eval(visit_node(expr))
385
+ .map() { |*a|
386
+ locals = [var_names.join("\", \"")].zip(a)
387
+ .to_h
388
+ (if @inside_macro
389
+ locals.merge!(scope)
390
+ end)
391
+ visit_node(body, locals)
392
+ }
393
+ .flatten
394
+ unless indent_level.zero?
395
+ @indent_level += 1
396
+ end
397
+ expanded.each() { |e|
398
+ src.write(e)
399
+ }
400
+ @inside_macro = false
401
+ when "MacroLiteral"
402
+ src.write(node.[](:"value"))
403
+ when "MacroExpression"
404
+ (if node.[](:"output")
405
+ expr = visit_node(node.[](:"expr"), scope)
406
+ val = scope.[](expr)
407
+ src.write(val)
408
+ end)
409
+ when "MacroIf"
410
+ (if evaluate_macro_condition(node.[](:"condition"), scope)
411
+ (if node.[](:"then")
412
+ src.write_ln(visit_node(node.[](:"then"), scope))
413
+ end)
414
+ else
415
+ (if node.[](:"else")
416
+ src.write_ln(visit_node(node.[](:"else"), scope))
417
+ end)
418
+ end)
419
+ when "Return"
420
+ val = (if node.[](:"value")
421
+ " #{visit_node(node.[](:"value"))
422
+ .strip}"
423
+ else
424
+ nil
425
+ end)
426
+ src.write("return#{val}")
427
+ when "TypeDeclaration"
428
+ src.write_ln("# @type var #{visit_node(node.[](:"var"))}: #{visit_node(node.[](:"declared_type"))}")
429
+ src.write_ln("#{visit_node(node.[](:"var"))} = #{visit_node(node.[](:"value"))}")
430
+ when "ExceptionHandler"
431
+ src.write_ln("begin")
432
+ indented(src) { ||
433
+ src.write_ln(visit_node(node.[](:"body")))
434
+ }
435
+ (if node.[](:"rescues")
436
+ node.[](:"rescues")
437
+ .each() { |r|
438
+ src.write_ln("rescue #{(if r.[](:"types")
439
+ r.[](:"types")
440
+ .map() { |n|
441
+ visit_node(n)
442
+ }
443
+ .join(", ")
444
+ end)}#{(if r.[](:"name")
445
+ " => #{r.[](:"name")}"
446
+ end)}")
447
+ (if r.[](:"body")
448
+ indented(src) { ||
449
+ src.write_ln(visit_node(r.[](:"body")))
450
+ }
451
+ end)
452
+ }
453
+ end)
454
+ (if node.[](:"else")
455
+ src.write_ln("else")
456
+ indented(src) { ||
457
+ src.write_ln(visit_node(node.[](:"else")))
458
+ }
459
+ end)
460
+ (if node.[](:"ensure")
461
+ src.write_ln("ensure")
462
+ indented(src) { ||
463
+ src.write_ln(visit_node(node.[](:"ensure")))
464
+ }
465
+ end)
466
+ src.write_ln("end")
467
+ when "Generic"
468
+ src.write("#{visit_node(node.[](:"name"))}[#{node.[](:"args")
469
+ .map() { |a|
470
+ visit_node(a)
471
+ }
472
+ .join(", ")}]")
473
+ when "Proc"
474
+ fn = node.[](:"function")
475
+ src.write("->#{render_args(fn)} { #{visit_node(fn.[](:"body"))} }")
476
+ when "Include"
477
+ current_namespace = (if @current_scope
478
+ @current_scope.name
479
+ .to_namespace
480
+ else
481
+ RBS::Namespace.root
482
+ end)
483
+ name = visit_node(node.[](:"name"))
484
+ src.write_ln("include #{name}")
485
+ type = RBS::AST::Members::Include.new(name: method(:"TypeName")
486
+ .call(name), args: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
487
+ (if @current_scope
488
+ @current_scope.members
489
+ .<<(type)
490
+ else
491
+ @type_checker.type_env
492
+ .<<(type)
493
+ end)
494
+ when "Extend"
495
+ current_namespace = (if @current_scope
496
+ @current_scope.name
497
+ .to_namespace
498
+ else
499
+ RBS::Namespace.root
500
+ end)
501
+ name = visit_node(node.[](:"name"))
502
+ src.write_ln("extend #{name}")
503
+ type = RBS::AST::Members::Extend.new(name: method(:"TypeName")
504
+ .call(name), args: Array.new, annotations: Array.new, location: node.[](:"location"), comment: node.[](:"comment"))
505
+ (if @current_scope
506
+ @current_scope.members
507
+ .<<(type)
508
+ else
509
+ @type_checker.type_env
510
+ .<<(type)
511
+ end)
512
+ when "RegexLiteral"
513
+ contents = visit_node(node.[](:"value"))
514
+ src.write(Regexp.new(contents.undump)
515
+ .inspect)
516
+ when "Union"
517
+ types = node.[](:"types")
518
+ output = (if types.length
519
+ .==(2) && types.[](1)
520
+ .[](:"type")
521
+ .==("Path") && types.[](1)
522
+ .[]("value")
523
+ .==(nil)
524
+ "#{visit_node(types.[](0))}?"
525
+ else
526
+ types.map() { |t|
527
+ visit_node(t)
528
+ }
529
+ .join(" | ")
530
+ end)
531
+ src.write(output)
532
+ when "Next"
533
+ (if node.[](:"value")
534
+ val = " #{node.[](:"value")}"
535
+ end)
536
+ src.write("next#{val}")
537
+ when "EmptyNode"
538
+ # no op
364
539
  else
365
- src.write_ln visit_node(node[:else], scope) if node[:else]
366
- end
367
- when "Return"
368
- val = node[:value] ? " #{visit_node(node[:value]).strip}" : nil
369
- src.write "return#{val}"
370
- when "TypeDeclaration"
371
- src.write_ln "# @type var #{visit_node(node[:var])}: #{visit_node(node[:declared_type])}"
372
- src.write_ln "#{visit_node(node[:var])} = #{visit_node(node[:value])}"
373
- when "ExceptionHandler"
374
- src.write_ln "begin"
375
- src.write_ln visit_node(node[:body])
376
- node[:rescues]&.each do |r|
377
- src.write_ln "rescue #{r[:types].map { |n| visit_node n }.join(", ") if r[:types]}#{" => #{r[:name]}" if r[:name]}"
378
- src.write_ln visit_node(r[:body]) if r[:body]
379
- end
380
- if node[:else]
381
- src.write_ln "else"
382
- src.write_ln visit_node(node[:else])
383
- end
384
- if node[:ensure]
385
- src.write_ln "ensure"
386
- src.write_ln visit_node(node[:ensure])
387
- end
388
- src.write_ln "end"
389
- when "EmptyNode"
390
- # pass
391
- else
392
- raise "Not implemented: #{node[:type]}"
540
+ raise("Not implemented: #{node.[](:"type")}")
393
541
  end
394
-
395
- src
542
+ src
396
543
  end
397
-
398
- private
399
-
400
- def evaluate_macro_condition(condition_node, scope)
544
+ private def evaluate_macro_condition(condition_node, scope)
401
545
  @eval_vars = true
402
546
  eval(visit_node(condition_node, scope))
403
547
  @eval_vars = false
404
548
  end
405
-
406
- def indented(src)
549
+ private def indented(src)
407
550
  increment_indent(src)
408
551
  yield
409
552
  decrement_indent(src)
410
553
  end
411
-
412
- def increment_indent(src)
554
+ private def increment_indent(src)
413
555
  @indent_level += 1
414
556
  src.increment_indent
415
557
  end
416
-
417
- def decrement_indent(src)
558
+ private def decrement_indent(src)
418
559
  @indent_level -= 1
419
560
  src.decrement_indent
420
561
  end
421
-
422
- def render_args(node)
423
- rp = node[:rp_args] || EMPTY_ARRAY
424
- op = node[:op_args] || EMPTY_ARRAY
425
- rkw = node[:req_kw_args] || EMPTY_HASH
426
- okw = node[:opt_kw_args] || EMPTY_HASH
427
- rest_p = node[:rest_p_args]
428
- rest_kw = node[:rest_kw_args]
429
- return nil unless [rp, op, rkw, okw, rest_p, rest_kw].any? { |a| !a.nil? || !a.empty? }
430
-
431
- contents = [
432
- rp.map { |a| visit_node(a) },
433
- op.map { |pos| "#{pos.name} = #{value}" },
434
- rkw.map { |name, _| "#{name}:" },
435
- okw.map { |name, _| "#{name}: #{value}" },
436
- rest_p ? "*#{rest_p}" : "",
437
- rest_kw ? "**#{visit_node(rest_kw)}" : ""
438
- ].reject(&:empty?).flatten.join(", ")
439
- "(#{contents})"
562
+ private def render_args(node)
563
+ # @type var rp: Array[Hash[Symbol, Any]]
564
+ rp = node.fetch(:"positional_args") { ||
565
+ EMPTY_ARRAY }
566
+ .filter() { |a|
567
+ !a.[](:"value") }
568
+ # @type var op: Array[Hash[Symbol, Any]]
569
+ op = node.fetch(:"positional_args") { ||
570
+ EMPTY_ARRAY }
571
+ .filter() { |a|
572
+ a.[](:"value")
573
+ }
574
+ # @type var rkw: Hash[Symbol, Any]
575
+ rkw = node.fetch(:"req_kw_args") { ||
576
+ EMPTY_HASH }
577
+ # @type var okw: Hash[Symbol, Any]
578
+ okw = node.fetch(:"opt_kw_args") { ||
579
+ EMPTY_HASH }
580
+ # @type var rest_p: String?
581
+ rest_p = (if node.[](:"rest_p_args")
582
+ visit_node(node.[](:"rest_p_args"))
583
+ else
584
+ nil
585
+ end)
586
+ # @type var rest_kw: Hash[Symbol, Any]?
587
+ rest_kw = node.[](:"rest_kw_args")
588
+ (if [rp, op, rkw, okw, rest_p, rest_kw].all?() { |a|
589
+ a && a.empty? }
590
+ return nil
591
+ end)
592
+ contents = [rp.map() { |a|
593
+ visit_node(a)
594
+ }, op.map() { |a|
595
+ "#{a.[](:"name")} = #{visit_node(a.[](:"value"))
596
+ .strip}" }, rkw.map() { |name, _|
597
+ "#{name}:" }, okw.map() { |name, value|
598
+ "#{name}: #{value}" }, (if rest_p
599
+ "*#{rest_p}"
600
+ else
601
+ ""
602
+ end), (if rest_kw
603
+ "**#{visit_node(rest_kw)}"
604
+ else
605
+ ""
606
+ end)].reject(&:"empty?")
607
+ .flatten
608
+ .join(", ")
609
+ representation = "(#{contents})"
610
+ rp.map!() { |a|
611
+ RBS::Types::Function::Param.new(name: visit_node(a)
612
+ .to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
613
+ }
614
+ op.map!() { |a|
615
+ RBS::Types::Function::Param.new(name: visit_node(a)
616
+ .to_sym, type: RBS::Types::Bases::Any.new(location: a.[](:"location")))
617
+ }
618
+ rest_p = (if rpa = node.[](:"rest_p_args")
619
+ RBS::Types::Function::Param.new(name: visit_node(rpa)
620
+ .to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
621
+ else
622
+ nil
623
+ end)
624
+ {:representation => representation,
625
+ :types => {:required_positionals => rp,
626
+ :optional_positionals => op,
627
+ :rest_positionals => rest_p,
628
+ :trailing_positionals => EMPTY_ARRAY,
629
+ :required_keywords => node.[](:"req_kw_args") || EMPTY_HASH,
630
+ :optional_keywords => node.[](:"opt_kw_args") || EMPTY_HASH,
631
+ :rest_keywords => (if node.[](:"rest_kw_args")
632
+ RBS::Types::Function::Param.new(name: visit_node(node.[](:"rest_kw_args"))
633
+ .to_sym, type: RBS::Types::Bases::Any.new(location: node.[](:"location")))
634
+ else
635
+ nil
636
+ end)
637
+ }.freeze}.freeze
440
638
  end
441
639
  end
442
640
  end