Module: RBS::Prototype::Helpers

Included in:
NodeUsage, RB, RBI, Runtime
Defined in:
lib/rbs/prototype/helpers.rb,
sig/prototype/helpers.rbs

Instance Method Summary collapse

Instance Method Details

#any_node?(node, nodes: []) {|arg0| ... } ⇒ Boolean

Parameters:

  • (node)
  • nodes: (Array[node]) (defaults to: [])

Yields:

Yield Parameters:

  • arg0 (node)

Yield Returns:

  • (Boolean)

Returns:

  • (Boolean)


153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rbs/prototype/helpers.rb', line 153

def any_node?(node, nodes: [], &block)
  if yield(node)
    nodes << node
  end

  each_child node do |child|
    any_node? child, nodes: nodes, &block
  end

  nodes.empty? ? nil : nodes
end

#args_from_node(args_node) ⇒ Array[untyped]

NOTE: args_node may be a nil by a bug https://bugs.ruby-lang.org/issues/17495

Parameters:

  • (node, nil)

Returns:



177
178
179
# File 'lib/rbs/prototype/helpers.rb', line 177

def args_from_node(args_node)
  args_node&.children || [0, nil, nil, nil, 0, nil, nil, nil, nil, nil]
end

#block_from_body(node) ⇒ Types::Block?

Parameters:

  • (node)

Returns:



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rbs/prototype/helpers.rb', line 65

def block_from_body(node)
  _, args_node, body_node = node.children
  _pre_num, _pre_init, _opt, _first_post, _post_num, _post_init, _rest, _kw, _kwrest, block_var = args_from_node(args_node)

  # @type var body_node: node?
  if body_node
    yields = any_node?(body_node) {|n| n.type == :YIELD }
  end

  if yields || block_var
    required = true

    if body_node
      if any_node?(body_node) {|n| n.type == :FCALL && n.children[0] == :block_given? && !n.children[1] }
        required = false
      end
    end

    if _rest == :* && block_var == :&
      # ... is given
      required = false
    end

    if block_var
      if body_node
        usage = NodeUsage.new(body_node)
        if usage.each_conditional_node.any? {|n| n.type == :LVAR && n.children[0] == block_var }
          required = false
        end
      end
    end

    if yields
      function = Types::Function.empty(untyped)

      yields.each do |yield_node|
        array_content = yield_node.children[0]&.children&.compact || []

        # @type var keywords: node?
        positionals, keywords = if keyword_hash?(array_content.last)
                                  [array_content.take(array_content.size - 1), array_content.last]
                                else
                                  [array_content, nil]
                                end

        if (diff = positionals.size - function.required_positionals.size) > 0
          diff.times do
            function.required_positionals << Types::Function::Param.new(
              type: untyped,
              name: nil
            )
          end
        end

        if keywords
          keywords.children[0].children.each_slice(2) do |key_node, value_node|
            if key_node
              key = key_node.children[0]
              function.required_keywords[key] ||=
                Types::Function::Param.new(
                  type: untyped,
                  name: nil
                )
            end
          end
        end
      end
    else
      function = Types::UntypedFunction.new(return_type: untyped)
    end


    Types::Block.new(required: required, type: function, self_type: nil)
  end
end

#each_child(node) {|child| ... } ⇒ void

This method returns an undefined value.

Parameters:

  • (node)

Yields:

Yield Parameters:

  • child (node)

Yield Returns:

  • (void)


141
142
143
# File 'lib/rbs/prototype/helpers.rb', line 141

def each_child(node, &block)
  each_node node.children, &block
end

#each_node(nodes) {|arg0| ... } ⇒ void

This method returns an undefined value.

Parameters:

Yields:

Yield Parameters:

  • arg0 (node)

Yield Returns:

  • (void)


145
146
147
148
149
150
151
# File 'lib/rbs/prototype/helpers.rb', line 145

def each_node(nodes)
  nodes.each do |child|
    if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
      yield child
    end
  end
end

#keyword_hash?(node) ⇒ Boolean

Parameters:

  • (node)

Returns:

  • (Boolean)


165
166
167
168
169
170
171
172
173
# File 'lib/rbs/prototype/helpers.rb', line 165

def keyword_hash?(node)
  if node && node.type == :HASH
    node.children[0].children.compact.each_slice(2).all? {|key, _|
      symbol_literal_node?(key)
    }
  else
    false
  end
end

#parse_comments(string, include_trailing:) ⇒ Hash[Integer, AST::Comment]

Parameters:

  • (String)
  • include_trailing: (Boolean)

Returns:



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rbs/prototype/helpers.rb', line 10

def parse_comments(string, include_trailing:)
  Prism.parse_comments(string, version: "current").yield_self do |prism_comments| # steep:ignore UnexpectedKeywordArgument
    prism_comments.each_with_object({}) do |comment, hash| #$ Hash[Integer, AST::Comment]
      # Skip EmbDoc comments
      next unless comment.is_a?(Prism::InlineComment)
      # skip like `module Foo # :nodoc:`
      next if comment.trailing? && !include_trailing

      line = comment.location.start_line
      body = "#{comment.location.slice}\n"
      body = body[2..-1] or raise
      body = "\n" if body.empty?

      comment = AST::Comment.new(string: body, location: nil)
      if prev_comment = hash.delete(line - 1)
        hash[line] = AST::Comment.new(string: prev_comment.string + comment.string,
                                      location: nil)
      else
        hash[line] = comment
      end
    end
  end
end

#symbol_literal_node?(node) ⇒ Symbol?

Returns a symbol if the node is a symbol literal node

Parameters:

  • (node)

Returns:

  • (Symbol, nil)


20
21
22
23
24
25
26
27
28
29
# File 'sig/prototype/helpers.rbs', line 20

def symbol_literal_node?(node)
  case node.type
  when :LIT
    if node.children[0].is_a?(Symbol)
      node.children[0]
    end
  when :SYM
    node.children[0]
  end
end

#untypedTypes::Bases::Any

Returns:



192
193
194
# File 'lib/rbs/prototype/helpers.rb', line 192

def untyped
  @untyped ||= Types::Bases::Any.new(location: nil)
end