/* -*- mode: c++; indent-tabs-mode: nil -*- */
/*
QorePythonClass.h
Qore Programming Language python Module
Copyright (C) 2020 - 2022 Qore Technologies, s.r.o.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "QorePythonClass.h"
#include "QorePythonProgram.h"
#include
type_vec_t QorePythonClass::gateParamTypeInfo = { stringTypeInfo };
static constexpr const char* PYOBJ_KEY = "__$PYCLS__";
QorePythonClass::QorePythonClass(const char* name, const char* path)
: QoreBuiltinClass(name, path, QDOM_UNCONTROLLED_API), pypgm(nullptr) {
}
QorePythonClass::QorePythonClass(QorePythonProgram* pypgm, const char* name, const char* path) :
QoreBuiltinClass(name, path, QDOM_UNCONTROLLED_API), pypgm(pypgm) {
pypgm->weakRef();
addMethod(nullptr, "memberGate", (q_external_method_t)memberGate, Public, QCF_NO_FLAGS, QDOM_UNCONTROLLED_API,
autoTypeInfo, gateParamTypeInfo);
addMethod(nullptr, "methodGate", (q_external_method_t)methodGate, Public, QCF_USES_EXTRA_ARGS, QDOM_UNCONTROLLED_API,
autoTypeInfo, gateParamTypeInfo);
addMember(PYOBJ_KEY, Internal, autoTypeInfo);
setPublicMemberFlag();
}
QorePythonClass::QorePythonClass(const QorePythonClass& old) : QoreBuiltinClass(old), pypgm(old.pypgm) {
if (pypgm) {
pypgm->weakRef();
}
}
QorePythonClass::~QorePythonClass() {
if (pypgm) {
pypgm->weakDeref();
}
}
void QorePythonClass::addObj(PyObject* obj) {
pypgm->addObj(obj);
}
PyObject* QorePythonClass::getPyObject(QoreObject* self, ExceptionSink* xsink) const {
ValueHolder v(self->getReferencedMemberNoMethod(PYOBJ_KEY, this, xsink), xsink);
if (*xsink) {
assert(!v);
return nullptr;
}
if (!v) {
return nullptr;
}
if (v->getType() != NT_INT) {
xsink->raiseException("PYTHON-OBJECT-ERROR", "invalid type '%s' saved to internal data key '%s'",
v->getFullTypeName(), PYOBJ_KEY);
return nullptr;
}
return (PyObject*)v->getAsBigInt();
}
int QorePythonClass::setPyObject(QoreObject* self, PyObject* pyself, ExceptionSink* xsink) const {
return self->setMemberValue(PYOBJ_KEY, this, (int64)pyself, xsink);
}
// static method
QoreValue QorePythonClass::methodGate(const QoreMethod& meth, void* m, QoreObject* self, QorePythonPrivateData* pd,
const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) {
assert(args && args->size() >= 1);
assert(args->retrieveEntry(0).getType() == NT_STRING);
const QoreStringNode* mname = args->retrieveEntry(0).get();
//printd(5, "QorePythonClass::methodGate() %s()\n", mname);
QorePythonProgram* pypgm = QorePythonProgram::getPythonProgramFromMethod(meth, xsink);
if (!pypgm) {
assert(*xsink);
return QoreValue();
}
const QorePythonClass* cls = static_cast(meth.getClass());
return cls->callPythonMethod(xsink, pypgm, mname->c_str(), args, pd, 2);
}
// static method
QoreValue QorePythonClass::memberGate(const QoreMethod& meth, void* m, QoreObject* self, QorePythonPrivateData* pd,
const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) {
assert(args && args->size() == 1);
assert(args->retrieveEntry(0).getType() == NT_STRING);
const QoreStringNode* mname = args->retrieveEntry(0).get();
QorePythonProgram* pypgm = QorePythonProgram::getPythonProgramFromMethod(meth, xsink);
if (!pypgm) {
assert(*xsink);
return QoreValue();
}
const QorePythonClass* cls = static_cast(meth.getClass());
return cls->getPythonMember(pypgm, mname->c_str(), pd, xsink);
}
QoreValue QorePythonClass::callPythonMethod(ExceptionSink* xsink, QorePythonProgram* pypgm, const char* mname,
const QoreListNode* args, QorePythonPrivateData* pd, size_t arg_offset) const {
//printd(5, "QorePythonClass::callPythonMethod() %s::%s()\n", pname.c_str(), mname);
PyObject* pyobj = pd->get();
PyTypeObject* mtype = Py_TYPE(pyobj);
QorePythonHelper qph(pypgm);
if (pypgm->checkValid(xsink)) {
return QoreValue();
}
// returns a borrowed reference
PyObject* attr = PyDict_GetItemString(mtype->tp_dict, mname);
if (!attr) {
xsink->raiseException("METHOD-DOES-NOT-EXIST", "Python value of type '%s' has no method or member '%s'",
mtype->tp_name, mname);
return QoreValue();
}
return pypgm->callPythonMethod(xsink, attr, pyobj, args, 2);
}
QoreValue QorePythonClass::getPythonMember(QorePythonProgram* pypgm, const char* mname, QorePythonPrivateData* pd,
ExceptionSink* xsink) const {
QorePythonHelper qph(pypgm);
if (pypgm->checkValid(xsink)) {
return QoreValue();
}
{
PyMemberDef* m = getPythonMember(mname);
if (m) {
return pypgm->getQoreValue(xsink, PyMember_GetOne((const char*)pd->get(), m));
}
}
return pypgm->getQoreAttr(pd->get(), mname, xsink);
}