Class: Rley::Parser::ParseWalkerFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/rley/parser/parse_walker_factory.rb

Overview

A factory that creates an Enumerator object that itself walks through a GFGParsing object. The walker (= Enumerator) yields visit events. This class implements an external iterator for a given GFGParsing object. This is different from the internal iterators, usually implemented in Ruby with an :each method. Allows to perform a backwards traversal over the relevant parse entries. backwards traversal means that the traversal starts from the accepting (final) parse entries and goes to the initial parse entry. Relevant parse entries are parse entries that "count" in the parse (i.e. they belong to a path that leads to the accepting parse entry)

Instance Method Summary collapse

Instance Method Details

#build_walker(acceptingEntry, maxIndex, lazyWalk = false) ⇒ Enumerator

Build an Enumerator that will yield the parse entries as it walks backwards on the parse graph. rubocop: disable Style/OptionalBooleanParameter

Parameters:

  • acceptingEntry (ParseEntry)

    the final ParseEntry of a successful parse.

  • maxIndex (Integer)

    the index of the last input token.

  • lazyWalk (Boolean) (defaults to: false)

    if true then take some shortcut in re-visits.

Returns:

  • (Enumerator)

    yields visit events when walking over the parse result

Raises:

  • (StandardError)


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/rley/parser/parse_walker_factory.rb', line 54

def build_walker(acceptingEntry, maxIndex, lazyWalk = false)
  msg = 'Internal error: nil entry argument'
  raise StandardError, msg if acceptingEntry.nil?

  # Local context for the enumerator
  ctx = init_context(acceptingEntry, maxIndex, lazyWalk)

  Enumerator.new do |receiver| # 'receiver' is a Yielder
    # At this point: current entry == accepting entry

    loop do
      event = visit_entry(ctx.curr_entry, ctx)
      receiver << event unless event.nil?

      if ctx.curr_entry.orphan? # No antecedent?...
        msg_prefix = "No antecedent for #{ctx.curr_entry}"
        msg_suffix = "at rank #{ctx.entry_set_index}"
        err_msg = "#{msg_prefix} #{msg_suffix}"
        raise StandardError, err_msg unless ctx.curr_entry.start_entry?
        break if ctx.backtrack_points.empty?

        receiver << use_backtrack_point(ctx)
        receiver << visit_entry(ctx.curr_entry, ctx)
      end

      result = jump_to_antecedent(ctx)
      # Emit detection of scan edge if any...
      receiver << result[0] if result.size > 1
      ctx.curr_entry = result.last
    end
  end
end