class Parse

Attributes

most_probable_error[R]

@return [Error, nil]

rule_start_pos[R]

See {Parse::rule}.

@return [Position]

Protected Class Methods

rule(name, &body) click to toggle source

defines method name with body body. Inside body {#rule_start_pos} is the value of {#pos} right before the defined method's call.

@param [Symbol] name @return [void]

# File lib/parse.rb, line 188
def self.rule(name, &body)
  define_method(name) do
    old_rule_start_pos = @rule_start_pos
    @rule_start_pos = pos
    begin
      if $DEBUG then STDERR.puts("#{pos.file}:#{pos.line+1}:#{pos.column+1}: entering rule :#{name}"); end
      r = instance_eval(&body)
      if $DEBUG then t = if r.nil? then "(with nil)" else "(with #{r.class.to_s})" end; STDERR.puts("#{pos.file}:#{pos.line+1}:#{pos.column+1}: exiting rule :#{name} #{t}"); end
      r
    ensure
      @rule_start_pos = old_rule_start_pos
    end
  end
end
token(name, *args, &body) click to toggle source

@overload token(name, [description], string | regexp | &body)

A shorthand for:

rule name do
  expect(description) {
    no_errors {
      r = (scan(string) | scan(regexp) | body) and
      whitespace_and_comments and
      r
    }
  }
end

Method whitespace_and_comments must be defined!

description defaults to "`#{string}'", %(regexp "#{regexp}") or "#{name}" (in that order, depending on what is defined).

@return [void]

# File lib/parse.rb, line 237
def self.token(name, *args, &body)
  pattern, body =
    if body.nil? then
      pattern = args.pop
      [pattern, proc { scan(pattern) }]
    else
      [nil, body]
    end
  description =
    args.pop ||
    case pattern
    when nil then "#{name}"
    when String then "`#{pattern}'"
    when Regexp then %(regexp "#{pattern.source}")
    end
  raise ArgumentError, "wrong number of arguments" unless args.empty?
  rule name do
    expect(description) {
      no_errors {
        r = instance_eval(&body) and whitespace_and_comments and r
      }
    }
  end
end

Public Instance Methods

call(text, file = "-") click to toggle source

parses text.

@param [String] text @param [String] file file the text is taken from. @raise [Parse::Error, IOError] @return [Object] what {#start} returns (non-nil).

# File lib/parse.rb, line 29
def call(text, file = "-")
  @text = StringScanner.new(text)
  @file = file
  @most_probable_error = nil
  @allow_errors = true
  @rule_start_pos = nil
  r = start()
  if r.nil? or not @text.eos? then
    if @most_probable_error
    then raise @most_probable_error
    else raise Error.new(StringScannerPosition.new(@text.pos, @text, @file), "syntax error")
    end
  end
  return r
end

Protected Instance Methods

_(arg = nil, &block) click to toggle source

alias for {#_1} and {#_2}

# File lib/parse.rb, line 171
def _(arg = nil, &block)
  if arg
  then _1(arg)
  else _2(&block)
  end
end
_1(node) click to toggle source

@param [ASTNode] node @return [ASTNode] node which is

{ASTNode#initialize_pos}({#rule_start_pos})-ed.
# File lib/parse.rb, line 212
def _1(node)
  node.initialize_pos(rule_start_pos)
end
_2(&f) click to toggle source

calls f. If f results in nil then it restores {#pos} to the value before the call.

@return what f returns.

# File lib/parse.rb, line 309
def _2(&f)
  old_text_pos = @text.pos
  f.() or begin
    @text.pos = old_text_pos
    nil
  end
end
act(&f) click to toggle source

calls f and returns true.

@return [true]

# File lib/parse.rb, line 298
def act(&f)
  f.()
  true
end
begin?() click to toggle source

is {#pos} at the beginning of the text?

# File lib/parse.rb, line 283
def begin?
  @text.pos == 0
end
end?() click to toggle source

is {#pos} at the end of the text?

# File lib/parse.rb, line 276
def end?
  @text.eos?
end
Also aliased as: eos?
eos?()
Alias for: end?
error(error) click to toggle source

sets {#most_probable_error} to error if it is more probable than {#most_probable_error} or if {#most_probable_error} is nil.

@param [Error] error @return [nil]

# File lib/parse.rb, line 400
def error(error)
  if @allow_errors then
    if @most_probable_error.nil? or @most_probable_error.pos < error.pos then
      @most_probable_error = error
    elsif @most_probable_error and @most_probable_error.pos == error.pos then
      @most_probable_error = @most_probable_error.or error
    else
      # do nothing
    end
  end
  return nil
end
expect(what_1, *what_2_n, &body) click to toggle source

macro

# File lib/parse.rb, line 419
def expect(what_1, *what_2_n, &body)
  p = pos and body.() or expected(p, what_1, *what_2_n)
end
expected(pos, what_1, *what_2_n) click to toggle source

macro

# File lib/parse.rb, line 414
def expected(pos, what_1, *what_2_n)
  error(Expected.new(pos, what_1, *what_2_n))
end
many(&f) click to toggle source

calls f using {#_2} many times until it returns nil.

@return [Array] an {Array} of non-nil results of f.

# File lib/parse.rb, line 321
def many(&f)
  r = []
  while true
    f0 = _(&f)
    if f0
    then r.push(f0)
    else break
    end
  end
  r
end
many1(&f)
Alias for: one_or_more
no_errors(&block) click to toggle source

calls block. Inside the block {#error} has no effect.

@return what block returns.

# File lib/parse.rb, line 427
def no_errors(&block)
  old_allow_errors = @allow_errors
  begin
    @allow_errors = false
    block.()
  ensure
    @allow_errors = old_allow_errors
  end
end
not_follows(*method_ids, &f) click to toggle source

@overload not_follows(*method_ids)

calls methods specified by +method_ids+. If any of them returns non-nil
then this method returns nil, otherwise it returns true. The methods
are called inside {#no_errors}. {#pos} is restored after each method's
call.

@param [Array<Symbol>] method_ids
@return [true, nil]

@overload not_follows(&f)

calls +f+. If +f+ returns non-nil then this method returns nil,
otherwise it returns true. +f+ is called inside {#no_errors}.
{#pos} is restored after +f+'s call.

@return [true, nil]
# File lib/parse.rb, line 371
def not_follows(*method_ids, &f)
  if f then
    if no_errors { _{ f.() } }
    then nil
    else true
    end
  else # if not method_ids.empty? then
    if no_errors { method_ids.any? { |method_id| _{ __send__(method_id) } } }
    then nil
    else true
    end
  end
end
one_or_more(&f) click to toggle source

The same as f.() and many(&f).

@return [Array, nil] an {Array} of results of f or nil if the first call

to +f+ returned nil.
# File lib/parse.rb, line 347
def one_or_more(&f)
  f1 = f.() and f2_n = many(&f) and [f1, *f2_n]
end
Also aliased as: many1
opt(&f) click to toggle source

calls f using {#_2}.

@return [Array] an empty {Array} if f results in nil and an {Array}

containing the single result of +f+ otherwise.
# File lib/parse.rb, line 338
def opt(&f)
  [_(&f)].compact
end
pos() click to toggle source

@return [Position] current {Position} in text passed to {#call}.

# File lib/parse.rb, line 271
def pos
  StringScannerPosition.new(@text.pos, @text, @file)
end
scan(arg) click to toggle source

scans arg in text passed to {#call} starting from {#pos} and, if scanned successfully, advances {#pos} and returns the scanned sub-{String}. Otherwise it calls {#expected} and returns nil.

@param [String, Regexp] arg @return [String, nil]

# File lib/parse.rb, line 163
def scan(arg)
  case arg
  when Regexp then @text.scan(arg) or expected(pos, %(regexp "#{arg.source}"))
  when String then @text.scan(Regexp.new(Regexp.escape(arg))) or expected(pos, %("#{arg}"))
  end
end