class Template
Attributes
Public Class Methods
This method adds every subclass of Template to the list of templates to parse
# File template.rb, line 38 def self.inherited(subclass) subclass_file = parse_caller(caller[0])[0] puts "Loaded template #{subclass} defined in #{subclass_file}" @@template_classes.store subclass, subclass_file end
# File template.rb, line 28 def initialize super @situation_manager = SituationManager.new(self) end
Parses the text of stack entries returned by the “caller” method, which have the following format: <file:line> or <file:line: in `method’>.
# File template.rb, line 46 def self.parse_caller(at) if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at file = Regexp.last_match[1] line = Regexp.last_match[2].to_i method = Regexp.last_match[3] return [file, line, method] end raise MTRubyError, "Failed to parse #{at}." end
# File template.rb, line 33 def self.template_classes @@template_classes end
Public Instance Methods
Creates an object that specifies an unknown immediate value to be used as an argument of a mode or op. A corresponding concrete value must be produced as a result of test data generation for some test situation.
# File template.rb, line 351 def _(allocator = nil, attrs = {}) if allocator.is_a? Hash and attrs.empty? then attrs = allocator allocator = nil end if !attrs.is_a?(Hash) raise MTRubyError, "#{attrs} is not a Hash." end retain = attrs[:retain] exclude = attrs[:exclude] @template.newUnknownImmediate get_caller_location, allocator, retain, exclude end
# File template.rb, line 668 def address(*args) if args.count != 0 and args.count != 2 raise MTRubyError, "Wrong argument count: #{args.count}. Must be 0 or 2." end reference = AddressReference.new @template if args.count == 2 reference.bits args[0], args[1] else reference end end
# File template.rb, line 795 def align(value) value_in_bytes = alignment_in_bytes(value) @template.setAlignment value, value_in_bytes, get_caller_location end
By default, align n is interpreted as alignment on 2**n byte border. This behavior can be overridden.
# File template.rb, line 804 def alignment_in_bytes(n) 2 ** n end
# File template.rb, line 155 def atomic(attributes = {}, &contents) blockBuilder = @template.beginBlock blockBuilder.setWhere get_caller_location blockBuilder.setAtomic true blockBuilder.setSequence false blockBuilder.setIterate false if attributes.has_key? :obfuscator blockBuilder.setObfuscator(attributes[:obfuscator]) end set_attributes blockBuilder, attributes self.instance_eval &contents @template.endBlock end
————————————————————————- # Methods for template description facilities # ————————————————————————- #
# File template.rb, line 103 def block(attributes = {}, &contents) blockBuilder = @template.beginBlock blockBuilder.setWhere get_caller_location blockBuilder.setAtomic false blockBuilder.setSequence false blockBuilder.setIterate false if attributes.has_key? :combinator blockBuilder.setCombinator(attributes[:combinator]) end if attributes.has_key? :permutator blockBuilder.setPermutator(attributes[:permutator]) end if attributes.has_key? :compositor blockBuilder.setCompositor(attributes[:compositor]) end if attributes.has_key? :rearranger blockBuilder.setRearranger(attributes[:rearranger]) end if attributes.has_key? :obfuscator blockBuilder.setObfuscator(attributes[:obfuscator]) end set_attributes blockBuilder, attributes self.instance_eval &contents @template.endBlock end
————————————————————————– # Creating Buffer Preparators # ————————————————————————– #
# File template.rb, line 656 def buffer_preparator(attrs, &contents) buffer_id = get_attribute attrs, :target builder = @template.beginBufferPreparator buffer_id if attrs.has_key?(:levels) builder.setLevels attrs[:levels] end self.instance_eval &contents @template.endBufferPreparator end
Adds a comment into the test program (uses sl_comment_starts_with).
# File template.rb, line 456 def comment(format, *args) print_format :COMMENT, format, *args end
# File template.rb, line 515 def comparator(attrs, &contents) create_preparator(true, attrs, &contents) end
# File template.rb, line 519 def create_preparator(is_comparator, attrs, &contents) target = get_attribute attrs, :target builder = @template.beginPreparator target.to_s, is_comparator builder.setWhere get_caller_location(2) name = attrs[:name] if !name.nil? builder.setName name.to_s end mask = attrs[:mask] if !mask.nil? if mask.is_a?(String) builder.setMaskValue mask elsif mask.is_a?(Array) builder.setMaskCollection mask else raise MTRubyError, "Illegal mask type: #{mask}" end end arguments = attrs[:arguments] if !arguments.nil? if !arguments.is_a?(Hash) raise MTRubyError, "#{arguments} is not a Hash." end arguments.each_pair do |name, value| if value.is_a?(Integer) builder.addArgumentValue name, value elsif value.is_a?(Range) builder.addArgumentRange name, value.min, value.max elsif value.is_a?(Array) builder.addArgumentCollection name, value else raise MTRubyError, "Illegal value of #{name} argument: #{value}" end end end self.instance_eval &contents @template.endPreparator end
# File template.rb, line 755 def data(attrs = {}, &contents) if nil == @data_manager raise MTRubyError, "Data configuration is not defined" end if attrs.has_key?(:global) global = attrs[:global] else global = false end if attrs.has_key?(:separate_file) separate_file = attrs[:separate_file] else separate_file = false end @data_manager.beginData global, separate_file @data_manager.instance_eval &contents @data_manager.endData end
————————————————————————– # Data Definition Facilities # ————————————————————————– #
# File template.rb, line 738 def data_config(attrs, &contents) if nil != @data_manager raise MTRubyError, "Data configuration is already defined" end target = get_attribute attrs, :target # Default value is 8 bits if other value is not explicitly specified addressableSize = attrs.has_key?(:item_size) ? attrs[:item_size] : 8 @data_manager = DataManager.new(self, @template.getDataManager) @data_manager.beginConfig target, addressableSize @data_manager.instance_eval &contents @data_manager.endConfig end
# File template.rb, line 632 def data_source @template.getDataSource end
# File template.rb, line 71 def define_method(method_name, &method_body) method_name = method_name.downcase if !Template.method_defined?(method_name) Template.send(:define_method, method_name, &method_body) else puts "Error: Failed to define the #{method_name} method." end end
————————————————————————– # Defining Groups # ————————————————————————– #
# File template.rb, line 399 def define_mode_group(name, distribution) if !distribution.is_a?(Dist) raise MTRubyError, "#{distribution} is not a distribution." end @template.defineGroup name, distribution.java_object TemplateBuilder.define_addressing_mode_group name end
# File template.rb, line 408 def define_op_group(name, distribution) if !distribution.is_a?(Dist) raise MTRubyError, "#{distribution} is not a distribution." end @template.defineGroup name, distribution.java_object TemplateBuilder.define_operation_group name end
Creates an object describing the probability distribution for random generation (biased generation). Methods arguments specify ranges of values with corresponding biases.
# File template.rb, line 274 def dist(*ranges) if !ranges.is_a?(Array) raise MTRubyError, "#{ranges} is not an Array." end builder = @template.newVariateBuilder ranges.each do |range_item| if !range_item.is_a?(ValueRange) raise MTRubyError, "#{range_item} is not a ValueRange." end value = range_item.value bias = range_item.bias if value.is_a?(Range) min = [value.first, value.last].min max = [value.first, value.last].max if bias.nil? then builder.addInterval min, max else builder.addInterval min, max, bias end elsif value.is_a?(Array) if bias.nil? then builder.addCollection value else builder.addCollection value, bias end elsif value.is_a?(Dist) if bias.nil? then builder.addVariate value.java_object else builder.addVariate value.java_object, bias end else if bias.nil? then builder.addValue value else builder.addValue value, bias end end end Dist.new builder.build end
Ends a multi-line comment (uses ml_comment_ends_with)
# File template.rb, line 471 def end_comment print_format :COMMENT_ML_END, '' @is_multiline_comment = false end
# File template.rb, line 681 def entry(*args) if args.count != 0 and args.count != 2 raise MTRubyError, "Wrong argument count: #{args.count}. Must be 0 or 2." end reference = BufferEntryReference.new @template if args.count == 2 reference.bits args[0], args[1] else reference end end
# File template.rb, line 854 def epilogue(&contents) @template.beginEpilogue self.instance_eval &contents @template.endEpilogue end
————————————————————————– # Exception Handling # ————————————————————————– #
# File template.rb, line 708 def exception_handler(attrs = {}, &contents) if attrs.has_key?(:id) id = attrs[:id] else id = '' end builder = @template.beginExceptionHandler id if attrs.has_key?(:instance) instance = attrs[:instance] else instance = 0..(get_option_value('instance-number').to_i - 1) end if instance.is_a?(Range) builder.setInstances instance.min, instance.max else builder.setInstances instance end exception_handler_object = ExceptionHandler.new self, builder exception_handler_object.instance_eval &contents @template.endExceptionHandler end
# File template.rb, line 391 def free_all_allocated_modes(mode) @template.freeAllocatedMode mode, true end
# File template.rb, line 387 def free_allocated_mode(mode) @template.freeAllocatedMode mode, false end
————————————————————————– # Generation (Execution and Printing) # ————————————————————————– #
# File template.rb, line 937 def generate java_import Java::Ru.ispras.microtesk.test.TestEngine engine = TestEngine.getInstance() TemplateBuilder.define_runtime_methods engine.getModel.getMetaData @template = engine.newTemplate @template.beginPreSection pre @template.endPreSection @template.beginPostSection post @template.endPostSection @template.beginMainSection run @template.endMainSection end
————————————————————————– # Generating Data Files # ————————————————————————– #
# File template.rb, line 698 def generate_data(address, label, type, length, method, *flags) # puts "Generating data file" separate_file = if flags.empty? then true else flags[0] end @template.generateData address, label, type, length, method, separate_file end
# File template.rb, line 199 def get_address_of(label) @template.getAddressForLabel label.to_s end
# File template.rb, line 65 def get_caller_location(caller_index = 1) # Parses the caller of this method's caller, so the default index is 1 caller_info = Template.parse_caller(caller[caller_index]) @template.where File.basename(caller_info[0]), caller_info[1] end
# File template.rb, line 963 def get_option_value(name) java_import Java::Ru.ispras.microtesk.test.TestEngine engine = TestEngine.getInstance engine.getOptionValue name end
# File template.rb, line 636 def index_source @template.getIndexSource end
# File template.rb, line 173 def iterate(attributes = {}, &contents) blockBuilder = @template.beginBlock blockBuilder.setWhere get_caller_location blockBuilder.setAtomic false blockBuilder.setSequence false blockBuilder.setIterate true if attributes.has_key? :obfuscator blockBuilder.setObfuscator(attributes[:obfuscator]) end if attributes.has_key? :rearranger blockBuilder.setRearranger(attributes[:rearranger]) end set_attributes blockBuilder, attributes self.instance_eval &contents @template.endBlock end
# File template.rb, line 195 def label(name) @template.addLabel name end
Creates a location-based format argument for format-like output methods.
# File template.rb, line 424 def location(name, index) Location.new name, index end
————————————————————————– # Memory Objects # ————————————————————————– #
# File template.rb, line 864 def memory_object(attrs) size = get_attribute attrs, :size builder = @template.newMemoryObjectBuilder size va = get_attribute attrs, :va is_va_label = false if va.is_a?(Integer) builder.setVa va elsif va.is_a?(Range) builder.setVa va.min, va.max elsif va.is_a?(String) or va.is_a?(Symbol) builder.setVa va.to_s is_va_label = true else raise MTRubyError, "The 'va' attribute has unsupported type #{va.class}." end if !is_va_label pa = get_attribute attrs, :pa if pa.is_a?(Integer) builder.setPa pa elsif pa.is_a?(Range) builder.setPa pa.min, pa.max elsif pa.is_a?(String) or pa.is_a?(Symbol) builder.setPa pa.to_s else raise MTRubyError, "The 'pa' attribute has unsupported type #{pa.class}." end end if attrs.has_key?(:name) builder.setName attrs[:name].to_s end if attrs.has_key?(:mode) builder.setMode attrs[:mode].to_s end if attrs.has_key?(:data) builder.setData attrs[:data] end builder.build end
uses address and data
# File template.rb, line 609 def memory_preparator(attrs, &contents) size = get_attribute attrs, :size builder = @template.beginMemoryPreparator size self.instance_eval &contents @template.endMemoryPreparator end
Hack to allow limited use of capslocked characters
# File template.rb, line 57 def method_missing(meth, *args, &block) if self.respond_to?(meth.to_s.downcase) self.send meth.to_s.downcase.to_sym, *args, &block else super end end
— Special “no value” method — Similar to the above method, but the described object is more complex than an immediate value (most likely, it will be some MODE or OP). TODO: Not implemented. Left as a requirement. Should be implemented in the future.
def __(aug_value = nil)
NoValue.new(aug_value)
end
# File template.rb, line 377 def mode_allocator(name, attrs = {}) builder = @template.newAllocatorBuilder name attrs.each_pair do |key, value| builder.setAttribute key.to_s, value.to_s end builder.build end
Adds the new line character into the test program
# File template.rb, line 438 def newline text '' end
————————————————————————– # Code Allocation Facilities # ————————————————————————– #
# File template.rb, line 781 def org(origin) if origin.is_a?(Integer) @template.setOrigin origin, get_caller_location elsif origin.is_a?(Hash) delta = get_attribute origin, :delta if !delta.is_a?(Integer) raise MTRubyError, "delta (#{delta}) must be an Integer." end @template.setRelativeOrigin delta, get_caller_location else raise MTRubyError, "origin (#{origin}) must be an Integer or a Hash." end end
# File template.rb, line 910 def page_table(attrs = {}, &contents) if nil == @data_manager raise MTRubyError, "Data configuration is not defined" end if attrs.has_key?(:global) global = attrs[:global] else global = false end if attrs.has_key?(:separate_file) separate_file = attrs[:separate_file] else separate_file = false end @data_manager.beginData global, separate_file page_table = PageTable.new self, @data_manager page_table.instance_eval &contents @data_manager.endData end
Post-condition instructions template
# File template.rb, line 95 def post end
Pre-condition instructions template
# File template.rb, line 85 def pre end
————————————————————————– # Creating Preparators and Comparators # ————————————————————————– #
# File template.rb, line 511 def preparator(attrs, &contents) create_preparator(false, attrs, &contents) end
# File template.rb, line 589 def prepare(target_mode, value_object, attrs = {}) preparator_name = attrs[:name] if !preparator_name.nil? preparator_name = preparator_name.to_s end variant_name = attrs[:variant] if !variant_name.nil? variant_name = variant_name.to_s end value_object = value_object.java_object if value_object.is_a? WrappedObject @template.addPreparatorCall target_mode, value_object, preparator_name, variant_name end
Prints a format-based output to the simulator log or to the test program depending of the is_runtime flag.
# File template.rb, line 480 def print_format(kind, format, *args) java_import Java::Ru.ispras.microtesk.test.template.Value builder = @template.newOutput kind.to_s, format args.each do |arg| if arg.is_a?(Integer) or arg.is_a?(String) or arg.is_a?(TrueClass) or arg.is_a?(FalseClass) or arg.is_a?(Value) builder.addArgument arg elsif arg.is_a?(Location) builder.addArgument arg.name, arg.index else raise MTRubyError, "Illegal format argument class #{arg.class}" end end @template.addOutput builder.build end
————————————————————————– # Test Case Level Prologue and Epilogue # ————————————————————————– #
# File template.rb, line 848 def prologue(&contents) @template.beginPrologue self.instance_eval &contents @template.endPrologue end
Creates a pseudo instruction call that prints user-specified text.
# File template.rb, line 502 def pseudo(text) @template.setCallText text @template.endBuildingCall end
Creates an object for generating a random integer (to be used as an argument of a mode or op) selected from the specified range or according to the specified distribution.
# File template.rb, line 246 def rand(*args) if args.count == 1 distribution = args.at(0) if !distribution.is_a?(Dist) raise MTRubyError, "the argument must be a distribution." end @template.newRandom distribution.java_object elsif args.count == 2 from = args.at(0) to = args.at(1) if !from.is_a?(Integer) or !to.is_a?(Integer) raise MTRubyError, "the arguments must be integers." end @template.newRandom from, to else raise MTRubyError, "Wrong argument count: #{args.count}. Must be 1 or 2." end end
# File template.rb, line 223 def random_situation(dist) dist.java_object end
Creates an object describing a value range (with corresponding bias) used in random generation. If the bias attribute is not specified, it will be set to nil, which means the default bias.
# File template.rb, line 325 def range(attrs = {}) if !attrs.is_a?(Hash) raise MTRubyError, "#{attrs} is not a Hash." end if !attrs.has_key?(:value) raise MTRubyError, "The :value attribute is not specified in #{attrs}." end value = attrs[:value] bias = nil if attrs.has_key?(:bias) bias = attrs[:bias] if !bias.is_a?(Integer) raise MTRubyError, "#{bias} is not an Integer." end end ValueRange.new value, bias end
Main instructions template
# File template.rb, line 90 def run puts "MTRuby: warning: Trying to execute the original Template#run." end
————————————————————————– # Sections # ————————————————————————– #
# File template.rb, line 812 def section(attrs, &contents) name = get_attribute attrs, :name pa = attrs[:pa] va = attrs[:va] args = attrs[:args] @template.beginSection name, pa, va, args self.instance_eval &contents @template.endSection end
# File template.rb, line 834 def section_data(attrs = {}, &contents) pa = attrs[:pa] va = attrs[:va] args = attrs[:args] @template.beginSectionData pa, va, args self.instance_eval &contents @template.endSection end
# File template.rb, line 824 def section_text(attrs = {}, &contents) pa = attrs[:pa] va = attrs[:va] args = attrs[:args] @template.beginSectionText pa, va, args self.instance_eval &contents @template.endSection end
# File template.rb, line 137 def sequence(attributes = {}, &contents) blockBuilder = @template.beginBlock blockBuilder.setWhere get_caller_location blockBuilder.setAtomic false blockBuilder.setSequence true blockBuilder.setIterate false if attributes.has_key? :obfuscator blockBuilder.setObfuscator(attributes[:obfuscator]) end set_attributes blockBuilder, attributes self.instance_eval &contents @template.endBlock end
# File template.rb, line 227 def set_default_situation(names, &situations) if !names.is_a?(String) and !names.is_a?(Array) raise MTRubyError, "#{names} must be String or Array." end default_situation = @situation_manager.instance_eval &situations if names.is_a?(Array) names.each do |name| @template.setDefaultSituation name, default_situation end else @template.setDefaultSituation names, default_situation end end
# File template.rb, line 957 def set_option_value(name, value) java_import Java::Ru.ispras.microtesk.test.TestEngine engine = TestEngine.getInstance engine.setOptionValue name, value end
# File template.rb, line 203 def situation(name, attrs = {}) if !attrs.is_a?(Hash) raise MTRubyError, "attrs (#{attrs}) must be a Hash." end builder = @template.newSituation name attrs.each_pair do |name, value| if value.is_a?(Dist) then attr_value = value.java_object elsif value.is_a?(Symbol) then attr_value = value.to_s else attr_value = value end builder.setAttribute name.to_s, attr_value end builder.build end
Starts a multi-line comment (uses sl_comment_starts_with)
# File template.rb, line 463 def start_comment @is_multiline_comment = true print_format :COMMENT_ML_START, '' end
# File template.rb, line 640 def start_label @template.getStartLabel end
————————————————————————– # Creating Streams # ————————————————————————– #
# File template.rb, line 648 def stream(label, data, index, length) @template.addStream label.to_s, data, index, length end
————————————————————————– # Creating Stream Preparators # ————————————————————————– #
# File template.rb, line 620 def stream_preparator(attrs, &contents) data = get_attribute attrs, :data_source index = get_attribute attrs, :index_source @template.beginStreamPreparator data.to_s, index.to_s data_stream_object = StreamPreparator.new self, @template data_stream_object.instance_eval &contents @template.endStreamPreparator end
# File template.rb, line 573 def target @template.getPreparatorTarget end
Adds text into the test program.
# File template.rb, line 445 def text(format, *args) if @is_multiline_comment print_format :COMMENT_ML_BODY, format, *args else print_format :TEXT, format, *args end end
Prints text into the simulator execution log.
# File template.rb, line 431 def trace(format, *args) print_format :TRACE, format, *args end
# File template.rb, line 577 def value(*args) if args.count != 0 and args.count != 2 raise MTRubyError, "Wrong argument count: #{args.count}. Must be 0 or 2." end if args.count == 2 @template.newLazy args.at(0), args.at(1) else @template.newLazy end end
# File template.rb, line 564 def variant(attrs = {}, &contents) name = attrs[:name] bias = attrs[:bias] @template.beginPreparatorVariant name, bias self.instance_eval &contents @template.endPreparatorVariant end