Sfoglia il codice sorgente

Refactoring and close buffer when read() returns an empty string.

Sander Mathijs van Veen 14 anni fa
parent
commit
805ca9d3ac
1 ha cambiato i file con 47 aggiunte e 24 eliminazioni
  1. 47 24
      src/c/bison_callback.c

+ 47 - 24
src/c/bison_callback.c

@@ -33,12 +33,14 @@
 #define likely(x)       __builtin_expect((x),1)
 #define unlikely(x)     __builtin_expect((x),0)
 
-static PyObject *py_callback_hook_handler_name;
-static PyObject *py_callback_hook_read_after_name;
-static PyObject *py_callback_hook_read_before_name;
+static PyObject *py_attr_hook_handler_name;
+static PyObject *py_attr_hook_read_after_name;
+static PyObject *py_attr_hook_read_before_name;
 
-static PyObject *py_callback_handle_name;
-static PyObject *py_callback_read_name;
+static PyObject *py_attr_handle_name;
+static PyObject *py_attr_read_name;
+static PyObject *py_attr_file_name;
+static PyObject *py_attr_close_name;
 
 // Construct attribute names (only the first time)
 // TODO: where do we Py_DECREF(handle_name) ??
@@ -78,11 +80,11 @@ PyObject* py_callback(PyObject *parser, char *target, int option, int nargs,
 
     va_end(ap);
 
-    INIT_ATTR(py_callback_handle_name, "_handle");
-    INIT_ATTR(py_callback_hook_handler_name, "hook_handler");
+    INIT_ATTR(py_attr_handle_name, "_handle");
+    INIT_ATTR(py_attr_hook_handler_name, "hook_handler");
 
     // Call the handler with the arguments
-    PyObject *handle = PyObject_GetAttr(parser, py_callback_handle_name);
+    PyObject *handle = PyObject_GetAttr(parser, py_attr_handle_name);
 
     if (unlikely(!handle)) return NULL;
 
@@ -97,10 +99,10 @@ PyObject* py_callback(PyObject *parser, char *target, int option, int nargs,
     if (unlikely(!res)) return res;
 
     // Check if the "hook_handler" callback exists
-    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_handler_name)))
+    if (unlikely(!PyObject_HasAttr(parser, py_attr_hook_handler_name)))
         return res;
 
-    handle = PyObject_GetAttr(parser, py_callback_hook_handler_name);
+    handle = PyObject_GetAttr(parser, py_attr_hook_handler_name);
 
     if (unlikely(!handle)) {
         Py_DECREF(res);
@@ -124,14 +126,16 @@ void py_input(PyObject *parser, char *buf, int *result, int max_size)
     PyObject *handle, *arglist, *res;
     char *bufstr;
 
-    INIT_ATTR(py_callback_hook_read_after_name, "hook_read_after");
-    INIT_ATTR(py_callback_hook_read_before_name, "hook_read_before");
-    INIT_ATTR(py_callback_read_name, "read");
+    INIT_ATTR(py_attr_hook_read_after_name, "hook_read_after");
+    INIT_ATTR(py_attr_hook_read_before_name, "hook_read_before");
+    INIT_ATTR(py_attr_read_name, "read");
+    INIT_ATTR(py_attr_file_name, "file");
+    INIT_ATTR(py_attr_close_name, "close");
 
     // Check if the "hook_READ_BEFORE" callback exists
-    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_read_before_name)))
+    if (unlikely(!PyObject_HasAttr(parser, py_attr_hook_read_before_name)))
     {
-        handle = PyObject_GetAttr(parser, py_callback_hook_read_before_name);
+        handle = PyObject_GetAttr(parser, py_attr_hook_read_before_name);
         if (unlikely(!handle)) return;
 
         // Call the "hook_READ_BEFORE" callback
@@ -145,7 +149,7 @@ void py_input(PyObject *parser, char *buf, int *result, int max_size)
     }
 
     // Read the input string and catch keyboard interrupt exceptions.
-    handle = PyObject_GetAttr(parser, py_callback_read_name);
+    handle = PyObject_GetAttr(parser, py_attr_read_name);
     if (unlikely(!handle)) {
         // TODO: set exception message for missing attribute error
         return;
@@ -162,10 +166,10 @@ void py_input(PyObject *parser, char *buf, int *result, int max_size)
     if (unlikely(!res)) { return; }
 
     // Check if the "hook_read_after" callback exists
-    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_read_after_name)))
+    if (unlikely(!PyObject_HasAttr(parser, py_attr_hook_read_after_name)))
         goto finish_input;
 
-    handle = PyObject_GetAttr(parser, py_callback_hook_read_after_name);
+    handle = PyObject_GetAttr(parser, py_attr_hook_read_after_name);
     if (unlikely(!handle)) return;
 
     // Call the "hook_READ_AFTER" callback
@@ -174,6 +178,7 @@ void py_input(PyObject *parser, char *buf, int *result, int max_size)
 
     res = PyObject_CallObject(handle, arglist);
 
+    Py_DECREF(res);
     Py_DECREF(handle);
     Py_DECREF(arglist);
 
@@ -186,10 +191,28 @@ finish_input:
     *result = strlen(bufstr);
     memcpy(buf, bufstr, *result);
 
-    // TODO: translate the following code snippet to the Python C aPI
-    //if buflen == 0 and parser.file:
-    //    # Marks the Python file object as being closed from Python's point of
-    //    # view. This does not close the associated C stream (which is not
-    //    # necessary here, otherwise use "os.close(0)").
-    //    parser.file.close()
+    // Close the read buffer if nothing is read. Marks the Python file object
+    // as being closed from Python's point of view. This does not close the
+    // associated C stream (which is not necessary here, otherwise use
+    // "os.close(0)").
+    if (!*result && PyObject_HasAttr(parser, py_attr_file_name)) {
+        PyObject *file_handle = PyObject_GetAttr(parser, py_attr_file_name);
+        if (unlikely(!file_handle)) return;
+
+        handle = PyObject_GetAttr(file_handle, py_attr_close_name);
+        Py_DECREF(file_handle);
+        if (unlikely(!handle)) return;
+
+        arglist = PyTuple_New(0);
+        if (unlikely(!arglist)) { Py_DECREF(handle); return; }
+
+        res = PyObject_CallObject(handle, arglist);
+
+        Py_DECREF(res);
+        Py_DECREF(handle);
+        Py_DECREF(arglist);
+
+        // TODO: something went wrong while closing the buffer.
+        if (unlikely(!res)) return;
+    }
 }