Skip to content

Instantly share code, notes, and snippets.

@pocke
Created May 9, 2019 04:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pocke/96a0621431abc475c589d2b2a04c8f15 to your computer and use it in GitHub Desktop.
Save pocke/96a0621431abc475c589d2b2a04c8f15 to your computer and use it in GitHub Desktop.
require 'optparse'
require 'pathname'
require 'open3'
require 'ripper'
require 'etc'
require 'timeout'
def valid_syntax?(code)
Ripper.sexp(code)
end
def sh(*cmd)
Open3.capture3(*cmd).then do |out, _err, status|
out if status.success?
end
end
def solve(code:, ch:, result:, pos:)
Timeout.timeout(TIMEOUT_SEC) do
code = code.dup
code.insert pos, ch
return nil unless valid_syntax?(code)
if sh('ruby', '-e', code) == result
[ch, pos]
end
end
rescue Timeout::Error
nil
end
opt = ARGV.getopts('result:', 'timeout:')
result = opt['result'] || "Hello world\n"
TIMEOUT_SEC = opt['timeout']&.to_i || 3
ruby_code = Pathname(ARGV.first).read
in_q = Queue.new
out_q = Queue.new
# TODO: null byte
(1..0xff).each do |i|
ch = i.chr
(ruby_code.size + 1).times do |pos|
in_q.push(code: ruby_code, ch: ch, result: result, pos: pos)
end
end
in_q.close
ths = Etc.nprocessors.times.map do
Thread.new do
loop do
v = in_q.pop
break unless v
ret = solve(**v)
next unless ret
out_q.push ret
end
end
end
ths.each(&:join)
out_q.close
while ret = out_q.pop
p ret
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment