Class: Ibex::Coverage::Collector

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/coverage/collector.rb,
sig/ibex/coverage/collector.rbs

Overview

Strictly turns one or more complete parse sessions into a coverage report.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCollector

Returns a new instance of Collector.

RBS:

  • () -> void



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/ibex/coverage/collector.rb', line 20

def initialize
  @grammar_digest = nil
  @table_format_version = nil
  @state_count = nil
  @production_count = nil
  @sessions = 0
  @event_count = 0
  @state_hits = Hash.new(0)
  @production_hits = Hash.new(0)
  @in_session = false
  @expected_sequence = 1
end

Class Method Details

.collect_file(path) ⇒ Report

RBS:

  • (String path) -> Report

Parameters:

  • path (String)

Returns:



34
35
36
37
38
39
40
# File 'lib/ibex/coverage/collector.rb', line 34

def self.collect_file(path)
  collector = new
  EventStream.each_file(path) do |document, line|
    collector.consume(document, source: path, line: line)
  end
  collector.finish(source: path)
end

Instance Method Details

#consume(document, source:, line:) ⇒ void

This method returns an undefined value.

RBS:

  • (Hash[String, untyped] document, source: String, line: Integer) -> void

Parameters:

  • document (Hash[String, untyped])
  • source: (String)
  • line: (Integer)


43
44
45
46
47
48
49
50
51
52
# File 'lib/ibex/coverage/collector.rb', line 43

def consume(document, source:, line:)
  event = document.fetch("event")
  sequence = document.fetch("sequence")
  if event == "start"
    start_session(document.fetch("data"), sequence, source, line)
  else
    consume_session_event(event, document.fetch("data"), sequence, source, line)
  end
  @event_count += 1
end

#consume_session_event(event, data, sequence, source, line) ⇒ void

This method returns an undefined value.

RBS:

  • (String event, Hash[untyped, untyped] data, untyped sequence, String source, Integer line) -> void

Parameters:

  • event (String)
  • data (Hash[untyped, untyped])
  • sequence (Object)
  • source (String)
  • line (Integer)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/ibex/coverage/collector.rb', line 89

def consume_session_event(event, data, sequence, source, line)
  invalid(source, line, "event appears outside a parse session") unless @in_session
  unless sequence == @expected_sequence
    invalid(source, line, "expected event sequence #{@expected_sequence}, got #{sequence.inspect}")
  end

  case event
  when "shift", "recover" then hit_state(data["state"], source, line)
  when "reduce"
    hit_production(data["production_id"], source, line)
    hit_state(data["goto_state"], source, line)
  end
  if %w[accept reject].include?(event)
    @in_session = false
    @expected_sequence = 1
  else
    @expected_sequence += 1
  end
end

#establish_metadata(metadata, source, line) ⇒ void

This method returns an undefined value.

RBS:

  • ([String, Integer, Integer, Integer] metadata, String source, Integer line) -> void

Parameters:

  • metadata ([ String, Integer, Integer, Integer ])
  • source (String)
  • line (Integer)


125
126
127
128
129
130
131
132
133
# File 'lib/ibex/coverage/collector.rb', line 125

def (, source, line)
  unless @grammar_digest
    @grammar_digest, @table_format_version, @state_count, @production_count = 
    return
  end

  expected = [@grammar_digest, @table_format_version, @state_count, @production_count]
  invalid(source, line, "parse sessions use different parser metadata") unless  == expected
end

#finish(source:) ⇒ Report

RBS:

  • (source: String) -> Report

Parameters:

  • source: (String)

Returns:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ibex/coverage/collector.rb', line 55

def finish(source:)
  invalid(source, 1, "event stream ended before accept or reject") if @in_session
  invalid(source, 1, "event stream does not contain a parse session") if @sessions.zero?
  Report.new(
    grammar_digest: (@grammar_digest),
    table_format_version: (@table_format_version),
    state_count: (@state_count),
    production_count: (@production_count),
    sessions: @sessions,
    event_count: @event_count,
    state_hits: @state_hits,
    production_hits: @production_hits
  )
rescue ArgumentError => e
  raise Ibex::Error, "#{source}:1:1: #{e.message}"
end

#hit_production(id, source, line) ⇒ void

This method returns an undefined value.

RBS:

  • (untyped id, String source, Integer line) -> void

Parameters:

  • id (Object)
  • source (String)
  • line (Integer)


159
160
161
162
163
# File 'lib/ibex/coverage/collector.rb', line 159

def hit_production(id, source, line)
  total = (@production_count)
  invalid(source, line, "production id #{id.inspect} is outside 0...#{total}") unless valid_id?(id, total)
  increment(@production_hits, id, "production", source, line)
end

#hit_state(id, source, line) ⇒ void

This method returns an undefined value.

RBS:

  • (untyped id, String source, Integer line) -> void

Parameters:

  • id (Object)
  • source (String)
  • line (Integer)


152
153
154
155
156
# File 'lib/ibex/coverage/collector.rb', line 152

def hit_state(id, source, line)
  total = (@state_count)
  invalid(source, line, "state id #{id.inspect} is outside 0...#{total}") unless valid_id?(id, total)
  increment(@state_hits, id, "state", source, line)
end

#increment(hits, id, kind, source, line) ⇒ void

This method returns an undefined value.

RBS:

  • (Hash[Integer, Integer] hits, Integer id, String kind, String source, Integer line) -> void

Parameters:

  • hits (Hash[Integer, Integer])
  • id (Integer)
  • kind (String)
  • source (String)
  • line (Integer)


171
172
173
174
175
# File 'lib/ibex/coverage/collector.rb', line 171

def increment(hits, id, kind, source, line)
  count = hits[id] + 1
  invalid(source, line, "#{kind} hit count exceeds the supported count") if count > Report::MAX_COUNT
  hits[id] = count
end

#invalid(source, line, message) ⇒ bot

RBS:

  • (String source, Integer line, String message) -> bot

Parameters:

  • source (String)
  • line (Integer)
  • message (String)

Returns:

  • (bot)


183
184
185
# File 'lib/ibex/coverage/collector.rb', line 183

def invalid(source, line, message)
  raise Ibex::Error, "#{source}:#{line}:1: #{message}"
end

#required_metadata(value) ⇒ void

This method returns an undefined value.

RBS:

  • [T] (T? value) -> T



178
179
180
# File 'lib/ibex/coverage/collector.rb', line 178

def (value)
  value || raise(ArgumentError, "coverage metadata is unavailable")
end

#session_metadata(data, source, line) ⇒ [ [ String, Integer, Integer, Integer ], Integer ]

RBS:

  • (Hash[untyped, untyped] data, String source, Integer line) -> [[String, Integer, Integer, Integer], Integer]

Parameters:

  • data (Hash[untyped, untyped])
  • source (String)
  • line (Integer)

Returns:

  • ([ [ String, Integer, Integer, Integer ], Integer ])


111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/ibex/coverage/collector.rb', line 111

def (data, source, line)
  digest = data["grammar_digest"]
  format = data["table_format_version"]
  states = data["state_count"]
  productions = data["production_count"]
  initial_state = data["initial_state"]
  unless digest.is_a?(String) && format.is_a?(Integer) && states.is_a?(Integer) &&
         productions.is_a?(Integer) && initial_state.is_a?(Integer)
    invalid(source, line, "start event lacks generated parser coverage metadata")
  end
  [[digest, format, states, productions], initial_state]
end

#start_session(data, sequence, source, line) ⇒ void

This method returns an undefined value.

RBS:

  • (Hash[untyped, untyped] data, untyped sequence, String source, Integer line) -> void

Parameters:

  • data (Hash[untyped, untyped])
  • sequence (Object)
  • source (String)
  • line (Integer)


75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ibex/coverage/collector.rb', line 75

def start_session(data, sequence, source, line)
  invalid(source, line, "new start event before prior session ended") if @in_session
  invalid(source, line, "start event sequence must be 1") unless sequence == 1

  , initial_state = (data, source, line)
  (, source, line)
  validate_metadata!(source, line)
  hit_state(initial_state, source, line)
  @sessions += 1
  @in_session = true
  @expected_sequence = 2
end

#valid_id?(id, total) ⇒ Boolean

RBS:

  • (untyped id, Integer total) -> bool

Parameters:

  • id (Object)
  • total (Integer)

Returns:

  • (Boolean)


166
167
168
# File 'lib/ibex/coverage/collector.rb', line 166

def valid_id?(id, total)
  id.is_a?(Integer) && id >= 0 && id < total
end

#validate_metadata!(source, line) ⇒ void

This method returns an undefined value.

RBS:

  • (String source, Integer line) -> void

Parameters:

  • source (String)
  • line (Integer)


136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/ibex/coverage/collector.rb', line 136

def validate_metadata!(source, line)
  Report.new(
    grammar_digest: (@grammar_digest),
    table_format_version: (@table_format_version),
    state_count: (@state_count),
    production_count: (@production_count),
    sessions: 1,
    event_count: 1,
    state_hits: {},
    production_hits: {}
  )
rescue ArgumentError => e
  invalid(source, line, e.message)
end