Repository: pyccel/pyccel
Pull request #2177 (2025-01-21 23:47:20)

Add support for list reverse method
Add support for reverse() method for lists.

pyccel-bot[bot]: Hello again! Thank you for this new pull request :star_struck:.

Please begin by requesting your checklist using the command `/bot checklist`

jalalium: /bot checklist
jalalium: /bot run linux
pyccel-bot[bot]: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

pyccel-bot[bot]: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

pyccel-bot[bot]: @jalalium, @EmilyBourne has a few questions/comments about your code. Can you go through and see if you agree with them. If not go ahead and explain why. Once you've adressed all the comments let me know with `/bot mark as ready` and we will see if we can get approval.

jalalium: /bot run linux
pyccel-bot[bot]: @jalalium, @EmilyBourne has a few questions/comments about your code. Can you go through and see if you agree with them. If not go ahead and explain why. Once you've adressed all the comments let me know with `/bot mark as ready` and we will see if we can get approval.

pyccel-bot[bot]: @EmilyBourne, @jalalium has been working hard and thinks that they have now replied to or fixed all your comments. Could you take another look at the PR and see if you can approve now?


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4e33e284..64a228eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
 
 ### Added
 -   #1720 : Add support for `Ellipsis` as the only index for an array.
--   #1787 : Ensure STC v5.0 is installed with Pyccel.
+-   #1787 : Ensure STC v5.0 (`ef322ae`) is installed with Pyccel.
 -   #1656 : Ensure gFTL is installed with Pyccel.
 -   #1694 : Add Python support for list method `extend()`.
 -   #1700 : Add Python support for list method `sort()`.
@@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file.
 -   #1689 : Add C and Fortran support for list method `append()`.
 -   #1876 : Add C support for indexing lists.
 -   #1690 : Add C and Fortran support for list method `pop()`.
+-   #1695 : Add C and Fortran support for list method `reverse()`.
 -   #1663 : Add C and Fortran support for sets as arguments.
 -   #1664 : Add C and Fortran support for returning sets from functions.
 -   #2023 : Add support for iterating over a `set`.
diff --git a/docs/builtin-functions.md b/docs/builtin-functions.md
index 6c8b6823..64aa4341 100644
--- a/docs/builtin-functions.md
+++ b/docs/builtin-functions.md
@@ -89,7 +89,7 @@ Python contains a limited number of builtin functions defined [here](https://doc
 | `min` | No |
 | **`pop`** | **Yes** |
 | `remove` | Python-only |
-| `reverse` | No |
+| **`reverse`** | **Yes** |
 | `sort` | Python-only |
 
 ## Set methods
diff --git a/pyccel/ast/builtin_methods/list_methods.py b/pyccel/ast/builtin_methods/list_methods.py
index 421955b9..76a7357f 100644
--- a/pyccel/ast/builtin_methods/list_methods.py
+++ b/pyccel/ast/builtin_methods/list_methods.py
@@ -21,7 +21,8 @@ __all__ = ('ListAppend',
            'ListMethod',
            'ListPop',
            'ListRemove',
-           'ListSort',
+           'ListReverse',
+           'ListSort'
            )
 
 #==============================================================================
@@ -348,3 +349,31 @@ class ListSort(ListMethod) :
         if reverse is not None or key is not None:
             raise TypeError("Optional Parameters are not supported for sort() method.")
         super().__init__(list_obj, reverse, key)
+
+#==============================================================================
+class ListReverse(ListMethod):
+    """
+    Represents a call to the .reverse() method.
+
+    Represents a call to the `.reverse()` method, which reverses the elements of the
+    list in place. This means that the elements of the original list are rearranged
+    in reverse order. The .reverse() method does not return any value and does not
+    accept any optional parameters.
+
+    >>> a = [1, 2, 3, 4, 5]
+    >>> a.reverse()
+    >>> print(a)
+    [5, 4, 3, 2, 1]
+
+    Parameters
+    ----------
+    list_obj : TypedAstNode
+        The list object which the method is called from.
+    """
+    __slots__ = ()
+    _shape = None
+    _class_type = VoidType()
+    name = 'reverse'
+
+    def __init__(self, list_obj) -> None:
+        super().__init__(list_obj)
diff --git a/pyccel/ast/class_defs.py b/pyccel/ast/class_defs.py
index ab48b59c..e697ce7e 100644
--- a/pyccel/ast/class_defs.py
+++ b/pyccel/ast/class_defs.py
@@ -12,7 +12,7 @@ from pyccel.ast.builtin_methods.set_methods  import (SetAdd, SetClear, SetCopy,
                                                      SetIsDisjoint)
 from pyccel.ast.builtin_methods.list_methods import (ListAppend, ListInsert, ListPop,
                                                      ListClear, ListExtend, ListRemove,
-                                                     ListCopy, ListSort)
+                                                     ListCopy, ListSort, ListReverse)
 from pyccel.ast.builtin_methods.dict_methods import (DictPop, DictPopitem, DictGet, DictClear,DictCopy,
                                                      DictSetDefault, DictItems, DictGetItem, DictKeys)
 
@@ -155,6 +155,7 @@ ListClass = ClassDef('list',
             PyccelFunctionDef('pop', func_class = ListPop),
             PyccelFunctionDef('sort', func_class = ListSort),
             PyccelFunctionDef('remove', func_class = ListRemove),
+            PyccelFunctionDef('reverse', func_class = ListReverse),
         ])
 
 #=======================================================================================
diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py
index b0ac86c3..7e1288a4 100644
--- a/pyccel/codegen/printing/ccode.py
+++ b/pyccel/codegen/printing/ccode.py
@@ -1216,7 +1216,7 @@ class CCodePrinter(CodePrinter):
                      f'#include <{stc_extension_mapping[source]}.h>\n',
                      f'#endif // {header_guard}\n\n'))
             return code
-        elif source != 'stc/cstr' and (source.startswith('stc/') or source in import_header_guard_prefix):
+        elif source in import_header_guard_prefix:
             code = ''
             for t in expr.target:
                 class_type = t.object.class_type
@@ -2903,6 +2903,14 @@ class CCodePrinter(CodePrinter):
         else:
             return f'{c_type}_pull({list_obj})'
 
+    def _print_ListReverse(self, expr):
+        class_type = expr.list_obj.class_type
+        c_type = self.get_c_type(class_type)
+        list_obj = self._print(ObjectAddress(expr.list_obj))
+        self.add_import(Import('stc/algorithm' ,AsName(VariableTypeAnnotation(class_type), c_type)))
+        return f'c_reverse({c_type}, {list_obj});\n'
+
+
     #================== Set methods ==================
 
     def _print_SetPop(self, expr):
diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py
index 5e1c43d9..11943b04 100644
--- a/pyccel/codegen/printing/fcode.py
+++ b/pyccel/codegen/printing/fcode.py
@@ -1412,6 +1412,12 @@ class FCodePrinter(CodePrinter):
             self._additional_code += code
             return lhs_code
 
+    def _print_ListReverse(self, expr):
+        target = self._print(expr.list_obj)
+        type_name = self._print(expr.list_obj.class_type)
+        self.add_import(self._build_gFTL_extension_module(expr.list_obj.class_type))
+        return f'call {type_name}_reverse({target})\n'
+
     #========================== Set Methods ================================#
 
     def _print_SetAdd(self, expr):
diff --git a/pyccel/codegen/utilities.py b/pyccel/codegen/utilities.py
index 26ef06b6..982dc73d 100644
--- a/pyccel/codegen/utilities.py
+++ b/pyccel/codegen/utilities.py
@@ -74,6 +74,10 @@ internal_libs["gFTL_functions/Vector_extensions"] = (stdlib_path / "gFTL_functio
                                                                      dependencies = (internal_libs['gFTL'][2],)))
 internal_libs["stc/cstr"] = (ext_path / "STC/src", "STC/src", CompileObj("cstr_core.c", folder="STC/include", dependencies = (internal_libs['stc'][2],)))
 internal_libs["stc/cspan"] = (ext_path / "STC/src", "STC/src", CompileObj("cspan.c", folder="STC/include", dependencies = (internal_libs['stc'][2],)))
+internal_libs["stc/algorithm"] = (ext_path / "STC/include/stc/", "STC/include/stc/", CompileObj("algorithm.h",
+                                    folder="STC/include",
+                                    has_target_file = False,
+                                    dependencies = (internal_libs['stc'][2],)))
 
 
 #==============================================================================
diff --git a/pyccel/extensions/STC b/pyccel/extensions/STC
index 0ccf9c3d..ef322aeb 160000
--- a/pyccel/extensions/STC
+++ b/pyccel/extensions/STC
@@ -1,1 +1,1 @@
-Subproject commit 0ccf9c3d6e114d99fc698a0200b7ecec995d5ad2
+Subproject commit ef322aeb21c682a02253ce6df524307d142294c7
diff --git a/pyccel/stdlib/gFTL_functions/Vector_extensions.inc b/pyccel/stdlib/gFTL_functions/Vector_extensions.inc
index 1cfcecc3..599bc608 100644
--- a/pyccel/stdlib/gFTL_functions/Vector_extensions.inc
+++ b/pyccel/stdlib/gFTL_functions/Vector_extensions.inc
@@ -7,6 +7,26 @@ contains
 #include "parameters/T/copy_vector_T_to_internal_T.inc"
 #include "parameters/T/define_derived_macros.inc"
 
+  subroutine __IDENTITY(Vector)_reverse(my_vector)
+    class(Vector), intent(inout) :: my_vector
+
+    integer :: left, right
+    __T_declare_dummy__ :: temp
+
+    left = 1
+    right = my_vector%size()
+
+    do while (left < right)
+        temp = my_vector%at(left)
+        call my_vector%set(left, my_vector%at(right))
+        call my_vector%set(right, temp)
+
+        left = left + 1
+        right = right - 1
+    end do
+
+  end subroutine __IDENTITY(Vector)_reverse
+
   function __IDENTITY(Vector)_min(my_vector) result(result)
     class(Vector), intent(in) :: my_vector
     __T_declare_dummy__ :: result
@@ -56,4 +76,5 @@ contains
     end do
 
   end function __IDENTITY(Vector)_max
+
 #include <vector/tail.inc>


Test patch:
diff --git a/tests/epyccel/test_epyccel_lists.py b/tests/epyccel/test_epyccel_lists.py
index 2da5a3e7..b4598507 100644
--- a/tests/epyccel/test_epyccel_lists.py
+++ b/tests/epyccel/test_epyccel_lists.py
@@ -815,6 +815,25 @@ def test_list_min_max(language):
     assert python_result == pyccel_result
     assert isinstance(python_result, type(pyccel_result))
 
+
+def test_list_reverse(language):
+    def list_reverse():
+        a_int = [1, 2, 3]
+        a_float = [1.1, 2.2, 3.3]
+        a_complex = [1j, 2-3j]
+        a_single = [1]
+        a_int.reverse()
+        a_float.reverse()
+        a_complex.reverse()
+        a_single.reverse()
+        return (a_int[0], a_int[-1], a_float[0], a_float[-1],
+                a_single[0], a_single[-1], a_complex[0], a_complex[-1])
+    epyccel_func = epyccel(list_reverse, language = language)
+    pyccel_result = epyccel_func()
+    python_result = list_reverse()
+    assert python_result == pyccel_result
+
+
 def test_list_str(stc_language):
     def list_str():
         a = ['hello', 'world', '!']