rubyx/test/support/risc_interpreter.rb
Torsten Rüger 12b29285d7 Lots of preloading for tests
so many relied (implicitly( on some builtin function
after all can't do much in ruby without calling
Now all those dependencies are explicit
Small risc changes come because the macro version has a return label and unreachable label
2019-09-13 14:07:12 +03:00

138 lines
3.5 KiB
Ruby

require "util/eventable"
require "risc/interpreter"
require_relative "compiling"
module Risc
module Ticker
include ScopeHelper
include Output
include Preloader
def setup
compiler = RubyX::RubyXCompiler.new(RubyX.interpreter_test_options)
@linker = compiler.ruby_to_binary(preload + @string_input, :interpreter)
@interpreter = Interpreter.new(@linker)
@interpreter.start_program
end
alias :do_setup :setup
def yielder
"def yielder; return yield ; end"
end
def tenner
"def tenner; return yield(10) ;end"
end
def block_main( main , extra = yielder)
in_Space("#{extra} ; def main(arg) ; #{main} ; end")
end
# check the given array of instructions is what the interpreter actually does
# possible second argument ignores the given amount, usually up until main
def check_chain( should , start_at = 0 )
ticks( start_at ) if start_at > 0
should.each_with_index do |name , index|
got = ticks(1)
assert_equal got.class ,name , "Wrong class for #{index + 1}, expect #{name} , got #{got}"
end
end
# check the main only, ignoring the __init instructions
def check_main_chain( should )
check_chain( should , main_at)
end
# how many instruction up until the main starts, ie
# ticks(main_at) will be the label for main
def main_at
14
end
def get_return
assert_equal Parfait::Message , @interpreter.get_register(:r8).class
@interpreter.get_register(:r0)
end
# do as many as given ticks in the main, ie main_at more
def main_ticks(num)
ticks( main_at + num)
end
# do a certain number of steps in the interpreter and return the last executed instruction
def ticks( num )
last = nil
num.times do
last = @interpreter.instruction
@interpreter.tick
end
return last
end
# collect the classes of all executed istructions
def all_classes(max = 300)
classes = []
tick = 1
begin
while(classes.length < max)
cl = ticks(1).class
tick += 1
classes << cl
break if cl == NilClass
end
rescue => e
puts "Error at tick #{tick}"
puts e
puts e.backtrace
end
classes
end
# do the setup, compile and run the input (a main) to the end
def run_main_return(input)
run_main("return #{input}")
end
# get the return from the message (not exit code)
# exit code must be int
def get_message_return
@interpreter.get_register(:r8).return_value
end
# wrap the input so it is a main, compile and run it
def run_main(input)
run_input as_main(input)
end
# use the input as it, compile and run it
# input muts contain a Space.main, but may contain more classes and methods
def run_input(input)
@string_input = preload + input
do_setup
run_all
end
def run_all
while(@interpreter.instruction)
@interpreter.tick
#puts @interpreter.instruction
end
@interpreter.clock
end
# for chaning the tests quickly output all instructions that are executed
def show_ticks
classes = all_classes
output_classes(classes)
end
# show all instructions of the main only
def show_main_ticks
classes = all_classes
classes = classes.slice(main_at , 1000)
output_classes(classes)
end
def output_classes(classes)
puts class_list(classes)
exit(1)
end
end
end