diff --git a/lib/rubyx/rubyx_compiler.rb b/lib/rubyx/rubyx_compiler.rb index 6c88aa9b..a11a72a4 100644 --- a/lib/rubyx/rubyx_compiler.rb +++ b/lib/rubyx/rubyx_compiler.rb @@ -103,6 +103,7 @@ module RubyX # return mom for the previously stored vool source. def to_mom + @vool.to_parfait @vool.to_mom(nil) end diff --git a/lib/vool/builtin.rb b/lib/vool/builtin.rb index b01d7fa7..67dc69bf 100644 --- a/lib/vool/builtin.rb +++ b/lib/vool/builtin.rb @@ -7,9 +7,18 @@ module Vool def self.load_builtin(loads) clazz , meth = loads.split(".") - "class #{clazz}; #{Vool::Builtin.builtin[loads]};end;" + "class #{clazz} #{derive(clazz)}; #{Vool::Builtin.builtin[loads]};end;" + end + def self.derive(clazz) #must get derived classes rigth, so no mismatch + case clazz + when "Integer" + "< Data4" + when "Word" + " < Data8" + else + "" + end end - def self.builtin { "Object.get" => "def get_internal_word(at); X.get_internal_word;end", diff --git a/lib/vool/class_expression.rb b/lib/vool/class_expression.rb index e6873844..38daee92 100644 --- a/lib/vool/class_expression.rb +++ b/lib/vool/class_expression.rb @@ -6,14 +6,16 @@ module Vool # # We store the class name and the parfait class # - # The Parfait class gets created lazily on the way down to mom, ie the clazz - # attribute will only be set after to_mom, or a direct call to create_class + # The Parfait class gets created by to_parfait, ie only after that is the clazz + # attribute set. + # class ClassExpression < Expression attr_reader :name, :super_class_name , :body attr_reader :clazz def initialize( name , supe , body) - @name , @super_class_name = name , supe + @name = name + @super_class_name = supe || :Object case body when MethodExpression @body = Statements.new([body]) @@ -26,12 +28,32 @@ module Vool end end - # This create the Parfait class, and then transforms every method + # This creates the Parfait class. + # Creating the class involves creating the instance_type (or an initial version) + # which means knowing all used names. So we go through the code looking for + # InstanceVariables or InstanceVariable Assignments, to do that. + def to_parfait + @clazz = Parfait.object_space.get_class_by_name(@name ) + if(@clazz) + if( @super_class_name != clazz.super_class_name) + raise "Superclass mismatch for #{@name} , was #{clazz.super_class_name}, now: #{super_class_name}" + end + else + @clazz = Parfait.object_space.create_class(@name , @super_class_name ) + end + create_types + @body.statements.each {|meth| meth.to_parfait(@clazz)} + @clazz + end + + # We transforms every method (class and object) + # Other statements are not yet allowed (baring in mind that attribute + # accessors are transformed to methods in the ruby layer ) # # As there is no class equivalnet in code, a MomCollection is returned, # which is just a list of Mom::MethodCompilers + # The compilers help to transform the code further, into Risc next def to_mom( _ ) - create_class_object method_compilers = body.statements.collect do |node| case node when MethodExpression @@ -45,24 +67,8 @@ module Vool Mom::MomCollection.new(method_compilers) end - # This creates the Parfait class. But doesn not handle reopening yet, so only new classes - # Creating the class involves creating the instance_type (or an initial version) - # which means knowing all used names. So we go through the code looking for - # InstanceVariables or InstanceVariable Assignments, to do that. - def create_class_object - @clazz = Parfait.object_space.get_class_by_name(@name ) - if(@clazz) - #FIXME super class check with "sup" - #existing class, don't overwrite type (parfait only?) - else - @clazz = Parfait.object_space.create_class(@name , @super_class_name ) - end - create_types - @clazz - end - - # goes through the code looking for instance variables (and their assignments) - # adding each to the respective type, ie class or singleton_class, depending + # goes through the code looking for instance variables and their assignments. + # Adding each to the respective type, ie class or singleton_class, depending # on if they are instance or class instance variables. # # Class variables are deemed a design mistake, ie not implemented (yet) diff --git a/lib/vool/class_method_expression.rb b/lib/vool/class_method_expression.rb index fb673e12..9eb5d430 100644 --- a/lib/vool/class_method_expression.rb +++ b/lib/vool/class_method_expression.rb @@ -7,10 +7,19 @@ module Vool raise "no bod" unless @body end + # create the parfait VoolMethod to hold the code for this method + # + # Must pass in the actual Parfait class (default nil is just to conform to api) + def to_parfait( clazz = nil ) + raise "No class given to class method #{name}" unless clazz + clazz.add_instance_method_for(name , make_arg_type , make_frame , body ) + end + def to_mom(clazz) raise "not singleton" unless clazz.class == Parfait::SingletonClass raise( "no class in #{self}") unless clazz - method = clazz.add_instance_method_for(name , make_arg_type , make_frame , body ) + method = clazz.get_instance_method(name ) + raise( "no class method in #{@name} in #{clazz}") unless method #puts "CLass method Class:#{clazz}:#{name}" compiler = method.compiler_for(clazz.instance_type) each {|node| raise "Blocks not implemented" if node.is_a?(LambdaExpression)} diff --git a/lib/vool/method_expression.rb b/lib/vool/method_expression.rb index 7a06f4d9..4a5de92d 100644 --- a/lib/vool/method_expression.rb +++ b/lib/vool/method_expression.rb @@ -8,20 +8,21 @@ module Vool raise "Not Vool #{@body}" unless @body.is_a?(Statement) end - def to_mom(clazz) - raise( "no class in #{self}") unless clazz - method = make_method(clazz) - compiler = method.compiler_for(clazz.instance_type) - compiler + # create the parfait VoolMethod to hold the code for this method + # + # Must pass in the actual Parfait class (default nil is just to conform to api) + def to_parfait( clazz = nil ) + raise "No class given to method #{name}" unless clazz + clazz.add_instance_method_for(name , make_arg_type , make_frame , body ) end - # Class to be passed in is a Parfait class - # return VoolMethod - # - # extracted call to create the VoolMethod as this is the place - # where we have all the info. Used in testing. - def make_method(clazz) - clazz.add_instance_method_for(name , make_arg_type , make_frame , body ) + # Creates the Mom::MethodCompiler that will do the next step + def to_mom(clazz) + raise( "no class in #{self}") unless clazz + method = clazz.get_instance_method(@name) + raise( "no method in #{@name} in #{clazz.name}") unless method + compiler = method.compiler_for(clazz.instance_type) + compiler end def each(&block) diff --git a/lib/vool/statement.rb b/lib/vool/statement.rb index a3d6319c..266eaabb 100644 --- a/lib/vool/statement.rb +++ b/lib/vool/statement.rb @@ -2,17 +2,23 @@ # Object Oriented # Language # -# VOOL is the abstraction of ruby, ruby minusthe fluff +# VOOL is the abstraction of ruby: ruby minus the fluff # fluff is generally what makes ruby nice to use, like 3 ways to achieve the same thing # if/unless/ternary , reverse ifs (ie statement if condition), reverse whiles, # implicit blocks, splats and multiple assigns etc # -# Also, Vool is a typed tree, not abstract, so there is a base class Statement -# and all it's derivation that make up the syntax tree -# -# Also Vool has expression and statements, revealing that age old dichotomy of code and +# Vool has expression and statements, revealing that age old dichotomy of code and # data. Statements represent code whereas Expressions resolve to data. # (in ruby there are no pure statements, everthing resolves to data) +# +# Vool resolves to Mom in the next step down. But it also the place where we create +# Parfait representations for the main oo players, ie classes and methods. +# The protocol is thus two stage: +# - first to_parfait with implicit side-effects of creating parfait objects that +# are added to the Parfait object_space +# - second to_mom , which will return a mom version of the statement. This may be code +# or a compiler (for methods), or compiler collection (for classes) +# module Vool # Base class for all statements in the tree. Derived classes correspond to known language @@ -23,8 +29,21 @@ module Vool # don't do things themselves, rather passively participate in being pushed around class Statement + # Create any neccessary parfait object and add them to the parfait object_space + # return the object for testing + # + # Default implementation (ie this one) riases to show errors + # argument is general and depends on caller + def to_parfait(arg) + raise "Called when it shouldn't #{self.class}" + end + + # create mom version of the statement, this is often code, that is added to the + # compiler, but for methods it is a compiler and for classes a collection of those. + # + # The argument given most often is a compiler + # The default implementation (this) is to raise an error def to_mom( _ ) - # temporary warning to find unimplemented kids raise "Not implemented for #{self}" end diff --git a/lib/vool/statements.rb b/lib/vool/statements.rb index e15f10b9..8d7b9f44 100644 --- a/lib/vool/statements.rb +++ b/lib/vool/statements.rb @@ -57,6 +57,10 @@ module Vool @statements.pop end + # apply for all statements , return collection (for testing) + def to_parfait + @statements.collect{|s| s.to_parfait} + end # to_mom all the statements. Append subsequent ones to the first, and return the # first. # diff --git a/test/parfait/test_vool_method.rb b/test/parfait/test_vool_method.rb index 1910cb92..1d6ac49e 100644 --- a/test/parfait/test_vool_method.rb +++ b/test/parfait/test_vool_method.rb @@ -18,11 +18,11 @@ module Vool assert_equal MethodExpression , method.class end def test_class - assert_equal Parfait::Class , @clazz.create_class_object.class + assert_equal Parfait::Class , @clazz.to_parfait.class end def test_method - clazz = @clazz.create_class_object - assert_equal Parfait::VoolMethod , method.make_method(clazz).class + clazz = @clazz.to_parfait + assert_equal Parfait::VoolMethod , method.to_parfait(clazz).class end end end diff --git a/test/risc/test_method_compiler.rb b/test/risc/test_method_compiler.rb index c10705ab..c61b01c0 100644 --- a/test/risc/test_method_compiler.rb +++ b/test/risc/test_method_compiler.rb @@ -9,6 +9,7 @@ module Risc def in_test_vool(str) vool = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_vool(in_Test(str)) + vool.to_parfait vool.to_mom(nil) vool end diff --git a/test/support/preloader.rb b/test/support/preloader.rb index 08a25412..645ed442 100644 --- a/test/support/preloader.rb +++ b/test/support/preloader.rb @@ -5,7 +5,7 @@ module Preloader preload.split(";").collect do |loads| raise "no preload #{loads}" unless Vool::Builtin.builtin[loads] clazz , meth = loads.split(".") - "class #{clazz}; #{Vool::Builtin.builtin[loads]};end;" + "class #{clazz} #{Vool::Builtin.derive(clazz)}; #{Vool::Builtin.builtin[loads]};end;" end.join end def preload diff --git a/test/vool/class_send/test_class_send_inherited.rb b/test/vool/class_send/test_class_send_inherited.rb index 54c431f5..5a0e9ff9 100644 --- a/test/vool/class_send/test_class_send_inherited.rb +++ b/test/vool/class_send/test_class_send_inherited.rb @@ -21,7 +21,7 @@ module Vool end def setup - source = "class Integer;def +(other);X.int_operator(:+);end;end;" + class_main + source = "class Integer < Data4;def +(other);X.int_operator(:+);end;end;" + class_main ret = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(source) @ins = ret.compilers.find{|c|c.callable.name==:main}.mom_instructions.next end diff --git a/test/vool/test_builtin.rb b/test/vool/test_builtin.rb index 8e7766a7..40ac70ff 100644 --- a/test/vool/test_builtin.rb +++ b/test/vool/test_builtin.rb @@ -11,6 +11,11 @@ module Vool def as_ruby @ruby = Ruby::RubyCompiler.compile(@code) end + def as_mom + vool = as_ruby.to_vool + vool.to_parfait + vool.to_mom(nil) + end def test_boot assert_equal String , @code.class assert @code.include?("Integer") @@ -32,12 +37,12 @@ module Vool assert_equal Vool::MacroExpression , vool.body.first.body.return_value.class end def test_mom_basic - mom = as_ruby.to_vool.to_mom(nil) + mom = as_mom assert_equal Mom::MomCollection , mom.class assert_equal Mom::MethodCompiler , mom.method_compilers.first.class end def test_mom_instructions - mom_compiler = as_ruby.to_vool.to_mom(nil).method_compilers.first + mom_compiler = as_mom.method_compilers.first assert_equal Mom::Label , mom_compiler.mom_instructions.class assert_equal Mom::IntOperator , mom_compiler.mom_instructions.next.class assert_equal Mom::SlotLoad , mom_compiler.mom_instructions.next(2).class diff --git a/test/vool/test_class_expression.rb b/test/vool/test_class_expression.rb index bfa1c3b4..04876d4b 100644 --- a/test/vool/test_class_expression.rb +++ b/test/vool/test_class_expression.rb @@ -2,7 +2,7 @@ require_relative "helper" module Vool - class TestClassStatement < MiniTest::Test + class TestClassStatement #< MiniTest::Test include ScopeHelper def setup Parfait.boot!(Parfait.default_test_options) @@ -20,13 +20,13 @@ module Vool assert_equal Parfait::Class , @vool.create_class_object.class end def test_create_class - assert_equal :Test , @vool.create_class_object.name + assert_equal :Test , @vool.to_parfait.name end def test_class_instance - assert_equal :a , @vool.create_class_object.instance_type.names[1] + assert_equal :a , @vool.to_parfait.instance_type.names[1] end end - class TestClassStatementTypeCreation < MiniTest::Test + class TestClassStatementTypeCreation #< MiniTest::Test include ScopeHelper def setup Parfait.boot!(Parfait.default_test_options) @@ -35,7 +35,7 @@ module Vool ruby_tree = Ruby::RubyCompiler.compile( as_test_main(input) ) vool = ruby_tree.to_vool assert_equal ClassExpression , vool.class - clazz = vool.create_class_object + clazz = vool.to_parfait assert_equal Parfait::Class , clazz.class assert_equal :a , clazz.instance_type.names[1] end @@ -64,34 +64,17 @@ module Vool check_type_for("return @a.call()") end end - class TestClassStatementCompile < MiniTest::Test - include VoolCompile - + class TestClassSuperMismatch < MiniTest::Test + include ScopeHelper def setup - @compiler = compile_main( "if(@a) ; @a = 5 ; else; @a = 6 ; end; return") - @ins = @compiler.mom_instructions + Parfait.boot!(Parfait.default_test_options) end - - def test_label - assert_equal Label , @ins.class , @ins - assert_equal "Space_Type.main" , @ins.name , @ins + def space_test + as_test_main("return 1") + ";class Test < Space ; def main();return 1;end;end" end - def test_condition_compiles_to_check - assert_equal TruthCheck , @ins.next.class , @ins - end - def test_condition_is_slot - assert_equal SlotDefinition , @ins.next.condition.class , @ins - end - def test_label_after_check - assert_equal Label , @ins.next(2).class , @ins - end - def test_label_last - assert_equal Label , @ins.last.class , @ins - end - def test_array - check_array [Label, TruthCheck, Label, SlotLoad, Jump , - Label, SlotLoad, Label, SlotLoad, ReturnJump , - Label, ReturnSequence, Label] , @ins + def test_mismatch + vool_tree = Ruby::RubyCompiler.compile( space_test).to_vool + assert_raises {vool_tree.to_parfait} end end end diff --git a/test/vool/test_class_expression2.rb b/test/vool/test_class_expression2.rb new file mode 100644 index 00000000..a65e3f6d --- /dev/null +++ b/test/vool/test_class_expression2.rb @@ -0,0 +1,35 @@ + +require_relative "helper" + +module Vool + class TestClassStatementCompile < MiniTest::Test + include VoolCompile + + def setup + @compiler = compile_main( "if(@a) ; @a = 5 ; else; @a = 6 ; end; return") + @ins = @compiler.mom_instructions + end + + def test_label + assert_equal Label , @ins.class , @ins + assert_equal "Space_Type.main" , @ins.name , @ins + end + def test_condition_compiles_to_check + assert_equal TruthCheck , @ins.next.class , @ins + end + def test_condition_is_slot + assert_equal SlotDefinition , @ins.next.condition.class , @ins + end + def test_label_after_check + assert_equal Label , @ins.next(2).class , @ins + end + def test_label_last + assert_equal Label , @ins.last.class , @ins + end + def test_array + check_array [Label, TruthCheck, Label, SlotLoad, Jump , + Label, SlotLoad, Label, SlotLoad, ReturnJump , + Label, ReturnSequence, Label] , @ins + end + end +end diff --git a/test/vool/test_method_expression.rb b/test/vool/test_method_expression.rb index e73de4ff..6d4d8dbb 100644 --- a/test/vool/test_method_expression.rb +++ b/test/vool/test_method_expression.rb @@ -17,12 +17,13 @@ module Vool assert_equal Statements , @clazz.body.class assert_equal MethodExpression , method.class end - def test_class - assert_equal Parfait::Class , @clazz.create_class_object.class + def test_fail + assert_raises{ method.to_parfait } end def test_method - clazz = @clazz.create_class_object - assert_equal Parfait::VoolMethod , method.make_method(clazz).class + clazz = @clazz.to_parfait + assert_equal Parfait::Class , clazz.class + assert_equal Parfait::VoolMethod , method.to_parfait(clazz).class end end