class TestML::Compiler::Lite

Constants

ANY
COMMA
COMP
DOT
DSTR
ENDING
EQ
HASH
LP
NUM
OPER
POINT
PUNCT
QSTR
RP
SEMI
SSTR
STAR
TILDE
TOKENS
WORD
WS

Attributes

function[RW]
input[RW]
points[RW]
tokens[RW]

Public Instance Methods

compile_code() click to toggle source
# File lib/testml/compiler/lite.rb, line 36
def compile_code
  @function = TestML::Function.new
  while not @code.empty? do
    @code.sub! /^(.*)(\r\n|\n|)/, ''
    @line = $1
    tokenize
    next if done
    parse_assignment ||
    parse_assertion ||
    fail_()
  end
end
compile_data() click to toggle source
# File lib/testml/compiler/lite.rb, line 139
def compile_data
  input = @data
  input.gsub! /^#.*\n/, "\n"
  input.gsub! /^\\/, ''
  blocks = input.split(/(^===.*?(?=^===|\z))/m).select{|el|!el.empty?}
  blocks.each{|block| block.sub! /\n+\z/, "\n"}

  data = []
  blocks.each do |string_block|
    block = TestML::Block.new
    string_block.gsub! /\A===\ +(.*?)\ *\n/, '' or
      fail "No block label! #{string_block}"
    block.label = $1
    while !string_block.empty? do
      next if string_block.sub! /\A\n+/, ''
      key, value = nil, nil
      if string_block.gsub!(/\A---\ +(\w+):\ +(.*)\n/, '') or
         string_block.gsub!(/\A---\ +(\w+)\n(.*?)(?=^---|\z)/m, '')
        key, value = $1, $2
      else
        fail "Failed to parse TestML string:\n#{string_block}"
      end
      block.points ||= {}
      block.points[key] = value

      if key =~ /^(ONLY|SKIP|LAST)$/
        block.points[key] = true
      end
    end
    data.push block
  end
  @function.data = data unless data.empty?
end
done() click to toggle source
# File lib/testml/compiler/lite.rb, line 173
def done
  tokens.empty?
end
fail_(message=nil) click to toggle source
# File lib/testml/compiler/lite.rb, line 188
def fail_(message=nil)
  text = "Failed to compile TestML document.\n"
  text << "Reason: #{message}\n" if message
  text << "\nCode section of failure:\n#{@line}\n#{@code}\n"
  fail text
end
parse_args() click to toggle source
# File lib/testml/compiler/lite.rb, line 128
def parse_args
  pop == '(' or fail
  args = []
  while peek != ')' do
    args.push parse_expression
    pop if peek == ','
  end
  pop
  return args
end
parse_assertion() click to toggle source
# File lib/testml/compiler/lite.rb, line 72
def parse_assertion
  return unless @tokens.grep /^#{COMP}$/
  @points = []
  left = parse_expression
  token = pop
  op =
    token == '==' ? 'EQ' :
    token == '~~' ? 'HAS' :
    fail_
  right = parse_expression
  pop if !done and peek == ';'
  fail_ unless done

  @function.statements.push TestML::Statement.new(
    left,
    TestML::Assertion.new(
      op,
      right,
    ),
    points.empty? ? nil : points
  )
  return true
end
parse_assignment() click to toggle source
# File lib/testml/compiler/lite.rb, line 62
def parse_assignment
  return unless peek(2) == '='
  var, op = pop(2)
  expr = parse_expression
  pop if !done and peek == ';'
  fail_() unless done
  @function.statements.push TestML::Assignment.new(var, expr)
  return true
end
parse_expression() click to toggle source
# File lib/testml/compiler/lite.rb, line 96
def parse_expression
  calls = []
  while !done and peek !~ /^(#{ENDING}|#{COMP})$/ do
    token = pop
    if token =~ /^#{NUM}$/
      calls.push TestML::Num.new(token.to_i)
    elsif token =~ /^#{QSTR}$/
      str = token[1..-2]
      calls.push TestML::Str.new(str)
    elsif token =~ /^#{WORD}$/
      call = TestML::Call.new(token)
      if !done and peek == '('
        call.args = parse_args
      end
      calls.push call
    elsif token =~ /^#{POINT}$/
      token =~ /(#{WORD})/ or fail
      points.push $1
      calls.push TestML::Point.new($1)
    else
      fail_("Unknown token '#{token}'")
    end
    if !done and peek == '.'
      pop
    end
  end

  return calls.size == 1 \
    ? calls[0]
    : TestML::Expression.new(calls)
end
peek(index=1) click to toggle source
# File lib/testml/compiler/lite.rb, line 177
def peek(index=1)
  fail if index > @tokens.size
  @tokens[index - 1]
end
pop(count=1) click to toggle source
# File lib/testml/compiler/lite.rb, line 182
def pop(count=1)
  fail if count > @tokens.size
  array = @tokens.slice! 0..(count-1)
  count > 1 ? array : array[0]
end
tokenize() click to toggle source
# File lib/testml/compiler/lite.rb, line 49
def tokenize
  @tokens = []
  while not @line.empty? do
    next if @line.sub!(/^#{WS}/, '')
    next if @line.sub!(/^#{HASH}#{ANY}*/, '')
    if @line.sub!(/^(#{TOKENS})/, '')
      @tokens.push $1
    else
      fail_("Failed to get token here: '#{@line}'")
    end
  end
end