mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
forgot to add
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9274 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a697b1f602
commit
ec4689b164
1 changed files with 180 additions and 0 deletions
180
ext/ripper/tools/generate.rb
Executable file
180
ext/ripper/tools/generate.rb
Executable file
|
@ -0,0 +1,180 @@
|
|||
# $Id$
|
||||
|
||||
require 'stringio'
|
||||
require 'optparse'
|
||||
|
||||
def main
|
||||
mode = nil
|
||||
ids1src = nil
|
||||
ids2src = nil
|
||||
template = nil
|
||||
output = nil
|
||||
|
||||
parser = @parser = OptionParser.new
|
||||
parser.banner = "Usage: #{File.basename($0)} --mode=MODE [--ids1src=PATH] [--ids2src=PATH] [--template=PATH] [--output=PATH]"
|
||||
parser.on('--mode=MODE', '"ripper/core" or "eventids1".') {|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('--template=PATH', 'A template file of ripper/core.rb.') {|path|
|
||||
template = path
|
||||
}
|
||||
parser.on('--output=PATH', 'An output file.') {|path|
|
||||
output = path
|
||||
}
|
||||
parser.on('--help', 'Prints this message and quit.') {
|
||||
puts parser.help
|
||||
exit 0
|
||||
}
|
||||
begin
|
||||
parser.parse!
|
||||
rescue OptionParser::ParseError => err
|
||||
usage err.message
|
||||
end
|
||||
usage 'no mode given' unless mode
|
||||
case mode
|
||||
when 'ripper/core', 'ripper/core.rb'
|
||||
usage 'no --ids1src' unless ids1src
|
||||
usage 'no --ids2src' unless ids2src
|
||||
usage 'no --template' unless template
|
||||
result = generate_ripper_core(template, read_ids1(ids1src), read_ids2(ids2src))
|
||||
when 'eventids1', 'eventids1.c'
|
||||
usage 'no --ids1src' unless ids1src
|
||||
result = generate_eventids1(read_ids1(ids1src))
|
||||
end
|
||||
if output
|
||||
File.open(output, 'w') {|f|
|
||||
f.write result
|
||||
}
|
||||
else
|
||||
puts result
|
||||
end
|
||||
end
|
||||
|
||||
def usage(msg)
|
||||
$stderr.puts msg
|
||||
$stderr.puts @parser.help
|
||||
exit 1
|
||||
end
|
||||
|
||||
def generate_ripper_core(template, ids1, ids2)
|
||||
f = StringIO.new
|
||||
f.print <<header
|
||||
# This file is automatically generated from #{File.basename(template)} and parse.y.
|
||||
# DO NOT MODIFY!!!!!!
|
||||
|
||||
header
|
||||
File.foreach(template) do |line|
|
||||
case line
|
||||
when /\A\#include ids1/
|
||||
comma = ''
|
||||
ids1.each do |id, arity|
|
||||
f.print comma; comma = ",\n"
|
||||
f.print " #{id.intern.inspect} => #{arity}"
|
||||
end
|
||||
f.puts
|
||||
when /\A\#include ids2/
|
||||
comma = ''
|
||||
ids2.each do |id|
|
||||
f.print comma; comma = ",\n"
|
||||
f.print " #{id.intern.inspect} => 1"
|
||||
end
|
||||
f.puts
|
||||
when /\A\#include handlers1/
|
||||
ids1.each do |id, arity|
|
||||
f.puts
|
||||
f.puts " def on_#{id}#{paramdecl(arity)}"
|
||||
f.puts " #{arity == 0 ? 'nil' : 'a'}"
|
||||
f.puts " end"
|
||||
end
|
||||
when /\A\#include handlers2/
|
||||
ids2.each do |id|
|
||||
f.puts
|
||||
f.puts " def on_#{id}(token)"
|
||||
f.puts " token"
|
||||
f.puts " end"
|
||||
end
|
||||
when /\A\#include (.*)/
|
||||
raise "unknown operation: #include #{$1}"
|
||||
else
|
||||
f.print line
|
||||
end
|
||||
end
|
||||
f.string
|
||||
end
|
||||
|
||||
def paramdecl(n)
|
||||
return '' if n == 0
|
||||
'(' + ('a'..'z').to_a[0, n].join(', ') + ')'
|
||||
end
|
||||
|
||||
def generate_eventids1(ids)
|
||||
f = StringIO.new
|
||||
ids.each do |id, arity|
|
||||
f.puts "static ID ripper_id_#{id};"
|
||||
end
|
||||
f.puts
|
||||
f.puts 'static void'
|
||||
f.puts 'ripper_init_eventids1()'
|
||||
f.puts '{'
|
||||
ids.each do |id, arity|
|
||||
f.puts %Q[ ripper_id_#{id} = rb_intern("on_#{id}");]
|
||||
end
|
||||
f.puts '}'
|
||||
f.string
|
||||
end
|
||||
|
||||
def read_ids1(path)
|
||||
check_arity path
|
||||
ids = {}
|
||||
File.open(path) {|f|
|
||||
f.each do |line|
|
||||
next if /\A\#\s*define\s+s?dispatch/ =~ line
|
||||
next if /ripper_dispatch/ =~ line
|
||||
if a = line.scan(/dispatch(\d)\((\w+)/)
|
||||
a.each do |arity, event|
|
||||
ids[event] = arity.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
ids.to_a.sort_by {|event, arity| event.to_s }
|
||||
end
|
||||
|
||||
def check_arity(path)
|
||||
invalid = false
|
||||
table = {}
|
||||
File.open(path) {|f|
|
||||
File.foreach(path) do |line|
|
||||
next if /\A\#\s*define\s+s?dispatch\d/ =~ line
|
||||
next if /ripper_dispatch\d/ =~ line
|
||||
line.scan(/dispatch(\d)\((\w+)/) do |num, ev|
|
||||
num = num.to_i
|
||||
if table.key?(ev)
|
||||
locations, arity = *table[ev]
|
||||
unless num == arity
|
||||
invalid = true
|
||||
$stderr.puts "arity differ [event=#{ev}]: #{f.lineno}=#{num}; #{locations.join(',')}=#{arity}"
|
||||
end
|
||||
locations.push f.lineno
|
||||
else
|
||||
table[ev] = [[f.lineno], num.to_i]
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
exit 1 if invalid
|
||||
end
|
||||
|
||||
def read_ids2(path)
|
||||
File.open(path) {|f|
|
||||
return f.read.scan(/ripper_id_(\w+)/).flatten.uniq.sort
|
||||
}
|
||||
end
|
||||
|
||||
main
|
Loading…
Reference in a new issue