Skip to content

Instantly share code, notes, and snippets.

@slingamn
Created August 11, 2011 22:09
Show Gist options
  • Save slingamn/1140929 to your computer and use it in GitHub Desktop.
Save slingamn/1140929 to your computer and use it in GitHub Desktop.
diff --git a/ezio/Ezio.h b/ezio/Ezio.h
index 7ff33f1..917fd9f 100644
--- a/ezio/Ezio.h
+++ b/ezio/Ezio.h
@@ -54,27 +54,6 @@ static void array_xdecref(Py_ssize_t num_vars, PyObject *vars[]) {
}
}
-/**
- Basic RAII for PyObject*'s; store a pointer and a new reference, ensure
- that the new reference is removed on function exit by putting an XDECREF
- in the destructor. This is used to implement #set, but not to implement, e.g.,
- function arguments or the temporary variables in for loops.
- */
-class PySmartPointer {
- public:
- // this value can be NULL and always requires a NULL test before use
- PyObject *referent;
- PySmartPointer() : referent(NULL) {}
- PySmartPointer(PyObject *referent) : referent(referent) {}
- ~PySmartPointer() { Py_XDECREF(referent); }
- // we could overload the assignment operator here, but we don't really need the magic:
- // the only value being added here is the destructor.
- void set_referent(PyObject *new_referent) {
- Py_XDECREF(referent);
- referent = new_referent;
- }
-};
-
namespace ezio_templates {
/** Base C++ class for all templates. */
diff --git a/ezio/compiler.py b/ezio/compiler.py
index ccb0f83..144fc7e 100644
--- a/ezio/compiler.py
+++ b/ezio/compiler.py
@@ -754,6 +754,7 @@ class CodeGenerator(LineBufferMixin, NodeVisitor):
# semantics; a local variable is scoped to its enclosing function, not to any smaller
# block.
self.assignment_targets = LineBufferMixin()
+ self.assignment_cleanup = LineBufferMixin()
self.assignment_namespace = {}
self.add_fixup(self.assignment_targets)
self.namespaces.append(self.assignment_namespace)
@@ -766,9 +767,13 @@ class CodeGenerator(LineBufferMixin, NodeVisitor):
self.namespaces.append(arg_namespace)
for stmt in function_def.body:
self.visit(stmt)
+ # insert the fixup to clean up assignments
+ self.add_fixup(self.assignment_cleanup)
# XXX Py_None is being used as a C-truthy sentinel for success
self.add_line("return Py_None;")
self.add_line('%s:' % exception_handler)
+ # insert the cleanup fixup *again*
+ self.add_fixup(self.assignment_cleanup)
self.add_line("return NULL;")
self.indent -= 1
# remove the argument and assignment namespaces:
@@ -1301,9 +1306,9 @@ class CodeGenerator(LineBufferMixin, NodeVisitor):
if name_status == 'SMART_POINTER':
# generate a NameError for uninitialized use of a #set variable:
- self.add_line('if (!%s.referent) { PyErr_SetString(PyExc_NameError, "%s"); goto %s; }' %
+ self.add_line('if (!%s) { PyErr_SetString(PyExc_NameError, "%s"); goto %s; }' %
(name, name, self.exception_handler_stack[-1]))
- return '%s.referent' % (name,)
+ return name
if name_status == 'SELF':
# generate a NameError if we have no wrapped object:
@@ -1671,12 +1676,16 @@ class CodeGenerator(LineBufferMixin, NodeVisitor):
target_name = target.id
name_status = self._get_name_status(target_name)
- assert name_status in ('SMART_POINTER', None), 'Cannot assign to a native name.'
if name_status is None:
# add a declaration of the requisite smart pointer
- self.assignment_targets.add_line('PySmartPointer %s;' % (target_name,))
+ self.assignment_targets.add_line('PyObject *%s = NULL;' % (target_name,))
self.assignment_namespace[target_name] = 'SMART_POINTER'
+ self.assignment_cleanup.add_line('Py_XDECREF(%s);' % (target_name,))
+ elif name_status == 'NATIVE':
+ # XXX check that this is an argument
+ self.assignment_targets.add_line('Py_INCREF(%s);' % (target_name,))
+ self.assignment_cleanup.add_line('Py_XDECREF(%s);' % (target_name,))
with self.block_scope():
tempvar = self._make_tempvar()
@@ -1685,7 +1694,7 @@ class CodeGenerator(LineBufferMixin, NodeVisitor):
# smart pointers always contain a new reference:
if not new_ref:
self.add_line('Py_INCREF(%s);' % (tempvar,))
- self.add_line('%s.set_referent(%s);' % (target_name, tempvar,))
+ self.add_line('Py_XDECREF(%s); %s = %s;' % (target_name, target_name, tempvar,))
def visit_With(self, with_node, variable_name=None):
"""Compile the with statement. See caveats below."""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment