def __init__(self, parent, expr="UNSET", typeselect=False): ''' Construct a SelectionGen for creating a SELECT block :param parent: node to which to add this select block as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str expr: the CASE expression :param bool typeselect: whether or not this is a SELECT TYPE rather than a SELECT CASE ''' self._typeselect = typeselect reader = FortranStringReader( "SELECT CASE (x)\nCASE (1)\nCASE DEFAULT\nEND SELECT") reader.set_format(FortranFormat(True, True)) # free form, strict select_line = reader.next() self._case_line = reader.next() self._case_default_line = reader.next() end_select_line = reader.next() if self._typeselect: select = SelectType(parent.root, select_line) else: select = SelectCase(parent.root, select_line) endselect = EndSelect(select, end_select_line) select.expr = expr select.content.append(endselect) BaseGen.__init__(self, parent, select)
def __init__(self, parent, name="", args=None, implicitnone=False): ''' :param parent: node in AST to which to add Subroutine as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str name: name of the Fortran subroutine :param list args: list of arguments accepted by the subroutine :param bool implicitnone: whether or not we should specify "implicit none" for the body of this subroutine ''' reader = FortranStringReader( "subroutine vanilla(vanilla_arg)\nend subroutine") reader.set_format(FortranFormat(True, True)) # free form, strict subline = reader.next() endsubline = reader.next() from fparser.one.block_statements import Subroutine, EndSubroutine self._sub = Subroutine(parent.root, subline) self._sub.name = name if args is None: args = [] self._sub.args = args endsub = EndSubroutine(self._sub, endsubline) self._sub.content.append(endsub) ProgUnitGen.__init__(self, parent, self._sub) if implicitnone: self.add(ImplicitNoneGen(self))
def test_multi_stmt_line1(): '''Check that simple statements separated by ; on a single line are correctly split into multiple lines by FortranReaderBase ''' code = "do i=1,10;b=20 ; c=30" reader = FortranStringReader(code) mode = FortranFormat(True, False) reader.set_format(mode) line1 = reader.next() assert isinstance(line1, Line) assert line1.line == "do i=1,10" assert line1.span == (1, 1) assert line1.label is None assert line1.name is None assert line1.reader is reader line2 = reader.next() assert isinstance(line2, Line) assert line2.line == "b=20" assert line2.span is line1.span assert line2.label is None assert line2.name is None assert line2.reader is reader line3 = reader.next() assert isinstance(line3, Line) assert line3.line == "c=30" assert line3.span is line1.span assert line3.label is None assert line3.name is None assert line3.reader is reader
def __init__(self, parent, datatype="", entity_decls=None, intent="", pointer=False, kind="", dimension="", allocatable=False): ''' :param parent: node to which to add this declaration as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str datatype: the (intrinsic) type for this declaration :param list entity_decls: list of variable names to declare :param str intent: the INTENT attribute of this declaration :param bool pointer: whether or not this is a pointer declaration :param str kind: the KIND attribute to use for this declaration :param str dimension: the DIMENSION specifier (i.e. the xx in DIMENSION(xx)) :param bool allocatable: whether this declaration is for an ALLOCATABLE quantity :raises RuntimeError: if no variable names are specified :raises RuntimeError: if datatype is not one of "integer" or "real" ''' if entity_decls is None: raise RuntimeError( "Cannot create a variable declaration without specifying the " "name(s) of the variable(s)") fort_fmt = FortranFormat(True, False) # free form, strict if datatype.lower() == "integer": reader = FortranStringReader("integer :: vanilla") reader.set_format(fort_fmt) myline = reader.next() self._decl = fparser1.typedecl_statements.Integer(parent.root, myline) elif datatype.lower() == "real": reader = FortranStringReader("real :: vanilla") reader.set_format(fort_fmt) myline = reader.next() self._decl = fparser1.typedecl_statements.Real(parent.root, myline) else: raise RuntimeError( "f2pygen:DeclGen:init: Only integer and real are currently" " supported and you specified '{0}'".format(datatype)) # make a copy of entity_decls as we may modify it local_entity_decls = entity_decls[:] self._decl.entity_decls = local_entity_decls my_attrspec = [] if intent != "": my_attrspec.append("intent({0})".format(intent)) if pointer is not False: my_attrspec.append("pointer") if allocatable is not False: my_attrspec.append("allocatable") self._decl.attrspec = my_attrspec if dimension != "": my_attrspec.append("dimension({0})".format(dimension)) if kind is not "": self._decl.selector = ('', kind) BaseGen.__init__(self, parent, self._decl)
def adduse(name, parent, only=False, funcnames=None): ''' Adds a use statement with the specified name to the supplied object. This routine is required when modifying an existing AST (e.g. when modifying a kernel). The classes are used when creating an AST from scratch (for the PSy layer). :param str name: name of module to USE :param parent: node in fparser1 AST to which to add this USE as a child :type parent: :py:class:`fparser.one.block_statements.*` :param bool only: whether this USE has an "ONLY" clause :param list funcnames: list of quantities to follow the "ONLY" clause :returns: an fparser1 Use object :rtype: :py:class:`fparser.one.block_statements.Use` ''' reader = FortranStringReader("use kern,only : func1_kern=>func1") reader.set_format(FortranFormat(True, True)) # free form, strict myline = reader.next() # find an appropriate place to add in our use statement while not (isinstance(parent, fparser1.block_statements.Program) or isinstance(parent, fparser1.block_statements.Module) or isinstance(parent, fparser1.block_statements.Subroutine)): parent = parent.parent use = fparser1.block_statements.Use(parent, myline) use.name = name use.isonly = only if funcnames is None: funcnames = [] use.isonly = False use.items = funcnames parent.content.insert(0, use) return use
def __init__(self, parent, clause): ''' :param parent: Node to which to add this IfThen as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str clause: the condition, xx, to evaluate in the if(xx)then ''' reader = FortranStringReader("if (dummy) then\nend if") reader.set_format(FortranFormat(True, True)) # free form, strict ifthenline = reader.next() endifline = reader.next() my_if = fparser1.block_statements.IfThen(parent.root, ifthenline) my_if.expr = clause my_endif = fparser1.block_statements.EndIfThen(my_if, endifline) my_if.content.append(my_endif) BaseGen.__init__(self, parent, my_if)
def test_include_not_found(): '''Tests that FortranReaderBase.next() provides the include line when the included file is not found. ''' code = "include 'nonexistant.f90'" unit_under_test = FortranStringReader(code) line = unit_under_test.next() assert str(line.line) == code
def __init__(self, parent, variable_name, start, end, step=None): ''' :param parent: the node to which to add this do loop as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str variable_name: the name of the loop variable :param str start: start value for Do loop :param str end: upper-limit of Do loop :param str step: increment to use in Do loop ''' reader = FortranStringReader("do i=1,n\nend do") reader.set_format(FortranFormat(True, True)) # free form, strict doline = reader.next() enddoline = reader.next() dogen = fparser1.block_statements.Do(parent.root, doline) dogen.loopcontrol = variable_name + "=" + start + "," + end if step is not None: dogen.loopcontrol = dogen.loopcontrol + "," + step enddo = fparser1.block_statements.EndDo(dogen, enddoline) dogen.content.append(enddo) BaseGen.__init__(self, parent, dogen)
def test_multi_stmt_line3(): '''Check that named do loops separated by ; on a single line are correctly split into multiple lines by FortranReaderBase ''' code = "name:do i=1,10;name2 : do j=1,10" reader = FortranStringReader(code) mode = FortranFormat(True, False) reader.set_format(mode) line1 = reader.next() assert isinstance(line1, Line) assert line1.line == "do i=1,10" assert line1.span == (1, 1) assert line1.label is None assert line1.name == "name" assert line1.reader is reader line2 = reader.next() assert line2.line == "do j=1,10" assert line2.span is line1.span assert line2.label is None assert line2.name == "name2" assert line2.reader is reader
def test_multi_stmt_line2(): '''Check that format statements separated by ; on a single line are correctly split into multiple lines by FortranReaderBase ''' code = "10 format(a); 20 format(b)" reader = FortranStringReader(code) mode = FortranFormat(True, False) reader.set_format(mode) line1 = reader.next() assert isinstance(line1, Line) assert line1.line == "format(a)" assert line1.span == (1, 1) assert line1.label == 10 assert line1.name is None assert line1.reader is reader line2 = reader.next() assert line2.line == "format(b)" assert line2.span is line1.span assert line2.label == 20 assert line2.name is None assert line2.reader is reader
def __init__(self, parent, content): ''' :param parent: node in AST to which to add the Comment as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str content: the content of the comment ''' reader = FortranStringReader("! content\n") reader.set_format(FortranFormat(True, True)) # free form, strict subline = reader.next() my_comment = Comment(parent.root, subline) my_comment.content = content BaseGen.__init__(self, parent, my_comment)
def __init__(self, parent, name="", args=None): ''' :param parent: node in AST to which to add CallGen as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str name: the name of the routine to call :param list args: list of arguments to pass to the call ''' reader = FortranStringReader("call vanilla(vanilla_arg)") reader.set_format(FortranFormat(True, True)) # free form, strict myline = reader.next() from fparser.one.block_statements import Call self._call = Call(parent.root, myline) self._call.designator = name if args is None: args = [] self._call.items = args BaseGen.__init__(self, parent, self._call)
def test_base_next_good_include(log): ''' Tests that FortranReaderBase.next() causes a message to be logged when a file is included. ''' code = "include 'modfile.f95'\nx=2" include_directories = [os.path.dirname(__file__)] unit_under_test = FortranStringReader( code, include_dirs=include_directories, ignore_comments=False) line = unit_under_test.next() assert str(line)[:19] == "Comment('! Modified" # First line of inclusion assert log.messages['debug'] == [] assert log.messages['error'] == [] assert log.messages['warning'] == [] assert log.messages['critical'] == [] expected = " 1:include 'modfile.f95' " \ + "<== including file '{path}/modfile.f95'" result = log.messages['info'][0].split('\n')[1] assert re.sub("u", "", result) == \ re.sub("u", "", expected.format(path=include_directories[0]))
def __init__(self, parent): ''' :param parent: node in AST to which to add 'implicit none' as a child :type parent: :py:class:`psyclone.f2pygen.ModuleGen` or :py:class:`psyclone.f2pygen.SubroutineGen` :raises Exception: if `parent` is not a ModuleGen or SubroutineGen ''' if not isinstance(parent, ModuleGen) and not isinstance(parent, SubroutineGen): raise Exception( "The parent of ImplicitNoneGen must be a module or a " "subroutine, but found {0}".format(type(parent))) reader = FortranStringReader("IMPLICIT NONE\n") reader.set_format(FortranFormat(True, True)) # free form, strict subline = reader.next() from fparser.one.typedecl_statements import Implicit my_imp_none = Implicit(parent.root, subline) BaseGen.__init__(self, parent, my_imp_none)
def __init__(self, parent, lhs="", rhs="", pointer=False): ''' :param parent: the node to which to add this assignment as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str lhs: the LHS of the assignment expression :param str rhs: the RHS of the assignment expression :param bool pointer: whether or not this is a pointer assignment ''' if pointer: reader = FortranStringReader("lhs=>rhs") else: reader = FortranStringReader("lhs=rhs") reader.set_format(FortranFormat(True, True)) # free form, strict myline = reader.next() if pointer: self._assign = fparser1.statements.PointerAssignment(parent.root, myline) else: self._assign = fparser1.statements.Assignment(parent.root, myline) self._assign.expr = rhs self._assign.variable = lhs BaseGen.__init__(self, parent, self._assign)
def __init__(self, parent, content): ''' :param parent: node to which to add this DEALLOCATE as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param content: string or list of variables to deallocate :type content: list of strings or a single string :raises RuntimeError: if `content` is not of correct type ''' reader = FortranStringReader("deallocate(dummy)") reader.set_format(FortranFormat(True, False)) # free form, strict myline = reader.next() self._decl = fparser1.statements.Deallocate(parent.root, myline) if isinstance(content, str): self._decl.items = [content] elif isinstance(content, list): self._decl.items = content else: raise RuntimeError( "DeallocateGen expected the content argument to be a str" " or a list, but found {0}".format(type(content))) BaseGen.__init__(self, parent, self._decl)
def __init__(self, parent, name="", only=False, funcnames=None): ''' :param parent: node in AST to which to add UseGen as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str name: name of the module to USE :param bool only: whether this USE has an ONLY clause :param list funcnames: list of names to follow ONLY clause ''' reader = FortranStringReader("use kern,only : func1_kern=>func1") reader.set_format(FortranFormat(True, True)) # free form, strict myline = reader.next() root = parent.root from fparser.one.block_statements import Use use = Use(root, myline) use.name = name use.isonly = only if funcnames is None: funcnames = [] use.isonly = False local_funcnames = funcnames[:] use.items = local_funcnames BaseGen.__init__(self, parent, use)
def __init__(self, parent, language, position, directive_type, content): ''' :param parent: node in AST to which to add directive as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str language: the type of directive (e.g. OMP or ACC) :param str position: "end" if this is the end of a directive block :param str directive_type: the directive itself (e.g. "PARALLEL DO") :param str content: any additional arguments to add to the directive (e.g. "PRIVATE(ji)") :raises RuntimeError: if an unrecognised directive language is specified ''' self._supported_languages = ["omp"] self._language = language self._directive_type = directive_type reader = FortranStringReader("! content\n") reader.set_format(FortranFormat(True, True)) # free form, strict subline = reader.next() if language == "omp": my_comment = OMPDirective(parent.root, subline, position, directive_type) my_comment.content = "$omp" if position == "end": my_comment.content += " end" my_comment.content += " " + directive_type if content != "": my_comment.content += " " + content else: raise RuntimeError( "Error, unsupported directive language. Expecting one of " "{0} but found '{1}'".format(str(self._supported_languages), language)) BaseGen.__init__(self, parent, my_comment)
def __init__(self, parent, datatype="", entity_decls=None, intent="", pointer=False, attrspec=None): ''' :param parent: the node to which to add this type delcn as a child :type parent: :py:class:`psyclone.f2pygen.BaseGen` :param str datatype: the derived type :param list entity_decls: List of variable names to declare :param str intent: the intent attribute for the declaration :param bool pointer: whether or not this is a pointer declaration :param attrspec: list of other attributes to add to declaration :raises RuntimeError: if no variable names are specified ''' if entity_decls is None: raise RuntimeError( "Cannot create a declaration of a derived-type variable " "without specifying the name(s) of the variable(s)") # make a copy of entity_decls as we may modify it local_entity_decls = entity_decls[:] if attrspec is None: attrspec = [] my_attrspec = [spec for spec in attrspec] if intent != "": my_attrspec.append("intent({0})".format(intent)) if pointer is not False: my_attrspec.append("pointer") self._names = local_entity_decls reader = FortranStringReader("type(vanillatype) :: vanilla") reader.set_format(FortranFormat(True, False)) # free form, strict myline = reader.next() self._typedecl = fparser1.typedecl_statements.Type(parent.root, myline) self._typedecl.selector = ('', datatype) self._typedecl.attrspec = my_attrspec self._typedecl.entity_decls = local_entity_decls BaseGen.__init__(self, parent, self._typedecl)