implement assignment type check
This commit is contained in:
parent
9cf56b3aa6
commit
af31774074
@ -150,19 +150,15 @@ module Typed
|
|||||||
# add an instruction after the current (insertion point)
|
# add an instruction after the current (insertion point)
|
||||||
# the added instruction will become the new insertion point
|
# the added instruction will become the new insertion point
|
||||||
def add_code instruction
|
def add_code instruction
|
||||||
unless instruction.is_a?(Register::Instruction)
|
raise instruction.to_s unless instruction.is_a?(Register::Instruction)
|
||||||
raise instruction.to_s
|
raise instruction.to_s if( instruction.class.name.split("::").first == "Arm")
|
||||||
end
|
|
||||||
if( instruction.class.name.split("::").first == "Arm")
|
|
||||||
raise instruction.to_s
|
|
||||||
end
|
|
||||||
@current.insert(instruction) #insert after current
|
@current.insert(instruction) #insert after current
|
||||||
@current = instruction
|
@current = instruction
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# require a (temporary) register. code must give this back with release_reg
|
# 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)
|
raise "Not type #{type.inspect}" unless type.is_a?(Symbol) or type.is_a?(Parfait::Type)
|
||||||
if @regs.empty?
|
if @regs.empty?
|
||||||
reg = Register.tmp_reg(type , value)
|
reg = Register.tmp_reg(type , value)
|
||||||
@ -173,7 +169,7 @@ module Typed
|
|||||||
return reg
|
return reg
|
||||||
end
|
end
|
||||||
|
|
||||||
def copy reg , source
|
def copy( reg , source )
|
||||||
copied = use_reg reg.type
|
copied = use_reg reg.type
|
||||||
add_code Reister.transfer source , reg , copied
|
add_code Reister.transfer source , reg , copied
|
||||||
copied
|
copied
|
||||||
@ -193,11 +189,5 @@ module Typed
|
|||||||
@regs.clear
|
@regs.clear
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
@ -2,32 +2,31 @@ module Typed
|
|||||||
module Assignment
|
module Assignment
|
||||||
|
|
||||||
def on_Assignment( statement )
|
def on_Assignment( statement )
|
||||||
# name , value = *statement
|
|
||||||
reset_regs # statements reset registers, ie have all at their disposal
|
reset_regs # statements reset registers, ie have all at their disposal
|
||||||
value = process(statement.value)
|
value = process(statement.value)
|
||||||
raise "Not register #{v}" unless value.is_a?(Register::RegisterValue)
|
raise "Not register #{v}" unless value.is_a?(Register::RegisterValue)
|
||||||
code = get_code( statement , value)
|
name = check_name(statement.name.name)
|
||||||
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
|
|
||||||
named_list = use_reg(:NamedList)
|
named_list = use_reg(:NamedList)
|
||||||
if( index = @method.has_arg(name))
|
if( index = @method.has_arg(name))
|
||||||
# TODO, check type @method.arguments[index].type
|
|
||||||
type = :arguments
|
type = :arguments
|
||||||
|
value_type = @method.argument_type( index )
|
||||||
else
|
else
|
||||||
# or a local so it is in the frame
|
|
||||||
index = @method.has_local( name )
|
index = @method.has_local( name )
|
||||||
type = :locals
|
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
|
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 )
|
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
|
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
|
||||||
end
|
end
|
||||||
|
@ -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}"
|
assert_equal 1 + 1, get.index , "Get to named_list index must be offset, not #{get.index}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_assign_int
|
def test_assign_local_int
|
||||||
Register.machine.space.get_main.add_local(:r , :Integer)
|
Register.machine.space.get_main.add_local(:r , :Integer)
|
||||||
@input = s(:statements, s(:assignment, s(:name, :r), s(:int, 5)) )
|
@input = s(:statements, s(:assignment, s(:name, :r), s(:int, 5)) )
|
||||||
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn]
|
@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}"
|
assert_equal 1 + 1, set.index , "Set to named_list index must be offset, not #{set.index}"
|
||||||
end
|
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
|
def test_assign_arg
|
||||||
Register.machine.space.get_main.add_argument(:blar , :Integer)
|
Register.machine.space.get_main.add_argument(:blar , :Integer)
|
||||||
@input = s(:statements, s(:assignment, s(:name, :blar), s(:int, 5)))
|
@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}"
|
assert_equal 1 + 1, set.index , "Set to args index must be offset, not #{set.index}"
|
||||||
end
|
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
|
def test_arg_get
|
||||||
# have to define bar externally, just because redefining main. Otherwise that would be automatic
|
# have to define bar externally, just because redefining main. Otherwise that would be automatic
|
||||||
Register.machine.space.get_main.add_argument(:balr , :Integer)
|
Register.machine.space.get_main.add_argument(:balr , :Integer)
|
||||||
|
Loading…
Reference in New Issue
Block a user