Skip to content

Instantly share code, notes, and snippets.

@tompng
Forked from hanachin/double.rb
Last active December 16, 2015 15:36
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 tompng/4e9eb6b5875fc028a686 to your computer and use it in GitHub Desktop.
Save tompng/4e9eb6b5875fc028a686 to your computer and use it in GitHub Desktop.
ブロック中のでgotoが使えるメソッド書いてみた
#! ./ruby -I.ext/x86_64-darwin14 --disable-gems
require '-test-/iseq_load/iseq_load'
def spaghetti(&block)
iseq_data_magic_index = 0
iseq_data_major_version_index = 1
iseq_data_minor_version_index = 2
iseq_data_format_type_index = 3
iseq_data_misc_index = 4
iseq_data_label_index = 5
iseq_data_path_index = 6
iseq_data_absolute_path_index = 7
iseq_data_first_lineno_index = 8
iseq_data_type_index = 9
iseq_data_locals_index = 10
iseq_data_params_index = 11
iseq_data_catch_table_index = 12
iseq_data_bytecode_index = 13
iseq = RubyVM::InstructionSequence.of(block)
iseq_data = iseq.to_a
old_bytecodes = iseq_data[iseq_data_bytecode_index]
max_label = old_bytecodes.grep(/^label_/).map{|l|l.to_s.scan(/\d+/)[0].to_i}.max || 0
labels = {}
label_of = ->key{
labels[key] ||= (max_label += 1)
}
new_bytecodes = []
old_bytecodes.map do |code|
op, arg = code
if op == :opt_send_without_block && arg[:mid] == :label
label = new_bytecodes.pop[1]
label = label[:mid] if Hash === label
new_bytecodes << "label_#{label_of[label]}".to_sym
elsif op == :opt_send_without_block && arg[:mid] == :goto
label = new_bytecodes.pop[1]
label = label[:mid] if Hash === label
new_bytecodes << [:jump, "label_#{label_of[label]}".to_sym]
else
new_bytecodes << code
end
end
new_iseq_data = iseq_data.dup
new_iseq_data[iseq_data_bytecode_index] = new_bytecodes
# topじゃないとevalときエラーになるのでblockをtopに細工
if new_iseq_data[iseq_data_type_index] == :block
new_iseq_data[iseq_data_type_index] = :top
end
new_iseq = RubyVM::InstructionSequence.iseq_load(new_iseq_data)
new_iseq.eval
end
spaghetti {
goto hoge
label :hoge
goto :piyo
label piyo
max = 1
label :restart_point
n = 0
goto :for_start
label :for_continue
n += 1
label :for_start
goto :for_end unless n < max
STDOUT.write n%10
goto :for_continue
label :for_end
puts
sleep 1
max += 1
goto restart_point
}
# 0
# 01
# 012
# 0123
# 01234
# 012345
# 0123456
# 01234567
# 012345678
# 0123456789
# 01234567890
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment