rubyx/test/support/risc_interpreter.rb

140 lines
3.6 KiB
Ruby
Raw Normal View History

require "util/eventable"
require "risc/interpreter"
require_relative "compiling"
2017-04-10 15:12:15 +02:00
module Risc
module Ticker
include ScopeHelper
2019-08-23 14:31:04 +02:00
include Output
def setup
compiler = RubyX::RubyXCompiler.new(RubyX.interpreter_test_options)
2019-02-08 22:03:23 +01:00
@linker = compiler.ruby_to_binary(@string_input, :interpreter)
2018-07-02 16:29:26 +02:00
@interpreter = Interpreter.new(@linker)
2018-07-02 22:03:33 +02:00
@interpreter.start_program
end
2018-04-23 13:05:37 +02:00
alias :do_setup :setup
2018-07-27 09:48:45 +02:00
def yielder
"def yielder; return yield ; end"
2018-07-27 09:48:45 +02:00
end
def tenner
"def tenner; return yield(10) ;end"
end
2018-07-27 09:48:45 +02:00
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
2017-04-10 15:12:15 +02:00
should.each_with_index do |name , index|
got = ticks(1)
assert_equal got.class ,name , "Wrong class for #{index + 1}, expect #{name} , got #{got}"
2017-04-10 15:12:15 +02:00
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
2019-08-23 14:31:04 +02:00
13
end
2017-04-10 15:12:15 +02:00
def get_return
assert_equal Parfait::Message , @interpreter.get_register(:r8).class
@interpreter.get_register(:r0)
2017-04-10 15:12:15 +02:00
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
2018-03-23 17:55:23 +01:00
def ticks( num )
2017-04-10 15:12:15 +02:00
last = nil
num.times do
last = @interpreter.instruction
@interpreter.tick
end
return last
end
# collect the classes of all executed istructions
2018-04-23 13:05:37 +02:00
def all_classes(max = 300)
2017-04-10 15:12:15 +02:00
classes = []
tick = 1
begin
2018-07-02 22:03:33 +02:00
while(classes.length < max)
2017-04-10 15:12:15 +02:00
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
2018-04-26 11:33:33 +02:00
# 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
2018-04-24 19:12:49 +02:00
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 = input
do_setup
2018-04-23 13:05:37 +02:00
run_all
end
2018-04-26 11:33:33 +02:00
# wrap the input in Space (main is assumed to be part of it)
def run_space(input)
@string_input = in_Space(input)
do_setup
run_all
end
2018-04-23 13:05:37 +02:00
def run_all
@interpreter.tick while(@interpreter.instruction)
@interpreter.clock
2018-04-23 13:05:37 +02:00
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)
2019-08-23 14:31:04 +02:00
puts class_list(classes)
2017-04-10 15:12:15 +02:00
exit(1)
end
end
end