def test_routine_properties(): ''' Check the various properties of the Routine class. ''' node1 = Routine("hello") assert node1.dag_name == "routine_hello_0" assert node1.return_type is None assert node1.is_program is False assert node1.name == "hello" # Give the Routine a child to get full coverage of __str__ method node1.addchild(Assignment()) assert "Routine[name:'hello']:\nAssignment" in str(node1) node2 = Routine("bonjour", return_type=INTEGER_TYPE) assert node2.return_type == INTEGER_TYPE assert node2.is_program is False node3 = Routine("gutentag", is_program=True) assert node3.return_type is None assert node3.is_program node4 = Routine("welcome", is_program=True, return_type=INTEGER_TYPE) assert node4.return_type == INTEGER_TYPE assert node4.is_program with pytest.raises(TypeError) as err: node4.name = node3 assert "must be a str but got" in str(err.value) node4.name = "goodbye" assert node4.name == "goodbye"
def test_routine_create_invalid(): '''Test that the create method in the Routine class raises the expected exceptions if the provided input is invalid. ''' symbol_table = SymbolTable() symbol = DataSymbol("x", REAL_TYPE) symbol_table.add(symbol) children = [Assignment.create(Reference(symbol), Literal("1", REAL_TYPE))] # name is not a string. with pytest.raises(TypeError) as excinfo: _ = Routine.create(1, symbol_table, children) assert ("name argument in create method of Routine class " "should be a string but found 'int'.") in str(excinfo.value) # symbol_table not a SymbolTable. with pytest.raises(TypeError) as excinfo: _ = Routine.create("mod_name", "invalid", children) assert ("symbol_table argument in create method of Routine class " "should be a SymbolTable but found 'str'.") in str(excinfo.value) # children not a list. with pytest.raises(TypeError) as excinfo: _ = Routine.create("mod_name", symbol_table, "invalid") assert ("children argument in create method of Routine class " "should be a list but found 'str'." in str(excinfo.value)) # contents of children list are not Node. with pytest.raises(TypeError) as excinfo: _ = Routine.create("mod_name", symbol_table, ["invalid"]) assert ( "child of children argument in create method of Routine class " "should be a PSyIR Node but found 'str'." in str(excinfo.value))
def test_routine_constructor(): ''' Check the constructor and associated type checking. ''' with pytest.raises(TypeError) as err: Routine(1) assert "must be a str but got" in str(err.value) with pytest.raises(TypeError) as err: Routine("hello", is_program=1) assert "'is_program' must be a bool" in str(err.value) node = Routine("hello") assert node._name == "hello"
def test_routine_return_symbol_setter(): ''' Check that the return_symbol setter works correctly and rejects invalid values. ''' node = Routine("hello") assert node.return_symbol is None with pytest.raises(TypeError) as err: node.return_symbol = "wrong" assert ("Routine return-symbol should be a DataSymbol but found 'str'" in str(err.value)) sym = DataSymbol("result", REAL_TYPE) with pytest.raises(KeyError) as err: node.return_symbol = sym assert ("For a symbol to be a return-symbol, it must be present in the " "symbol table of the Routine but 'result' is not." in str(err.value)) node.symbol_table.add(sym) node.return_symbol = sym assert node.return_symbol is sym
def test_routine_name_setter(): ''' Check the name setter property of the Routine class updates its name and its associated Routine symbol. ''' node = Routine("hello") # The constructor has an implicit name setter # Check the associated RoutineSymbol has been created assert "hello" in node.symbol_table assert isinstance(node.symbol_table.lookup("hello"), RoutineSymbol) # Check with an incorrect value type with pytest.raises(TypeError) as err: node.name = 3 assert "must be a str but got" in str(err.value) # Perform a successful name change node.name = "goodbye" assert node.name == "goodbye" # Check that the previous symbol has been deleted and the new one created assert "welcome" not in node.symbol_table assert "goodbye" in node.symbol_table # Check that the 'own_routine_symbol' tag has been updated assert node.symbol_table.lookup_with_tag('own_routine_symbol').name == \ "goodbye"
def test_routine_create(): '''Test that the create method correctly creates a Routine instance. ''' symbol_table = SymbolTable() symbol = DataSymbol("tmp", REAL_TYPE) symbol_table.add(symbol) assignment = Assignment.create(Reference(symbol), Literal("0.0", REAL_TYPE)) kschedule = Routine.create("mod_name", symbol_table, [assignment], is_program=True, return_type=INTEGER_TYPE) assert isinstance(kschedule, Routine) check_links(kschedule, [assignment]) assert kschedule.symbol_table is symbol_table assert kschedule.is_program assert kschedule.return_type == INTEGER_TYPE
def test_file_container_create(): '''Test that the create method in the Container class correctly creates a FileContainer instance. ''' symbol_table = SymbolTable() symbol_table.add(DataSymbol("tmp", REAL_SINGLE_TYPE)) module = Container.create("mod_1", symbol_table, []) program = Routine.create("prog_1", SymbolTable(), [], is_program=True) file_container = FileContainer.create("container_name", SymbolTable(), [module, program]) assert isinstance(file_container, FileContainer) result = FortranWriter().filecontainer_node(file_container) assert result == ("module mod_1\n" " implicit none\n" " real :: tmp\n\n" " contains\n\n" "end module mod_1\n" "program prog_1\n\n\n" "end program prog_1\n")
def test_routine_properties(): ''' Check the various properties of the Routine class. ''' node1 = Routine("hello") assert node1.dag_name == "routine_hello_0" assert node1.return_symbol is None assert node1.is_program is False assert node1.name == "hello" # Give the Routine a child to get full coverage of __str__ method node1.addchild(Assignment()) assert "Routine[name:'hello']:\nAssignment" in str(node1) node2 = Routine("bonjour") assert node2.is_program is False node3 = Routine("gutentag", is_program=True) assert node3.is_program
def test_scoping_node_copy_hierarchy(): ''' Test that the ScopingNode copy() method creates a new symbol table with copied symbols and updates the children references. This test has 2 ScopingNodes, and the copy will only be applied to the inner one. This means that the References to the symbols on the outer scope should not be duplicated. Also it contains argument symbols and a reference inside another reference to make sure all these are copied appropriately. ''' parent_node = Container("module") symbol_b = parent_node.symbol_table.new_symbol("b", symbol_type=DataSymbol, datatype=ArrayType( INTEGER_TYPE, [5])) schedule = Routine("routine") parent_node.addchild(schedule) symbol_a = schedule.symbol_table.new_symbol( "a", symbol_type=DataSymbol, datatype=INTEGER_TYPE, interface=ArgumentInterface(ArgumentInterface.Access.READWRITE)) schedule.symbol_table.specify_argument_list([symbol_a]) symbol_i = schedule.symbol_table.new_symbol("i", symbol_type=DataSymbol, datatype=INTEGER_TYPE) schedule.addchild( Assignment.create( Reference(symbol_a), ArrayReference.create(symbol_b, [Reference(symbol_i)]))) new_schedule = schedule.copy() # Check that the symbol_table has been deep copied assert new_schedule.symbol_table is not schedule.symbol_table assert new_schedule.symbol_table.lookup("i") is not \ schedule.symbol_table.lookup("i") assert new_schedule.symbol_table.lookup("a") is not \ schedule.symbol_table.lookup("a") # Check that 'a' and 'i' have been copied to the new symbol table. assert new_schedule[0].lhs.symbol not in schedule.symbol_table.symbols assert new_schedule[0].lhs.symbol in new_schedule.symbol_table.symbols assert new_schedule[0].rhs.children[0].symbol not in \ schedule.symbol_table.symbols assert new_schedule[0].rhs.children[0].symbol in \ new_schedule.symbol_table.symbols # Add the "_new" suffix to all symbol in the copied schedule for symbol in new_schedule.symbol_table.symbols: new_schedule.symbol_table.rename_symbol(symbol, symbol.name + "_new") # An update to a symbol in the outer scope must affect both copies of the # inner schedule. parent_node.symbol_table.rename_symbol(symbol_b, symbol_b.name + "_global") # Insert the schedule back to the original container parent_node.addchild(new_schedule) # Check that the expected code is generated # TODO #1200: the new 'routine' RoutineSymbol also needs to change. expected = '''\ module module implicit none integer, dimension(5) :: b_global contains subroutine routine(a) integer, intent(inout) :: a integer :: i a = b_global(i) end subroutine routine subroutine routine(a_new) integer, intent(inout) :: a_new integer :: i_new a_new = b_global(i_new) end subroutine routine end module module ''' writer = FortranWriter() output = writer(parent_node) assert expected == output
def create_psyir_tree(): ''' Create an example PSyIR Tree. :returns: an example PSyIR tree. :rtype: :py:class:`psyclone.psyir.nodes.Container` ''' # Symbol table, symbols and scalar datatypes symbol_table = SymbolTable() arg1 = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_TYPE, interface=ArgumentInterface( ArgumentInterface.Access.READWRITE)) symbol_table.specify_argument_list([arg1]) tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol, datatype=REAL_DOUBLE_TYPE) index_symbol = symbol_table.new_symbol(root_name="i", symbol_type=DataSymbol, datatype=INTEGER4_TYPE) real_kind = symbol_table.new_symbol(root_name="RKIND", symbol_type=DataSymbol, datatype=INTEGER_TYPE, constant_value=8) routine_symbol = RoutineSymbol("my_sub") # Array using precision defined by another symbol scalar_type = ScalarType(ScalarType.Intrinsic.REAL, real_kind) array = symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=ArrayType(scalar_type, [10])) # Make generators for nodes which do not have other Nodes as children, # with some predefined scalar datatypes def zero(): return Literal("0.0", REAL_TYPE) def one(): return Literal("1.0", REAL4_TYPE) def two(): return Literal("2.0", scalar_type) def int_zero(): return Literal("0", INTEGER_SINGLE_TYPE) def int_one(): return Literal("1", INTEGER8_TYPE) def tmp1(): return Reference(arg1) def tmp2(): return Reference(tmp_symbol) # Unary Operation oper = UnaryOperation.Operator.SIN unaryoperation = UnaryOperation.create(oper, tmp2()) # Binary Operation oper = BinaryOperation.Operator.ADD binaryoperation = BinaryOperation.create(oper, one(), unaryoperation) # Nary Operation oper = NaryOperation.Operator.MAX naryoperation = NaryOperation.create(oper, [tmp1(), tmp2(), one()]) # Array reference using a range lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(array), int_one()) ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(array), int_one()) my_range = Range.create(lbound, ubound) tmparray = ArrayReference.create(array, [my_range]) # Assignments assign1 = Assignment.create(tmp1(), zero()) assign2 = Assignment.create(tmp2(), zero()) assign3 = Assignment.create(tmp2(), binaryoperation) assign4 = Assignment.create(tmp1(), tmp2()) assign5 = Assignment.create(tmp1(), naryoperation) assign6 = Assignment.create(tmparray, two()) # Call call = Call.create(routine_symbol, [tmp1(), binaryoperation.copy()]) # If statement if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, tmp1(), zero()) ifblock = IfBlock.create(if_condition, [assign3, assign4]) # Loop loop = Loop.create(index_symbol, int_zero(), int_one(), int_one(), [ifblock]) # Routine routine = Routine.create("work", symbol_table, [assign1, call, assign2, loop, assign5, assign6]) # Container container_symbol_table = SymbolTable() container = Container.create("CONTAINER", container_symbol_table, [routine]) # Import data from another container external_container = ContainerSymbol("some_mod") container_symbol_table.add(external_container) external_var = DataSymbol("some_var", INTEGER_TYPE, interface=GlobalInterface(external_container)) container_symbol_table.add(external_var) routine_symbol.interface = GlobalInterface(external_container) container_symbol_table.add(routine_symbol) # Routine (specified as being a program) program_symbol_table = SymbolTable() work_symbol = RoutineSymbol("work") container_symbol = ContainerSymbol("CONTAINER") work_symbol.interface = GlobalInterface(container_symbol) arg_symbol = program_symbol_table.new_symbol(root_name="arg", symbol_type=DataSymbol, datatype=REAL_TYPE) program_symbol_table.add(container_symbol) program_symbol_table.add(work_symbol) call = Call.create(work_symbol, [Reference(arg_symbol)]) program = Routine.create("some_program", program_symbol_table, [call], is_program=True) # File container file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) return file_container