Class: Paco::Parser

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(desc = "", &block) ⇒ Parser

Returns a new instance of Parser.

Parameters:

  • desc (String) (defaults to: "")


10
11
12
13
# File 'lib/paco/parser.rb', line 10

def initialize(desc = "", &block)
  @desc = desc
  @block = block
end

Instance Attribute Details

#descObject (readonly)

Returns the value of attribute desc.



7
8
9
# File 'lib/paco/parser.rb', line 7

def desc
  @desc
end

Instance Method Details

#_parse(ctx) ⇒ Object

Parameters:



30
31
32
33
34
35
# File 'lib/paco/parser.rb', line 30

def _parse(ctx)
  ctx.start_parse(self)
  res = @block.call(ctx, self)
  ctx.success_parse(res, self)
  res
end

#at_least(num) ⇒ Object

Returns a parser that runs ‘parser` at least `num` times, and returns an array of the results.



168
169
170
171
172
# File 'lib/paco/parser.rb', line 168

def at_least(num)
  Paco::Combinators.seq(times(num), many) do |head, rest|
    head + rest
  end
end

#at_most(num) ⇒ Object

Returns a parser that runs ‘parser` at most `num` times, and returns an array of the results.



176
177
178
# File 'lib/paco/parser.rb', line 176

def at_most(num)
  times(0, num)
end

#bind(&block) ⇒ Paco::Parser Also known as: chain

Returns a new parser which tries ‘parser`, and on success calls the `block` with the result of the parse, which is expected to return another parser, which will be tried next. This allows you to dynamically decide how to continue the parse, which is impossible with the other Paco::Combinators.

Returns:



88
89
90
91
92
# File 'lib/paco/parser.rb', line 88

def bind(&block)
  Parser.new("#{desc}.bind") do |ctx|
    block.call(_parse(ctx))._parse(ctx)
  end
end

#failure(ctx) ⇒ Object

Raises ParseError

Parameters:

Raises:



40
41
42
43
# File 'lib/paco/parser.rb', line 40

def failure(ctx)
  ctx.failure_parse(self)
  raise ParseError.new(ctx, desc), "", []
end

#fallback(value) ⇒ Paco::Parser

Returns a new parser which tries ‘parser` and, if it fails, returns `value` without consuming any input.

Returns:



109
110
111
# File 'lib/paco/parser.rb', line 109

def fallback(value)
  self.or(Paco::Combinators.succeed(value))
end

#fmap(&block) ⇒ Paco::Parser

Transforms the output of ‘parser` with the given block.

Returns:



76
77
78
79
80
# File 'lib/paco/parser.rb', line 76

def fmap(&block)
  Parser.new("#{desc}.fmap") do |ctx|
    block.call(_parse(ctx))
  end
end

#join(separator = "") ⇒ Paco::Parser

Returns a parser that runs ‘parser` and concatenate it results with the `separator`.

Parameters:

  • separator (String) (defaults to: "")

Returns:



139
140
141
# File 'lib/paco/parser.rb', line 139

def join(separator = "")
  fmap { |result| result.join(separator) }
end

#manyPaco::Parser

Expects ‘parser` zero or more times, and returns an array of the results.

Returns:



97
98
99
# File 'lib/paco/parser.rb', line 97

def many
  Paco::Combinators.many(self)
end

#next(other) ⇒ Paco::Parser Also known as: >

Expects ‘other` parser to follow `parser`, but returns only the value of `other` parser.

Parameters:

  • other (Poco::Parser)

Returns:



68
69
70
71
# File 'lib/paco/parser.rb', line 68

def next(other)
  Paco::Combinators.seq(self, other).fmap { |results| results[1] }
    .with_desc("#{desc}.next(#{other.desc})")
end

#not_followed_by(other) ⇒ Paco::Parser

Returns a parser that runs passed ‘other` parser without consuming the input, and returns result of the `parser` if the passed one _does not match_ the input. Fails otherwise.

Parameters:

Returns:



132
133
134
# File 'lib/paco/parser.rb', line 132

def not_followed_by(other)
  skip(Paco::Combinators.not_followed_by(other))
end

#or(other) ⇒ Paco::Parser Also known as: |

Returns a new parser which tries ‘parser`, and if it fails uses `other`.

Parameters:

Returns:



48
49
50
51
52
53
54
# File 'lib/paco/parser.rb', line 48

def or(other)
  Parser.new("or(#{desc}, #{other.desc})") do |ctx|
    _parse(ctx)
  rescue ParseError
    other._parse(ctx)
  end
end

#parse(input, with_callstack: false) ⇒ Object

Parameters:

  • input (String, Paco::Context)
  • with_callstack (true, false) (defaults to: false)


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

def parse(input, with_callstack: false)
  ctx = input.is_a?(Context) ? input : Context.new(input, with_callstack: with_callstack)
  skip(Paco::Combinators.eof)._parse(ctx)
end

#result(value) ⇒ Paco::Parser

Returns a new parser with the same behavior, but which returns passed ‘value`.

Returns:



103
104
105
# File 'lib/paco/parser.rb', line 103

def result(value)
  fmap { value }
end

#skip(other) ⇒ Paco::Parser Also known as: <

Expects ‘other` parser to follow `parser`, but returns only the value of `parser`.

Parameters:

  • other (Poco::Parser)

Returns:



60
61
62
# File 'lib/paco/parser.rb', line 60

def skip(other)
  Paco::Combinators.seq(self, other).fmap { |results| results[0] }.with_desc("#{desc}.skip(#{other.desc})")
end

#times(min, max = nil) ⇒ Paco::Parser

Returns a parser that runs ‘parser` between `min` and `max` times, and returns an array of the results. When `max` is not specified, `max` = `min`.

Parameters:

  • min (Integer)
  • max (Integer) (defaults to: nil)

Returns:



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/paco/parser.rb', line 148

def times(min, max = nil)
  max ||= min
  if min < 0 || max < min
    raise ArgumentError, "invalid attributes: min `#{min}`, max `#{max}`"
  end

  Parser.new("#{desc}.times(#{min}, #{max})") do |ctx|
    results = min.times.map { _parse(ctx) }
    (max - min).times.each do
      results << _parse(ctx)
    rescue ParseError
      break
    end

    results
  end
end

#trim(other) ⇒ Paco::Parser

Expects ‘other` parser before and after `parser`, and returns the result of the parser.

Parameters:

Returns:



116
117
118
# File 'lib/paco/parser.rb', line 116

def trim(other)
  other.next(self).skip(other)
end

#with_desc(desc) ⇒ Paco::Parser

Parameters:

  • desc (String)

Returns:



17
18
19
20
# File 'lib/paco/parser.rb', line 17

def with_desc(desc)
  @desc = desc
  self
end

#wrap(before, after) ⇒ Paco::Parser

Expects the parser ‘before` before `parser` and `after` after `parser. Returns the result of the parser.

Parameters:

Returns:



124
125
126
# File 'lib/paco/parser.rb', line 124

def wrap(before, after)
  Paco::Combinators.wrap(before, after, self)
end