class ReVIEW::Preprocessor

Constants

INF_INDENT
KNOWN_DIRECTIVES
TYPES

Public Class Methods

new(repo, param) click to toggle source
# File lib/review/preprocessor.rb, line 93
def initialize(repo, param)
  @repository = repo
  @config = param
end
strip(f) click to toggle source
# File lib/review/preprocessor.rb, line 54
def Preprocessor.strip(f)
  buf = ''
  Strip.new(f).each do |line|
    buf << line.rstrip << "\n"
  end
  buf
end

Public Instance Methods

process(inf, outf) click to toggle source
# File lib/review/preprocessor.rb, line 98
def process(inf, outf)
  init_ErrorUtils inf
  @f = outf
  begin
    preproc inf
  rescue Errno::ENOENT => err
    error err.message
  end
end

Private Instance Methods

defvar(name, value) click to toggle source
# File lib/review/preprocessor.rb, line 275
def defvar(name, value)
  @vartable[name] = value
end
evaluate(path, chunk) click to toggle source
# File lib/review/preprocessor.rb, line 299
def evaluate(path, chunk)
  outputs = get_output("ruby #{path}", false).split(/\n/).map {|s| s.strip }
  chunk.map {|line|
    if /\# \$\d+/ =~ line.string
      # map result into source.
      line.edit {|s|
        s.sub(/\$(\d+)/) { outputs[$1.to_i - 1] }
      }
    else
      line
    end
  }
end
expand(str) click to toggle source
# File lib/review/preprocessor.rb, line 279
def expand(str)
  str.gsub(/\$\w+/) {|name|
    s = @vartable[name.sub('$', '')]
    s ? expand(s) : name
  }
end
get_output(cmd, use_stderr) click to toggle source
# File lib/review/preprocessor.rb, line 315
def get_output(cmd, use_stderr)
  out = err = nil
  Open3.popen3(cmd) {|stdin, stdout, stderr|
    out = stdout.readlines
    if use_stderr
      out.concat stderr.readlines
    else
      err = stderr.readlines
    end
  }
  if err and !err.empty?
    $stderr.puts "[unexpected stderr message]"
    err.each do |line|
      $stderr.print line
    end
    error "get_output: got unexpected output"
  end
  num = 0
  out.map {|line| Line.new(num += 1, line) }
end
init_vars() click to toggle source
# File lib/review/preprocessor.rb, line 271
def init_vars
  @vartable = {}
end
known_directive?(op) click to toggle source
# File lib/review/preprocessor.rb, line 166
def known_directive?(op)
  KNOWN_DIRECTIVES.index(op)
end
minimum_indent(chunk) click to toggle source
# File lib/review/preprocessor.rb, line 294
def minimum_indent(chunk)
  n = chunk.map {|line| line.empty? ? INF_INDENT : line.num_indent }.min
  n == INF_INDENT ? 0 : n
end
optarg_value(spec) click to toggle source
# File lib/review/preprocessor.rb, line 259
def optarg_value(spec)
  case spec
  when 'true' then true # [name=true]
  when 'false' then false # [name=false]
  when 'nil' then nil # [name=nil]
  when nil then true # [name]
  when /^\d+$/ then $&.to_i # [name=8]
  else # [name=val]
    spec
  end
end
parse_directive(line, argc, *optdecl) click to toggle source
# File lib/review/preprocessor.rb, line 228
def parse_directive(line, argc, *optdecl)
  m = /\A\#@(\w+)\((.*?)\)(?:\[(.*?)\])?\z/.match(line.strip) or
          error "wrong directive: #{line.strip}"
  op = m[1]
  args = m[2].split(/,\s*/)
  opts = parse_optargs(m[3])
  return if argc == 0 and args.empty?
  if argc == -1
    # Any number of arguments are allowed.
  elsif args.size != argc
    error "wrong arg size"
  end
  if opts
    wrong_opts = opts.keys - optdecl
    unless wrong_opts.empty?
      error "wrong option: #{wrong_opts.keys.join(' ')}"
    end
  end
  Directive.new(op, args, opts || {})
end
parse_optargs(str) click to toggle source
# File lib/review/preprocessor.rb, line 249
def parse_optargs(str)
  return nil unless str
  table = {}
  str.split(/,\s*/).each do |a|
    name, spec = a.split(/=/, 2)
    table[name] = optarg_value(spec)
  end
  table
end
preproc(f) click to toggle source
# File lib/review/preprocessor.rb, line 112
def preproc(f)
  init_vars
  while line = f.gets
    case line
    when /\A\#@\#/, /\A\#\#\#\#/
      @f.print line

    when /\A\#@defvar/
      @f.print line
      direc = parse_directive(line, 2)
      defvar(*direc.args)

    when /\A\#@mapoutput/
      direc = parse_directive(line, 1, 'stderr')
      @f.print line
      get_output(expand(direc.arg), direc['stderr']).each do |out|
        @f.print out.string
      end
      skip_list f

    when /\A\#@mapfile/
      direc = parse_directive(line, 1, 'eval')
      path = expand(direc.arg)
      ent = @repository.fetch_file(path)
      ent = evaluate(path, ent) if direc['eval']
      replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp

    when /\A\#@map(?:range)?/
      direc = parse_directive(line, 2, 'unindent')
      path = expand(direc.args[0])
      ent = @repository.fetch_range(path, direc.args[1]) or
              error "unknown range: #{path}: #{direc.args[1]}"
      ent = (direc['unindent'] ? unindent(ent, direc['unindent']) : ent)
      replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp

    when /\A\#@end/
      error 'unbaranced #@end'

    when /\A\#@/
      op = line.slice(/@(\w+)/, 1)
      #error "unkown directive: #{line.strip}" unless known_directive?(op)
      warn "unkown directive: #{line.strip}" unless known_directive?(op)
      @f.print line

    when /\A\s*\z/ # empty line
      @f.puts
    else
      @f.print line
    end
  end
end
print_number(num) click to toggle source
replace_block(f, directive_line, newlines, with_lineno) click to toggle source
# File lib/review/preprocessor.rb, line 170
def replace_block(f, directive_line, newlines, with_lineno)
  @f.print directive_line
  newlines.each do |line|
    print_number line.number if with_lineno
    @f.print line.string
  end
  skip_list f
end
skip_list(f) click to toggle source
# File lib/review/preprocessor.rb, line 183
def skip_list(f)
  begline = f.lineno
  while line = f.gets
    case line
    when %r[\A\#@end]
      @f.print line
      return
    when %r[\A//\}]
      warn '//} seen in list'
      @f.print line
      return
    when %r[\A\#@\w]
      warn "#{line.slice(/\A\#@\w+/)} seen in list"
      @f.print line
    when %r[\A\#@]
      @f.print line
    end
  end
  error "list reached end of file (beginning line = #{begline})"
end
unindent(chunk, n) click to toggle source
# File lib/review/preprocessor.rb, line 286
def unindent(chunk, n)
  n = minimum_indent(chunk) unless n.kind_of?(Integer)
  re = /\A#{' ' * n}/
  chunk.map {|line| line.edit {|s| s.sub(re,'') } }
end