turned out to be a rewrite of boot process

and also attribute handling and fake_memory
luckily there are tests and all is green again
This commit is contained in:
Torsten Ruger 2015-07-21 15:40:25 +03:00
parent f8cb33ec5e
commit 2d0424a370
19 changed files with 258 additions and 221 deletions

View File

@ -6,6 +6,7 @@ gem "rake"
gem "salama-reader" , :github => "salama/salama-reader"
gem "salama-object-file" , :github => "salama/salama-object-file"
#gem "salama-object-file" , :path => "../salama-object-file"
gem "salama-arm" , :github => "salama/salama-arm"
gem "codeclimate-test-reporter", require: nil

View File

@ -6,7 +6,7 @@ GIT
GIT
remote: git://github.com/salama/salama-object-file.git
revision: 9e49f2e725dbad48edc151419882b159505b2e9b
revision: fbae6a02764dbe97e01e4833f9ffffe09879b100
specs:
salama-object-file (0.2.0)
@ -56,3 +56,6 @@ DEPENDENCIES
salama-arm!
salama-object-file!
salama-reader!
BUNDLED WITH
1.10.5

View File

@ -12,9 +12,9 @@ module Parfait
class BinaryCode < Word
def initialize name
super(0)
@name = name
self.name = name
end
attr_reader :name
attribute :name
# this is a sof check if there are instance variables or "structure"
# have to override false, as word answers true
@ -22,7 +22,7 @@ module Parfait
false
end
def to_s
"BinaryCode #{@name}"
"BinaryCode #{self.name}"
end
def == other

View File

@ -14,16 +14,13 @@ require_relative "meta_class"
module Parfait
class Class < Module
attribute :object_layout
def initialize name , super_class
super( name , super_class)
# the layout for this class (class = object of type Class) carries the class
# as an instance. The relation is from an object through the Layout to it's class
@object_layout = Layout.new(self)
end
def object_layout
@object_layout
self.object_layout = Layout.new(self)
end
def allocate_object
@ -31,7 +28,7 @@ module Parfait
end
def add_instance_name name
@object_layout.push name
self.object_layout.push name
end
def sof_reference_name

View File

@ -2,35 +2,25 @@
module Parfait
class Dictionary < Object
attribute :keys
attribute :values
# only empty initialization for now
#
# internally we store keys and values in lists, which means this does **not** scale well
def initialize
super()
@keys = List.new()
@values = List.new()
end
# return all values as a list
# TODO, list should be copied to avoid inconcisencies
def values()
@values
end
# return all keys as a list
# TODO, list should be copied to avoid inconcisencies
def keys()
@keys
self.keys = List.new()
self.values = List.new()
end
# are there any key/value items in the list
def empty?
@keys.empty?
self.keys.empty?
end
# How many key/value pairs there are
def length()
return @keys.get_length()
return self.keys.get_length()
end
# get a value fot the given key
@ -39,7 +29,7 @@ module Parfait
def get(key)
index = key_index(key)
if( index )
@values.get(index)
self.values.get(index)
else
nil
end
@ -52,11 +42,11 @@ module Parfait
# private method
def key_index(key)
len = @keys.get_length()
len = self.keys.get_length()
index = 1
found = nil
while(index <= len)
if( @keys.get(index) == key)
if( self.keys.get(index) == key)
found = index
break
end
@ -69,10 +59,10 @@ module Parfait
def set(key , value)
index = key_index(key)
if( index )
@keys.set(index , value)
self.keys.set(index , value)
else
@keys.push(key)
@values.push(value)
self.keys.push(key)
self.values.push(value)
end
value
end
@ -85,9 +75,9 @@ module Parfait
# yield to each key value pair
def each
index = 1
while index <= @keys.get_length
key = @keys.get(index)
value = @values.get(index)
while index <= self.keys.get_length
key = self.keys.get(index)
value = self.values.get(index)
yield key , value
index = index + 1
end

View File

@ -22,10 +22,11 @@
module Parfait
class Layout < List
attribute :object_class
def initialize( object_class )
super()
@object_class = object_class
self.object_class = object_class
end
def == other
@ -45,23 +46,30 @@ module Parfait
# beat the recursion! fixed known offset for class object in the layout
def get_object_class()
return @object_class
return self.object_class
end
def object_instance_names
names = List.new
index = 1
index = 2 # first is object_class
while index <= self.get_length
item = get(index)
names.push item
index = index + 1
end
self
names
end
# index of a variable name into the layout.
# layout is a list, so lowest index is 1
# :layout is a variable for every object, so 1 is taken for :layout
# still, the index is the same.
def variable_index name
index_of(name)
end
def sof_reference_name
"#{@object_class.name}_Layout"
"#{self.object_class.name}_Layout"
end
end

View File

@ -9,18 +9,19 @@
module Parfait
class Message < Object
attributes [:next_message , :frame, :caller]
attributes [:receiver , :return_address , :return_value , :name]
def initialize next_m
@next_message = next_m
@frame = Frame.new()
@caller = nil
self.next_message = next_m
self.frame = Frame.new()
self.caller = nil
super()
end
attr_reader :next_message , :frame , :caller # aka prev_message
attr_reader :receiver , :return_address , :return_value , :name
def set_caller caller
@caller = caller
self.caller = caller
end
def get_type_for(name)

View File

@ -18,26 +18,26 @@ module Parfait
def initialize(object)
super()
@functions = []
@me_self = object
self.functions = []
self.me_self = object
end
# in a non-booting version this should map to _add_singleton_method
def add_function function
raise "not a function #{function}" unless function.is_a? Virtual::Function
raise "syserr " unless function.name.is_a? Symbol
@functions << function
self.functions << function
end
def get_function name
name = name.to_sym
f = @functions.detect{ |f| f.name == name }
f = self.functions.detect{ |f| f.name == name }
return f if f
if( @me_self == "Object" )
puts "no function for :#{name} in Meta #{@me_self.inspect}"
if( self.me_self == "Object" )
puts "no function for :#{name} in Meta #{self.me_self.inspect}"
return nil
else #recurse up class hierachy unless we're at Object
return @me_self.context.object_space.get_class_by_name(@me_self.super_class).get_function name
return self.me_self.context.object_space.get_class_by_name(self.me_self.super_class).get_function name
end
end
@ -52,7 +52,7 @@ module Parfait
end
def to_s
"#{inspect} on #{@me_self}, #{@functions.length} functions"
"#{inspect} on #{self.me_self}, #{self.functions.length} functions"
end
end
end

View File

@ -22,14 +22,14 @@ module Parfait
def initialize clazz , name , arg_names
super()
raise "No class #{name}" unless clazz
@for_class = clazz
@name = name
@code = BinaryCode.new name
@arg_names = arg_names
@locals = List.new
@tmps = List.new
self.for_class = clazz
self.name = name
self.code = BinaryCode.new name
self.arg_names = arg_names
self.locals = List.new
self.tmps = List.new
end
attr_reader :name , :arg_names , :for_class , :code , :locals , :tmps
attributes [:name , :arg_names , :for_class , :code , :locals , :tmps]
# determine whether this method has a variable by the given name
@ -46,32 +46,32 @@ module Parfait
# determine whether this method has an argument by the name
def has_arg name
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol
@arg_names.index_of name
self.arg_names.index_of name
end
# determine if method has a local variable or tmp (anonymous local) by given name
def has_local name
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol
index = @locals.index_of(name)
index = @tmps.index_of(name) unless index
index = self.locals.index_of(name)
index = self.tmps.index_of(name) unless index
index
end
def ensure_local name
index = has_local name
return index if index
@locals.push name
@locals.get_length
self.locals.push name
self.locals.get_length
end
def get_var name
var = has_var name
raise "no var #{name} in method #{self.name} , #{@locals} #{@arg_names}" unless var
raise "no var #{name} in method #{self.name} , #{self.locals} #{self.arg_names}" unless var
var
end
def sof_reference_name
@name
self.name
end
end

View File

@ -13,25 +13,23 @@
module Parfait
class Module < Object
attribute :name
attribute :instance_methods
attribute :super_class
attribute :meta_class
def initialize name , superclass
super()
@name = name
@instance_methods = List.new
@super_class = superclass
@meta_class = nil#MetaClass.new(self)
self.name = name
self.instance_methods = List.new
self.super_class = superclass
self.meta_class = nil#MetaClass.new(self)
end
def name
@name
end
def instance_methods
@instance_methods
end
def method_names
names = List.new
@instance_methods.each do |method|
self.instance_methods.each do |method|
names.push method.name
end
names
@ -42,36 +40,36 @@ module Parfait
raise "syserr #{method.name.class}" unless method.name.is_a? Symbol
found = get_instance_method( method.name )
if found
@instance_methods.delete(found)
self.instance_methods.delete(found)
#raise "existed in #{self.name} #{Sof.write found.source.blocks}"
end
@instance_methods.push method
self.instance_methods.push method
#puts "#{self.name} add #{method.name}"
method
end
def remove_instance_method method
@instance_methods.delete method
self.instance_methods.delete method
end
def create_instance_method name , arg_names
raise "uups #{name}.#{name.class}" unless name.is_a?(Symbol)
clazz = Space.object_space.get_class_by_name(self.name)
raise "??? #{self.name}" unless clazz
Method.new( clazz , name , arg_names )
def create_instance_method method_name , arg_names
raise "uups #{method_name}.#{method_name.class}" unless method_name.is_a?(Symbol)
clazz = get_layout().object_class()
raise "??? #{method_name}" unless clazz
Method.new( clazz , method_name , arg_names )
end
# this needs to be done during booting as we can't have all the classes and superclassses
# instantiated. By that logic it should maybe be part of vm rather.
# On the other hand vague plans to load the hierachy from sof exist, so for now...
def set_super_class sup
@super_class = sup
self.super_class = sup
end
def get_instance_method fname
raise "uups #{fname}.#{fname.class}" unless fname.is_a?(Symbol)
#if we had a hash this would be easier. Detect or find would help too
@instance_methods.each do |m|
self.instance_methods.each do |m|
return m if(m.name == fname )
end
nil
@ -82,8 +80,8 @@ module Parfait
raise "uups #{m_name}.#{m_name.class}" unless m_name.is_a?(Symbol)
method = get_instance_method(m_name)
return method if method
if( @super_class )
method = @super_class.resolve_method(m_name)
if( self.super_class )
method = self.super_class.resolve_method(m_name)
raise "Method not found #{m_name}, for \n#{self}" unless method
end
method

View File

@ -19,11 +19,26 @@ module Parfait
def self.new *args
object = self.allocate
#HACK, but used to do the adapter in the init, bu that is too late now
object.fake_init if object.respond_to?(:fake_init) # at compile, not run-time
# have to grab the class, because we are in the ruby class not the parfait one
cl = Space.object_space.get_class_by_name( self.name.split("::").last.to_sym)
# and have to set the layout before we let the object do anything. otherwise boom
object.set_layout cl.object_layout
object.send :initialize , *args
#puts "NEW #{object.class}"
object
end
def self.attributes names
names.each{|name| attribute(name) }
end
def self.attribute name
define_method(name) { get_instance_variable(name) }
define_method("#{name}=".to_sym) { |value| set_instance_variable(name , value) }
end
def == other
self.object_id == other.object_id
end
@ -42,8 +57,8 @@ module Parfait
# data that every object carries.
def get_class()
l = get_layout()
puts "Layout #{l.class} in #{self.class} , #{self}"
l.get_object_class()
#puts "Layout #{l.class} in #{self.class} , #{self}"
l.object_class()
end
# private
@ -60,6 +75,7 @@ module Parfait
def get_layout()
l = internal_object_get(LAYOUT_INDEX)
#puts "get layout for #{self.class} returns #{l.class}"
raise "No layout #{self.object_id.to_s(16)}:#{self.class} " unless l
return l
end
@ -70,6 +86,7 @@ module Parfait
def get_instance_variable name
index = instance_variable_defined(name)
#puts "getting #{name} at #{index}"
return nil if index == nil
return internal_object_get(index)
end
@ -81,7 +98,7 @@ module Parfait
end
def instance_variable_defined name
get_layout().index_of(name)
get_layout().variable_index(name)
end
def word_length

View File

@ -22,22 +22,19 @@ module Parfait
class Space < Object
def initialize
super()
Parfait::Space.set_object_space self
@classes = Parfait::Dictionary.new
raise "Space can not be instantiated by new, you'd need a space to do so. Chicken and egg"
end
attr_reader :classes , :first_message
attributes [:classes , :first_message]
# need a two phase init for the object space (and generally parfait) because the space
# is an interconnected graph, so not everthing is ready
def late_init
message = Message.new(nil)
5.times do
@first_message = Message.new message
message.set_caller @first_message
message = @first_message
self.first_message = Message.new message
message.set_caller self.first_message
message = self.first_message
end
init_layout
end
@@object_space = nil
@ -64,8 +61,8 @@ module Parfait
# return nili if no such class. Use bang version if create should be implicit
def get_class_by_name name
raise "uups #{name}.#{name.class}" unless name.is_a?(Symbol)
c = @classes[name]
puts "MISS, no class #{name} #{name.class}" unless c # " #{@classes}"
c = self.classes[name]
#puts "MISS, no class #{name} #{name.class}" unless c # " #{self.classes}"
c
end
@ -82,7 +79,7 @@ module Parfait
def create_class name , superclass
raise "uups #{name.class}" unless name.is_a? Symbol
c = Class.new(name , superclass)
@classes[name] = c
self.classes[name] = c
end
def sof_reference_name

View File

@ -18,16 +18,6 @@ require "virtual/passes/get_implementation"
require "virtual/passes/enter_implementation"
require "virtual/passes/set_optimisation"
Sof::Volotile.add(Parfait::Object , [:memory])
Sof::Volotile.add(Parfait::Method , [:memory])
Sof::Volotile.add(Parfait::Class , [:memory])
Sof::Volotile.add(Parfait::Layout , [:memory])
Sof::Volotile.add(Parfait::Space , [:memory])
Sof::Volotile.add(Parfait::Frame , [:memory])
Sof::Volotile.add(Parfait::Message , [:memory])
Sof::Volotile.add(Parfait::BinaryCode , [:memory])
Sof::Volotile.add(Virtual::Block , [:method])
Sof::Volotile.add(Virtual::MethodSource , [:current])
class Fixnum
def fits_u8?

View File

@ -16,80 +16,114 @@ module Virtual
#
# The way out is to build empty shell objects and stuff the neccessary data into them
# (not use the normal initialize way)
#
# There are some helpers below, but the roadmap is something like:
# - create all the layouts, with thier layouts, but no classes
# - create a space by "hand" , using allocate, not new
# - create the class objects and assign them to the layouts
def boot_space
space_dict = object_with_layout Parfait::Dictionary
space_dict.keys = object_with_layout Parfait::List
space_dict.values = object_with_layout Parfait::List
@space = object_with_layout Parfait::Space
@space.classes = space_dict
Parfait::Space.set_object_space @space
end
def boot_layouts
@layouts = {}
layout_names.each do |name , ivars |
@layouts[name] = layout_for( name , ivars)
end
layout_layout = @layouts[:Layout]
@layouts.each do |name , layout |
layout.set_layout(layout_layout)
end
end
def boot_classes
# when running code instantiates a class, a layout is created automatically
# but even to get our space up, we have already instantiated all layouts
# so we have to continue and allocate classes and fill the data by hand
# and off cource we can't use space.create_class , but still they need to go there
classes = space.classes
layout_names.each do |name , vars|
cl = object_with_layout Parfait::Class
cl.object_layout = @layouts[name]
@layouts[name].object_class = cl
cl.instance_methods = object_with_layout Parfait::List
# puts "instance_methods is #{cl.instance_methods.class}"
cl.name = name
classes[name] = cl
end
object_class = classes[:Object]
# superclasses other than default object
supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module ,
:Object => :Kernel , :Kernel => :Value, :Integer => :Value }
layout_names.each do |classname , ivar|
next if classname == :Value # has no superclass
clazz = classes[classname]
super_name = supers[classname]
if super_name
clazz.set_super_class classes[super_name]
else
clazz.set_super_class object_class
end
end
end
def boot_parfait!
@space = Parfait::Space.new
# map from the vm - class_name to the Parfait class (which carries parfait name)
class_mappings = {} #will later become instance variable
values = [ :Value , :Integer , :Kernel , :Object]
value_classes = values.collect { |cl| @space.create_class(cl,nil) }
layouts = { :Word => [] ,
:List => [] ,
# Assumtion is that name is the last of message
:Message => [:next_message , :receiver , :frame , :return_address , :return_value,
:caller , :name ],
:MetaClass => [],
:BinaryCode => [],
:Space => [:classes , :first_message ],
:Frame => [:next_frame ],
:Layout => [:object_class] ,
:Class => [:object_layout ],
:Dictionary => [:keys , :values ] ,
:Method => [:name , :code ,:arg_names , :locals , :tmps ] ,
:Module => [:name , :instance_methods , :super_class , :meta_class ]
}
layouts.each do |name , layout|
class_mappings[name] = @space.create_class(name , nil)
end
value_classes[1].set_super_class( value_classes[0] ) # #set superclass (value) for integer
value_classes[2].set_super_class( value_classes[0] ) # and kernel (TODO is module)
value_classes[3].set_super_class( value_classes[2] ) # and object (TODO hacked to kernel)
class_mappings.each do |name , clazz| # and the rest
clazz.set_super_class(value_classes[3]) # superclasses are object
end
# next create layouts by adding instance variable names to the layouts
class_mappings.each do |name , clazz|
variables = layouts[name]
variables.each do |var_name|
clazz.object_layout.add_instance_variable var_name
end
end
# superclass and layout corrections
supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module }
supers.each do |classname , superclass_name|
clazz = class_mappings[classname]
super_class = class_mappings[superclass_name]
# set_super_class has no sideeffects, so setting twice ok
clazz.set_super_class super_class
# Add superclass layout too
super_class.object_layout.each do |var|
clazz.object_layout.add_instance_variable var
end
end
# now store the classes so we can hand them out later during object creation
# this can not be done earlier, as parfait objects are all the time created and would
# lookup half created class info
# but it must be done before going through the objects (next step)
@class_mappings = class_mappings
class_mappings[:Integer ] = value_classes[1] #need for further booting
class_mappings[:Kernel ] = value_classes[2] #need for further booting
class_mappings[:Object ] = value_classes[3] #need for further booting
boot_layouts
boot_space
boot_classes
@space.late_init
# add_object @space
class_mappings.values.each {|v| v.init_layout }
# now update the layout on all objects created so far,
# go through objects in space
@objects.each do | o |
o.init_layout
end
#puts Sof.write(@space)
boot_functions!
end
# helper to create a Layout, name is the parfait name, ie :Layout
def layout_for( name , ivars )
l = Parfait::Layout.allocate.fake_init
l.add_instance_variable :layout
ivars.each {|n| l.add_instance_variable n }
l
end
# create an object with layout (ie allocate it and assign layout)
# meaning the lauouts have to be booted, @layouts filled
# here we pass the actual (ruby) class
def object_with_layout(cl)
o = cl.allocate.fake_init
name = cl.name.split("::").last.to_sym
o.set_layout @layouts[name]
o
end
def layout_names
{ :Word => [] ,
:List => [] ,
# Assumtion is that name is the last of message
:Message => [:next_message , :receiver , :frame , :return_address , :return_value,
:caller , :name ],
:MetaClass => [],
:Integer => [],
:Object => [],
:Kernel => [], #fix, kernel is a class, but should be a module
:BinaryCode => [],
:Space => [:classes , :first_message ],
:Frame => [:next_frame ],
:Layout => [:object_class] ,
# TODO fix layouts for inherited classes. Currently only :Class and the
# instances are copied (shame on you)
:Class => [:object_layout , :name , :instance_methods , :super_class , :meta_class],
:Dictionary => [:keys , :values ] ,
:Method => [:name , :code ,:arg_names , :for_class, :locals , :tmps ] ,
:Module => [:name , :instance_methods , :super_class , :meta_class ]
}
end
# classes have booted, now create a minimal set of functions
# minimal means only that which can not be coded in ruby
# Methods are grabbed from respective modules by sending the method name. This should return the
@ -99,19 +133,19 @@ module Virtual
# very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we
# have to define some dummies, just for the other to compile
# TODO go through the virtual parfait layer and adjust function names to what they really are
obj = @class_mappings[:Object ]
obj = @space.get_class_by_name(:Object)
[:main , :_get_instance_variable , :_set_instance_variable].each do |f|
obj.add_instance_method Register::Builtin::Object.send(f , nil)
end
obj = @class_mappings[:Kernel ]
obj = @space.get_class_by_name(:Kernel)
# create dummy main first, __init__ calls it
[:exit,:__send , :__init__ ].each do |f|
obj.add_instance_method Register::Builtin::Kernel.send(f , nil)
end
@class_mappings[:Word].add_instance_method Register::Builtin::Word.send(:putstring , nil)
@space.get_class_by_name(:Word).add_instance_method Register::Builtin::Word.send(:putstring , nil)
obj = @class_mappings[:Integer ]
obj = @space.get_class_by_name(:Integer)
[:putint,:fibo].each do |f|
obj.add_instance_method Register::Builtin::Integer.send(f , nil)
end

View File

@ -42,7 +42,7 @@ module Virtual
def initialize
@parser = Parser::Salama.new
@passes = [ FIRST_PASS ]
@objects = []
@objects = {}
@booted = false
end
attr_reader :passes , :space , :class_mappings , :init , :objects , :booted
@ -92,8 +92,8 @@ module Virtual
# Objects are data and get assembled after functions
def add_object o
return false if @objects.include?(o)
@objects.push o
return false if @objects[o.object_id]
@objects[o.object_id] = o
true
end

View File

@ -4,25 +4,6 @@
# To stay sane, we use the same classes that we use later, but "adapt" them to work in ruby
# This affects mainly memory layout
module FakeMem
def initialize
super()
@memory = [0,nil]
@position = nil
if Virtual.machine.class_mappings
init_layout
else
#puts "No init for #{self.class}:#{self.object_id}"
end
end
def init_layout
vm_name = self.class.name.split("::").last.to_sym
clazz = Virtual.machine.class_mappings[vm_name]
raise "Class not found #{vm_name}" unless clazz
raise "Layout not set #{vm_name}" unless clazz.object_layout
self.set_layout clazz.object_layout
end
end
module Virtual
def self.new_list array
list = Parfait::List.new
@ -39,12 +20,13 @@ class Symbol
include Positioned
include Padding
def init_layout; end
def has_layout?
true
end
def get_layout
Virtual.machine.class_mappings[:Word].object_layout
l = Virtual.machine.space.classes[:Word].object_layout
puts "LL #{l.class}"
l
end
def word_length
padded to_s.length
@ -82,10 +64,15 @@ module Parfait
# but we implement it with ruby array (0 based) and use 0 as type-word
# These are the same functions that Builtin implements at run-time
class Object
include FakeMem
include Padding
include Positioned
def fake_init
@memory = [0,nil]
@position = nil
self # for chaining
end
# these internal functions are _really_ internal
# they respresent the smallest code needed to build larger functionality
# but should _never_ be used outside parfait. in fact that should be impossible
@ -108,10 +95,6 @@ module Parfait
# 1 -based index
def internal_object_set(index , value)
raise "failed init for #{self.class}" unless @memory
#shaddowing layout so we can ignore memory in Sof
if(index == LAYOUT_INDEX)
@layout = value
end
@memory[index] = value
end
def internal_object_grow(length)
@ -174,4 +157,20 @@ module Parfait
string
end
end
## sof related stuff
class Object
# parfait versions are deliberately called different, so we "relay"
# have to put the "@" on the names for sof to take them off again
def instance_variables
get_instance_variables.to_a.collect{ |n| "@#{n}".to_sym }
end
# name comes in as a ruby @var name
def instance_variable_get name
var = get_instance_variable name.to_s[1 .. -1].to_sym
puts "getting #{name} #{var}"
var
end
end
end

View File

@ -11,6 +11,7 @@ module Virtual
return if object.nil?
return unless Virtual.machine.add_object object
#puts "adding #{object.class}"
return unless object.respond_to? :has_layout?
unless object.has_layout?
object.init_layout
end
@ -19,8 +20,8 @@ module Virtual
end
layout = object.get_layout
keep layout
#puts "Layout #{layout.get_object_class.name} #{Machine.instance.objects.include?(layout)}"
layout.each do |name|
#puts "Layout #{layout.object_class.name} #{Machine.instance.objects.include?(layout)}"
layout.object_instance_names.each do |name|
inst = object.instance_variable_get "@#{name}".to_sym
keep inst
end

View File

@ -30,7 +30,7 @@ HERE
check
end
def test_string_put
def ttest_string_put
@string_input = <<HERE
"Hello again\n".putstring()
HERE

View File

@ -1,6 +1,7 @@
require_relative "../helper"
class TestDictionary < MiniTest::Test
Virtual.machine.boot #have to book, otherwise layouts etc not set
def setup
@lookup = ::Parfait::Dictionary.new