def test_routinesymbol_init(): '''Test that a RoutineSymbol instance can be created.''' assert isinstance(RoutineSymbol('jo'), RoutineSymbol) assert isinstance( RoutineSymbol('ellie', visibility=Symbol.Visibility.PRIVATE), RoutineSymbol) assert isinstance( RoutineSymbol('isaac', interface=UnresolvedInterface()), RoutineSymbol)
def test_call_error2(): '''Test that the appropriate exception is raised if the arguments argument to the create method is not a list''' routine = RoutineSymbol("isaac") with pytest.raises(GenerationError) as info: _ = Call.create(routine, None) assert ("Call create arguments argument should be a list but found " "'NoneType'." in str(info.value))
def test_lfricalgorithminvokecall_create_nodescription(): '''Check that the LFRicAlgorithmInvokeCall create method sets description to None if it is not provided. ''' routine = RoutineSymbol("hello") call = LFRicAlgorithmInvokeCall.create(routine, [], 0) assert call._description is None
def test_routinesymbol_init_error(): '''Test that the RoutineSymbol raises an error (via the Symbol parent class) if there is an invalid argument. ''' with pytest.raises(TypeError) as error: _ = RoutineSymbol(None) assert ("RoutineSymbol 'name' attribute should be of type 'str' but " "'NoneType' found." in str(error.value))
def test_lfricalgorithminvokecall_node_str(): '''Check that the LFRicAlgorithmInvokeCall node_str method creates the expected object. ''' routine = RoutineSymbol("hello") call = LFRicAlgorithmInvokeCall.create( routine, [], 0, description="describing an invoke") assert ("LFRicAlgorithmInvokeCall[description=\"describing an invoke\"]" in call.node_str(colour=False))
def test_algorithminvokecall(): '''Check that an instance of AlgorithmInvokeCall can be created. ''' routine = RoutineSymbol("hello") call = AlgorithmInvokeCall(routine, 2) assert call._text_name == "AlgorithmInvokeCall" assert call._colour == "green" assert call.psylayer_routine_symbol is None assert call._index == 2
def test_invoke_error(): '''Test that the expected exception is raised in the validate method when the supplied node is a call but its name is not the expected 'invoke' name. ''' invoke_trans = InvokeCallTrans() with pytest.raises(TransformationError) as info: invoke_trans.validate(Call(RoutineSymbol("hello"))) assert ("Error in InvokeCallTrans transformation. The supplied call " "argument should be a `Call` node with name 'invoke' but " "found 'hello'." in str(info.value))
def test_lfricalgorithminvokecall_options(): '''Check that an instance of LFRicAlgorithmInvokeCall can be created with optional arguments and that these optional arguments are stored as expected. ''' node = Node() routine = RoutineSymbol("hello") call = LFRicAlgorithmInvokeCall( routine, 0, description="describing an invoke", parent=node) assert call._description == "describing an invoke" assert call.parent is node
def test_call_error3(): '''Test that the appropriate exception is raised if one or more of the arguments argument list entries to the create method is not a DataNode. ''' routine = RoutineSymbol("roo") with pytest.raises(GenerationError) as info: _ = Call.create(routine, [Reference(DataSymbol("arg1", INTEGER_TYPE)), None]) assert ("Item 'NoneType' can't be child 1 of 'Call'. The valid format " "is: '[DataNode]*'." in str(info.value))
def test_lfricalgorithminvokecall(): '''Check that an instance of LFRicAlgorithmInvokeCall can be created. ''' routine = RoutineSymbol("hello") index = 2 call = LFRicAlgorithmInvokeCall(routine, index) assert call._description is None assert call.parent is None assert call.routine is routine assert call._index == index assert call._text_name == "LFRicAlgorithmInvokeCall"
def name(self, new_name): ''' Sets a new name for the Routine. :param str new_name: new name for the Routine. :raises TypeError: if new_name is not a string. ''' if not isinstance(new_name, six.string_types): raise TypeError("Routine name must be a str but got " "'{0}'".format(type(new_name).__name__)) if not self._name: self._name = new_name self.symbol_table.add(RoutineSymbol(new_name), tag='own_routine_symbol') elif self._name != new_name: old_symbol = self.symbol_table.lookup(self._name) self.symbol_table.remove(old_symbol) self._name = new_name self.symbol_table.add(RoutineSymbol(new_name), tag='own_routine_symbol')
def test_aic_validate_child(): '''Check that the _validate_child method behaves as expected.''' kernel_functor = KernelFunctor(DataTypeSymbol("dummy", REAL_TYPE)) assert AlgorithmInvokeCall._validate_child(0, kernel_functor) assert not AlgorithmInvokeCall._validate_child(0, "Invalid") routine = RoutineSymbol("hello") call = AlgorithmInvokeCall(routine, 0) with pytest.raises(GenerationError) as info: call.children = ["invalid"] assert ("Item 'str' can't be child 0 of 'AlgorithmInvokeCall'. The valid " "format is: '[KernelFunctor]*'." in str(info.value)) call.children = [kernel_functor]
def test_call_create(): '''Test that the create method creates a valid call with arguments''' routine = RoutineSymbol("ellie") array_type = ArrayType(INTEGER_TYPE, shape=[10, 20]) arguments = [ Reference(DataSymbol("arg1", INTEGER_TYPE)), Array(DataSymbol("arg2", array_type)) ] call = Call.create(routine, arguments) assert call.routine is routine for idx, child, in enumerate(call.children): assert child is arguments[idx] assert child.parent is call
def test_lfricalgorithminvokecall_create(cls): '''Check that the LFRicAlgorithmInvokeCall create method creates the expected object. ''' routine = RoutineSymbol("hello") klc = LFRicKernelFunctor.create(DataTypeSymbol("arg", StructureType()), []) call = cls.create(routine, [klc], 0, description="describing an invoke") assert call._description == "describing an invoke" assert call.routine is routine # pylint: disable=unidiomatic-typecheck assert type(call) is cls assert len(call.children) == 1 assert call.children[0] == klc
def test_aic_defroutinerootname(): '''Check that the _def_routine_root_name() internal method behaves as expected. ''' symbol_name = "dummy" kernel_functor = KernelFunctor(DataTypeSymbol(symbol_name, REAL_TYPE)) routine = RoutineSymbol("hello") index = 3 call = AlgorithmInvokeCall(routine, index) call.children = [kernel_functor] assert call._def_routine_root_name() == "invoke_{0}_{1}".format( index, symbol_name) call.children.append(kernel_functor.copy()) assert call._def_routine_root_name() == "invoke_{0}".format(index)
def test_algorithminvokecall_error(): '''Check that AlgorithmInvokeCall raises the expected exceptions if the invoke argument has an invalid value. ''' routine = RoutineSymbol("hello") with pytest.raises(TypeError) as info: AlgorithmInvokeCall(routine, "error") assert ("AlgorithmInvokeCall index argument should be an int but found " "'str'." in str(info.value)) with pytest.raises(ValueError) as info: AlgorithmInvokeCall(routine, -1) assert ("AlgorithmInvokeCall index argument should be a non-negative " "integer but found -1." in str(info.value))
def test_aic_create(): '''Check that the create method behaves as expected.''' kernel_functor = KernelFunctor(DataTypeSymbol("dummy", REAL_TYPE)) routine = RoutineSymbol("hello") index = 10 aic = AlgorithmInvokeCall.create(routine, [kernel_functor], index) assert isinstance(aic, AlgorithmInvokeCall) assert len(aic.children) == 1 assert aic.children[0] is kernel_functor assert aic._routine is routine assert aic._index == index with pytest.raises(GenerationError) as info: AlgorithmInvokeCall.create(routine, kernel_functor, index) assert ("AlgorithmInvokeCall create arguments argument should be a list " "but found 'KernelFunctor'." in str(info.value))
def test_name_clash_derived_type_def(f2008_parser): ''' Check that the frontend raises an error if it encounters a definition of a derived type with a name that clashes with another symbol. ''' fake_parent = KernelSchedule("dummy_schedule") symtab = fake_parent.symbol_table # Add a RoutineSymbol to the symbol table that will clash with the name # of the derived type. symtab.add(RoutineSymbol("my_type")) # Add a DataTypeSymbol to the symbol table. Make it appear that we've # already seen a definition of this symbol by making it of # UnknownFortranType. symtab.new_symbol("my_type2", symbol_type=DataTypeSymbol, datatype=UnknownFortranType("huh")) processor = Fparser2Reader() fparser2spec = f2008_parser( FortranStringReader("subroutine my_sub()\n" " type :: my_type\n" " integer :: flag\n" " end type my_type\n" "end subroutine my_sub\n")) # This should raise an error because the Container symbol table will # already contain a RoutineSymbol named 'my_type' with pytest.raises(SymbolError) as err: processor.process_declarations(fake_parent, fparser2spec.content, []) assert ("Error processing definition of derived type 'my_type'. The " "symbol table already contains an entry with this name but it is a" " 'RoutineSymbol' when it should be a 'DataTypeSymbol' (for the " "derived-type definition 'TYPE :: my_type\n INTEGER :: flag\n" "END TYPE my_type')" in str(err.value)) # Repeat but with a derived-type name that will clash with our existing # DataTypeSymbol fparser2spec = f2008_parser( FortranStringReader("subroutine my_sub2()\n" " type :: my_type2\n" " integer :: flag\n" " end type my_type2\n" "end subroutine my_sub2\n")) with pytest.raises(SymbolError) as err: processor.process_declarations(fake_parent, fparser2spec.content, []) assert ("Error processing definition of derived type 'my_type2'. The " "symbol table already contains a DataTypeSymbol with this name but" " it is of type 'UnknownFortranType' when it should be of " "'DeferredType'" in str(err.value))
def test_call_init(): '''Test that a Call can be created as expected. Also test the routine property. ''' # routine argument routine = RoutineSymbol("jo") call = Call(routine) assert call._routine is routine assert call.routine is call._routine assert call.parent is None assert call.children == [] # optional parent argument parent = Schedule() call = Call(routine, parent=parent) assert call.routine is routine assert call.parent is parent assert call.children == []
def _parse_args(code_block, fp2_node): '''Return the arguments from a Structure Constructor stored as a CodeBlock containing an fparser2 ast. :param code_block: the CodeBlock containing a StructureConstructor. :type code_block: :py:class:`psyclone.psyir.nodes.CodeBlock` :param fp2_node: the fparser2 Structure Constructor node. :type fp2_node: \ :py:class:`fparser.two.Fortran2003.Structure_Constructor` :returns: a list of PSyIR nodes containing the \ StructureConstructor arguments. :rtype: list of :py:class:`psyclone.psyir.nodes.Node` ''' dummy_call = Call(RoutineSymbol("dummy"), parent=code_block.parent) fparser2 = Fparser2Reader() for arg in fp2_node.children[1].children: fparser2.process_nodes(dummy_call, [arg]) return dummy_call.pop_all_children()
def test_name_clash_derived_type(f2008_parser, type_name): ''' Check that the frontend raises an error if it encounters a reference to a derived type that clashes with another symbol. ''' fake_parent = KernelSchedule("dummy_schedule") symtab = fake_parent.symbol_table # Add a RoutineSymbol to the symbol table that clashes with the name # of the derived type. symtab.add(RoutineSymbol("my_type")) processor = Fparser2Reader() reader = FortranStringReader("subroutine my_sub()\n" " type({0}) :: some_var\n" "end subroutine my_sub\n".format(type_name)) fparser2spec = f2008_parser(reader) # This should raise an error because the Container symbol table should # already contain a RoutineSymbol named 'my_type' with pytest.raises(SymbolError) as err: processor.process_declarations(fake_parent, fparser2spec.content, []) assert ("Search for a DataTypeSymbol named '{0}' (required by " "specification 'TYPE({0})') found a 'RoutineSymbol' instead". format(type_name) in str(err.value))
def create_psylayer_symbols(self): '''If the PSy-layer routine and container symbols have not been created, then create them. The names are based on the position of this node (compared to other nodes of the same type) in the PSyIR tree. ''' if self.psylayer_routine_symbol: # The language-level symbols have already been created return routine_root_name = self._def_routine_root_name() symbol_table = self.scope.symbol_table routine_name = symbol_table.next_available_name( root_name=routine_root_name) container_root_name = "{0}_mod".format(routine_name) container_name = symbol_table.next_available_name( root_name=container_root_name) interface = GlobalInterface(ContainerSymbol(container_name)) self.psylayer_routine_symbol = RoutineSymbol(routine_name, interface=interface)
def test_call_str(): ''' Test that the str method behaves as expected ''' routine = RoutineSymbol("roo") call = Call(routine) assert str(call) == "Call[name='roo']"
def test_call_node_str(): ''' Test that the node_str method behaves as expected ''' routine = RoutineSymbol("isaac") call = Call(routine) colouredtext = colored("Call", SCHEDULE_COLOUR_MAP["Call"]) assert call.node_str() == colouredtext + "[name='isaac']"
ARG1 = DataSymbol(TMP_NAME1, REAL_TYPE, interface=ArgumentInterface( ArgumentInterface.Access.READWRITE)) SYMBOL_TABLE.add(ARG1) TMP_NAME2 = SYMBOL_TABLE.new_symbol_name() TMP_SYMBOL = DataSymbol(TMP_NAME2, REAL_DOUBLE_TYPE) SYMBOL_TABLE.add(TMP_SYMBOL) INDEX_NAME = SYMBOL_TABLE.new_symbol_name(root_name="i") INDEX_SYMBOL = DataSymbol(INDEX_NAME, INTEGER4_TYPE) SYMBOL_TABLE.add(INDEX_SYMBOL) SYMBOL_TABLE.specify_argument_list([ARG1]) REAL_KIND_NAME = SYMBOL_TABLE.new_symbol_name(root_name="RKIND") REAL_KIND = DataSymbol(REAL_KIND_NAME, INTEGER_TYPE, constant_value=8) SYMBOL_TABLE.add(REAL_KIND) ROUTINE_SYMBOL = RoutineSymbol("my_sub") # Array using precision defined by another symbol ARRAY_NAME = SYMBOL_TABLE.new_symbol_name(root_name="a") SCALAR_TYPE = ScalarType(ScalarType.Intrinsic.REAL, REAL_KIND) ARRAY = DataSymbol(ARRAY_NAME, ArrayType(SCALAR_TYPE, [10])) SYMBOL_TABLE.add(ARRAY) # Nodes which do not have Nodes as children and (some) predefined # scalar datatypes ZERO = Literal("0.0", REAL_TYPE) ONE = Literal("1.0", REAL4_TYPE) TWO = Literal("2.0", SCALAR_TYPE) INT_ZERO = Literal("0", INTEGER_SINGLE_TYPE) INT_ONE = Literal("1", INTEGER8_TYPE) TMP1 = Reference(ARG1)
def test_routinesymbol_str(): '''Test that the __str__ method in routinesymbol behaves as expected.''' routine_symbol = RoutineSymbol("roo") assert routine_symbol.__str__() == "roo : RoutineSymbol"
"diff_basis_w3", [3, Reference(NDF_W3), Reference(NQP_XY), Reference(NQP_Z)], "w3", interface=READ_ARG) for symbol in [NQP_XY, NQP_Z, WEIGHTS_XY, WEIGHTS_Z, BASIS_W3, DIFF_BASIS_W3]: SYMBOL_TABLE.add(symbol) SYMBOL_TABLE.specify_argument_list([ NDF_W3, UNDF_W3, NCELL_3D, FIELD2, OPERATOR, NQP_XY, NQP_Z, WEIGHTS_XY, WEIGHTS_Z, BASIS_W3, DIFF_BASIS_W3 ]) # Routine symbol ROUTINE_SYMBOL = RoutineSymbol("my_sub") # Call CALL = Call.create(ROUTINE_SYMBOL, [Reference(FIELD1), Reference(FIELD2), Reference(OPERATOR)]) # KernelSchedule KERNEL_SCHEDULE = KernelSchedule.create("work", SYMBOL_TABLE, [CALL]) # Container CONTAINER_SYMBOL_TABLE = SymbolTable() CONTAINER = Container.create("CONTAINER", CONTAINER_SYMBOL_TABLE, [KERNEL_SCHEDULE])
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]) # KernelSchedule kernel_schedule = KernelSchedule.create( "work", symbol_table, [assign1, call, assign2, loop, assign5, assign6]) # Container container_symbol_table = SymbolTable() container = Container.create("CONTAINER", container_symbol_table, [kernel_schedule]) # 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) return container
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])) # Nodes which do not have Nodes as children and (some) predefined # scalar datatypes # TODO: Issue #1136 looks at how to avoid all of the _x versions zero_1 = Literal("0.0", REAL_TYPE) zero_2 = Literal("0.0", REAL_TYPE) zero_3 = Literal("0.0", REAL_TYPE) one_1 = Literal("1.0", REAL4_TYPE) one_2 = Literal("1.0", REAL4_TYPE) one_3 = Literal("1.0", REAL4_TYPE) two = Literal("2.0", scalar_type) int_zero = Literal("0", INTEGER_SINGLE_TYPE) int_one_1 = Literal("1", INTEGER8_TYPE) int_one_2 = Literal("1", INTEGER8_TYPE) int_one_3 = Literal("1", INTEGER8_TYPE) int_one_4 = Literal("1", INTEGER8_TYPE) tmp1_1 = Reference(arg1) tmp1_2 = Reference(arg1) tmp1_3 = Reference(arg1) tmp1_4 = Reference(arg1) tmp1_5 = Reference(arg1) tmp1_6 = Reference(arg1) tmp2_1 = Reference(tmp_symbol) tmp2_2 = Reference(tmp_symbol) tmp2_3 = Reference(tmp_symbol) tmp2_4 = Reference(tmp_symbol) tmp2_5 = Reference(tmp_symbol) tmp2_6 = Reference(tmp_symbol) # Unary Operation oper = UnaryOperation.Operator.SIN unaryoperation_1 = UnaryOperation.create(oper, tmp2_1) unaryoperation_2 = UnaryOperation.create(oper, tmp2_2) # Binary Operation oper = BinaryOperation.Operator.ADD binaryoperation_1 = BinaryOperation.create(oper, one_1, unaryoperation_1) binaryoperation_2 = BinaryOperation.create(oper, one_2, unaryoperation_2) # Nary Operation oper = NaryOperation.Operator.MAX naryoperation = NaryOperation.create(oper, [tmp1_1, tmp2_3, one_3]) # Array reference using a range lbound = BinaryOperation.create(BinaryOperation.Operator.LBOUND, Reference(array), int_one_1) ubound = BinaryOperation.create(BinaryOperation.Operator.UBOUND, Reference(array), int_one_2) my_range = Range.create(lbound, ubound) tmparray = ArrayReference.create(array, [my_range]) # Assignments assign1 = Assignment.create(tmp1_2, zero_1) assign2 = Assignment.create(tmp2_4, zero_2) assign3 = Assignment.create(tmp2_5, binaryoperation_1) assign4 = Assignment.create(tmp1_3, tmp2_6) assign5 = Assignment.create(tmp1_4, naryoperation) assign6 = Assignment.create(tmparray, two) # Call call = Call.create(routine_symbol, [tmp1_5, binaryoperation_2]) # If statement if_condition = BinaryOperation.create(BinaryOperation.Operator.GT, tmp1_6, zero_3) ifblock = IfBlock.create(if_condition, [assign3, assign4]) # Loop loop = Loop.create(index_symbol, int_zero, int_one_3, int_one_4, [ifblock]) # KernelSchedule kernel_schedule = KernelSchedule.create( "work", symbol_table, [assign1, call, assign2, loop, assign5, assign6]) # Container container_symbol_table = SymbolTable() container = Container.create("CONTAINER", container_symbol_table, [kernel_schedule]) # 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) return container