📄 transform.c
字号:
/* * The parse tree transformation module for SIP. * * Copyright (c) 2006 * Riverbank Computing Limited <info@riverbankcomputing.co.uk> * * 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 sameArgType(argDef *,argDef *,int);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 setAllModules(sipSpec *pt);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(sipSpec *pt,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; 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; cd = next; } pt -> classes = rev; /* Build the list of all modules and number them. */ setAllModules(pt); /* 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 (!isOpaque(cd)) 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. */ for (mld = pt->allimports; mld != NULL; mld = mld->next) filterVirtualHandlers(pt,mld -> module); filterVirtualHandlers(pt,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->sd); /* 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 modules and number them. The list is ordered so that * a module appears before any module that imports it. */static void setAllModules(sipSpec *pt){ int nr, none; moduleListDef **tail; /* * We do multiple passes until there is a pass when nothing was done. */ nr = 0; tail = &pt->allimports; do { moduleDef *mod; none = TRUE; for (mod = pt->modules; mod != NULL; mod = mod->next) { moduleListDef *mld; /* Skip the main module and anything already done. */ if (mod == pt->module || isOrdered(mod)) continue; /* This can be done if it only has ordered imports. */ for (mld = mod->imports; mld != NULL; mld = mld->next) if (!isOrdered(mld->module)) break; if (mld != NULL) continue; /* Append this to the ordered list. */ mld = sipMalloc(sizeof (moduleListDef)); mld->module = mod; mld->next = NULL; *tail = mld; tail = &mld->next; mod->modulenr = nr++; setIsOrdered(mod); none = FALSE; } } while (!none);}/* * 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)) { *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->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->supers; 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(sipSpec *pt,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 = pt->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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -