Class: Ryac::Pipeline::EndlessMethod

Inherits:
Stage
  • Object
show all
Defined in:
lib/ryac/pipeline/endless_method.rb,
sig/ryac/pipeline/endless_method.rbs

Instance Method Summary collapse

Methods inherited from Stage

#analysis, #analysis_options, #call, #finish, #needs_analysis?, new

Methods included from SourcePatcher

#apply_patches, #mk, #src, #verify_parses

Instance Method Details

#collect(ctx, patches) ⇒ void

This method returns an undefined value.

Parameters:



10
11
12
# File 'lib/ryac/pipeline/endless_method.rb', line 10

def collect(ctx, patches)
  walk(ctx.ast, ctx.source, patches)
end

#fixpoint? ⇒ Boolean

A conversion can expose another convertible def (nested singles), so this runs to a fixed point.

Returns:

  • (Boolean)


8
# File 'lib/ryac/pipeline/endless_method.rb', line 8

def fixpoint? = true

#keyword_logical?(node, source) ⇒ Boolean

Parameters:

  • node (Prism::Node)
  • source (String)

Returns:

  • (Boolean)


52
53
54
55
56
57
# File 'lib/ryac/pipeline/endless_method.rb', line 52

def keyword_logical?(node, source)
  return false unless node.is_a?(Prism::AndNode) || node.is_a?(Prism::OrNode)

  op = source.byteslice(node.operator_loc.start_offset, node.operator_loc.length)
  op == 'and' || op == 'or'
end

#try_def(node, source) ⇒ String?

Parameters:

  • node (Prism::DefNode)
  • source (String)

Returns:

  • (String, nil)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ryac/pipeline/endless_method.rb', line 26

def try_def(node, source)
  body_node = node.body
  return nil unless body_node.is_a?(Prism::StatementsNode)
  return nil if AstUtils.setter_def_name?(node.name)

  stmts = body_node.body
  return nil if stmts.any? { |s| s.is_a?(Prism::MultiWriteNode) }

  body = src(source, body_node)

  if stmts.size > 1
    body = "(#{body})"
  elsif (stmt = stmts.first)
    if keyword_logical?(stmt, source) || AstUtils.modifier_control_flow?(stmt) ||
       AstUtils.match_rebind?(stmt)
      body = "(#{body})"
    end
  end

  header_end = body_node.location.start_offset
  # the def header range is always inside the source, so byteslice is non-nil
  header = source.byteslice(node.location.start_offset, header_end - node.location.start_offset).chomp(';') # steep:ignore NoMethod

  "#{header} =#{body}"
end

#walk(node, source, patches) ⇒ void

This method returns an undefined value.

Parameters:

  • node (Prism::Node)
  • source (String)
  • patches (Array[patch_entry])


16
17
18
19
20
21
22
23
24
# File 'lib/ryac/pipeline/endless_method.rb', line 16

def walk(node, source, patches)
  if node.is_a?(Prism::DefNode) && node.end_keyword_loc
    if (replacement = try_def(node, source))
      patches << mk(node, replacement)
      return
    end
  end
  node.compact_child_nodes.each { |child| walk(child, source, patches) }
end