From af31774074721241cd8ffad4ac4182874029fc51 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Wed, 28 Dec 2016 19:20:16 +0200 Subject: [PATCH] implement assignment type check --- lib/typed/method_compiler.rb | 18 ++++----------- lib/typed/method_compiler/assignment.rb | 29 ++++++++++++------------- test/typed/statements/test_assign.rb | 16 +++++++++++++- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/lib/typed/method_compiler.rb b/lib/typed/method_compiler.rb index f7ad69fa..1c94486f 100644 --- a/lib/typed/method_compiler.rb +++ b/lib/typed/method_compiler.rb @@ -150,19 +150,15 @@ module Typed # add an instruction after the current (insertion point) # the added instruction will become the new insertion point def add_code instruction - unless instruction.is_a?(Register::Instruction) - raise instruction.to_s - end - if( instruction.class.name.split("::").first == "Arm") - raise instruction.to_s - end + raise instruction.to_s unless instruction.is_a?(Register::Instruction) + raise instruction.to_s if( instruction.class.name.split("::").first == "Arm") @current.insert(instruction) #insert after current @current = instruction self end # require a (temporary) register. code must give this back with release_reg - def use_reg type , value = nil + def use_reg( type , value = nil ) raise "Not type #{type.inspect}" unless type.is_a?(Symbol) or type.is_a?(Parfait::Type) if @regs.empty? reg = Register.tmp_reg(type , value) @@ -173,7 +169,7 @@ module Typed return reg end - def copy reg , source + def copy( reg , source ) copied = use_reg reg.type add_code Reister.transfer source , reg , copied copied @@ -193,11 +189,5 @@ module Typed @regs.clear end - # ensure the name given is not space and raise exception otherwise - # return the name for chaining - def no_space name - raise "space is a reserved name" if name == :space - name - end end end diff --git a/lib/typed/method_compiler/assignment.rb b/lib/typed/method_compiler/assignment.rb index 2d77a887..3ffa5da2 100644 --- a/lib/typed/method_compiler/assignment.rb +++ b/lib/typed/method_compiler/assignment.rb @@ -2,32 +2,31 @@ module Typed module Assignment def on_Assignment( statement ) - # name , value = *statement reset_regs # statements reset registers, ie have all at their disposal value = process(statement.value) raise "Not register #{v}" unless value.is_a?(Register::RegisterValue) - code = get_code( statement , value) - raise "must define variable #{statement.name.name} before using it in #{@method.inspect}" unless code - add_code code - end - - private - - def get_code( statement , value) - name = no_space(statement.name).name + name = check_name(statement.name.name) named_list = use_reg(:NamedList) if( index = @method.has_arg(name)) - # TODO, check type @method.arguments[index].type type = :arguments + value_type = @method.argument_type( index ) else - # or a local so it is in the frame index = @method.has_local( name ) type = :locals - return nil unless index + raise "must define variable #{statement.name.name} before using it in #{@method.inspect}" unless index + value_type = @method.locals_type( index ) end - # TODO, check type @method.locals[index].type + raise "Type mismatch for #{type} access #{value.type}!=#{value_type}" unless value.type == value_type add_code Register.slot_to_reg(statement , :message , type , named_list ) - return Register.reg_to_slot(statement , value , named_list , index + 1 ) # one for type + add_code Register.reg_to_slot(statement , value , named_list , index + 1 ) # one for type end + + # ensure the name given is not space and raise exception otherwise + # return the name + def check_name( name ) + raise "space is a reserved name" if name == :space + name + end + end end diff --git a/test/typed/statements/test_assign.rb b/test/typed/statements/test_assign.rb index 0864c7f8..7cd9b0d3 100644 --- a/test/typed/statements/test_assign.rb +++ b/test/typed/statements/test_assign.rb @@ -52,7 +52,7 @@ class TestAssignStatement < MiniTest::Test assert_equal 1 + 1, get.index , "Get to named_list index must be offset, not #{get.index}" end - def test_assign_int + def test_assign_local_int Register.machine.space.get_main.add_local(:r , :Integer) @input = s(:statements, s(:assignment, s(:name, :r), s(:int, 5)) ) @expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn] @@ -62,6 +62,13 @@ class TestAssignStatement < MiniTest::Test assert_equal 1 + 1, set.index , "Set to named_list index must be offset, not #{set.index}" end + def test_misassign_local + Register.machine.space.get_main.add_local(:r , :Integer) + @input = s(:statements, s(:assignment, s(:name, :r), s(:string, "5")) ) + @expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn] + assert_raises {check } + end + def test_assign_arg Register.machine.space.get_main.add_argument(:blar , :Integer) @input = s(:statements, s(:assignment, s(:name, :blar), s(:int, 5))) @@ -72,6 +79,13 @@ class TestAssignStatement < MiniTest::Test assert_equal 1 + 1, set.index , "Set to args index must be offset, not #{set.index}" end + def test_misassign_arg + Register.machine.space.get_main.add_argument(:blar , :Integer) + @input = s(:statements, s(:assignment, s(:name, :blar), s(:string, "5"))) + @expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn] + assert_raises {check } + end + def test_arg_get # have to define bar externally, just because redefining main. Otherwise that would be automatic Register.machine.space.get_main.add_argument(:balr , :Integer)