SIP4 python bindings generator for TQt
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sip4-tqt/sipgen/transform.c

3446 lines
90 KiB

/*
* The parse tree transformation module for SIP.
*
* Copyright (c) 2010 Riverbank Computing Limited <info@riverbankcomputing.com>
*
* This file is part of SIP.
*
* This copy of SIP is licensed for use under the terms of the SIP License
* Agreement. See the file LICENSE for more details.
*
* This copy of SIP may also used under the terms of the GNU General Public
* License v2 or v3 as published by the Free Software Foundation which can be
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
*
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "sip.h"
static int samePythonSignature(signatureDef *sd1, signatureDef *sd2);
static int nextSignificantArg(signatureDef *sd, int a);
static int sameArgType(argDef *a1, argDef *a2, int strict);
static int supportedType(classDef *,overDef *,argDef *,int);
static int sameOverload(overDef *od1, overDef *od2);
static int sameVirtualHandler(virtHandlerDef *vhd1,virtHandlerDef *vhd2);
static int isSubClass(classDef *cc,classDef *pc);
static void setAllImports(moduleDef *mod);
static void addUniqueModule(moduleDef *mod, moduleDef *imp);
static void ensureInput(classDef *,overDef *,argDef *);
static void defaultInput(argDef *);
static void defaultOutput(argDef *ad);
static void createSortedNumberedTypesTable(sipSpec *pt, moduleDef *mod);
static int compareTypes(const void *t1, const void *t2);
static void addAutoOverload(sipSpec *,classDef *,overDef *);
static void ifaceFileIsUsed(ifaceFileList **used, argDef *ad);
static void ifaceFilesAreUsedByOverload(ifaceFileList **used, overDef *od);
static void ifaceFilesAreUsedBySignature(ifaceFileList **used,
signatureDef *sd);
static void scopeDefaultValue(sipSpec *,classDef *,argDef *);
static void setHierarchy(sipSpec *,classDef *,classDef *,classList **);
static void transformModules(sipSpec *pt, moduleDef *mod);
static void transformCtors(sipSpec *,classDef *);
static void transformCasts(sipSpec *,classDef *);
static void addDefaultCopyCtor(classDef *);
static void transformScopeOverloads(sipSpec *pt, classDef *c_scope,
mappedTypeDef *mt_scope, overDef *overs);
static void transformVariableList(sipSpec *pt, moduleDef *mod);
static void transformMappedTypes(sipSpec *pt, moduleDef *mod);
static void getVisibleMembers(sipSpec *,classDef *);
static void getVirtuals(sipSpec *pt,classDef *cd);
static void getClassVirtuals(classDef *,classDef *);
static void transformTypedefs(sipSpec *pt, moduleDef *mod);
static void resolveMappedTypeTypes(sipSpec *,mappedTypeDef *);
static void resolveCtorTypes(sipSpec *,classDef *,ctorDef *);
static void resolveFuncTypes(sipSpec *pt, moduleDef *mod, classDef *c_scope,
mappedTypeDef *mt_scope, overDef *od);
static void resolvePySigTypes(sipSpec *,moduleDef *,classDef *,overDef *,signatureDef *,int);
static void resolveVariableType(sipSpec *,varDef *);
static void fatalNoDefinedType(scopedNameDef *);
static void getBaseType(sipSpec *,moduleDef *,classDef *,argDef *);
static void searchClassScope(sipSpec *,classDef *,scopedNameDef *,argDef *);
static void searchMappedTypes(sipSpec *,moduleDef *,scopedNameDef *,argDef *);
static void searchEnums(sipSpec *,scopedNameDef *,argDef *);
static void searchClasses(sipSpec *,moduleDef *mod,scopedNameDef *,argDef *);
static void appendToMRO(mroDef *,mroDef ***,classDef *);
static void moveMainModuleCastsSlots(sipSpec *pt, moduleDef *mod);
static void moveClassCasts(sipSpec *pt, moduleDef *mod, classDef *cd);
static void moveGlobalSlot(sipSpec *pt, moduleDef *mod, memberDef *gmd);
static classDef *findAltClassImplementation(sipSpec *pt, mappedTypeDef *mtd);
static void filterMainModuleVirtualHandlers(moduleDef *mod);
static void filterModuleVirtualHandlers(moduleDef *mod);
static ifaceFileDef *getIfaceFile(argDef *ad);
static mappedTypeDef *instantiateMappedTypeTemplate(sipSpec *pt, moduleDef *mod, mappedTypeTmplDef *mtt, argDef *type);
static classDef *getProxy(moduleDef *mod, classDef *cd);
static int generatingCodeForModule(sipSpec *pt, moduleDef *mod);
static void checkAssignmentHelper(sipSpec *pt, classDef *cd);
static void addComplementarySlots(sipSpec *pt, classDef *cd);
static void addComplementarySlot(sipSpec *pt, classDef *cd, memberDef *md,
slotType cslot, const char *cslot_name);
static void resolveInstantiatedClassTemplate(sipSpec *pt, argDef *type);
static void setStringPoolOffsets(sipSpec *pt);
static const char *templateString(const char *src, scopedNameDef *names,
scopedNameDef *values);
/*
* Transform the parse tree.
*/
void transform(sipSpec *pt)
{
moduleDef *mod;
classDef *cd, *rev, **tail;
classList *newl;
overDef *od;
/*
* The class list has the main module's classes at the front and the ones
* from the module at the most nested %Import at the end. This affects
* some of the following algorithms. We have to have consistency whenever
* a module is used. To achieve this we reverse the order of the classes.
*/
rev = NULL;
cd = pt -> classes;
while (cd != NULL)
{
classDef *next = cd -> next;
cd -> next = rev;
rev = cd;
/*
* Mark any TQObject class. This flag will ripple through all derived
* classes when we set the hierarchy.
*/
if (strcmp(classBaseName(cd), TQOBJECT_OBJECT_NAME_STRING) == 0)
setIsTQObjectSubClass(cd);
cd = next;
}
pt -> classes = rev;
/*
* Build the list of all imports for each module and check each has been
* named.
*/
for (mod = pt->modules; mod != NULL; mod = mod->next)
{
if (mod->name == NULL)
fatal("A module is missing a %%Module or %%CModule directive\n");
setAllImports(mod);
}
/*
* Set the default meta-type for the main module if it doesn't have one
* explicitly set.
*/
if (pt->module->defmetatype == NULL)
{
moduleListDef *mld;
for (mld = pt->module->allimports; mld != NULL; mld = mld->next)
{
if (mld->module->defmetatype == NULL)
continue;
if (pt->module->defmetatype == NULL)
pt->module->defmetatype = mld->module->defmetatype;
else if (pt->module->defmetatype != mld->module->defmetatype)
fatal("The %s module has imported different default meta-types %s and %s\n",
pt->module->fullname->text,
pt->module->defmetatype->text,
mld->module->defmetatype->text);
}
}
/* Check each class has been defined. */
for (cd = pt -> classes; cd != NULL; cd = cd -> next)
if (cd -> iff -> module == NULL)
{
fatalScopedName(classFTQCName(cd));
fatal(" has not been defined\n");
}
/*
* Set the super-class hierarchy for each class and re-order the list of
* classes so that no class appears before a super class or an enclosing
* scope class.
*/
newl = NULL;
for (cd = pt -> classes; cd != NULL; cd = cd -> next)
setHierarchy(pt,cd,cd,&newl);
/* Replace the old list with the new one. */
tail = &pt -> classes;
while (newl != NULL)
{
classList *cl = newl;
*tail = cl -> cd;
tail = &cl -> cd -> next;
newl = cl -> next;
free(cl);
}
*tail = NULL;
/* Transform the various types in the modules. */
if (isConsolidated(pt->module))
{
/* Transform the modules included by the consolidated module. */
for (mod = pt->modules->next; mod != NULL; mod = mod->next)
transformModules(pt, mod);
}
else
{
transformModules(pt, pt->modules);
}
/* Handle default ctors now that the argument types are resolved. */
if (!pt->genc)
for (cd = pt->classes; cd != NULL; cd = cd->next)
if (!noDefaultCtors(cd) && !isOpaque(cd) && cd->iff->type != namespace_iface)
addDefaultCopyCtor(cd);
/* Create the array of numbered types sorted by type name. */
for (mod = pt->modules; mod != NULL; mod = mod->next)
createSortedNumberedTypesTable(pt, mod);
/* Add any automatically generated methods. */
for (cd = pt -> classes; cd != NULL; cd = cd -> next)
for (od = cd -> overs; od != NULL; od = od -> next)
if (isAutoGen(od))
addAutoOverload(pt,cd,od);
/*
* Move casts and slots around to their correct classes (if in the same
* module) or create proxies for them (if cross-module).
*/
if (!pt->genc)
for (mod = pt->modules; mod != NULL; mod = mod->next)
if (generatingCodeForModule(pt, mod))
moveMainModuleCastsSlots(pt, mod);
/* Automatically generate missing complementary slots. */
if (!pt->genc)
{
for (cd = pt->classes; cd != NULL; cd = cd->next)
addComplementarySlots(pt, cd);
for (mod = pt->modules; mod != NULL; mod = mod->next)
if (generatingCodeForModule(pt, mod))
for (cd = mod->proxies; cd != NULL; cd = cd->next)
addComplementarySlots(pt, cd);
}
/* Generate the different class views. */
for (cd = pt->classes; cd != NULL; cd = cd->next)
if (cd->iff->type == class_iface)
{
/* Get the list of visible member functions. */
getVisibleMembers(pt, cd);
/* Get the virtual members. */
if (hasShadow(cd))
getVirtuals(pt, cd);
}
else if (cd->iff->type == namespace_iface)
for (od = cd->overs; od != NULL; od = od->next)
ifaceFilesAreUsedByOverload(&cd->iff->used, od);
/*
* Filter the virtuals of all component modules (if consolidated) or the
* main module (if not).
*/
for (mod = pt->modules; mod != NULL; mod = mod->next)
{
if (generatingCodeForModule(pt, mod))
{
filterMainModuleVirtualHandlers(mod);
for (od = mod->overs; od != NULL; od = od->next)
ifaceFilesAreUsedByOverload(&mod->used, od);
}
/* Update proxies with some information from the real classes. */
for (cd = mod->proxies; cd != NULL; cd = cd->next)
cd->iff->ifacenr = cd->real->iff->ifacenr;
}
/* Mark classes that can have an assignment helper. */
for (cd = pt->classes; cd != NULL; cd = cd->next)
checkAssignmentHelper(pt, cd);
setStringPoolOffsets(pt);
}
/*
* Transform a module and the modules it imports.
*/
static void transformModules(sipSpec *pt, moduleDef *mod)
{
classDef *cd;
moduleListDef *mld;
/* Handle the trivial case. */
if (isTransformed(mod))
return;
/*
* The modules on which this one depends must be done first because they
* might generate new template-based types and they must be defined in the
* right module.
*/
for (mld = mod->imports; mld != NULL; mld = mld->next)
transformModules(pt, mld->module);
/* Transform typedefs, variables and global functions. */
transformTypedefs(pt, mod);
transformVariableList(pt, mod);
transformScopeOverloads(pt, NULL, NULL, mod->overs);
/* Transform class ctors, functions and casts. */
for (cd = pt->classes; cd != NULL; cd = cd->next)
{
if (cd->iff->module == mod)
{
transformCtors(pt, cd);
if (!pt->genc)
{
transformScopeOverloads(pt, cd, NULL, cd->overs);
transformCasts(pt, cd);
}
}
}
/* Transform mapped types based on templates. */
transformMappedTypes(pt, mod);
setIsTransformed(mod);
}
/*
* Set the offset into the string pool for every used name.
*/
static void setStringPoolOffsets(sipSpec *pt)
{
nameDef *nd;
size_t offset = 0;
for (nd = pt->namecache; nd != NULL; nd = nd->next)
{
size_t len;
nameDef *prev;
if (!isUsedName(nd))
continue;
/* See if the tail of a previous used name could be used instead. */
len = nd->len;
for (prev = pt->namecache; prev->len > len; prev = prev->next)
{
size_t pos;
if (!isUsedName(prev) || isSubstring(prev))
continue;
pos = prev->len - len;
if (memcmp(&prev->text[pos], nd->text, len) == 0)
{
setIsSubstring(nd);
nd->offset = prev->offset + pos;
break;
}
}
if (!isSubstring(nd))
{
nd->offset = offset;
offset += len + 1;
}
}
}
/*
* Add any missing complementary slots to a class. This emulates the C++
* behaviour of automatically interpreting (for example) >= as !<.
*/
static void addComplementarySlots(sipSpec *pt, classDef *cd)
{
memberDef *md;
for (md = cd->members; md != NULL; md = md->next)
switch (md->slot)
{
case lt_slot:
addComplementarySlot(pt, cd, md, ge_slot, "__ge__");
break;
case le_slot:
addComplementarySlot(pt, cd, md, gt_slot, "__gt__");
break;
case gt_slot:
addComplementarySlot(pt, cd, md, le_slot, "__le__");
break;
case ge_slot:
addComplementarySlot(pt, cd, md, lt_slot, "__lt__");
break;
case eq_slot:
addComplementarySlot(pt, cd, md, ne_slot, "__ne__");
break;
case ne_slot:
addComplementarySlot(pt, cd, md, eq_slot, "__eq__");
break;
}
}
/*
* Add a complementary slot if it is missing.
*/
static void addComplementarySlot(sipSpec *pt, classDef *cd, memberDef *md,
slotType cslot, const char *cslot_name)
{
overDef *od1;
memberDef *md2 = NULL;
for (od1 = cd->overs; od1 != NULL; od1 = od1->next)
{
overDef *od2;
if (od1->common != md || isComplementary(od1) || od1->methodcode != NULL)
continue;
/* Try and find an existing complementary slot. */
for (od2 = cd->overs; od2 != NULL; od2 = od2->next)
if (od2->common->slot == cslot && sameSignature(&od1->pysig, &od2->pysig, TRUE))
break;
/*
* If there is an explicit complementary slot then there is nothing to
* do.
*/
if (od2 != NULL)
continue;
/* Create a new member if needed. */
if (md2 == NULL)
{
for (md2 = cd->members; md2 != NULL; md2 = md2->next)
if (md2->slot == cslot)
break;
if (md2 == NULL)
{
md2 = sipMalloc(sizeof (memberDef));
md2->pyname = cacheName(pt, cslot_name);
md2->memberflags = md->memberflags;
md2->slot = cslot;
md2->module = md->module;
md2->next = cd->members;
cd->members = md2;
if (isUsedName(md->pyname))
setIsUsedName(md2->pyname);
}
}
/* Create the complementary slot. */
od2 = sipMalloc(sizeof (overDef));
*od2 = *od1;
resetIsVirtual(od2);
setIsComplementary(od2);
od2->common = md2;
od2->next = cd->overs;
cd->overs = od2;
}
}
/*
* See if a class supports an assignment helper.
*/
static void checkAssignmentHelper(sipSpec *pt, classDef *cd)
{
int pub_def_ctor, pub_copy_ctor;
ctorDef *ct;
/*
* We register types with TQt if the class is not abstract, doesn't have a
* private assignment operator, has a public default ctor, a public copy
* ctor and a public dtor.
*/
if (isAbstractClass(cd))
return;
if (cannotAssign(cd))
return;
if (!isPublicDtor(cd))
return;
pub_def_ctor = pub_copy_ctor = FALSE;
for (ct = cd->ctors; ct != NULL; ct = ct->next)
{
if (ct->cppsig == NULL || !isPublicCtor(ct))
continue;
if (ct->cppsig->nrArgs == 0 || ct->cppsig->args[0].defval != NULL)
{
/*
* The ctor either has no arguments or all arguments have defaults.
*/
pub_def_ctor = TRUE;
}
else if (ct->cppsig->nrArgs == 1)
{
argDef *ad = &ct->cppsig->args[0];
classDef *arg_cd;
if (ad->atype == class_type)
arg_cd = ad->u.cd;
else if (ad->atype == mapped_type)
arg_cd = findAltClassImplementation(pt, ad->u.mtd);
else
arg_cd = NULL;
if (arg_cd == cd && isReference(ad) && isConstArg(ad) &&
ad->nrderefs == 0 && ad->defval == NULL)
pub_copy_ctor = TRUE;
}
}
if (pub_def_ctor && pub_copy_ctor)
{
setAssignmentHelper(cd);
addToUsedList(&cd->iff->module->used, cd->iff);
}
}
/*
* Set the list of all imports for a module. The list is ordered so that a
* module appears before any module that imports it.
*/
static void setAllImports(moduleDef *mod)
{
moduleListDef *mld;
/*
* Handle the trivial case where there are no imports, or the list has
* already been done.
*/
if (mod->imports == NULL || mod->allimports != NULL)
return;
/* Make sure all the direct imports are done first. */
for (mld = mod->imports; mld != NULL; mld = mld->next)
setAllImports(mld->module);
/*
* Now build the list from our direct imports lists but ignoring
* duplicates.
*/
for (mld = mod->imports; mld != NULL; mld = mld->next)
{
moduleListDef *amld;
for (amld = mld->module->allimports; amld != NULL; amld = amld->next)
addUniqueModule(mod, amld->module);
addUniqueModule(mod, mld->module);
}
}
/*
* Append a module to the list of all imported modules if it isn't already
* there.
*/
static void addUniqueModule(moduleDef *mod, moduleDef *imp)
{
moduleListDef **tail;
for (tail = &mod->allimports; *tail != NULL; tail = &(*tail)->next)
if ((*tail)->module == imp)
return;
*tail = sipMalloc(sizeof (moduleListDef));
(*tail)->module = imp;
(*tail)->next = NULL;
}
/*
* Move the casts and slots to the correct place for a main module (ie. one we
* are generating code for).
*/
static void moveMainModuleCastsSlots(sipSpec *pt, moduleDef *mod)
{
classDef *cd;
memberDef *md;
for (cd = pt->classes; cd != NULL; cd = cd->next)
if (cd->iff->module == mod)
moveClassCasts(pt, mod, cd);
for (md = mod->othfuncs; md != NULL; md = md->next)
if (md->slot != no_slot && md->module == mod)
moveGlobalSlot(pt, mod, md);
}
/*
* Move any class casts to its correct class, or publish as a ctor extender.
*/
static void moveClassCasts(sipSpec *pt, moduleDef *mod, classDef *cd)
{
argList *al;
for (al = cd->casts; al != NULL; al = al->next)
{
classDef *dcd = al->arg.u.cd;
ctorDef *ct, **ctp;
argDef *ad;
if (al->arg.atype == class_type)
dcd = al->arg.u.cd;
else
/* Previous error checking means this will always work. */
dcd = findAltClassImplementation(pt, al->arg.u.mtd);
/*
* If the destination class is in a different module then use
* a proxy.
*/
if (dcd->iff->module != mod)
dcd = getProxy(mod, dcd);
/* Create the new ctor. */
ct = sipMalloc(sizeof (ctorDef));
ct->ctorflags = SECT_IS_PUBLIC | CTOR_CAST;
ct->cppsig = &ct->pysig;
/* Add the source class as the only argument. */
ct->pysig.result.atype = void_type;
ad = &ct->pysig.args[0];
ad->atype = class_type;
ad->name = NULL;
ad->argflags = ARG_IN | (al->arg.argflags & (ARG_IS_REF | ARG_IS_CONST));
ad->nrderefs = al->arg.nrderefs;
ad->defval = NULL;
ad->u.cd = cd;
ifaceFileIsUsed(&dcd->iff->used, ad);
ct->pysig.nrArgs = 1;
/* Append it to the list. */
for (ctp = &dcd->ctors; *ctp != NULL; ctp = &(*ctp)->next)
if (sameSignature(&(*ctp)->pysig, &ct->pysig, FALSE))
{
fatal("operator ");
fatalScopedName(classFTQCName(dcd));
fatal("::");
fatalScopedName(classFTQCName(dcd));
fatal("(");
fatalScopedName(classFTQCName(cd));
fatal(") already defined\n");
}
*ctp = ct;
}
}
/*
* If possible, move a global slot to its correct class.
*/
static void moveGlobalSlot(sipSpec *pt, moduleDef *mod, memberDef *gmd)
{
overDef **odp = &mod->overs, *od;
while ((od = *odp) != NULL)
{
int second;
argDef *arg0, *arg1;
memberDef *md, **mdhead;
overDef **odhead;
moduleDef *mod;
nameDef *nd;
if (od->common != gmd)
{
odp = &od->next;
continue;
}
/*
* We know that the slot has the right number of arguments, but the
* first or second one needs to be a class or enum defined in the same
* module. Otherwise we leave it as it is and publish it as a slot
* extender.
*/
arg0 = &od->pysig.args[0];
arg1 = &od->pysig.args[1];
mdhead = NULL;
second = FALSE;
nd = NULL;
if (arg0->atype == class_type)
{
mdhead = &arg0->u.cd->members;
odhead = &arg0->u.cd->overs;
mod = arg0->u.cd->iff->module;
}
else if (arg0->atype == mapped_type)
{
classDef *cd = findAltClassImplementation(pt, arg0->u.mtd);
if (cd != NULL)
{
mdhead = &cd->members;
odhead = &cd->overs;
mod = cd->iff->module;
}
}
else if (arg0->atype == enum_type)
{
mdhead = &arg0->u.ed->slots;
odhead = &arg0->u.ed->overs;
mod = arg0->u.ed->module;
nd = arg0->u.ed->pyname;
}
else if (arg1->atype == class_type)
{
mdhead = &arg1->u.cd->members;
odhead = &arg1->u.cd->overs;
mod = arg1->u.cd->iff->module;
second = TRUE;
}
else if (arg1->atype == mapped_type)
{
classDef *cd = findAltClassImplementation(pt, arg1->u.mtd);
if (cd != NULL)
{
mdhead = &cd->members;
odhead = &cd->overs;
mod = cd->iff->module;
second = TRUE;
}
}
else if (arg1->atype == enum_type)
{
mdhead = &arg1->u.ed->slots;
odhead = &arg1->u.ed->overs;
mod = arg1->u.ed->module;
nd = arg1->u.ed->pyname;
second = TRUE;
}
if (mdhead == NULL)
{
fatal("One of the arguments of ");
prOverloadName(stderr, od);
fatal(" must be a class or enum\n");
}
/*
* For rich comparisons the first argument must be a class or an enum.
* For cross-module slots then it may only be a class. (This latter
* limitation is artificial, but is unlikely to be a problem in
* practice.)
*/
if (isRichCompareSlot(gmd))
{
if (second)
{
fatal("The first argument of ");
prOverloadName(stderr, od);
fatal(" must be a class or enum\n");
}
if (mod != gmd->module && arg0->atype == enum_type)
{
fatal("The first argument of ");
prOverloadName(stderr, od);
fatal(" must be a class\n");
}
}
if (mod != gmd->module)
{
if (isRichCompareSlot(gmd))
{
classDef *pcd = getProxy(mod, arg0->u.cd);
memberDef *pmd;
overDef *pod;
/* Create a new proxy member if needed. */
for (pmd = pcd->members; pmd != NULL; pmd = pmd->next)
if (pmd->slot == gmd->slot)
break;
if (pmd == NULL)
{
pmd = sipMalloc(sizeof (memberDef));
pmd->pyname = gmd->pyname;
pmd->memberflags = 0;
pmd->slot = gmd->slot;
pmd->module = mod;
pmd->next = pcd->members;
pcd->members = pmd;
}
/* Add the proxy overload. */
pod = sipMalloc(sizeof (overDef));
*pod = *od;
pod->common = pmd;
pod->next = pcd->overs;
pcd->overs = pod;
/* Remove the first argument. */
pod->pysig.args[0] = pod->pysig.args[1];
pod->pysig.nrArgs = 1;
/* Remove from the list. */
*odp = od->next;
}
else
odp = &od->next;
continue;
}
/* Remove from the list. */
*odp = od->next;
/* The only time we need the name of an enum is when it has slots. */
if (nd != NULL)
setIsUsedName(nd);
/* See if there is already a member or create a new one. */
for (md = *mdhead; md != NULL; md = md->next)
if (md->slot == gmd->slot)
break;
if (md == NULL)
{
md = sipMalloc(sizeof (memberDef));
*md = *gmd;
md->module = mod;
md->next = *mdhead;
*mdhead = md;
}
/* Move the overload to the end of the destination list. */
setIsPublic(od);
setIsGlobal(od);
od->common = md;
od->next = NULL;
while (*odhead != NULL)
odhead = &(*odhead)->next;
*odhead = od;
/* Remove the first argument of comparison operators. */
if (isRichCompareSlot(md))
{
/* Remember if the argument was a pointer. */
if (arg0->nrderefs > 0)
setDontDerefSelf(od);
*arg0 = *arg1;
od->pysig.nrArgs = 1;
}
}
}
/*
* Return an alternative class implementation of a mapped type if there is
* one. Note that we cheat as we assume there is one going to be one (as
* there will be in PyTQt at the moment).
*/
static classDef *findAltClassImplementation(sipSpec *pt, mappedTypeDef *mtd)
{
ifaceFileDef *iff = mtd->iff->first_alt;
while (iff != NULL)
{
if (iff->type == class_iface)
{
classDef *cd;
for (cd = pt->classes; cd != NULL; cd = cd->next)
if (cd->iff == iff)
return cd;
}
iff = iff->next_alt;
}
return NULL;
}
/*
* Create a proxy for a class if it doesn't already exist. Proxies are used as
* containers for cross-module extenders.
*/
static classDef *getProxy(moduleDef *mod, classDef *cd)
{
classDef *pcd;
for (pcd = mod->proxies; pcd != NULL; pcd = pcd->next)
if (pcd->iff == cd->iff)
return pcd;
pcd = sipMalloc(sizeof (classDef));
pcd->pyname = cd->pyname;
pcd->iff = cd->iff;
pcd->ecd = cd->ecd;
pcd->real = cd;
pcd->supers = cd->supers;
pcd->mro = cd->mro;
pcd->next = mod->proxies;
mod->proxies = pcd;
return pcd;
}
/*
* Filter the virtual handlers for a main module (ie. one we are generating
* code for.
*/
static void filterMainModuleVirtualHandlers(moduleDef *mod)
{
moduleListDef *mld;
virtHandlerDef *vhd;
/*
* Remove redundant virtual handlers. It's important that earlier, ie.
* those at the deepest level of %Import, are done first.
*/
for (mld = mod->allimports; mld != NULL; mld = mld->next)
filterModuleVirtualHandlers(mld->module);
filterModuleVirtualHandlers(mod);
/*
* Make sure we have the interface files for all types from other modules
* that are used in virtual handlers implemented in this module.
*/
for (vhd = mod->virthandlers; vhd != NULL; vhd = vhd->next)
if (!isDuplicateVH(vhd))
ifaceFilesAreUsedBySignature(&mod->used, vhd->cppsig);
}
/*
* Go through the virtual handlers filtering those that can duplicate earlier
* ones. Make sure each virtual is numbered within its module, and according
* to their position in the list (ignoring duplicates).
*/
static void filterModuleVirtualHandlers(moduleDef *mod)
{
virtHandlerDef *vhd;
/* See if it has already been done for this module. */
if (mod->nrvirthandlers >= 0)
return;
mod->nrvirthandlers = 0;
for (vhd = mod->virthandlers; vhd != NULL; vhd = vhd->next)
{
virtHandlerDef *best, *best_thismod, *hd;
best = best_thismod = NULL;
/*
* If this has handwritten code then we will want to use it.
* Otherwise, look for a handler in earlier modules.
*/
if (vhd->virtcode == NULL)
{
moduleListDef *mld;
for (mld = mod->allimports; mld != NULL && mld->module != mod; mld = mld->next)
{
for (hd = mld->module->virthandlers; hd != NULL; hd = hd->next)
if (sameVirtualHandler(vhd, hd))
{
best = hd;
break;
}
/*
* No need to check later modules as this will either be the
* right one, or a duplicate of the right one.
*/
if (best != NULL)
break;
}
}
/*
* Find the best candidate in this module in case we want to give it
* our handwritten code.
*/
for (hd = mod->virthandlers; hd != vhd; hd = hd->next)
if (sameVirtualHandler(vhd, hd))
{
best_thismod = hd;
break;
}
/*
* We don't use this one if it doesn't have virtual code and there is
* an alternative, or if it does have virtual code and there is already
* an alternative in the same module which doesn't have virtual code.
*/
if ((vhd->virtcode == NULL && (best != NULL || best_thismod != NULL)) ||
(vhd->virtcode != NULL && best_thismod != NULL && best_thismod->virtcode == NULL))
{
virtHandlerDef *saved;
/*
* If the alternative is in the same module and we have virtual
* code then give it to the alternative. Note that there is a bug
* here. If there are three handlers, the first without code and
* the second and third with code then which code is transfered to
* the first is down to luck. We should really only transfer code
* to methods that are known to be re-implementations - just having
* the same signature isn't enough.
*/
if (best_thismod != NULL)
{
if (best_thismod->virtcode == NULL && vhd->virtcode != NULL)
{
best_thismod->virtcode = vhd->virtcode;
resetIsDuplicateVH(best_thismod);
}
best = best_thismod;