diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index 5edd6adc..8e6d7020 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -11,10 +11,24 @@ module Ast function = context.program.get_or_create_function(name) raise "Forward declaration not implemented (#{name}) #{inspect}" if function == nil call = Vm::CallSite.new( name , params , function) + save_locals context , into call.load_args into call.do_call into + resore_locals context , into end - + + def save_locals context , into + into.instance_eval do + push [:r0, :r1 , :r2] + end + end + + def resore_locals context , into + into.instance_eval do + pop [:r0, :r1 , :r2] + end + end + def inspect self.class.name + ".new(" + name.inspect + ", ["+ args.collect{|m| m.inspect }.join( ",") +"] )" diff --git a/lib/ast/operator_expressions.rb b/lib/ast/operator_expressions.rb index d07ed818..ec185e25 100644 --- a/lib/ast/operator_expressions.rb +++ b/lib/ast/operator_expressions.rb @@ -18,6 +18,7 @@ module Ast def compile context , into puts "compile operator #{to_s}" r_val = right.compile(context , into) + puts "compiled right #{r_val.inspect}" if operator == "=" # assignment, value based raise "Can only assign variables, not #{left}" unless left.is_a?(NameExpression) l_val = context.locals[left.name] @@ -38,7 +39,9 @@ module Ast code = l_val.less_or_equal into , r_val when "+" res = Vm::Integer.new(context.function.next_register) - code = res.plus into , l_val , r_val + into.add_code res.is l_val + r_val +# code = res.plus into , l_val , r_val + code = res when "-" res = Vm::Integer.new(context.function.next_register) code = res.minus into , l_val , r_val diff --git a/lib/core/kernel.rb b/lib/core/kernel.rb index dc78956d..75feb7e2 100644 --- a/lib/core/kernel.rb +++ b/lib/core/kernel.rb @@ -23,8 +23,8 @@ module Core #TODO this is in the wrong place. It is a function that returns a function object # while all other methods add their code into some block. --> kernel - def putstring context - function = Vm::Function.new(:putstring , [Vm::Integer , Vm::Integer ] ) + def putstring context , string = Vm::Integer , length = Vm::Integer + function = Vm::Function.new(:putstring , [string , length ] , string) block = function.body # should be another level of indirection, ie write(io,str) ret = Vm::CMachine.instance.write_stdout(block) @@ -32,16 +32,16 @@ module Core function end - def putint context - function = Vm::Function.new(:putint , [Vm::Integer , Vm::Integer ] ) - block = function.body + def putint context , arg = Vm::Integer + arg = Vm::Integer.new( 0 ) + function = Vm::Function.new(:putint , [arg ] , arg ) buffer = Vm::StringConstant.new(" ") context.program.add_object buffer - str_addr = Vm::Integer.new(0) # address of the + str_addr = Vm::Integer.new(1) context.str_addr = str_addr - reg1 = Vm::Integer.new(1) + reg1 = Vm::Integer.new(2) itos_fun = context.program.get_or_create_function(:utoa) - block.instance_eval do + function.body.instance_eval do mov( reg1 , str_addr ) #move arg up add( str_addr , buffer ,nil ) # string to write to add( str_addr , str_addr , (buffer.length-3)) @@ -50,7 +50,7 @@ module Core add( str_addr , buffer , nil ) # string to write to mov( reg1 , buffer.length ) end - ret = Vm::CMachine.instance.write_stdout(block) + ret = Vm::CMachine.instance.write_stdout(function.body) function end diff --git a/test/runners/fibo_while.rb b/test/runners/fibo_while.rb index 6dccce9a..399f0aa5 100644 --- a/test/runners/fibo_while.rb +++ b/test/runners/fibo_while.rb @@ -5,10 +5,9 @@ def fibonaccit(n) # n == r0 tmp = a # r3 <- r1 a = b # r1 <- r2 b = tmp + b # r4 = r2 + r3 (r4 transient) r2 <- r4 - tmp = putint(b) - putstring(tmp) - n = n - 1 # r2 <- 0 ???? #call ok - end #r5 <- r0 - 1 # r0 <- r5 -end + putint(b) + n = n - 1 # r0 <- r2 for call, #call ok + end #r5 <- r0 - 1 n=n-1 through r5 tmp +end # r0 <- r5 fibonaccit( 10 ) diff --git a/test/test_runner.rb b/test/test_runner.rb index 9e694d91..a687da02 100644 --- a/test/test_runner.rb +++ b/test/test_runner.rb @@ -22,6 +22,7 @@ class TestRunner < MiniTest::Test parser = Parser::Crystal.new program = Vm::Program.new "Arm" syntax = parser.parse_with_debug(string) + assert syntax parts = Parser::Transform.new.apply(syntax) # file is a list of expressions, all but the last must be a function # and the last is wrapped as a main @@ -37,7 +38,7 @@ class TestRunner < MiniTest::Test program.link_at( 0 , program.context ) binary = program.assemble(StringIO.new ) - + assert binary writer = Elf::ObjectWriter.new(Elf::Constants::TARGET_ARM) blocks = program.functions.collect{ |f| [f.entry , f.exit , f.body] } blocks += [program.entry , program.exit , program.main]