From 1d2ec8e8acc482880268b3c45153bfa517135dd4 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Mon, 30 Jul 2018 14:45:37 +0300 Subject: [PATCH] abstract CallStatement base class, just like in ruby to_mom differs much more than the to_vool in ruby, but data and base functionality still warrent unification also we can check for CallStatement now --- lib/vool/call_statement.rb | 31 ++++++++++++++++++++++++++ lib/vool/send_statement.rb | 24 +++----------------- lib/vool/statement.rb | 1 + lib/vool/yield_statement.rb | 44 ++++++++++--------------------------- 4 files changed, 46 insertions(+), 54 deletions(-) create mode 100644 lib/vool/call_statement.rb diff --git a/lib/vool/call_statement.rb b/lib/vool/call_statement.rb new file mode 100644 index 00000000..7da70c6d --- /dev/null +++ b/lib/vool/call_statement.rb @@ -0,0 +1,31 @@ +module Vool + + class CallStatement < Statement + attr_reader :name , :receiver , :arguments + + def initialize(name , receiver , arguments ) + @name , @receiver , @arguments = name , receiver , arguments + @arguments ||= [] + end + + # 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) + Mom::SlotDefinition.new(:message ,[ :return_value]) + end + + def to_s(depth = 0) + sen = "#{receiver}.#{name}(#{@arguments.collect{|a| a.to_s}.join(', ')})" + at_depth(depth , sen) + end + + def each(&block) + block.call(self) + block.call(@receiver) + @arguments.each do |arg| + block.call(arg) + end + end + + end +end diff --git a/lib/vool/send_statement.rb b/lib/vool/send_statement.rb index feca3bf6..e0336fd6 100644 --- a/lib/vool/send_statement.rb +++ b/lib/vool/send_statement.rb @@ -9,13 +9,8 @@ module Vool # # As cache key we must use the type of the object (which is the first word of _every_ object) # as that is constant, and function implementations depend on the type (not class) - class SendStatement < Statement - attr_reader :name , :receiver , :arguments , :block - - def initialize(name , receiver , arguments ) - @name , @receiver , @arguments = name , receiver , arguments - @arguments ||= [] - end + class SendStatement < CallStatement + attr_reader :block def block return nil if arguments.empty? @@ -27,15 +22,8 @@ module Vool @arguments << block end - def to_s - "#{receiver}.#{name}(#{arguments.join(', ')})" - end def each(&block) - block.call(self) - block.call(@receiver) - @arguments.each do |arg| - block.call(arg) - end + super self.block.each(&block) if self.block end @@ -56,12 +44,6 @@ module Vool end end - # 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) - Mom::SlotDefinition.new(:message ,[ :return_value]) - end - def message_setup(compiler,called_method) setup = Mom::MessageSetup.new( called_method ) mom_receive = @receiver.slot_definition(compiler) diff --git a/lib/vool/statement.rb b/lib/vool/statement.rb index bc233131..2b5d350f 100644 --- a/lib/vool/statement.rb +++ b/lib/vool/statement.rb @@ -65,6 +65,7 @@ require_relative "assignment" require_relative "array_statement" require_relative "basic_values" require_relative "block_statement" +require_relative "call_statement" require_relative "class_statement" require_relative "hash_statement" require_relative "if_statement" diff --git a/lib/vool/yield_statement.rb b/lib/vool/yield_statement.rb index d1a6c995..3aa8a0c6 100644 --- a/lib/vool/yield_statement.rb +++ b/lib/vool/yield_statement.rb @@ -1,34 +1,17 @@ module Vool - class YieldStatement < Statement - attr_reader :arguments + # A Yield is a lot like a Send, which is why they share the base class CallStatement + # That means it has a receiver (self), arguments and an (implicitly assigned) name + # + # On the ruby side, normalisation works pretty much the same too. + # + # On the way down to Mom, small differences become abvious, as the block that is + # yielded to is an argument. Whereas in a send it is either statically known + # or resolved and cached. Here it is dynamic, but sort of known dynamic. + # All we do before calling it is check that it is the right type. + class YieldStatement < CallStatement - def initialize(name , receiver , arguments) - @arguments = arguments - @receiver = receiver - @name = name - @arguments ||= [] - end - - def to_s - "#{receiver}.#{name}(#{arguments.join(', ')})" - end - - def each(&block) - block.call(self) - block.call(@receiver) - @arguments.each do |arg| - block.call(arg) - end - end - - # 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) - Mom::SlotDefinition.new(:message ,[ :return_value]) - end - - # A Send breaks down to 2 steps: + # A Yield breaks down to 2 steps: # - Setting up the next message, with receiver, arguments, and (importantly) return address # - a SimpleCall, def to_mom( compiler ) @@ -76,10 +59,5 @@ module Vool setup << Mom::BlockYield.new( arg_index ) end - def to_s(depth = 0) - sen = "#{receiver}.#{name}(#{@arguments.collect{|a| a.to_s}.join(', ')})" - at_depth(depth , sen) - end - end end