Class: Spectre::InputIterator

Inherits:
Object
  • Object
show all
Defined in:
lib/spectre/base/inputiterator.rb

Overview

Used to access the input stream. The standard implementation works with Integers on Array or String-like structures and is a forward iterator. Jumping to a position behind the current one is only possible via a call to #to. To actually be able to use the InputIterator, you have to subclass it and implement the #concat and #empty methods. When implementing iterators for non-array-like data, you will also have to reimplement #get and #valid?. When implementing iterators which do not rely on 0 based Integers, you will also have to reimplement #+, #@+, #-, #skip! and #to.

The Input =

The input the InputIterator will traverse must have some properties, regardless of the Parsers used on it. It must be

  • comparable, i.e. it has to supply the standard comparison operators <, >, ==, != etc.

  • non-atomic, i.e. you must be able to split the input into pieces.

Direct Known Subclasses

StringParsing::StringInputIterator

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input, pos = 0) ⇒ InputIterator

Initializes the iterator to a position on an input.



91
92
93
# File 'lib/spectre/base/inputiterator.rb', line 91

def initialize input, pos = 0
    @pos, @input, @transformation, @skipper = pos, input, :default, :default
end

Instance Attribute Details

#inputObject

The input this iterator works on. The default is an array-like structure.



46
47
48
# File 'lib/spectre/base/inputiterator.rb', line 46

def input
  @input
end

#posObject

The position this iterator is currently at. The default is an Integer.



86
87
88
# File 'lib/spectre/base/inputiterator.rb', line 86

def pos
  @pos
end

#skipperObject

Returns the skipper or an empty skipper or the #default_skipper if the skipper is set to :default.



64
65
66
# File 'lib/spectre/base/inputiterator.rb', line 64

def skipper
  @skipper
end

#transformationObject

Returns the transformation or an empty transformation or the #default_transformation if the transformation is set to nil.



81
82
83
# File 'lib/spectre/base/inputiterator.rb', line 81

def transformation
  @transformation
end

Instance Method Details

#+(n) ⇒ Object

Returns the next n tokens from (and including) the current position and advances by n tokens.



116
117
118
119
120
# File 'lib/spectre/base/inputiterator.rb', line 116

def + n
    tokens,len = self.internal_get(@pos..@pos+n-1)
    @pos += len
    tokens
end

#+@Object

Returns the token at the current position and advances by one token.



106
107
108
109
110
# File 'lib/spectre/base/inputiterator.rb', line 106

def +@
    token,len = self.internal_get(@pos..@pos)
    @pos += len
    token
end

#-(iter) ⇒ Object

Calculates the distance between the positions this iterator and the other iter point to. If they point to the same location, the distance will be 0, if this iterator points behind iter, the distance will be positive, else negative.

NOTE: This method must be used to correctly calculate Match length in Parsers.



138
139
140
# File 'lib/spectre/base/inputiterator.rb', line 138

def - iter
    @pos - iter.pos
end

#concat(val1, val2) ⇒ Object

Concatenates the two values and returns the result. The values will be of the same type as the input. Must be able to handle nil as a value as well. Must be implemented by a subclass.



235
236
237
# File 'lib/spectre/base/inputiterator.rb', line 235

def concat val1, val2
    nil
end

#default_skipperObject

Returns the default skipper for this InputIterator class. The default implementation simply returns nil.



174
175
176
# File 'lib/spectre/base/inputiterator.rb', line 174

def default_skipper
    nil
end

#default_transformationObject

Returns the default transformation for this InputIterator class. The default implementation simply returns nil.



182
183
184
# File 'lib/spectre/base/inputiterator.rb', line 182

def default_transformation
    nil
end

#emptyObject

Returns an empty object of the input type, e.g. an empty String or an empty Array. Must be implemented by a subclass.



243
244
245
# File 'lib/spectre/base/inputiterator.rb', line 243

def empty
    nil
end

#get(*args) ⇒ Object

Retrieves the tokens from within the specified range, with the transformation applied.



216
217
218
# File 'lib/spectre/base/inputiterator.rb', line 216

def get *args
    self.internal_get(*args)[0]
end

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

Executes the given block with the skipper being set to nil.

Yields:

  • (_self)

Yield Parameters:



223
224
225
226
227
228
# File 'lib/spectre/base/inputiterator.rb', line 223

def ignore_skipper &block
    return unless block_given?
    bak, @skipper = @skipper, nil
    yield self
    @skipper = bak
end

#initialize_copy(other) ⇒ Object

Copies the position and input reference from the other iterator to initialize this one.



99
100
101
# File 'lib/spectre/base/inputiterator.rb', line 99

def initialize_copy other
    @pos, @input = other.pos, other.input
end

#restObject

Returns all of the input that has not yet been parsed, while ignoring the skipper.



209
210
211
# File 'lib/spectre/base/inputiterator.rb', line 209

def rest
    @input[@pos..-1]
end

#skip!Object

If there are any skippable tokens from (and including) the current position, a call to this method will cause the InputIterator to advance over them to the next non-skippable token.



163
164
165
166
167
168
# File 'lib/spectre/base/inputiterator.rb', line 163

def skip!
    copy = self.dup
    while dist = skipper.call(@input[@pos..@pos], copy)
        @pos += dist
    end
end

#to(n) ⇒ Object

Sets the iterator to point to address n. Will not return the token at that position but the modified iterator instead..



126
127
128
129
# File 'lib/spectre/base/inputiterator.rb', line 126

def to n
    @pos = n
    self
end

#valid?Boolean

Whether or not this iterator points to a valid location in the input. This must take the skip parser into consideration.

Returns:

  • (Boolean)


146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/spectre/base/inputiterator.rb', line 146

def valid?
    return false if @pos >= @input.length

    pos = @pos
    while skip = skipper.call(@input[pos..pos], self)
        pos += skip
    end

    return false if pos >= @input.length

    true
end