Module: Rsec::Parser

Included in:
Binary, Cached, RepeatAtLeastN, RepeatN, RepeatRange, SeqOne, SeqOne_, Seq_, Unary
Defined in:
lib/rsec/parser.rb,
lib/rsec/helpers.rb

Overview


combinators attached to parsers

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#nameObject

Returns the value of attribute name.



24
25
26
# File 'lib/rsec/parser.rb', line 24

def name
  @name
end

Instance Method Details

#&(other, &p) ⇒ Object

@ desc

Lookahead predicate, note that other can be a very complex parser


257
258
259
260
# File 'lib/rsec/helpers.rb', line 257

def & other, &p
  other = Rsec.make_parser other
  LookAhead[self, other].map p
end

#*(n, &p) ⇒ Object

@ desc

Repeat n or in a range.
If range.end < 0, repeat at least range.begin
(Infinity and -Infinity are considered)


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/rsec/helpers.rb', line 217

def * n, &p
  # FIXME if self is an epsilon parser, will cause infinite loop
  parser =
    if n.is_a?(Range)
      raise "invalid n: #{n}" if n.begin < 0
      Rsec.assert_type n.begin, Integer
      end_inf = (n.end.infinite? rescue false)
      (Rsec.assert_type n.end, Integer) unless end_inf
      if n.end > 0
        RepeatRange[self, n]
      else
        RepeatAtLeastN[self, n.begin]
      end
    else
      Rsec.assert_type n, Integer
      raise "invalid n: #{n}" if n < 0
      RepeatN[self, n]
    end
  parser.map p
end

#<<(other, &p) ⇒ Object

@ desc

Short for seq_(parser, other)[0]


287
288
289
290
291
# File 'lib/rsec/helpers.rb', line 287

def << other, &p
  other = Rsec.make_parser other
  right = Rsec.try_skip_pattern other
  SeqOne_[self, [right], SkipPattern[/\s*/], 0].map p
end

#>>(other, &p) ⇒ Object

@ desc

Short for seq_(parser, other)[1]


279
280
281
282
283
# File 'lib/rsec/helpers.rb', line 279

def >> other, &p
  other = Rsec.make_parser other
  left = Rsec.try_skip_pattern self
  SeqOne_[left, [other], SkipPattern[/\s*/], 1].map p
end

#^(other, &p) ⇒ Object

@ desc

Negative lookahead predicate


264
265
266
267
# File 'lib/rsec/helpers.rb', line 264

def ^ other, &p
  other = Rsec.make_parser other
  NegativeLookAhead[self, other].map p
end

#cached(&p) ⇒ Object

@ desc

Packrat parser combinator, returns a parser that caches parse result, may optimize performance


301
302
303
# File 'lib/rsec/helpers.rb', line 301

def cached &p
  Cached[self].map p
end

#eof(&p) ⇒ Object

@ desc

Should be end of input after parse


295
296
297
# File 'lib/rsec/helpers.rb', line 295

def eof &p
  Eof[self].map p
end

#fail(*tokens, &p) ⇒ Object Also known as: expect

@ desc

When parsing failed, show "expect tokens" error


271
272
273
274
# File 'lib/rsec/helpers.rb', line 271

def fail *tokens, &p
  return self if tokens.empty?
  Fail[self, tokens].map p
end

#inspectObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/rsec/parser.rb', line 25

def inspect
  # TODO move
  @name ||= self.class.to_s[/\w+$/]
  case self
  when Lazy
    "<#{name}>"
  when Binary
    "<#{name} #{left.inspect} #{right.inspect}>"
  when Seq, Seq_, Branch
    # don't use redefined map!
    res = []
    each{|e| res << e.inspect}
    "<#{name} #{res.join ' '}>"
  when Unary
    "<#{name} #{some.inspect}>"
  else
    "<#{name}>"
  end
end

#join(inter, &p) ⇒ Object

@ desc

"p.join('+')" parses strings like "p+p+p+p+p".
Note that at least 1 of p appears in the string.
Sometimes it is useful to reverse the joining:
/\s*/.r.join('p').odd parses string like " p p  p "


194
195
196
197
# File 'lib/rsec/helpers.rb', line 194

def join inter, &p
  inter = Rsec.make_parser inter
  Join[self, inter].map p
end

#map(lambda_p = nil, &p) ⇒ Object

@ desc

Transform result

@ example

parser = /\w+/.r.map{|word| word * 2}
assert_equal 'hellohello', parser.parse!('hello')

Raises:

  • (TypeError)


182
183
184
185
186
187
# File 'lib/rsec/helpers.rb', line 182

def map lambda_p=nil, &p
  return self if (lambda_p.nil? and p.nil?)
  p = lambda_p || p
  raise TypeError, 'should give a proc or lambda' unless (p.is_a? Proc)
  Map[self, p]
end

#maybe(&p) ⇒ Object Also known as: _?

@ desc

Appears 0 or 1 times, result is wrapped in an array

@ example

parser = 'a'.r.maybe
assert_equal ['a'], parser.parse('a')
assert_equal [], parser.parse('')


244
245
246
# File 'lib/rsec/helpers.rb', line 244

def maybe &p
  Maybe[self].map &p
end

#parse(str, source_name = 'source') ⇒ Object

parses string<br/> returns nil if unparsed



8
9
10
11
# File 'lib/rsec/parser.rb', line 8

def parse str, source_name='source'
  ctx = ParseContext.new str, source_name
  _parse ctx
end

#parse!(str, source_name = 'source') ⇒ Object

almost the same as parse<br/> but raises SyntaxError



15
16
17
18
19
20
21
22
# File 'lib/rsec/parser.rb', line 15

def parse! str, source_name='source'
  ctx = ParseContext.new str, source_name
  ret = _parse ctx
  if INVALID[ret]
    raise ctx.generate_error source_name
  end
  ret
end

#star(&p) ⇒ Object

@ desc

Kleen star, 0 or more any times


251
252
253
# File 'lib/rsec/helpers.rb', line 251

def star &p
  self.* (0..-1), &p
end

#|(y, &p) ⇒ Object

@ desc

Branch parser, note that rsec is a PEG parser generator,
beware of the difference between PEG and CFG.


202
203
204
205
206
207
208
209
210
211
# File 'lib/rsec/helpers.rb', line 202

def | y, &p
  y = Rsec.make_parser y
  arr =
    if (is_a?(Branch) and !p)
      [*some, y]
    else
      [self, y]
    end
  Branch[arr].map p
end