Skip to content

Instantly share code, notes, and snippets.

@ko1
Created June 27, 2024 02:06
Show Gist options
  • Save ko1/3b422ce5a52c607b08b6467220ccbf2a to your computer and use it in GitHub Desktop.
Save ko1/3b422ce5a52c607b08b6467220ccbf2a to your computer and use it in GitHub Desktop.
require_relative 'finder'
class MethodNameFinder < Finder
def rec node
if node.type == :call_node
inc [:call, node.name]
# pp [nloc(node),nlines(node).lines.first.chomp] unless @@opt[:quiet]
elsif node.type == :def_node
inc [:def, node.name]
# pp [nloc(node),nlines(node).lines.first.chomp] unless @@opt[:quiet]
end
node.child_nodes.compact.each{|n|
rec n
}
end
def self.print_result
@@result.sort_by{|(t, m), v| [t, -v]}.each{|(t, m), v|
puts "#{v}\t#{t}\t#{m}"
}
end
end
require 'prism'
require 'optparse'
require 'etc'
class Finder
def initialize file
@file = file
end
def rec node
# override here
end
def nline node
node.slice_lines.lines.first.chomp
end
def nlines node
node.slice_lines
end
def nloc node
"#{@file}:#{node.location.start_line}"
end
def success? r
return true if r.success?
if r.errors.size == 1 &&
r.errors.first.type == :script_not_found
true
else
false
end
end
def check
puts "Start #{@file}" if $VERBOSE
r = Prism.parse_file(@file)
if success?(r)
@ast = r.value
rec @ast
else
# pp [@file, r.errors]
inc :FAILED
end
rescue Exception
pp [$!, @file]
inc :FAILED
end
def inc sym
@@result[sym] += 1
end
def self.inc sym
@@result[sym] += 1
end
@@last_finder = self
def self.inherited klass
@@last_finder = klass
end
def self.last_finder
@@last_finder
end
@@result = Hash.new(0)
@@opt = {}
def self.setup_parallel pn
taskq = @@opt[:taskq] = Queue.new
resq = @@opt[:resq] = Queue.new
term_cmd = '-- terminate'
@@opt[:threads] = pn.times.map{
Thread.new _1 do |ti|
task_r, task_w = IO.pipe
res_r, res_w = IO.pipe
last_result = 'ok'
pid = fork do
loop do
res_w.puts last_result.to_s.dump
file = task_r.gets.chomp
if file == term_cmd
last_result = Marshal.dump(@@result).dump
else
kick(file)
last_result = nil
end
end
end
fst_msg = res_r.gets.chomp
raise if fst_msg != 'ok'.dump
while file = taskq.pop
# p [ti, taskq.size]
task_w.puts file
res_r.gets # wait for the result
end
task_w.puts term_cmd
s = res_r.gets.chomp.undump.undump
resq << Marshal.load(s)
ensure
p [Thread.current, $!] if $VERBOSE
Process.kill :KILL, pid
Process.waitpid pid
end
}
end
def self.cleanup_parallel
return unless taskq = @@opt[:taskq]
taskq.close
@@opt[:parallel].times{|i|
r = @@opt[:resq].pop
@@result.merge!(r){|k, a, b| a + b}
}
end
def self.parse_opt argv
o = OptionParser.new
o.on '-v', '--verbose', 'VERBOSE mode' do
$VERBOSE = true
end
o.on '-j', '--jobs[=N]', 'Parallel mode' do
pn = @@opt[:parallel] = _1&.to_i || Etc.nprocessors
setup_parallel pn
end
o.on '-q', '--quiet' do
@@opt[:quiet] = true
end
o.parse! argv
pp options: @@opt if $VERBOSE
end
def self.kick file
last_finder.new(file).check
end
def self.print_result
pp @@result
end
def self.run argv = ARGV
parse_opt argv
finder = last_finder
ARGF.each do |f|
f = f.scrub.strip
next unless FileTest.file?(f)
inc :FILES
if q = @@opt[:taskq]
q << f
else
kick f
end
end
cleanup_parallel
finder.print_result
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment