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.

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)


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
86
87
88
89
# File 'lib/rley/parser/parse_walker_factory.rb', line 56

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)

  walker = 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

  return walker
end