Parent

Included Modules

RText::Parser

Constants

AnyValue
Problem

Public Class Methods

new(reference_regexp) click to toggle source
# File lib/rtext/parser.rb, line 11
def initialize(reference_regexp)
  @reference_regexp = reference_regexp
end

Public Instance Methods

consume(*args) click to toggle source
# File lib/rtext/parser.rb, line 209
def consume(*args)
  t = @tokens.first
  if t.nil?
    @non_consume_count += 1
    report_consume_problem("Unexpected end of file, expected #{args.join(", ")}", @last_line)
    return nil
  end
  if args.include?(t.kind)
    @tokens.shift
    @consume_problem_reported = false
    @non_consume_count = 0
    puts "consuming #{t.kind} #{t.value}" if @debug
    t
  else
    if t.kind == :error
      @tokens.shift
      @non_consume_count = 0
      report_consume_problem("Parse error on token '#{t.value}'", t.line)
      return nil
    else
      value = " '#{t.value}'" if t.value
      @non_consume_count += 1
      report_consume_problem("Unexpected #{t.kind}#{value}, expected #{args.join(", ")}", t.line)
      return nil
    end
  end
end
discard_until(kind) click to toggle source
# File lib/rtext/parser.rb, line 197
def discard_until(kind)
  t = @tokens.shift
  if t
    puts "discarding #{t.kind} #{t.value}" if @debug
    while t.kind != kind
      t = @tokens.shift
      break unless t
      puts "discarding #{t.kind} #{t.value}" if @debug
    end
  end
end
next_token() click to toggle source
# File lib/rtext/parser.rb, line 193
def next_token
  @tokens.first && @tokens.first.kind
end
parse(str, options) click to toggle source
# File lib/rtext/parser.rb, line 15
def parse(str, options)
  @dsc_visitor = options[:descent_visitor]
  @asc_visitor = options[:ascent_visitor]
  @problems = options[:problems] || []
  @non_consume_count = 0
  @consume_problem_reported = false
  @tokens = tokenize(str, @reference_regexp, :on_command_token => options[:on_command_token])
  @last_line = @tokens.last && @tokens.last.line 
  #@debug = true
  begin
    while next_token
      statement = parse_statement(true, true)
    end
  rescue InternalError
  end
end
parse_annotation() click to toggle source
# File lib/rtext/parser.rb, line 79
def parse_annotation
  result = nil
  while next_token == :annotation
    result ||= []
    result << consume(:annotation)
    consume(:newline)
  end
  result
end
parse_argument(arg_list) click to toggle source
# File lib/rtext/parser.rb, line 157
def parse_argument(arg_list)
  if next_token == :label
    label = consume(:label)
    arg_list << [label, parse_argument_value]
  else
    arg_list << parse_argument_value
  end
end
parse_argument_list(arg_list) click to toggle source
# File lib/rtext/parser.rb, line 148
def parse_argument_list(arg_list)
  first = true
  while (AnyValue + [",", "[", :label, :error]).include?(next_token)
    consume(",") unless first
    first = false
    parse_argument(arg_list)
  end
end
parse_argument_value() click to toggle source
# File lib/rtext/parser.rb, line 166
def parse_argument_value
  if next_token == "["
    parse_argument_value_list
  else
    parse_value
  end
end
parse_argument_value_list() click to toggle source
# File lib/rtext/parser.rb, line 174
def parse_argument_value_list
  consume("[")
  first = true
  result = []
  while (AnyValue + [",", :error]).include?(next_token)
    consume(",") unless first
    first = false
    result << parse_value
  end
  consume("]")
  result
end
parse_block_element(element_list, comments) click to toggle source
# File lib/rtext/parser.rb, line 108
def parse_block_element(element_list, comments)
  if next_token == :label
    label = consume(:label)
    element_list << [label, parse_labeled_block_element(comments)]
  else
    statement = parse_statement(false, true)
    element_list << statement if statement 
  end
end
parse_comment() click to toggle source
# File lib/rtext/parser.rb, line 69
def parse_comment
  result = nil 
  while next_token == :comment
    result ||= []
    result << consume(:comment)
    consume(:newline)
  end
  result
end
parse_element_list(comments) click to toggle source
# File lib/rtext/parser.rb, line 130
def parse_element_list(comments)
  consume("[")
  eol_comment = parse_eol_comment
  comments << [ eol_comment, :eol ] if eol_comment
  nl = consume(:newline)
  discard_until(:newline) unless nl
  result = []
  while next_token && next_token != "]"
    statement = parse_statement(false, true)
    result << statement if statement 
  end
  consume("]")
  eol_comment = parse_eol_comment
  comments << [ eol_comment, :eol ] if eol_comment
  consume(:newline)
  result
end
parse_eol_comment() click to toggle source
# File lib/rtext/parser.rb, line 89
def parse_eol_comment
  if next_token == :comment
    consume(:comment)
  else
    nil
  end
end
parse_labeled_block_element(comments) click to toggle source
# File lib/rtext/parser.rb, line 118
def parse_labeled_block_element(comments)
  if next_token == "["
    parse_element_list(comments)
  else
    eol_comment = parse_eol_comment
    comments << [ eol_comment, :eol ] if eol_comment
    nl = consume(:newline)
    discard_until(:newline) unless nl
    parse_statement
  end
end
parse_statement(is_root=false, allow_unassociated_comment=false) click to toggle source

parse a statement with optional leading comment or an unassociated comment

# File lib/rtext/parser.rb, line 33
def parse_statement(is_root=false, allow_unassociated_comment=false)
  comments = [] 
  comment = parse_comment 
  annotation = parse_annotation
  if (next_token && next_token == :identifier) || !allow_unassociated_comment
    comments << [ comment, :above] if comment
    command = consume(:identifier)
    if command
      @dsc_visitor.call(command)
      arg_list = []
      parse_argument_list(arg_list)
      element_list = []
      if next_token == "{"
        parse_statement_block(element_list, comments)
      end
      eol_comment = parse_eol_comment
      comments << [ eol_comment, :eol ] if eol_comment
      consume(:newline)
      @asc_visitor.call(command, arg_list, element_list, comments, annotation, is_root)
    else
      discard_until(:newline)
      nil
    end
  elsif comment
    # if there is no statement, the comment is non-optional
    comments << [ comment, :unassociated ]
    @asc_visitor.call(nil, nil, nil, comments, nil, nil)
    nil
  else
    # die expecting an identifier (next token is not an identifier)
    consume(:identifier)
    discard_until(:newline)
    nil
  end
end
parse_statement_block(element_list, comments) click to toggle source
# File lib/rtext/parser.rb, line 97
def parse_statement_block(element_list, comments)
  consume("{")
  eol_comment = parse_eol_comment
  comments << [ eol_comment, :eol ] if eol_comment
  consume(:newline)
  while next_token && next_token != "}"
    parse_block_element(element_list, comments)
  end
  consume("}")
end
parse_value() click to toggle source
# File lib/rtext/parser.rb, line 189
def parse_value
  consume(*AnyValue)
end
report_consume_problem(message, line) click to toggle source
# File lib/rtext/parser.rb, line 240
def report_consume_problem(message, line)
  problem = Problem.new(message, line)
  if @non_consume_count > 100
    # safety check, stop reoccuring problems to avoid endless loops
    @problems << Problem.new("Internal error", line) 
    puts [@problems.last.message, @problems.last.line].inspect if @debug
    raise InternalError.new
  else
    if !@consume_problem_reported
      @consume_problem_reported = true
      @problems << problem 
      puts [@problems.last.message, @problems.last.line].inspect if @debug
    end
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.