implement assignment type check

This commit is contained in:
Torsten Ruger 2016-12-28 19:20:16 +02:00
parent 9cf56b3aa6
commit af31774074
3 changed files with 33 additions and 30 deletions

View File

@ -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

View File

@ -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

View File

@ -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)