Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# sanity check the readers and writers we identify.
all_array_refs = {}
# Loop over a flat list of all the nodes in the supplied region
for node in walk(nodes):
if isinstance(node, Assignment_Stmt):
# Found lhs = rhs
structure_name_str = None
lhs = node.items[0]
rhs = node.items[2]
# Do RHS first as we cull readers after writers but want to
# keep a = a + ... as the RHS is computed before assigning
# to the LHS
for node2 in walk(rhs):
if isinstance(node2, Part_Ref):
name = node2.items[0].string
if name.upper() not in FORTRAN_INTRINSICS:
if name not in writers:
readers.add(name)
if isinstance(node2, Data_Ref):
# TODO we need a robust implementation - issue #309.
raise NotImplementedError(
"get_inputs_outputs: derived-type references on "
"the RHS of assignments are not yet supported.")
# Now do LHS
if isinstance(lhs, Data_Ref):
# This is a structure which contains an array access.
structure_name_str = lhs.items[0].string
writers.add(structure_name_str)
lhs = lhs.items[1]
lhs = create_var_name(lhs)
rhs = str(designator.items[2])
var_name = "{0}_{1}".format(lhs, rhs)
var_name = var_name.lower()
arguments.append(Arg('indexed_variable', full_text, var_name))
elif isinstance(argument, Data_Ref):
# A structure dereference e.g. base%arg, base%arg(n)
full_text = argument.tostr().lower()
var_name = create_var_name(argument).lower()
arguments.append(Arg('variable', full_text, var_name))
elif isinstance(argument, (Level_2_Unary_Expr, Add_Operand,
Parenthesis)):
# An expression e.g. -1, 1*n, ((1*n)/m). Note, for some
# reason Add_Operation represents binary expressions in
# fparser2. Walk the tree to look for an argument.
if not walk(argument, Name):
# This is a literal so store the full expression as a
# string
arguments.append(Arg('literal', argument.tostr().lower()))
else:
raise NotImplementedError(
"algorithm.py:get_kernel: Expressions containing "
"variables are not yet supported '{0}', value '{1}', "
"kernel '{2}' in file '{3}'.".format(
type(argument), str(argument), parse_tree,
alg_filename))
else:
raise InternalError(
"algorithm.py:get_kernel: Unsupported argument structure "
"'{0}', value '{1}', kernel '{2}' in file '{3}'.".format(
type(argument), str(argument), parse_tree, alg_filename))
self.invoke_map = {}
self.invoke_list = []
# Keep a pointer to the whole fparser2 AST
self._ast = ast
# TODO #737 - this routine should really process generic PSyIR to
# create domain-specific PSyIR (D-PSyIR) for the NEMO domain.
# Use the fparser2 frontend to construct the PSyIR from the parse tree
processor = NemoFparser2Reader()
# First create a Container representing any Fortran module
# contained in the parse tree.
self._container = processor.generate_container(ast)
# Find all the subroutines contained in the file
routines = walk(ast.content, (Subroutine_Subprogram,
Function_Subprogram))
# Add the main program as a routine to analyse - take care
# here as the Fortran source file might not contain a
# main program (might just be a subroutine in a module)
main_prog = get_child(ast, Main_Program)
if main_prog:
routines.append(main_prog)
# Analyse each routine we've found
for subroutine in routines:
# Get the name of this subroutine, program or function
substmt = subroutine.content[0]
if isinstance(substmt, Function_Stmt):
for item in substmt.items:
if isinstance(item, Name):
sub_name = str(item)
ArgumentInterface.Access.READWRITE)
arg_symbols.append(symbol)
# Now that we've updated the Symbols themselves, set the
# argument list
parent.symbol_table.specify_argument_list(arg_symbols)
except KeyError:
raise InternalError("The kernel argument "
"list '{0}' does not match the variable "
"declarations for fparser nodes {1}."
"".format(str(arg_list), nodes))
# fparser2 does not always handle Statement Functions correctly, this
# loop checks for Stmt_Functions that should be an array statement
# and recovers them, otherwise it raises an error as currently
# Statement Functions are not supported in PSyIR.
for stmtfn in walk(nodes, Fortran2003.Stmt_Function_Stmt):
(fn_name, arg_list, scalar_expr) = stmtfn.items
try:
symbol = parent.symbol_table.lookup(fn_name.string.lower())
if symbol.is_array:
# This is an array assignment wrongly categorized as a
# statement_function by fparser2.
array_name = fn_name
array_subscript = arg_list.items
assignment_rhs = scalar_expr
# Create assingment node
assignment = Assignment(parent=parent)
parent.addchild(assignment)
# Build lhs
# array(1,:,:) = a_func(array2(:,:,:), mask(:,:))
# where a_func is an array-valued function and `array2(:,:,:)`
# could just be `array2`.
# We check the left-hand side...
lhs = node.items[0]
if not isinstance(lhs, Fortran2003.Part_Ref):
# LHS is not an array reference
return False
colons = walk(lhs.items, Fortran2003.Subscript_Triplet)
if not colons:
# LHS does not use array syntax
return False
# Now check the right-hand side...
rhs = node.items[2]
try:
if not walk(rhs.items, Fortran2003.Subscript_Triplet):
# We don't have any array syntax on the RHS
return True
except AttributeError:
# The RHS doesn't have the `items` attribute (it may be just
# a Name for instance).
return True
# Check that we haven't got array syntax used within the index
# expression to another array. Array references are represented by
# Part_Ref nodes in the fparser2 AST.
# Find all array references
array_refs = walk(rhs, Fortran2003.Part_Ref)
for ref in array_refs:
nested_refs = walk(ref.items, Fortran2003.Part_Ref)
# Do any of these nested array references use array syntax?
for nested_ref in nested_refs:
colons = walk(nested_ref.items, Fortran2003.Subscript_Triplet)
# We don't have any array syntax on the RHS
return True
except AttributeError:
# The RHS doesn't have the `items` attribute (it may be just
# a Name for instance).
return True
# Check that we haven't got array syntax used within the index
# expression to another array. Array references are represented by
# Part_Ref nodes in the fparser2 AST.
# Find all array references
array_refs = walk(rhs, Fortran2003.Part_Ref)
for ref in array_refs:
nested_refs = walk(ref.items, Fortran2003.Part_Ref)
# Do any of these nested array references use array syntax?
for nested_ref in nested_refs:
colons = walk(nested_ref.items, Fortran2003.Subscript_Triplet)
if colons:
return False
return True
for node in node_list[:]:
if isinstance(node, Fortran2003.Use_Stmt) and \
fortran_module == str(node.items[2]).lower():
# Check that the use statement matches the one we would
# insert (i.e. the code doesn't already contain a module
# with the same name as that used by the PSyData API)
if str(node).lower() != self.use_stmt.lower():
raise NotImplementedError(
"Cannot add PSyData calls to '{0}' because it "
"already 'uses' a module named '{1}'".format(
routine_name, fortran_module))
found = True
# To make our check on name clashes below easier, remove
# the Name nodes associated with this use from our
# list of nodes.
names = walk([node], Fortran2003.Name)
for name in names:
node_list.remove(name)
if not found:
# We don't already have a use for the PSyData module so
# add one.
reader = FortranStringReader(
"use {0}, only: {1}"
.format(self.add_psydata_class_prefix("psy_data_mod"),
self.add_psydata_class_prefix("PSyDataType")))
# Tell the reader that the source is free format
reader.set_format(FortranFormat(True, False))
use = Fortran2003.Use_Stmt(reader)
spec_part.content.insert(0, use)
# Check that we won't have any name-clashes when we insert the
def __init__(self, ast):
# pylint: disable=super-init-not-called
names = walk(ast.content, Fortran2003.Name)
# The name of the program unit will be the first in the list
if not names:
raise InternalError("Found no names in supplied Fortran - should "
"be impossible!")
self._name = str(names[0]) + "_psy"
self._invokes = NemoInvokes(ast)
self._ast = ast
symbol_table = _get_symbol_table(psyir_parent)
if not isinstance(type_spec.items[1], Fortran2003.Kind_Selector):
# No precision is specified
return None
kind_selector = type_spec.items[1]
if (isinstance(kind_selector.children[0], str) and
kind_selector.children[0] == "*"):
# Precision is provided in the form *N
precision = int(str(kind_selector.children[1]))
return precision
# Precision is supplied in the form "kind=..."
intrinsics = walk(kind_selector.items,
Fortran2003.Intrinsic_Function_Reference)
if intrinsics and isinstance(intrinsics[0].items[0],
Fortran2003.Intrinsic_Name) and \
str(intrinsics[0].items[0]).lower() == "kind":
# We have kind=KIND(X) where X may be of any intrinsic type. It
# may be a scalar or an array. items[1] is an
# Actual_Arg_Spec_List with the first entry being the argument.
kind_arg = intrinsics[0].items[1].items[0]
# We currently only support integer and real literals as
# arguments to KIND
if isinstance(kind_arg, (Fortran2003.Int_Literal_Constant,
Fortran2003.Real_Literal_Constant)):
return get_literal_precision(kind_arg, psyir_parent)
raise NotImplementedError(