changeset 704:457ef358c1a0

filter-only expansions also implemented in the C extension. BUGS: No caching yet (pure Python and C extension).
author Franz Glasner <f.glasner@feldmann-mg.com>
date Mon, 14 Aug 2023 13:00:19 +0200
parents 193a616e0b3c
children 0485a033c95d
files configmix/_speedups.c
diffstat 1 files changed, 56 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/configmix/_speedups.c	Mon Aug 14 09:31:27 2023 +0200
+++ b/configmix/_speedups.c	Mon Aug 14 13:00:19 2023 +0200
@@ -40,6 +40,7 @@
 
 
 static PyObject * _fast_getvar_s(PyObject *config, PyObject *varname, PyObject *default_, struct speedups_state *sstate, int *cacheable);
+static PyObject * _fast_interpolate_variables(PyObject *self, PyObject *config, PyObject *s, PyObject *cache);
 
 
 static
@@ -1035,6 +1036,17 @@
     PyObject *s;
     PyObject *cache = NULL;
 
+    if (!PyArg_UnpackTuple(args, "s", 2, 3, &config, &s, &cache)) {
+        return NULL;
+    }
+    return _fast_interpolate_variables(self, config, s, cache);
+}
+
+
+static
+PyObject *
+_fast_interpolate_variables(PyObject *self, PyObject *config, PyObject *s, PyObject *cache)
+{
     int cmp;
     Py_ssize_t s_len;
     Py_ssize_t start, rest, end;
@@ -1049,9 +1061,6 @@
     int use_cache, cacheable;
     struct speedups_state *sstate;
 
-    if (!PyArg_UnpackTuple(args, "s", 2, 3, &config, &s, &cache)) {
-        return NULL;
-    }
     /* Disable caching if the cache param is given as None */
     if ((cache != NULL) && py_object_is(cache, Py_None)) {
         cache = NULL;
@@ -1101,17 +1110,22 @@
         }
     }
 
+    /* Check for {{| ... |}} */
     if ((s_len >= 6)
             && (start == 0)
-            && (PyUnicode_ReadChar(s, 2) == 0x7c  /* | */)) {
+            && (PyUnicode_ReadChar(s, 2) == 0x7c  /* `|' */)) {
         end = PyUnicode_Find(s, sstate->ENDTOK_FILTER, start+3, s_len, 1);
         if (end == -2) {
             return NULL;
         }
         if (end != (s_len - 3)) {
-            PyErr_SetString(PyExc_ValueError, "XXX") ; /*`{{|' global filter interpolation must end with `|}}'"); */
+            PyErr_SetString(PyExc_ValueError, "`{{|' global filter interpolation must end with `|}}'");
             return NULL;
         }
+        /*
+         * Handle {{| ... |filters, ... |}} :
+         * split and recurse and apply filters
+         */
         tmp = PyUnicode_Substring(s, 3, s_len-3);
         if (tmp == NULL) {
             return NULL;
@@ -1127,11 +1141,44 @@
             goto error;
         }
         py_transfer_owned(&tmp, &filters);
-
-        /* XXX TBD */
+        /* Unpack the result tuple */
+        /* borrowed -- cannot fail -- need ownership */
+        varname = Py_NewRef(PyTuple_GetItem(tmp, 0));
+        /* borrowed -- cannot fail -- need ownership */
+        filters = Py_NewRef(PyTuple_GetItem(tmp, 1));
         py_clear_ref(&tmp);
-        PyErr_SetString(PyExc_KeyError, "ERRRRRRR in C");
-        return NULL;
+
+        varvalue = _fast_interpolate_variables(self, config, varname, cache);
+        if (varvalue == NULL) {
+            if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+                if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) {
+                    PyErr_Clear();
+                    varvalue = Py_NewRef(Py_None);
+                }
+                else {
+                    if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) {
+                        PyErr_Clear();
+                        varvalue = Py_NewRef(sstate->EMPTY_STR);
+                    }
+                    else {
+                        goto error;
+                    }
+                }
+            }
+            else {
+                /* other exception/error than KeyError */
+                goto error;
+            }
+        }
+        py_clear_ref(&varname);
+        result = PyObject_CallMethod(
+            config, "_apply_filters", "OO", filters, varvalue);
+        if (result == NULL) {
+            goto error;
+        }
+        py_clear_ref(&varvalue);
+        py_clear_ref(&filters);
+        return result;
     }
 
     result = PyList_New(0);