Skip to content

(Closes #466) Fix for "==" when matching implicit loop in array constructor #467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Modifications by (in alphabetical order):
* P. Vitt, University of Siegen, Germany
* A. Voysey, UK Met Office

21/07/2025 PR #467 for #466. Fix "==" when matching implicit loops in array constructors.

26/06/2025 PR #471 for #470. Drop support for Python 3.7 and 3.8.

25/06/2025 PR #459 for #458. Improvements to the 'make public' example script.
Expand Down
19 changes: 15 additions & 4 deletions src/fparser/two/Fortran2003.py
Original file line number Diff line number Diff line change
Expand Up @@ -2945,13 +2945,24 @@ class Ac_Implied_Do(Base):
use_names = ["Ac_Value_List", "Ac_Implied_Do_Control"]

@staticmethod
def match(string):
def match(string: str):
"""
Attempts to match the supplied string as an implicit do within an
array constructor.

:param string: the text to match against.

:returns: a tuple describing the match or None if there is no match.
:rtype: Optional[Tuple[Ac_Value_List, Ac_Implied_Do_Control]]

"""
if string[0] + string[-1] != "()":
return
return None
line, repmap = string_replace_map(string[1:-1].strip())
i = line.rfind("=")
if i == -1:
return
if i == -1 or (i > 0 and line[i - 1] == "="):
# No "=" or it is "==" so no match.
return None
j = line[:i].rfind(",")
assert j != -1
s1 = repmap(line[:j].rstrip())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2020-2021 Science and Technology Facilities Council.
# Copyright (c) 2020-2025 Science and Technology Facilities Council.
#
# All rights reserved.
#
Expand Down Expand Up @@ -57,6 +57,18 @@ def test_implicit_loop_constructor_no_parentheses():
assert ast is None


@pytest.mark.usefixtures("f2003_create")
def test_no_implicit_loop_constructor_with_is_equal_to():
"""Test that the parser does not match an implicit loop if the
array constructor contains '=='."""
fcode = "(/lval1, ival1==ival2/)"
reader = FortranStringReader(fcode)
ast = Fortran2003.Array_Constructor(reader)
# Should have an array constructor without an implicit loop.
assert isinstance(ast, Fortran2003.Array_Constructor)
assert isinstance(ast.children[1], Fortran2003.Ac_Value_List)


@pytest.mark.xfail(reason="#257 Constraint C497 is not checked.")
@pytest.mark.usefixtures("f2003_create")
def test_nested_implied_do():
Expand Down
13 changes: 12 additions & 1 deletion src/fparser/two/tests/fortran2003/test_intrinsics.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -----------------------------------------------------------------------------
# BSD 3-Clause License
#
# Copyright (c) 2019-2023, Science and Technology Facilities Council.
# Copyright (c) 2019-2025, Science and Technology Facilities Council.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -206,6 +206,17 @@ def test_intrinsic_function_reference_unlimited_args():
assert str(result) == f"MAX({args})"


@pytest.mark.usefixtures("f2003_create")
def test_intrinsic_function_reference_all_args():
"""Check that we match a call to ALL containing an array constructor
of logical type.

"""
code = "all( (/ var1, var2, (i1==i2) /) )"
result = Intrinsic_Function_Reference(code)
assert isinstance(result, Intrinsic_Function_Reference)


@pytest.mark.usefixtures("f2003_create")
def test_intrinsic_function_reference_error1():
"""Test that class Intrinsic_Function_Reference raises the expected
Expand Down