Class: DeepCover::Node

Inherits:
Object
  • Object
show all
Extended by:
CheckCompletion
Includes:
CanAugmentChildren, ChildCanBeEmpty, Memoize, Mixin, ExecutionLocation, FlowAccounting, HasChild, HasChildHandler, HasTracker, IsStatement, Rewriting
Defined in:
lib/deep_cover/node/base.rb,
lib/deep_cover/node.rb,
lib/deep_cover/node/if.rb,
lib/deep_cover/node/case.rb,
lib/deep_cover/node/send.rb,
lib/deep_cover/node/begin.rb,
lib/deep_cover/node/block.rb,
lib/deep_cover/node/loops.rb,
lib/deep_cover/node/splat.rb,
lib/deep_cover/node/branch.rb,
lib/deep_cover/node/module.rb,
lib/deep_cover/node/keywords.rb,
lib/deep_cover/node/literals.rb,
lib/deep_cover/node/arguments.rb,
lib/deep_cover/node/variables.rb,
lib/deep_cover/node/exceptions.rb,
lib/deep_cover/node/assignments.rb,
lib/deep_cover/node/collections.rb,
lib/deep_cover/node/short_circuit.rb

Overview

Base class to handle covered nodes.

Defined Under Namespace

Modules: BackwardsStrategy, Branch, Mixin, WithBlock Classes: Alias, Arg, Args, Array, Begin, Block, BlockPass, Blockarg, BooleanAssignment, Break, Case, Casgn, Cbase, Class, Const, ConstantOperatorAssign, Csend, CsendWithBlock, Def, Defined, Defs, DynamicLiteral, EmptyBody, Ensure, For, Hash, If, Kwbegin, Kwsplat, Masgn, MatchWithLvasgn, Mlhs, Module, ModuleName, NeverEvaluated, Next, NthRef, OpAsgn, Optarg, Pair, Range, Regexp, Regopt, Resbody, Rescue, Restarg, Return, Root, Sclass, Send, SendBase, SendOperatorAssign, SendWithBlock, ShortCircuit, SingletonLiteral, Splat, Str, Super, SuperWithBlock, TrivialBranch, Undef, Until, UntilPost, Variable, VariableAssignment, VariableOperatorAssign, When, WhenCondition, WhenSplatCondition, While, WhilePost, Xstr, Yield

Constant Summary collapse

CLASSES =

Reopened in base

[]
Zsuper =

TODO

Super
True =
False = Nil = Self = SingletonLiteral
Sym =
atom(::Symbol)
Int =
atom(::Integer)
Float =
atom(::Float)
Complex =
atom(::Complex)
Rational =
atom(::Rational)
Erange =
Irange = Range
Dsym =
Dstr = DynamicLiteral
Kwarg =
Arg
Kwrestarg =
Restarg
Kwoptarg =
Optarg
Ivar =
Lvar = Cvar = Gvar = BackRef = Variable
Cvasgn =
Gvasgn = Ivasgn = Lvasgn = VariableAssignment
OrAsgn =
AndAsgn = BooleanAssignment
And =
Or = ShortCircuit

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Memoize

#freeze, included

Constructor Details

#initialize(base_node, parent: raise, index: 0, base_children: base_node.children) ⇒ Node

Returns a new instance of Node.



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/deep_cover/node/base.rb', line 20

def initialize(base_node, parent: raise, index: 0, base_children: base_node.children)
  @base_node = base_node
  @parent = parent
  @index = index
  @children = []
  begin
    @children = augment_children(base_children)
    initialize_siblings
    super()
  rescue StandardError => e
    diagnose(e)
  end
end

Instance Attribute Details

#base_nodeObject (readonly)

Returns the value of attribute base_node.



18
19
20
# File 'lib/deep_cover/node/base.rb', line 18

def base_node
  @base_node
end

#childrenObject (readonly)

Returns the value of attribute children.



18
19
20
# File 'lib/deep_cover/node/base.rb', line 18

def children
  @children
end

#indexObject (readonly)

Returns the value of attribute index.



18
19
20
# File 'lib/deep_cover/node/base.rb', line 18

def index
  @index
end

#next_siblingObject

Returns the value of attribute next_sibling.



80
81
82
# File 'lib/deep_cover/node/base.rb', line 80

def next_sibling
  @next_sibling
end

#parentObject (readonly)

Returns the value of attribute parent.



18
19
20
# File 'lib/deep_cover/node/base.rb', line 18

def parent
  @parent
end

#previous_siblingObject

Returns the value of attribute previous_sibling.



81
82
83
# File 'lib/deep_cover/node/base.rb', line 81

def previous_sibling
  @previous_sibling
end

Class Method Details

.[](source) ⇒ Object

Shortcut to create a node from source code



71
72
73
# File 'lib/deep_cover/node/base.rb', line 71

def self.[](source)
  CoveredCode.new(source: source).execute_code.covered_ast
end

.atom(type) ⇒ Object

Atoms



14
15
16
17
18
19
# File 'lib/deep_cover/node/literals.rb', line 14

def self.atom(type)
  ::Class.new(Node) do
    has_child value: type
    executed_loc_keys :expression
  end
end

.has_evaluated_segmentsObject

Dynamic



54
55
56
# File 'lib/deep_cover/node/literals.rb', line 54

def self.has_evaluated_segments
  has_extra_children constituents: [Str, Begin, Ivar, Cvar, Gvar, Dstr, NthRef]
end

.inherited(parent) ⇒ Object



7
8
9
10
# File 'lib/deep_cover/node.rb', line 7

def self.inherited(parent)
  CLASSES << parent
  super
end

Instance Method Details

#[](v) ⇒ Object

Shortcut to access children



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/deep_cover/node/base.rb', line 54

def [](v)
  if v.is_a?(Integer)
    children.fetch(v)
  else
    found = find_all(v)
    case found.size
    when 1
      found.first
    when 0
      raise "No children of type #{v}"
    else
      raise "Ambiguous lookup #{v}, found #{found}."
    end
  end
end

#children_nodesObject Also known as: children_nodes_in_flow_order



75
76
77
# File 'lib/deep_cover/node/base.rb', line 75

def children_nodes
  children.select { |c| c.is_a? Node }
end

#covered_codeObject

Internal API



111
112
113
# File 'lib/deep_cover/node/base.rb', line 111

def covered_code
  parent.covered_code
end

#each_node(order = :postorder) {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



120
121
122
123
124
125
126
127
128
# File 'lib/deep_cover/node/base.rb', line 120

def each_node(order = :postorder, &block)
  return to_enum :each_node, order unless block_given?
  yield self unless order == :postorder
  children_nodes.each do |child|
    child.each_node(order, &block)
  end
  yield self if order == :postorder
  self
end

#fancy_typeObject



130
131
132
133
134
# File 'lib/deep_cover/node/base.rb', line 130

def fancy_type
  class_name = self.class.to_s.gsub(/^DeepCover::/, '').gsub(/^Node::/, '')
  t = type.to_s
  t.casecmp(class_name) == 0 ? t : "#{t}[#{class_name}]"
end

#find_all(lookup) ⇒ Object

Search self and descendants for a particular Class or type



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/deep_cover/node/base.rb', line 37

def find_all(lookup)
  case lookup
  when ::Class
    each_node.grep(lookup)
  when ::Symbol
    each_node.find_all { |n| n.type == lookup }
  when ::String
    each_node.find_all { |n| n.source == lookup }
  when ::Regexp
    each_node.find_all { |n| n.source =~ lookup }
  else
    binding.pry
    raise ::TypeError, "Expected class or symbol, got #{lookup.class}: #{lookup.inspect}"
  end
end

#to_s(indent = 0) ⇒ Object Also known as: inspect



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/deep_cover/node/base.rb', line 92

def to_s(indent = 0)
  [
    '  ' * indent,
    '(',
    fancy_type,
    *children.map do |child, idx|
      if child.is_a?(Node)
        "\n#{child.to_s(indent + 1)}"
      else
        " #{child.inspect}"
      end
    end,
    ')',
  ].join
end

#typeObject



115
116
117
118
# File 'lib/deep_cover/node/base.rb', line 115

def type
  return base_node.type if base_node.respond_to? :type
  self.class.name.split('::').last.to_sym
end