mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Remove the copy of dukpy. Make it an external dependency.
This commit is contained in:
parent
f005731212
commit
9564c94ad1
@ -115,12 +115,6 @@
|
|||||||
"sources": "calibre/ebooks/djvu/bzzdecoder.c",
|
"sources": "calibre/ebooks/djvu/bzzdecoder.c",
|
||||||
"windows_inc_dirs": "calibre/utils/chm"
|
"windows_inc_dirs": "calibre/utils/chm"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "dukpy",
|
|
||||||
"sources": "duktape/errors.c duktape/context.c duktape/conversions.c duktape/proxy.c duktape/module.c duktape/duktape/duktape.c",
|
|
||||||
"headers": "duktape/dukpy.h duktape/duktape/duk_config.h duktape/duktape/duktape.h",
|
|
||||||
"optimize_level": 2
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "podofo",
|
"name": "podofo",
|
||||||
"sources": "calibre/utils/podofo/utils.cpp calibre/utils/podofo/output.cpp calibre/utils/podofo/doc.cpp calibre/utils/podofo/outline.cpp calibre/utils/podofo/podofo.cpp",
|
"sources": "calibre/utils/podofo/utils.cpp calibre/utils/podofo/output.cpp calibre/utils/podofo/doc.cpp calibre/utils/podofo/outline.cpp calibre/utils/podofo/podofo.cpp",
|
||||||
|
@ -167,7 +167,6 @@ class Plugins(collections.Mapping):
|
|||||||
'matcher',
|
'matcher',
|
||||||
'tokenizer',
|
'tokenizer',
|
||||||
'certgen',
|
'certgen',
|
||||||
'dukpy',
|
|
||||||
'lzma_binding',
|
'lzma_binding',
|
||||||
]
|
]
|
||||||
if iswindows:
|
if iswindows:
|
||||||
|
@ -12,13 +12,11 @@ __all__ = ['dukpy', 'Context', 'undefined', 'JSError', 'to_python']
|
|||||||
import errno, os, sys, numbers, hashlib, json
|
import errno, os, sys, numbers, hashlib, json
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from calibre.constants import plugins, iswindows
|
import dukpy
|
||||||
|
|
||||||
|
from calibre.constants import iswindows
|
||||||
from calibre.utils.filenames import atomic_rename
|
from calibre.utils.filenames import atomic_rename
|
||||||
|
|
||||||
dukpy, err = plugins['dukpy']
|
|
||||||
if err:
|
|
||||||
raise RuntimeError('Failed to load dukpy with error: %s' % err)
|
|
||||||
del err
|
|
||||||
Context_, undefined = dukpy.Context, dukpy.undefined
|
Context_, undefined = dukpy.Context, dukpy.undefined
|
||||||
|
|
||||||
fs = '''
|
fs = '''
|
||||||
|
@ -1,248 +0,0 @@
|
|||||||
#include "dukpy.h"
|
|
||||||
#include <structmember.h>
|
|
||||||
|
|
||||||
static void DukContext_init_internal(DukContext *self)
|
|
||||||
{
|
|
||||||
/* heap_stash[(void *)self->ctx] = (void *)self */
|
|
||||||
duk_push_heap_stash(self->ctx);
|
|
||||||
duk_push_pointer(self->ctx, self->ctx);
|
|
||||||
duk_push_pointer(self->ctx, self);
|
|
||||||
duk_put_prop(self->ctx, -3);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int DukContext_init(DukContext *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
(void)args;
|
|
||||||
(void)kw;
|
|
||||||
|
|
||||||
self->heap_manager = NULL; /* We manage the heap */
|
|
||||||
self->py_thread_state = NULL;
|
|
||||||
|
|
||||||
self->ctx = duk_create_heap_default();
|
|
||||||
if (!self->ctx) {
|
|
||||||
PyErr_SetString(PyExc_MemoryError, "Failed to create duktape heap");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* heap_stash.heap = (void *)self */
|
|
||||||
duk_push_heap_stash(self->ctx);
|
|
||||||
duk_push_pointer(self->ctx, self);
|
|
||||||
duk_put_prop_string(self->ctx, -2, "heap");
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
|
|
||||||
DukContext_init_internal(self);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukContext_new_global_env(DukContext *self, PyObject *args)
|
|
||||||
{
|
|
||||||
DukContext *new_context;
|
|
||||||
(void)args;
|
|
||||||
|
|
||||||
new_context = PyObject_New(DukContext, &DukContext_Type);
|
|
||||||
if (new_context == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
new_context->heap_manager = self->heap_manager ? self->heap_manager : self;
|
|
||||||
Py_INCREF(self);
|
|
||||||
|
|
||||||
/* heap_stash[(void *)new_context] = new_context->ctx (thread object) */
|
|
||||||
duk_push_heap_stash(self->ctx);
|
|
||||||
duk_push_pointer(self->ctx, new_context);
|
|
||||||
duk_push_thread_new_globalenv(self->ctx);
|
|
||||||
new_context->ctx = duk_get_context(self->ctx, -1);
|
|
||||||
duk_put_prop(self->ctx, -3);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
|
|
||||||
DukContext_init_internal(new_context);
|
|
||||||
|
|
||||||
return (PyObject *)new_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DukContext_dealloc(DukContext *self)
|
|
||||||
{
|
|
||||||
if (!self->heap_manager) {
|
|
||||||
duk_destroy_heap(self->ctx);
|
|
||||||
} else {
|
|
||||||
/* Use heap manager's ctx because self->ctx is destroyed */
|
|
||||||
duk_context *ctx = self->heap_manager->ctx;
|
|
||||||
duk_push_heap_stash(ctx);
|
|
||||||
|
|
||||||
/* delete heap_stash[(void *)self->ctx] */
|
|
||||||
duk_push_pointer(ctx, self->ctx);
|
|
||||||
duk_del_prop(ctx, -2);
|
|
||||||
|
|
||||||
/* delete heap_stash[(void *)self] */
|
|
||||||
duk_push_pointer(ctx, self);
|
|
||||||
duk_del_prop(ctx, -2);
|
|
||||||
|
|
||||||
duk_pop(ctx);
|
|
||||||
Py_DECREF(self->heap_manager);
|
|
||||||
}
|
|
||||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukContext_eval(DukContext *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
const char *code, *fname = "<eval>";
|
|
||||||
int noresult = 0, ret = 0;
|
|
||||||
PyObject *result = NULL, *temp = NULL;
|
|
||||||
|
|
||||||
static char *keywords[] = {"code", "noreturn", "fname", NULL};
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|Os:eval", keywords,
|
|
||||||
&code, &temp, &fname)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
|
||||||
|
|
||||||
self->py_thread_state = PyEval_SaveThread(); // Release GIL
|
|
||||||
ret = DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | ((noresult) ? DUK_COMPILE_NORESULT : 0);
|
|
||||||
duk_push_string(self->ctx, fname);
|
|
||||||
ret = duk_eval_raw(self->ctx, code, 0, ret);
|
|
||||||
PyEval_RestoreThread(self->py_thread_state); // Acquire GIL
|
|
||||||
self->py_thread_state = NULL;
|
|
||||||
if (ret != 0) {
|
|
||||||
temp = duk_to_python(self->ctx, -1);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
if (temp) {
|
|
||||||
set_dukpy_error(temp);
|
|
||||||
Py_DECREF(temp);
|
|
||||||
} else PyErr_SetString(PyExc_RuntimeError, "The was an error during eval(), but the error could not be read of the stack");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noresult) {
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = duk_to_python(self->ctx, -1);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukContext_eval_file(DukContext *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
const char *path;
|
|
||||||
int noresult = 0, ret = 0;
|
|
||||||
PyObject *result = NULL, *temp = NULL;
|
|
||||||
|
|
||||||
static char *keywords[] = {"path", "noreturn", NULL};
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|O:eval_file", keywords,
|
|
||||||
&path, &temp)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
|
||||||
|
|
||||||
self->py_thread_state = PyEval_SaveThread(); // Release GIL
|
|
||||||
ret = (noresult) ? duk_peval_file_noresult(self->ctx, path) : duk_peval_file(self->ctx, path);
|
|
||||||
PyEval_RestoreThread(self->py_thread_state); // Acquire GIL
|
|
||||||
self->py_thread_state = NULL;
|
|
||||||
if (ret != 0) {
|
|
||||||
temp = duk_to_python(self->ctx, -1);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
if (temp) {
|
|
||||||
set_dukpy_error(temp);
|
|
||||||
Py_DECREF(temp);
|
|
||||||
} else PyErr_SetString(PyExc_RuntimeError, "The was an error during eval_file(), but the error could not be read of the stack");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noresult) {
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = duk_to_python(self->ctx, -1);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DukContext *DukContext_get(duk_context *ctx)
|
|
||||||
{
|
|
||||||
DukContext *context;
|
|
||||||
|
|
||||||
/* Read DukContext from heap_stash[(void *)ctx] */
|
|
||||||
duk_push_heap_stash(ctx);
|
|
||||||
duk_push_pointer(ctx, ctx);
|
|
||||||
duk_get_prop(ctx, -2);
|
|
||||||
context = duk_get_pointer(ctx, -1);
|
|
||||||
duk_pop_n(ctx, 2);
|
|
||||||
|
|
||||||
/* context is NULL for uncached contexts */
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef DukContext_methods[] = {
|
|
||||||
{"eval", (PyCFunction)DukContext_eval,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, "Evaluate code"},
|
|
||||||
{"eval_file", (PyCFunction)DukContext_eval_file,
|
|
||||||
METH_VARARGS | METH_KEYWORDS, "Evaluate a file"},
|
|
||||||
{"new_global_env", (PyCFunction)DukContext_new_global_env,
|
|
||||||
METH_NOARGS, "Return a new context with a fresh global object"},
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyObject *DukContext_get_global(DukContext *self, void *closure)
|
|
||||||
{
|
|
||||||
DukObject *global;
|
|
||||||
(void)closure;
|
|
||||||
|
|
||||||
duk_push_global_object(self->ctx);
|
|
||||||
global = DukObject_from_DukContext(self, -1);
|
|
||||||
duk_pop(self->ctx);
|
|
||||||
|
|
||||||
return (PyObject *)global;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyGetSetDef DukContext_getset[] = {
|
|
||||||
{"g", (getter)DukContext_get_global, NULL, "The global object", NULL},
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyTypeObject DukContext_Type = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"dukpy.Context", /* tp_name */
|
|
||||||
sizeof(DukContext), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)DukContext_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_print */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_reserved */
|
|
||||||
0, /* tp_repr */
|
|
||||||
0, /* tp_as_number */
|
|
||||||
0, /* tp_as_sequence */
|
|
||||||
0, /* tp_as_mapping */
|
|
||||||
0, /* tp_hash */
|
|
||||||
0, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
0, /* tp_getattro */
|
|
||||||
0, /* tp_setattro */
|
|
||||||
0, /* tp_as_buffer */
|
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
||||||
"Duktape context", /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
0, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
DukContext_methods, /* tp_methods */
|
|
||||||
0, /* tp_members */
|
|
||||||
DukContext_getset, /* tp_getset */
|
|
||||||
0, /* tp_base */
|
|
||||||
0, /* tp_dict */
|
|
||||||
0, /* tp_descr_get */
|
|
||||||
0, /* tp_descr_set */
|
|
||||||
0, /* tp_dictoffset */
|
|
||||||
(initproc)DukContext_init /* tp_init */
|
|
||||||
};
|
|
@ -1,331 +0,0 @@
|
|||||||
#include "dukpy.h"
|
|
||||||
|
|
||||||
static int get_repr(PyObject *value, char *buf, int bufsz) {
|
|
||||||
PyObject *temp = NULL, *repr = NULL;
|
|
||||||
memset(buf, 0, bufsz);
|
|
||||||
|
|
||||||
if (!value) return 0;
|
|
||||||
repr = PyObject_Repr(value);
|
|
||||||
|
|
||||||
if (repr && !PyBytes_Check(repr)) {
|
|
||||||
temp = PyUnicode_AsUTF8String(repr);
|
|
||||||
Py_DECREF(repr); repr = temp;
|
|
||||||
}
|
|
||||||
if (!repr) return 0;
|
|
||||||
strncpy(buf, PyBytes_AS_STRING(repr), bufsz - 1);
|
|
||||||
Py_DECREF(repr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static duk_ret_t python_function_caller(duk_context *ctx)
|
|
||||||
{
|
|
||||||
PyObject *func, *args, *result;
|
|
||||||
PyObject *ptype = NULL, *pval = NULL, *tb = NULL;
|
|
||||||
DukContext *dctx;
|
|
||||||
duk_idx_t nargs, i;
|
|
||||||
static char buf1[200], buf2[1024];
|
|
||||||
int gil_acquired = 0, ret = 1, err_occured;
|
|
||||||
|
|
||||||
dctx = DukContext_get(ctx);
|
|
||||||
nargs = duk_get_top(ctx);
|
|
||||||
|
|
||||||
duk_push_current_function(ctx);
|
|
||||||
duk_get_prop_string(ctx, -1, "\xff" "py_object");
|
|
||||||
func = duk_get_pointer(ctx, -1);
|
|
||||||
|
|
||||||
if (dctx->py_thread_state) {
|
|
||||||
gil_acquired = 1;
|
|
||||||
PyEval_RestoreThread(dctx->py_thread_state);
|
|
||||||
dctx->py_thread_state = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
args = PyTuple_New(nargs);
|
|
||||||
if (!args) {
|
|
||||||
ret = DUK_RET_ALLOC_ERROR;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nargs; i++) {
|
|
||||||
PyObject *arg = duk_to_python(ctx, i);
|
|
||||||
if (arg == NULL) {
|
|
||||||
Py_DECREF(args);
|
|
||||||
ret = DUK_RET_TYPE_ERROR;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTuple_SET_ITEM(args, i, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = PyObject_Call(func, args, NULL);
|
|
||||||
Py_DECREF(args);
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
err_occured = PyErr_Occurred() != NULL;
|
|
||||||
get_repr(func, buf1, 200);
|
|
||||||
if (!err_occured) {
|
|
||||||
if (gil_acquired) {
|
|
||||||
dctx->py_thread_state = PyEval_SaveThread();
|
|
||||||
gil_acquired = 0;
|
|
||||||
}
|
|
||||||
get_repr(func, buf1, 200);
|
|
||||||
duk_error(ctx, DUK_ERR_ERROR, "Function (%s) failed", buf1);
|
|
||||||
}
|
|
||||||
PyErr_Fetch(&ptype, &pval, &tb);
|
|
||||||
if (!get_repr(pval, buf2, 1024)) get_repr(ptype, buf2, 1024);
|
|
||||||
Py_XDECREF(ptype); Py_XDECREF(pval); Py_XDECREF(tb);
|
|
||||||
PyErr_Clear(); /* In case there was an error in get_repr() */
|
|
||||||
if (gil_acquired) {
|
|
||||||
dctx->py_thread_state = PyEval_SaveThread();
|
|
||||||
gil_acquired = 0;
|
|
||||||
}
|
|
||||||
get_repr(func, buf1, 200);
|
|
||||||
duk_error(ctx, DUK_ERR_ERROR, "Function (%s) failed with error: %s", buf1, buf2);
|
|
||||||
|
|
||||||
}
|
|
||||||
python_to_duk(ctx, result);
|
|
||||||
Py_DECREF(result);
|
|
||||||
error:
|
|
||||||
if (gil_acquired) {
|
|
||||||
dctx->py_thread_state = PyEval_SaveThread();
|
|
||||||
gil_acquired = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static duk_ret_t python_object_decref(duk_context *ctx) {
|
|
||||||
int deleted = 0, gil_acquired = 0;
|
|
||||||
DukContext *dctx = DukContext_get(ctx);
|
|
||||||
|
|
||||||
|
|
||||||
duk_get_prop_string(ctx, 0, "\xff""deleted");
|
|
||||||
deleted = duk_to_boolean(ctx, -1);
|
|
||||||
duk_pop(ctx);
|
|
||||||
if (!deleted) {
|
|
||||||
duk_get_prop_string(ctx, 0, "\xff""py_object");
|
|
||||||
if (dctx->py_thread_state) {
|
|
||||||
gil_acquired = 1;
|
|
||||||
PyEval_RestoreThread(dctx->py_thread_state);
|
|
||||||
dctx->py_thread_state = NULL;
|
|
||||||
}
|
|
||||||
Py_XDECREF(duk_get_pointer(ctx, -1));
|
|
||||||
if (gil_acquired) {
|
|
||||||
dctx->py_thread_state = PyEval_SaveThread();
|
|
||||||
gil_acquired = 0;
|
|
||||||
}
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
// Mark as deleted
|
|
||||||
duk_push_boolean(ctx, 1);
|
|
||||||
duk_put_prop_string(ctx, 0, "\xff""deleted");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int python_to_duk(duk_context *ctx, PyObject *value)
|
|
||||||
{
|
|
||||||
/* Python to duktape conversion. If successful, leaves the
|
|
||||||
converted value on the top of the stack and returns 0.
|
|
||||||
Otherwise, raises a Python exception and returns -1.
|
|
||||||
*/
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
int ret;
|
|
||||||
#endif
|
|
||||||
static char buf[200];
|
|
||||||
|
|
||||||
if (value == Duk_undefined) {
|
|
||||||
duk_push_undefined(ctx);
|
|
||||||
}
|
|
||||||
else if (value == Py_None) {
|
|
||||||
/* Map None to null */
|
|
||||||
duk_push_null(ctx);
|
|
||||||
}
|
|
||||||
else if (value == Py_True) {
|
|
||||||
duk_push_true(ctx);
|
|
||||||
}
|
|
||||||
else if (value == Py_False) {
|
|
||||||
duk_push_false(ctx);
|
|
||||||
}
|
|
||||||
else if (Py_TYPE(value) == &DukObject_Type || Py_TYPE(value) == &DukFunction_Type || Py_TYPE(value) == &DukArray_Type) {
|
|
||||||
DukObject_push((DukObject *)value, ctx);
|
|
||||||
}
|
|
||||||
else if (PyUnicode_Check(value)) {
|
|
||||||
/* Unicode string */
|
|
||||||
#ifdef PyUnicode_AsUTF8AndSize
|
|
||||||
char *str;
|
|
||||||
Py_ssize_t len;
|
|
||||||
str = PyUnicode_AsUTF8AndSize(value, &len);
|
|
||||||
if (str == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
duk_push_lstring(ctx, str, len);
|
|
||||||
#else
|
|
||||||
PyObject *utf8str = PyUnicode_AsUTF8String(value);
|
|
||||||
if (utf8str == NULL)
|
|
||||||
return -1;
|
|
||||||
duk_push_lstring(ctx, PyBytes_AS_STRING(utf8str), PyBytes_GET_SIZE(utf8str));
|
|
||||||
Py_DECREF(utf8str);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
else if (PyBytes_Check(value)) {
|
|
||||||
/* Happens in python 2 for attribute access, for example*/
|
|
||||||
PyObject *urepr = PyUnicode_FromObject(value);
|
|
||||||
if (urepr == NULL)
|
|
||||||
return -1;
|
|
||||||
ret = python_to_duk(ctx, urepr);
|
|
||||||
Py_DECREF(urepr);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (PyLong_Check(value)) {
|
|
||||||
double val = PyLong_AsDouble(value);
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
duk_push_number(ctx, val);
|
|
||||||
}
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
else if (PyInt_Check(value)) {
|
|
||||||
double val = (double)PyInt_AsLong(value);
|
|
||||||
duk_push_number(ctx, val);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if (PyFloat_Check(value)) {
|
|
||||||
double val = PyFloat_AsDouble(value);
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
duk_push_number(ctx, val);
|
|
||||||
}
|
|
||||||
else if (PyDict_Check(value)) {
|
|
||||||
PyObject *key, *val;
|
|
||||||
Py_ssize_t pos = 0;
|
|
||||||
|
|
||||||
duk_push_object(ctx);
|
|
||||||
|
|
||||||
while (PyDict_Next(value, &pos, &key, &val)) {
|
|
||||||
if (python_to_duk(ctx, key) == -1) {
|
|
||||||
/* Pop the object */
|
|
||||||
duk_pop(ctx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (python_to_duk(ctx, val) == -1) {
|
|
||||||
/* Pop the key and the object */
|
|
||||||
duk_pop_n(ctx, 2);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
duk_put_prop(ctx, -3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (PyList_Check(value)) {
|
|
||||||
PyObject *val;
|
|
||||||
Py_ssize_t i, len;
|
|
||||||
|
|
||||||
duk_push_array(ctx);
|
|
||||||
|
|
||||||
len = PyList_Size(value);
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
val = PyList_GetItem(value, i);
|
|
||||||
if (python_to_duk(ctx, val) == -1) {
|
|
||||||
/* Pop the array */
|
|
||||||
duk_pop(ctx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
duk_put_prop_index(ctx, -2, (duk_uarridx_t)i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (PyCallable_Check(value)) {
|
|
||||||
// Store the callable
|
|
||||||
duk_push_c_function(ctx, python_function_caller, DUK_VARARGS);
|
|
||||||
duk_push_pointer(ctx, value);
|
|
||||||
Py_INCREF(value);
|
|
||||||
duk_put_prop_string(ctx, -2, "\xff" "py_object");
|
|
||||||
// Store a boolean flag to mark the object as deleted because the destructor may be called several times
|
|
||||||
duk_push_boolean(ctx, 0);
|
|
||||||
duk_put_prop_string(ctx, -2, "\xff""deleted");
|
|
||||||
// Store the function destructor
|
|
||||||
duk_push_c_function(ctx, python_object_decref, 1);
|
|
||||||
duk_set_finalizer(ctx, -2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(get_repr(value, buf, 200))
|
|
||||||
PyErr_Format(PyExc_TypeError, "%s is not coercible", buf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *duk_to_python(duk_context *ctx, duk_idx_t index)
|
|
||||||
{
|
|
||||||
/* Duktape to Python conversion. If successful, returns a pointer
|
|
||||||
to a new PyObject reference. If not, raises a Python exception
|
|
||||||
and returns NULL.
|
|
||||||
*/
|
|
||||||
duk_idx_t index_n = duk_normalize_index(ctx, index);
|
|
||||||
PyObject *result;
|
|
||||||
|
|
||||||
if (duk_is_undefined(ctx, index_n)) {
|
|
||||||
Py_INCREF(Duk_undefined);
|
|
||||||
return Duk_undefined;
|
|
||||||
}
|
|
||||||
else if (duk_is_null(ctx, index_n)) {
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
else if (duk_is_boolean(ctx, index_n)) {
|
|
||||||
if (duk_get_boolean(ctx, index_n))
|
|
||||||
Py_RETURN_TRUE;
|
|
||||||
else
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
else if (duk_is_number(ctx, index_n)) {
|
|
||||||
double number, temp;
|
|
||||||
number = duk_get_number(ctx, index_n);
|
|
||||||
if (modf(number, &temp) == 0) {
|
|
||||||
/* No fractional part */
|
|
||||||
return PyLong_FromDouble(number);
|
|
||||||
} else {
|
|
||||||
/* Has fractional part */
|
|
||||||
return PyFloat_FromDouble(number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (duk_is_string(ctx, index_n)) {
|
|
||||||
const char *str;
|
|
||||||
duk_size_t len;
|
|
||||||
|
|
||||||
/* Duplicate the string because it's replaced by duk_to_lstring() */
|
|
||||||
duk_dup(ctx, index_n);
|
|
||||||
str = duk_to_lstring(ctx, -1, &len);
|
|
||||||
|
|
||||||
result = PyUnicode_DecodeUTF8(str, len, NULL);
|
|
||||||
|
|
||||||
/* Pop the duplicate */
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else if (duk_is_array(ctx, index_n)) {
|
|
||||||
return (PyObject *)DukArray_from_ctx(ctx, index_n);
|
|
||||||
}
|
|
||||||
else if (duk_is_function(ctx, index_n)) {
|
|
||||||
return (PyObject *)DukFunction_from_ctx(ctx, index_n);
|
|
||||||
}
|
|
||||||
else if (duk_is_object(ctx, index_n)) {
|
|
||||||
/* Other objects than arrays or functions */
|
|
||||||
return (PyObject *)DukObject_from_ctx(ctx, index_n);
|
|
||||||
}
|
|
||||||
else if (duk_check_type(ctx, index_n, DUK_TYPE_BUFFER)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "'buffer' is not coercible");
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (duk_check_type(ctx, index_n, DUK_TYPE_POINTER)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "'pointer' is not coercible");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Not reached */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
#ifndef DUKPY_H
|
|
||||||
#define DUKPY_H
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
#include "duktape/duktape.h"
|
|
||||||
|
|
||||||
typedef struct DukContext_ DukContext;
|
|
||||||
typedef struct DukObject_ DukObject;
|
|
||||||
typedef struct DukEnum_ DukEnum;
|
|
||||||
|
|
||||||
|
|
||||||
/* module.c */
|
|
||||||
|
|
||||||
extern PyObject DukUndefined;
|
|
||||||
#define Duk_undefined (&DukUndefined)
|
|
||||||
extern PyObject *JSError;
|
|
||||||
|
|
||||||
|
|
||||||
/* context.c */
|
|
||||||
|
|
||||||
struct DukContext_ {
|
|
||||||
PyObject_HEAD
|
|
||||||
duk_context *ctx;
|
|
||||||
DukContext *heap_manager;
|
|
||||||
PyThreadState *py_thread_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern PyTypeObject DukContext_Type;
|
|
||||||
|
|
||||||
DukContext *DukContext_get(duk_context *ctx);
|
|
||||||
|
|
||||||
|
|
||||||
/* proxy.c */
|
|
||||||
|
|
||||||
struct DukObject_ {
|
|
||||||
PyObject_HEAD
|
|
||||||
DukContext *context;
|
|
||||||
DukObject *parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern PyTypeObject DukObject_Type;
|
|
||||||
extern PyTypeObject DukArray_Type;
|
|
||||||
extern PyTypeObject DukFunction_Type;
|
|
||||||
extern PyTypeObject DukEnum_Type;
|
|
||||||
|
|
||||||
DukObject *DukObject_from_DukContext(DukContext *context, duk_idx_t index);
|
|
||||||
DukObject *DukObject_from_ctx(duk_context *ctx, duk_idx_t index);
|
|
||||||
int DukObject_push(DukObject *self, duk_context *ctx);
|
|
||||||
|
|
||||||
DukObject *DukArray_from_ctx(duk_context *ctx, duk_idx_t index);
|
|
||||||
DukObject *DukFunction_from_ctx(duk_context *ctx, duk_idx_t index);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DUKENUM_KEYS,
|
|
||||||
DUKENUM_VALUES,
|
|
||||||
DUKENUM_PAIRS
|
|
||||||
} dukenum_mode_t;
|
|
||||||
|
|
||||||
struct DukEnum_ {
|
|
||||||
PyObject_HEAD
|
|
||||||
DukObject base;
|
|
||||||
dukenum_mode_t mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
DukEnum *DukEnum_from_DukContext(DukContext *context, dukenum_mode_t mode);
|
|
||||||
|
|
||||||
|
|
||||||
/* conversions.c */
|
|
||||||
|
|
||||||
int python_to_duk(duk_context *ctx, PyObject *value);
|
|
||||||
PyObject *duk_to_python(duk_context *ctx, duk_idx_t index);
|
|
||||||
|
|
||||||
void set_dukpy_error(PyObject *obj);
|
|
||||||
|
|
||||||
#endif /* DUKPY_H */
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* errors.c
|
|
||||||
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
|
|
||||||
*
|
|
||||||
* Distributed under terms of the GPL3 license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "dukpy.h"
|
|
||||||
|
|
||||||
static int copy_error_attr(PyObject *obj, const char* name, PyObject *dest) {
|
|
||||||
PyObject *value = NULL;
|
|
||||||
if (!PyObject_HasAttrString(obj, name)) return 0;
|
|
||||||
value = PyObject_GetAttrString(obj, name);
|
|
||||||
if (value == NULL) return 0;
|
|
||||||
if (PyDict_SetItemString(dest, name, value) != 0) {Py_DECREF(value); return 0;}
|
|
||||||
Py_DECREF(value);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_dukpy_error(PyObject *obj) {
|
|
||||||
PyObject *err = NULL, *iterator = NULL, *item = NULL;
|
|
||||||
if (Py_TYPE(obj) == &DukObject_Type) {
|
|
||||||
err = PyDict_New();
|
|
||||||
if (err == NULL) { PyErr_NoMemory(); return; }
|
|
||||||
|
|
||||||
// Look for the common error object properties that may be up the prototype chain
|
|
||||||
if (!copy_error_attr(obj, "name", err)) { Py_DECREF(err); return; }
|
|
||||||
if (!copy_error_attr(obj, "message", err)) { Py_DECREF(err); return; }
|
|
||||||
if (!copy_error_attr(obj, "fileName", err)) { Py_DECREF(err); return; }
|
|
||||||
if (!copy_error_attr(obj, "lineNumber", err)) { Py_DECREF(err); return; }
|
|
||||||
if (!copy_error_attr(obj, "stack", err)) { Py_DECREF(err); return; }
|
|
||||||
|
|
||||||
// Now copy over own properties
|
|
||||||
iterator = PyObject_CallMethod(obj, "items", NULL);
|
|
||||||
if (iterator == NULL) { Py_DECREF(err); return; }
|
|
||||||
while ((item = PyIter_Next(iterator))) {
|
|
||||||
PyDict_SetItem(err, PyTuple_GET_ITEM(item, 0), PyTuple_GET_ITEM(item, 1));
|
|
||||||
Py_DECREF(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_SetObject(JSError, err);
|
|
||||||
Py_DECREF(err); Py_DECREF(iterator);
|
|
||||||
} else PyErr_SetObject(JSError, obj);
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
#include "dukpy.h"
|
|
||||||
|
|
||||||
PyObject *JSError = NULL;
|
|
||||||
|
|
||||||
/* ARGSUSED */
|
|
||||||
static PyObject *
|
|
||||||
undefined_repr(PyObject *op)
|
|
||||||
{
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
return PyBytes_FromString("undefined");
|
|
||||||
#else
|
|
||||||
return PyUnicode_FromString("undefined");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ARGUSED */
|
|
||||||
static void
|
|
||||||
undefined_dealloc(PyObject* ignore)
|
|
||||||
{
|
|
||||||
/* This should never get called, but we also don't want to SEGV if
|
|
||||||
* we accidentally decref undef out of existence.
|
|
||||||
*/
|
|
||||||
Py_FatalError("deallocating undefined");
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyTypeObject DukUndefined_Type = {
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
#else
|
|
||||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
||||||
#endif
|
|
||||||
"UndefinedType",
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
undefined_dealloc,
|
|
||||||
0, /*tp_print*/
|
|
||||||
0, /*tp_getattr*/
|
|
||||||
0, /*tp_setattr*/
|
|
||||||
0, /*tp_compare*/
|
|
||||||
undefined_repr, /*tp_repr*/
|
|
||||||
0, /*tp_as_number*/
|
|
||||||
0, /*tp_as_sequence*/
|
|
||||||
0, /*tp_as_mapping*/
|
|
||||||
};
|
|
||||||
|
|
||||||
PyObject DukUndefined = {
|
|
||||||
_PyObject_EXTRA_INIT
|
|
||||||
1, &DukUndefined_Type
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
static struct PyModuleDef moduledef = {
|
|
||||||
PyModuleDef_HEAD_INIT,
|
|
||||||
"dukpy", /* m_name */
|
|
||||||
NULL, /* m_doc */
|
|
||||||
0, /* m_size */
|
|
||||||
NULL, /* m_methods */
|
|
||||||
NULL, /* m_reload */
|
|
||||||
NULL, /* m_traverse */
|
|
||||||
NULL, /* m_clear */
|
|
||||||
NULL /* m_free */
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
__attribute__ ((visibility ("default")))
|
|
||||||
#endif
|
|
||||||
PyMODINIT_FUNC
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
PyInit_dukpy(void)
|
|
||||||
#else
|
|
||||||
initdukpy(void)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
PyObject *mod;
|
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
DukUndefined_Type.ob_type = &PyType_Type;
|
|
||||||
#endif
|
|
||||||
if (PyType_Ready(&DukUndefined_Type) < 0)
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DukContext_Type.tp_new = PyType_GenericNew;
|
|
||||||
if (PyType_Ready(&DukContext_Type) < 0)
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DukObject_Type.tp_new = PyType_GenericNew;
|
|
||||||
if (PyType_Ready(&DukObject_Type) < 0)
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DukArray_Type.tp_new = PyType_GenericNew;
|
|
||||||
if (PyType_Ready(&DukArray_Type) < 0)
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DukFunction_Type.tp_new = PyType_GenericNew;
|
|
||||||
if (PyType_Ready(&DukFunction_Type) < 0)
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DukEnum_Type.tp_new = PyType_GenericNew;
|
|
||||||
if (PyType_Ready(&DukEnum_Type) < 0)
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
mod = PyModule_Create(&moduledef);
|
|
||||||
#else
|
|
||||||
mod = Py_InitModule3("dukpy", NULL, "Python bindings for duktape");
|
|
||||||
#endif
|
|
||||||
if (mod != NULL) {
|
|
||||||
Py_INCREF(&DukContext_Type);
|
|
||||||
PyModule_AddObject(mod, "Context", (PyObject *)&DukContext_Type);
|
|
||||||
|
|
||||||
Py_INCREF(Duk_undefined);
|
|
||||||
PyModule_AddObject(mod, "undefined", (PyObject *)Duk_undefined);
|
|
||||||
|
|
||||||
JSError = PyErr_NewException("dukpy.JSError", NULL, NULL);
|
|
||||||
if (JSError) PyModule_AddObject(mod, "JSError", JSError);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
return mod;
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -1,586 +0,0 @@
|
|||||||
#include "dukpy.h"
|
|
||||||
|
|
||||||
/* DukObject {{{ */
|
|
||||||
|
|
||||||
static void DukObject_INIT(DukObject *self, DukContext *context,
|
|
||||||
duk_idx_t index)
|
|
||||||
{
|
|
||||||
duk_context *ctx = context->ctx;
|
|
||||||
duk_idx_t index_n = duk_normalize_index(ctx, index);
|
|
||||||
|
|
||||||
Py_INCREF(context);
|
|
||||||
self->context = context;
|
|
||||||
self->parent = NULL;
|
|
||||||
|
|
||||||
/* heap_stash[(void *)self] = proxied_value */
|
|
||||||
duk_push_heap_stash(ctx);
|
|
||||||
duk_push_pointer(ctx, self);
|
|
||||||
duk_dup(ctx, index_n);
|
|
||||||
duk_put_prop(ctx, -3);
|
|
||||||
duk_pop(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DukObject_DESTRUCT(DukObject *self)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
|
|
||||||
/* delete heap_stash[(void *)self] */
|
|
||||||
duk_push_heap_stash(ctx);
|
|
||||||
duk_push_pointer(ctx, self);
|
|
||||||
duk_del_prop(ctx, -2);
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
Py_XDECREF(self->parent);
|
|
||||||
Py_DECREF(self->context);
|
|
||||||
}
|
|
||||||
|
|
||||||
DukObject *DukObject_from_DukContext(DukContext *context, duk_idx_t index)
|
|
||||||
{
|
|
||||||
DukObject *self;
|
|
||||||
|
|
||||||
self = PyObject_New(DukObject, &DukObject_Type);
|
|
||||||
if (self == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
DukObject_INIT(self, context, index);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
DukObject *DukObject_from_ctx(duk_context *ctx, duk_idx_t index)
|
|
||||||
{
|
|
||||||
DukContext *context = DukContext_get(ctx);
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "Unknown context %p", ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DukObject_from_DukContext(context, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DukObject_dealloc(DukObject *self)
|
|
||||||
{
|
|
||||||
DukObject_DESTRUCT(self);
|
|
||||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DukObject_push(DukObject *self, duk_context *ctx)
|
|
||||||
{
|
|
||||||
/* Push the proxied value to given context's stack */
|
|
||||||
duk_push_heap_stash(ctx);
|
|
||||||
duk_push_pointer(ctx, self);
|
|
||||||
duk_get_prop(ctx, -2);
|
|
||||||
duk_replace(ctx, -2);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PUSH(p) DukObject_push((p), (p)->context->ctx)
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *DukObject_getattr(DukObject *self, PyObject *name)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
PyObject *value;
|
|
||||||
|
|
||||||
/* Look up normal attributes first */
|
|
||||||
if (!(value = PyObject_GenericGetAttr((PyObject *)self, name))) {
|
|
||||||
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
|
||||||
return NULL;
|
|
||||||
PyErr_Clear();
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Not found, query the duktape object */
|
|
||||||
PUSH(self);
|
|
||||||
|
|
||||||
if (python_to_duk(ctx, name) != 0) {
|
|
||||||
duk_pop(ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
duk_get_prop(ctx, -2);
|
|
||||||
value = duk_to_python(ctx, -1);
|
|
||||||
duk_pop_n(ctx, 2);
|
|
||||||
|
|
||||||
if (Py_TYPE(value) == &DukFunction_Type) {
|
|
||||||
/* Set parent link for method calls */
|
|
||||||
Py_INCREF(self);
|
|
||||||
((DukObject *)value)->parent = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int DukObject_setattr(DukObject *self, PyObject *name, PyObject *value)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
|
|
||||||
PUSH(self);
|
|
||||||
|
|
||||||
if (python_to_duk(ctx, name) != 0) {
|
|
||||||
duk_pop(ctx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (python_to_duk(ctx, value) != 0) {
|
|
||||||
duk_pop_n(ctx, 2);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
duk_put_prop(ctx, -3);
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukObject_make_enum(DukObject *self, dukenum_mode_t mode)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
PyObject *result;
|
|
||||||
|
|
||||||
PUSH(self);
|
|
||||||
|
|
||||||
duk_enum(ctx, -1, 0);
|
|
||||||
result = (PyObject *)DukEnum_from_DukContext(self->context, mode);
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *DukObject_iter(DukObject *self)
|
|
||||||
{
|
|
||||||
return DukObject_make_enum(self, DUKENUM_KEYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *DukObject_keys(DukObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
(void)args;
|
|
||||||
return DukObject_make_enum(self, DUKENUM_KEYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukObject_values(DukObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
(void)args;
|
|
||||||
return DukObject_make_enum(self, DUKENUM_VALUES);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukObject_items(DukObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
(void)args;
|
|
||||||
return DukObject_make_enum(self, DUKENUM_PAIRS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMappingMethods DukObject_as_mapping = {
|
|
||||||
NULL,
|
|
||||||
(binaryfunc)DukObject_getattr,
|
|
||||||
(objobjargproc)DukObject_setattr
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyMethodDef DukObject_methods[] = {
|
|
||||||
{"keys", (PyCFunction)DukObject_keys, METH_NOARGS,
|
|
||||||
"Iterate over object keys"},
|
|
||||||
{"values", (PyCFunction)DukObject_values, METH_NOARGS,
|
|
||||||
"Iterate over object values"},
|
|
||||||
{"items", (PyCFunction)DukObject_items, METH_NOARGS,
|
|
||||||
"Iterate over key-value pairs"},
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyTypeObject DukObject_Type = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"Object proxy", /* tp_name */
|
|
||||||
sizeof(DukObject), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)DukObject_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_print */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_reserved */
|
|
||||||
0, /* tp_repr */
|
|
||||||
0, /* tp_as_number */
|
|
||||||
0, /* tp_as_sequence */
|
|
||||||
&DukObject_as_mapping, /* tp_as_mapping */
|
|
||||||
0, /* tp_hash */
|
|
||||||
0, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
(getattrofunc)DukObject_getattr, /* tp_getattro */
|
|
||||||
(setattrofunc)DukObject_setattr, /* tp_setattro */
|
|
||||||
0, /* tp_as_buffer */
|
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
||||||
"Duktape object proxy", /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
(getiterfunc)DukObject_iter, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
DukObject_methods, /* tp_methods */
|
|
||||||
0, /* tp_members */
|
|
||||||
0, /* tp_getset */
|
|
||||||
0, /* tp_base */
|
|
||||||
0, /* tp_dict */
|
|
||||||
0, /* tp_descr_get */
|
|
||||||
0, /* tp_descr_set */
|
|
||||||
0, /* tp_dictoffset */
|
|
||||||
0, /* tp_init */
|
|
||||||
0, /* tp_alloc */
|
|
||||||
0 /* tp_new */
|
|
||||||
};
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
/* DukArray {{{ */
|
|
||||||
|
|
||||||
DukObject *DukArray_from_ctx(duk_context *ctx, duk_idx_t index)
|
|
||||||
{
|
|
||||||
DukObject *self;
|
|
||||||
DukContext *context = DukContext_get(ctx);
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "Unknown context %p", ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
self = PyObject_New(DukObject, &DukArray_Type);
|
|
||||||
if (self == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
DukObject_INIT(self, context, index);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_ssize_t DukArray_length(DukObject *self)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
duk_size_t len;
|
|
||||||
|
|
||||||
PUSH(self);
|
|
||||||
len = duk_get_length(ctx, -1);
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
return (Py_ssize_t)len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukArray_getitem(DukObject *self, Py_ssize_t i)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
PyObject *result;
|
|
||||||
|
|
||||||
PUSH(self);
|
|
||||||
duk_get_prop_index(ctx, -1, (duk_uarridx_t)i);
|
|
||||||
|
|
||||||
result = duk_to_python(ctx, -1);
|
|
||||||
if (!result)
|
|
||||||
duk_pop(ctx);
|
|
||||||
else
|
|
||||||
duk_pop_n(ctx, 2);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (result == Duk_undefined) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
PyErr_Format(PyExc_IndexError, "%R has no index %li", self, i);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int DukArray_setitem(DukObject *self, Py_ssize_t i, PyObject *value)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
PUSH(self);
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
/* self[i] = value */
|
|
||||||
if (python_to_duk(ctx, value) == -1) {
|
|
||||||
duk_pop(ctx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
duk_put_prop_index(ctx, -2, (duk_uarridx_t)i);
|
|
||||||
} else {
|
|
||||||
/* del self[i]
|
|
||||||
|
|
||||||
Note that this always succeeds, even if the index doesn't
|
|
||||||
exist.
|
|
||||||
*/
|
|
||||||
duk_del_prop_index(ctx, -1, (duk_uarridx_t)i);
|
|
||||||
duk_pop(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukArray_iter(DukObject *self)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
PyObject *result;
|
|
||||||
|
|
||||||
PUSH(self);
|
|
||||||
|
|
||||||
duk_enum(ctx, -1, DUK_ENUM_ARRAY_INDICES_ONLY);
|
|
||||||
result = (PyObject *)DukEnum_from_DukContext(self->context, DUKENUM_VALUES);
|
|
||||||
duk_pop(ctx);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PySequenceMethods DukArray_as_sequence = {
|
|
||||||
(lenfunc)DukArray_length, /* sq_length */
|
|
||||||
NULL, /* sq_concat */
|
|
||||||
NULL, /* sq_repeat */
|
|
||||||
(ssizeargfunc)DukArray_getitem, /* sq_item */
|
|
||||||
NULL, /* unused */
|
|
||||||
(ssizeobjargproc)DukArray_setitem, /* sq_ass_item */
|
|
||||||
NULL, /* sq_contains */
|
|
||||||
NULL, /* sq_inplace_concat */
|
|
||||||
NULL, /* sq_inplace_repeat */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyTypeObject DukArray_Type = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"Array proxy", /* tp_name */
|
|
||||||
sizeof(DukObject), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)DukObject_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_print */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_reserved */
|
|
||||||
0, /* tp_repr */
|
|
||||||
0, /* tp_as_number */
|
|
||||||
&DukArray_as_sequence, /* tp_as_sequence */
|
|
||||||
0, /* tp_as_mapping */
|
|
||||||
0, /* tp_hash */
|
|
||||||
0, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
(getattrofunc)DukObject_getattr, /* tp_getattro */
|
|
||||||
(setattrofunc)DukObject_setattr, /* tp_setattro */
|
|
||||||
0, /* tp_as_buffer */
|
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
||||||
"Duktape array proxy" , /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
(getiterfunc)DukArray_iter /* tp_iter */
|
|
||||||
};
|
|
||||||
/// }}}
|
|
||||||
|
|
||||||
/* DukFunction {{{ */
|
|
||||||
|
|
||||||
DukObject *DukFunction_from_ctx(duk_context *ctx, duk_idx_t index)
|
|
||||||
{
|
|
||||||
DukObject *self;
|
|
||||||
DukContext *context = DukContext_get(ctx);
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
PyErr_Format(PyExc_RuntimeError, "Unknown context %p", ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
self = PyObject_New(DukObject, &DukFunction_Type);
|
|
||||||
if (self == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
DukObject_INIT(self, context, index);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* DukFunction_repr(DukObject *self) {
|
|
||||||
PyObject *ans = NULL;
|
|
||||||
PyObject *name = PyObject_GetAttrString((PyObject*)self, "name"), *fname = PyObject_GetAttrString((PyObject*)self, "fileName");
|
|
||||||
ans = PyUnicode_FromFormat("[Function proxy: %S() in filename: %S]", name, fname);
|
|
||||||
Py_XDECREF(name); Py_XDECREF(fname);
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* DukFunction_call(DukObject *self, PyObject *args, PyObject *kw)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->context->ctx;
|
|
||||||
Py_ssize_t nargs, i;
|
|
||||||
int return_none = 0, ret = 0;
|
|
||||||
PyObject *result, *temp;
|
|
||||||
|
|
||||||
/* NULL if no parent */
|
|
||||||
PyObject *this = (PyObject *)self->parent;
|
|
||||||
|
|
||||||
if (kw) {
|
|
||||||
|
|
||||||
temp = PyDict_GetItemString(kw, "this");
|
|
||||||
if (temp)
|
|
||||||
this = temp;
|
|
||||||
|
|
||||||
temp = PyDict_GetItemString(kw, "return_none");
|
|
||||||
if (temp)
|
|
||||||
return_none = PyObject_IsTrue(temp);
|
|
||||||
}
|
|
||||||
nargs = PyTuple_Size(args);
|
|
||||||
|
|
||||||
/* Push the function */
|
|
||||||
PUSH(self);
|
|
||||||
|
|
||||||
if (this) {
|
|
||||||
/* Push the "this" binding */
|
|
||||||
if (python_to_duk(ctx, this) == -1) {
|
|
||||||
duk_pop(ctx);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Push args */
|
|
||||||
for (i = 0; i < nargs; i++) {
|
|
||||||
PyObject *arg = PyTuple_GetItem(args, i);
|
|
||||||
if (python_to_duk(ctx, arg) == -1) {
|
|
||||||
duk_pop_n(ctx, 1 + (this ? 1 : 0) + (duk_idx_t)i);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this)
|
|
||||||
ret = duk_pcall_method(ctx, (duk_idx_t)nargs);
|
|
||||||
else
|
|
||||||
ret = duk_pcall(ctx, (duk_idx_t)nargs);
|
|
||||||
|
|
||||||
if (ret != DUK_EXEC_SUCCESS) {
|
|
||||||
temp = duk_to_python(ctx, -1);
|
|
||||||
duk_pop(ctx);
|
|
||||||
if (temp) {
|
|
||||||
set_dukpy_error(temp);
|
|
||||||
Py_DECREF(temp);
|
|
||||||
} else PyErr_SetString(PyExc_RuntimeError, "The was an error during call(), but the error could not be read of the stack");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (return_none) {
|
|
||||||
/* Always return None. This saves converting the function's
|
|
||||||
return value. */
|
|
||||||
duk_pop(ctx);
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
} else {
|
|
||||||
result = duk_to_python(ctx, -1);
|
|
||||||
duk_pop(ctx);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTypeObject DukFunction_Type = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"Function proxy", /* tp_name */
|
|
||||||
sizeof(DukObject), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)DukObject_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_print */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_reserved */
|
|
||||||
(reprfunc)DukFunction_repr, /* tp_repr */
|
|
||||||
0, /* tp_as_number */
|
|
||||||
0, /* tp_as_sequence */
|
|
||||||
0, /* tp_as_mapping */
|
|
||||||
0, /* tp_hash */
|
|
||||||
(ternaryfunc)DukFunction_call, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
(getattrofunc)DukObject_getattr, /* tp_getattro */
|
|
||||||
(setattrofunc)DukObject_setattr, /* tp_setattro */
|
|
||||||
0, /* tp_as_buffer */
|
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
||||||
"Duktape function proxy" /* tp_doc */
|
|
||||||
};
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
/* DukEnum {{{ */
|
|
||||||
|
|
||||||
DukEnum *DukEnum_from_DukContext(DukContext *context, dukenum_mode_t mode)
|
|
||||||
{
|
|
||||||
DukEnum *self;
|
|
||||||
|
|
||||||
self = PyObject_New(DukEnum, &DukEnum_Type);
|
|
||||||
if (self == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
DukObject_INIT(&self->base, context, -1);
|
|
||||||
self->mode = mode;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DukEnum_dealloc(DukEnum *self)
|
|
||||||
{
|
|
||||||
DukObject_DESTRUCT(&self->base);
|
|
||||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukEnum_iter(DukEnum *self)
|
|
||||||
{
|
|
||||||
Py_INCREF(self);
|
|
||||||
return (PyObject *)self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *DukEnum_iternext(DukEnum *self)
|
|
||||||
{
|
|
||||||
duk_context *ctx = self->base.context->ctx;
|
|
||||||
PyObject *result = NULL;
|
|
||||||
int mode = self->mode;
|
|
||||||
int get_value = mode == DUKENUM_VALUES || mode == DUKENUM_PAIRS;
|
|
||||||
int pop = 1;
|
|
||||||
|
|
||||||
PUSH(&self->base);
|
|
||||||
|
|
||||||
if (duk_next(ctx, -1, get_value)) {
|
|
||||||
switch (mode) {
|
|
||||||
case DUKENUM_KEYS:
|
|
||||||
result = duk_to_python(ctx, -1);
|
|
||||||
pop = 2;
|
|
||||||
break;
|
|
||||||
case DUKENUM_VALUES:
|
|
||||||
result = duk_to_python(ctx, -1);
|
|
||||||
pop = 3;
|
|
||||||
break;
|
|
||||||
case DUKENUM_PAIRS:
|
|
||||||
result = Py_BuildValue("(NN)",
|
|
||||||
duk_to_python(ctx, -2),
|
|
||||||
duk_to_python(ctx, -1));
|
|
||||||
pop = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
duk_pop_n(ctx, pop);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTypeObject DukEnum_Type = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"Enumerator", /* tp_name */
|
|
||||||
sizeof(DukEnum), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)DukEnum_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_print */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_reserved */
|
|
||||||
0, /* tp_repr */
|
|
||||||
0, /* tp_as_number */
|
|
||||||
0, /* tp_as_sequence */
|
|
||||||
0, /* tp_as_mapping */
|
|
||||||
0, /* tp_hash */
|
|
||||||
0, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
0, /* tp_getattro */
|
|
||||||
0, /* tp_setattro */
|
|
||||||
0, /* tp_as_buffer */
|
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
||||||
"Duktape enumerator", /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
(getiterfunc)DukEnum_iter, /* tp_iter */
|
|
||||||
(iternextfunc)DukEnum_iternext, /* tp_iternext */
|
|
||||||
};
|
|
||||||
// }}}
|
|
@ -2,10 +2,13 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from threading import Thread, Event
|
from threading import Event, Thread
|
||||||
from duktape import dukpy
|
|
||||||
|
import dukpy
|
||||||
|
|
||||||
undefined, JSError, Context = dukpy.undefined, dukpy.JSError, dukpy.Context
|
undefined, JSError, Context = dukpy.undefined, dukpy.JSError, dukpy.Context
|
||||||
|
|
||||||
|
|
||||||
class ContextTests(unittest.TestCase):
|
class ContextTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user