Repository: pyccel/pyccel (python)

Issue:
[DICT] Add C support for get
### Describe the feature
Add C support for the dict method `get`.

### Test Code
Provide code which does not currently work but which should do when this issue is fixed:
```python
def foo():
    a = {1,1.0, 2:2.0}
    b = a.get (1)
    c = a.get(3, 4.0)
    return b, c
```

### Proposed Solution
This should be implemented using the `hmap_X_at` and `hmap_X_at_mut` methods documented here: 
https://github.com/stclib/STC/blob/master/docs/hmap_api.md



Pull request:
Add C support for `dict.get`
Add C support for dict method `get()`. Fixes #2049

**Commit Summary**
- Implement C support for the `dict.get` method for default value use-case.
- Activate `dict.get` tests for C.
- Support falsy default values in `dict.pop`.
- Add falsy default values tests for `dict.pop` and `dict.get`.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5bc56a88..4c54d10b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,7 +19,7 @@ All notable changes to this project will be documented in this file.
 -   #1886 : Add Python and C support for dict method `pop()`.
 -   #1887 : Add Python support for dict method `popitem()`.
 -   #1888 : Add Python support for dict method `setdefault()`.
--   #1885 : Add Python support for dict method `get()`.
+-   #1885 : Add Python and C support for dict method `get()`.
 -   #1844 : Add line numbers and code to errors from built-in function calls.
 -   #1655 : Add the appropriate C language equivalent for declaring a Python `list` container using the STC library.
 -   #1659 : Add the appropriate C language equivalent for declaring a Python `set` container using the STC library.
diff --git a/docs/builtin-functions.md b/docs/builtin-functions.md
index 77bf241b..c8fcccf6 100644
--- a/docs/builtin-functions.md
+++ b/docs/builtin-functions.md
@@ -122,7 +122,7 @@ Python contains a limited number of builtin functions defined [here](https://doc
 |----------|-----------|
 | `clear` | **Yes** |
 | `copy` | Python-only |
-| `get` | Python-only |
+| `get` | Python and C |
 | `items` | **Yes** |
 | `keys` | No |
 | `pop` | Python and C |
diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py
index edf85791..23a111ec 100644
--- a/pyccel/codegen/printing/ccode.py
+++ b/pyccel/codegen/printing/ccode.py
@@ -2835,6 +2835,20 @@ class CCodePrinter(CodePrinter):
         dict_var = self._print(ObjectAddress(expr.dict_obj))
         return f"{c_type}_clear({dict_var});\n"
 
+    def _print_DictGet(self, expr):
+        target = expr.dict_obj
+        class_type = target.class_type
+        c_type = self.get_c_type(class_type)
+
+        dict_var = self._print(ObjectAddress(target))
+        key = self._print(expr.key)
+
+        if expr.default_value is not None:
+            default_val = self._print(expr.default_value)
+            return f"({c_type}_contains({dict_var}, {key}) ? *{c_type}_at({dict_var}, {key}) : {default_val})"
+
+        raise errors.report("Accessing dictionary using get without default is not supported yet", symbol=expr, severity="fatal")
+
     def _print_DictPop(self, expr):
         target = expr.dict_obj
         class_type = target.class_type
@@ -2843,7 +2857,7 @@ class CCodePrinter(CodePrinter):
         dict_var = self._print(ObjectAddress(target))
         key = self._print(expr.key)
 
-        if expr.default_value:
+        if expr.default_value is not None:
             default = self._print(expr.default_value)
             pop_expr = f"{c_type}_pop_with_default({dict_var}, {key}, {default})"
         else:


Test patch:
diff --git a/tests/epyccel/test_epyccel_dicts.py b/tests/epyccel/test_epyccel_dicts.py
index 585683d4..51b360f4 100644
--- a/tests/epyccel/test_epyccel_dicts.py
+++ b/tests/epyccel/test_epyccel_dicts.py
@@ -100,6 +100,26 @@ def test_pop_bool_keys(stc_language):
     assert isinstance(python_result, type(pyccel_result))
     assert python_result == pyccel_result
 
+def test_pop_falsy_int_default_element(stc_language):
+    def pop_falsy_int_default_element():
+        a = {1:2, 2:3}
+        return a.pop(3, 0)
+    epyc_func = epyccel(pop_falsy_int_default_element, language = stc_language)
+    pyccel_result = epyc_func()
+    python_result = pop_falsy_int_default_element()
+    assert isinstance(python_result, type(pyccel_result))
+    assert python_result == pyccel_result
+
+def test_pop_falsy_bool_default_element(stc_language):
+    def pop_falsy_bool_default_element():
+        a = {1:True, 2:False}
+        return a.pop(3, False)
+    epyc_default_element = epyccel(pop_falsy_bool_default_element, language = stc_language)
+    pyccel_result = epyc_default_element()
+    python_result = pop_falsy_bool_default_element()
+    assert isinstance(python_result, type(pyccel_result))
+    assert python_result == pyccel_result
+
 def test_pop_str_keys(python_only_language):
     def pop_str_keys():
         a = {'a':1, 'b':2}
@@ -163,11 +183,11 @@ def test_get_element(python_only_language):
     assert isinstance(python_result, type(pyccel_result))
     assert python_result == pyccel_result
 
-def test_get_default_element(python_only_language):
+def test_get_default_element(stc_language):
     def get_default_element():
         a = {1:True, 2:False}
         return a.get(3, True)
-    epyc_default_element = epyccel(get_default_element, language = python_only_language)
+    epyc_default_element = epyccel(get_default_element, language = stc_language)
     pyccel_result = epyc_default_element()
     python_result = get_default_element()
     assert isinstance(python_result, type(pyccel_result))
@@ -193,6 +213,26 @@ def test_get_default_str_keys(python_only_language):
     assert isinstance(python_result, type(pyccel_result))
     assert python_result == pyccel_result
 
+def test_get_falsy_int_default_element(stc_language):
+    def get_falsy_int_default_element():
+        a = {1:2, 2:3}
+        return a.get(3, 0)
+    epyc_func = epyccel(get_falsy_int_default_element, language = stc_language)
+    pyccel_result = epyc_func()
+    python_result = get_falsy_int_default_element()
+    assert isinstance(python_result, type(pyccel_result))
+    assert python_result == pyccel_result
+
+def test_get_falsy_bool_default_element(stc_language):
+    def get_falsy_bool_default_element():
+        a = {1:True, 2:False}
+        return a.get(3, False)
+    epyc_func = epyccel(get_falsy_bool_default_element, language = stc_language)
+    pyccel_result = epyc_func()
+    python_result = get_falsy_bool_default_element()
+    assert isinstance(python_result, type(pyccel_result))
+    assert python_result == pyccel_result
+
 def test_dict_contains(language):
     def dict_contains():
         a = {1:1.0, 2:2.0, 3:3.0}
@@ -203,7 +243,6 @@ def test_dict_contains(language):
     assert isinstance(python_result, type(pyccel_result))
     assert python_result == pyccel_result
 
-
 def test_set_default(python_only_language):
     def set_default():
         a = {1: 1.0, 2:2.0}