diff --git a/lib/ruby/call_statement.rb b/lib/ruby/call_statement.rb index 5826ed17..3675a342 100644 --- a/lib/ruby/call_statement.rb +++ b/lib/ruby/call_statement.rb @@ -1,5 +1,14 @@ module Ruby + # A CallStatement is the abstraction of Send and Yield. The two are really + # much more similar than different. + # + # A CallStatement has a name, receiver and arguments + # + # Using the "vool_brother" we can create the right Vool class for it. + # Arguments in vool must be simple, so any complex expressions get + # hoisted and assigned to temporary variables. + # class CallStatement < Statement attr_reader :name , :receiver , :arguments diff --git a/lib/ruby/if_statement.rb b/lib/ruby/if_statement.rb index 4d9f4f01..f1377720 100644 --- a/lib/ruby/if_statement.rb +++ b/lib/ruby/if_statement.rb @@ -1,6 +1,15 @@ require_relative "normalizer" module Ruby + # The if must have condition and a true branch, the false is optional + # + # It maps pretty much one to one to a Vool, except for "hoisting" + # + # Ruby may have super complex expressions as the condition, whereas + # Vool may not. Ie of a Statement list all but the last are hoisted to before + # the vool if. This is equivalent, just easier to compile later + # + # The hoisintg code is in Normalizer, as it is also useed in return and while class IfStatement < Statement include Normalizer @@ -28,8 +37,8 @@ module Ruby end def to_s(depth = 0) - parts = ["if (#{@condition})" , @body.to_s(depth + 1) ] - parts += ["else" , "@if_false.to_s(depth + 1)"] if(@false) + parts = ["if(#{@condition})" , @if_true.to_s(depth + 1) ] + parts += ["else" , @if_false.to_s(depth + 1)] if(@if_false) parts << "end" at_depth(depth , *parts ) end diff --git a/lib/ruby/send_statement.rb b/lib/ruby/send_statement.rb index 45d7348c..f9550b26 100644 --- a/lib/ruby/send_statement.rb +++ b/lib/ruby/send_statement.rb @@ -1,5 +1,8 @@ module Ruby - + # Send and yield are very very similar, so they have a base class CallStatement + # + # The SendStatement really only provides to_s, so see CallStatement + # class SendStatement < CallStatement def to_s "#{receiver}.#{name}(#{arguments.join(', ')})" diff --git a/lib/ruby/statement.rb b/lib/ruby/statement.rb index c34261eb..ef8efb14 100644 --- a/lib/ruby/statement.rb +++ b/lib/ruby/statement.rb @@ -7,17 +7,26 @@ module Ruby # class Statement + # Many statements exist in the vool layer in quite a similar arrangement + # Especially for different types of assignment we can abstract the creation + # of the vool, by using the right class to instantiate, the "vool_brother" + # Ie same class_name, but in the Vool module + def vool_brother + eval "Vool::#{class_name}" + end + + # return the class name without the module + # used to evaluate the vool_brother + def class_name + self.class.name.split("::").last + end + + # helper method for formatting source code + # depth is the depth in the tree (os the ast) + # and the string are the ones to be indented (2 spaces) def at_depth(depth , *strings) prefix = " " * 2 * depth strings.collect{|str| prefix + str}.join("\n") end - - def vool_brother - eval "Vool::#{class_name}" - end - def class_name - self.class.name.split("::").last - end end - end diff --git a/lib/ruby/yield_statement.rb b/lib/ruby/yield_statement.rb index 05d3c6ea..0ef4f2c5 100644 --- a/lib/ruby/yield_statement.rb +++ b/lib/ruby/yield_statement.rb @@ -1,7 +1,14 @@ module Ruby + # Send and yield are very very similar, so they have a base class CallStatement + # + # The YieldStatement really only provides to_s, and has slightly + # different constructor. See CallStatement + # class YieldStatement < CallStatement + # We give the instance of the yield and auto generated name + # Also, a yield is always (for now) on self def initialize(arguments) super("yield_#{object_id}".to_sym , SelfExpression.new , arguments) end diff --git a/lib/vool/basic_values.rb b/lib/vool/basic_values.rb index fff84829..a65ef96b 100644 --- a/lib/vool/basic_values.rb +++ b/lib/vool/basic_values.rb @@ -1,16 +1,18 @@ module Vool + #Marker class for different constants class Constant < Expression #gobble it up def each(&block) end end + # An integer at the vool level class IntegerConstant < Constant attr_reader :value def initialize(value) @value = value end - def slot_definition(compiler) + def slot_definition(_) return Mom::SlotDefinition.new(Mom::IntegerConstant.new(@value) , []) end def ct_type @@ -22,6 +24,7 @@ module Vool def each(&block) end end + # An float at the vool level class FloatConstant < Constant attr_reader :value def initialize(value) @@ -30,40 +33,48 @@ module Vool def ct_type true end + def to_s + value.to_s + end end + # True at the vool level class TrueConstant < Constant def ct_type Parfait.object_space.get_type_by_class_name(:True) end - def slot_definition(compiler) + def slot_definition(_) return Mom::SlotDefinition.new(Parfait.object_space.true_object , []) end def to_s(depth = 0) "true" end end + # False at the vool level class FalseConstant < Constant def ct_type Parfait.object_space.get_type_by_class_name(:False) end - def slot_definition(compiler) + def slot_definition(_) return Mom::SlotDefinition.new(Parfait.object_space.false_object , []) end def to_s(depth = 0) "false" end end + # Nil at the vool level class NilConstant < Constant def ct_type Parfait.object_space.get_type_by_class_name(:Nil) end - def slot_definition(compiler) + def slot_definition(_) return Mom::SlotDefinition.new(Parfait.object_space.nil_object , []) end def to_s(depth = 0) "nil" end end + + # Self at the vool level class SelfExpression < Expression attr_reader :my_type def initialize(type = nil) @@ -90,7 +101,7 @@ module Vool def initialize(value) @value = value end - def slot_definition(compiler) + def slot_definition(_) return Mom::SlotDefinition.new(Mom::StringConstant.new(@value),[]) end def ct_type diff --git a/lib/vool/call_statement.rb b/lib/vool/call_statement.rb index 7da70c6d..fc5ca5ab 100644 --- a/lib/vool/call_statement.rb +++ b/lib/vool/call_statement.rb @@ -10,7 +10,7 @@ module Vool # When used as right hand side, this tells what data to move to get the result into # a varaible. It is (off course) the return value of the message - def slot_definition(compiler) + def slot_definition(_) Mom::SlotDefinition.new(:message ,[ :return_value]) end diff --git a/lib/vool/variables.rb b/lib/vool/variables.rb index 7ef13adb..42c94fa1 100644 --- a/lib/vool/variables.rb +++ b/lib/vool/variables.rb @@ -21,7 +21,7 @@ module Vool class InstanceVariable < Expression include Named - def slot_definition(compiler) + def slot_definition(_) Mom::SlotDefinition.new(:message , [ :receiver , @name] ) end # used to collect type information diff --git a/test/ruby/test_basic_values.rb b/test/ruby/test_basic_values.rb index b08c5609..92d10616 100644 --- a/test/ruby/test_basic_values.rb +++ b/test/ruby/test_basic_values.rb @@ -60,6 +60,9 @@ module Ruby def test_integer assert_equal IntegerConstant , compile_const( "123") end + def test_float + assert_equal FloatConstant , compile_const( "123.1") + end def test_string assert_equal StringConstant , compile_const( "'string'") end @@ -76,4 +79,36 @@ module Ruby assert_equal TrueConstant , compile_const( "true") end end + class TestBasicTypesVool < MiniTest::Test + include RubyTests + + def setup + Parfait.boot! + end + def compile_const( input ) + lst = compile( input ) + lst.to_vool.to_s + end + def test_integer + assert_equal "123" , compile_const( "123") + end + def test_float + assert_equal "123.0" , compile_const( "123.0") + end + def test_string + assert_equal "'string'" , compile_const( "'string'") + end + def test_sym + assert_equal "'symbol'" , compile_const( ":symbol") + end + def test_nil + assert_equal "nil" , compile_const( "nil") + end + def test_false + assert_equal "false" , compile_const( "false") + end + def test_true + assert_equal "true" , compile_const( "true") + end + end end diff --git a/test/ruby/test_if_statement.rb b/test/ruby/test_if_statement.rb index faa47ab7..b4fb45a5 100644 --- a/test/ruby/test_if_statement.rb +++ b/test/ruby/test_if_statement.rb @@ -37,5 +37,9 @@ module Ruby assert_equal TrueConstant , lst.if_true.class assert_equal FalseConstant, lst.if_false.class end + def test_to_s + lst = compile( double_if ) + assert_equal "if(false);true;else;false;end" , lst.to_s.gsub("\n",";") + end end end diff --git a/test/ruby/test_send_statement.rb b/test/ruby/test_send_statement.rb index ebb3963e..ae490f4e 100644 --- a/test/ruby/test_send_statement.rb +++ b/test/ruby/test_send_statement.rb @@ -18,6 +18,9 @@ module Ruby def test_simple_args assert_equal [] , @lst.arguments end + def test_tos + assert_equal "self.foo()" , @lst.to_s + end end class TestSendBar < MiniTest::Test include RubyTests diff --git a/test/ruby/test_yield_statement.rb b/test/ruby/test_yield_statement.rb index be53a5fb..11664447 100644 --- a/test/ruby/test_yield_statement.rb +++ b/test/ruby/test_yield_statement.rb @@ -28,5 +28,8 @@ module Ruby def test_block_args assert_equal IntegerConstant , @lst.arguments.first.class end + def test_tos + assert_equal "yield(0)" , @lst.to_s + end end end