From 7056f6f05c94c12739e23a587800317a2b4c2f7e Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Tue, 20 May 2014 11:03:18 +0300 Subject: [PATCH] first step of assignment magic --- lib/vm/block.rb | 36 +++++++++++++++++++++++++++------- lib/vm/values.rb | 5 ++++- test/arm/test_small_program.rb | 20 +++++++++---------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/lib/vm/block.rb b/lib/vm/block.rb index 85f72415..1c551ca8 100644 --- a/lib/vm/block.rb +++ b/lib/vm/block.rb @@ -63,8 +63,15 @@ module Vm end end - def at where - @current = where + # to use the assignment syntax (see method_missing) the scope must be set, so variables can be resolved + # The scope you set should be a binding (literally, the kernel.binding) + # The function return the block, so it can be chained into an assignment + # Example (coding a function ) and having variable int defined + # b = function.body.scope(binding) + # b.int = 5 will create a mov instruction to set the register that int points to + def scope where + @scope = where + self end # set the next executed block after self. # why is this useful? if it's unconditional, why not merge them: @@ -74,12 +81,27 @@ module Vm @next = block end - # sugar to create instructions easily. Any method with one arg is sent to the machine and the result - # (hopefully an instruction) added as code + # sugar to create instructions easily. Actually just got double sweet with two versions: + # 1 for any method that ends in = we evaluate the method name in the current scope (see scope()) + # for the result we call assign with the right value. The resulting instruction is added to + # the block. + # Thus we emulate assignment, + # Example: block b + # b.variable = value looks like what it does, but actually generates + # an instruction for the block (mov or add) + # + # 2- any other method will be passed on to the CMachine and the result added to the block + # With this trick we can write what looks like assembler, + # Example b.instance_eval + # mov( r1 , r2 ) + # add( r1 , r2 , 4) + # end + # mov and add will be called on Machine and generate Inststuction that are then added + # to the block def method_missing(meth, *args, &block) - if( meth.to_s[-1] == "=") - val = @current.eval meth.to_s[0 ... -1] - raise "hallo #{val}" + if( meth.to_s[-1] == "=" && args.length == 1) + l_val = @scope.eval meth.to_s[0 ... -1] + add_code l_val.asign(args[0]) end add_code CMachine.instance.send(meth , *args) end diff --git a/lib/vm/values.rb b/lib/vm/values.rb index 8e4d6e20..f2c0724b 100644 --- a/lib/vm/values.rb +++ b/lib/vm/values.rb @@ -48,7 +48,10 @@ module Vm attr_accessor :register def inspect - self.class.name + ":reg:#{register}:" + self.class.name + "(r#{register})" + end + def to_s + inspect end def initialize reg @register = reg diff --git a/test/arm/test_small_program.rb b/test/arm/test_small_program.rb index f9b29820..1e88099e 100644 --- a/test/arm/test_small_program.rb +++ b/test/arm/test_small_program.rb @@ -13,17 +13,17 @@ class TestSmallProg < MiniTest::Test end def test_loop - @program.main.instance_eval do - mov :r0, 5 #1 - start = Vm::Block.new("start") - add_code start - start.instance_eval do - sub :r0, :r0, 1 , :update_status => 1 #2 - bne start ,{} #3 - end + start = Vm::Block.new("start") + m = @program.main.scope binding + r0 = Vm::Integer.new(0) + m.r0 = 5 #1 + m.add_code start + start.instance_eval do + sub :r0, :r0, 1 , :update_status => 1 #2 + bne start #3 end @should = [0,176,160,227,5,0,160,227,1,0,80,226,253,255,255,26,1,112,160,227,0,0,0,239] - write( 6 , "loop" ) + write "loop" end def test_hello @@ -60,7 +60,7 @@ class TestSmallProg < MiniTest::Test def write name writer = Elf::ObjectWriter.new(@program , Elf::Constants::TARGET_ARM) assembly = writer.text - puts assembly + # use this for getting the bytes to compare to : puts assembly assembly.text.bytes.each_with_index do |byte , index| assert_equal byte , @should[index] , "byte #{index}" end