From 04720d4950b5846f6df338ac405b0c9fc4a17105 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Wed, 6 Mar 2019 11:21:09 +0200 Subject: [PATCH] implement attr setter correctly part of #25 still need to do for list and attr_reader --- lib/ruby/class_statement.rb | 39 +++++++++++++++++++++++++++---- test/ruby/test_class_statement.rb | 35 +++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/lib/ruby/class_statement.rb b/lib/ruby/class_statement.rb index 2f6a2d93..a6152302 100644 --- a/lib/ruby/class_statement.rb +++ b/lib/ruby/class_statement.rb @@ -2,6 +2,8 @@ module Ruby class ClassStatement < Statement attr_reader :name, :super_class_name , :body + # init with the class name, super class name and statement body + # body must be Method or Send (See to_vool) or empty/nil (possibly not handled right) def initialize( name , supe , body) @name , @super_class_name = name , supe case body @@ -16,21 +18,50 @@ module Ruby end end + # Create equivalent vool objects. Mostly for method statements + # For calls, call transform_statement, see there def to_vool - meths = body.statements.collect do |meth| - meth.is_a?(MethodStatement) ? meth.to_vool : tranform_statement(meth) + meths = [] + body.statements.each do |meth| + if( meth.is_a?(MethodStatement)) + meths << meth.to_vool + else + meths += transform_statement(meth) + end end Vool::ClassStatement.new(@name , @super_class_name, Vool::Statements.new(meths) ) end - def tranform_statement( class_send ) + # We rewrite certain send statements (so raise error for all else) + # Currently only attributes (ie attr :name) supported, for which the standard getter + # and setter is created and returned as vool + def transform_statement( class_send ) unless class_send.is_a?(SendStatement) raise "Other than methods, only class methods allowed, not #{class_send.class}" end unless class_send.name == :attr raise "Only remapping attr and cattr, not #{class_send.name}" end - raise "todo" + attr = class_send.arguments.first.value + [ getter_for(attr) , setter_for(attr) ] + end + + # creates a getter method for the given instance name (sym) + # The Method is created in Ruby, and to_vool is called to transform to Vool + # The standard getter obviously only returns the ivar + def getter_for(instance_name) + return_statement = ReturnStatement.new(InstanceVariable.new(instance_name)) + MethodStatement.new(instance_name , [] , return_statement).to_vool + end + + # creates a setter method (name=) for the given instance name (sym) + # The Method is created in Ruby, and to_vool is called to transform to Vool + # The setter method assigns the incoming value and returns the ivar + def setter_for(instance_name) + assign = IvarAssignment.new(instance_name , LocalVariable.new(:val)) + return_statement = ReturnStatement.new(InstanceVariable.new(instance_name)) + statements = Statements.new([assign, return_statement]) + MethodStatement.new("#{instance_name}=".to_sym , [:val] , statements).to_vool end def to_s(depth = 0) diff --git a/test/ruby/test_class_statement.rb b/test/ruby/test_class_statement.rb index 229fb0ad..e0307d95 100644 --- a/test/ruby/test_class_statement.rb +++ b/test/ruby/test_class_statement.rb @@ -81,19 +81,44 @@ module Ruby input = "class Tryout < Base;attr :page ;end" @vool = compile( input ).to_vool end + def getter + @vool.body.statements.first + end + def setter + @vool.body.statements.last + end def test_class assert_equal Vool::ClassStatement , @vool.class end def test_body assert_equal Vool::Statements , @vool.body.class end - def test_compile_class_name - assert_equal :Tryout , @vool.name + def test_getter + assert_equal Vool::MethodStatement , getter.class end - def test_compile_class_super - assert_equal :Base , @vool.super_class_name + def test_getter_return + assert_equal Vool::ReturnStatement , getter.body.class + end + def test_getter_name + assert_equal :page , getter.name + end + def test_setter + assert_equal Vool::MethodStatement , setter.class + end + def test_setter_assign + assert_equal Vool::Statements , setter.body.class + assert_equal Vool::IvarAssignment , setter.body.first.class + end + def test_setter_return + assert_equal Vool::Statements , setter.body.class + assert_equal Vool::ReturnStatement , setter.body.last.class + end + def test_setter_name + assert_equal :page= , setter.name + end + def test_setter_args + assert_equal [:val] , setter.args end - end end