40 '''Module that uses the Fortran parser fparser1 to parse
41 PSyclone-conformant kernel code.
48 from pyparsing
import ParseException
51 from fparser.two.parser
import ParserFactory
52 from fparser.two
import Fortran2003
53 from fparser.two.utils
import walk
55 from fparser
import one
as fparser1
56 from fparser
import api
as fpapi
57 from fparser.one
import parsefortran
65 def get_kernel_filepath(module_name, kernel_paths, alg_filename):
66 '''Search for a kernel module file containing a module with
67 'module_name'. The assumed convention is that the name of the
68 kernel file is the name of the module with .f90 or .F90 appended.
70 Look in the directories and all subdirectories associated with the
71 supplied kernel paths or in the same directory as the algorithm
72 file if not found within the kernel paths.
74 Return the filepath if the file is found.
76 :param str module_name: the name of the module to search for. The \
77 assumption is that the file containing the module will have the \
78 same name as the module name with .f90 or .F90 appended.
79 :param kernel_paths: directories in which to search for the module \
80 file. If nothing is supplied then look in the same directory \
81 as the algorithm file. Directories below the specified \
82 directories are recursively searched.
83 :type list_kernels: list of str
84 :param str alg_filename: the name of the algorithm file. This is \
85 used to determine its directory location if required.
87 :returns: a filepath to the file containing the specified module \
91 :raises ParseError: if the supplied kernel directory does not \
93 :raises ParseError: if the file can not be found.
94 :raises ParseError: if more than one file with the specified name \
101 search_string = f
"{module_name}.F90"
106 for kernel_path
in kernel_paths:
109 cdir = os.path.abspath(kernel_path)
111 if not os.access(cdir, os.R_OK):
113 f
"kernel.py:get_kernel_filepath: Supplied kernel search path "
114 f
"does not exist or cannot be read: {cdir}")
118 for root, _, filenames
in os.walk(cdir):
119 for filename
in filenames:
121 if filename.lower() == search_string.lower():
122 matches.append(os.path.join(root, filename))
126 cdir = os.path.abspath(os.path.dirname(alg_filename))
127 filenames = os.listdir(cdir)
128 for filename
in filenames:
130 if filename.lower() == search_string.lower():
131 matches.append(os.path.join(cdir, filename))
136 f
"Kernel file '{module_name}.[fF]90' not found in {cdir}")
140 f
"kernel.py:get_kernel_filepath: More than one match for kernel "
141 f
"file '{module_name}.[fF]90' found!")
146 def get_kernel_parse_tree(filepath):
147 '''Parse the file in filepath with fparser1 and return a parse tree.
149 :param str filepath: path to a file (hopefully) containing \
150 PSyclone kernel code.
152 :returns: Parse tree of the kernel code contained in the specified \
154 :rtype: :py:class:`fparser.one.block_statements.BeginSource`
156 :raises ParseError: if fparser fails to parse the file
159 parsefortran.FortranParser.cache.clear()
163 if 'sphinx.ext.doctest' not in sys.modules:
164 fparser.logging.disable(fparser.logging.CRITICAL)
167 parse_tree = fpapi.parse(filepath)
173 except Exception
as err:
175 f
"Failed to parse kernel code '{filepath}'. Is the Fortran "
176 f
"correct?")
from err
180 def get_kernel_ast(module_name, alg_filename, kernel_paths, line_length):
181 '''Search for the kernel source code containing a module with the name
182 'module_name' looking in the directory and subdirectories
183 associated with the supplied 'kernel_paths' or in the same
184 directory as the 'algorithm_filename' if the kernel path is
185 empty. If the file is found then check it conforms to the
186 'line_length' restriction if this is set and then parse this file
187 and return the parsed file.
189 :param str module_name: the name of the module to search for.
190 :param str alg_filename: the name of the algorithm file.
191 :param kernel_paths: directory in which to search for the module \
193 :type kernel_paths: list of str
194 :param bool line_length: whether to check that the kernel code \
195 conforms to the 132 character line length limit (True) or not \
198 :returns: Parse tree of the kernel module with the name 'module_name'.
199 :rtype: :py:class:`fparser.one.block_statements.BeginSource`
202 filepath = get_kernel_filepath(module_name, kernel_paths, alg_filename)
204 check_line_length(filepath)
205 parse_tree = get_kernel_parse_tree(filepath)
211 '''Factory to create the required API-specific information about
212 coded-kernel metadata and a reference to its code.
214 :param str api: The API for which this factory is to create Kernel \
215 information. If it is not supplied then the default API, as \
216 specified in the PSyclone config file, is used.
219 def __init__(self, api=""):
221 _config = Config.get()
222 self.
_type_type = _config.default_api
225 self.
_type_type = api
228 '''Create API-specific information about the kernel metadata and a
229 reference to its code. The API is set when the factory is
232 :param parse_tree: The fparser1 parse tree for the Kernel code.
233 :type parse_tree: :py:class:`fparser.one.block_statements.BeginSource`
235 :param name: the name of the Kernel. Defaults to None if \
237 :type name: str or NoneType
239 :raises ParseError: if the supplied API is not supported.
244 if self.
_type_type ==
"dynamo0.3":
246 return LFRicKernMetadata(parse_tree, name=name)
247 if self.
_type_type ==
"gocean1.0":
249 return GOKernelType1p0(parse_tree, name=name)
251 f
"KernelTypeFactory:create: Unsupported kernel type '{self._type}'"
256 '''Create API-specific information about the builtin metadata. The API
257 is set when the factory is created. Subclasses KernelTypeFactory
258 and makes use of its init method.
262 def create(self, builtin_names, builtin_defs_file, name=None):
263 '''Create API-specific information about the builtin metadata. This
264 method finds and parses the metadata then makes use of the
265 KernelTypeFactory parent class to return the api-specific
266 information about the builtin.
268 :param builtin_names: a list of valid builtin names
269 :type builtin_names: list of str
270 :param str builtin_defs_file: the file containing builtin \
272 :param name: the name of the builtin. Defaults to None if \
274 :type name: str or NoneType
276 :raises ParseError: if the supplied name is not one of the \
278 :raises ParseError: if the supplied name is recognised as a \
279 builtin but the associated file containing the required \
280 metadata can not be found.
281 :raises ParseError: if the metadata for the supplied builtin \
285 if name
not in builtin_names:
287 f
"BuiltInKernelTypeFactory:create unrecognised built-in name. "
288 f
"Got '{name}' but expected one of {builtin_names}")
291 fname = os.path.join(
292 os.path.dirname(os.path.abspath(__file__)),
294 if not os.path.isfile(fname):
296 f
"BuiltInKernelTypeFactory:create Kernel '{name}' is a "
297 f
"recognised Built-in but cannot find file '{fname}' "
298 f
"containing the meta-data describing the Built-in operations "
299 f
"for API '{self._type}'")
302 parsefortran.FortranParser.cache.clear()
303 fparser.logging.disable(fparser.logging.CRITICAL)
304 parse_tree = fpapi.parse(fname)
305 except Exception
as err:
307 f
"BuiltInKernelTypeFactory:create: Failed to parse the meta-"
308 f
"data for PSyclone built-ins in file '{fname}'.")
from err
312 return KernelTypeFactory.create(self, parse_tree, name)
316 def get_mesh(metadata, valid_mesh_types):
318 Returns the mesh-type described by the supplied meta-data
320 :param metadata: node in parser ast
321 :type metadata: py:class:`psyclone.expression.NamedArg`
322 :param valid_mesh_types: List of valid mesh types
323 :type valid_mesh_types: list of strings
325 :return: the name of the mesh
328 :raises ParseError: if the supplied meta-data is not a recognised \
330 :raises ParseError: if the mesh type is unsupported.
333 if not isinstance(metadata, expr.NamedArg)
or \
334 metadata.name.lower() !=
"mesh_arg":
336 f
"{metadata} is not a valid mesh identifier (expected "
337 f
"mesh_arg=MESH_TYPE where MESH_TYPE is one of "
338 f
"{valid_mesh_types}))")
339 mesh = metadata.value.lower()
340 if mesh
not in valid_mesh_types:
341 raise ParseError(f
"mesh_arg must be one of {valid_mesh_types} but got "
346 def get_stencil(metadata, valid_types):
347 '''Returns stencil_type and stencil_extent as a dictionary
348 object from stencil metadata if the metadata conforms to the
349 stencil(type[,extent]) format
351 :param metadata: Component of kernel meta-data stored as a node in \
353 :type metadata: :py:class:`psyclone.expression.FunctionVar`
354 :param list valid_types: List of valid stencil types (strings)
356 :return: The stencil type and extent described in the meta-data
357 :rtype: dict with keys 'type' (str) and 'extent' (int)
359 :raises ParseError: if the supplied meta-data is not a recognised \
360 stencil specification
364 if not isinstance(metadata, expr.FunctionVar):
366 f
"Expecting format stencil(<type>[,<extent>]) but found the "
367 f
"literal {metadata}")
368 if metadata.name.lower() !=
"stencil" or not metadata.args:
370 f
"Expecting format stencil(<type>[,<extent>]) but found {metadata}"
372 if len(metadata.args) > 2:
374 f
"Expecting format stencil(<type>[,<extent>]) so there must "
375 f
"be at most two arguments inside the brackets {metadata}")
376 if not isinstance(metadata.args[0], expr.FunctionVar):
377 if isinstance(metadata.args[0], str):
379 f
"Expecting format stencil(<type>[,<extent>]). However, "
380 f
"the specified <type> '{metadata.args[0]}' is a literal and "
381 f
"therefore is not one of the valid types '{valid_types}'")
383 f
"Internal error, expecting either FunctionVar or str from the "
384 f
"expression analyser but found {type(metadata.args[0])}")
385 if metadata.args[0].args:
387 "Expected format stencil(<type>[,<extent>]). However, the "
388 "specified <type> '{0}' includes brackets")
389 stencil_type = metadata.args[0].name
390 if stencil_type
not in valid_types:
392 f
"Expected format stencil(<type>[,<extent>]). However, the "
393 f
"specified <type> '{stencil_type}' is not one of the valid types "
396 stencil_extent =
None
397 if len(metadata.args) == 2:
398 if not isinstance(metadata.args[1], str):
400 f
"Expected format stencil(<type>[,<extent>]). However, the "
401 f
"specified <extent> '{metadata.args[1]}' is not an integer")
402 stencil_extent = int(metadata.args[1])
403 if stencil_extent < 1:
405 f
"Expected format stencil(<type>[,<extent>]). However, the "
406 f
"specified <extent> '{stencil_extent}' is less than 1")
407 raise NotImplementedError(
408 "Kernels with fixed stencil extents are not currently "
410 return {
"type": stencil_type,
"extent": stencil_extent}
415 A description of how a kernel argument is accessed, constructed from
418 :param str access: whether argument is read/write etc.
419 :param str space: which function space/grid-point type argument is on.
420 :param int metadata_index: position of this argument in the list of \
421 arguments specified in the metadata.
422 :param dict stencil: type of stencil access for this argument. \
423 Defaults to None if the argument is not supplied.
424 :param str mesh: which mesh this argument is on. Defaults to None \
425 if the argument is not supplied.
426 :param str argument_type: the type of this argument. Defaults to \
427 None if the argument is not supplied.
429 :raises InternalError: if the metadata_index argument is not an int or is \
434 def __init__(self, access, space, metadata_index, stencil=None, mesh=None,
438 if not isinstance(metadata_index, int)
or metadata_index < 0:
440 f
"The metadata index must be an integer and greater than or "
441 f
"equal to zero but got: {metadata_index}")
444 self.
_mesh_mesh = mesh
450 :returns: whether argument is read/write etc.
459 :returns: which function space/grid-point type argument is on.
468 :returns: the position of the corresponding argument descriptor in \
477 :returns: type of stencil access for this argument.
478 :rtype: dict or NoneType
486 :returns: the mesh the argument is on.
487 :rtype: str or NoneType
490 return self.
_mesh_mesh
495 :returns: the type of the argument depending on the specific \
496 API (e.g. scalar, field, grid property, operator).
497 :rtype: str or NoneType
503 return (f
"Descriptor({self.access}, {self.function_space}, "
504 f
"{self.metadata_index})")
509 Captures the parse tree and name of a kernel subroutine.
511 :param ktype_ast: the fparser1 parse tree for the Kernel meta-data.
512 :type ktype_ast: :py:class:`fparser.one.block_statements.Type`
513 :param str ktype_name: name of the Fortran type holding the Kernel \
515 :param modast: the fparser1 parse tree for the module containing the \
517 :type modast: :py:class:`fparser.one.block_statements.BeginSource`
520 def __init__(self, ktype_ast, ktype_name, modast):
521 self._ast, self.
_name_name = KernelProcedure.get_procedure(
522 ktype_ast, ktype_name, modast)
528 Get the name of the subroutine associated with the Kernel. This is
529 a type-bound procedure in the meta-data which may take one of three
531 PROCEDURE, nopass :: code => <proc_name>
533 PROCEDURE, nopass :: <proc_name>
534 or if there is no type-bound procedure, an interface may be used:
535 INTERFACE <proc_name>
537 :param ast: the fparser1 parse tree for the Kernel meta-data.
538 :type ast: :py:class:`fparser.one.block_statements.Type`
539 :param str name: the name of the Fortran type holding the Kernel \
541 :param modast: the fparser1 parse tree for the module containing the \
543 :type modast: :py:class:`fparser.one.block_statements.BeginSource`
545 :returns: 2-tuple of the fparser1 parse tree of the Subroutine \
546 statement and the name of that Subroutine.
547 :rtype: (:py:class:`fparser1.block_statements.Subroutine`, str)
549 :raises ParseError: if the supplied Kernel meta-data does not \
550 have a type-bound procedure or interface.
551 :raises ParseError: if no implementation is found for the \
552 type-bound procedure or interface module \
554 :raises ParseError: if the type-bound procedure specifies a binding \
555 name but the generic name is not "code".
556 :raises InternalError: if we get an empty string for the name of the \
557 type-bound procedure.
561 for statement
in ast.content:
562 if isinstance(statement, fparser1.statements.SpecificBinding):
567 if statement.name.lower() !=
"code":
569 f
"Kernel type {name} binds to a specific procedure"
570 f
" but does not use 'code' as the generic name.")
571 bname = statement.bname.lower()
573 bname = statement.name.lower()
578 bname, subnames = get_kernel_interface(name, modast)
582 f
"Kernel type {name} does not bind a specific procedure "
583 f
"or provide an explicit interface")
586 f
"Empty Kernel name returned for Kernel type {name}.")
592 for subname
in subnames:
593 for statement, _
in fpapi.walk(modast):
594 if isinstance(statement,
595 fparser1.block_statements.Subroutine) \
596 and statement.name.lower() \
598 procedure_count = procedure_count + 1
599 if procedure_count == 1:
607 f
"kernel.py:KernelProcedure:get_procedure: Kernel "
608 f
"subroutine '{subname}' not found.")
614 :returns: the name of the kernel subroutine
618 return self.
_name_name
623 :returns: the parse tree of the kernel subroutine
624 :rtype: :py:class:`fparser.one.block_statements.Subroutine`
630 return f
"KernelProcedure({self.name})"
633 return str(self._ast)
636 def get_kernel_metadata(name, ast):
637 '''Takes the kernel module parse tree and returns the metadata part
638 of the parse tree (a Fortran type) with the name 'name'.
640 :param str name: the metadata name (of a Fortran type). Also \
641 the name referencing the kernel in the algorithm layer. The name \
642 provided and the name of the kernel in the parse tree are case \
643 insensitive in this function.
644 :param ast: parse tree of the kernel module code
645 :type ast: :py:class:`fparser.one.block_statements.BeginSource`
647 :returns: Parse tree of the metadata (a Fortran type with name \
649 :rtype: :py:class:`fparser.one.block_statements.Type`
651 :raises ParseError: if the metadata type name is not found in \
652 the kernel code parse tree
656 for statement, _
in fpapi.walk(ast):
657 if isinstance(statement, fparser1.block_statements.Type) \
658 and statement.name.lower() == name.lower():
662 raise ParseError(f
"Kernel type {name} does not exist")
666 def get_kernel_interface(name, ast):
667 '''Takes the kernel module parse tree and returns the interface part
670 :param str name: The kernel name
671 :param ast: parse tree of the kernel module code
672 :type ast: :py:class:`fparser.one.block_statements.BeginSource`
674 :returns: Name of the interface block and the names of the module \
675 procedures (lower case). Or None, None if there is no \
676 interface or the interface has no nodule procedures.
677 :rtype: : `str`, list of str`.
679 :raises ParseError: if more than one interface is found.
685 for statement, _
in fpapi.walk(ast):
686 if isinstance(statement, fparser1.block_statements.Interface):
690 raise ParseError(f
"Module containing kernel {name} has more "
691 f
"than one interface, this is forbidden in "
694 if statement.a.module_procedures:
695 iname = statement.name.lower()
701 sname = [str(sname).lower()
for sname
702 in statement.a.module_procedures]
706 def getkerneldescriptors(name, ast, var_name='meta_args', var_type=None):
707 '''Get the required argument metadata information for a kernel.
709 :param str name: the name of the kernel (for error messages).
710 :param ast: metadata describing kernel arguments.
711 :type ast: :py:class:`fparser.one.block_statements.Type`
712 :param str var_name: the name of the variable storing the \
713 argument metadata. this argument is optional and defaults to \
715 :param str var_type: the type of the structure constructor used to \
716 define the meta-data or None.
718 :returns: argument metadata parsed using the expression parser \
719 (as fparser1 will not parse expressions and arguments).
720 :rtype: :py:class:`psyclone.expression.LiteralArray`
722 :raises ParseError: if 'var_name' is not found in the metadata.
723 :raises ParseError: if 'var_name' is not an array.
724 :raises ParseError: if 'var_name' is not a 1D array.
725 :raises ParseError: if the structure constructor uses '[...]' \
726 as only '(/.../)' is supported.
727 :raises ParseError: if the argument metadata is invalid and cannot \
729 :raises ParseError: if the dimensions specified do not tally with \
730 the number of metadata arguments.
731 :raises ParseError: if var_type is specified and a structure \
732 constructor for a different type is found.
734 descs = ast.get_variable(var_name)
735 if "INTEGER" in str(descs):
739 f
"No variable named '{var_name}' found in the metadata for kernel "
740 f
"'{name}': '{str(ast).strip()}'.")
742 nargs = int(descs.shape[0])
743 except AttributeError
as err:
745 f
"In kernel metadata '{name}': '{var_name}' variable must be an "
747 if len(descs.shape) != 1:
749 f
"In kernel metadata '{name}': '{var_name}' variable must be a 1 "
750 f
"dimensional array.")
751 if descs.init.find(
"[") != -1
and descs.init.find(
"]") != -1:
754 f
"Parser does not currently support '[...]' initialisation for "
755 f
"'{var_name}', please use '(/.../)' instead.")
757 inits = expr.FORT_EXPRESSION.parseString(descs.init)[0]
758 except ParseException
as err:
759 raise ParseError(f
"Kernel metadata has an invalid format "
760 f
"{descs.init}.")
from err
761 nargs = int(descs.shape[0])
762 if len(inits) != nargs:
764 f
"In the '{var_name}' metadata, the number of items in the array "
765 f
"constructor ({len(inits)}) does not match the extent of the "
769 if not all(init.name == var_type
for init
in inits):
771 f
"The '{var_name}' metadata must consist of an array of "
772 f
"structure constructors, all of type '{var_type}' but found: "
773 f
"{[str(init.name) for init in inits]}.")
778 '''Base class for describing Kernel Metadata.
780 This contains the name of the elemental procedure and metadata associated
781 with how that procedure is mapped over mesh entities.
783 :param ast: fparser1 AST for the parsed kernel meta-data.
784 :type ast: :py:class:`fparser.one.block_statements.BeginSource`
785 :param str name: name of the Fortran derived type describing the kernel.
787 :raises ParseError: if the supplied AST does not contain a Fortran \
789 :raises ParseError: if the module name is too short to contain \
791 :raises ParseError: if the module name does not end in '_mod'.
794 def __init__(self, ast, name=None):
802 for statement, _
in fpapi.walk(ast):
803 if isinstance(statement, fparser1.block_statements.Module):
804 module_name = statement.name
809 "Error KernelType, the file does not contain a module. "
810 "Is it a Kernel file?")
812 mn_len = len(module_name)
815 f
"Error, module name '{module_name}' is too short to have "
816 f
"'_mod' as an extension. This convention is assumed.")
817 base_name = module_name.lower()[:mn_len-4]
818 extension_name = module_name.lower()[mn_len-4:mn_len]
819 if extension_name !=
"_mod":
821 f
"Error, module name '{module_name}' does not have '_mod' "
822 f
"as an extension. This convention is assumed.")
823 name = base_name +
"_type"
825 self.
_name_name = name
827 self.
_ktype_ktype = get_kernel_metadata(name, ast)
848 if operates_on
and iterates_over:
849 raise ParseError(f
"The metadata for kernel '{name}' contains both "
850 f
"'operates_on' and 'iterates_over'. Only one of "
851 f
"these is permitted.")
853 self.
_inits_inits = getkerneldescriptors(name, self.
_ktype_ktype)
859 :returns: the name of the kernel subroutine.
863 return self.
_name_name
868 :returns: the name of the iteration space supported by this kernel
877 :returns: a kernelprocedure instance which contains a parse tree \
878 of the kernel subroutine and its name.
879 :rtype: :py:class:`psyclone.parse.kernel.KernelProcedure`
887 :returns: the number of arguments specified in the metadata.
896 :returns: a list of API-specific argument descriptors.
897 :rtype: list of API-specific specialisation of \
898 :py:class:`psyclone.kernel.Descriptor`
904 return f
"KernelType({self.name}, {self.iterates_over})"
907 ''' Parse the kernel meta-data and find the value of the
908 integer variable with the supplied name. Return None if no
909 matching variable is found. The search is not case sensitive.
911 :param str name: the name of the integer variable to find.
913 :return: value of the specified integer variable (lower case) or None.
916 :raises ParseError: if the RHS of the assignment is not a Name.
920 _ = ParserFactory().create(std=
"f2008")
922 lower_name = name.lower()
924 for statement, _
in fpapi.walk(self.
_ktype_ktype):
925 if isinstance(statement, fparser1.typedecl_statements.Integer):
929 assign = Fortran2003.Assignment_Stmt(
930 statement.entity_decls[0])
931 if str(assign.items[0]).lower() == lower_name:
932 if not isinstance(assign.items[2], Fortran2003.Name):
934 f
"get_integer_variable: RHS of assignment is not "
935 f
"a variable name: '{assign}'")
936 return str(assign.items[2]).lower()
940 ''' Parse the kernel meta-data and find the values of the
941 integer array variable with the supplied name. Returns an empty list
942 if no matching variable is found. The search is not case sensitive.
944 :param str name: the name of the integer array to find.
946 :return: list of values (lower-case).
949 :raises InternalError: if we fail to parse the LHS of the array \
950 declaration or the array constructor.
951 :raises ParseError: if the array is not of rank 1.
952 :raises ParseError: if the array extent is not specified using an \
954 :raises ParseError: if the RHS of the declaration is not an array \
956 :raises InternalError: if the parse tree for the array constructor \
957 does not have the expected structure.
958 :raises ParseError: if the number of items in the array constructor \
959 does not match the extent of the array.
963 _ = ParserFactory().create(std=
"f2008")
965 lower_name = name.lower()
967 for statement, _
in fpapi.walk(self.
_ktype_ktype):
968 if not isinstance(statement, fparser1.typedecl_statements.Integer):
973 assign = Fortran2003.Assignment_Stmt(statement.entity_decls[0])
974 names = walk(assign.children, Fortran2003.Name)
979 if str(names[0]).lower() != lower_name:
983 if not isinstance(assign.children[0], Fortran2003.Part_Ref):
987 if not isinstance(assign.children[0].children[1],
988 Fortran2003.Section_Subscript_List):
990 f
"get_integer_array: expected array declaration to have a "
991 f
"Section_Subscript_List but found "
992 f
"'{type(assign.children[0].children[1]).__name__}' "
995 dim_stmt = assign.children[0].children[1]
996 if len(dim_stmt.children) != 1:
998 f
"get_integer_array: array must be 1D but found an array "
999 f
"with {len(dim_stmt.children)} dimensions for name '"
1001 if not isinstance(dim_stmt.children[0],
1002 Fortran2003.Int_Literal_Constant):
1004 f
"get_integer_array: array extent must be specified using "
1005 f
"an integer literal but found '{dim_stmt.children[0]}' "
1006 f
"for array '{name}'")
1008 array_extent = int(str(dim_stmt.children[0]))
1010 if not isinstance(assign.children[2],
1011 Fortran2003.Array_Constructor):
1013 f
"get_integer_array: RHS of assignment is not "
1014 f
"an array constructor: '{assign}'")
1019 names = walk(assign.children[2].children, Fortran2003.Name)
1022 f
"'{assign.items[2]}'")
1023 if len(names) != array_extent:
1027 f
"get_integer_array: declared length of array '{name}' is "
1028 f
"{array_extent} but constructor only contains "
1029 f
"{len(names)} names: '{assign}'")
1030 return [str(name).lower()
for name
in names]
def create(self, builtin_names, builtin_defs_file, name=None)
def get_procedure(ast, name, modast)
def create(self, parse_tree, name=None)
def arg_descriptors(self)
def get_integer_array(self, name)
def get_integer_variable(self, name)