36 '''Module that uses the Fortran parser fparser2 to parse
37 PSyclone-conformant Algorithm code.
41 from collections
import OrderedDict
43 from fparser.two.utils
import walk
45 from fparser.two.Fortran2003
import Main_Program, Module, \
46 Subroutine_Subprogram, Function_Subprogram, Use_Stmt, Call_Stmt, \
47 Actual_Arg_Spec, Data_Ref, Part_Ref, Char_Literal_Constant, \
48 Section_Subscript_List, Name, Real_Literal_Constant, \
49 Int_Literal_Constant, Function_Reference, Level_2_Unary_Expr, \
50 Add_Operand, Parenthesis, Structure_Constructor, Component_Spec_List, \
51 Proc_Component_Ref, Kind_Selector, Type_Declaration_Stmt, \
52 Declaration_Type_Spec, Entity_Decl, Intrinsic_Type_Spec, \
53 Data_Component_Def_Stmt, Component_Decl
70 def parse(alg_filename, api="", invoke_name="invoke", kernel_paths=None,
72 '''Takes a PSyclone conformant algorithm file as input and outputs a
73 parse tree of the code contained therein and an object containing
74 information about the 'invoke' calls in the algorithm file and any
75 associated kernels within the invoke calls.
77 :param str alg_filename: the file containing the algorithm \
79 :param str api: the PSyclone API to use when parsing the \
80 code. Defaults to empty string.
81 :param str invoke_name: the expected name of the invocation calls \
82 in the algorithm code. Defaults to "invoke".
83 :param kernel_paths: the paths to search for kernel source files \
84 (if different from the location of the algorithm source). \
86 :type kernel_paths: list of str or NoneType
87 :param bool line_length: a logical flag specifying whether we care \
88 about line lengths being longer than 132 characters. If so, \
89 the input (algorithm and kernel) code is checked to make sure \
90 that it conforms and an error raised if not. The default is \
93 :returns: 2-tuple consisting of the fparser2 parse tree of the \
94 Algorithm file and an object holding details of the invokes \
96 :rtype: (:py:class:`fparser.two.Fortran2003.Program`, \
97 :py:class:`psyclone.parse.FileInfo`)
101 >>> from psyclone.parse.algorithm import parse
102 >>> ast, info = parse(SOURCE_FILE)
105 if kernel_paths
is None:
109 my_parser = Parser(api, invoke_name, kernel_paths, line_length)
110 return my_parser.parse(alg_filename)
115 '''Supports the parsing of PSyclone conformant algorithm code within a
116 file and extraction of relevant information for any 'invoke' calls
117 contained within the code.
119 :param str api: the PSyclone API to use when parsing the code.
120 :param str invoke_name: the expected name of the invocation calls in the \
122 :param kernel_paths: the paths to search for kernel source files \
123 (if different from the location of the algorithm source). \
125 :type kernel_paths: list of str or NoneType
126 :param bool line_length: a logical flag specifying whether we care \
127 about line lengths being longer than 132 characters. If so, \
128 the input (algorithm and kernel) code is checked to make sure \
129 that it conforms and an error raised if not. The default is \
134 >>> from psyclone.parse.algorithm import Parser
135 >>> parser = Parser(api="gocean1.0")
136 >>> ast, info = parser.parse(SOURCE_FILE)
140 def __init__(self, api="", invoke_name="invoke", kernel_paths=None,
144 if kernel_paths
is None:
150 _config = Config.get()
152 api = _config.default_api
168 self._builtin_name_map, \
174 '''Takes a PSyclone conformant algorithm file as input and outputs a
175 parse tree of the code contained therein and an object
176 containing information about the 'invoke' calls in the
177 algorithm file and any associated kernels within the invoke
178 calls. If the NEMO API is being used then the parsed code is
179 returned without any additional information about the code.
181 :param str alg_filename: The file containing the algorithm code.
183 :returns: 2-tuple consisting of the fparser2 parse tree of the \
184 algorithm code and an object holding details of the \
185 algorithm code and the invokes found within it, unless it \
186 is the NEMO API, where the first entry of the tuple is \
187 None and the second is the fparser2 parse tree of the \
189 :rtype: (:py:class:`fparser.two.Fortran2003.Program`, \
190 :py:class:`psyclone.parse.FileInfo`) or (NoneType, \
191 :py:class:`fparser.two.Fortran2003.Program`)
197 check_line_length(alg_filename)
198 alg_parse_tree = parse_fp2(alg_filename)
200 if self.
_api_api ==
"nemo":
203 return None, alg_parse_tree
205 return alg_parse_tree, self.
invoke_infoinvoke_info(alg_parse_tree)
208 '''Takes an fparser2 representation of a PSyclone-conformant algorithm
209 code as input and returns an object containing information
210 about the 'invoke' calls in the algorithm file and any
211 associated kernels within the invoke calls. Also captures the
212 type and precision of every variable declaration within the
215 :param alg_parse_tree: the fparser2 representation of the \
217 :type: :py:class:`fparser.two.Fortran2003.Program`
219 :returns: an object holding details of the algorithm \
220 code and the invokes found within it.
221 :rtype: :py:class:`psyclone.parse.FileInfo`
223 :raises ParseError: if a program, module, subroutine or \
224 function is not found in the fparser2 tree.
225 :raises InternalError: if the fparser2 tree representing the \
226 type declaration statements is not in the expected form.
227 :raises NotImplementedError: if the algorithm code contains \
228 two different datatypes with the same name.
234 container_name =
None
235 for child
in alg_parse_tree.content:
236 if isinstance(child, (Main_Program, Module, Subroutine_Subprogram,
237 Function_Subprogram)):
238 container_name = str(child.content[0].items[1])
241 if not container_name:
244 "algorithm.py:parser:parse: Program, module, function or "
245 "subroutine not found in fparser2 parse tree.")
261 for statement
in walk(alg_parse_tree.content,
262 types=(Type_Declaration_Stmt,
263 Data_Component_Def_Stmt,
264 Use_Stmt, Call_Stmt)):
265 if isinstance(statement,
266 (Type_Declaration_Stmt, Data_Component_Def_Stmt)):
268 spec = statement.children[0]
269 if isinstance(spec, Declaration_Type_Spec):
271 my_type = spec.children[1].string.lower()
273 elif isinstance(spec, Intrinsic_Type_Spec):
275 my_type = spec.children[0].lower()
277 if isinstance(spec.children[1], Kind_Selector):
279 spec.children[1].children[1].string.lower()
282 f
"Expected first child of Type_Declaration_Stmt or "
283 f
"Data_Component_Def_Stmt to be Declaration_Type_Spec "
284 f
"or Intrinsic_Type_Spec but found "
285 f
"'{type(spec).__name__}'")
286 for decl
in walk(statement.children[2], (
287 Entity_Decl, Component_Decl)):
294 my_var_name = decl.children[0].string.lower()
299 raise NotImplementedError(
300 f
"The same symbol '{my_var_name}' is used for "
301 f
"different datatypes, "
302 f
"'{self._arg_type_defns[my_var_name][0]}, "
303 f
"{self._arg_type_defns[my_var_name][1]}' and "
304 f
"'{my_type}, {my_precision}'. This is not "
305 f
"currently supported.")
307 self.
_arg_type_defns_arg_type_defns[my_var_name] = (my_type, my_precision)
309 if isinstance(statement, Use_Stmt):
313 if isinstance(statement, Call_Stmt):
315 call_name = str(statement.items[0])
316 if call_name.lower() == self.
_invoke_name_invoke_name.lower():
319 invoke_calls.append(invoke_call)
321 return FileInfo(container_name, invoke_calls)
324 '''Takes the part of a parse tree containing an invoke call and
325 returns an InvokeCall object which captures the required
326 information about the invoke.
328 :param statement: Parse tree of the invoke call.
329 :type statement: :py:class:`fparser.two.Fortran2003.Call_Stmt`
330 :returns: An InvokeCall object which contains relevant \
331 information about the invoke call.
332 :rtype: :py:class:`psyclone.parse.algorithm.InvokeCall`
333 :raises ParseError: if more than one invoke argument contains \
335 :raises ParseError: if an unknown or unsupported invoke \
340 argument_list = statement.items[1].items
345 for argument
in argument_list:
347 if isinstance(argument, Actual_Arg_Spec):
351 f
"algorithm.py:Parser():create_invoke_call: An invoke "
352 f
"must contain one or zero 'name=xxx' arguments but "
353 f
"found more than one in: {statement} in file "
354 f
"{self._alg_filename}")
358 argument, (Data_Ref, Part_Ref, Structure_Constructor)):
361 kernel_calls.append(kernel_call)
366 f
"algorithm.py:Parser():create_invoke_call: Expecting "
367 f
"argument to be of the form 'name=xxx' or a Kernel call "
368 f
"but found '{argument}' in file '{self._alg_filename}'.")
370 return InvokeCall(kernel_calls, name=invoke_label)
373 '''Takes the parse tree of an invoke argument containing a
374 reference to a kernel or a builtin and returns the kernel or
375 builtin object respectively which contains the required
378 :param argument: Parse tree of an invoke argument. This \
379 should contain a kernel name and associated arguments.
380 :type argument: :py:class:`fparser.two.Fortran2003.Part_Ref` or \
381 :py:class:`fparser.two.Fortran2003.Structure_Constructor`
383 :returns: A builtin or coded kernel call object which contains \
384 relevant information about the Kernel.
385 :rtype: :py:class:`psyclone.parse.algorithm.KernelCall` or \
386 :py:class:`psyclone.parse.algorithm.BuiltInCall`
389 kernel_name, args = get_kernel(argument, self.
_alg_filename_alg_filename,
391 if kernel_name.lower()
in self._builtin_name_map:
402 '''Takes the builtin kernel name and a list of Arg objects which
403 capture information about the builtin call arguments and
404 returns a BuiltinCall instance with content specific to the
405 particular API (as specified in self._api).
407 :param str kernel_name: the name of the builtin kernel being \
409 :param args: a list of 'Arg' instances containing the required \
410 information for the arguments being passed from the algorithm \
411 layer. The list order is the same as the argument order.
412 :type arg: list of :py:class:`psyclone.parse.algorithm.Arg`
413 :returns: a BuiltInCall instance with information specific to \
415 :rtype: :py:class:`psyclone.parse.algorithm.BuiltInCall`
416 :raises ParseError: if the builtin is specified in a use \
417 statement in the algorithm layer
422 f
"A built-in cannot be named in a use statement but "
423 f
"'{kernel_name}' is used from module "
424 f
"'{self._arg_name_to_module_name[kernel_name.lower()]}' in "
425 f
"file {self._alg_filename}")
429 name=kernel_name.lower()), args)
432 '''Takes a coded kernel name and a list of Arg objects which
433 capture information about the coded call arguments and
434 returns a KernelCall instance with content specific to the
435 particular API (as specified in self._api).
437 :param str kernel_name: the name of the coded kernel being \
439 :param args: a list of 'Arg' instances containing the required \
440 information for the arguments being passed from the algorithm \
441 layer. The list order is the same as the argument order.
442 :type arg: list of :py:class:`psyclone.parse.algorithm.Arg`
443 :returns: a KernelCall instance with information specific to \
445 :rtype: :py:class:`psyclone.parse.algorithm.KernelCall`
446 :raises ParseError: if the kernel is not specified in a use \
447 statement in the algorithm layer
452 except KeyError
as info:
454 f
"kernel call '{kernel_name.lower()}' must either be named in "
455 f
"a use statement (found "
456 f
"{list(self._arg_name_to_module_name.values())}) or be a "
457 f
"recognised built-in (one of "
458 f
"'{list(self._builtin_name_map.keys())}' for "
462 modast = get_kernel_ast(module_name, self.
_alg_filename_alg_filename,
466 modast, name=kernel_name), args)
469 '''Takes a use statement and adds its contents to the internal
470 arg_name_to_module_name map. This map associates names
471 specified in the 'only' list with the corresponding use name.
473 :param statement: A use statement
474 :type statement: :py:class:`fparser.two.Fortran2003.Use_Stmt`
475 :raises InternalError: if the statement being passed is not an \
476 fparser use statement.
480 if not isinstance(statement, Use_Stmt):
482 f
"algorithm.py:Parser:update_arg_to_module_map: Expected "
483 f
"a use statement but found instance of "
484 f
"'{type(statement)}'.")
486 use_name = str(statement.items[2])
489 if statement.items[4]:
490 only_list = statement.items[4].items
494 for item
in only_list:
498 '''Takes the parse tree of an invoke argument containing an invoke
499 label. Raises an exception if this label has already been used
500 by another invoke in the same algorithm code. If all is well
501 it returns the label as a string.
503 :param argument: Parse tree of an invoke argument. This \
504 should contain a "name=xxx" argument.
505 :type argument: :py:class:`fparser.two.Actual_Arg_Spec`
506 :returns: the label as a string.
508 :raises ParseError: if this label has already been used by \
509 another invoke in this algorithm code.
512 invoke_label = get_invoke_label(argument, self.
_alg_filename_alg_filename)
515 f
"Found multiple named invoke()'s with the same "
516 f
"label ('{invoke_label}') when parsing {self._alg_filename}")
526 def get_builtin_defs(api):
528 Get the names of the supported built-in operations and the file
529 containing the associated meta-data for the supplied API
531 :param str api: the specified PSyclone API.
532 :returns: a 2-tuple containing a dictionary of the supported \
533 built-ins and the filename where these built-ins are specified.
542 if api ==
"dynamo0.3":
546 BUILTIN_DEFINITIONS_FILE
as fname
551 return builtins, fname
554 def get_invoke_label(parse_tree, alg_filename, identifier="name"):
555 '''Takes an invoke argument contained in the parse_tree argument and
556 returns the label specified within it.
558 :param parse_tree: Parse tree of an invoke argument. This should \
559 contain a "name=xxx" argument.
560 :type parse_tree: :py:class:`fparser.two.Actual_Arg_Spec`
561 :param str alg_filename: The file containing the algorithm code.
562 :param str identifier: An optional name used to specify a named argument. \
565 :returns: the label as a lower-cased string.
568 :except InternalError: if the form of the argument is not what was \
570 :except InternalError: if the number of items contained in the \
571 argument is not what was expected.
572 :except ParseError: if the name used for the named argument does \
573 not match what was expected.
574 :except ParseError: if the label is not specified as a string.
575 :except ParseError: if the label is not a valid Fortran name.
578 if not isinstance(parse_tree, Actual_Arg_Spec):
580 f
"algorithm.py:Parser:get_invoke_label: Expected a Fortran "
581 f
"argument of the form name=xxx but found instance of "
582 f
"'{type(parse_tree)}'.")
584 if len(parse_tree.items) != 2:
586 f
"algorithm.py:Parser:get_invoke_label: Expected the Fortran "
587 f
"argument to have two items but found "
588 f
"'{len(parse_tree.items)}'.")
590 ident = str(parse_tree.items[0])
591 if ident.lower() != identifier.lower():
593 f
"algorithm.py:Parser:get_invoke_label: Expected named identifier "
594 f
"to be '{identifier.lower()}' but found '{ident.lower()}'")
596 if not isinstance(parse_tree.items[1], Char_Literal_Constant):
598 f
"algorithm.py:Parser:get_invoke_label: The (optional) name of an "
599 f
"invoke must be specified as a string, but found "
600 f
"{parse_tree.items[1]} in {alg_filename}")
602 invoke_label = parse_tree.items[1].items[0]
603 invoke_label = invoke_label.lower()
604 invoke_label = invoke_label.strip()
605 if invoke_label[0] ==
'"' and invoke_label[-1] ==
'"' or \
606 invoke_label[0] ==
"'" and invoke_label[-1] ==
"'":
607 invoke_label = invoke_label[1:-1]
611 FortranReader.validate_name(invoke_label)
613 invoke_label = invoke_label.lower()
614 except (TypeError, ValueError)
as err:
617 f
"algorithm.py:Parser:get_invoke_label the (optional) name of "
618 f
"an invoke must be a string containing a valid Fortran name "
619 f
"(with no whitespace) but got '{invoke_label}' in file "
620 f
"{alg_filename}"))
from err
625 def get_kernel(parse_tree, alg_filename, arg_type_defns):
626 '''Takes the parse tree of an invoke kernel argument and returns the
627 name of the kernel and a list of Arg instances which capture the
628 relevant information about the arguments associated with the
631 :param parse_tree: parse tree of an invoke argument. This \
632 should contain a kernel name and associated arguments.
633 :type parse_tree: :py:class:`fparser.two.Fortran2003.Part_Ref` or \
634 :py:class:`fparser.two.Fortran2003.Structure_Constructor`
635 :param str alg_filename: The file containing the algorithm code.
637 :param arg_type_defns: dictionary holding a 2-tuple consisting of \
638 type and precision information for each variable declared in \
639 the algorithm layer, indexed by variable name.
640 :type arg_type_defns: dict[str] = (str, str or NoneType)
642 :returns: a 2-tuple with the name of the kernel being called and a \
643 list of 'Arg' instances containing the required information for \
644 the arguments being passed from the algorithm layer. The list \
645 order is the same as the argument order.
646 :rtype: (str, list of :py:class:`psyclone.parse.algorithm.Arg`)
648 :raises InternalError: if the parse tree is of the wrong type.
649 :raises InternalError: if Part_Ref or Structure_Constructor do not \
651 :raises InternalError: if Proc_Component_Ref has a child with an \
653 :raises InternalError: if Data_Ref has a child with an unexpected \
655 :raises NotImplementedError: if an expression contains a variable.
656 :raises InternalError: if an unsupported argument format is found.
660 if not isinstance(parse_tree, (Part_Ref, Structure_Constructor)):
662 f
"algorithm.py:get_kernel: Expected a parse tree (type Part_Ref "
663 f
"or Structure_Constructor) but found instance of "
664 f
"'{type(parse_tree)}'.")
666 if len(parse_tree.items) != 2:
668 f
"algorithm.py:get_kernel: Expected Part_Ref or "
669 f
"Structure_Constructor to have 2 children "
670 f
"but found {len(parse_tree.items)}.")
672 kernel_name = str(parse_tree.items[0])
676 if isinstance(parse_tree.items[1],
677 (Section_Subscript_List, Component_Spec_List)):
678 argument_list = parse_tree.items[1].items
681 argument_list = [parse_tree.items[1]]
684 for argument
in argument_list:
685 if isinstance(argument, (Real_Literal_Constant, Int_Literal_Constant)):
687 precision = argument.children[1]
689 precision = str(precision)
690 if isinstance(argument, Real_Literal_Constant):
691 datatype = (
"real", precision)
693 datatype = (
"integer", precision)
694 arguments.append(
Arg(
'literal', argument.tostr().lower(),
696 elif isinstance(argument, Name):
698 full_text = str(argument).lower()
700 datatype = arg_type_defns.get(var_name)
701 arguments.append(
Arg(
'variable', full_text, varname=var_name,
703 elif isinstance(argument, Part_Ref):
705 full_text = argument.tostr().lower()
706 var_name = str(argument.items[0]).lower()
707 datatype = arg_type_defns.get(var_name)
708 arguments.append(
Arg(
'indexed_variable', full_text,
709 varname=var_name, datatype=datatype))
710 elif isinstance(argument, Function_Reference):
713 full_text = argument.tostr().lower()
714 designator = argument.items[0]
715 lhs = designator.items[0]
716 lhs = create_var_name(lhs)
717 rhs = str(designator.items[2])
718 var_name = f
"{lhs}_{rhs}"
719 var_name = var_name.lower()
720 arguments.append(
Arg(
'indexed_variable', full_text,
722 elif isinstance(argument, (Data_Ref, Proc_Component_Ref)):
724 if isinstance(argument, Proc_Component_Ref):
725 if isinstance(argument.children[2], Name):
726 arg = argument.children[2].string.lower()
734 f
"The third argument to to a Proc_Component_Ref is "
735 f
"expected to be a Name, but found "
736 f
"'{type(argument.children[2]).__name__}'.")
737 elif isinstance(argument, Data_Ref):
738 rhs_node = argument.children[-1]
739 if isinstance(rhs_node, Part_Ref):
740 rhs_node = rhs_node.children[0]
741 if not isinstance(rhs_node, Name):
743 f
"The last child of a Data_Ref is expected to be "
744 f
"a Name or a Part_Ref whose first child is a "
745 f
"Name, but found '{type(rhs_node).__name__}'.")
746 arg = rhs_node.string.lower()
747 datatype = arg_type_defns.get(arg)
748 full_text = argument.tostr().lower()
749 var_name = create_var_name(argument).lower()
750 collection_type =
None
751 if not datatype
and isinstance(argument, Data_Ref):
754 collection = argument.children[-2]
755 if isinstance(collection, Part_Ref):
756 collection = collection.children[0]
757 if isinstance(collection, Name):
758 collection_type = arg_type_defns.get(
759 collection.tostr().lower())
762 Arg(
'collection', full_text,
763 varname=var_name, datatype=collection_type))
765 arguments.append(
Arg(
'variable', full_text,
766 varname=var_name, datatype=datatype))
767 elif isinstance(argument, (Level_2_Unary_Expr, Add_Operand,
772 if walk(argument, Name):
773 raise NotImplementedError(
774 f
"algorithm.py:get_kernel: Expressions containing "
775 f
"variables are not yet supported '{type(argument)}', "
776 f
"value '{str(argument)}', kernel '{parse_tree}' in "
777 f
"file '{alg_filename}'.")
780 candidate_datatype =
None
783 argument, (Real_Literal_Constant,
784 Int_Literal_Constant)):
785 precision = literal.children[1]
787 precision = str(precision)
788 if isinstance(literal, Real_Literal_Constant):
789 datatype = (
"real", precision)
791 datatype = (
"integer", precision)
793 if not candidate_datatype:
795 candidate_datatype = datatype
796 elif candidate_datatype != datatype:
797 raise NotImplementedError(
798 f
"Found two non-matching literals within an "
799 f
"expression ('{str(argument)}') passed into an "
800 f
"invoke from the algorithm layer. '{datatype}' and "
801 f
"'{candidate_datatype}' do not match. This is not "
802 f
"supported in PSyclone.")
803 arguments.append(
Arg(
'literal', argument.tostr().lower(),
807 f
"algorithm.py:get_kernel: Unsupported argument structure "
808 f
"'{type(argument)}', value '{str(argument)}', kernel "
809 f
"'{parse_tree}' in file '{alg_filename}'.")
811 return kernel_name, arguments
814 def create_var_name(arg_parse_tree):
815 '''Creates a valid variable name from an argument that optionally
816 includes brackets and potentially dereferences using '%'.
818 :param arg_parse_tree: the input argument. Contains braces and \
819 potentially dereferencing. e.g. a%b(c).
820 :type arg_parse_tree: :py:class:`fparser.two.Fortran2003.Name` or \
821 :py:class:`fparser.two.Fortran2003.Data_Ref` or \
822 :py:class:`fparser.two.Fortran2003.Part_Ref` or \
823 :py:class:`fparser.two.Fortran2003.Proc_Component_Ref`
825 :returns: a valid variable name.
828 :raises InternalError: if unrecognised fparser content is found.
831 tree = arg_parse_tree
832 if isinstance(tree, Name):
834 if isinstance(tree, Part_Ref):
835 return str(tree.items[0])
836 if isinstance(tree, Proc_Component_Ref):
841 return f
"{create_var_name(tree.items[0])}_{tree.items[2]}"
842 if isinstance(tree, Data_Ref):
844 for item
in tree.items:
845 if isinstance(item, (Data_Ref, Part_Ref)):
846 component_names.append(str(item.items[0]))
847 elif isinstance(item, Name):
848 component_names.append(str(item))
851 f
"algorithm.py:create_var_name unrecognised structure "
852 f
"'{type(item)}' in '{type(tree)}'.")
853 return "_".join(component_names)
855 f
"algorithm.py:create_var_name unrecognised structure '{type(tree)}'")
861 '''Captures information about the algorithm file and the invoke calls
862 found within the contents of the file.
864 :param str name: the name of the algorithm program unit (program, \
865 module, subroutine or function)
866 :param calls: information about the invoke calls in the algorithm code.
867 :type calls: list of :py:class:`psyclone.parse.algorithm.InvokeCall`
871 def __init__(self, name, calls):
872 self.
_name_name = name
878 :returns: the name of the algorithm program unit
882 return self.
_name_name
887 :returns: information about invoke calls
888 :rtype: list of :py:class:`psyclone.parse.algorithm.InvokeCall`
895 '''Keeps information about an individual invoke call.
897 :param kcalls: Information about the kernels specified in the \
899 :type kcalls: list of \
900 :py:class:`psyclone.parse.algorithm.KernelCall` or \
901 :py:class:`psyclone.parse.algorithm.BuiltInCall`
902 :param str name: An optional name to call the transformed invoke \
903 call. This defaults to None.
904 :param str invoke_name: the name that is used to indicate an invoke \
905 call. This defaults to 'invoke'.
909 def __init__(self, kcalls, name=None, invoke_name="invoke"):
914 if not name.lower().startswith(f
"{invoke_name}_"):
915 self.
_name_name = f
"{invoke_name}_{name.lower()}"
917 self.
_name_name = name.lower()
919 self.
_name_name =
None
924 :returns: the name of this invoke call
928 return self.
_name_name
933 :returns: the list of kernel calls in this invoke call
935 :py:class:`psyclone.parse.algorithm.KernelCall` or \
936 :py:class:`psyclone.parse.algorithm.BuiltInCall`
943 '''Base class for information about a user-supplied or built-in
946 :param ktype: information about a kernel or builtin. Provides \
947 access to the PSyclone description metadata and the code if it \
949 :type ktype: API-specific specialisation of \
950 :py:class:`psyclone.parse.kernel.KernelType`
951 :param args: a list of Arg instances which capture the relevant \
952 information about the arguments associated with the call to the \
954 :type args: list of :py:class:`psyclone.parse.algorithm.Arg`
957 def __init__(self, ktype, args):
959 self.
_args_args = args
967 f
"Kernel '{self._ktype.name}' called from the algorithm layer "
968 f
"with an insufficient number of arguments as specified by "
969 f
"the metadata. Expected at least '{self._ktype.nargs}' but "
970 f
"found '{len(self._args)}'.")
976 :returns: information about a kernel or builtin. Provides \
977 access to the PSyclone description metadata and the code if it \
979 :rtype: API-specific specialisation of \
980 :py:class:`psyclone.parse.kernel.KernelType`
988 :returns: a list of Arg instances which capture the relevant \
989 information about the arguments associated with the call to the \
991 :rtype: list of :py:class:`psyclone.parse.algorithm.Arg`
994 return self.
_args_args
998 '''This name is assumed to be set by the subclasses.
1000 :returns: the name of the module containing the kernel code.
1008 '''Store information about a user-supplied (coded) kernel. Specialises
1009 the generic ParsedCall class adding a module name value and a
1010 type for distinguishing this class.
1012 :param str module_name: the name of the kernel module.
1013 :param ktype: information about the kernel. Provides access to the \
1014 PSyclone description metadata and the code.
1015 :type ktype: API-specific specialisation of \
1016 :py:class:`psyclone.parse.kernel.KernelType`
1017 :param args: a list of Arg instances which capture the relevant \
1018 information about the arguments associated with the call to the \
1020 :type arg: list of :py:class:`psyclone.parse.algorithm.Arg`
1023 def __init__(self, module_name, ktype, args):
1024 ParsedCall.__init__(self, ktype, args)
1029 '''Specifies that this is a kernel call.
1031 :returns: the type of call as a string.
1038 return f
"KernelCall('{self.ktype.name}', {self.args})"
1042 '''Store information about a system-supplied (builtin)
1043 kernel. Specialises the generic ParsedCall class adding a function
1044 name method (the name of the builtin) and a type for
1045 distinguishing this class.
1047 :param ktype: information about this builtin. Provides \
1048 access to the PSyclone description metadata.
1049 :type ktype: API-specific specialisation of \
1050 :py:class:`psyclone.parse.kernel.KernelType`
1051 :param args: a list of Arg instances which capture the relevant \
1052 information about the arguments associated with the call to the \
1054 :type args: list of :py:class:`psyclone.parse.algorithm.Arg`
1057 def __init__(self, ktype, args):
1058 ParsedCall.__init__(self, ktype, args)
1064 :returns: the name of this builtin.
1072 '''Specifies that this is a builtin call.
1074 :returns: the type of call as a string.
1078 return "BuiltInCall"
1081 return f
"BuiltInCall('{self.ktype.name}', {self.args})"
1085 '''Description of an argument as obtained from parsing kernel or
1086 builtin arguments within invokes in a PSyclone algorithm code.
1088 :param str form: describes whether the argument is a literal \
1089 value, standard variable or indexed variable. Supported options \
1090 are specified in the local form_options list.
1091 :param str text: the original Fortran text of the argument.
1092 :param varname: the extracted variable name from the text if the \
1093 form is not literal otherwise it is set to None. This is optional \
1094 and defaults to None.
1095 :value varname: str or NoneType
1096 :param datatype: a tuple containing information about the datatype \
1097 and precision of the argument, or None if no information is \
1098 available. Defaults to None.
1099 :type datatype: (str, str or NoneType) or NoneType
1101 :raises InternalError: if the form argument is not one one of the \
1102 supported types as specified in the local form_options list.
1105 form_options = [
"literal",
"variable",
"indexed_variable",
"collection"]
1107 def __init__(self, form, text, varname=None, datatype=None):
1108 self.
_form_form = form
1109 self.
_text_text = text
1111 if form
not in Arg.form_options:
1113 f
"algorithm.py:Alg:__init__: Unknown arg type provided. "
1114 f
"Expected one of {str(Arg.form_options)} but found "
1121 return (f
"Arg(form='{self._form}',text='{self._text}',"
1122 f
"varname='{self._varname}')")
1127 :returns: a string indicating what type of variable this \
1128 is. Supported options are specified in the local form_options \
1133 return self.
_form_form
1138 :returns: the original Fortran text of the argument.
1142 return self.
_text_text
1147 :returns: the extracted variable name from the text if the \
1148 form is not literal and None otherwise
1149 :rtype: str or NoneType
1156 '''Allows the setting or re-setting of the variable name value.
1158 :param str value: the new variable name
1164 ''' Indicates whether this argument is a literal or not.
1166 :returns: True if this argument is a literal and False otherwise.
1170 return self.
_form_form ==
"literal"
1173 __all__ = [
"parse",
"Parser",
"get_builtin_defs",
"get_invoke_label",
1174 "get_kernel",
"create_var_name",
"FileInfo",
"InvokeCall",
1175 "ParsedCall",
"KernelCall",
"BuiltInCall",
"Arg"]
def create_coded_kernel_call(self, kernel_name, args)
def update_arg_to_module_map(self, statement)
def invoke_info(self, alg_parse_tree)
def check_invoke_label(self, argument)
def create_builtin_kernel_call(self, kernel_name, args)
def parse(self, alg_filename)
def create_invoke_call(self, statement)
def create_kernel_call(self, argument)