diff options
Diffstat (limited to 'python/sip/sipgen/transform.c')
-rw-r--r-- | python/sip/sipgen/transform.c | 2856 |
1 files changed, 0 insertions, 2856 deletions
diff --git a/python/sip/sipgen/transform.c b/python/sip/sipgen/transform.c deleted file mode 100644 index d19fb719..00000000 --- a/python/sip/sipgen/transform.c +++ /dev/null @@ -1,2856 +0,0 @@ -/* - * The parse tree transformation module for SIP. - * - * Copyright (c) 2007 - * Riverbank Computing Limited <[email protected]> - * - * 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. - * - * 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(sipSpec *pt, moduleDef *mod); -static void addUniqueModule(moduleDef *mod, moduleDef *imp); -static void ensureInput(classDef *,overDef *,argDef *); -static void defaultInput(argDef *); -static void defaultOutput(classDef *,overDef *,argDef *); -static void assignClassNrs(sipSpec *,moduleDef *,nodeDef *); -static void assignEnumNrs(sipSpec *pt); -static void positionClass(classDef *); -static void addNodeToParent(nodeDef *,classDef *); -static void addAutoOverload(sipSpec *,classDef *,overDef *); -static void ifaceFileIsUsed(sipSpec *, ifaceFileDef *, argDef *); -static void ifaceFilesAreUsed(sipSpec *, ifaceFileDef *, overDef *); -static void ifaceFilesAreUsedByMethod(sipSpec *, classDef *, memberDef *); -static void ifaceFilesAreUsedFromOther(sipSpec *pt, signatureDef *sd); -static void scopeDefaultValue(sipSpec *,classDef *,argDef *); -static void setHierarchy(sipSpec *,classDef *,classDef *,classList **); -static void transformCtors(sipSpec *,classDef *); -static void transformCasts(sipSpec *,classDef *); -static void addDefaultCopyCtor(classDef *); -static void transformOverloads(sipSpec *,classDef *,overDef *); -static void transformVariableList(sipSpec *); -static void transformMappedTypes(sipSpec *); -static void getVisibleMembers(sipSpec *,classDef *); -static void getVirtuals(sipSpec *pt,classDef *cd); -static void getClassVirtuals(classDef *,classDef *); -static void transformTypedefs(sipSpec *pt); -static void resolveMappedTypeTypes(sipSpec *,mappedTypeDef *); -static void resolveCtorTypes(sipSpec *,classDef *,ctorDef *); -static void resolveFuncTypes(sipSpec *,moduleDef *,classDef *,overDef *); -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 searchScope(sipSpec *,classDef *,scopedNameDef *,argDef *); -static void searchMappedTypes(sipSpec *,scopedNameDef *,argDef *); -static void searchTypedefs(sipSpec *,scopedNameDef *,argDef *); -static void searchEnums(sipSpec *,scopedNameDef *,argDef *); -static void searchClasses(sipSpec *,moduleDef *mod,scopedNameDef *,argDef *); -static void appendToMRO(mroDef *,mroDef ***,classDef *); -static void moveClassCasts(sipSpec *pt, classDef *cd); -static void moveGlobalSlot(sipSpec *pt, memberDef *gmd); -static void filterVirtualHandlers(moduleDef *mod); -static ifaceFileDef *getIfaceFile(argDef *ad); -static mappedTypeDef *instantiateMappedTypeTemplate(sipSpec *pt, moduleDef *mod, mappedTypeTmplDef *mtt, argDef *type); -static classDef *getProxy(sipSpec *pt, classDef *cd); - - -/* - * Transform the parse tree. - */ - -void transform(sipSpec *pt) -{ - moduleDef *mod; - moduleListDef *mld; - classDef *cd, *rev, **tail; - classList *newl; - overDef *od; - mappedTypeDef *mtd; - virtHandlerDef *vhd; - int nr; - - if (pt -> module -> name == NULL) - fatal("No %%Module has been specified for the module\n"); - - /* - * 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, eg. when assigning class - * numbers. 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") == 0) - setIsQObjectSubClass(cd); - - cd = next; - } - - pt -> classes = rev; - - /* Build the list of all imports for each module. */ - for (mod = pt->modules; mod != NULL; mod = mod->next) - setAllImports(pt, mod); - - /* Check each class has been defined. */ - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - if (cd -> iff -> module == NULL) - { - fatalScopedName(classFQCName(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 typedefs, variables and global functions. */ - transformTypedefs(pt); - transformVariableList(pt); - transformOverloads(pt,NULL,pt -> overs); - - /* Transform class ctors, functions and casts. */ - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - { - transformCtors(pt,cd); - - if (!pt -> genc) - { - transformOverloads(pt,cd,cd -> overs); - transformCasts(pt, cd); - } - } - - /* Transform mapped types based on templates. */ - transformMappedTypes(pt); - - /* 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); - - /* - * Go through each class and add it to it's defining module's tree of - * classes. The tree reflects the namespace hierarchy. - */ - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - addNodeToParent(&cd -> iff -> module -> root,cd); - - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - positionClass(cd); - - /* Assign module specific class numbers for all modules. */ - for (mod = pt->modules; mod != NULL; mod = mod->next) - assignClassNrs(pt, mod, &mod->root); - - /* Assign module specific enum numbers for all enums. */ - assignEnumNrs(pt); - - /* 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); - - /* Allocate mapped types numbers. */ - for (mtd = pt -> mappedtypes; mtd != NULL; mtd = mtd -> next) - mtd -> mappednr = mtd -> iff -> module -> nrmappedtypes++; - - /* - * 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) - { - memberDef *md; - - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - if (cd->iff->module == pt->module) - moveClassCasts(pt, cd); - - for (md = pt->othfuncs; md != NULL; md = md->next) - if (md->slot != no_slot && md->module == pt->module) - moveGlobalSlot(pt, md); - } - - /* Generate the different class views. */ - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - { - ifaceFileDef *iff = cd -> iff; - - if (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 (iff -> type == namespace_iface && iff -> module == pt -> module) - { - memberDef *md; - - for (md = cd -> members; md != NULL; md = md -> next) - ifaceFilesAreUsedByMethod(pt, cd, md); - } - } - - /* - * In case there are any global functions that need external interface - * files. - */ - for (od = pt -> overs; od != NULL; od = od -> next) - if (od->common->module == pt->module) - ifaceFilesAreUsedFromOther(pt, &od->pysig); - - /* - * Remove redundant virtual handlers. It's important that earlier, - * ie. those at the deepest level of %Import, are done first. - */ - nr = 0; - - for (mld = pt->module->allimports; mld != NULL; mld = mld->next) - { - mld->module->modulenr = nr++; - filterVirtualHandlers(mld->module); - } - - pt->module->modulenr = nr; - filterVirtualHandlers(pt->module); - - /* - * 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 = pt->module->virthandlers; vhd != NULL; vhd = vhd->next) - if (!isDuplicateVH(vhd)) - ifaceFilesAreUsedFromOther(pt, vhd->cppsig); - - /* Update proxies with some information from the real classes. */ - for (cd = pt->proxies; cd != NULL; cd = cd->next) - cd->classnr = cd->real->classnr; -} - - -/* - * 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(sipSpec *pt, 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(pt, 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 any class casts to its correct class, or publish as a ctor extender. - */ -static void moveClassCasts(sipSpec *pt, 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 the destination class is in a different module then use - * a proxy. - */ - if (dcd->iff->module != pt->module) - dcd = getProxy(pt, dcd); - - /* Create the new ctor. */ - ct = sipMalloc(sizeof (ctorDef)); - - ct->ctorflags = SECT_IS_PUBLIC | CTOR_CAST; - ct->cppsig = &ct->pysig; - ct->exceptions = NULL; - ct->methodcode = NULL; - ct->prehook = NULL; - ct->posthook = NULL; - ct->next = NULL; - - /* Add the source class as the only argument. */ - 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(pt, dcd->iff, 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(classFQCName(dcd)); - fatal("::"); - fatalScopedName(classFQCName(dcd)); - fatal("("); - fatalScopedName(classFQCName(cd)); - fatal(") already defined\n"); - } - - *ctp = ct; - } -} - - -/* - * If possible, move a global slot to its correct class. - */ -static void moveGlobalSlot(sipSpec *pt, memberDef *gmd) -{ - overDef **odp = &pt->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]; - - 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 == 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 == enum_type) - { - mdhead = &arg1->u.ed->slots; - odhead = &arg1->u.ed->overs; - mod = arg1->u.ed->module; - nd = arg1->u.ed->pyname; - second = TRUE; - } - else - { - 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(pt, 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. */ - setIsPublic(od); - od->common = md; - od->next = *odhead; - - *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; - } - } -} - - -/* - * Create a proxy for a class if it doesn't already exist. Proxies are used as - * containers for cross-module extenders. - */ -static classDef *getProxy(sipSpec *pt, classDef *cd) -{ - classDef *pcd; - - for (pcd = pt->proxies; pcd != NULL; pcd = pcd->next) - if (pcd->iff == cd->iff) - return pcd; - - pcd = sipMalloc(sizeof (classDef)); - - pcd->classflags = 0; - pcd->userflags = 0; - pcd->classnr = -1; - pcd->pyname = cd->pyname; - pcd->iff = cd->iff; - pcd->ecd = cd->ecd; - pcd->real = cd; - pcd->node = NULL; - pcd->supers = cd->supers; - pcd->mro = cd->mro; - pcd->td = NULL; - pcd->ctors = NULL; - pcd->defctor = NULL; - pcd->dealloccode = NULL; - pcd->dtorcode = NULL; - pcd->dtorexceptions = NULL; - pcd->members = NULL; - pcd->overs = NULL; - pcd->casts = NULL; - pcd->vmembers = NULL; - pcd->visible = NULL; - pcd->cppcode = NULL; - pcd->hdrcode = NULL; - pcd->convtosubcode = NULL; - pcd->subbase = NULL; - pcd->convtocode = NULL; - pcd->travcode = NULL; - pcd->clearcode = NULL; - pcd->readbufcode = NULL; - pcd->writebufcode = NULL; - pcd->segcountcode = NULL; - pcd->charbufcode = NULL; - pcd->next = pt->proxies; - - pt->proxies = pcd; - - return pcd; -} - - -/* - * 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 filterVirtualHandlers(moduleDef *mod) -{ - virtHandlerDef *vhd; - - 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; - } - - /* Use the better one in place of this one. */ - saved = vhd->next; - *vhd = *best; - setIsDuplicateVH(vhd); - vhd->next = saved; - } - else - vhd->virthandlernr = mod->nrvirthandlers++; - } -} - - -/* - * Add an overload that is automatically generated (typically by Qt's moc). - */ -static void addAutoOverload(sipSpec *pt,classDef *autocd,overDef *autood) -{ - classDef *cd; - - /* Find every class that has this one in its hierarchy. */ - - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - { - mroDef *mro; - - if (cd == autocd) - continue; - - for (mro = cd -> mro; mro != NULL; mro = mro -> next) - if (mro -> cd == autocd) - { - memberDef *md; - overDef *od; - - /* Another overload may already exist. */ - - for (md = cd -> members; md != NULL; md = md -> next) - if (md -> pyname == autood -> common -> pyname) - break; - - if (md == NULL) - { - md = sipMalloc(sizeof (memberDef)); - - md -> pyname = autood -> common -> pyname; - md -> memberflags = autood -> common -> memberflags; - md -> slot = autood -> common -> slot; - md -> module = cd -> iff -> module; - md -> next = cd -> members; - cd -> members = md; - } - - od = sipMalloc(sizeof (overDef)); - - *od = *autood; - od -> common = md; - od -> next = cd -> overs; - cd -> overs = od; - - resetIsAutoGen(od); - - if (cd -> iff -> module == pt -> module) - setIsUsedName(md -> pyname); - - break; - } - } -} - - -/* - * Set the complete hierarchy for a class. - */ -static void setHierarchy(sipSpec *pt,classDef *base,classDef *cd, - classList **head) -{ - mroDef **tailp = &cd -> mro; - - /* See if it has already been done. */ - if (cd -> mro != NULL) - return; - - if (cd -> ecd != NULL) - setHierarchy(pt,base,cd -> ecd,head); - - if (cd -> iff -> type == class_iface) - { - classList *cl; - - /* The first thing is itself. */ - appendToMRO(cd -> mro,&tailp,cd); - - if (cd -> convtosubcode != NULL) - cd -> subbase = cd; - - /* Now do it's superclasses. */ - for (cl = cd -> supers; cl != NULL; cl = cl -> next) - { - mroDef *mro; - - /* - * Make sure the super-class's hierarchy has been done. - */ - setHierarchy(pt,base,cl -> cd,head); - - /* Append the super-classes hierarchy. */ - for (mro = cl -> cd -> mro; mro != NULL; mro = mro -> next) - { - appendToMRO(cd -> mro,&tailp,mro -> cd); - - /* - * If the super-class is a TQObject sub-class then this one is - * as well. - */ - if (isQObjectSubClass(mro->cd)) - setIsQObjectSubClass(cd); - - /* - * If the super-class has a shadow then this one should have - * one as well. - */ - if (hasShadow(mro->cd)) - setHasShadow(cd); - - /* - * Ensure that the sub-class base class is the furthest up the - * hierarchy. - */ - if (mro->cd->subbase != NULL) - cd->subbase = mro->cd->subbase; - } - } - } - - /* - * We can't have a shadow if the specification is incomplete, there is - * a private dtor, there are no none-private ctors or there are private - * abstract methods. - */ - if (isIncomplete(cd) || isPrivateDtor(cd) || !canCreate(cd)) - resetHasShadow(cd); - else - { - overDef *od; - - /* - * Note that we should be able to provide better support for - * abstract private methods than we do at the moment. - */ - for (od = cd->overs; od != NULL; od = od->next) - if (isAbstract(od) && isPrivate(od)) - { - resetHasShadow(cd); - - /* - * It also means we cannot create an instance - * from Python. - */ - resetCanCreate(cd); - - break; - } - } - - /* Add it to the new list. */ - appendToClassList(head,cd); -} - - -/* - * Append a class definition to an mro list - */ -static void appendToMRO(mroDef *head,mroDef ***tailp,classDef *cd) -{ - mroDef *mro, *new; - - new = sipMalloc(sizeof (mroDef)); - - new -> cd = cd; - new -> mroflags = 0; - new -> next = NULL; - - /* See if it is a duplicate. */ - - for (mro = head; mro != NULL; mro = mro -> next) - if (mro -> cd == cd) - { - setIsDuplicateSuper(new); - - if (!isDuplicateSuper(mro)) - setHasDuplicateSuper(mro); - - break; - } - - /* Append to the list and update the tail pointer. */ - **tailp = new; - *tailp = &new -> next; -} - - -/* - * Get the base types for all typedefs. - */ -static void transformTypedefs(sipSpec *pt) -{ - typedefDef *td; - - for (td = pt -> typedefs; td != NULL; td = td -> next) - getBaseType(pt, td->module, td -> ecd, &td -> type); -} - - -/* - * Transform the data types for mapped types based on a template. - */ -static void transformMappedTypes(sipSpec *pt) -{ - mappedTypeDef *mt; - - for (mt = pt -> mappedtypes; mt != NULL; mt = mt -> next) - { - /* Nothing to do if this isn't template based. */ - - if (mt -> type.atype == template_type) - resolveMappedTypeTypes(pt,mt); - } -} - - -/* - * Transform the data types for a list of ctors. - */ -static void transformCtors(sipSpec *pt, classDef *cd) -{ - ctorDef *ct; - - for (ct = cd->ctors; ct != NULL; ct = ct->next) - { - ctorDef *prev; - - resolveCtorTypes(pt, cd, ct); - - /* - * Now check that the Python signature doesn't conflict with an - * earlier one. - */ - for (prev = cd->ctors; prev != ct; prev = prev->next) - if (samePythonSignature(&prev->pysig, &ct->pysig)) - { - fatalScopedName(classFQCName(cd)); - fatal(" has ctors with the same Python signature\n"); - } - } -} - - -/* - * Transform the data type for a list of casts. - */ -static void transformCasts(sipSpec *pt, classDef *cd) -{ - argList *al; - - for (al = cd->casts; al != NULL; al = al->next) - { - getBaseType(pt, cd->iff->module, cd, &al->arg); - - if (al->arg.atype != class_type) - { - fatalScopedName(classFQCName(cd)); - fatal(" operator cast must be to a class\n"); - } - } -} - - -/* - * Add a default copy ctor is required. - */ -static void addDefaultCopyCtor(classDef *cd) -{ - ctorDef *copyct; - mroDef *mro; - - /* See if there is a private copy ctor in the hierarchy. */ - - copyct = NULL; - - for (mro = cd -> mro; mro != NULL; mro = mro -> next) - { - ctorDef *ct; - - if (isDuplicateSuper(mro)) - continue; - - for (ct = mro -> cd -> ctors; ct != NULL; ct = ct -> next) - { - argDef *ad = &ct -> pysig.args[0]; - - /* See if is a copy ctor. */ - if (ct -> pysig.nrArgs != 1 || ad -> nrderefs != 0 || - !isReference(ad) || ad -> atype != class_type || - ad -> u.cd != mro -> cd) - continue; - - /* Stop now if the copy ctor is private. */ - if (isPrivateCtor(ct)) - return; - - /* - * Remember if it's in the class we are dealing with. - */ - if (mro == cd -> mro) - copyct = ct; - - break; - } - } - - if (copyct == NULL) - { - ctorDef **tailp; - - /* Create a default public copy ctor. */ - - copyct = sipMalloc(sizeof (ctorDef)); - - copyct -> ctorflags = SECT_IS_PUBLIC; - copyct -> pysig.nrArgs = 1; - copyct -> pysig.args[0].name = "other"; - copyct -> pysig.args[0].atype = class_type; - copyct -> pysig.args[0].u.cd = cd; - copyct -> pysig.args[0].argflags = (ARG_IS_REF | ARG_IS_CONST | ARG_IN); - copyct -> pysig.args[0].nrderefs = 0; - copyct -> pysig.args[0].defval = NULL; - - copyct -> cppsig = ©ct -> pysig; - copyct -> exceptions = NULL; - copyct -> methodcode = NULL; - copyct -> prehook = NULL; - copyct -> posthook = NULL; - copyct -> next = NULL; - - /* Append it to the list. */ - for (tailp = &cd -> ctors; *tailp != NULL; tailp = &(*tailp) -> next) - ; - - *tailp = copyct; - } -} - - -/* - * Transform the data types for a list of overloads. - */ -static void transformOverloads(sipSpec *pt, classDef *scope, overDef *overs) -{ - overDef *od; - - for (od = overs; od != NULL; od = od -> next) - { - overDef *prev; - - resolveFuncTypes(pt, od->common->module, scope, od); - - /* - * Now check that the Python signature doesn't conflict with an - * earlier one. - */ - for (prev = overs; prev != od; prev = prev->next) - { - if (prev->common != od->common) - continue; - - if (samePythonSignature(&prev->pysig, &od->pysig)) - { - if (scope != NULL) - { - fatalScopedName(classFQCName(scope)); - fatal("::"); - } - - fatal("%s() has overloaded functions with the same Python signature\n", od->common->pyname->text); - } - } - } -} - - -/* - * Transform the data types for the variables. - */ -static void transformVariableList(sipSpec *pt) -{ - varDef *vd; - - for (vd = pt -> vars; vd != NULL; vd = vd -> next) - resolveVariableType(pt,vd); -} - - -/* - * Set the list of visible member functions for a class. - */ -static void getVisibleMembers(sipSpec *pt,classDef *cd) -{ - mroDef *mro; - - cd -> visible = NULL; - - for (mro = cd -> mro; mro != NULL; mro = mro -> next) - { - memberDef *md; - classDef *mrocd; - - if (isDuplicateSuper(mro)) - continue; - - mrocd = mro -> cd; - - /* - * If the base class is in the main module, see if it needs to - * publish any protected enums. - */ - if (cd -> iff -> module == pt -> module) - { - enumDef *ed; - - for (ed = pt -> enums; ed != NULL; ed = ed -> next) - { - /* Skip unless we are the publisher. */ - if (ed -> pcd != mrocd) - continue; - - /* - * If we are not in the main module then the - * base class must take over as the publisher. - */ - if (mrocd -> iff -> module != pt -> module) - ed -> pcd = cd; - } - } - - for (md = mrocd -> members; md != NULL; md = md -> next) - { - visibleList *vl; - - /* - * See if it is already in the list. This has the desired side - * effect of eliminating any functions that have an implementation - * closer to this class in the hierarchy. This is the only reason - * to define private functions. - */ - for (vl = cd->visible; vl != NULL; vl = vl->next) - if (vl->m->pyname == md->pyname) - break; - - /* See if it is a new member function. */ - - if (vl == NULL) - { - overDef *od; - - vl = sipMalloc(sizeof (visibleList)); - - vl -> m = md; - vl -> cd = mrocd; - vl -> next = cd -> visible; - - addToUsedList(&cd->iff->used, mrocd->iff); - - cd -> visible = vl; - - for (od = mrocd -> overs; od != NULL; od = od -> next) - if (od -> common == md) - { - if (isAbstract(od)) - setIsAbstractClass(cd); - - ifaceFilesAreUsed(pt, cd->iff, od); - - /* See if we need the name. */ - if (cd->iff->module != pt->module) - continue; - - if (isProtected(od) || (isSignal(od) && !optNoEmitters(pt))) - setIsUsedName(md->pyname); - } - } - } - } -} - - -/* - * Get all the virtuals for a particular class. - */ -static void getVirtuals(sipSpec *pt,classDef *cd) -{ - mroDef *mro; - virtOverDef *vod; - - for (mro = cd -> mro; mro != NULL; mro = mro -> next) - { - if (isDuplicateSuper(mro)) - continue; - - getClassVirtuals(cd,mro -> cd); - } - - /* - * Identify any re-implementations of virtuals. We have to do this for - * all classes, not just those in the main module. - */ - for (vod = cd -> vmembers; vod != NULL; vod = vod -> next) - { - overDef *od; - - for (od = cd->overs; od != NULL; od = od->next) - { - if (isVirtual(od)) - continue; - - if (strcmp(vod->o.cppname, od->cppname) == 0 && sameOverload(&vod->o, od)) - { - setIsVirtualReimp(od); - break; - } - } - - /* - * If this class is defined in the main module make sure we get - * the API files for all the visible virtuals. - */ - if (cd->iff->module == pt->module) - { - /* Make sure we get the name. */ - setIsUsedName(vod -> o.common -> pyname); - - ifaceFilesAreUsed(pt, cd->iff, &vod -> o); - } - } -} - - -/* - * Get the list of visible virtual functions for a class. - */ -static void getClassVirtuals(classDef *base,classDef *cd) -{ - overDef *od; - - for (od = cd -> overs; od != NULL; od = od -> next) - { - virtOverDef **tailp, *vod; - - if (!isVirtual(od) || isPrivate(od)) - continue; - - /* - * See if a virtual of this name and signature is already in - * the list. - */ - for (tailp = &base -> vmembers; (vod = *tailp) != NULL; tailp = &vod -> next) - if (strcmp(vod -> o.cppname,od -> cppname) == 0 && sameOverload(&vod -> o,od)) - break; - - if (vod == NULL) - { - /* - * See if there is a non-virtual reimplementation - * nearer in the class hierarchy. - */ - - mroDef *mro; - classDef *scope = NULL; - overDef *eod; - - for (mro = base -> mro; mro -> cd != cd; mro = mro -> next) - { - if (isDuplicateSuper(mro)) - continue; - - /* - * Ignore classes that are on a different - * branch of the class hierarchy. - */ - if (!isSubClass(mro -> cd,cd)) - continue; - - for (eod = mro -> cd -> overs; eod != NULL; eod = eod -> next) - if (strcmp(eod -> cppname,od -> cppname) == 0 && sameSignature(eod -> cppsig,od -> cppsig,TRUE) && isConst(eod) == isConst(od) && !isAbstract(eod)) - { - scope = mro -> cd; - break; - } - - if (scope != NULL) - break; - } - - vod = sipMalloc(sizeof (virtOverDef)); - - vod -> o = *od; - vod -> scope = (scope != NULL ? scope : cd); - vod -> next = NULL; - - *tailp = vod; - - /* - * If there was a nearer reimplementation then we use - * its protection and abstract flags. - */ - if (scope != NULL) - { - vod -> o.overflags &= ~(SECT_MASK | OVER_IS_ABSTRACT); - vod -> o.overflags |= (SECT_MASK | OVER_IS_ABSTRACT) & eod -> overflags; - } - } - } -} - - -/* - * Return TRUE is a class is derived from another. - */ -static int isSubClass(classDef *cc,classDef *pc) -{ - mroDef *mro; - - /* - * In other words, does the parent class appear in the child class's - * MRO list. - */ - for (mro = cc -> mro; mro != NULL; mro = mro -> next) - if (mro -> cd == pc) - return TRUE; - - return FALSE; -} - - -/* - * Resolve the types of a mapped type based on a template. - */ -static void resolveMappedTypeTypes(sipSpec *pt,mappedTypeDef *mt) -{ - int a; - templateDef *td = mt -> type.u.td; - - for (a = 0; a < td -> types.nrArgs; ++a) - { - getBaseType(pt, mt->iff->module, NULL, &td->types.args[a]); - - ifaceFileIsUsed(pt, mt->iff, &td->types.args[a]); - } -} - - -/* - * Resolve the types of a ctor. - */ -static void resolveCtorTypes(sipSpec *pt,classDef *scope,ctorDef *ct) -{ - int a; - - /* Handle any C++ signature. */ - if (ct->cppsig != NULL && ct->cppsig != &ct->pysig) - for (a = 0; a < ct -> cppsig -> nrArgs; ++a) - getBaseType(pt, scope->iff->module, scope, &ct->cppsig->args[a]); - - /* Handle the Python signature. */ - for (a = 0; a < ct -> pysig.nrArgs; ++a) - { - argDef *ad = &ct -> pysig.args[a]; - - getBaseType(pt, scope->iff->module, scope, ad); - - if (!supportedType(scope,NULL,ad,FALSE) && (ct -> cppsig == &ct -> pysig || ct -> methodcode == NULL)) - { - fatalScopedName(classFQCName(scope)); - fatal(" unsupported ctor argument type - provide %%MethodCode and a C++ signature\n"); - } - - ifaceFileIsUsed(pt, scope->iff, ad); - scopeDefaultValue(pt,scope,ad); - } -} - - -/* - * Resolve the types of a function. - */ -static void resolveFuncTypes(sipSpec *pt, moduleDef *mod, classDef *scope, overDef *od) -{ - argDef *res; - - /* Handle any C++ signature. */ - if (od -> cppsig != &od -> pysig) - { - int a; - - getBaseType(pt,mod, scope, &od->cppsig->result); - - for (a = 0; a < od -> cppsig -> nrArgs; ++a) - getBaseType(pt, mod, scope, &od->cppsig->args[a]); - } - - /* Handle the Python signature. */ - resolvePySigTypes(pt, mod, scope, od, &od->pysig,isSignal(od)); - - /* These slots must return int. */ - res = &od -> pysig.result; - - if (isIntReturnSlot(od->common)) - if (res -> atype != int_type || res -> nrderefs != 0 || - isReference(res) || isConstArg(res)) - fatal("%s slots must return int\n",od -> common -> pyname -> text); - - /* These slots must return void. */ - if (isVoidReturnSlot(od -> common)) - if (res -> atype != void_type || res -> nrderefs != 0 || - isReference(res) || isConstArg(res)) - fatal("%s slots must return void\n",od -> common -> pyname -> text); - - /* These slots must return long. */ - if (isLongReturnSlot(od->common)) - if (res->atype != long_type || res->nrderefs != 0 || - isReference(res) || isConstArg(res)) - fatal("%s slots must return long\n", od->common->pyname->text); -} - - -/* - * Resolve the types of a Python signature. - */ -static void resolvePySigTypes(sipSpec *pt, moduleDef *mod, classDef *scope, - overDef *od, signatureDef *pysig, int issignal) -{ - int a; - argDef *res = &pysig -> result; - - if (res -> atype != void_type || res -> nrderefs != 0) - { - if (issignal) - { - if (scope != NULL) - { - fatalScopedName(classFQCName(scope)); - fatal("::"); - } - - fatal("%s() signals must return void\n",od -> cppname); - } - - getBaseType(pt, mod, scope, res); - - /* Results must be simple. */ - if (!supportedType(scope,od,res,FALSE) && (od -> cppsig == &od -> pysig || od -> methodcode == NULL)) - { - if (scope != NULL) - { - fatalScopedName(classFQCName(scope)); - fatal("::"); - } - - fatal("%s() unsupported function return type - provide %%MethodCode and a %s signature\n",od -> cppname,(pt -> genc ? "C" : "C++")); - } - } - - for (a = 0; a < pysig -> nrArgs; ++a) - { - argDef *ad = &pysig -> args[a]; - - getBaseType(pt, mod, scope, ad); - - if (ad -> atype == slotcon_type) - resolvePySigTypes(pt, mod, scope, od, ad->u.sa, TRUE); - - /* - * Note signal arguments are restricted in their types because we don't - * (yet) support handwritten code for them. - */ - if (issignal) - { - if (!supportedType(scope,od,ad,FALSE)) - { - if (scope != NULL) - { - fatalScopedName(classFQCName(scope)); - fatal("::"); - } - - fatal("%s() unsupported signal argument type\n"); - } - } - else if (!supportedType(scope,od,ad,TRUE) && (od -> cppsig == &od -> pysig || od -> methodcode == NULL || (isVirtual(od) && od -> virthandler -> virtcode == NULL))) - { - if (scope != NULL) - { - fatalScopedName(classFQCName(scope)); - fatal("::"); - } - - if (isVirtual(od)) - fatal("%s() unsupported function argument type - provide %%Method code, a valid %%VirtualCatcherCode and a valid C++ signature\n",od -> cppname); - - fatal("%s() unsupported function argument type - provide %%Method code and a valid %s signature\n",od -> cppname,(pt -> genc ? "C" : "C++")); - } - - if (scope != NULL) - scopeDefaultValue(pt,scope,ad); - } -} - - -/* - * Resolve the type of a variable. - */ -static void resolveVariableType(sipSpec *pt,varDef *vd) -{ - int bad = TRUE; - argDef *vtype = &vd -> type; - - getBaseType(pt, vd->module, vd->ecd, vtype); - - switch (vtype -> atype) - { - case mapped_type: - case class_type: - /* Class, Class & and Class * are supported. */ - - if (vtype -> nrderefs <= 1) - bad = FALSE; - break; - - case sstring_type: - case ustring_type: - case string_type: - case wstring_type: - /* - * (signed/unsigned) char, (signed/unsigned) char *, wchar_t, wchar_t * - * are supported. - */ - - if (!isReference(vtype) && vtype -> nrderefs <= 1) - bad = FALSE; - break; - - case cfloat_type: - case float_type: - case cdouble_type: - case double_type: - case enum_type: - case bool_type: - case cbool_type: - case ushort_type: - case short_type: - case uint_type: - case cint_type: - case int_type: - case ulong_type: - case long_type: - case ulonglong_type: - case longlong_type: - case pyobject_type: - case pytuple_type: - case pylist_type: - case pydict_type: - case pycallable_type: - case pyslice_type: - case pytype_type: - /* These are supported without pointers or references. */ - - if (!isReference(vtype) && vtype -> nrderefs == 0) - bad = FALSE; - break; - - case struct_type: - case void_type: - /* A simple pointer is supported. */ - - if (!isReference(vtype) && vtype -> nrderefs == 1) - bad = FALSE; - break; - } - - if (bad) - { - fatalScopedName(vd -> fqcname); - fatal(" has an unsupported type\n"); - } - - if (vtype -> atype != class_type && vd -> accessfunc != NULL) - { - fatalScopedName(vd -> fqcname); - fatal(" has %%AccessCode but isn't a class instance\n"); - } - - if (vd -> ecd != NULL) - ifaceFileIsUsed(pt, vd->ecd->iff, vtype); - else - ifaceFileIsUsed(pt, NULL, vtype); - - /* - * Instance variables or static class variables (unless they are - * constants) need a handler. - */ - if (vd -> ecd != NULL && vd -> accessfunc == NULL && - (!isStaticVar(vd) || vtype -> nrderefs != 0 || !isConstArg(vtype))) - { - setNeedsHandler(vd); - setHasVarHandlers(vd -> ecd); - } -} - - -/* - * See if a type is supported by the generated code. - */ -static int supportedType(classDef *cd,overDef *od,argDef *ad,int outputs) -{ - switch (ad -> atype) - { - case anyslot_type: - /* - * This must be an input, and must also have handwritten code. - */ - - ensureInput(cd,od,ad); - return FALSE; - - case signal_type: - case slot_type: - case rxcon_type: - case rxdis_type: - case slotcon_type: - case slotdis_type: - case qobject_type: - case ellipsis_type: - /* These can only appear in argument lists without * or &. */ - - ensureInput(cd,od,ad); - return TRUE; - - case sstring_type: - case ustring_type: - case string_type: - case wstring_type: - if (isReference(ad)) - { - if (outputs && ad -> nrderefs <= 1) - { - defaultOutput(cd,od,ad); - return TRUE; - } - } - else if (ad -> nrderefs == 0) - { - ensureInput(cd,od,ad); - return TRUE; - } - else if (ad -> nrderefs == 1) - { - if (outputs) - defaultInput(ad); - else - ensureInput(cd,od,ad); - - return TRUE; - } - else if (ad -> nrderefs == 2 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - - break; - - case cfloat_type: - case float_type: - case cdouble_type: - case double_type: - case enum_type: - case bool_type: - case cbool_type: - case ushort_type: - case short_type: - case uint_type: - case cint_type: - case int_type: - case ulong_type: - case long_type: - case ulonglong_type: - case longlong_type: - case pyobject_type: - case pytuple_type: - case pylist_type: - case pydict_type: - case pycallable_type: - case pyslice_type: - case pytype_type: - if (isReference(ad)) - { - if (ad -> nrderefs == 0 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - } - else if (ad -> nrderefs == 0) - { - ensureInput(cd,od,ad); - return TRUE; - } - else if (ad -> nrderefs == 1 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - - break; - - case mapped_type: - case class_type: - if (isReference(ad)) - { - if (ad -> nrderefs == 0) - { - defaultInput(ad); - return TRUE; - } - else if (ad -> nrderefs == 1 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - } - else if (ad -> nrderefs == 0) - { - ensureInput(cd,od,ad); - return TRUE; - } - else if (ad -> nrderefs == 1) - { - if (outputs) - defaultInput(ad); - else - ensureInput(cd,od,ad); - - return TRUE; - } - else if (ad -> nrderefs == 2 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - - break; - - case struct_type: - case void_type: - if (isReference(ad)) - { - if (ad -> nrderefs == 1 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - } - else if (ad -> nrderefs == 1) - { - ensureInput(cd,od,ad); - return TRUE; - } - else if (ad -> nrderefs == 2 && outputs) - { - defaultOutput(cd,od,ad); - return TRUE; - } - - break; - } - - /* Unsupported if we got this far. */ - return FALSE; -} - - -/* - * Ensure the direction of an argument is an input. - */ -static void ensureInput(classDef *cd,overDef *od,argDef *ad) -{ - if (isOutArg(ad)) - { - if (cd != NULL) - { - fatalScopedName(classFQCName(cd)); - fatal("::"); - } - - if (od != NULL) - fatal("%s",od -> cppname); - - fatal("() invalid argument type for /Out/\n"); - } - - setIsInArg(ad); -} - - -/* - * Default the direction of an argument to an input. - */ -static void defaultInput(argDef *ad) -{ - if (!isInArg(ad) && !isOutArg(ad)) - setIsInArg(ad); -} - - -/* - * Default the direction of an argument to an output unless the argument is - * const. - */ -static void defaultOutput(classDef *cd,overDef *od,argDef *ad) -{ - if (isOutArg(ad)) - { - if (isConstArg(ad)) - { - if (cd != NULL) - { - fatalScopedName(classFQCName(cd)); - fatal("::"); - } - - if (od != NULL) - fatal("%s",od -> cppname); - - fatal("() const argument cannot have /Out/ specified\n"); - } - } - else if (!isInArg(ad)) - if (isConstArg(ad)) - setIsInArg(ad); - else - setIsOutArg(ad); -} - - -/* - * Put a scoped name to stderr. - */ -void fatalScopedName(scopedNameDef *snd) -{ - while (snd != NULL) - { - fatal("%s",snd -> name); - - snd = snd -> next; - - if (snd != NULL) - fatal("::"); - } -} - - -/* - * Compare two overloads and return TRUE if they are the same. - */ -static int sameOverload(overDef *od1,overDef *od2) -{ - /* They must both be const, or both not. */ - if (isConst(od1) != isConst(od2)) - return FALSE; - - return sameSignature(&od1 -> pysig,&od2 -> pysig,TRUE); -} - - -/* - * Compare two virtual handlers and return TRUE if they are the same. - */ -static int sameVirtualHandler(virtHandlerDef *vhd1,virtHandlerDef *vhd2) -{ - if (isTransferVH(vhd1) != isTransferVH(vhd2)) - return FALSE; - - if (!sameArgType(&vhd1->pysig->result, &vhd2->pysig->result, TRUE)) - return FALSE; - - if (!sameSignature(vhd1->pysig, vhd2->pysig, TRUE)) - return FALSE; - - if (vhd1->pysig == vhd1->cppsig && vhd2->pysig == vhd2->cppsig) - return TRUE; - - if (!sameArgType(&vhd1->cppsig->result, &vhd2->cppsig->result, TRUE)) - return FALSE; - - return sameSignature(vhd1->cppsig, vhd2->cppsig, TRUE); -} - - -/* - * Compare two signatures and return TRUE if they are the same. - */ -int sameSignature(signatureDef *sd1,signatureDef *sd2,int strict) -{ - int a; - - if (strict) - { - /* The number of arguments must be the same. */ - if (sd1 -> nrArgs != sd2 -> nrArgs) - return FALSE; - } - else - { - int na1, na2; - - /* We only count the compulsory arguments. */ - na1 = 0; - - for (a = 0; a < sd1 -> nrArgs; ++a) - { - if (sd1 -> args[a].defval != NULL) - break; - - ++na1; - } - - na2 = 0; - - for (a = 0; a < sd2 -> nrArgs; ++a) - { - if (sd2 -> args[a].defval != NULL) - break; - - ++na2; - } - - if (na1 != na2) - return FALSE; - } - - /* The arguments must be the same. */ - for (a = 0; a < sd1 -> nrArgs; ++a) - { - if (!strict && sd1 -> args[a].defval != NULL) - break; - - if (!sameArgType(&sd1 -> args[a],&sd2 -> args[a],strict)) - return FALSE; - } - - /* Must be the same if we've got this far. */ - return TRUE; -} - - -#define pyAsString(t) ((t) == ustring_type || (t) == sstring_type || \ - (t) == string_type) -#define pyAsFloat(t) ((t) == cfloat_type || (t) == float_type || \ - (t) == cdouble_type || (t) == double_type) -#define pyAsInt(t) ((t) == cint_type || (t) == bool_type || \ - (t) == short_type || (t) == ushort_type || \ - (t) == int_type || (t) == uint_type) -#define pyAsLong(t) ((t) == long_type || (t) == longlong_type) -#define pyAsULong(t) ((t) == ulong_type || (t) == ulonglong_type) -#define pyAsAuto(t) ((t) == bool_type || \ - (t) == short_type || (t) == ushort_type || \ - (t) == int_type || (t) == uint_type || \ - (t) == float_type || (t) == double_type) - -/* - * Compare two argument types and return TRUE if they are the same. "strict" - * means as C++ would see it, rather than Python. - */ -static int sameArgType(argDef *a1, argDef *a2, int strict) -{ - /* The references must be the same. */ - if (isReference(a1) != isReference(a2) || a1->nrderefs != a2->nrderefs) - return FALSE; - - if (strict) - { - /* The const should be the same. */ - if (isConstArg(a1) != isConstArg(a2)) - return FALSE; - - return sameBaseType(a1,a2); - } - - /* Python will see all these as strings. */ - if (pyAsString(a1->atype) && pyAsString(a2->atype)) - return TRUE; - - /* Python will see all these as floats. */ - if (pyAsFloat(a1->atype) && pyAsFloat(a2->atype)) - return TRUE; - - /* Python will see all these as ints. */ - if (pyAsInt(a1->atype) && pyAsInt(a2->atype)) - return TRUE; - - /* Python will see all these as longs. */ - if (pyAsLong(a1->atype) && pyAsLong(a2->atype)) - return TRUE; - - /* Python will see all these as unsigned longs. */ - if (pyAsULong(a1->atype) && pyAsULong(a2->atype)) - return TRUE; - - /* Python will automatically convert between these. */ - if (pyAsAuto(a1->atype) && pyAsAuto(a2->atype)) - return TRUE; - - /* All the special cases have been handled. */ - return sameBaseType(a1, a2); -} - - -/* - * Compare two basic types and return TRUE if they are the same. - */ - -int sameBaseType(argDef *a1,argDef *a2) -{ - /* The types must be the same. */ - - if (a1 -> atype != a2 ->atype) - return FALSE; - - switch (a1 -> atype) - { - case class_type: - if (a1 -> u.cd != a2 -> u.cd) - return FALSE; - - break; - - case enum_type: - if (a1 -> u.ed != a2 -> u.ed) - return FALSE; - - break; - - case slotcon_type: - case slotdis_type: - if (!sameSignature(a1 -> u.sa,a2 -> u.sa,TRUE)) - return FALSE; - - break; - - case template_type: - { - int a; - templateDef *td1, *td2; - - td1 = a1 -> u.td; - td2 = a2 -> u.td; - - if (!sameScopedName(td1 -> fqname,td2 -> fqname) != 0 || - td1 -> types.nrArgs != td2 -> types.nrArgs) - return FALSE; - - for (a = 0; a < td1 -> types.nrArgs; ++a) - if (!sameBaseType(&td1 -> types.args[a],&td2 -> types.args[a])) - return FALSE; - - break; - } - - case struct_type: - if (!sameScopedName(a1 -> u.sname,a2 -> u.sname) != 0) - return FALSE; - - break; - - case defined_type: - if (!sameScopedName(a1 -> u.snd,a2 -> u.snd)) - return FALSE; - - break; - - case mapped_type: - if (a1 -> u.mtd != a2 -> u.mtd) - return FALSE; - - break; - } - - /* Must be the same if we've got this far. */ - - return TRUE; -} - - -/* - * See if two Python signatures are the same as far as Python is concerned. - */ -static int samePythonSignature(signatureDef *sd1, signatureDef *sd2) -{ - int a1, a2; - - a1 = a2 = -1; - - for (;;) - { - a1 = nextSignificantArg(sd1, a1); - a2 = nextSignificantArg(sd2, a2); - - if (a1 < 0 || a2 < 0) - break; - - if (!sameArgType(&sd1->args[a1], &sd2->args[a2], FALSE)) - return FALSE; - } - - return (a1 < 0 && a2 < 0); - -} - - -/* - * Return the next significant argument from a Python signature (ie. one that - * is not optional or an output only argument. Return -1 if there isn't one. - */ -static int nextSignificantArg(signatureDef *sd, int a) -{ - while (++a < sd->nrArgs) - { - if (sd->args[a].defval != NULL) - break; - - if (isInArg(&sd->args[a])) - return a; - } - - return -1; -} - - -/* - * Return TRUE if two scoped names are the same. - */ - -int sameScopedName(scopedNameDef *snd1,scopedNameDef *snd2) -{ - while (snd1 != NULL && snd2 != NULL && strcmp(snd1 -> name,snd2 -> name) == 0) - { - snd1 = snd1 -> next; - snd2 = snd2 -> next; - } - - return (snd1 == NULL && snd2 == NULL); -} - - -/* - * Add an explicit scope to the default value of an argument if possible. - */ - -static void scopeDefaultValue(sipSpec *pt,classDef *cd,argDef *ad) -{ - valueDef *vd, **tailp, *newvd; - - /* - * We do a quick check to see if we need to do anything. This means - * we can limit the times we need to copy the default value. It needs - * to be copied because it will be shared by class versions that have - * been created on the fly and it may need to be scoped differently for - * each of those versions. - */ - - for (vd = ad -> defval; vd != NULL; vd = vd -> next) - if (vd -> vtype == scoped_value && vd -> u.vscp -> next == NULL) - break; - - if (vd == NULL) - return; - - /* - * It's not certain that we will do anything, but we assume we will and - * start copying. - */ - - newvd = NULL; - tailp = &newvd; - - for (vd = ad -> defval; vd != NULL; vd = vd -> next) - { - mroDef *mro; - scopedNameDef *origname; - valueDef *new; - - /* Make the copy. */ - - new = sipMalloc(sizeof (valueDef)); - - *new = *vd; - *tailp = new; - tailp = &new -> next; - - /* - * Skip this part of the expression if it isn't a named value - * or it already has a scope. - */ - - if (vd -> vtype != scoped_value || vd -> u.vscp -> next != NULL) - continue; - - /* - * Search the class hierarchy for an enum value with the same - * name. If we don't find one, leave it as it is (the compiler - * will find out if this is a problem). - */ - - origname = vd -> u.vscp; - - for (mro = cd -> mro; mro != NULL; mro = mro -> next) - { - enumDef *ed; - - if (isDuplicateSuper(mro)) - continue; - - for (ed = pt -> enums; ed != NULL; ed = ed -> next) - { - enumMemberDef *emd; - - if (ed -> ecd != mro -> cd) - continue; - - for (emd = ed -> members; emd != NULL; emd = emd -> next) - if (strcmp(emd -> cname,origname -> name) == 0) - { - scopedNameDef *snd; - - /* - * Take the scope from the - * class that the enum was - * defined in. - */ - - snd = copyScopedName(mro -> cd -> iff -> fqcname); - appendScopedName(&snd,origname); - - new -> u.vscp = snd; - - /* Nothing more to do. */ - - break; - } - - if (emd != NULL) - break; - } - - if (ed != NULL) - break; - } - } - - ad -> defval = newvd; -} - - -/* - * Make sure a type is a base type. - */ -static void getBaseType(sipSpec *pt, moduleDef *mod, classDef *defscope, argDef *type) -{ - /* Loop until we've got to a base type. */ - while (type -> atype == defined_type) - { - scopedNameDef *snd = type -> u.snd; - - type -> atype = no_type; - - if (defscope != NULL) - searchScope(pt,defscope,snd,type); - - if (type -> atype == no_type) - searchMappedTypes(pt,snd,type); - - if (type -> atype == no_type) - searchTypedefs(pt,snd,type); - - if (type -> atype == no_type) - searchEnums(pt,snd,type); - - if (type -> atype == no_type) - searchClasses(pt, mod, snd, type); - - if (type -> atype == no_type) - fatalNoDefinedType(snd); - } - - /* Get the base type of any slot arguments. */ - if (type -> atype == slotcon_type || type -> atype == slotdis_type) - { - int sa; - - for (sa = 0; sa < type -> u.sa -> nrArgs; ++sa) - getBaseType(pt, mod, defscope, &type->u.sa->args[sa]); - } - - /* See if the type refers to an instantiated template. */ - if (type->atype == template_type) - { - classDef *cd; - - for (cd = pt->classes; cd != NULL; cd = cd->next) - if (cd->td != NULL && - sameScopedName(cd->td->fqname, type->u.td->fqname) && - sameSignature(&cd->td->types, &type->u.td->types, TRUE)) - { - type->atype = class_type; - type->u.cd = cd; - - break; - } - } - - /* Replace the base type if it has been mapped. */ - if (type -> atype == struct_type || type -> atype == template_type) - { - searchMappedTypes(pt,NULL,type); - - /* - * If we still have a template then see if we need to - * automatically instantiate it. - */ - if (type->atype == template_type) - { - mappedTypeTmplDef *mtt; - - for (mtt = pt->mappedtypetemplates; mtt != NULL; mtt = mtt->next) - if (sameScopedName(type->u.td->fqname, mtt->mt->type.u.td->fqname) && sameTemplateSignature(&type->u.td->types, &mtt->mt->type.u.td->types, TRUE)) - { - type->u.mtd = instantiateMappedTypeTemplate(pt, mod, mtt, type); - type->atype = mapped_type; - - break; - } - } - } -} - - -/* - * Instantiate a mapped type template and return it. - */ -static mappedTypeDef *instantiateMappedTypeTemplate(sipSpec *pt, moduleDef *mod, mappedTypeTmplDef *mtt, argDef *type) -{ - scopedNameDef *type_names, *type_values; - mappedTypeDef *mtd; - - type_names = type_values = NULL; - appendTypeStrings(type->u.td->fqname, &mtt->mt->type.u.td->types, &type->u.td->types, &mtt->sig, &type_names, &type_values); - - mtd = allocMappedType(type); - - mtd->iff = findIfaceFile(pt, mod, type->u.td->fqname, mappedtype_iface, type); - mtd->iff->module = mod; - - mtd->hdrcode = templateCode(pt, &mtd->iff->used, mtt->mt->hdrcode, type_names, type_values); - mtd->convfromcode = templateCode(pt, &mtd->iff->used, mtt->mt->convfromcode, type_names, type_values); - mtd->convtocode = templateCode(pt, &mtd->iff->used, mtt->mt->convtocode, type_names, type_values); - - mtd->next = pt->mappedtypes; - pt->mappedtypes = mtd; - - if (type_names != NULL) - freeScopedName(type_names); - - if (type_values != NULL) - freeScopedName(type_values); - - return mtd; -} - - -/* - * Search for a name in a scope and return the corresponding type. - */ - -static void searchScope(sipSpec *pt,classDef *scope,scopedNameDef *snd, - argDef *ad) -{ - scopedNameDef *tmpsnd = NULL; - mroDef *mro; - - for (mro = scope -> mro; mro != NULL; mro = mro -> next) - { - if (isDuplicateSuper(mro)) - continue; - - /* Append the name to the scope and see if it exists. */ - - tmpsnd = copyScopedName(classFQCName(mro -> cd)); - appendScopedName(&tmpsnd,copyScopedName(snd)); - - searchMappedTypes(pt,tmpsnd,ad); - - if (ad -> atype != no_type) - break; - - searchTypedefs(pt,tmpsnd,ad); - - if (ad -> atype != no_type) - break; - - searchEnums(pt,tmpsnd,ad); - - if (ad -> atype != no_type) - break; - - searchClasses(pt, mro->cd->iff->module, tmpsnd, ad); - - if (ad -> atype != no_type) - break; - - freeScopedName(tmpsnd); - tmpsnd = NULL; - } - - if (tmpsnd != NULL) - freeScopedName(tmpsnd); -} - - -/* - * Search the mapped types for a name and return the type. - */ - -static void searchMappedTypes(sipSpec *pt,scopedNameDef *snd,argDef *ad) -{ - mappedTypeDef *mtd; - scopedNameDef *oname; - - /* Patch back to defined types so we can use sameBaseType(). */ - if (snd != NULL) - { - oname = ad -> u.snd; - ad -> u.snd = snd; - ad -> atype = defined_type; - } - - for (mtd = pt -> mappedtypes; mtd != NULL; mtd = mtd -> next) - if (sameBaseType(ad,&mtd -> type)) - { - /* Copy the type. */ - ad -> atype = mapped_type; - ad -> u.mtd = mtd; - - return; - } - - /* Restore because we didn't find anything. */ - if (snd != NULL) - { - ad -> u.snd = oname; - ad -> atype = no_type; - } -} - - -/* - * Search the typedefs for a name and return the type. - */ - -static void searchTypedefs(sipSpec *pt,scopedNameDef *snd,argDef *ad) -{ - typedefDef *td; - - for (td = pt -> typedefs; td != NULL; td = td -> next) - if (sameScopedName(td -> fqname,snd)) - { - /* Copy the type. */ - - ad -> atype = td -> type.atype; - ad -> argflags |= td -> type.argflags; - ad -> nrderefs += td -> type.nrderefs; - ad -> u = td -> type.u; - - break; - } -} - - -/* - * Search the enums for a name and return the type. - */ - -static void searchEnums(sipSpec *pt,scopedNameDef *snd,argDef *ad) -{ - enumDef *ed; - - for (ed = pt -> enums; ed != NULL; ed = ed -> next) - { - if (ed -> fqcname == NULL) - continue; - - if (sameScopedName(ed -> fqcname,snd)) - { - ad -> atype = enum_type; - ad -> u.ed = ed; - - break; - } - } -} - - -/* - * Search the classes for one with a particular name and return it as a type. - */ -static void searchClasses(sipSpec *pt, moduleDef *mod, scopedNameDef *cname, argDef *ad) -{ - classDef *cd; - - for (cd = pt -> classes; cd != NULL; cd = cd -> next) - { - /* - * Ignore an external class unless it was declared in the same - * context (ie. module) as the name is being used. - */ - if (isExternal(cd) && cd->iff->module != mod) - continue; - - if (sameScopedName(classFQCName(cd), cname)) - { - ad -> atype = class_type; - ad -> u.cd = cd; - - break; - } - } -} - - -/* - * Print an error message describing an undefined type to stderr and terminate. - */ - -static void fatalNoDefinedType(scopedNameDef *snd) -{ - fatalScopedName(snd); - fatal(" is undefined\n"); -} - - -/* - * Make sure all external interface files for all other functions of a module - * are used. - */ -static void ifaceFilesAreUsedFromOther(sipSpec *pt, signatureDef *sd) -{ - int a; - ifaceFileDef *iff; - - if ((iff = getIfaceFile(&sd->result)) != NULL && iff->module != pt->module) - addToUsedList(&pt->used, iff); - - for (a = 0; a < sd->nrArgs; ++a) - if ((iff = getIfaceFile(&sd->args[a])) != NULL && iff->module != pt->module) - addToUsedList(&pt->used, iff); -} - - -/* - * Make sure all interface files for all overloads of a method are used. - */ -static void ifaceFilesAreUsedByMethod(sipSpec *pt, classDef *cd, memberDef *md) -{ - overDef *od; - - for (od = cd -> overs; od != NULL; od = od -> next) - if (od -> common == md) - ifaceFilesAreUsed(pt, cd->iff, od); -} - - -/* - * Make sure all interface files for a signature are used. - */ -static void ifaceFilesAreUsed(sipSpec *pt, ifaceFileDef *iff, overDef *od) -{ - int a; - - ifaceFileIsUsed(pt, iff, &od->pysig.result); - - for (a = 0; a < od->pysig.nrArgs; ++a) - ifaceFileIsUsed(pt, iff, &od->pysig.args[a]); - - if (od->cppsig != &od->pysig) - { - ifaceFileIsUsed(pt, iff, &od->cppsig->result); - - for (a = 0; a < od->cppsig->nrArgs; ++a) - ifaceFileIsUsed(pt, iff, &od->cppsig->args[a]); - } -} - - -/* - * If a type has an interface file then add it to the appropriate list of used - * interface files so that the header file is #included in the generated code. - */ -static void ifaceFileIsUsed(sipSpec *pt, ifaceFileDef *iff, argDef *ad) -{ - ifaceFileDef *usediff; - - if ((usediff = getIfaceFile(ad)) != NULL && usediff != iff) - { - ifaceFileList *iffl, **used; - - used = (iff != NULL ? &iff->used : &pt->used); - - iffl = addToUsedList(used, usediff); - - /* - * If the type is a protected enum then its scoping shadow - * class is needed in the generated header file. - */ - if (ad->atype == enum_type && isProtectedEnum(ad->u.ed)) - iffl->header = TRUE; - } -} - - -/* - * Return the interface file for a type, or NULL if it doesn't have one. - */ -static ifaceFileDef *getIfaceFile(argDef *ad) -{ - ifaceFileDef *iff; - - switch (ad -> atype) - { - case class_type: - iff = ad -> u.cd -> iff; - break; - - case mapped_type: - iff = ad -> u.mtd -> iff; - break; - - case enum_type: - if (ad -> u.ed -> fqcname != NULL && ad -> u.ed -> ecd != NULL) - { - iff = ad -> u.ed -> ecd -> iff; - break; - } - - /* Drop through. */ - - default: - iff = NULL; - } - - return iff; -} - - -/* - * Position a class so that it is after all its super-classes. - */ -static void positionClass(classDef *cd) -{ - classList *cl; - - /* See if it has already been done. */ - if (cd -> node -> ordered) - return; - - for (cl = cd -> supers; cl != NULL; cl = cl -> next) - { - nodeDef **ndp, *nd1, *nd2, *rp; - - /* Ignore super-classes from different modules. */ - if (cl -> cd -> iff -> module != cd -> iff -> module) - continue; - - /* Make sure the super-class is positioned. */ - positionClass(cl -> cd); - - /* - * Find ancestors of the two that are siblings (ie. they have a - * common parent). - */ - rp = &cd -> iff -> module -> root; - - for (nd1 = cd -> node; nd1 != rp; nd1 = nd1 -> parent) - { - for (nd2 = cl -> cd -> node; nd2 != rp; nd2 = nd2 -> parent) - if (nd1 -> parent == nd2 -> parent) - break; - - if (nd2 != rp) - break; - } - - /* - * The first node must appear after the second in the common - * parent's list of children. - */ - for (ndp = &nd1 -> parent -> child; *ndp != NULL; ndp = &(*ndp) -> next) - { - nodeDef *nd = *ndp; - - if (nd == nd2) - break; - - if (nd == nd1) - { - /* Remove this one from the list. */ - *ndp = nd -> next; - - /* Find the super-class ancestor. */ - while (*ndp != nd2) - ndp = &(*ndp) -> next; - - /* - * Put this one back after the super-class - * ancestor. - */ - nd -> next = (*ndp) -> next; - (*ndp) -> next = nd; - - break; - } - } - } - - cd -> node -> ordered = TRUE; -} - - -/* - * Make sure a class is in the namespace tree. - */ -static void addNodeToParent(nodeDef *root,classDef *cd) -{ - nodeDef *nd, *parent; - - /* Skip classes already in the tree. */ - if (cd -> node != NULL) - return; - - /* Add this child to the parent. */ - nd = sipMalloc(sizeof (nodeDef)); - - nd -> ordered = FALSE; - nd -> cd = cd; - nd -> child = NULL; - - /* Get the address of the parent node. */ - if (cd -> ecd == NULL) - parent = root; - else - { - /* Make sure the parent is in the tree. */ - addNodeToParent(root,cd -> ecd); - - parent = cd -> ecd -> node; - } - - nd -> parent = parent; - - /* Insert this at the head of the parent's children. */ - nd -> next = parent -> child; - parent -> child = nd; - - /* Remember where we are in the tree. */ - cd -> node = nd; -} - - -/* - * Assign the module specific class number for a class and all it's children. - */ -static void assignClassNrs(sipSpec *pt,moduleDef *mod,nodeDef *nd) -{ - classDef *cd; - nodeDef *cnd; - - /* Assign the class if it's not the root. */ - if ((cd = nd -> cd) != NULL) - { - cd -> classnr = mod -> nrclasses++; - - /* - * If we find a class defined in the main module called TQObject, assume - * it's Qt. - */ - if (mod == pt -> module && strcmp(classBaseName(cd),"TQObject") == 0) - pt -> qobjclass = cd -> classnr; - } - - /* Assign all it's children. */ - for (cnd = nd -> child; cnd != NULL; cnd = cnd -> next) - assignClassNrs(pt,mod,cnd); -} - - -/* - * Assign the module specific enum number for all named enums. - */ -static void assignEnumNrs(sipSpec *pt) -{ - enumDef *ed; - - for (ed = pt -> enums; ed != NULL; ed = ed -> next) - if (ed -> fqcname != NULL) - ed -> enumnr = ed -> module -> nrenums++; -} |