mirror of https://github.com/KLayout/klayout.git
Synthesize getters from is_... predicates, added getter for RecursiveShapeIterator#shape_flags
This commit is contained in:
parent
be6e05da55
commit
daad80d5d5
|
|
@ -523,6 +523,13 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
"The flags must be specified before the shapes are being retrieved.\n"
|
||||
"Settings the shapes flags will reset the iterator.\n"
|
||||
) +
|
||||
gsi::method ("shape_flags", (unsigned int (db::RecursiveShapeIterator::*)() const) &db::RecursiveShapeIterator::shape_flags,
|
||||
"@brief Gets the shape selection flags\n"
|
||||
"\n"
|
||||
"See \\shape_flags= for a description of that property.\n"
|
||||
"\n"
|
||||
"This getter has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::method ("trans|#itrans", &db::RecursiveShapeIterator::trans,
|
||||
"@brief Gets the current transformation by which the shapes must be transformed into the initial cell\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -24,10 +24,27 @@
|
|||
|
||||
#include "gsiDecl.h"
|
||||
#include "pyaInternal.h"
|
||||
#include "pya.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static const pya::MethodTableEntry *getter (std::pair<const pya::MethodTableEntry *, const pya::MethodTableEntry *> *p)
|
||||
{
|
||||
return p->second;
|
||||
}
|
||||
|
||||
static const pya::MethodTableEntry *setter (std::pair<const pya::MethodTableEntry *, const pya::MethodTableEntry *> *p)
|
||||
{
|
||||
return p->first;
|
||||
}
|
||||
|
||||
gsi::Class<std::pair<const pya::MethodTableEntry *, const pya::MethodTableEntry *> > decl_PythonGetterSetterPair ("tl", "PythonGetterSetterPair",
|
||||
gsi::method_ext ("getter", &getter, "@brief Gets the getter function") +
|
||||
gsi::method_ext ("setter", &setter, "@brief Gets the setter function"),
|
||||
"@hide"
|
||||
);
|
||||
|
||||
gsi::Class<pya::MethodTableEntry> decl_PythonFunction ("tl", "PythonFunction",
|
||||
gsi::method ("methods", &pya::MethodTableEntry::methods, "@brief Gets the list of methods bound to this Python function") +
|
||||
gsi::method ("name", &pya::MethodTableEntry::name, "@brief Gets the name of this Python function") +
|
||||
|
|
@ -77,4 +94,10 @@ gsi::ClassExt<gsi::ClassBase> class_base_ext (
|
|||
"@hide"
|
||||
);
|
||||
|
||||
static
|
||||
gsi::ClassExt<gsi::MethodBase> method_base_ext (
|
||||
gsi::method_ext ("python_methods", &pya::PythonInterpreter::python_doc, "@brief Gets the Python specific documentation"),
|
||||
"@hide"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,13 +11,16 @@ SOURCES = \
|
|||
pyaConvert.cc \
|
||||
pyaHelpers.cc \
|
||||
pyaInspector.cc \
|
||||
pyaInternal.cc \
|
||||
pyaCallables.cc \
|
||||
pyaMarshal.cc \
|
||||
pyaObject.cc \
|
||||
pyaRefs.cc \
|
||||
pyaUtils.cc \
|
||||
pyaModule.cc \
|
||||
pyaSignalHandler.cc \
|
||||
pyaStatusChangedListener.cc
|
||||
pyaStatusChangedListener.cc \
|
||||
gsiDeclPya.cc
|
||||
|
||||
HEADERS += \
|
||||
pya.h \
|
||||
|
|
@ -25,6 +28,8 @@ HEADERS += \
|
|||
pyaConvert.h \
|
||||
pyaHelpers.h \
|
||||
pyaInspector.h \
|
||||
pyaInternal.h \
|
||||
pyaCallables.h \
|
||||
pyaMarshal.h \
|
||||
pyaObject.h \
|
||||
pyaRefs.h \
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace pya
|
|||
// MethodTableEntry implementation
|
||||
|
||||
MethodTableEntry::MethodTableEntry (const std::string &name, bool st, bool prot)
|
||||
: m_name (name), m_is_static (st), m_is_protected (prot), m_is_enabled (true)
|
||||
: m_name (name), m_is_static (st), m_is_protected (prot), m_is_enabled (true), m_is_init (false)
|
||||
{ }
|
||||
|
||||
const std::string &
|
||||
|
|
@ -62,6 +62,18 @@ MethodTableEntry::is_enabled () const
|
|||
return m_is_enabled;
|
||||
}
|
||||
|
||||
void
|
||||
MethodTableEntry::set_init (bool f)
|
||||
{
|
||||
m_is_init = f;
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTableEntry::is_init () const
|
||||
{
|
||||
return m_is_init;
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTableEntry::is_static () const
|
||||
{
|
||||
|
|
@ -139,16 +151,28 @@ MethodTable::MethodTable (const gsi::ClassBase *cls_decl, PythonModule *module)
|
|||
|
||||
// then add normal methods - on name clash with properties make them a getter
|
||||
for (gsi::ClassBase::method_iterator m = cls_decl->begin_methods (); m != cls_decl->end_methods (); ++m) {
|
||||
|
||||
if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
|
||||
|
||||
bool st = (*m)->is_static ();
|
||||
|
||||
for (gsi::MethodBase::synonym_iterator syn = (*m)->begin_synonyms (); syn != (*m)->end_synonyms (); ++syn) {
|
||||
if (! syn->is_getter && ! syn->is_setter) {
|
||||
if ((*m)->end_arguments () - (*m)->begin_arguments () == 0 && find_property ((*m)->is_static (), syn->name).first) {
|
||||
if ((*m)->end_arguments () - (*m)->begin_arguments () == 0 && is_property_setter (st, syn->name) && ! is_property_getter (st, syn->name)) {
|
||||
add_getter (syn->name, *m);
|
||||
} else {
|
||||
if (syn->is_predicate && std::string (syn->name, 0, 3) == "is_") {
|
||||
std::string n = std::string (syn->name, 3, std::string::npos);
|
||||
if (is_property_setter (st, n) && ! is_property_getter (st, n)) {
|
||||
// synthesize a getter from is_...? predicates (e.g. is_empty? -> empty getter)
|
||||
add_getter (n, *m);
|
||||
}
|
||||
}
|
||||
add_method (syn->name, *m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -199,6 +223,26 @@ MethodTable::find_property (bool st, const std::string &name) const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_property_setter (bool st, const std::string &name)
|
||||
{
|
||||
std::pair<bool, size_t> p = find_property (st, name);
|
||||
if (! p.first) {
|
||||
return false;
|
||||
}
|
||||
return (begin_setters (p.second) != end_setters (p.second));
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_property_getter (bool st, const std::string &name)
|
||||
{
|
||||
std::pair<bool, size_t> p = find_property (st, name);
|
||||
if (! p.first) {
|
||||
return false;
|
||||
}
|
||||
return (begin_getters (p.second) != end_getters (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts the Python name from a generic name
|
||||
*
|
||||
|
|
@ -324,7 +368,14 @@ static std::string extract_python_name (const std::string &name)
|
|||
void
|
||||
MethodTable::add_method (const std::string &name, const gsi::MethodBase *mb)
|
||||
{
|
||||
if (name == "to_s" && mb->compatible_with_num_args (0)) {
|
||||
if (name == "new" && mb->ret_type ().type () == gsi::T_object && mb->ret_type ().pass_obj ()) {
|
||||
|
||||
add_method_basic (name, mb);
|
||||
|
||||
add_method_basic ("__init__", mb, true /*enabled*/, true /*constructor*/);
|
||||
mp_module->add_python_doc (mb, tl::to_string (tr ("This method is the default initializer of the object")));
|
||||
|
||||
} else if (name == "to_s" && mb->compatible_with_num_args (0)) {
|
||||
|
||||
add_method_basic (name, mb);
|
||||
|
||||
|
|
@ -473,6 +524,18 @@ MethodTable::set_enabled (size_t mid, bool en)
|
|||
m_table [mid - m_method_offset].set_enabled (en);
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_init(size_t mid) const
|
||||
{
|
||||
return m_table [mid - m_method_offset].is_init ();
|
||||
}
|
||||
|
||||
void
|
||||
MethodTable::set_init (size_t mid, bool f)
|
||||
{
|
||||
m_table [mid - m_method_offset].set_init (f);
|
||||
}
|
||||
|
||||
bool
|
||||
MethodTable::is_static (size_t mid) const
|
||||
{
|
||||
|
|
@ -561,9 +624,9 @@ MethodTable::finish ()
|
|||
}
|
||||
|
||||
void
|
||||
MethodTable::add_method_basic (const std::string &name, const gsi::MethodBase *mb, bool enabled)
|
||||
MethodTable::add_method_basic (const std::string &name, const gsi::MethodBase *mb, bool enabled, bool init)
|
||||
{
|
||||
bool st = mb->is_static ();
|
||||
bool st = mb->is_static () && ! init;
|
||||
|
||||
std::map<std::pair<bool, std::string>, size_t>::iterator n = m_name_map.find (std::make_pair (st, name));
|
||||
if (n == m_name_map.end ()) {
|
||||
|
|
@ -573,6 +636,9 @@ MethodTable::add_method_basic (const std::string &name, const gsi::MethodBase *m
|
|||
if (! enabled) {
|
||||
m_table.back ().set_enabled (false);
|
||||
}
|
||||
if (init) {
|
||||
m_table.back ().set_init (true);
|
||||
}
|
||||
m_table.back ().add (mb);
|
||||
|
||||
} else {
|
||||
|
|
@ -585,6 +651,9 @@ MethodTable::add_method_basic (const std::string &name, const gsi::MethodBase *m
|
|||
if (! enabled) {
|
||||
m_table [n->second].set_enabled (false);
|
||||
}
|
||||
if (init) {
|
||||
tl_assert (m_table [n->second].is_init ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -627,167 +696,5 @@ PythonClassClientData::initialize (const gsi::ClassBase &cls_decl, PyTypeObject
|
|||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// The PythonModule implementation
|
||||
|
||||
std::map<const gsi::MethodBase *, std::string> PythonModule::m_python_doc;
|
||||
std::vector<const gsi::ClassBase *> PythonModule::m_classes;
|
||||
|
||||
const std::string pymod_name ("klayout");
|
||||
|
||||
PythonModule::PythonModule ()
|
||||
: mp_mod_def (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PythonModule::~PythonModule ()
|
||||
{
|
||||
PYAObjectBase::clear_callbacks_cache ();
|
||||
|
||||
// the Python objects were probably deleted by Python itself as it exited -
|
||||
// don't try to delete them again.
|
||||
mp_module.release ();
|
||||
|
||||
while (!m_methods_heap.empty ()) {
|
||||
delete m_methods_heap.back ();
|
||||
m_methods_heap.pop_back ();
|
||||
}
|
||||
|
||||
while (!m_getseters_heap.empty ()) {
|
||||
delete m_getseters_heap.back ();
|
||||
m_getseters_heap.pop_back ();
|
||||
}
|
||||
|
||||
if (mp_mod_def) {
|
||||
delete[] mp_mod_def;
|
||||
mp_mod_def = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PythonModule::module ()
|
||||
{
|
||||
return mp_module.get ();
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PythonModule::take_module ()
|
||||
{
|
||||
return mp_module.release ();
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::init (const char *mod_name, const char *description)
|
||||
{
|
||||
// create a (standalone) Python interpreter if we don't have one yet
|
||||
// NOTE: Python itself will take care to remove this instance in this case.
|
||||
if (! pya::PythonInterpreter::instance ()) {
|
||||
new pya::PythonInterpreter (false);
|
||||
}
|
||||
|
||||
// do some checks before we create the module
|
||||
tl_assert (mod_name != 0);
|
||||
tl_assert (mp_module.get () == 0);
|
||||
|
||||
m_mod_name = pymod_name + "." + mod_name;
|
||||
m_mod_description = description;
|
||||
|
||||
PyObject *module = 0;
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{NULL} // Sentinel
|
||||
};
|
||||
|
||||
module = Py_InitModule3 (m_mod_name.c_str (), module_methods, m_mod_description.c_str ());
|
||||
|
||||
#else
|
||||
|
||||
struct PyModuleDef mod_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
m_mod_name.c_str (),
|
||||
NULL, // module documentation
|
||||
-1, // size of per-interpreter state of the module,
|
||||
// if the module keeps state in global variables.
|
||||
NULL
|
||||
};
|
||||
|
||||
tl_assert (! mp_mod_def);
|
||||
|
||||
// prepare a persistent structure with the module definition
|
||||
// and pass this one to PyModule_Create
|
||||
mp_mod_def = new char[sizeof (PyModuleDef)];
|
||||
memcpy ((void *) mp_mod_def, (const void *) &mod_def, sizeof (PyModuleDef));
|
||||
|
||||
module = PyModule_Create ((PyModuleDef *) mp_mod_def);
|
||||
|
||||
#endif
|
||||
|
||||
mp_module = PythonRef (module);
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::init (const char *mod_name, PyObject *module)
|
||||
{
|
||||
// do some checks before we create the module
|
||||
tl_assert (mp_module.get () == 0);
|
||||
|
||||
m_mod_name = mod_name;
|
||||
mp_module = PythonRef (module);
|
||||
}
|
||||
|
||||
PyMethodDef *
|
||||
PythonModule::make_method_def ()
|
||||
{
|
||||
static PyMethodDef md = { };
|
||||
m_methods_heap.push_back (new PyMethodDef (md));
|
||||
return m_methods_heap.back ();
|
||||
}
|
||||
|
||||
PyGetSetDef *
|
||||
PythonModule::make_getset_def ()
|
||||
{
|
||||
static PyGetSetDef gsd = { };
|
||||
m_getseters_heap.push_back (new PyGetSetDef (gsd));
|
||||
return m_getseters_heap.back ();
|
||||
}
|
||||
|
||||
char *
|
||||
PythonModule::make_string (const std::string &s)
|
||||
{
|
||||
m_string_heap.push_back (s);
|
||||
return const_cast<char *> (m_string_heap.back ().c_str ());
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::add_python_doc (const gsi::ClassBase & /*cls*/, const MethodTable *mt, int mid, const std::string &doc)
|
||||
{
|
||||
for (MethodTableEntry::method_iterator m = mt->begin (mid); m != mt->end (mid); ++m) {
|
||||
std::string &doc_string = m_python_doc [*m];
|
||||
doc_string += doc;
|
||||
doc_string += "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PythonModule::add_python_doc (const gsi::MethodBase *m, const std::string &doc)
|
||||
{
|
||||
m_python_doc [m] += doc;
|
||||
}
|
||||
|
||||
std::string
|
||||
PythonModule::python_doc (const gsi::MethodBase *method)
|
||||
{
|
||||
std::map<const gsi::MethodBase *, std::string>::const_iterator d = m_python_doc.find (method);
|
||||
if (d != m_python_doc.end ()) {
|
||||
return d->second;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,10 @@ public:
|
|||
void set_enabled (bool en);
|
||||
bool is_enabled () const;
|
||||
|
||||
bool is_static () const;
|
||||
void set_init(bool f);
|
||||
bool is_init () const;
|
||||
|
||||
bool is_static () const;
|
||||
bool is_protected () const;
|
||||
|
||||
void add (const gsi::MethodBase *m);
|
||||
|
|
@ -78,11 +80,17 @@ public:
|
|||
method_iterator begin () const;
|
||||
method_iterator end () const;
|
||||
|
||||
const std::vector<const gsi::MethodBase *> &methods () const
|
||||
{
|
||||
return m_methods;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
bool m_is_static : 1;
|
||||
bool m_is_protected : 1;
|
||||
bool m_is_enabled : 1;
|
||||
bool m_is_init : 1;
|
||||
std::vector<const gsi::MethodBase *> m_methods;
|
||||
};
|
||||
|
||||
|
|
@ -161,6 +169,16 @@ public:
|
|||
*/
|
||||
void set_enabled (size_t mid, bool en);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the method is an initializer
|
||||
*/
|
||||
bool is_init (size_t mid) const;
|
||||
|
||||
/**
|
||||
* @brief Sets initializer
|
||||
*/
|
||||
void set_init (size_t mid, bool f);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the method with the given ID is static
|
||||
*/
|
||||
|
|
@ -228,6 +246,22 @@ public:
|
|||
*/
|
||||
static MethodTable *method_table_by_class (const gsi::ClassBase *cls_decl);
|
||||
|
||||
/**
|
||||
* @brief Gets the method table
|
||||
*/
|
||||
const std::vector<MethodTableEntry> &method_table () const
|
||||
{
|
||||
return m_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the property table
|
||||
*/
|
||||
const std::vector<std::pair<MethodTableEntry, MethodTableEntry> > &property_table () const
|
||||
{
|
||||
return m_property_table;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_method_offset;
|
||||
size_t m_property_offset;
|
||||
|
|
@ -238,7 +272,9 @@ private:
|
|||
std::vector<std::pair<MethodTableEntry, MethodTableEntry> > m_property_table;
|
||||
PythonModule *mp_module;
|
||||
|
||||
void add_method_basic (const std::string &name, const gsi::MethodBase *mb, bool enabled = true);
|
||||
void add_method_basic (const std::string &name, const gsi::MethodBase *mb, bool enabled = true, bool init = false);
|
||||
bool is_property_setter (bool st, const std::string &name);
|
||||
bool is_property_getter (bool st, const std::string &name);
|
||||
};
|
||||
|
||||
struct PythonClassClientData
|
||||
|
|
|
|||
|
|
@ -541,7 +541,11 @@ public:
|
|||
|
||||
PyMethodDef *method = mp_module->make_method_def ();
|
||||
method->ml_name = mp_module->make_string (name);
|
||||
method->ml_meth = (PyCFunction) get_method_adaptor (mid);
|
||||
if (mt->is_init (mid)) {
|
||||
method->ml_meth = (PyCFunction) get_method_init_adaptor (mid);
|
||||
} else {
|
||||
method->ml_meth = (PyCFunction) get_method_adaptor (mid);
|
||||
}
|
||||
method->ml_doc = mp_module->make_string (doc);
|
||||
method->ml_flags = METH_VARARGS;
|
||||
|
||||
|
|
@ -569,22 +573,6 @@ public:
|
|||
|
||||
} else if (! as_static) { // Class methods
|
||||
|
||||
if (m_first->ret_type ().type () == gsi::T_object && m_first->ret_type ().pass_obj () && name == "new") {
|
||||
|
||||
// The constructor is also routed via the pya_object_init implementation
|
||||
mp_module->add_python_doc (*cls, mt, int (mid), tl::to_string (tr ("This method is the default initializer of the object")));
|
||||
|
||||
PyMethodDef *method = mp_module->make_method_def ();
|
||||
method->ml_name = "__init__";
|
||||
method->ml_meth = (PyCFunction) get_method_init_adaptor (mid);
|
||||
method->ml_doc = mp_module->make_string (doc);
|
||||
method->ml_flags = METH_VARARGS;
|
||||
|
||||
PythonRef attr = PythonRef (PyDescr_NewMethod (type, method));
|
||||
set_type_attr (type, method->ml_name, attr);
|
||||
|
||||
}
|
||||
|
||||
PyMethodDef *method = mp_module->make_method_def ();
|
||||
method->ml_name = mp_module->make_string (name);
|
||||
method->ml_meth = (PyCFunction) get_method_adaptor (mid);
|
||||
|
|
|
|||
Loading…
Reference in New Issue