Repository: pyccel/pyccel (python)

Issue:
Error when comparing expressions
The code
```
if a%5 == 0:
    ...
```
fails with pyccel because we search for the `dtype` property that does not belong to sympy objects:
```
    def _print_Equality(self, expr):
        lhs = self._print(expr.lhs)
        rhs = self._print(expr.rhs)
        a = expr.args[0]
        b = expr.args[1]
>       if ((a.is_Boolean or isinstance(a.dtype, NativeBool)) and
            (b.is_Boolean or isinstance(b.dtype, NativeBool))):
E           AttributeError: 'Mod' object has no attribute 'dtype'

pyccel/codegen/printing/fcode.py:1207: AttributeError
```
This bug can be fixed easily, as checking the `dtype` is not necessary in this situation, but we should add some unit tests to verify this.

Pull request description:
Compare expressions
fixes #269 

Patch:
diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py
index 94fc33b3..f83ca0a6 100644
--- a/pyccel/codegen/printing/fcode.py
+++ b/pyccel/codegen/printing/fcode.py
@@ -55,7 +55,7 @@ from pyccel.ast.core import (Assign, AugAssign, Variable, CodeBlock,
 from pyccel.ast.builtins import Enumerate, Int, Len, Map, Print, Range, Zip
 from pyccel.ast.datatypes import DataType, is_pyccel_datatype
 from pyccel.ast.datatypes import is_iterable_datatype, is_with_construct_datatype
-from pyccel.ast.datatypes import NativeBool, NativeSymbol, NativeString, NativeList
+from pyccel.ast.datatypes import NativeSymbol, NativeString, NativeList
 from pyccel.ast.datatypes import NativeComplex, NativeReal, NativeInteger
 from pyccel.ast.datatypes import NativeRange, NativeTensor
 from pyccel.ast.datatypes import CustomDataType
@@ -1204,8 +1204,7 @@ class FCodePrinter(CodePrinter):
         rhs = self._print(expr.rhs)
         a = expr.args[0]
         b = expr.args[1]
-        if ((a.is_Boolean or isinstance(a.dtype, NativeBool)) and
-            (b.is_Boolean or isinstance(b.dtype, NativeBool))):
+        if a.is_Boolean and b.is_Boolean:
             return '{} .eqv. {}'.format(lhs, rhs)
         return '{0} == {1} '.format(lhs, rhs)
 
@@ -1214,8 +1213,7 @@ class FCodePrinter(CodePrinter):
         rhs = self._print(expr.rhs)
         a = expr.args[0]
         b = expr.args[1]
-        if ((a.is_Boolean or isinstance(a.dtype, NativeBool)) and
-            (b.is_Boolean or isinstance(b.dtype, NativeBool))):
+        if a.is_Boolean and b.is_Boolean:
             return '{} .neqv. {}'.format(lhs, rhs)
         return '{0} /= {1} '.format(self._print(expr.lhs), self._print(expr.rhs))
 
@@ -2040,8 +2038,8 @@ class FCodePrinter(CodePrinter):
 
         if isinstance(expr.rhs, Nil):
             return '.not. present({})'.format(lhs)
-        if ((a.is_Boolean or isinstance(a.dtype, NativeBool)) and
-            (b.is_Boolean or isinstance(b.dtype, NativeBool))):
+
+        if a.is_Boolean and b.is_Boolean:
             return '{} .eqv. {}'.format(lhs, rhs)
 
         raise NotImplementedError(PYCCEL_RESTRICTION_IS_RHS)
@@ -2054,8 +2052,8 @@ class FCodePrinter(CodePrinter):
 
         if isinstance(expr.rhs, Nil):
             return 'present({})'.format(lhs)
-        if ((a.is_Boolean or isinstance(a.dtype, NativeBool)) and
-            (b.is_Boolean or isinstance(b.dtype, NativeBool))):
+
+        if a.is_Boolean and b.is_Boolean:
             return '{} .neqv. {}'.format(lhs, rhs)
 
         raise NotImplementedError(PYCCEL_RESTRICTION_IS_RHS)


Test patch:
diff --git a/tests/epyccel/test_compare_expressions.py b/tests/epyccel/test_compare_expressions.py
new file mode 100644
index 00000000..d20a857f
--- /dev/null
+++ b/tests/epyccel/test_compare_expressions.py
@@ -0,0 +1,53 @@
+from pyccel.epyccel import epyccel
+from pyccel.decorators import types
+
+#==============================================================================
+def compare_epyccel(f1, *args):
+    f2 = epyccel(f1)
+    out1 = f1(*args)
+    out2 = f2(*args)
+    assert out1 == out2
+
+#==============================================================================
+@types('int, int, int')
+def mod_eq_pow(a, m, n):
+    return a%m == n**2
+
+@types('int, int, int')
+def mod_neq_pow(a, m, n):
+    return a%m != n**2
+
+@types('int, int, int')
+def idiv_gt_add(a, m, n):
+    return a//m > n+1
+
+#==============================================================================
+def test_mod_eq_pow():
+    # True
+    compare_epyccel(mod_eq_pow, 10, 3, 1)
+    compare_epyccel(mod_eq_pow, 19, 10, 3)
+    compare_epyccel(mod_eq_pow, 21, 3, 0)
+    # False
+    compare_epyccel(mod_eq_pow, 10, 5, 2)
+    compare_epyccel(mod_eq_pow, 19, 10, 1)
+    compare_epyccel(mod_eq_pow, 21, 3, 1)
+
+def test_mod_neq_pow():
+    # True
+    compare_epyccel(mod_neq_pow, 10, 5, 2)
+    compare_epyccel(mod_neq_pow, 19, 10, 1)
+    compare_epyccel(mod_neq_pow, 21, 3, 1)
+    # False
+    compare_epyccel(mod_neq_pow, 10, 3, 1)
+    compare_epyccel(mod_neq_pow, 19, 10, 3)
+    compare_epyccel(mod_neq_pow, 21, 3, 0)
+
+def test_idiv_gt_add():
+    # True
+    compare_epyccel(idiv_gt_add, 10, 3, 2)
+    compare_epyccel(idiv_gt_add, 8, 2, 2)
+    compare_epyccel(idiv_gt_add, 16, 3, 4)
+    # False
+    compare_epyccel(idiv_gt_add, 10, 3, 2)
+    compare_epyccel(idiv_gt_add, 8, 2, 3)
+    compare_epyccel(idiv_gt_add, 16, 3, 5)