Skip to content

Commit

Permalink
opApply wrapping and various refactoring
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.dsource.org/projects/pyd/trunk@37 1df65b71-e716-0410-9316-ac55df2b1602
  • Loading branch information
KirkMcDonald authored and KirkMcDonald committed Aug 15, 2006
1 parent f609511 commit c540609
Show file tree
Hide file tree
Showing 13 changed files with 5,757 additions and 238 deletions.
87 changes: 57 additions & 30 deletions dcompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,19 @@
'exception.d',
'ftype.d',
'func_wrap.d',
'iteration.d',
'make_object.d',
'op_wrap.d',
'pyd.d',
'tuples.d',
]

_stFiles = [
'coroutine.d',
'stackcontext.d',
'stackthread.d',
]

_pyVerXDotY = '.'.join(str(v) for v in sys.version_info[:2]) # e.g., '2.4'
_pyVerXY = _pyVerXDotY.replace('.', '') # e.g., '24'

Expand Down Expand Up @@ -124,7 +131,7 @@ def compile(self, sources,

binpath = _qp(self._binpath)
compileOpts = self._compileOpts
#outputOpts = self._outputOpts
outputOpts = self._outputOpts

includePathOpts = []

Expand All @@ -149,7 +156,15 @@ def compile(self, sources,
" missing." % filePath
)
sources.append(filePath)
# Add the pyd directory to the include path
# And StackThreads
for file in _stFiles:
filePath = os.path.join(_infraDir, 'st', file)
if not os.path.isfile(filePath):
raise DistutilsPlatformError("Required StackThreads source"
"file '%s' is missing." % filePath
)
sources.append(filePath)
# Add the infraDir to the include path for Pyd and ST
includePathOpts += self._includeOpts
includePathOpts[-1] = includePathOpts[-1] % os.path.join(_infraDir)

Expand Down Expand Up @@ -198,35 +213,47 @@ def compile(self, sources,
else:
optimizationOpts = self._defaultOptimizeOpts

#for source in sources:
#outOpts = outputOpts[:]
#objName = self.object_filenames([os.path.split(source)[1]], 0, output_dir)[0]
#outOpts[-1] = outOpts[-1] % _qp(objName)
#cmdElements = (
# [binpath] + extra_preargs + compileOpts +
# [pythonVersionOpt, self._unicodeOpt] + optimizationOpts +
# includePathOpts + outOpts + userVersionAndDebugOpts +
# [_qp(source)] + extra_postargs
#)
# gdc/gcc doesn't support the idea of an output directory, so we
# compile from the destination
sources = [_qp(os.path.abspath(s)) for s in sources]
cwd = os.getcwd()
os.chdir(output_dir)
cmdElements = (
[binpath] + extra_preargs + compileOpts +
[pythonVersionOpt, self._unicodeOpt] + optimizationOpts +
includePathOpts + userVersionAndDebugOpts +
sources + extra_postargs
)
cmdElements = [el for el in cmdElements if el]

try:
self.spawn(cmdElements)
except DistutilsExecError, msg:
print 'sources: ', [os.path.basename(s) for s in sources]
# Compiling one-by-one exhibits a strange bug in the D front-end, while
# compiling all at once works. This flags allows me to test each form
# easily. Supporting the one-by-one form is synonymous with GDC support.
ONE_BY_ONE = False
if ONE_BY_ONE:
for source in sources:
outOpts = outputOpts[:]
objName = self.object_filenames([os.path.split(source)[1]], 0, output_dir)[0]
outOpts[-1] = outOpts[-1] % _qp(objName)
cmdElements = (
[binpath] + extra_preargs + compileOpts +
[pythonVersionOpt, self._unicodeOpt] + optimizationOpts +
includePathOpts + outOpts + userVersionAndDebugOpts +
[_qp(source)] + extra_postargs
)
cmdElements = [el for el in cmdElements if el]
try:
self.spawn(cmdElements)
except DistutilsExecError, msg:
raise CompileError(msg)
else:
# gdc/gcc doesn't support the idea of an output directory, so we
# compile from the destination
sources = [_qp(os.path.abspath(s)) for s in sources]
cwd = os.getcwd()
os.chdir(output_dir)
cmdElements = (
[binpath] + extra_preargs + compileOpts +
[pythonVersionOpt, self._unicodeOpt] + optimizationOpts +
includePathOpts + userVersionAndDebugOpts +
sources + extra_postargs
)
cmdElements = [el for el in cmdElements if el]

try:
self.spawn(cmdElements)
except DistutilsExecError, msg:
#os.chdir(cwd)
raise CompileError(msg)
os.chdir(cwd)
raise CompileError(msg)
os.chdir(cwd)

return [os.path.join(output_dir, fn) for fn in os.listdir(output_dir) if fn.endswith(self.obj_extension)]

Expand Down
4 changes: 4 additions & 0 deletions examples/testdll/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
a = testdll.Foo(10)
a.foo()

print "Testing opApply wrapping:"
for i in a:
print i

print

print '--------'
Expand Down
8 changes: 8 additions & 0 deletions examples/testdll/testdll.d
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ class Foo {
writefln("Foo.foo(): i = %s", m_i);
}
Foo opAdd(Foo f) { return new Foo(m_i + f.m_i); }
int opApply(int delegate(inout int) dg) {
int result = 0;
for (int i=0; i<10; ++i) {
result = dg(i);
if (result) break;
}
return result;
}
int i() { return m_i; }
void i(int j) { m_i = j; }
}
Expand Down
109 changes: 84 additions & 25 deletions infrastructure/pyd/class_wrap.d
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ private import python;

private import pyd.ctor_wrap;
private import pyd.def;
private import pyd.exception;
private import pyd.ftype;
private import pyd.func_wrap;
private import pyd.iteration;
private import pyd.make_object;
private import pyd.op_wrap;
private import pyd.tuples;
Expand Down Expand Up @@ -110,27 +112,26 @@ template wrapped_methods(T) {
/// The generic "__new__" method
extern(C)
PyObject* wrapped_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
wrap_object* self;
return exception_catcher(delegate PyObject*() {
wrap_object* self;

self = cast(wrap_object*)type.tp_alloc(type, 0);
if (self !is null) {
self.d_obj = null;
}
self = cast(wrap_object*)type.tp_alloc(type, 0);
if (self !is null) {
self.d_obj = null;
}

return cast(PyObject*)self;
return cast(PyObject*)self;
});
}

/// The generic dealloc method.
extern(C)
void wrapped_dealloc(PyObject* _self) {
wrap_object* self = cast(wrap_object*)_self;
if (self.d_obj !is null) {
wrap_class_instances!(T)[self.d_obj]--;
if (wrap_class_instances!(T)[self.d_obj] <= 0) {
wrap_class_instances!(T).remove(self.d_obj);
}
}
self.ob_type.tp_free(self);
void wrapped_dealloc(PyObject* self) {
exception_catcher(delegate PyObject*() {
WrapPyObject_SetObj(self, null);
self.ob_type.tp_free(self);
return null;
});
}
}

Expand All @@ -139,9 +140,11 @@ template wrapped_repr(T) {
/// The default repr method calls the class's toString.
extern(C)
PyObject* repr(PyObject* _self) {
wrap_object* self = cast(wrap_object*)_self;
char[] repr = self.d_obj.toString();
return _py(repr);
return exception_catcher({
wrap_object* self = cast(wrap_object*)_self;
char[] repr = self.d_obj.toString();
return _py(repr);
});
}
}

Expand All @@ -151,10 +154,10 @@ template wrapped_init(T) {
/// The default _init method calls the class's zero-argument constructor.
extern(C)
int init(PyObject* self, PyObject* args, PyObject* kwds) {
T t = new T;
(cast(wrap_object*)self).d_obj = t;
wrap_class_instances!(T)[t] = 1;
return 0;
return exception_catcher({
WrapPyObject_SetObj(self, new T);
return 0;
});
}
}

Expand All @@ -181,6 +184,7 @@ template wrapped_get(T, alias Fn) {
/// A generic wrapper around a "getter" property.
extern(C)
PyObject* func(PyObject* self, void* closure) {
// func_wrap already catches exceptions
return func_wrap!(Fn, 0, T, property_parts!(Fn).getter_type).func(self, null);
}
}
Expand All @@ -192,12 +196,15 @@ template wrapped_set(T, alias Fn) {
int func(PyObject* self, PyObject* value, void* closure) {
PyObject* temp_tuple = PyTuple_New(1);
if (temp_tuple is null) return -1;
scope(exit) Py_DECREF(temp_tuple);
Py_INCREF(value);
PyTuple_SetItem(temp_tuple, 0, value);
PyObject* res = func_wrap!(Fn, 1, T, property_parts!(Fn).setter_type).func(self, temp_tuple);
// We'll get something back, and need to DECREF it.
Py_DECREF(res);
Py_DECREF(temp_tuple);
// If we get something back, we need to DECREF it.
if (res) Py_DECREF(res);
// If we don't, propagate the exception
else return -1;
// Otherwise, all is well.
return 0;
}
}
Expand Down Expand Up @@ -340,6 +347,11 @@ void finalize_class(CLS) (CLS cls) {
if (wrapped_class_as_number!(T) != PyNumberMethods.init) {
type.tp_as_number = &wrapped_class_as_number!(T);
}

static if (is(typeof(&T.opApply))) {
DPySC_Ready();
type.tp_iter = &wrapped_iter!(T).iter;
}

// If a ctor wasn't supplied, try the default.
if (type.tp_init is null) {
Expand All @@ -355,3 +367,50 @@ void finalize_class(CLS) (CLS cls) {
is_wrapped!(T) = true;
wrapped_classes[typeid(T)] = true;
}

/**
* Returns a new Python object of a wrapped type.
*/
PyObject* WrapPyObject_FromObject(T) (T t) {
alias wrapped_class_object!(T) wrapped_object;
alias wrapped_class_type!(T) type;
if (is_wrapped!(T)) {
// Allocate the object
wrapped_object* obj =
cast(wrapped_object*)type.tp_new(&type, null, null);
// Set the contained instance
WrapPyObject_SetObj(obj, t);
return cast(PyObject*)obj;
} else {
PyErr_SetString(PyExc_RuntimeError, "Type " ~ typeid(T).toString() ~ " is not wrapped by Pyd.");
return null;
}
}

T WrapPyObject_AsObject(T) (PyObject* _self) {
alias wrapped_class_object!(T) wrapped_object;
alias wrapped_class_type!(T) type;
wrapped_object* self = cast(wrapped_object*)_self;
if (!is_wrapped!(T) || self is null || !PyObject_TypeCheck(_self, &type)) {
// Throw something
}
return self.d_obj;
}

/**
* Sets the contained object in self to t.
*/
void WrapPyObject_SetObj(PY, T) (PY* _self, T t) {
alias wrapped_class_object!(T) obj;
obj* self = cast(obj*)_self;
// Clean up the old object, if there is one
if (self.d_obj !is null) {
wrap_class_instances!(T)[self.d_obj]--;
if (wrap_class_instances!(T)[self.d_obj] <= 0) {
wrap_class_instances!(T).remove(self.d_obj);
}
}
self.d_obj = t;
// Handle the new one, if there is one
if (t !is null) wrap_class_instances!(T)[t]++;
}
Loading

0 comments on commit c540609

Please sign in to comment.