类 Object

常量

SCRIPT_LINES__

当一个 Hash 被赋值给 SCRIPT_LINES__ 时,在赋值之后加载的文件内容将被添加为一个包含文件名的键和行数组。

公共类方法

const_missing(name) 点击切换源代码
# File ripper/tools/dsl.rb, line 87
def self.const_missing(name)
  name
end

公共实例方法

add_event(event, args, qundef_check = false) 点击切换源代码
# File ripper/tools/dsl.rb, line 62
def add_event(event, args, qundef_check = false)
  event = event.to_s.sub(/!\z/, "")
  @events[event] = args.size
  vars = []
  args.each do |arg|
    vars << v = new_var
    @code << "#{ v }=#{ arg };"
  end
  v = new_var
  d = "dispatch#{ args.size }(#{ [event, *vars].join(",") })"
  d = "#{ vars.last }==Qundef ? #{ vars.first } : #{ d }" if qundef_check
  @code << "#{ v }=#{ d };"
  v
end
check_arity(h) 点击切换源代码
# File ripper/tools/generate.rb, line 151
def check_arity(h)
  invalid = false
  h.each do |event, list|
    unless list.map {|line, arity| arity }.uniq.size == 1
      invalid = true
      locations = list.map {|line, a| "#{line}:#{a}" }.join(', ')
      $stderr.puts "arity crash [event=#{event}]: #{locations}"
    end
  end
  abort if invalid
end
generate_eventids1(ids) 点击切换源代码
# File ripper/tools/generate.rb, line 94
def generate_eventids1(ids)
  buf = "".dup
  buf << %Q[#include "ruby/ruby.h"\n]
  buf << %Q[#include "eventids1.h"\n]
  buf << %Q[\n]
  buf << %Q[struct ripper_parser_ids ripper_parser_ids;\n]
  buf << %Q[\n]
  buf << %Q[void\n]
  buf << %Q[ripper_init_eventids1(void)\n]
  buf << %Q[{\n]
  buf << %Q[#define set_id1(name) ripper_id_##name = rb_intern_const("on_"#name)\n]
  ids.each do |id, arity|
    buf << %Q[    set_id1(#{id});\n]
  end
  buf << %Q[}\n]
  buf << %Q[\n]
  buf << %Q[#define intern_sym(name) ID2SYM(rb_intern_const(name))\n]
  buf << %Q[\n]
  buf << %Q[void\n]
  buf << %Q[ripper_init_eventids1_table(VALUE self)\n]
  buf << %Q[{\n]
  buf << %Q[    VALUE h = rb_hash_new();\n]
  buf << %Q[    rb_define_const(self, "PARSER_EVENT_TABLE", h);\n]
  ids.each do |id, arity|
    buf << %Q[    rb_hash_aset(h, intern_sym("#{id}"), INT2FIX(#{arity}));\n]
  end
  buf << %Q[}\n]
  buf
end
generate_eventids1_h(ids) 点击切换源代码
# File ripper/tools/generate.rb, line 73
def generate_eventids1_h(ids)
  buf = "".dup
  buf << %Q[#ifndef RIPPER_EVENTIDS1\n]
  buf << %Q[#define RIPPER_EVENTIDS1\n]
  buf << %Q[\n]
  buf << %Q[void ripper_init_eventids1(void);\n]
  buf << %Q[void ripper_init_eventids1_table(VALUE self);\n]
  buf << %Q[\n]
  buf << %Q[struct ripper_parser_ids {\n]
  ids.each do |id, arity|
    buf << %Q[    ID id_#{id};\n]
  end
  buf << %Q[};\n]
  buf << %Q[\n]
  ids.each do |id, arity|
    buf << %Q[#define ripper_id_#{id} ripper_parser_ids.id_#{id}\n]
  end
  buf << %Q[#endif /* RIPPER_EVENTIDS1 */\n]
  buf << %Q[\n]
end
generate_eventids2_table(ids) 点击切换源代码
# File ripper/tools/generate.rb, line 124
def generate_eventids2_table(ids)
  buf = "".dup
  buf << %Q[#include "ruby/ruby.h"\n]
  buf << %Q[\n]
  buf << %Q[#define intern_sym(name) ID2SYM(rb_intern_const(name))\n]
  buf << %Q[\n]
  buf << %Q[void\n]
  buf << %Q[ripper_init_eventids2_table(VALUE self)\n]
  buf << %Q[{\n]
  buf << %Q[    VALUE h = rb_hash_new();\n]
  buf << %Q[    rb_define_const(self, "SCANNER_EVENT_TABLE", h);\n]
  ids.each do |id|
    buf << %Q[    rb_hash_aset(h, intern_sym("#{id}"), INT2FIX(1));\n]
  end
  buf << %Q[}\n]
  buf
end
grammar(f, out) 点击切换源代码
# File ripper/tools/preproc.rb, line 89
def grammar(f, out)
  while line = f.gets
    case line
    when %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
      out << DSL.new($2, ($1 || "").split(",")).generate << "\n"
    when %r</\*%%%\*/>
      out << "#if 0\n"
    when %r</\*%>
      out << "#endif\n"
    when %r<%\*/>
      out << "\n"
    when /\A%%/
      out << "%%\n"
      return
    else
      out << line
    end
  end
end
main() 点击切换源代码
# File ripper/tools/generate.rb, line 6
def main
  mode = nil
  ids1src = nil
  ids2src = nil
  output = nil

  parser = @parser = OptionParser.new
  parser.banner = "Usage: #{File.basename($0)} --mode=MODE [--ids1src=PATH] [--ids2src=PATH] [--output=PATH]"
  parser.on('--mode=MODE', 'check, eventids1_h, eventids1, or eventids2table.') {|m|
    mode = m
  }
  parser.on('--ids1src=PATH', 'A source file of event-IDs 1 (parse.y).') {|path|
    ids1src = path
  }
  parser.on('--ids2src=PATH', 'A source file of event-IDs 2 (eventids2.c).') {|path|
    ids2src = path
  }
  parser.on('--output=PATH', 'An output file.') {|path|
    output = path
  }
  parser.on('--help', 'Prints this message and quit.') {
    puts parser.help
    exit true
  }
  begin
    parser.parse!
  rescue OptionParser::ParseError => err
    usage err.message
  end
  usage 'no mode given' unless mode
  case mode
  when 'check'
    usage 'no --ids1src' unless ids1src
    usage 'no --ids2src' unless ids2src
    h = read_ids1_with_locations(ids1src)
    check_arity h
    ids2 = read_ids2(ids2src)
    common = h.keys & ids2
    unless common.empty?
      abort "event crash: #{common.join(' ')}"
    end
    exit 0
  when 'eventids1_h'
    usage 'no --ids1src' unless ids1src
    result = generate_eventids1_h(read_ids1(ids1src))
  when 'eventids1'
    usage 'no --ids1src' unless ids1src
    result = generate_eventids1(read_ids1(ids1src))
  when 'eventids2table'
    usage 'no --ids2src' unless ids2src
    result = generate_eventids2_table(read_ids2(ids2src))
  end
  if output
    File.open(output, 'w') {|f|
      f.write result
    }
  else
    puts result
  end
end
method_missing(event, *args) 点击切换源代码
# File ripper/tools/dsl.rb, line 77
def method_missing(event, *args)
  if event.to_s =~ /!\z/
    add_event(event, args)
  elsif args.empty? and /\Aid[A-Z_]/ =~ event.to_s
    event
  else
    "#{ event }(#{ args.join(", ") })"
  end
end
new_var() 点击切换源代码
# File ripper/tools/dsl.rb, line 54
def new_var
  "v#{ @vars += 1 }"
end
opt_event(event, default, addend) 点击切换源代码
# File ripper/tools/dsl.rb, line 58
def opt_event(event, default, addend)
  add_event(event, [default, addend], true)
end
prelude(f, out) 点击切换源代码
# File ripper/tools/preproc.rb, line 54
def prelude(f, out)
  @exprs = {}
  lex_state_def = false
  while line = f.gets
    case line
    when /\A%%/
      out << "%%\n"
      return
    when /\A%token/, /\A%type/, /\A} <node(?>_\w+)?>/
      # types in %union which have corresponding set_yylval_* macro.
      out << line.sub(/<(?:node(?>_\w+)?|num|id)>/, '<val>')
    when /^enum lex_state_(?:bits|e) \{/
      lex_state_def = true
      out << line
    when /^\}/
      lex_state_def = false
      out << line
    else
      out << line
    end
    if lex_state_def
      case line
      when /^\s*(EXPR_\w+),\s+\/\*(.+)\*\//
        @exprs[$1.chomp("_bit")] = $2.strip
      when /^\s*(EXPR_\w+)\s+=\s+(.+)$/
        name = $1
        val = $2.chomp(",")
        @exprs[name] = "equals to " + (val.start_with?("(") ? "<tt>#{val}</tt>" : "+#{val}+")
      end
    end
  end
end
process(f, out, path, template) 点击切换源代码
# File ripper/tools/preproc.rb, line 48
def process(f, out, path, template)
  prelude f, out
  grammar f, out
  usercode f, out, path, template
end
read_ids1(path) 点击切换源代码
# File ripper/tools/generate.rb, line 142
def read_ids1(path)
  strip_locations(read_ids1_with_locations(path))
end
read_ids1_with_locations(path) 点击切换源代码
# File ripper/tools/generate.rb, line 165
def read_ids1_with_locations(path)
  h = {}
  File.open(path) {|f|
    f.each do |line|
      next if /\A\#\s*define\s+dispatch/ =~ line
      next if /ripper_dispatch/ =~ line
      line.scan(/\bdispatch(\d)\((\w+)/) do |arity, event|
        (h[event] ||= []).push [f.lineno, arity.to_i]
      end
      if line =~ %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
        gen = DSL.new($2, ($1 || "").split(","))
        gen.generate
        gen.events.each do |event, arity|
          (h[event] ||= []).push [f.lineno, arity.to_i]
        end
      end
    end
  }
  h
end
read_ids2(path) 点击切换源代码
# File ripper/tools/generate.rb, line 186
def read_ids2(path)
  src = File.open(path) {|f| f.read}
  ids2 = src.scan(/ID\s+ripper_id_(\w+)/).flatten.uniq.sort
  diff = src.scan(/set_id2\((\w+)\);/).flatten - ids2
  unless diff.empty?
    abort "missing scanner IDs: #{diff}"
  end
  return ids2
end
strip_locations(h) 点击切换源代码
# File ripper/tools/generate.rb, line 146
def strip_locations(h)
  h.map {|event, list| [event, list.first[1]] }\
      .sort_by {|event, arity| event.to_s }
end
usage(msg) 点击切换源代码
# File ripper/tools/generate.rb, line 67
def usage(msg)
  $stderr.puts msg
  $stderr.puts @parser.help
  exit false
end
usercode(f, out, path, template) 点击切换源代码
# File ripper/tools/preproc.rb, line 109
def usercode(f, out, path, template)
  require 'erb'
  lineno = nil
  src = nil
  compiler = ERB::Compiler.new('%-')
  compiler.put_cmd = compiler.insert_cmd = "out.<<"

  if template
    File.open(template) do |f|
      out.clear
      lineno = f.lineno
      src, = compiler.compile(f.read)
      path = template
    end
  else
    lineno = f.lineno
    src, = compiler.compile(f.read)
  end

  eval(src, binding, path, lineno)
end