Class: Citrus::Repeat

Inherits:
Object show all
Includes:
Nonterminal
Defined in:
lib/citrus.rb

Overview

A Repeat is a Nonterminal that specifies a minimum and maximum number of times its rule must match. The Citrus notation is an integer, N, followed by an asterisk, followed by another integer, M, all of which follow any other expression, e.g.:

expr N*M

In this notation N specifies the minimum number of times the preceding expression must match and M specifies the maximum. If N is ommitted, it is assumed to be 0. Likewise, if M is omitted, it is assumed to be infinity (no maximum). Thus, an expression followed by only an asterisk may match any number of times, including zero.

The shorthand notation + and ? may be used for the common cases of 1* and *1 respectively, e.g.:

expr+
expr?

Instance Attribute Summary collapse

Attributes included from Nonterminal

#rules

Attributes included from Rule

#extension, #grammar, #label, #name

Instance Method Summary collapse

Methods included from Nonterminal

#grammar=

Methods included from Rule

#==, #===, #default_options, #elide?, #extend_match, for, #inspect, #needs_paren?, #parse, #terminal?, #test, #to_embedded_s, #to_s

Constructor Details

#initialize(rule = '', min = 1, max = Infinity) ⇒ Repeat

Returns a new instance of Repeat.

Raises:

  • (ArgumentError)


1129
1130
1131
1132
1133
1134
# File 'lib/citrus.rb', line 1129

def initialize(rule='', min=1, max=Infinity)
  raise ArgumentError, "Min cannot be greater than max" if min > max
  super([rule])
  @min = min
  @max = max
end

Instance Attribute Details

#maxObject (readonly)

The maximum number of times this rule may match.



1169
1170
1171
# File 'lib/citrus.rb', line 1169

def max
  @max
end

#minObject (readonly)

The minimum number of times this rule must match.



1166
1167
1168
# File 'lib/citrus.rb', line 1166

def min
  @min
end

Instance Method Details

#exec(input, events = []) ⇒ Object

Returns an array of events for this rule on the given input.



1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
# File 'lib/citrus.rb', line 1142

def exec(input, events=[])
  events << self

  index = events.size
  start = index - 1
  length = n = 0

  while n < max && input.exec(rule, events).size > index
    length += events[-1]
    index = events.size
    n += 1
  end

  if n >= min
    events << CLOSE
    events << length
  else
    events.slice!(start, index)
  end

  events
end

#operatorObject

Returns the operator this rule uses as a string. Will be one of +, ?, or N*M.



1173
1174
1175
1176
1177
1178
1179
1180
1181
# File 'lib/citrus.rb', line 1173

def operator
  @operator ||= case [min, max]
    when [0, 0] then ''
    when [0, 1] then '?'
    when [1, Infinity] then '+'
    else
      [min, max].map {|n| n == 0 || n == Infinity ? '' : n.to_s }.join('*')
    end
end

#ruleObject

Returns the Rule object this rule uses to match.



1137
1138
1139
# File 'lib/citrus.rb', line 1137

def rule
  rules[0]
end

#to_citrusObject

Returns the Citrus notation of this rule as a string.



1184
1185
1186
# File 'lib/citrus.rb', line 1184

def to_citrus # :nodoc:
  rule.to_embedded_s + operator
end