类 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