def test_children_setter(): ''' Test that the children setter sets-up accepts lists or raises the appropriate issue. ''' testnode = Schedule() # children is initialised as a ChildrenList assert isinstance(testnode.children, ChildrenList) # When is set up with a list, this becomes a ChildrenList statement1 = Statement() statement2 = Statement() testnode.children = [statement1, statement2] assert isinstance(testnode.children, ChildrenList) assert statement1.parent is testnode assert statement2.parent is testnode # Other types are not accepted with pytest.raises(TypeError) as error: testnode.children = Node() assert "The 'my_children' parameter of the node.children setter must be" \ " a list." in str(error.value) # If a children list is overwritten, it properly disconnects the previous # children testnode.children = [] assert statement1.parent is None assert statement2.parent is None
def test_replace_with_error2(): '''Check that the replace_with method raises the expected exceptions if either node is invalid. ''' parent = Schedule() node1 = Statement() node2 = Statement() with pytest.raises(TypeError) as info: node1.replace_with("hello") assert ("The argument node in method replace_with in the Node class " "should be a Node but found 'str'." in str(info.value)) with pytest.raises(GenerationError) as info: node1.replace_with(node2) assert ("This node should have a parent if its replace_with method " "is called." in str(info.value)) node1.parent = parent node2.parent = parent parent.children = [node1, node2] with pytest.raises(GenerationError) as info: node1.replace_with(node2) assert ("The parent of argument node in method replace_with in the Node " "class should be None but found 'Schedule'." in str(info.value)) node3 = Container("hello") with pytest.raises(GenerationError) as info: node1.replace_with(node3) assert ("Generation Error: Item 'Container' can't be child 0 of " "'Schedule'. The valid format is: '[Statement]*'." in str(info.value))
def test_handling_literal_precision_1(value, dprecision, intrinsic): '''Check that the fparser2 frontend can handle literals with a specified precision kind symbol. ''' if intrinsic == ScalarType.Intrinsic.CHARACTER: code = "x={0}_{1}".format(dprecision, value) else: code = "x={0}_{1}".format(value, dprecision) reader = FortranStringReader(code) astmt = Fortran2003.Assignment_Stmt(reader) fake_parent = Schedule() # Ensure the symbol table has an entry for "x" fake_parent.symbol_table.add( DataSymbol("x", ScalarType(ScalarType.Intrinsic.INTEGER, 4))) processor = Fparser2Reader() processor.process_nodes(fake_parent, [astmt]) assert not fake_parent.walk(CodeBlock) literal = fake_parent.children[0].children[1] assert isinstance(literal, Literal) assert literal.datatype.intrinsic == intrinsic if intrinsic == ScalarType.Intrinsic.BOOLEAN: assert ".{0}.".format(literal.value) == value.lower() else: assert literal.value == value assert isinstance(literal.datatype.precision, DataSymbol) assert literal.datatype.precision.name == dprecision assert isinstance(literal.datatype.precision.datatype, ScalarType) assert (literal.datatype.precision.datatype.intrinsic == ScalarType.Intrinsic.INTEGER)
def test_node_constructor_with_parent(): ''' Check that the node constructor parent parameter works as expected. ''' parent = Schedule() wrong_parent = Schedule() # By default no parent reference is given node = Statement() assert node.parent is None assert node.has_constructor_parent is False # The parent argument can predefine the parent reference node = Return(parent=parent) assert node.parent is parent assert node.has_constructor_parent is True # Then only an addition to this predefined parent is accepted with pytest.raises(GenerationError) as err: wrong_parent.addchild(node) assert ("'Schedule' cannot be set as parent of 'Return' because its " "constructor predefined the parent reference to a different " "'Schedule' node." in str(err.value)) # Once given the proper parent, it can act as a regular node parent.addchild(node) assert node.parent is parent assert node.has_constructor_parent is False wrong_parent.addchild(node.detach()) assert node.parent is wrong_parent
def test_scoping_node_copy(): ''' Test that the ScopingNode copy() method creates a new symbol table with copied symbols and updates the children references.''' # Since ScopingNode is abstract we will try this with a Schedule schedule = Schedule() symbol_a = schedule.symbol_table.new_symbol("a") symbol_b = schedule.symbol_table.new_symbol("b") schedule.addchild( Assignment.create(Reference(symbol_a), Reference(symbol_b))) new_schedule = schedule.copy() # Check that node generic copy() and _refine_copy() have been called # (e.g. children are not shallow copies and tree has been copied down # recursively) assert len(new_schedule.children) == 1 assert new_schedule[0] is not schedule[0] assert new_schedule[0].lhs is not schedule[0].lhs assert new_schedule[0].rhs is not schedule[0].rhs # 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("a") is not \ schedule.symbol_table.lookup("a") assert new_schedule.symbol_table.lookup("b") is not \ schedule.symbol_table.lookup("b") # Check that the children references of the copied schedule point to # symbols in the new schedule's 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.symbol not in schedule.symbol_table.symbols assert new_schedule[0].rhs.symbol in new_schedule.symbol_table.symbols
def test_handling_literal_precision_2(value, dprecision, intrinsic): '''Check that the fparser2 frontend can handle literals with a specified precision value. TODO #754 fix test so that 'disable_declaration_check' fixture is not required. ''' if intrinsic == ScalarType.Intrinsic.CHARACTER: code = "x={0}_{1}".format(dprecision, value) else: code = "x={0}_{1}".format(value, dprecision) reader = FortranStringReader(code) astmt = Fortran2003.Assignment_Stmt(reader) fake_parent = Schedule() processor = Fparser2Reader() processor.process_nodes(fake_parent, [astmt]) assert not fake_parent.walk(CodeBlock) literal = fake_parent.children[0].children[1] assert isinstance(literal, Literal) assert literal.datatype.intrinsic == intrinsic if intrinsic == ScalarType.Intrinsic.BOOLEAN: assert ".{0}.".format(literal.value) == value.lower() else: assert literal.value == value assert isinstance(literal.datatype.precision, int) assert literal.datatype.precision == dprecision
def test_fusetrans_error_not_same_parent(): ''' Check that we reject attempts to fuse loops which don't share the same parent ''' from psyclone.transformations import LoopFuseTrans sch1 = Schedule() sch2 = Schedule() loop1 = Loop(variable=DataSymbol("i", INTEGER_TYPE), parent=sch1) loop2 = Loop(variable=DataSymbol("j", INTEGER_TYPE), parent=sch2) sch1.addchild(loop1) sch2.addchild(loop2) loop1.addchild(Literal("1", INTEGER_TYPE, parent=loop1)) # start loop1.addchild(Literal("10", INTEGER_TYPE, parent=loop1)) # stop loop1.addchild(Literal("1", INTEGER_TYPE, parent=loop1)) # step loop1.addchild(Schedule(parent=loop1)) # loop body loop2.addchild(Literal("1", INTEGER_TYPE, parent=loop2)) # start loop2.addchild(Literal("10", INTEGER_TYPE, parent=loop2)) # stop loop2.addchild(Literal("1", INTEGER_TYPE, parent=loop2)) # step loop2.addchild(Schedule(parent=loop2)) # loop body fuse = LoopFuseTrans() # Try to fuse loops with different parents with pytest.raises(TransformationError) as err: fuse.validate(loop1, loop2) assert ("Error in LoopFuseTrans transformation. Loops do not have the " "same parent" in str(err.value))
def _insert_schedule(self, children=None, ast=None): ''' Utility method to insert a Schedule between this Node and the supplied list of children. :param children: nodes which will become children of the \ new Schedule. :type children: list of :py:class:`psyclone.psyir.nodes.Node` :param ast: reference to fparser2 parse tree for associated \ Fortran code. :type ast: :py:class:`fparser.two.utils.Base` :returns: the new Schedule node. :rtype: :py:class:`psyclone.psyir.nodes.Schedule` ''' from psyclone.psyir.nodes import Schedule sched = Schedule(children=children, parent=self) if children: # If we have children then set the Schedule's AST pointer to # point to the AST associated with them. sched.ast = children[0].ast for child in children: child.parent = sched else: sched.ast = ast return sched
def test_psyirvisitor_lower_dsl_concepts(): ''' Test that DSL concepts are lowered by the visitors but the node is not modified after the visitor has finished. ''' class MyDSLNode(Statement): ''' DSL Concept that lowers to a return statement ''' _text_name = "MyDSLNode" def lower_to_language_level(self): ''' MyDSLNode lowers to a return statement and adds a symbol if it is inside an scoping region. ''' # This will break if this Node does not have a parent with # a scope. This is intentional to cause an error during the # lowering step. self.scope.symbol_table.add(DataSymbol("val", REAL_TYPE)) self.replace_with(Return()) class MyVisitor(PSyIRVisitor): ''' Simple Visitor for Schedules and Return statements ''' def return_node(self, _): ''' Return node visitor ''' return "return" def schedule_node(self, node): ''' Schedule node visitor ''' return "schedule(" + self._visit(node.children[0]) + ")" # Create a custom visitor and dsl-level node visitor = MyVisitor(indent_string=" ", initial_indent_depth=4) schedule = Schedule() my_dsl_node = MyDSLNode() schedule.addchild(my_dsl_node) # Visit DSL Node in a tree (the tree should not be modified) assert visitor(schedule) == "schedule(return)" assert isinstance(schedule.children[0], MyDSLNode) assert schedule.children[0] is my_dsl_node assert len(schedule.symbol_table.symbols) == 0 # Visit DSL Node directly (the tree is also not modified) assert visitor(my_dsl_node) == "return" assert isinstance(my_dsl_node, MyDSLNode) assert isinstance(schedule.children[0], MyDSLNode) assert len(my_dsl_node.scope.symbol_table.symbols) == 0 # Visit DSL node without a parent, which is an invalid state to # lower this node my_dsl_node.detach() with pytest.raises(VisitorError) as excinfo: visitor(my_dsl_node) assert ( "Failed to lower 'MyDSLNode[]'. Note that some nodes need to be " "lowered from an ancestor in order to properly apply their in-tree " "modifications." in str(excinfo.value))
def test_profile_trans_invalid_name(value): '''Invalid name supplied to options argument.''' profile_trans = ProfileTrans() # We need to have a schedule as parent, otherwise the node # (with no parent) will not be allowed. sched = Schedule() node = Statement(parent=sched) sched.addchild(node) with pytest.raises(TransformationError) as excinfo: _ = profile_trans.apply(node, options={"region_name": value}) assert ("User-supplied region name must be a tuple containing " "two non-empty strings." in str(excinfo.value))
def test_set_lower_bound_functions(): ''' Test that we raise appropriate exceptions when the lower bound of a DynLoop is set to invalid values. ''' schedule = Schedule() my_loop = DynLoop(parent=schedule) schedule.children = [my_loop] with pytest.raises(GenerationError) as excinfo: my_loop.set_lower_bound("invalid_loop_bounds_name") assert "lower bound loop name is invalid" in str(excinfo.value) with pytest.raises(GenerationError) as excinfo: my_loop.set_lower_bound("inner", index=0) assert "specified index" in str(excinfo.value) assert "lower loop bound is invalid" in str(excinfo.value)
def test_fusetrans_error_not_same_parent(): ''' Check that we reject attempts to fuse loops which don't share the same parent ''' loop1 = Loop.create(DataSymbol("i", INTEGER_TYPE), Literal("1", INTEGER_TYPE), Literal("10", INTEGER_TYPE), Literal("1", INTEGER_TYPE), [Return()]) sch1 = Schedule() sch1.addchild(loop1) sch2 = Schedule() loop2 = Loop.create(DataSymbol("j", INTEGER_TYPE), Literal("1", INTEGER_TYPE), Literal("10", INTEGER_TYPE), Literal("1", INTEGER_TYPE), [Return()]) sch2.addchild(loop2) fuse = LoopFuseTrans() # Try to fuse loops with different parents with pytest.raises(TransformationError) as err: fuse.validate(loop1, loop2) assert ("Error in LoopFuseTrans transformation. Loops do not have the " "same parent" in str(err.value))
def test_replace_with(): '''Check that the replace_with method behaves as expected.''' parent_node = Schedule() node1 = Statement() node2 = Statement() node3 = Statement() parent_node.children = [node1, node2, node3] new_node = Assignment() node2.replace_with(new_node) assert parent_node.children[1] is new_node assert new_node.parent is parent_node assert node2.parent is None
def test_goloop_no_parent(): ''' Attempt to generate code for a loop that has no GOInvokeSchedule as a parent ''' # First create with a schedule as one is required to declare the # loop variable schedule = Schedule() goloop = GOLoop(loop_type="inner", parent=schedule) schedule.children = [goloop] # Now remove parent and children goloop.parent = None goloop.children = None # Try and generate the code for this loop even though it # has no parent schedule and no children with pytest.raises(GenerationError): goloop.gen_code(None)
def test_call_noargs(): '''Test that fparser2reader transforms a Fortran subroutine call with no arguments into the equivalent PSyIR Call node. Also test that a new RoutineSymbol is added to the symbol table (with an unresolved interface) when one does not already exist. Also test that the Call node ast property is set to reference the original fparser2 call node. ''' reader = FortranStringReader(" call kernel()") ast = Fortran2003.Call_Stmt(reader) fake_parent = Schedule() processor = Fparser2Reader() processor.process_nodes(fake_parent, [ast]) call_node = fake_parent.children[0] assert isinstance(call_node, Call) assert not call_node.children routine_symbol = call_node.routine assert isinstance(routine_symbol, RoutineSymbol) assert isinstance(routine_symbol.interface, UnresolvedInterface) assert routine_symbol.name == "kernel" assert routine_symbol in call_node.scope.symbol_table.symbols assert (str(call_node)) == "Call[name='kernel']" assert call_node.ast == ast
def test_ubound_lbound_arg_error(): ''' Check that the _copy_full_base_reference utility method raises the expected error if the supplied node is of the wrong type. ''' with pytest.raises(InternalError) as err: _copy_full_base_reference(Schedule()) assert ("supplied node must be an instance of either Reference or " "Member but got 'Schedule'" in str(err.value))
def _process_loopbody(self, loop_body, node): ''' Specialized method to process Nemo loop bodies. If the schedule matches with a NemoKern, it will add a NemoKern instead of statements in the loop_body. :param loop_body: schedule representing the body of the loop. :type loop_body: :py:class:`psyclone.psyir.nodes.Schedule` :param node: fparser loop node being processed. :type node: \ :py:class:`fparser.two.Fortran2003.Block_Nonlabel_Do_Construct` ''' # We create a fake node because we need to parse the children # before we decide what to do with them. fakeparent = Schedule(parent=loop_body) self.process_nodes(parent=fakeparent, nodes=node.content[1:-1]) if NemoKern.match(fakeparent): # Create a new kernel object and make it the only # child of this Loop node. The PSyIR of the loop body becomes # the schedule of this kernel. nemokern = NemoKern(fakeparent.children, node, parent=loop_body) loop_body.children.append(nemokern) else: # Otherwise just connect the new children into the tree. loop_body.children.extend(fakeparent.children) for child in fakeparent.children: child.parent = loop_body
def __init__(self, parent=None, loop_type=""): Loop.__init__(self, parent=parent, valid_loop_types=["", "colours", "colour"]) self.loop_type = loop_type # Work out the variable name from the loop type if self._loop_type == "colours": tag = "colours_loop_idx" suggested_name = "colour" elif self._loop_type == "colour": tag = "colour_loop_idx" suggested_name = "cell" else: tag = "cell_loop_idx" suggested_name = "cell" symtab = self.scope.symbol_table try: data_symbol = symtab.lookup_with_tag(tag) except KeyError: name = symtab.new_symbol_name(suggested_name) data_symbol = DataSymbol(name, INTEGER_TYPE) symtab.add(data_symbol, tag=tag) self.variable = data_symbol # Pre-initialise the Loop children # TODO: See issue #440 self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # start self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # stop self.addchild(Literal("1", INTEGER_TYPE, parent=self)) # step self.addchild(Schedule(parent=self)) # loop body
def process_where(code, fparser_cls, symbols=None): ''' Utility routine to process the supplied Fortran code and return the PSyIR and fparser2 parse trees. :param str code: Fortran code to process. :param type fparser_cls: the fparser2 class to instantiate to \ represent the supplied Fortran. :param symbols: list of symbol names that must be added to the symbol \ table before constructing the PSyIR. :type symbols: list of str :returns: 2-tuple of a parent PSyIR Schedule and the created instance of \ the requested fparser2 class. :rtype: (:py:class:`psyclone.psyir.nodes.Schedule`, \ :py:class:`fparser.two.utils.Base`) ''' sched = Schedule() if symbols: for sym_name in symbols: sched.symbol_table.new_symbol(sym_name) processor = Fparser2Reader() reader = FortranStringReader(code) fparser2spec = fparser_cls(reader) if fparser_cls is Fortran2003.Execution_Part: processor.process_nodes(sched, fparser2spec.content) else: processor.process_nodes(sched, [fparser2spec]) return sched, fparser2spec
def test_get_node_list(): '''Test for valid parameters to get_node_list.''' my_rt = MyRegionTrans() # 1) Provide a schedule # --------------------- sched = Schedule() # get_node_list returns a copy of the list, so it must be a list # with the same content, but NOT the same list: node_list = my_rt.get_node_list(sched) assert sched.children == node_list assert node_list is not sched.children # 2) Provide a single node # ------------------------ node = Node() node_list = my_rt.get_node_list(node) assert node_list == [node] # 3) Provide a node list # ---------------------- # We use the previously returned node list, and make sure # that we get a copy of that list. node_list2 = my_rt.get_node_list(node_list) assert node_list2 == node_list assert node_list2 is not node_list
def test_array_notation_rank(): ''' Check that the _array_notation_rank() utility handles various examples of array notation. TODO #754 fix test so that 'disable_declaration_check' fixture is not required. ''' fake_parent = Schedule() processor = Fparser2Reader() reader = FortranStringReader(" z1_st(:, 2, :) = ptsu(:, :, 3)") fparser2spec = Fortran2003.Assignment_Stmt(reader) processor.process_nodes(fake_parent, [fparser2spec]) assert processor._array_notation_rank(fake_parent[0].lhs) == 2 reader = FortranStringReader(" z1_st(:, :, 2, :) = ptsu(:, :, :, 3)") fparser2spec = Fortran2003.Assignment_Stmt(reader) processor.process_nodes(fake_parent, [fparser2spec]) assert processor._array_notation_rank(fake_parent[1].lhs) == 3 # We don't support bounds on slices reader = FortranStringReader(" z1_st(:, 1:n, 2, :) = ptsu(:, :, :, 3)") fparser2spec = Fortran2003.Assignment_Stmt(reader) processor.process_nodes(fake_parent, [fparser2spec]) with pytest.raises(NotImplementedError) as err: processor._array_notation_rank(fake_parent[2].lhs) assert ("Only array notation of the form my_array(:, :, ...) is " "supported." in str(err.value))
def __init__(self, parent=None, topology_name="", loop_type=""): Loop.__init__(self, parent=parent, valid_loop_types=["inner", "outer"]) self.loop_type = loop_type if self._loop_type == "inner": tag = "inner_loop_idx" suggested_name = "i" elif self.loop_type == "outer": tag = "outer_loop_idx" suggested_name = "j" symtab = self.scope.symbol_table try: self.variable = symtab.lookup_with_tag(tag) except KeyError: self.variable = symtab.new_symbol(suggested_name, tag, symbol_type=DataSymbol, datatype=INTEGER_TYPE) # Pre-initialise the Loop children # TODO: See issue #440 self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # start self.addchild(Literal("NOT_INITIALISED", INTEGER_TYPE, parent=self)) # stop self.addchild(Literal("1", INTEGER_TYPE, parent=self)) # step self.addchild(Schedule(parent=self)) # loop body
def test_loop_navigation_properties(): # pylint: disable=too-many-statements ''' Tests the start_expr, stop_expr, step_expr and loop_body setter and getter properties. ''' loop = Loop() # Properties return an error if the node is incomplete error_str = ("Loop is incomplete. It should have exactly 4 " "children, but found") with pytest.raises(InternalError) as err: _ = loop.start_expr assert error_str in str(err.value) loop.addchild(Literal("start", INTEGER_SINGLE_TYPE)) loop.addchild(Literal("stop", INTEGER_SINGLE_TYPE)) loop.addchild(Literal("step", INTEGER_SINGLE_TYPE)) # If it's not fully complete, it still returns an error with pytest.raises(InternalError) as err: _ = loop.start_expr assert error_str in str(err.value) with pytest.raises(InternalError) as err: _ = loop.stop_expr assert error_str in str(err.value) with pytest.raises(InternalError) as err: _ = loop.step_expr assert error_str in str(err.value) with pytest.raises(InternalError) as err: _ = loop.loop_body assert error_str in str(err.value) with pytest.raises(InternalError) as err: loop.start_expr = Literal("invalid", INTEGER_SINGLE_TYPE) assert error_str in str(err.value) with pytest.raises(InternalError) as err: loop.stop_expr = Literal("invalid", INTEGER_SINGLE_TYPE) assert error_str in str(err.value) with pytest.raises(InternalError) as err: loop.step_expr = Literal("invalid", INTEGER_SINGLE_TYPE) assert error_str in str(err.value) # Check that Getters properties work loop.addchild(Schedule(parent=loop)) loop.loop_body.addchild(Return(parent=loop.loop_body)) assert loop.start_expr.value == "start" assert loop.stop_expr.value == "stop" assert loop.step_expr.value == "step" assert isinstance(loop.loop_body[0], Return) # Test Setters loop.start_expr = Literal("newstart", INTEGER_SINGLE_TYPE) loop.stop_expr = Literal("newstop", INTEGER_SINGLE_TYPE) loop.step_expr = Literal("newstep", INTEGER_SINGLE_TYPE) assert loop.start_expr.value == "newstart" assert loop.stop_expr.value == "newstop" assert loop.step_expr.value == "newstep"
def test_number_handler(): ''' Check that the number_handler raises a NotImplementedError for an unrecognised fparser2 node. ''' processor = Fparser2Reader() fake_parent = Schedule() reader = FortranStringReader("(1.0, 1.0)") with pytest.raises(NotImplementedError): processor._number_handler(Fortran2003.Complex_Literal_Constant(reader), fake_parent)
def test_cw_ifblock(): '''Check the CWriter class ifblock method correctly prints out the C representation. ''' from psyclone.psyir.nodes import IfBlock # Try with just an IfBlock node ifblock = IfBlock() cwriter = CWriter() with pytest.raises(VisitorError) as err: _ = cwriter(ifblock) assert ("IfBlock malformed or incomplete. It should have " "at least 2 children, but found 0." in str(err.value)) # Add the if condition ifblock.addchild(Reference(DataSymbol('a', REAL_TYPE), parent=ifblock)) with pytest.raises(VisitorError) as err: _ = cwriter(ifblock) assert ("IfBlock malformed or incomplete. It should have " "at least 2 children, but found 1." in str(err.value)) # Fill the if_body and else_body ifblock.addchild(Schedule(parent=ifblock)) ifblock.addchild(Schedule(parent=ifblock)) ifblock.if_body.addchild(Return(parent=ifblock.if_body)) condition = Reference(DataSymbol('b', REAL_TYPE)) then_content = [Return()] else_content = [Return()] ifblock2 = IfBlock.create(condition, then_content, else_content) ifblock2.parent = ifblock.if_body ifblock.else_body.addchild(ifblock2) result = cwriter(ifblock) assert result == ("if (a) {\n" " return;\n" "} else {\n" " if (b) {\n" " return;\n" " } else {\n" " return;\n" " }\n" "}\n")
def test_handling_literal_precision_3(value, dprecision): '''Check that the fparser2 frontend can handle literals with a precision value specified by the exponent. The literal value TODO #754 fix test so that 'disable_declaration_check' fixture is not required. should always use a lower case "e" for the exponent. ''' code = "x={0}".format(value) reader = FortranStringReader(code) astmt = Fortran2003.Assignment_Stmt(reader) fake_parent = Schedule() processor = Fparser2Reader() processor.process_nodes(fake_parent, [astmt]) assert not fake_parent.walk(CodeBlock) literal = fake_parent.children[0].children[1] assert isinstance(literal, Literal) assert literal.value.lower() == "0.0e0" assert literal.datatype.intrinsic == ScalarType.Intrinsic.REAL assert literal.datatype.precision == dprecision
def test_sched_init(): ''' Check the Schedule class is initialised as expected.''' # By default Schedule sets parent to None, children to an empty list and # initialises its own symbol table. sched = Schedule() assert isinstance(sched, Schedule) assert not sched.parent assert not sched.children assert isinstance(sched.symbol_table, SymbolTable) # A custom symbol table and parent and children nodes can be given as # arguments of Schedule. symtab = SymbolTable() sched2 = Schedule(parent=sched, children=[Statement(), Statement()], symbol_table=symtab) assert isinstance(sched2, Schedule) assert sched2.parent is sched assert len(sched2.children) == 2 assert sched2.symbol_table is symtab
def test_handling_literal(code, dtype): ''' Check that the fparser2 frontend can handle literals of all supported datatypes. Note that signed literals are represented in the PSyIR as a Unary operation on an unsigned literal. TODO #754 fix test so that 'disable_declaration_check' fixture is not required. ''' reader = FortranStringReader("x=" + code) astmt = Fortran2003.Assignment_Stmt(reader) fake_parent = Schedule() processor = Fparser2Reader() processor.process_nodes(fake_parent, [astmt]) assert not fake_parent.walk(CodeBlock) literal = fake_parent.children[0].children[1] assert isinstance(literal, Literal) assert literal.datatype.intrinsic == dtype if dtype != ScalarType.Intrinsic.BOOLEAN: assert literal.value == code else: assert literal.value == code.lower()[1:-1] # Remove wrapping dots
def test_subscript_triplet_handler_error(): ''' Check that the subscript-triplet handler raises the expected error if the parent PSyIR node is not of the correct type. ''' processor = Fparser2Reader() fake_parent = Schedule() reader = FortranStringReader("x(:) = a") fp2node = Execution_Part.match(reader) triplet = fp2node[0][0].children[0].children[1].children[0] with pytest.raises(InternalError) as err: processor._subscript_triplet_handler(triplet, fake_parent) assert ("Expected parent PSyIR node to be either a Reference or a Member " "but got 'Schedule' when processing ':'" in str(err.value))
def test_children_setter(): ''' Test that the children setter sets-up accepts lists or None or raises the appropriate issue. ''' testnode = Schedule() # children is initialised as a ChildrenList assert isinstance(testnode.children, ChildrenList) # When is set up with a list, this becomes a ChildrenList testnode.children = [Statement(), Statement()] assert isinstance(testnode.children, ChildrenList) # It also accepts None testnode.children = None assert testnode.children is None # Other types are not accepted with pytest.raises(TypeError) as error: testnode.children = Node() assert "The 'my_children' parameter of the node.children setter must be" \ " a list or None." in str(error.value)