class Take::Unit::Scanner

Attributes

tokens[R]

Public Class Methods

new(input) click to toggle source
# File lib/take/unit/scanner.rb, line 9
def initialize(input)
  @input = "\n" << input
  @scanner = StringScanner.new(input)
end

Public Instance Methods

scan() click to toggle source
# File lib/take/unit/scanner.rb, line 14
def scan
  @tokens ||= begin
    @tokens = []
    until @scanner.eos?
      scan_group_body { error! }
    end
    @tokens
  end
end
scan_body() click to toggle source
# File lib/take/unit/scanner.rb, line 64
def scan_body
  if @scanner.check(/\s*\{/)
    emit :block, _scan_block
  end
end
scan_group(scan = /macro|test|before|after|prefix/) click to toggle source
# File lib/take/unit/scanner.rb, line 50
def scan_group(scan = /macro|test|before|after|prefix/)
  if @scanner.scan(scan)
    group_type = @scanner[0]
    @scanner.scan(/ ([A-Za-z0-9_.-]+)\(/) or error!
    group_name = @scanner[1]

    @scanner.scan(/\s*\;/)

    emit group_type.intern,
         group_name,
         _scan_arguments(/\s*\)/, /,\s+/)
  end
end
scan_group_body() { || ... } click to toggle source
# File lib/take/unit/scanner.rb, line 24
def scan_group_body
  pre_scan
  scan_nested or
  scan_group or
  scan_body or
  scan_whitespace or
  yield
end
scan_nested() click to toggle source
# File lib/take/unit/scanner.rb, line 33
def scan_nested
  if scan_group(/group/)
    scan_whitespace
    @scanner.scan(/\{/) or error!
    loop do
      scan_group_body do
        if @scanner.scan(/\}/)
          pre_scan
          return emit(:group_end)
        else
          error!
        end
      end
    end
  end
end
scan_whitespace(newlines = true) click to toggle source
# File lib/take/unit/scanner.rb, line 70
def scan_whitespace(newlines = true)
  if newlines
    @scanner.scan(/\s+/)
  else
    @scanner.scan(/[ \t]+/)
  end
end

Private Instance Methods

_scan_arguments(ending, seperator) click to toggle source
# File lib/take/unit/scanner.rb, line 132
def _scan_arguments(ending, seperator)
  arguments = []
  until @scanner.scan(ending)
    @scanner.scan(/(&?[A-Za-z0-9_-]+)/)
    arguments << @scanner[1]
    @scanner.scan(seperator) or @scanner.check(ending) or error!
  end

  arguments
end
_scan_block() click to toggle source
# File lib/take/unit/scanner.rb, line 98
def _scan_block
  brack = 1
  body = @scanner.scan(/\s*\{/)
  scan_for = %r{
    (
      (?: " ( \\\\ | \\" | [^"] )* "? )
    | (?: ' ( \\\\ | \\' | [^'] )* '? )
    | (?: // .*? \n )
    | (?: \# .*? \n )
    | (?: /\* [\s\S]+? \*/ )
    | (?: \} )
    | (?: \{ )
    )
  }x

  until brack.zero?
    if part = @scanner.scan_until(scan_for)
      body << part


      if @scanner[1] == "}"
        brack -= 1
      elsif @scanner[1] == "{"
        brack += 1
      end
    else
      @scanner.scan(/(.+)/m)
      error!
    end
  end

  body.gsub(/\A\n*/, "").gsub(/\A\s*\{([\s\S]*)\}\z/, "\\1")
end
column() click to toggle source
# File lib/take/unit/scanner.rb, line 88
def column
  last_newline = @input[0..@pos].rindex("\n") || 0
  @pos - last_newline
end
emit(*args) click to toggle source
# File lib/take/unit/scanner.rb, line 93
def emit(*args)
  @tokens << args.concat([line, column])
  true
end
error!() click to toggle source
# File lib/take/unit/scanner.rb, line 143
def error!
  p @tokens
  raise SyntaxError, "Unexpected `#{@scanner.check(/./)}' on line #{line} (column #{column})"
end
line() click to toggle source
# File lib/take/unit/scanner.rb, line 84
def line
  @input[0..@pos].count("\n")
end
pre_scan() click to toggle source
# File lib/take/unit/scanner.rb, line 80
def pre_scan
  @pos = @scanner.pos
end