Class: DeepCover::Node

Inherits:
Object
  • Object
show all
Extended by:
CheckCompletion, Filters::ClassMethods
Includes:
CanAugmentChildren, ChildCanBeEmpty, Memoize, Mixin, ExecutionLocation, Filters, 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, SimpleIfEmpty, SimpleIfItsChildrenAre, WithBlock Classes: Alias, And, Arg, Args, Array, Begin, Block, BlockPass, Blockarg, BooleanAssignment, Break, Case, Casgn, Cbase, Class, Const, ConstantOperatorAssign, Csend, CsendInnerSend, Def, Defined, Defs, DynamicLiteral, EmptyBody, Ensure, For, Hash, If, Kwbegin, Kwsplat, Masgn, MatchWithLvasgn, Mlhs, Module, ModuleName, NeverEvaluated, Next, NthRef, OpAsgn, Optarg, Or, Pair, Range, Regexp, Regopt, Resbody, Rescue, Restarg, Return, Root, Sclass, Send, SendBase, SendOperatorAssign, SendWithBlock, ShortCircuit, SingletonLiteral, Splat, StaticLiteral, 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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Memoize

#freeze, included

Constructor Details

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

Returns a new instance of Node.



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

def initialize(base_node, parent:, 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.



20
21
22
# File 'lib/deep_cover/node/base.rb', line 20

def base_node
  @base_node
end

#childrenObject (readonly)

Returns the value of attribute children.



20
21
22
# File 'lib/deep_cover/node/base.rb', line 20

def children
  @children
end

#indexObject (readonly)

Returns the value of attribute index.



20
21
22
# File 'lib/deep_cover/node/base.rb', line 20

def index
  @index
end

#next_siblingObject

Returns the value of attribute next_sibling.



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

def next_sibling
  @next_sibling
end

#parentObject (readonly)

Returns the value of attribute parent.



20
21
22
# File 'lib/deep_cover/node/base.rb', line 20

def parent
  @parent
end

#previous_siblingObject

Returns the value of attribute previous_sibling.



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

def previous_sibling
  @previous_sibling
end

Class Method Details

.[](source) ⇒ Object

Shortcut to create a node from source code



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

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

.atom(type) ⇒ Object

Atoms



26
27
28
29
30
# File 'lib/deep_cover/node/literals.rb', line 26

def self.atom(type)
  ::Class.new(StaticLiteral) do
    has_child value: type
  end
end

.define_module_classObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/deep_cover/node/module.rb', line 24

def self.define_module_class
  check_completion
  has_tracker :body_entry
  yield
  has_child body: Node,
            can_be_empty: -> { base_node.loc.end.begin },
            rewrite: '%{body_entry_tracker};%{node}',
            is_statement: true,
            flow_entry_count: :body_entry_tracker_hits
  executed_loc_keys :keyword

  class_eval do
    def execution_count # Overrides ExecutedAfterChildren
      body_entry_tracker_hits
    end
  end
end

.has_evaluated_segmentsObject

Dynamic



73
74
75
# File 'lib/deep_cover/node/literals.rb', line 73

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

.inherited(parent) ⇒ Object



10
11
12
13
# File 'lib/deep_cover/node.rb', line 10

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

Instance Method Details

#[](lookup) ⇒ Object

Shortcut to access children



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

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

#children_nodesObject Also known as: children_nodes_in_flow_order



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

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

#covered_codeObject

Internal API



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

def covered_code
  parent.covered_code
end

#each_node {|_self| ... } ⇒ Object

Yields its children and itself

Yields:

  • (_self)

Yield Parameters:



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

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

#fancy_typeObject



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

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



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

def find_all(lookup)
  case lookup
  when ::Module
    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
    raise ::TypeError, "Expected class or symbol, got #{lookup.class}: #{lookup.inspect}"
  end
end

#simple_literal?Boolean

Returns:

  • (Boolean)


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

def simple_literal?
  false
end

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



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

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



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

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