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.
6385 lines
167 KiB
6385 lines
167 KiB
/* |
|
* The SIP parser. |
|
* |
|
* 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 <stdlib.h> |
|
#include <string.h> |
|
#include <ctype.h> |
|
|
|
#include "sip.h" |
|
|
|
|
|
#define MAX_NESTED_IF 10 |
|
#define MAX_NESTED_SCOPE 10 |
|
|
|
#define inMainModule() (currentSpec->module == currentModule || currentModule->container != NULL) |
|
|
|
|
|
static sipSpec *currentSpec; /* The current spec being parsed. */ |
|
static stringList *neededQualifiers; /* The list of required qualifiers. */ |
|
static stringList *excludedQualifiers; /* The list of excluded qualifiers. */ |
|
static moduleDef *currentModule; /* The current module being parsed. */ |
|
static mappedTypeDef *currentMappedType; /* The current mapped type. */ |
|
static enumDef *currentEnum; /* The current enum being parsed. */ |
|
static int sectionFlags; /* The current section flags. */ |
|
static int currentOverIsVirt; /* Set if the overload is virtual. */ |
|
static int currentCtorIsExplicit; /* Set if the ctor is explicit. */ |
|
static int currentIsStatic; /* Set if the current is static. */ |
|
static int currentIsSignal; /* Set if the current is Q_SIGNAL. */ |
|
static int currentIsSlot; /* Set if the current is Q_SLOT. */ |
|
static int currentIsTemplate; /* Set if the current is a template. */ |
|
static char *previousFile; /* The file just parsed. */ |
|
static parserContext currentContext; /* The current context. */ |
|
static int skipStackPtr; /* The skip stack pointer. */ |
|
static int skipStack[MAX_NESTED_IF]; /* Stack of skip flags. */ |
|
static classDef *scopeStack[MAX_NESTED_SCOPE]; /* The scope stack. */ |
|
static int sectFlagsStack[MAX_NESTED_SCOPE]; /* The section flags stack. */ |
|
static int currentScopeIdx; /* The scope stack index. */ |
|
static int currentTimelineOrder; /* The current timeline order. */ |
|
static classList *currentSupers; /* The current super-class list. */ |
|
static int defaultKwdArgs; /* Support keyword arguments by default. */ |
|
static int makeProtPublic; /* Treat protected items as public. */ |
|
|
|
|
|
static const char *getPythonName(optFlags *optflgs, const char *cname); |
|
static classDef *findClass(sipSpec *pt, ifaceFileType iftype, |
|
apiVersionRangeDef *api_range, scopedNameDef *fqname); |
|
static classDef *findClassWithInterface(sipSpec *pt, ifaceFileDef *iff); |
|
static classDef *newClass(sipSpec *pt, ifaceFileType iftype, |
|
apiVersionRangeDef *api_range, scopedNameDef *snd); |
|
static void finishClass(sipSpec *, moduleDef *, classDef *, optFlags *); |
|
static exceptionDef *findException(sipSpec *pt, scopedNameDef *fqname, int new); |
|
static mappedTypeDef *newMappedType(sipSpec *,argDef *, optFlags *); |
|
static enumDef *newEnum(sipSpec *pt, moduleDef *mod, mappedTypeDef *mt_scope, |
|
char *name, optFlags *of, int flags); |
|
static void instantiateClassTemplate(sipSpec *pt, moduleDef *mod, classDef *scope, scopedNameDef *fqname, classTmplDef *tcd, templateDef *td); |
|
static void newTypedef(sipSpec *, moduleDef *, char *, argDef *, optFlags *); |
|
static void newVar(sipSpec *, moduleDef *, char *, int, argDef *, optFlags *, |
|
codeBlock *, codeBlock *, codeBlock *); |
|
static void newCtor(char *, int, signatureDef *, optFlags *, codeBlock *, |
|
throwArgs *, signatureDef *, int, codeBlock *); |
|
static void newFunction(sipSpec *, moduleDef *, classDef *, mappedTypeDef *, |
|
int, int, int, int, int, char *, signatureDef *, int, int, optFlags *, |
|
codeBlock *, codeBlock *, throwArgs *, signatureDef *, codeBlock *); |
|
static optFlag *findOptFlag(optFlags *,char *,flagType); |
|
static memberDef *findFunction(sipSpec *, moduleDef *, classDef *, |
|
mappedTypeDef *, const char *, int, int, int); |
|
static void checkAttributes(sipSpec *, moduleDef *, classDef *, |
|
mappedTypeDef *, const char *, int); |
|
static void newModule(FILE *fp, char *filename); |
|
static moduleDef *allocModule(); |
|
static void parseFile(FILE *fp, char *name, moduleDef *prevmod, int optional); |
|
static void handleEOF(void); |
|
static void handleEOM(void); |
|
static qualDef *findQualifier(const char *name); |
|
static scopedNameDef *text2scopedName(ifaceFileDef *scope, char *text); |
|
static scopedNameDef *scopeScopedName(ifaceFileDef *scope, |
|
scopedNameDef *name); |
|
static void pushScope(classDef *); |
|
static void popScope(void); |
|
static classDef *currentScope(void); |
|
static void newQualifier(moduleDef *,int,int,char *,qualType); |
|
static void newImport(char *filename); |
|
static int timePeriod(char *,char *); |
|
static int platOrFeature(char *,int); |
|
static int isNeeded(qualDef *); |
|
static int notSkipping(void); |
|
static void getHooks(optFlags *,char **,char **); |
|
static int getTransfer(optFlags *optflgs); |
|
static int getReleaseGIL(optFlags *optflgs); |
|
static int getHoldGIL(optFlags *optflgs); |
|
static int getDeprecated(optFlags *optflgs); |
|
static int getAllowNone(optFlags *optflgs); |
|
static const char *getDocType(optFlags *optflgs); |
|
static const char *getDocValue(optFlags *optflgs); |
|
static void templateSignature(signatureDef *sd, int result, classTmplDef *tcd, templateDef *td, classDef *ncd); |
|
static void templateType(argDef *ad, classTmplDef *tcd, templateDef *td, classDef *ncd); |
|
static int search_back(const char *end, const char *start, const char *target); |
|
static char *type2string(argDef *ad); |
|
static char *scopedNameToString(scopedNameDef *name); |
|
static void addUsedFromCode(sipSpec *pt, ifaceFileList **used, const char *sname); |
|
static int sameName(scopedNameDef *snd, const char *sname); |
|
static int stringFind(stringList *sl, const char *s); |
|
static void setModuleName(sipSpec *pt, moduleDef *mod, const char *fullname); |
|
static int foundInScope(scopedNameDef *fq_name, scopedNameDef *rel_name); |
|
static void defineClass(scopedNameDef *snd, classList *supers, optFlags *of); |
|
static classDef *completeClass(scopedNameDef *snd, optFlags *of, int has_def); |
|
static memberDef *instantiateTemplateMethods(memberDef *tmd, moduleDef *mod); |
|
static void instantiateTemplateEnums(sipSpec *pt, classTmplDef *tcd, |
|
templateDef *td, classDef *cd, ifaceFileList **used, |
|
scopedNameDef *type_names, scopedNameDef *type_values); |
|
static void instantiateTemplateVars(sipSpec *pt, classTmplDef *tcd, |
|
templateDef *td, classDef *cd, ifaceFileList **used, |
|
scopedNameDef *type_names, scopedNameDef *type_values); |
|
static overDef *instantiateTemplateOverloads(sipSpec *pt, overDef *tod, |
|
memberDef *tmethods, memberDef *methods, classTmplDef *tcd, |
|
templateDef *td, classDef *cd, ifaceFileList **used, |
|
scopedNameDef *type_names, scopedNameDef *type_values); |
|
static void resolveAnyTypedef(sipSpec *pt, argDef *ad); |
|
static void addVariable(sipSpec *pt, varDef *vd); |
|
static void applyTypeFlags(moduleDef *mod, argDef *ad, optFlags *flags); |
|
static argType convertEncoding(const char *encoding); |
|
static apiVersionRangeDef *getAPIRange(optFlags *optflgs); |
|
static apiVersionRangeDef *convertAPIRange(moduleDef *mod, nameDef *name, |
|
int from, int to); |
|
static char *convertFeaturedString(char *fs); |
|
static scopedNameDef *text2scopePart(char *text); |
|
static int usesKeywordArgs(optFlags *optflgs, signatureDef *sd); |
|
static char *strip(char *s); |
|
static int isEnabledFeature(const char *name); |
|
%} |
|
|
|
%union { |
|
char qchar; |
|
char *text; |
|
long number; |
|
double real; |
|
argDef memArg; |
|
signatureDef signature; |
|
signatureDef *optsignature; |
|
throwArgs *throwlist; |
|
codeBlock *codeb; |
|
valueDef value; |
|
valueDef *valp; |
|
optFlags optflags; |
|
optFlag flag; |
|
scopedNameDef *scpvalp; |
|
fcallDef fcall; |
|
int boolean; |
|
exceptionDef exceptionbase; |
|
classDef *klass; |
|
} |
|
|
|
%token TK_API |
|
%token TK_DEFENCODING |
|
%token TK_PLUGIN |
|
%token TK_DOCSTRING |
|
%token TK_DOC |
|
%token TK_EXPORTEDDOC |
|
%token TK_MAKEFILE |
|
%token TK_ACCESSCODE |
|
%token TK_GETCODE |
|
%token TK_SETCODE |
|
%token TK_PREINITCODE |
|
%token TK_INITCODE |
|
%token TK_POSTINITCODE |
|
%token TK_UNITCODE |
|
%token TK_MODCODE |
|
%token TK_TYPECODE |
|
%token TK_PREPYCODE |
|
%token TK_COPYING |
|
%token TK_MAPPEDTYPE |
|
%token <codeb> TK_CODELINE |
|
%token TK_IF |
|
%token TK_END |
|
%token <text> TK_NAME |
|
%token <text> TK_PATHNAME |
|
%token <text> TK_STRING |
|
%token TK_VIRTUALCATCHERCODE |
|
%token TK_TRAVERSECODE |
|
%token TK_CLEARCODE |
|
%token TK_GETBUFFERCODE |
|
%token TK_RELEASEBUFFERCODE |
|
%token TK_READBUFFERCODE |
|
%token TK_WRITEBUFFERCODE |
|
%token TK_SEGCOUNTCODE |
|
%token TK_CHARBUFFERCODE |
|
%token TK_PICKLECODE |
|
%token TK_METHODCODE |
|
%token TK_FROMTYPE |
|
%token TK_TOTYPE |
|
%token TK_TOSUBCLASS |
|
%token TK_INCLUDE |
|
%token TK_OPTINCLUDE |
|
%token TK_IMPORT |
|
%token TK_EXPHEADERCODE |
|
%token TK_MODHEADERCODE |
|
%token TK_TYPEHEADERCODE |
|
%token TK_MODULE |
|
%token TK_CMODULE |
|
%token TK_CONSMODULE |
|
%token TK_COMPOMODULE |
|
%token TK_CLASS |
|
%token TK_STRUCT |
|
%token TK_PUBLIC |
|
%token TK_PROTECTED |
|
%token TK_PRIVATE |
|
%token TK_SIGNALS |
|
%token TK_SIGNAL_METHOD |
|
%token TK_SLOTS |
|
%token TK_SLOT_METHOD |
|
%token TK_BOOL |
|
%token TK_SHORT |
|
%token TK_INT |
|
%token TK_LONG |
|
%token TK_FLOAT |
|
%token TK_DOUBLE |
|
%token TK_CHAR |
|
%token TK_WCHAR_T |
|
%token TK_VOID |
|
%token TK_PYOBJECT |
|
%token TK_PYTUPLE |
|
%token TK_PYLIST |
|
%token TK_PYDICT |
|
%token TK_PYCALLABLE |
|
%token TK_PYSLICE |
|
%token TK_PYTYPE |
|
%token TK_VIRTUAL |
|
%token TK_ENUM |
|
%token TK_SIGNED |
|
%token TK_UNSIGNED |
|
%token TK_SCOPE |
|
%token TK_LOGICAL_OR |
|
%token TK_CONST |
|
%token TK_STATIC |
|
%token TK_SIPSIGNAL |
|
%token TK_SIPSLOT |
|
%token TK_SIPANYSLOT |
|
%token TK_SIPRXCON |
|
%token TK_SIPRXDIS |
|
%token TK_SIPSLOTCON |
|
%token TK_SIPSLOTDIS |
|
%token <number> TK_NUMBER |
|
%token <real> TK_REAL |
|
%token TK_TYPEDEF |
|
%token TK_NAMESPACE |
|
%token TK_TIMELINE |
|
%token TK_PLATFORMS |
|
%token TK_FEATURE |
|
%token TK_LICENSE |
|
%token <qchar> TK_QCHAR |
|
%token TK_TRUE |
|
%token TK_FALSE |
|
%token TK_NULL |
|
%token TK_OPERATOR |
|
%token TK_THROW |
|
%token TK_QOBJECT |
|
%token TK_EXCEPTION |
|
%token TK_RAISECODE |
|
%token TK_EXPLICIT |
|
%token TK_TEMPLATE |
|
%token TK_ELLIPSIS |
|
%token TK_DEFMETATYPE |
|
%token TK_DEFSUPERTYPE |
|
|
|
%type <memArg> argvalue |
|
%type <memArg> argtype |
|
%type <memArg> cpptype |
|
%type <memArg> basetype |
|
%type <signature> template |
|
%type <signature> arglist |
|
%type <signature> rawarglist |
|
%type <signature> cpptypelist |
|
%type <optsignature> optsig |
|
%type <optsignature> optctorsig |
|
%type <throwlist> optexceptions |
|
%type <throwlist> exceptionlist |
|
%type <number> optslot |
|
%type <number> optref |
|
%type <number> optconst |
|
%type <number> optvirtual |
|
%type <number> optabstract |
|
%type <number> deref |
|
%type <number> optnumber |
|
%type <value> simplevalue |
|
%type <valp> value |
|
%type <valp> expr |
|
%type <valp> optassign |
|
%type <codeb> optaccesscode |
|
%type <codeb> optgetcode |
|
%type <codeb> optsetcode |
|
%type <codeb> exphdrcode |
|
%type <codeb> modhdrcode |
|
%type <codeb> typehdrcode |
|
%type <codeb> opttypehdrcode |
|
%type <codeb> travcode |
|
%type <codeb> clearcode |
|
%type <codeb> getbufcode |
|
%type <codeb> releasebufcode |
|
%type <codeb> readbufcode |
|
%type <codeb> writebufcode |
|
%type <codeb> segcountcode |
|
%type <codeb> charbufcode |
|
%type <codeb> picklecode |
|
%type <codeb> modcode |
|
%type <codeb> typecode |
|
%type <codeb> codeblock |
|
%type <codeb> codelines |
|
%type <codeb> virtualcatchercode |
|
%type <codeb> methodcode |
|
%type <codeb> raisecode |
|
%type <codeb> docstring |
|
%type <codeb> optdocstring |
|
%type <text> operatorname |
|
%type <text> optfilename |
|
%type <text> optname |
|
%type <text> dottedname |
|
%type <optflags> optflags |
|
%type <optflags> flaglist |
|
%type <flag> flag |
|
%type <flag> flagvalue |
|
%type <qchar> optunop |
|
%type <qchar> binop |
|
%type <scpvalp> scopepart |
|
%type <scpvalp> scopedname |
|
%type <fcall> exprlist |
|
%type <boolean> qualifiers |
|
%type <boolean> oredqualifiers |
|
%type <boolean> modlang |
|
%type <boolean> optclassbody |
|
%type <exceptionbase> baseexception |
|
%type <klass> class |
|
|
|
%% |
|
|
|
specification: statement |
|
| specification statement |
|
; |
|
|
|
statement: { |
|
/* |
|
* We don't do these in parserEOF() because the parser is reading |
|
* ahead and that would be too early. |
|
*/ |
|
|
|
if (previousFile != NULL) |
|
{ |
|
handleEOF(); |
|
|
|
if (currentContext.prevmod != NULL) |
|
handleEOM(); |
|
|
|
free(previousFile); |
|
previousFile = NULL; |
|
} |
|
} modstatement |
|
; |
|
|
|
modstatement: module |
|
| consmodule |
|
| compmodule |
|
| plugin |
|
| copying |
|
| include |
|
| optinclude |
|
| import |
|
| api |
|
| timeline |
|
| platforms |
|
| feature |
|
| license |
|
| defencoding |
|
| defmetatype |
|
| defsupertype |
|
| exphdrcode { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tSpec->exphdrcode, $1); |
|
} |
|
| modhdrcode { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tModule->hdrcode, $1); |
|
} |
|
| modcode { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tModule->cppcode, $1); |
|
} |
|
| preinitcode |
|
| initcode |
|
| postinitcode |
|
| unitcode |
|
| prepycode |
|
| doc |
|
| exporteddoc |
|
| makefile |
|
| mappedtype |
|
| mappedtypetmpl |
|
| nsstatement |
|
; |
|
|
|
nsstatement: ifstart |
|
| ifend |
|
| namespace |
|
| struct |
|
| class |
|
| classtmpl |
|
| exception |
|
| typedef |
|
| enum |
|
| function |
|
| variable |
|
| typehdrcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope == NULL) |
|
yyerror("%TypeHeaderCode can only be used in a namespace, class or mapped type"); |
|
|
|
appendCodeBlock(&scope->iff->hdrcode, $1); |
|
} |
|
} |
|
; |
|
|
|
defencoding: TK_DEFENCODING TK_STRING { |
|
if (notSkipping()) |
|
{ |
|
if ((currentModule->encoding = convertEncoding($2)) == no_type) |
|
yyerror("The value of %DefaultEncoding must be one of \"ASCII\", \"Latin-1\", \"UTF-8\" or \"None\""); |
|
} |
|
} |
|
; |
|
|
|
plugin: TK_PLUGIN TK_NAME { |
|
appendString(¤tSpec->plugins, $2); |
|
} |
|
; |
|
|
|
api: TK_API TK_NAME TK_NUMBER { |
|
if (notSkipping()) |
|
{ |
|
apiVersionRangeDef *avd; |
|
|
|
if (findAPI(currentSpec, $2) != NULL) |
|
yyerror("The API name in the %API directive has already been defined"); |
|
|
|
if ($3 < 1) |
|
yyerror("The version number in the %API directive must be greater than or equal to 1"); |
|
|
|
avd = sipMalloc(sizeof (apiVersionRangeDef)); |
|
|
|
avd->api_name = cacheName(currentSpec, $2); |
|
avd->from = $3; |
|
avd->to = -1; |
|
|
|
avd->next = currentModule->api_versions; |
|
currentModule->api_versions = avd; |
|
|
|
if (inMainModule()) |
|
setIsUsedName(avd->api_name); |
|
} |
|
} |
|
; |
|
|
|
exception: TK_EXCEPTION scopedname baseexception optflags '{' opttypehdrcode raisecode '}' ';' { |
|
if (notSkipping()) |
|
{ |
|
exceptionDef *xd; |
|
const char *pyname; |
|
|
|
if (currentSpec->genc) |
|
yyerror("%Exception not allowed in a C module"); |
|
|
|
pyname = getPythonName(&$4, scopedNameTail($2)); |
|
|
|
checkAttributes(currentSpec, currentModule, NULL, NULL, |
|
pyname, FALSE); |
|
|
|
xd = findException(currentSpec, $2, TRUE); |
|
|
|
if (xd->cd != NULL) |
|
yyerror("%Exception name has already been seen as a class name - it must be defined before being used"); |
|
|
|
if (xd->iff->module != NULL) |
|
yyerror("The %Exception has already been defined"); |
|
|
|
/* Complete the definition. */ |
|
xd->iff->module = currentModule; |
|
xd->iff->hdrcode = $6; |
|
xd->pyname = pyname; |
|
xd->bibase = $3.bibase; |
|
xd->base = $3.base; |
|
xd->raisecode = $7; |
|
|
|
if (findOptFlag(&$4, "Default", bool_flag) != NULL) |
|
currentModule->defexception = xd; |
|
|
|
if (xd->bibase != NULL || xd->base != NULL) |
|
xd->exceptionnr = currentModule->nrexceptions++; |
|
} |
|
} |
|
; |
|
|
|
baseexception: { |
|
$$.bibase = NULL; |
|
$$.base = NULL; |
|
} |
|
| '(' scopedname ')' { |
|
exceptionDef *xd; |
|
|
|
$$.bibase = NULL; |
|
$$.base = NULL; |
|
|
|
/* See if it is a defined exception. */ |
|
for (xd = currentSpec->exceptions; xd != NULL; xd = xd->next) |
|
if (compareScopedNames(xd->iff->fqcname, $2) == 0) |
|
{ |
|
$$.base = xd; |
|
break; |
|
} |
|
|
|
if (xd == NULL && $2->next == NULL && strncmp($2->name, "SIP_", 4) == 0) |
|
{ |
|
/* See if it is a builtin exception. */ |
|
|
|
static char *builtins[] = { |
|
"Exception", |
|
"StopIteration", |
|
"StandardError", |
|
"ArithmeticError", |
|
"LookupError", |
|
"AssertionError", |
|
"AttributeError", |
|
"EOFError", |
|
"FloatingPointError", |
|
"EnvironmentError", |
|
"IOError", |
|
"OSError", |
|
"ImportError", |
|
"IndexError", |
|
"KeyError", |
|
"KeyboardInterrupt", |
|
"MemoryError", |
|
"NameError", |
|
"OverflowError", |
|
"RuntimeError", |
|
"NotImplementedError", |
|
"SyntaxError", |
|
"IndentationError", |
|
"TabError", |
|
"ReferenceError", |
|
"SystemError", |
|
"SystemExit", |
|
"TypeError", |
|
"UnboundLocalError", |
|
"UnicodeError", |
|
"UnicodeEncodeError", |
|
"UnicodeDecodeError", |
|
"UnicodeTranslateError", |
|
"ValueError", |
|
"ZeroDivisionError", |
|
"WindowsError", |
|
"VMSError", |
|
NULL |
|
}; |
|
|
|
char **cp; |
|
|
|
for (cp = builtins; *cp != NULL; ++cp) |
|
if (strcmp($2->name + 4, *cp) == 0) |
|
{ |
|
$$.bibase = *cp; |
|
break; |
|
} |
|
} |
|
|
|
if ($$.bibase == NULL && $$.base == NULL) |
|
yyerror("Unknown exception base type"); |
|
} |
|
; |
|
|
|
raisecode: TK_RAISECODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
mappedtype: TK_MAPPEDTYPE basetype optflags { |
|
if (notSkipping()) |
|
currentMappedType = newMappedType(currentSpec, &$2, &$3); |
|
} mtdefinition |
|
; |
|
|
|
mappedtypetmpl: template TK_MAPPEDTYPE basetype optflags { |
|
int a; |
|
|
|
if (currentSpec->genc) |
|
yyerror("%MappedType templates not allowed in a C module"); |
|
|
|
/* Check the template arguments are basic types or simple names. */ |
|
for (a = 0; a < $1.nrArgs; ++a) |
|
{ |
|
argDef *ad = &$1.args[a]; |
|
|
|
if (ad->atype == defined_type && ad->u.snd->next != NULL) |
|
yyerror("%MappedType template arguments must be simple names"); |
|
} |
|
|
|
if ($3.atype != template_type) |
|
yyerror("%MappedType template must map a template type"); |
|
|
|
if (notSkipping()) |
|
{ |
|
mappedTypeTmplDef *mtt; |
|
ifaceFileDef *iff; |
|
|
|
/* Check a template hasn't already been provided. */ |
|
for (mtt = currentSpec->mappedtypetemplates; mtt != NULL; mtt = mtt->next) |
|
if (compareScopedNames(mtt->mt->type.u.td->fqname, $3.u.td->fqname) == 0 && sameTemplateSignature(&mtt->mt->type.u.td->types, &$3.u.td->types, TRUE)) |
|
yyerror("%MappedType template for this type has already been defined"); |
|
|
|
$3.nrderefs = 0; |
|
$3.argflags = 0; |
|
|
|
mtt = sipMalloc(sizeof (mappedTypeTmplDef)); |
|
|
|
mtt->sig = $1; |
|
mtt->mt = allocMappedType(currentSpec, &$3); |
|
mtt->mt->doctype = getDocType(&$4); |
|
mtt->next = currentSpec->mappedtypetemplates; |
|
|
|
currentSpec->mappedtypetemplates = mtt; |
|
|
|
currentMappedType = mtt->mt; |
|
|
|
/* Create a dummy interface file. */ |
|
iff = sipMalloc(sizeof (ifaceFileDef)); |
|
iff->hdrcode = NULL; |
|
mtt->mt->iff = iff; |
|
} |
|
} mtdefinition |
|
; |
|
|
|
mtdefinition: '{' mtbody '}' ';' { |
|
if (notSkipping()) |
|
{ |
|
if (currentMappedType->convfromcode == NULL) |
|
yyerror("%MappedType must have a %ConvertFromTypeCode directive"); |
|
|
|
if (currentMappedType->convtocode == NULL) |
|
yyerror("%MappedType must have a %ConvertToTypeCode directive"); |
|
|
|
currentMappedType = NULL; |
|
} |
|
} |
|
; |
|
|
|
mtbody: mtline |
|
| mtbody mtline |
|
; |
|
|
|
mtline: typehdrcode { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tMappedType->iff->hdrcode, $1); |
|
} |
|
| TK_FROMTYPE codeblock { |
|
if (notSkipping()) |
|
{ |
|
if (currentMappedType -> convfromcode != NULL) |
|
yyerror("%MappedType has more than one %ConvertFromTypeCode directive"); |
|
|
|
currentMappedType -> convfromcode = $2; |
|
} |
|
} |
|
| TK_TOTYPE codeblock { |
|
if (notSkipping()) |
|
{ |
|
if (currentMappedType -> convtocode != NULL) |
|
yyerror("%MappedType has more than one %ConvertToTypeCode directive"); |
|
|
|
currentMappedType -> convtocode = $2; |
|
} |
|
} |
|
| enum |
|
| mtfunction |
|
; |
|
|
|
mtfunction: TK_STATIC cpptype TK_NAME '(' arglist ')' optconst optexceptions optflags optsig ';' optdocstring methodcode { |
|
if (notSkipping()) |
|
{ |
|
applyTypeFlags(currentModule, &$2, &$9); |
|
|
|
$5.result = $2; |
|
|
|
newFunction(currentSpec, currentModule, NULL, |
|
currentMappedType, 0, TRUE, FALSE, FALSE, FALSE, $3, |
|
&$5, $7, FALSE, &$9, $13, NULL, $8, $10, $12); |
|
} |
|
} |
|
; |
|
|
|
namespace: TK_NAMESPACE TK_NAME { |
|
if (currentSpec -> genc) |
|
yyerror("namespace definition not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
{ |
|
classDef *ns, *c_scope; |
|
ifaceFileDef *scope; |
|
|
|
if ((c_scope = currentScope()) != NULL) |
|
scope = c_scope->iff; |
|
else |
|
scope = NULL; |
|
|
|
ns = newClass(currentSpec, namespace_iface, NULL, |
|
text2scopedName(scope, $2)); |
|
|
|
pushScope(ns); |
|
|
|
sectionFlags = 0; |
|
} |
|
} '{' nsbody '}' ';' { |
|
if (notSkipping()) |
|
{ |
|
if (inMainModule()) |
|
{ |
|
classDef *ns = currentScope(); |
|
|
|
setIsUsedName(ns->iff->name); |
|
setIsUsedName(ns->pyname); |
|
} |
|
|
|
popScope(); |
|
} |
|
} |
|
; |
|
|
|
nsbody: nsstatement |
|
| nsbody nsstatement |
|
; |
|
|
|
platforms: TK_PLATFORMS { |
|
qualDef *qd; |
|
|
|
for (qd = currentModule -> qualifiers; qd != NULL; qd = qd -> next) |
|
if (qd -> qtype == platform_qualifier) |
|
yyerror("%Platforms has already been defined for this module"); |
|
} |
|
'{' platformlist '}' { |
|
qualDef *qd; |
|
int nrneeded; |
|
|
|
/* |
|
* Check that exactly one platform in the set was |
|
* requested. |
|
*/ |
|
|
|
nrneeded = 0; |
|
|
|
for (qd = currentModule -> qualifiers; qd != NULL; qd = qd -> next) |
|
if (qd -> qtype == platform_qualifier && isNeeded(qd)) |
|
++nrneeded; |
|
|
|
if (nrneeded > 1) |
|
yyerror("No more than one of these %Platforms must be specified with the -t flag"); |
|
} |
|
; |
|
|
|
platformlist: platform |
|
| platformlist platform |
|
; |
|
|
|
platform: TK_NAME { |
|
newQualifier(currentModule,-1,-1,$1,platform_qualifier); |
|
} |
|
; |
|
|
|
feature: TK_FEATURE TK_NAME { |
|
newQualifier(currentModule,-1,-1,$2,feature_qualifier); |
|
} |
|
; |
|
|
|
timeline: TK_TIMELINE { |
|
currentTimelineOrder = 0; |
|
} |
|
'{' qualifierlist '}' { |
|
qualDef *qd; |
|
int nrneeded; |
|
|
|
/* |
|
* Check that exactly one time slot in the set was |
|
* requested. |
|
*/ |
|
|
|
nrneeded = 0; |
|
|
|
for (qd = currentModule -> qualifiers; qd != NULL; qd = qd -> next) |
|
if (qd -> qtype == time_qualifier && isNeeded(qd)) |
|
++nrneeded; |
|
|
|
if (nrneeded > 1) |
|
yyerror("At most one of this %Timeline must be specified with the -t flag"); |
|
|
|
currentModule -> nrtimelines++; |
|
} |
|
; |
|
|
|
qualifierlist: qualifiername |
|
| qualifierlist qualifiername |
|
; |
|
|
|
qualifiername: TK_NAME { |
|
newQualifier(currentModule,currentModule -> nrtimelines,currentTimelineOrder++,$1,time_qualifier); |
|
} |
|
; |
|
|
|
ifstart: TK_IF '(' qualifiers ')' { |
|
if (skipStackPtr >= MAX_NESTED_IF) |
|
yyerror("Internal error: increase the value of MAX_NESTED_IF"); |
|
|
|
/* Nested %Ifs are implicit logical ands. */ |
|
|
|
if (skipStackPtr > 0) |
|
$3 = ($3 && skipStack[skipStackPtr - 1]); |
|
|
|
skipStack[skipStackPtr++] = $3; |
|
} |
|
; |
|
|
|
oredqualifiers: TK_NAME { |
|
$$ = platOrFeature($1,FALSE); |
|
} |
|
| '!' TK_NAME { |
|
$$ = platOrFeature($2,TRUE); |
|
} |
|
| oredqualifiers TK_LOGICAL_OR TK_NAME { |
|
$$ = (platOrFeature($3,FALSE) || $1); |
|
} |
|
| oredqualifiers TK_LOGICAL_OR '!' TK_NAME { |
|
$$ = (platOrFeature($4,TRUE) || $1); |
|
} |
|
; |
|
|
|
qualifiers: oredqualifiers |
|
| optname '-' optname { |
|
$$ = timePeriod($1,$3); |
|
} |
|
; |
|
|
|
ifend: TK_END { |
|
if (skipStackPtr-- <= 0) |
|
yyerror("Too many %End directives"); |
|
} |
|
; |
|
|
|
license: TK_LICENSE optflags { |
|
optFlag *of; |
|
|
|
if ($2.nrFlags == 0) |
|
yyerror("%License details not specified"); |
|
|
|
if ((of = findOptFlag(&$2,"Type",string_flag)) == NULL) |
|
yyerror("%License type not specified"); |
|
|
|
currentModule -> license = sipMalloc(sizeof (licenseDef)); |
|
|
|
currentModule -> license -> type = of -> fvalue.sval; |
|
|
|
currentModule -> license -> licensee = |
|
((of = findOptFlag(&$2,"Licensee",string_flag)) != NULL) |
|
? of -> fvalue.sval : NULL; |
|
|
|
currentModule -> license -> timestamp = |
|
((of = findOptFlag(&$2,"Timestamp",string_flag)) != NULL) |
|
? of -> fvalue.sval : NULL; |
|
|
|
currentModule -> license -> sig = |
|
((of = findOptFlag(&$2,"Signature",string_flag)) != NULL) |
|
? of -> fvalue.sval : NULL; |
|
} |
|
; |
|
|
|
defmetatype:TK_DEFMETATYPE dottedname { |
|
if (notSkipping()) |
|
{ |
|
if (currentModule->defmetatype != NULL) |
|
yyerror("%DefaultMetatype has already been defined for this module"); |
|
|
|
currentModule->defmetatype = cacheName(currentSpec, $2); |
|
} |
|
} |
|
; |
|
|
|
defsupertype: TK_DEFSUPERTYPE dottedname { |
|
if (notSkipping()) |
|
{ |
|
if (currentModule->defsupertype != NULL) |
|
yyerror("%DefaultSupertype has already been defined for this module"); |
|
|
|
currentModule->defsupertype = cacheName(currentSpec, $2); |
|
} |
|
} |
|
; |
|
|
|
consmodule: TK_CONSMODULE dottedname { |
|
/* Make sure this is the first mention of a module. */ |
|
if (currentSpec->module != currentModule) |
|
yyerror("A %ConsolidatedModule cannot be %Imported"); |
|
|
|
if (currentModule->fullname != NULL) |
|
yyerror("%ConsolidatedModule must appear before any %Module or %CModule directive"); |
|
|
|
setModuleName(currentSpec, currentModule, $2); |
|
setIsConsolidated(currentModule); |
|
} |
|
; |
|
|
|
compmodule: TK_COMPOMODULE dottedname { |
|
/* Make sure this is the first mention of a module. */ |
|
if (currentSpec->module != currentModule) |
|
yyerror("A %CompositeModule cannot be %Imported"); |
|
|
|
if (currentModule->fullname != NULL) |
|
yyerror("%CompositeModule must appear before any %Module or %CModule directive"); |
|
|
|
setModuleName(currentSpec, currentModule, $2); |
|
setIsComposite(currentModule); |
|
} |
|
; |
|
|
|
module: modlang dottedname optnumber { |
|
/* Check the module hasn't already been defined. */ |
|
|
|
moduleDef *mod; |
|
|
|
for (mod = currentSpec->modules; mod != NULL; mod = mod->next) |
|
if (mod->fullname != NULL && strcmp(mod->fullname->text, $2) == 0) |
|
yyerror("Module is already defined"); |
|
|
|
/* |
|
* If we are in a container module then create a component module |
|
* and make it current. |
|
*/ |
|
if (isContainer(currentModule) || currentModule->container != NULL) |
|
{ |
|
mod = allocModule(); |
|
|
|
mod->file = currentContext.filename; |
|
mod->container = (isContainer(currentModule) ? currentModule : currentModule->container); |
|
|
|
currentModule = mod; |
|
} |
|
|
|
setModuleName(currentSpec, currentModule, $2); |
|
currentModule->version = $3; |
|
|
|
if (currentSpec->genc < 0) |
|
currentSpec->genc = $1; |
|
else if (currentSpec->genc != $1) |
|
yyerror("Cannot mix C and C++ modules"); |
|
} |
|
; |
|
|
|
modlang: TK_MODULE { |
|
$$ = FALSE; |
|
} |
|
| TK_CMODULE { |
|
$$ = TRUE; |
|
} |
|
; |
|
|
|
dottedname: TK_NAME |
|
| TK_PATHNAME { |
|
/* |
|
* The grammar design is a bit broken and this is the easiest way |
|
* to allow periods in names. |
|
*/ |
|
|
|
char *cp; |
|
|
|
for (cp = $1; *cp != '\0'; ++cp) |
|
if (*cp != '.' && *cp != '_' && !isalnum(*cp)) |
|
yyerror("Invalid character in name"); |
|
|
|
$$ = $1; |
|
} |
|
; |
|
|
|
optnumber: { |
|
$$ = -1; |
|
} |
|
| TK_NUMBER |
|
; |
|
|
|
include: TK_INCLUDE TK_PATHNAME { |
|
parseFile(NULL, $2, NULL, FALSE); |
|
} |
|
; |
|
|
|
optinclude: TK_OPTINCLUDE TK_PATHNAME { |
|
parseFile(NULL, $2, NULL, TRUE); |
|
} |
|
; |
|
|
|
import: TK_IMPORT TK_PATHNAME { |
|
newImport($2); |
|
} |
|
; |
|
|
|
optaccesscode: { |
|
$$ = NULL; |
|
} |
|
| TK_ACCESSCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
optgetcode: { |
|
$$ = NULL; |
|
} |
|
| TK_GETCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
optsetcode: { |
|
$$ = NULL; |
|
} |
|
| TK_SETCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
copying: TK_COPYING codeblock { |
|
appendCodeBlock(¤tModule->copying, $2); |
|
} |
|
; |
|
|
|
exphdrcode: TK_EXPHEADERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
modhdrcode: TK_MODHEADERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
typehdrcode: TK_TYPEHEADERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
opttypehdrcode: { |
|
$$ = NULL; |
|
} |
|
| typehdrcode |
|
; |
|
|
|
travcode: TK_TRAVERSECODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
clearcode: TK_CLEARCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
getbufcode: TK_GETBUFFERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
releasebufcode: TK_RELEASEBUFFERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
readbufcode: TK_READBUFFERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
writebufcode: TK_WRITEBUFFERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
segcountcode: TK_SEGCOUNTCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
charbufcode: TK_CHARBUFFERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
picklecode: TK_PICKLECODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
modcode: TK_MODCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
typecode: TK_TYPECODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
preinitcode: TK_PREINITCODE codeblock { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tModule->preinitcode, $2); |
|
} |
|
; |
|
|
|
initcode: TK_INITCODE codeblock { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tModule->initcode, $2); |
|
} |
|
; |
|
|
|
postinitcode: TK_POSTINITCODE codeblock { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tModule->postinitcode, $2); |
|
} |
|
; |
|
|
|
unitcode: TK_UNITCODE codeblock { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tModule->unitcode, $2); |
|
} |
|
; |
|
|
|
prepycode: TK_PREPYCODE codeblock { |
|
/* |
|
* This is a no-op and is retained for compatibility |
|
* until the last use of it (by SIP v3) can be removed |
|
* from PyQt. |
|
*/ |
|
} |
|
; |
|
|
|
doc: TK_DOC codeblock { |
|
if (inMainModule()) |
|
appendCodeBlock(¤tSpec -> docs,$2); |
|
} |
|
; |
|
|
|
exporteddoc: TK_EXPORTEDDOC codeblock { |
|
appendCodeBlock(¤tSpec -> docs,$2); |
|
} |
|
; |
|
|
|
makefile: TK_MAKEFILE TK_PATHNAME optfilename codeblock { |
|
if (inMainModule()) |
|
yywarning("%Makefile is ignored, please use the -b flag instead"); |
|
} |
|
; |
|
|
|
codeblock: codelines TK_END |
|
; |
|
|
|
codelines: TK_CODELINE |
|
| codelines TK_CODELINE { |
|
$$ = $1; |
|
|
|
append(&$$->frag, $2->frag); |
|
|
|
free($2->frag); |
|
free((char *)$2->filename); |
|
free($2); |
|
} |
|
; |
|
|
|
enum: TK_ENUM optname optflags { |
|
if (notSkipping()) |
|
{ |
|
if (sectionFlags != 0 && (sectionFlags & ~(SECT_IS_PUBLIC | SECT_IS_PROT)) != 0) |
|
yyerror("Class enums must be in the public or protected sections"); |
|
|
|
currentEnum = newEnum(currentSpec, currentModule, |
|
currentMappedType, $2, &$3, sectionFlags); |
|
} |
|
} '{' optenumbody '}' ';' |
|
; |
|
|
|
optfilename: { |
|
$$ = NULL; |
|
} |
|
| TK_PATHNAME { |
|
$$ = $1; |
|
} |
|
; |
|
|
|
optname: { |
|
$$ = NULL; |
|
} |
|
| TK_NAME { |
|
$$ = $1; |
|
} |
|
; |
|
|
|
optenumbody: |
|
| enumbody |
|
; |
|
|
|
enumbody: enumline |
|
| enumbody enumline |
|
; |
|
|
|
enumline: ifstart |
|
| ifend |
|
| TK_NAME optenumassign optflags optcomma { |
|
if (notSkipping()) |
|
{ |
|
enumMemberDef *emd, **tail; |
|
|
|
/* Note that we don't use the assigned value. */ |
|
emd = sipMalloc(sizeof (enumMemberDef)); |
|
|
|
emd -> pyname = cacheName(currentSpec, getPythonName(&$3, $1)); |
|
emd -> cname = $1; |
|
emd -> ed = currentEnum; |
|
emd -> next = NULL; |
|
|
|
checkAttributes(currentSpec, currentModule, emd->ed->ecd, |
|
emd->ed->emtd, emd->pyname->text, FALSE); |
|
|
|
/* Append to preserve the order. */ |
|
for (tail = ¤tEnum->members; *tail != NULL; tail = &(*tail)->next) |
|
; |
|
|
|
*tail = emd; |
|
|
|
if (inMainModule()) |
|
setIsUsedName(emd -> pyname); |
|
} |
|
} |
|
; |
|
|
|
optcomma: |
|
| ',' |
|
; |
|
|
|
optenumassign: |
|
| '=' value |
|
; |
|
|
|
optassign: { |
|
$$ = NULL; |
|
} |
|
| '=' expr { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
expr: value |
|
| expr binop value { |
|
valueDef *vd; |
|
|
|
if ($1 -> vtype == string_value || $3 -> vtype == string_value) |
|
yyerror("Invalid binary operator for string"); |
|
|
|
/* Find the last value in the existing expression. */ |
|
|
|
for (vd = $1; vd -> next != NULL; vd = vd -> next) |
|
; |
|
|
|
vd -> vbinop = $2; |
|
vd -> next = $3; |
|
|
|
$$ = $1; |
|
} |
|
; |
|
|
|
binop: '-' { |
|
$$ = '-'; |
|
} |
|
| '+' { |
|
$$ = '+'; |
|
} |
|
| '*' { |
|
$$ = '*'; |
|
} |
|
| '/' { |
|
$$ = '/'; |
|
} |
|
| '&' { |
|
$$ = '&'; |
|
} |
|
| '|' { |
|
$$ = '|'; |
|
} |
|
; |
|
|
|
optunop: { |
|
$$ = '\0'; |
|
} |
|
| '!' { |
|
$$ = '!'; |
|
} |
|
| '~' { |
|
$$ = '~'; |
|
} |
|
| '-' { |
|
$$ = '-'; |
|
} |
|
| '+' { |
|
$$ = '+'; |
|
} |
|
; |
|
|
|
value: optunop simplevalue { |
|
if ($1 != '\0' && $2.vtype == string_value) |
|
yyerror("Invalid unary operator for string"); |
|
|
|
/* |
|
* Convert the value to a simple expression on the |
|
* heap. |
|
*/ |
|
|
|
$$ = sipMalloc(sizeof (valueDef)); |
|
|
|
*$$ = $2; |
|
$$ -> vunop = $1; |
|
$$ -> vbinop = '\0'; |
|
$$ -> next = NULL; |
|
} |
|
; |
|
|
|
scopedname: scopepart |
|
| scopedname TK_SCOPE scopepart { |
|
if (currentSpec -> genc) |
|
yyerror("Scoped names are not allowed in a C module"); |
|
|
|
appendScopedName(&$1,$3); |
|
} |
|
; |
|
|
|
scopepart: TK_NAME { |
|
$$ = text2scopePart($1); |
|
} |
|
; |
|
|
|
simplevalue: scopedname { |
|
/* |
|
* We let the C++ compiler decide if the value is a valid one - no |
|
* point in building a full C++ parser here. |
|
*/ |
|
|
|
$$.vtype = scoped_value; |
|
$$.u.vscp = $1; |
|
} |
|
| basetype '(' exprlist ')' { |
|
fcallDef *fcd; |
|
|
|
fcd = sipMalloc(sizeof (fcallDef)); |
|
*fcd = $3; |
|
fcd -> type = $1; |
|
|
|
$$.vtype = fcall_value; |
|
$$.u.fcd = fcd; |
|
} |
|
| TK_REAL { |
|
$$.vtype = real_value; |
|
$$.u.vreal = $1; |
|
} |
|
| TK_NUMBER { |
|
$$.vtype = numeric_value; |
|
$$.u.vnum = $1; |
|
} |
|
| TK_TRUE { |
|
$$.vtype = numeric_value; |
|
$$.u.vnum = 1; |
|
} |
|
| TK_FALSE { |
|
$$.vtype = numeric_value; |
|
$$.u.vnum = 0; |
|
} |
|
| TK_NULL { |
|
$$.vtype = numeric_value; |
|
$$.u.vnum = 0; |
|
} |
|
| TK_STRING { |
|
$$.vtype = string_value; |
|
$$.u.vstr = $1; |
|
} |
|
| TK_QCHAR { |
|
$$.vtype = qchar_value; |
|
$$.u.vqchar = $1; |
|
} |
|
; |
|
|
|
exprlist: { |
|
/* No values. */ |
|
|
|
$$.nrArgs = 0; |
|
} |
|
| expr { |
|
/* The single or first expression. */ |
|
|
|
$$.args[0] = $1; |
|
$$.nrArgs = 1; |
|
} |
|
| exprlist ',' expr { |
|
/* Check that it wasn't ...(,expression...). */ |
|
|
|
if ($$.nrArgs == 0) |
|
yyerror("First argument to function call is missing"); |
|
|
|
/* Check there is room. */ |
|
|
|
if ($1.nrArgs == MAX_NR_ARGS) |
|
yyerror("Too many arguments to function call"); |
|
|
|
$$ = $1; |
|
|
|
$$.args[$$.nrArgs] = $3; |
|
$$.nrArgs++; |
|
} |
|
; |
|
|
|
typedef: TK_TYPEDEF cpptype TK_NAME optflags ';' { |
|
if (notSkipping()) |
|
{ |
|
applyTypeFlags(currentModule, &$2, &$4); |
|
newTypedef(currentSpec, currentModule, $3, &$2, &$4); |
|
} |
|
} |
|
| TK_TYPEDEF cpptype '(' deref TK_NAME ')' '(' cpptypelist ')' optflags ';' { |
|
if (notSkipping()) |
|
{ |
|
signatureDef *sig; |
|
argDef ftype; |
|
|
|
applyTypeFlags(currentModule, &$2, &$10); |
|
|
|
memset(&ftype, 0, sizeof (argDef)); |
|
|
|
/* Create the full signature on the heap. */ |
|
sig = sipMalloc(sizeof (signatureDef)); |
|
*sig = $8; |
|
sig->result = $2; |
|
|
|
/* Create the full type. */ |
|
ftype.atype = function_type; |
|
ftype.nrderefs = $4; |
|
ftype.u.sa = sig; |
|
|
|
newTypedef(currentSpec, currentModule, $5, &ftype, &$10); |
|
} |
|
} |
|
; |
|
|
|
struct: TK_STRUCT scopedname { |
|
if (currentSpec -> genc && $2->next != NULL) |
|
yyerror("Namespaces not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
currentSupers = NULL; |
|
} superclasses optflags { |
|
if (notSkipping()) |
|
{ |
|
if (currentSpec->genc && currentSupers != NULL) |
|
yyerror("Super-classes not allowed in a C module struct"); |
|
|
|
defineClass($2, currentSupers, &$5); |
|
sectionFlags = SECT_IS_PUBLIC; |
|
} |
|
} optclassbody ';' { |
|
if (notSkipping()) |
|
completeClass($2, &$5, $7); |
|
} |
|
; |
|
|
|
classtmpl: template {currentIsTemplate = TRUE;} class { |
|
if (currentSpec->genc) |
|
yyerror("Class templates not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
{ |
|
classTmplDef *tcd; |
|
|
|
/* |
|
* Make sure there is room for the extra class name argument. |
|
*/ |
|
if ($1.nrArgs == MAX_NR_ARGS) |
|
yyerror("Internal error - increase the value of MAX_NR_ARGS"); |
|
|
|
tcd = sipMalloc(sizeof (classTmplDef)); |
|
tcd->sig = $1; |
|
tcd->cd = $3; |
|
tcd->next = currentSpec->classtemplates; |
|
|
|
currentSpec->classtemplates = tcd; |
|
} |
|
|
|
currentIsTemplate = FALSE; |
|
} |
|
; |
|
|
|
template: TK_TEMPLATE '<' cpptypelist '>' { |
|
$$ = $3; |
|
} |
|
; |
|
|
|
class: TK_CLASS scopedname { |
|
if (currentSpec->genc) |
|
yyerror("Class definition not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
currentSupers = NULL; |
|
} superclasses optflags { |
|
if (notSkipping()) |
|
{ |
|
defineClass($2, currentSupers, &$5); |
|
sectionFlags = SECT_IS_PRIVATE; |
|
} |
|
} optclassbody ';' { |
|
if (notSkipping()) |
|
$$ = completeClass($2, &$5, $7); |
|
} |
|
; |
|
|
|
superclasses: |
|
| ':' superlist |
|
; |
|
|
|
superlist: superclass |
|
| superlist ',' superclass |
|
; |
|
|
|
superclass: scopedname { |
|
if (notSkipping()) |
|
{ |
|
argDef ad; |
|
classDef *super; |
|
scopedNameDef *snd = $1; |
|
|
|
/* |
|
* This is a hack to allow typedef'ed classes to be used before |
|
* we have resolved the typedef definitions. Unlike elsewhere, |
|
* we require that the typedef is defined before being used. |
|
*/ |
|
for (;;) |
|
{ |
|
ad.atype = no_type; |
|
ad.argflags = 0; |
|
ad.nrderefs = 0; |
|
ad.original_type = NULL; |
|
|
|
searchTypedefs(currentSpec, snd, &ad); |
|
|
|
if (ad.atype != defined_type) |
|
break; |
|
|
|
if (ad.nrderefs != 0 || isConstArg(&ad) || isReference(&ad)) |
|
break; |
|
|
|
snd = ad.u.snd; |
|
} |
|
|
|
if (ad.atype != no_type) |
|
yyerror("Super-class list contains an invalid type"); |
|
|
|
super = findClass(currentSpec, class_iface, NULL, snd); |
|
appendToClassList(¤tSupers, super); |
|
} |
|
} |
|
; |
|
|
|
optclassbody: { |
|
$$ = FALSE; |
|
} |
|
| '{' classbody '}' { |
|
$$ = TRUE; |
|
} |
|
; |
|
|
|
classbody: classline |
|
| classbody classline |
|
; |
|
|
|
classline: ifstart |
|
| ifend |
|
| namespace |
|
| struct |
|
| class |
|
| exception |
|
| typedef |
|
| enum |
|
| docstring { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
/* Make sure this is before any ctor docstrings. */ |
|
$1->next = scope->docstring; |
|
scope->docstring = $1; |
|
} |
|
} |
|
| typecode { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tScope()->cppcode, $1); |
|
} |
|
| typehdrcode { |
|
if (notSkipping()) |
|
appendCodeBlock(¤tScope()->iff->hdrcode, $1); |
|
} |
|
| travcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->travcode != NULL) |
|
yyerror("%GCTraverseCode already given for class"); |
|
|
|
scope->travcode = $1; |
|
} |
|
} |
|
| clearcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->clearcode != NULL) |
|
yyerror("%GCClearCode already given for class"); |
|
|
|
scope->clearcode = $1; |
|
} |
|
} |
|
| getbufcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->getbufcode != NULL) |
|
yyerror("%BIGetBufferCode already given for class"); |
|
|
|
scope->getbufcode = $1; |
|
} |
|
} |
|
| releasebufcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->releasebufcode != NULL) |
|
yyerror("%BIReleaseBufferCode already given for class"); |
|
|
|
scope->releasebufcode = $1; |
|
} |
|
} |
|
| readbufcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->readbufcode != NULL) |
|
yyerror("%BIGetReadBufferCode already given for class"); |
|
|
|
scope->readbufcode = $1; |
|
} |
|
} |
|
| writebufcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->writebufcode != NULL) |
|
yyerror("%BIGetWriteBufferCode already given for class"); |
|
|
|
scope->writebufcode = $1; |
|
} |
|
} |
|
| segcountcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->segcountcode != NULL) |
|
yyerror("%BIGetSegCountCode already given for class"); |
|
|
|
scope->segcountcode = $1; |
|
} |
|
} |
|
| charbufcode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->charbufcode != NULL) |
|
yyerror("%BIGetCharBufferCode already given for class"); |
|
|
|
scope->charbufcode = $1; |
|
} |
|
} |
|
| picklecode { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->picklecode != NULL) |
|
yyerror("%PickleCode already given for class"); |
|
|
|
scope->picklecode = $1; |
|
} |
|
} |
|
| ctor |
|
| dtor |
|
| varmember |
|
| TK_TOSUBCLASS codeblock { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->convtosubcode != NULL) |
|
yyerror("Class has more than one %ConvertToSubClassCode directive"); |
|
|
|
scope->convtosubcode = $2; |
|
} |
|
} |
|
| TK_TOTYPE codeblock { |
|
if (notSkipping()) |
|
{ |
|
classDef *scope = currentScope(); |
|
|
|
if (scope->convtocode != NULL) |
|
yyerror("Class has more than one %ConvertToTypeCode directive"); |
|
|
|
scope->convtocode = $2; |
|
} |
|
} |
|
| TK_PUBLIC optslot ':' { |
|
if (currentSpec -> genc) |
|
yyerror("public section not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
sectionFlags = SECT_IS_PUBLIC | $2; |
|
} |
|
| TK_PROTECTED optslot ':' { |
|
if (currentSpec -> genc) |
|
yyerror("protected section not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
sectionFlags = SECT_IS_PROT | $2; |
|
} |
|
| TK_PRIVATE optslot ':' { |
|
if (currentSpec -> genc) |
|
yyerror("private section not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
sectionFlags = SECT_IS_PRIVATE | $2; |
|
} |
|
| TK_SIGNALS ':' { |
|
if (currentSpec -> genc) |
|
yyerror("signals section not allowed in a C module"); |
|
|
|
if (notSkipping()) |
|
sectionFlags = SECT_IS_SIGNAL; |
|
} |
|
; |
|
|
|
optslot: { |
|
$$ = 0; |
|
} |
|
| TK_SLOTS { |
|
$$ = SECT_IS_SLOT; |
|
} |
|
; |
|
|
|
dtor: optvirtual '~' TK_NAME '(' ')' optexceptions optabstract optflags ';' methodcode virtualcatchercode { |
|
/* Note that we allow non-virtual dtors in C modules. */ |
|
|
|
if (notSkipping()) |
|
{ |
|
classDef *cd = currentScope(); |
|
|
|
if (strcmp(classBaseName(cd),$3) != 0) |
|
yyerror("Destructor doesn't have the same name as its class"); |
|
|
|
if (isDtor(cd)) |
|
yyerror("Destructor has already been defined"); |
|
|
|
if (currentSpec -> genc && $10 == NULL) |
|
yyerror("Destructor in C modules must include %MethodCode"); |
|
|
|
cd -> dealloccode = $10; |
|
cd -> dtorcode = $11; |
|
cd -> dtorexceptions = $6; |
|
|
|
/* |
|
* Note that we don't apply the protected/public hack to dtors |
|
* as it (I think) may change the behaviour of the wrapped API. |
|
*/ |
|
cd->classflags |= sectionFlags; |
|
|
|
if ($7) |
|
{ |
|
if (!$1) |
|
yyerror("Abstract destructor must be virtual"); |
|
|
|
setIsAbstractClass(cd); |
|
} |
|
|
|
/* |
|
* The class has a shadow if we have a virtual dtor or some |
|
* dtor code. |
|
*/ |
|
if ($1 || $11 != NULL) |
|
{ |
|
if (currentSpec -> genc) |
|
yyerror("Virtual destructor or %VirtualCatcherCode not allowed in a C module"); |
|
|
|
setHasShadow(cd); |
|
} |
|
|
|
if (getReleaseGIL(&$8)) |
|
setIsReleaseGILDtor(cd); |
|
else if (getHoldGIL(&$8)) |
|
setIsHoldGILDtor(cd); |
|
} |
|
} |
|
; |
|
|
|
ctor: TK_EXPLICIT {currentCtorIsExplicit = TRUE;} simplector |
|
| simplector |
|
; |
|
|
|
simplector: TK_NAME '(' arglist ')' optexceptions optflags optctorsig ';' optdocstring methodcode { |
|
/* Note that we allow ctors in C modules. */ |
|
|
|
if (notSkipping()) |
|
{ |
|
if (currentSpec -> genc) |
|
{ |
|
if ($10 == NULL && $3.nrArgs != 0) |
|
yyerror("Constructors with arguments in C modules must include %MethodCode"); |
|
|
|
if (currentCtorIsExplicit) |
|
yyerror("Explicit constructors not allowed in a C module"); |
|
} |
|
|
|
if ((sectionFlags & (SECT_IS_PUBLIC | SECT_IS_PROT | SECT_IS_PRIVATE)) == 0) |
|
yyerror("Constructor must be in the public, private or protected sections"); |
|
|
|
newCtor($1, sectionFlags, &$3, &$6, $10, $5, $7, |
|
currentCtorIsExplicit, $9); |
|
} |
|
|
|
free($1); |
|
|
|
currentCtorIsExplicit = FALSE; |
|
} |
|
; |
|
|
|
optctorsig: { |
|
$$ = NULL; |
|
} |
|
| '[' '(' arglist ')' ']' { |
|
$$ = sipMalloc(sizeof (signatureDef)); |
|
|
|
*$$ = $3; |
|
} |
|
; |
|
|
|
optsig: { |
|
$$ = NULL; |
|
} |
|
| '[' cpptype '(' arglist ')' ']' { |
|
$$ = sipMalloc(sizeof (signatureDef)); |
|
|
|
*$$ = $4; |
|
$$ -> result = $2; |
|
} |
|
; |
|
|
|
optvirtual: { |
|
$$ = FALSE; |
|
} |
|
| TK_VIRTUAL { |
|
$$ = TRUE; |
|
} |
|
; |
|
|
|
function: cpptype TK_NAME '(' arglist ')' optconst optexceptions optabstract optflags optsig ';' optdocstring methodcode virtualcatchercode { |
|
if (notSkipping()) |
|
{ |
|
applyTypeFlags(currentModule, &$1, &$9); |
|
|
|
$4.result = $1; |
|
|
|
newFunction(currentSpec, currentModule, currentScope(), NULL, |
|
sectionFlags, currentIsStatic, currentIsSignal, |
|
currentIsSlot, currentOverIsVirt, $2, &$4, $6, $8, &$9, |
|
$13, $14, $7, $10, $12); |
|
} |
|
|
|
currentIsStatic = FALSE; |
|
currentIsSignal = FALSE; |
|
currentIsSlot = FALSE; |
|
currentOverIsVirt = FALSE; |
|
} |
|
| cpptype TK_OPERATOR '=' '(' cpptype ')' ';' { |
|
/* |
|
* It looks like an assignment operator (though we don't bother to |
|
* check the types) so make sure it is private. |
|
*/ |
|
if (notSkipping()) |
|
{ |
|
classDef *cd = currentScope(); |
|
|
|
if (cd == NULL || !(sectionFlags & SECT_IS_PRIVATE)) |
|
yyerror("Assignment operators may only be defined as private"); |
|
|
|
setCannotAssign(cd); |
|
} |
|
|
|
currentIsStatic = FALSE; |
|
currentIsSignal = FALSE; |
|
currentIsSlot = FALSE; |
|
currentOverIsVirt = FALSE; |
|
} |
|
| cpptype TK_OPERATOR operatorname '(' arglist ')' optconst optexceptions optabstract optflags optsig ';' methodcode virtualcatchercode { |
|
if (notSkipping()) |
|
{ |
|
classDef *cd = currentScope(); |
|
|
|
applyTypeFlags(currentModule, &$1, &$10); |
|
|
|
/* Handle the unary '+' and '-' operators. */ |
|
if ((cd != NULL && $5.nrArgs == 0) || (cd == NULL && $5.nrArgs == 1)) |
|
{ |
|
if (strcmp($3, "__add__") == 0) |
|
$3 = "__pos__"; |
|
else if (strcmp($3, "__sub__") == 0) |
|
$3 = "__neg__"; |
|
} |
|
|
|
$5.result = $1; |
|
|
|
newFunction(currentSpec, currentModule, cd, NULL, |
|
sectionFlags, currentIsStatic, currentIsSignal, |
|
currentIsSlot, currentOverIsVirt, $3, &$5, $7, $9, |
|
&$10, $13, $14, $8, $11, NULL); |
|
} |
|
|
|
currentIsStatic = FALSE; |
|
currentIsSignal = FALSE; |
|
currentIsSlot = FALSE; |
|
currentOverIsVirt = FALSE; |
|
} |
|
| TK_OPERATOR cpptype '(' arglist ')' optconst optexceptions optabstract optflags optsig ';' methodcode virtualcatchercode { |
|
if (notSkipping()) |
|
{ |
|
char *sname; |
|
classDef *scope = currentScope(); |
|
|
|
if (scope == NULL || $4.nrArgs != 0) |
|
yyerror("Operator casts must be specified in a class and have no arguments"); |
|
|
|
applyTypeFlags(currentModule, &$2, &$9); |
|
|
|
switch ($2.atype) |
|
{ |
|
case defined_type: |
|
sname = NULL; |
|
break; |
|
|
|
case bool_type: |
|
case cbool_type: |
|
case short_type: |
|
case ushort_type: |
|
case int_type: |
|
case cint_type: |
|
case uint_type: |
|
sname = "__int__"; |
|
break; |
|
|
|
case long_type: |
|
case ulong_type: |
|
case longlong_type: |
|
case ulonglong_type: |
|
sname = "__long__"; |
|
break; |
|
|
|
case float_type: |
|
case cfloat_type: |
|
case double_type: |
|
case cdouble_type: |
|
sname = "__float__"; |
|
break; |
|
|
|
default: |
|
yyerror("Unsupported operator cast"); |
|
} |
|
|
|
if (sname != NULL) |
|
{ |
|
$4.result = $2; |
|
|
|
newFunction(currentSpec, currentModule, scope, NULL, |
|
sectionFlags, currentIsStatic, currentIsSignal, |
|
currentIsSlot, currentOverIsVirt, sname, &$4, $6, |
|
$8, &$9, $12, $13, $7, $10, NULL); |
|
} |
|
else |
|
{ |
|
argList *al; |
|
|
|
/* Check it doesn't already exist. */ |
|
for (al = scope->casts; al != NULL; al = al->next) |
|
if (compareScopedNames($2.u.snd, al->arg.u.snd) == 0) |
|
yyerror("This operator cast has already been specified in this class"); |
|
|
|
al = sipMalloc(sizeof (argList)); |
|
al->arg = $2; |
|
al->next = scope->casts; |
|
|
|
scope->casts = al; |
|
} |
|
} |
|
|
|
currentIsStatic = FALSE; |
|
currentIsSignal = FALSE; |
|
currentIsSlot = FALSE; |
|
currentOverIsVirt = FALSE; |
|
} |
|
; |
|
|
|
operatorname: '+' {$$ = "__add__";} |
|
| '-' {$$ = "__sub__";} |
|
| '*' {$$ = "__mul__";} |
|
| '/' {$$ = "__div__";} |
|
| '%' {$$ = "__mod__";} |
|
| '&' {$$ = "__and__";} |
|
| '|' {$$ = "__or__";} |
|
| '^' {$$ = "__xor__";} |
|
| '<' '<' {$$ = "__lshift__";} |
|
| '>' '>' {$$ = "__rshift__";} |
|
| '+' '=' {$$ = "__iadd__";} |
|
| '-' '=' {$$ = "__isub__";} |
|
| '*' '=' {$$ = "__imul__";} |
|
| '/' '=' {$$ = "__idiv__";} |
|
| '%' '=' {$$ = "__imod__";} |
|
| '&' '=' {$$ = "__iand__";} |
|
| '|' '=' {$$ = "__ior__";} |
|
| '^' '=' {$$ = "__ixor__";} |
|
| '<' '<' '=' {$$ = "__ilshift__";} |
|
| '>' '>' '=' {$$ = "__irshift__";} |
|
| '~' {$$ = "__invert__";} |
|
| '(' ')' {$$ = "__call__";} |
|
| '[' ']' {$$ = "__getitem__";} |
|
| '<' {$$ = "__lt__";} |
|
| '<' '=' {$$ = "__le__";} |
|
| '=' '=' {$$ = "__eq__";} |
|
| '!' '=' {$$ = "__ne__";} |
|
| '>' {$$ = "__gt__";} |
|
| '>' '=' {$$ = "__ge__";} |
|
; |
|
|
|
optconst: { |
|
$$ = FALSE; |
|
} |
|
| TK_CONST { |
|
$$ = TRUE; |
|
} |
|
; |
|
|
|
optabstract: { |
|
$$ = 0; |
|
} |
|
| '=' TK_NUMBER { |
|
if ($2 != 0) |
|
yyerror("Abstract virtual function '= 0' expected"); |
|
|
|
$$ = TRUE; |
|
} |
|
; |
|
|
|
optflags: { |
|
$$.nrFlags = 0; |
|
} |
|
| '/' flaglist '/' { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
|
|
flaglist: flag { |
|
$$.flags[0] = $1; |
|
$$.nrFlags = 1; |
|
} |
|
| flaglist ',' flag { |
|
/* Check there is room. */ |
|
|
|
if ($1.nrFlags == MAX_NR_FLAGS) |
|
yyerror("Too many optional flags"); |
|
|
|
$$ = $1; |
|
|
|
$$.flags[$$.nrFlags++] = $3; |
|
} |
|
; |
|
|
|
flag: TK_NAME { |
|
$$.ftype = bool_flag; |
|
$$.fname = $1; |
|
} |
|
| TK_NAME '=' flagvalue { |
|
$$ = $3; |
|
$$.fname = $1; |
|
} |
|
; |
|
|
|
flagvalue: dottedname { |
|
$$.ftype = (strchr($1, '.') != NULL) ? dotted_name_flag : name_flag; |
|
$$.fvalue.sval = $1; |
|
} |
|
| TK_NAME ':' optnumber '-' optnumber { |
|
apiVersionRangeDef *avd; |
|
int from, to; |
|
|
|
$$.ftype = api_range_flag; |
|
|
|
/* Check that the API is known. */ |
|
if ((avd = findAPI(currentSpec, $1)) == NULL) |
|
yyerror("unknown API name in API annotation"); |
|
|
|
if (inMainModule()) |
|
setIsUsedName(avd->api_name); |
|
|
|
/* Unbounded values are represented by 0. */ |
|
if ((from = $3) < 0) |
|
from = 0; |
|
|
|
if ((to = $5) < 0) |
|
to = 0; |
|
|
|
$$.fvalue.aval = convertAPIRange(currentModule, avd->api_name, |
|
from, to); |
|
} |
|
| TK_STRING { |
|
$$.ftype = string_flag; |
|
$$.fvalue.sval = convertFeaturedString($1); |
|
} |
|
| TK_NUMBER { |
|
$$.ftype = integer_flag; |
|
$$.fvalue.ival = $1; |
|
} |
|
; |
|
|
|
docstring: TK_DOCSTRING codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
optdocstring: { |
|
$$ = NULL; |
|
} |
|
| docstring |
|
; |
|
|
|
methodcode: { |
|
$$ = NULL; |
|
} |
|
| TK_METHODCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
virtualcatchercode: { |
|
$$ = NULL; |
|
} |
|
| TK_VIRTUALCATCHERCODE codeblock { |
|
$$ = $2; |
|
} |
|
; |
|
|
|
arglist: rawarglist { |
|
int a, nrrxcon, nrrxdis, nrslotcon, nrslotdis, nrarray, nrarraysize; |
|
|
|
nrrxcon = nrrxdis = nrslotcon = nrslotdis = nrarray = nrarraysize = 0; |
|
|
|
for (a = 0; a < $1.nrArgs; ++a) |
|
{ |
|
argDef *ad = &$1.args[a]; |
|
|
|
switch (ad -> atype) |
|
{ |
|
case rxcon_type: |
|
++nrrxcon; |
|
break; |
|
|
|
case rxdis_type: |
|
++nrrxdis; |
|
break; |
|
|
|
case slotcon_type: |
|
++nrslotcon; |
|
break; |
|
|
|
case slotdis_type: |
|
++nrslotdis; |
|
break; |
|
} |
|
|
|
if (isArray(ad)) |
|
++nrarray; |
|
|
|
if (isArraySize(ad)) |
|
++nrarraysize; |
|
} |
|
|
|
if (nrrxcon != nrslotcon || nrrxcon > 1) |
|
yyerror("SIP_RXOBJ_CON and SIP_SLOT_CON must both be given and at most once"); |
|
|
|
if (nrrxdis != nrslotdis || nrrxdis > 1) |
|
yyerror("SIP_RXOBJ_DIS and SIP_SLOT_DIS must both be given and at most once"); |
|
|
|
if (nrarray != nrarraysize || nrarray > 1) |
|
yyerror("/Array/ and /ArraySize/ must both be given and at most once"); |
|
|
|
$$ = $1; |
|
} |
|
; |
|
|
|
rawarglist: { |
|
/* No arguments. */ |
|
|
|
$$.nrArgs = 0; |
|
} |
|
| argvalue { |
|
/* The single or first argument. */ |
|
|
|
$$.args[0] = $1; |
|
$$.nrArgs = 1; |
|
} |
|
| rawarglist ',' argvalue { |
|
/* Check that it wasn't ...(,arg...). */ |
|
if ($1.nrArgs == 0) |
|
yyerror("First argument of the list is missing"); |
|
|
|
/* Check there is nothing after an ellipsis. */ |
|
if ($1.args[$1.nrArgs - 1].atype == ellipsis_type) |
|
yyerror("An ellipsis must be at the end of the argument list"); |
|
|
|
/* |
|
* If this argument has no default value, then the |
|
* previous one mustn't either. |
|
*/ |
|
if ($3.defval == NULL && $1.args[$1.nrArgs - 1].defval != NULL) |
|
yyerror("Compulsory argument given after optional argument"); |
|
|
|
/* Check there is room. */ |
|
if ($1.nrArgs == MAX_NR_ARGS) |
|
yyerror("Internal error - increase the value of MAX_NR_ARGS"); |
|
|
|
$$ = $1; |
|
|
|
$$.args[$$.nrArgs] = $3; |
|
$$.nrArgs++; |
|
} |
|
; |
|
|
|
argvalue: TK_SIPSIGNAL optname optflags optassign { |
|
$$.atype = signal_type; |
|
$$.argflags = ARG_IS_CONST; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $2); |
|
$$.defval = $4; |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_SIPSLOT optname optflags optassign { |
|
$$.atype = slot_type; |
|
$$.argflags = ARG_IS_CONST; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $2); |
|
$$.defval = $4; |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_SIPANYSLOT optname optflags optassign { |
|
$$.atype = anyslot_type; |
|
$$.argflags = ARG_IS_CONST; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $2); |
|
$$.defval = $4; |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_SIPRXCON optname optflags { |
|
$$.atype = rxcon_type; |
|
$$.argflags = 0; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $2); |
|
|
|
if (findOptFlag(&$3, "SingleShot", bool_flag) != NULL) |
|
$$.argflags |= ARG_SINGLE_SHOT; |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_SIPRXDIS optname optflags { |
|
$$.atype = rxdis_type; |
|
$$.argflags = 0; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $2); |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_SIPSLOTCON '(' arglist ')' optname optflags { |
|
$$.atype = slotcon_type; |
|
$$.argflags = ARG_IS_CONST; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $5); |
|
|
|
memset(&$3.result, 0, sizeof (argDef)); |
|
$3.result.atype = void_type; |
|
|
|
$$.u.sa = sipMalloc(sizeof (signatureDef)); |
|
*$$.u.sa = $3; |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_SIPSLOTDIS '(' arglist ')' optname optflags { |
|
$$.atype = slotdis_type; |
|
$$.argflags = ARG_IS_CONST; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $5); |
|
|
|
memset(&$3.result, 0, sizeof (argDef)); |
|
$3.result.atype = void_type; |
|
|
|
$$.u.sa = sipMalloc(sizeof (signatureDef)); |
|
*$$.u.sa = $3; |
|
|
|
currentSpec -> sigslots = TRUE; |
|
} |
|
| TK_QOBJECT optname optflags { |
|
$$.atype = qobject_type; |
|
$$.argflags = 0; |
|
$$.nrderefs = 0; |
|
$$.name = cacheName(currentSpec, $2); |
|
} |
|
| argtype optassign { |
|
$$ = $1; |
|
$$.defval = $2; |
|
} |
|
; |
|
|
|
varmember: |
|
TK_SIGNAL_METHOD {currentIsSignal = TRUE;} simple_varmem |
|
| TK_SLOT_METHOD {currentIsSlot = TRUE;} simple_varmem |
|
| simple_varmem |
|
; |
|
|
|
simple_varmem: |
|
TK_STATIC {currentIsStatic = TRUE;} varmem |
|
| varmem |
|
; |
|
|
|
varmem: |
|
member |
|
| variable |
|
; |
|
|
|
member: |
|
TK_VIRTUAL {currentOverIsVirt = TRUE;} function |
|
| function |
|
; |
|
|
|
variable: cpptype TK_NAME optflags ';' optaccesscode optgetcode optsetcode { |
|
if (notSkipping()) |
|
{ |
|
/* Check the section. */ |
|
|
|
if (sectionFlags != 0) |
|
{ |
|
if ((sectionFlags & SECT_IS_PUBLIC) == 0) |
|
yyerror("Class variables must be in the public section"); |
|
|
|
if (!currentIsStatic && $5 != NULL) |
|
yyerror("%AccessCode cannot be specified for non-static class variables"); |
|
} |
|
|
|
if (currentIsStatic && currentSpec -> genc) |
|
yyerror("Cannot have static members in a C structure"); |
|
|
|
applyTypeFlags(currentModule, &$1, &$3); |
|
|
|
if ($6 != NULL || $7 != NULL) |
|
{ |
|
if ($5 != NULL) |
|
yyerror("Cannot mix %AccessCode and %GetCode or %SetCode"); |
|
|
|
if (currentScope() == NULL) |
|
yyerror("Cannot specify %GetCode or %SetCode for global variables"); |
|
} |
|
|
|
newVar(currentSpec,currentModule,$2,currentIsStatic,&$1,&$3,$5,$6,$7); |
|
} |
|
|
|
currentIsStatic = FALSE; |
|
} |
|
; |
|
|
|
cpptype: TK_CONST basetype deref optref { |
|
$$ = $2; |
|
$$.nrderefs += $3; |
|
$$.argflags |= ARG_IS_CONST | $4; |
|
} |
|
| basetype deref optref { |
|
$$ = $1; |
|
$$.nrderefs += $2; |
|
$$.argflags |= $3; |
|
} |
|
; |
|
|
|
argtype: cpptype optname optflags { |
|
$$ = $1; |
|
$$.name = cacheName(currentSpec, $2); |
|
|
|
if (getAllowNone(&$3)) |
|
$$.argflags |= ARG_ALLOW_NONE; |
|
|
|
if (findOptFlag(&$3,"GetWrapper",bool_flag) != NULL) |
|
$$.argflags |= ARG_GET_WRAPPER; |
|
|
|
if (findOptFlag(&$3,"Array",bool_flag) != NULL) |
|
$$.argflags |= ARG_ARRAY; |
|
|
|
if (findOptFlag(&$3,"ArraySize",bool_flag) != NULL) |
|
$$.argflags |= ARG_ARRAY_SIZE; |
|
|
|
if (getTransfer(&$3)) |
|
$$.argflags |= ARG_XFERRED; |
|
|
|
if (findOptFlag(&$3,"TransferThis",bool_flag) != NULL) |
|
$$.argflags |= ARG_THIS_XFERRED; |
|
|
|
if (findOptFlag(&$3,"TransferBack",bool_flag) != NULL) |
|
$$.argflags |= ARG_XFERRED_BACK; |
|
|
|
if (findOptFlag(&$3, "KeepReference", bool_flag) != NULL) |
|
{ |
|
$$.argflags |= ARG_KEEP_REF; |
|
$$.key = currentModule->next_key++; |
|
} |
|
|
|
if (findOptFlag(&$3,"In",bool_flag) != NULL) |
|
$$.argflags |= ARG_IN; |
|
|
|
if (findOptFlag(&$3,"Out",bool_flag) != NULL) |
|
$$.argflags |= ARG_OUT; |
|
|
|
if (findOptFlag(&$3, "ResultSize", bool_flag) != NULL) |
|
$$.argflags |= ARG_RESULT_SIZE; |
|
|
|
if (findOptFlag(&$3, "NoCopy", bool_flag) != NULL) |
|
$$.argflags |= ARG_NO_COPY; |
|
|
|
if (findOptFlag(&$3,"Constrained",bool_flag) != NULL) |
|
{ |
|
$$.argflags |= ARG_CONSTRAINED; |
|
|
|
switch ($$.atype) |
|
{ |
|
case bool_type: |
|
$$.atype = cbool_type; |
|
break; |
|
|
|
case int_type: |
|
$$.atype = cint_type; |
|
break; |
|
|
|
case float_type: |
|
$$.atype = cfloat_type; |
|
break; |
|
|
|
case double_type: |
|
$$.atype = cdouble_type; |
|
break; |
|
} |
|
} |
|
|
|
applyTypeFlags(currentModule, &$$, &$3); |
|
$$.docval = getDocValue(&$3); |
|
} |
|
; |
|
|
|
optref: { |
|
$$ = 0; |
|
} |
|
| '&' { |
|
if (currentSpec -> genc) |
|
yyerror("References not allowed in a C module"); |
|
|
|
$$ = ARG_IS_REF; |
|
} |
|
; |
|
|
|
deref: { |
|
$$ = 0; |
|
} |
|
| deref '*' { |
|
$$ = $1 + 1; |
|
} |
|
; |
|
|
|
basetype: scopedname { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = defined_type; |
|
$$.u.snd = $1; |
|
|
|
/* Try and resolve typedefs as early as possible. */ |
|
resolveAnyTypedef(currentSpec, &$$); |
|
} |
|
| scopedname '<' cpptypelist '>' { |
|
templateDef *td; |
|
|
|
td = sipMalloc(sizeof(templateDef)); |
|
td->fqname = $1; |
|
td->types = $3; |
|
|
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = template_type; |
|
$$.u.td = td; |
|
} |
|
| TK_STRUCT scopedname { |
|
memset(&$$, 0, sizeof (argDef)); |
|
|
|
/* In a C module all structures must be defined. */ |
|
if (currentSpec -> genc) |
|
{ |
|
$$.atype = defined_type; |
|
$$.u.snd = $2; |
|
} |
|
else |
|
{ |
|
$$.atype = struct_type; |
|
$$.u.sname = $2; |
|
} |
|
} |
|
| TK_UNSIGNED TK_SHORT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = ushort_type; |
|
} |
|
| TK_SHORT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = short_type; |
|
} |
|
| TK_UNSIGNED { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = uint_type; |
|
} |
|
| TK_UNSIGNED TK_INT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = uint_type; |
|
} |
|
| TK_INT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = int_type; |
|
} |
|
| TK_LONG { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = long_type; |
|
} |
|
| TK_UNSIGNED TK_LONG { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = ulong_type; |
|
} |
|
| TK_LONG TK_LONG { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = longlong_type; |
|
} |
|
| TK_UNSIGNED TK_LONG TK_LONG { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = ulonglong_type; |
|
} |
|
| TK_FLOAT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = float_type; |
|
} |
|
| TK_DOUBLE { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = double_type; |
|
} |
|
| TK_BOOL { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = bool_type; |
|
} |
|
| TK_SIGNED TK_CHAR { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = sstring_type; |
|
} |
|
| TK_UNSIGNED TK_CHAR { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = ustring_type; |
|
} |
|
| TK_CHAR { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = string_type; |
|
} |
|
| TK_WCHAR_T { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = wstring_type; |
|
} |
|
| TK_VOID { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = void_type; |
|
} |
|
| TK_PYOBJECT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pyobject_type; |
|
} |
|
| TK_PYTUPLE { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pytuple_type; |
|
} |
|
| TK_PYLIST { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pylist_type; |
|
} |
|
| TK_PYDICT { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pydict_type; |
|
} |
|
| TK_PYCALLABLE { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pycallable_type; |
|
} |
|
| TK_PYSLICE { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pyslice_type; |
|
} |
|
| TK_PYTYPE { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = pytype_type; |
|
} |
|
| TK_ELLIPSIS { |
|
memset(&$$, 0, sizeof (argDef)); |
|
$$.atype = ellipsis_type; |
|
} |
|
; |
|
|
|
cpptypelist: cpptype { |
|
/* The single or first type. */ |
|
|
|
$$.args[0] = $1; |
|
$$.nrArgs = 1; |
|
} |
|
| cpptypelist ',' cpptype { |
|
/* Check there is nothing after an ellipsis. */ |
|
if ($1.args[$1.nrArgs - 1].atype == ellipsis_type) |
|
yyerror("An ellipsis must be at the end of the argument list"); |
|
|
|
/* Check there is room. */ |
|
if ($1.nrArgs == MAX_NR_ARGS) |
|
yyerror("Internal error - increase the value of MAX_NR_ARGS"); |
|
|
|
$$ = $1; |
|
|
|
$$.args[$$.nrArgs] = $3; |
|
$$.nrArgs++; |
|
} |
|
; |
|
|
|
optexceptions: { |
|
$$ = NULL; |
|
} |
|
| TK_THROW '(' exceptionlist ')' { |
|
if (currentSpec->genc) |
|
yyerror("Exceptions not allowed in a C module"); |
|
|
|
$$ = $3; |
|
} |
|
; |
|
|
|
exceptionlist: { |
|
/* Empty list so use a blank. */ |
|
|
|
$$ = sipMalloc(sizeof (throwArgs)); |
|
$$ -> nrArgs = 0; |
|
} |
|
| scopedname { |
|
/* The only or first exception. */ |
|
|
|
$$ = sipMalloc(sizeof (throwArgs)); |
|
$$ -> nrArgs = 1; |
|
$$ -> args[0] = findException(currentSpec, $1, FALSE); |
|
} |
|
| exceptionlist ',' scopedname { |
|
/* Check that it wasn't ...(,arg...). */ |
|
|
|
if ($1 -> nrArgs == 0) |
|
yyerror("First exception of throw specifier is missing"); |
|
|
|
/* Check there is room. */ |
|
|
|
if ($1 -> nrArgs == MAX_NR_ARGS) |
|
yyerror("Internal error - increase the value of MAX_NR_ARGS"); |
|
|
|
$$ = $1; |
|
$$ -> args[$$ -> nrArgs++] = findException(currentSpec, $3, FALSE); |
|
} |
|
; |
|
|
|
%% |
|
|
|
|
|
/* |
|
* Parse the specification. |
|
*/ |
|
void parse(sipSpec *spec, FILE *fp, char *filename, stringList *tsl, |
|
stringList *xfl, int kwdArgs, int protHack) |
|
{ |
|
classTmplDef *tcd; |
|
|
|
/* Initialise the spec. */ |
|
|
|
spec->modules = NULL; |
|
spec->namecache = NULL; |
|
spec->ifacefiles = NULL; |
|
spec->classes = NULL; |
|
spec->classtemplates = NULL; |
|
spec->exceptions = NULL; |
|
spec->mappedtypes = NULL; |
|
spec->mappedtypetemplates = NULL; |
|
spec->enums = NULL; |
|
spec->vars = NULL; |
|
spec->typedefs = NULL; |
|
spec->exphdrcode = NULL; |
|
spec->docs = NULL; |
|
spec->sigslots = FALSE; |
|
spec->genc = -1; |
|
spec->plugins = NULL; |
|
|
|
currentSpec = spec; |
|
neededQualifiers = tsl; |
|
excludedQualifiers = xfl; |
|
currentModule = NULL; |
|
currentMappedType = NULL; |
|
currentOverIsVirt = FALSE; |
|
currentCtorIsExplicit = FALSE; |
|
currentIsStatic = FALSE; |
|
currentIsSignal = FALSE; |
|
currentIsSlot = FALSE; |
|
currentIsTemplate = FALSE; |
|
previousFile = NULL; |
|
skipStackPtr = 0; |
|
currentScopeIdx = 0; |
|
sectionFlags = 0; |
|
defaultKwdArgs = kwdArgs; |
|
makeProtPublic = protHack; |
|
|
|
newModule(fp, filename); |
|
spec->module = currentModule; |
|
|
|
yyparse(); |
|
|
|
handleEOF(); |
|
handleEOM(); |
|
|
|
/* |
|
* Go through each template class and remove it from the list of classes. |
|
*/ |
|
for (tcd = spec->classtemplates; tcd != NULL; tcd = tcd->next) |
|
{ |
|
classDef **cdp; |
|
|
|
for (cdp = &spec->classes; *cdp != NULL; cdp = &(*cdp)->next) |
|
if (*cdp == tcd->cd) |
|
{ |
|
ifaceFileDef **ifdp; |
|
|
|
/* Remove the interface file as well. */ |
|
for (ifdp = &spec->ifacefiles; *ifdp != NULL; ifdp = &(*ifdp)->next) |
|
if (*ifdp == tcd->cd->iff) |
|
{ |
|
*ifdp = (*ifdp)->next; |
|
break; |
|
} |
|
|
|
*cdp = (*cdp)->next; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
/* |
|
* Tell the parser that a complete file has now been read. |
|
*/ |
|
void parserEOF(char *name, parserContext *pc) |
|
{ |
|
previousFile = sipStrdup(name); |
|
currentContext = *pc; |
|
} |
|
|
|
|
|
/* |
|
* Append a class definition to a class list if it doesn't already appear. |
|
* Append is needed specifically for the list of super-classes because the |
|
* order is important to Python. |
|
*/ |
|
void appendToClassList(classList **clp,classDef *cd) |
|
{ |
|
classList *new; |
|
|
|
/* Find the end of the list. */ |
|
|
|
while (*clp != NULL) |
|
{ |
|
if ((*clp) -> cd == cd) |
|
return; |
|
|
|
clp = &(*clp) -> next; |
|
} |
|
|
|
new = sipMalloc(sizeof (classList)); |
|
|
|
new -> cd = cd; |
|
new -> next = NULL; |
|
|
|
*clp = new; |
|
} |
|
|
|
|
|
/* |
|
* Create a new module for the current specification and make it current. |
|
*/ |
|
static void newModule(FILE *fp, char *filename) |
|
{ |
|
moduleDef *mod; |
|
|
|
parseFile(fp, filename, currentModule, FALSE); |
|
|
|
mod = allocModule(); |
|
mod->file = filename; |
|
|
|
if (currentModule != NULL) |
|
mod->defexception = currentModule->defexception; |
|
|
|
currentModule = mod; |
|
} |
|
|
|
|
|
/* |
|
* Allocate and initialise the memory for a new module. |
|
*/ |
|
static moduleDef *allocModule() |
|
{ |
|
moduleDef *newmod, **tailp; |
|
|
|
newmod = sipMalloc(sizeof (moduleDef)); |
|
|
|
newmod->version = -1; |
|
newmod->encoding = no_type; |
|
newmod->qobjclass = -1; |
|
newmod->nrvirthandlers = -1; |
|
newmod->next_key = 1; |
|
|
|
/* |
|
* The consolidated module support needs these to be in order that they |
|
* appeared. |
|
*/ |
|
for (tailp = ¤tSpec->modules; *tailp != NULL; tailp = &(*tailp)->next) |
|
; |
|
|
|
*tailp = newmod; |
|
|
|
return newmod; |
|
} |
|
|
|
|
|
/* |
|
* Switch to parsing a new file. |
|
*/ |
|
static void parseFile(FILE *fp, char *name, moduleDef *prevmod, int optional) |
|
{ |
|
parserContext pc; |
|
|
|
pc.filename = name; |
|
pc.ifdepth = skipStackPtr; |
|
pc.prevmod = prevmod; |
|
|
|
if (setInputFile(fp, &pc, optional)) |
|
currentContext = pc; |
|
} |
|
|
|
|
|
/* |
|
* Find an interface file, or create a new one. |
|
*/ |
|
ifaceFileDef *findIfaceFile(sipSpec *pt, moduleDef *mod, scopedNameDef *fqname, |
|
ifaceFileType iftype, apiVersionRangeDef *api_range, argDef *ad) |
|
{ |
|
ifaceFileDef *iff, *first_alt = NULL; |
|
|
|
/* See if the name is already used. */ |
|
|
|
for (iff = pt->ifacefiles; iff != NULL; iff = iff->next) |
|
{ |
|
if (compareScopedNames(iff->fqcname, fqname) != 0) |
|
continue; |
|
|
|
/* |
|
* If they are both versioned then assume the user knows what they are |
|
* doing. |
|
*/ |
|
if (iff->api_range != NULL && api_range != NULL && iff->module == mod) |
|
{ |
|
/* Remember the first of the alternate APIs. */ |
|
if ((first_alt = iff->first_alt) == NULL) |
|
first_alt = iff; |
|
|
|
break; |
|
} |
|
|
|
/* |
|
* They must be the same type except that we allow a class if we want |
|
* an exception. This is because we allow classes to be used before |
|
* they are defined. |
|
*/ |
|
if (iff->type != iftype) |
|
if (iftype != exception_iface || iff->type != class_iface) |
|
yyerror("A class, exception, namespace or mapped type has already been defined with the same name"); |
|
|
|
/* Ignore an external class declared in another module. */ |
|
if (iftype == class_iface && iff->module != mod) |
|
{ |
|
classDef *cd; |
|
|
|
for (cd = pt->classes; cd != NULL; cd = cd->next) |
|
if (cd->iff == iff) |
|
break; |
|
|
|
if (cd != NULL && iff->module != NULL && isExternal(cd)) |
|
continue; |
|
} |
|
|
|
/* |
|
* If this is a mapped type with the same name defined in a different |
|
* module, then check that this type isn't the same as any of the |
|
* mapped types defined in that module. |
|
*/ |
|
if (iftype == mappedtype_iface && iff->module != mod) |
|
{ |
|
mappedTypeDef *mtd; |
|
|
|
/* |
|
* This is a bit of a cheat. With consolidated modules it's |
|
* possible to have two implementations of a mapped type in |
|
* different branches of the module hierarchy. We assume that, if |
|
* there really are multiple implementations in the same branch, |
|
* then it will be picked up in a non-consolidated build. |
|
*/ |
|
if (isConsolidated(pt->module)) |
|
continue; |
|
|
|
for (mtd = pt->mappedtypes; mtd != NULL; mtd = mtd->next) |
|
{ |
|
if (mtd->iff != iff) |
|
continue; |
|
|
|
if (ad->atype != template_type || |
|
mtd->type.atype != template_type || |
|
sameBaseType(ad, &mtd->type)) |
|
yyerror("Mapped type has already been defined in another module"); |
|
} |
|
|
|
/* |
|
* If we got here then we have a mapped type based on an existing |
|
* template, but with unique parameters. We don't want to use |
|
* interface files from other modules, so skip this one. |
|
*/ |
|
|
|
continue; |
|
} |
|
|
|
/* Ignore a namespace defined in another module. */ |
|
if (iftype == namespace_iface && iff->module != mod) |
|
continue; |
|
|
|
return iff; |
|
} |
|
|
|
iff = sipMalloc(sizeof (ifaceFileDef)); |
|
|
|
iff->name = cacheName(pt, scopedNameToString(fqname)); |
|
iff->api_range = api_range; |
|
|
|
if (first_alt != NULL) |
|
{ |
|
iff->first_alt = first_alt; |
|
iff->next_alt = first_alt->next_alt; |
|
|
|
first_alt->next_alt = iff; |
|
} |
|
else |
|
{ |
|
/* This is the first alternate so point to itself. */ |
|
iff->first_alt = iff; |
|
} |
|
|
|
iff->type = iftype; |
|
iff->ifacenr = -1; |
|
iff->fqcname = fqname; |
|
iff->module = NULL; |
|
iff->hdrcode = NULL; |
|
iff->used = NULL; |
|
iff->next = pt->ifacefiles; |
|
|
|
pt->ifacefiles = iff; |
|
|
|
return iff; |
|
} |
|
|
|
|
|
/* |
|
* Find a class definition in a parse tree. |
|
*/ |
|
static classDef *findClass(sipSpec *pt, ifaceFileType iftype, |
|
apiVersionRangeDef *api_range, scopedNameDef *fqname) |
|
{ |
|
return findClassWithInterface(pt, findIfaceFile(pt, currentModule, fqname, iftype, api_range, NULL)); |
|
} |
|
|
|
|
|
/* |
|
* Find a class definition given an existing interface file. |
|
*/ |
|
static classDef *findClassWithInterface(sipSpec *pt, ifaceFileDef *iff) |
|
{ |
|
classDef *cd; |
|
|
|
for (cd = pt -> classes; cd != NULL; cd = cd -> next) |
|
if (cd -> iff == iff) |
|
return cd; |
|
|
|
/* Create a new one. */ |
|
cd = sipMalloc(sizeof (classDef)); |
|
|
|
cd->iff = iff; |
|
cd->pyname = cacheName(pt, classBaseName(cd)); |
|
cd->next = pt->classes; |
|
|
|
pt->classes = cd; |
|
|
|
return cd; |
|
} |
|
|
|
|
|
/* |
|
* Add an interface file to an interface file list if it isn't already there. |
|
*/ |
|
void addToUsedList(ifaceFileList **ifflp, ifaceFileDef *iff) |
|
{ |
|
/* Make sure we don't try to add an interface file to its own list. */ |
|
if (&iff->used != ifflp) |
|
{ |
|
ifaceFileList *iffl; |
|
|
|
while ((iffl = *ifflp) != NULL) |
|
{ |
|
/* Don't bother if it is already there. */ |
|
if (iffl->iff == iff) |
|
return; |
|
|
|
ifflp = &iffl -> next; |
|
} |
|
|
|
iffl = sipMalloc(sizeof (ifaceFileList)); |
|
|
|
iffl->iff = iff; |
|
iffl->next = NULL; |
|
|
|
*ifflp = iffl; |
|
} |
|
} |
|
|
|
|
|
/* |
|
* Find an undefined (or create a new) exception definition in a parse tree. |
|
*/ |
|
static exceptionDef *findException(sipSpec *pt, scopedNameDef *fqname, int new) |
|
{ |
|
exceptionDef *xd, **tail; |
|
ifaceFileDef *iff; |
|
classDef *cd; |
|
|
|
iff = findIfaceFile(pt, currentModule, fqname, exception_iface, NULL, NULL); |
|
|
|
/* See if it is an existing one. */ |
|
for (xd = pt->exceptions; xd != NULL; xd = xd->next) |
|
if (xd->iff == iff) |
|
return xd; |
|
|
|
/* |
|
* If it is an exception interface file then we have never seen this |
|
* name before. We require that exceptions are defined before being |
|
* used, but don't make the same requirement of classes (for reasons of |
|
* backwards compatibility). Therefore the name must be reinterpreted |
|
* as a (as yet undefined) class. |
|
*/ |
|
if (new) |
|
{ |
|
if (iff->type == exception_iface) |
|
cd = NULL; |
|
else |
|
yyerror("There is already a class with the same name or the exception has been used before being defined"); |
|
} |
|
else |
|
{ |
|
if (iff->type == exception_iface) |
|
iff->type = class_iface; |
|
|
|
cd = findClassWithInterface(pt, iff); |
|
} |
|
|
|
/* Create a new one. */ |
|
xd = sipMalloc(sizeof (exceptionDef)); |
|
|
|
xd->exceptionnr = -1; |
|
xd->iff = iff; |
|
xd->pyname = NULL; |
|
xd->cd = cd; |
|
xd->bibase = NULL; |
|
xd->base = NULL; |
|
xd->raisecode = NULL; |
|
xd->next = NULL; |
|
|
|
/* Append it to the list. */ |
|
for (tail = &pt->exceptions; *tail != NULL; tail = &(*tail)->next) |
|
; |
|
|
|
*tail = xd; |
|
|
|
return xd; |
|
} |
|
|
|
|
|
/* |
|
* Find an undefined (or create a new) class definition in a parse tree. |
|
*/ |
|
static classDef *newClass(sipSpec *pt, ifaceFileType iftype, |
|
apiVersionRangeDef *api_range, scopedNameDef *fqname) |
|
{ |
|
int flags; |
|
classDef *cd, *scope; |
|
codeBlock *hdrcode; |
|
|
|
if (sectionFlags & SECT_IS_PRIVATE) |
|
yyerror("Classes, structs and namespaces must be in the public or protected sections"); |
|
|
|
flags = 0; |
|
|
|
if ((scope = currentScope()) != NULL) |
|
{ |
|
if (sectionFlags & SECT_IS_PROT && !makeProtPublic) |
|
{ |
|
flags = CLASS_IS_PROTECTED; |
|
|
|
if (scope->iff->type == class_iface) |
|
setHasShadow(scope); |
|
} |
|
|
|
/* Header code from outer scopes is also included. */ |
|
hdrcode = scope->iff->hdrcode; |
|
} |
|
else |
|
hdrcode = NULL; |
|
|
|
if (pt -> genc) |
|
{ |
|
/* C structs are always global types. */ |
|
while (fqname -> next != NULL) |
|
fqname = fqname -> next; |
|
|
|
scope = NULL; |
|
} |
|
|
|
cd = findClass(pt, iftype, api_range, fqname); |
|
|
|
/* Check it hasn't already been defined. */ |
|
if (iftype != namespace_iface && cd->iff->module != NULL) |
|
yyerror("The struct/class has already been defined"); |
|
|
|
/* Complete the initialisation. */ |
|
cd->classflags |= flags; |
|
cd->ecd = scope; |
|
cd->iff->module = currentModule; |
|
|
|
if (currentIsTemplate) |
|
setIsTemplateClass(cd); |
|
|
|
appendCodeBlock(&cd->iff->hdrcode, hdrcode); |
|
|
|
/* See if it is a namespace extender. */ |
|
if (iftype == namespace_iface) |
|
{ |
|
classDef *ns; |
|
|
|
for (ns = pt->classes; ns != NULL; ns = ns->next) |
|
{ |
|
if (ns == cd) |
|
continue; |
|
|
|
if (ns->iff->type != namespace_iface) |
|
continue; |
|
|
|
if (compareScopedNames(ns->iff->fqcname, fqname) != 0) |
|
continue; |
|
|
|
cd->real = ns; |
|
break; |
|
} |
|
} |
|
|
|
return cd; |
|
} |
|
|
|
|
|
/* |
|
* Tidy up after finishing a class definition. |
|
*/ |
|
static void finishClass(sipSpec *pt, moduleDef *mod, classDef *cd, |
|
optFlags *of) |
|
{ |
|
const char *pyname; |
|
optFlag *flg; |
|
|
|
/* Get the Python name and see if it is different to the C++ name. */ |
|
pyname = getPythonName(of, classBaseName(cd)); |
|
|
|
cd->pyname = NULL; |
|
checkAttributes(pt, mod, cd->ecd, NULL, pyname, FALSE); |
|
cd->pyname = cacheName(pt, pyname); |
|
|
|
if ((flg = findOptFlag(of, "Metatype", dotted_name_flag)) != NULL) |
|
cd->metatype = cacheName(pt, flg->fvalue.sval); |
|
|
|
if ((flg = findOptFlag(of, "Supertype", dotted_name_flag)) != NULL) |
|
cd->supertype = cacheName(pt, flg->fvalue.sval); |
|
|
|
if ((flg = findOptFlag(of, "PyQt4Flags", integer_flag)) != NULL) |
|
cd->pyqt4_flags = flg->fvalue.ival; |
|
|
|
if (findOptFlag(of, "PyQt4NoQMetaObject", bool_flag) != NULL) |
|
setPyTQt4NoTQMetaObject(cd); |
|
|
|
if (isOpaque(cd)) |
|
{ |
|
if (findOptFlag(of, "External", bool_flag) != NULL) |
|
setIsExternal(cd); |
|
} |
|
else |
|
{ |
|
int seq_might, seq_not; |
|
memberDef *md; |
|
|
|
if (findOptFlag(of, "NoDefaultCtors", bool_flag) != NULL) |
|
setNoDefaultCtors(cd); |
|
|
|
if (cd -> ctors == NULL) |
|
{ |
|
if (!noDefaultCtors(cd)) |
|
{ |
|
/* Provide a default ctor. */ |
|
|
|
cd->ctors = sipMalloc(sizeof (ctorDef)); |
|
|
|
cd->ctors->ctorflags = SECT_IS_PUBLIC; |
|
cd->ctors->pysig.result.atype = void_type; |
|
cd->ctors->cppsig = &cd->ctors->pysig; |
|
|
|
cd->defctor = cd->ctors; |
|
|
|
setCanCreate(cd); |
|
} |
|
} |
|
else if (cd -> defctor == NULL) |
|
{ |
|
ctorDef *ct, *last = NULL; |
|
|
|
for (ct = cd -> ctors; ct != NULL; ct = ct -> next) |
|
{ |
|
if (!isPublicCtor(ct)) |
|
continue; |
|
|
|
if (ct -> pysig.nrArgs == 0 || ct -> pysig.args[0].defval != NULL) |
|
{ |
|
cd -> defctor = ct; |
|
break; |
|
} |
|
|
|
if (last == NULL) |
|
last = ct; |
|
} |
|
|
|
/* The last resort is the first public ctor. */ |
|
if (cd->defctor == NULL) |
|
cd->defctor = last; |
|
} |
|
|
|
if (getDeprecated(of)) |
|
setIsDeprecatedClass(cd); |
|
|
|
if (cd->convtocode != NULL && getAllowNone(of)) |
|
setClassHandlesNone(cd); |
|
|
|
if (findOptFlag(of,"Abstract",bool_flag) != NULL) |
|
{ |
|
setIsAbstractClass(cd); |
|
setIsIncomplete(cd); |
|
resetCanCreate(cd); |
|
} |
|
|
|
/* We assume a public dtor if nothing specific was provided. */ |
|
if (!isDtor(cd)) |
|
setIsPublicDtor(cd); |
|
|
|
if (findOptFlag(of, "DelayDtor", bool_flag) != NULL) |
|
{ |
|
setIsDelayedDtor(cd); |
|
setHasDelayedDtors(mod); |
|
} |
|
|
|
/* |
|
* There are subtle differences between the add and concat methods and |
|
* the multiply and repeat methods. The number versions can have their |
|
* operands swapped and may return NotImplemented. If the user has |
|
* used the /Numeric/ annotation or there are other numeric operators |
|
* then we use add/multiply. Otherwise, if there are indexing |
|
* operators then we use concat/repeat. |
|
*/ |
|
seq_might = seq_not = FALSE; |
|
|
|
for (md = cd -> members; md != NULL; md = md -> next) |
|
switch (md -> slot) |
|
{ |
|
case getitem_slot: |
|
case setitem_slot: |
|
case delitem_slot: |
|
/* This might be a sequence. */ |
|
seq_might = TRUE; |
|
break; |
|
|
|
case sub_slot: |
|
case isub_slot: |
|
case div_slot: |
|
case idiv_slot: |
|
case mod_slot: |
|
case imod_slot: |
|
case floordiv_slot: |
|
case ifloordiv_slot: |
|
case truediv_slot: |
|
case itruediv_slot: |
|
case pos_slot: |
|
case neg_slot: |
|
/* This is definately not a sequence. */ |
|
seq_not = TRUE; |
|
break; |
|
} |
|
|
|
if (!seq_not && seq_might) |
|
for (md = cd -> members; md != NULL; md = md -> next) |
|
{ |
|
/* Ignore if the user has been explicit. */ |
|
if (isNumeric(md)) |
|
continue; |
|
|
|
switch (md -> slot) |
|
{ |
|
case add_slot: |
|
md -> slot = concat_slot; |
|
break; |
|
|
|
case iadd_slot: |
|
md -> slot = iconcat_slot; |
|
break; |
|
|
|
case mul_slot: |
|
md -> slot = repeat_slot; |
|
break; |
|
|
|
case imul_slot: |
|
md -> slot = irepeat_slot; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (inMainModule()) |
|
{ |
|
setIsUsedName(cd->iff->name); |
|
setIsUsedName(cd->pyname); |
|
} |
|
} |
|
|
|
|
|
/* |
|
* Return the encoded name of a template (ie. including its argument types) as |
|
* a scoped name. |
|
*/ |
|
scopedNameDef *encodedTemplateName(templateDef *td) |
|
{ |
|
int a; |
|
scopedNameDef *snd; |
|
|
|
snd = copyScopedName(td->fqname); |
|
|
|
for (a = 0; a < td->types.nrArgs; ++a) |
|
{ |
|
char buf[50]; |
|
int flgs; |
|
scopedNameDef *arg_snd; |
|
argDef *ad = &td->types.args[a]; |
|
|
|
flgs = 0; |
|
|