diff options
Diffstat (limited to 'gcc/d/dmd/parse.c')
-rw-r--r-- | gcc/d/dmd/parse.c | 8492 |
1 files changed, 0 insertions, 8492 deletions
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c deleted file mode 100644 index e1f1321..0000000 --- a/gcc/d/dmd/parse.c +++ /dev/null @@ -1,8492 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c - */ - -// This is the D parser - -#include "root/dsystem.h" // strlen(),memcpy() -#include "root/rmem.h" - -#include "mars.h" -#include "lexer.h" -#include "parse.h" -#include "init.h" -#include "attrib.h" -#include "cond.h" -#include "mtype.h" -#include "template.h" -#include "staticassert.h" -#include "expression.h" -#include "statement.h" -#include "module.h" -#include "dsymbol.h" -#include "import.h" -#include "declaration.h" -#include "aggregate.h" -#include "enum.h" -#include "id.h" -#include "version.h" -#include "aliasthis.h" -#include "nspace.h" -#include "hdrgen.h" - -Expression *typeToExpression(Type *t); - -// Support C cast syntax: -// (type)(expression) -#define CCASTSYNTAX 1 - -// Support postfix C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - -Parser::Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment) - : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false) -{ - //printf("Parser::Parser()\n"); - mod = module; - md = NULL; - linkage = LINKd; - endloc = Loc(); - inBrackets = 0; - lookingForElse = Loc(); - //nextToken(); // start up the scanner -} - -/********************* - * Use this constructor for string mixins. - * Input: - * loc location in source file of mixin - */ -Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment) - : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false) -{ - //printf("Parser::Parser()\n"); - scanloc = loc; - - if (loc.filename) - { - /* Create a pseudo-filename for the mixin string, as it may not even exist - * in the source file. - */ - char *filename = (char *)mem.xmalloc(strlen(loc.filename) + 7 + sizeof(loc.linnum) * 3 + 1); - sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum); - scanloc.filename = filename; - } - - mod = module; - md = NULL; - linkage = LINKd; - endloc = Loc(); - inBrackets = 0; - lookingForElse = Loc(); - //nextToken(); // start up the scanner -} - -Dsymbols *Parser::parseModule() -{ - const utf8_t *comment = token.blockComment; - bool isdeprecated = false; - Expression *msg = NULL; - Expressions *udas = NULL; - Dsymbols *decldefs; - - Token *tk; - if (skipAttributes(&token, &tk) && tk->value == TOKmodule) - { - while (token.value != TOKmodule) - { - switch (token.value) - { - case TOKdeprecated: - { - // deprecated (...) module ... - if (isdeprecated) - { - error("there is only one deprecation attribute allowed for module declaration"); - } - else - { - isdeprecated = true; - } - nextToken(); - if (token.value == TOKlparen) - { - check(TOKlparen); - msg = parseAssignExp(); - check(TOKrparen); - } - break; - } - case TOKat: - { - Expressions *exps = NULL; - StorageClass stc = parseAttribute(&exps); - - if (stc == STCproperty || stc == STCnogc || stc == STCdisable || - stc == STCsafe || stc == STCtrusted || stc == STCsystem) - { - error("@%s attribute for module declaration is not supported", token.toChars()); - } - else - { - udas = UserAttributeDeclaration::concat(udas, exps); - } - if (stc) - nextToken(); - break; - } - default: - { - error("`module` expected instead of %s", token.toChars()); - nextToken(); - break; - } - } - } - } - - if (udas) - { - Dsymbols *a = new Dsymbols(); - UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a); - mod->userAttribDecl = udad; - } - - // ModuleDeclation leads off - if (token.value == TOKmodule) - { - Loc loc = token.loc; - - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following module"); - goto Lerr; - } - else - { - Identifiers *a = NULL; - Identifier *id; - - id = token.ident; - while (nextToken() == TOKdot) - { - if (!a) - a = new Identifiers(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following package"); - goto Lerr; - } - id = token.ident; - } - - md = new ModuleDeclaration(loc, a, id); - md->isdeprecated = isdeprecated; - md->msg = msg; - - if (token.value != TOKsemicolon) - error("`;` expected following module declaration instead of %s", token.toChars()); - nextToken(); - addComment(mod, comment); - } - } - - decldefs = parseDeclDefs(0); - if (token.value != TOKeof) - { - error(token.loc, "unrecognized declaration"); - goto Lerr; - } - return decldefs; - -Lerr: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - return new Dsymbols(); -} - -static StorageClass parseDeprecatedAttribute(Parser *p, Expression **msg) -{ - if (p->peekNext() != TOKlparen) - return STCdeprecated; - - p->nextToken(); - p->check(TOKlparen); - Expression *e = p->parseAssignExp(); - p->check(TOKrparen); - if (*msg) - { - p->error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", - (*msg)->toChars(), e->toChars()); - } - *msg = e; - return STCundefined; -} - -struct PrefixAttributes -{ - StorageClass storageClass; - Expression *depmsg; - LINK link; - Prot protection; - bool setAlignment; - Expression *ealign; - Expressions *udas; - const utf8_t *comment; - - PrefixAttributes() - : storageClass(STCundefined), - depmsg(NULL), - link(LINKdefault), - protection(Prot::undefined), - setAlignment(false), - ealign(NULL), - udas(NULL), - comment(NULL) - { - } -}; - -Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes *pAttrs) -{ - Dsymbol *lastDecl = NULL; // used to link unittest to its previous declaration - if (!pLastDecl) - pLastDecl = &lastDecl; - - LINK linksave = linkage; // save global state - - //printf("Parser::parseDeclDefs()\n"); - Dsymbols *decldefs = new Dsymbols(); - do - { - // parse result - Dsymbol *s = NULL; - Dsymbols *a = NULL; - - PrefixAttributes attrs; - if (!once || !pAttrs) - { - pAttrs = &attrs; - pAttrs->comment = token.blockComment; - } - Prot::Kind prot; - StorageClass stc; - Condition *condition; - - linkage = linksave; - - switch (token.value) - { - case TOKenum: - { - /* Determine if this is a manifest constant declaration, - * or a conventional enum. - */ - Token *t = peek(&token); - if (t->value == TOKlcurly || t->value == TOKcolon) - s = parseEnum(); - else if (t->value != TOKidentifier) - goto Ldeclaration; - else - { - t = peek(t); - if (t->value == TOKlcurly || t->value == TOKcolon || - t->value == TOKsemicolon) - s = parseEnum(); - else - goto Ldeclaration; - } - break; - } - - case TOKimport: - a = parseImport(); - // keep pLastDecl - break; - - case TOKtemplate: - s = (Dsymbol *)parseTemplateDeclaration(); - break; - - case TOKmixin: - { - Loc loc = token.loc; - switch (peekNext()) - { - case TOKlparen: - { - // mixin(string) - nextToken(); - Expressions *exps = parseArguments(); - check(TOKsemicolon); - s = new CompileDeclaration(loc, exps); - break; - } - case TOKtemplate: - // mixin template - nextToken(); - s = (Dsymbol *)parseTemplateDeclaration(true); - break; - - default: - s = parseMixin(); - break; - } - break; - } - - case TOKwchar: case TOKdchar: - case TOKbool: case TOKchar: - case TOKint8: case TOKuns8: - case TOKint16: case TOKuns16: - case TOKint32: case TOKuns32: - case TOKint64: case TOKuns64: - case TOKint128: case TOKuns128: - case TOKfloat32: case TOKfloat64: case TOKfloat80: - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: - case TOKvoid: - case TOKalias: - case TOKidentifier: - case TOKsuper: - case TOKtypeof: - case TOKdot: - case TOKvector: - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - case TOKtraits: - Ldeclaration: - a = parseDeclarations(false, pAttrs, pAttrs->comment); - if (a && a->length) - *pLastDecl = (*a)[a->length-1]; - break; - - case TOKthis: - if (peekNext() == TOKdot) - goto Ldeclaration; - else - s = parseCtor(pAttrs); - break; - - case TOKtilde: - s = parseDtor(pAttrs); - break; - - case TOKinvariant: - { - Token *t = peek(&token); - if (t->value == TOKlparen || t->value == TOKlcurly) - { - // invariant { statements... } - // invariant() { statements... } - // invariant (expression); - s = parseInvariant(pAttrs); - } - else - { - error("invariant body expected, not `%s`", token.toChars()); - goto Lerror; - } - break; - } - - case TOKunittest: - if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration) - { - s = parseUnitTest(pAttrs); - if (*pLastDecl) - (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s; - } - else - { - // Skip over unittest block by counting { } - Loc loc = token.loc; - int braces = 0; - while (1) - { - nextToken(); - switch (token.value) - { - case TOKlcurly: - ++braces; - continue; - - case TOKrcurly: - if (--braces) - continue; - nextToken(); - break; - - case TOKeof: - /* { */ - error(loc, "closing } of unittest not found before end of file"); - goto Lerror; - - default: - continue; - } - break; - } - // Workaround 14894. Add an empty unittest declaration to keep - // the number of symbols in this scope independent of -unittest. - s = new UnitTestDeclaration(loc, token.loc, STCundefined, NULL); - } - break; - - case TOKnew: - s = parseNew(pAttrs); - break; - - case TOKdelete: - s = parseDelete(pAttrs); - break; - - case TOKcolon: - case TOKlcurly: - error("declaration expected, not `%s`",token.toChars()); - goto Lerror; - - case TOKrcurly: - case TOKeof: - if (once) - error("declaration expected, not `%s`", token.toChars()); - return decldefs; - - case TOKstatic: - { - TOK next = peekNext(); - if (next == TOKthis) - s = parseStaticCtor(pAttrs); - else if (next == TOKtilde) - s = parseStaticDtor(pAttrs); - else if (next == TOKassert) - s = parseStaticAssert(); - else if (next == TOKif) - { - condition = parseStaticIfCondition(); - Dsymbols *athen; - if (token.value == TOKcolon) - athen = parseBlock(pLastDecl); - else - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = token.loc; - athen = parseBlock(pLastDecl); - lookingForElse = lookingForElseSave; - } - Dsymbols *aelse = NULL; - if (token.value == TOKelse) - { - Loc elseloc = token.loc; - nextToken(); - aelse = parseBlock(pLastDecl); - checkDanglingElse(elseloc); - } - s = new StaticIfDeclaration(condition, athen, aelse); - } - else if (next == TOKimport) - { - a = parseImport(); - // keep pLastDecl - } - else if (next == TOKforeach || next == TOKforeach_reverse) - { - s = parseForeachStaticDecl(token.loc, pLastDecl); - } - else - { - stc = STCstatic; - goto Lstc; - } - break; - } - - case TOKconst: - if (peekNext() == TOKlparen) - goto Ldeclaration; - stc = STCconst; - goto Lstc; - - case TOKimmutable: - if (peekNext() == TOKlparen) - goto Ldeclaration; - stc = STCimmutable; - goto Lstc; - - case TOKshared: - { - TOK next = peekNext(); - if (next == TOKlparen) - goto Ldeclaration; - if (next == TOKstatic) - { - TOK next2 = peekNext2(); - if (next2 == TOKthis) - { - s = parseSharedStaticCtor(pAttrs); - break; - } - if (next2 == TOKtilde) - { - s = parseSharedStaticDtor(pAttrs); - break; - } - } - stc = STCshared; - goto Lstc; - } - - case TOKwild: - if (peekNext() == TOKlparen) - goto Ldeclaration; - stc = STCwild; - goto Lstc; - - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKgshared: stc = STCgshared; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; - case TOKat: - { - Expressions *exps = NULL; - stc = parseAttribute(&exps); - if (stc) - goto Lstc; // it's a predefined attribute - // no redundant/conflicting check for UDAs - pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps); - goto Lautodecl; - } - Lstc: - pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc); - nextToken(); - - Lautodecl: - Token *tk; - - /* Look for auto initializers: - * storage_class identifier = initializer; - * storage_class identifier(...) = initializer; - */ - if (token.value == TOKidentifier && - skipParensIf(peek(&token), &tk) && - tk->value == TOKassign) - { - a = parseAutoDeclarations(pAttrs->storageClass, pAttrs->comment); - pAttrs->storageClass = STCundefined; - if (a && a->length) - *pLastDecl = (*a)[a->length-1]; - if (pAttrs->udas) - { - s = new UserAttributeDeclaration(pAttrs->udas, a); - pAttrs->udas = NULL; - } - break; - } - - /* Look for return type inference for template functions. - */ - if (token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) && - (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || - tk->value == TOKout || tk->value == TOKdo || - (tk->value == TOKidentifier && tk->ident == Id::_body)) - ) - { - a = parseDeclarations(true, pAttrs, pAttrs->comment); - if (a && a->length) - *pLastDecl = (*a)[a->length-1]; - if (pAttrs->udas) - { - s = new UserAttributeDeclaration(pAttrs->udas, a); - pAttrs->udas = NULL; - } - break; - } - - a = parseBlock(pLastDecl, pAttrs); - if (pAttrs->storageClass != STCundefined) - { - s = new StorageClassDeclaration(pAttrs->storageClass, a); - pAttrs->storageClass = STCundefined; - } - if (pAttrs->udas) - { - if (s) - { - a = new Dsymbols(); - a->push(s); - } - s = new UserAttributeDeclaration(pAttrs->udas, a); - pAttrs->udas = NULL; - } - break; - - case TOKdeprecated: - { - if (StorageClass _stc = parseDeprecatedAttribute(this, &pAttrs->depmsg)) - { - stc = _stc; - goto Lstc; - } - a = parseBlock(pLastDecl, pAttrs); - if (pAttrs->depmsg) - { - s = new DeprecatedDeclaration(pAttrs->depmsg, a); - pAttrs->depmsg = NULL; - } - break; - } - - case TOKlbracket: - { - if (peekNext() == TOKrbracket) - error("empty attribute list is not allowed"); - error("use @(attributes) instead of [attributes]"); - Expressions *exps = parseArguments(); - // no redundant/conflicting check for UDAs - - pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps); - a = parseBlock(pLastDecl, pAttrs); - if (pAttrs->udas) - { - s = new UserAttributeDeclaration(pAttrs->udas, a); - pAttrs->udas = NULL; - } - break; - } - - case TOKextern: - { - if (peek(&token)->value != TOKlparen) - { - stc = STCextern; - goto Lstc; - } - - Loc linkLoc = token.loc; - Identifiers *idents = NULL; - CPPMANGLE cppmangle = CPPMANGLEdefault; - bool cppMangleOnly = false; - LINK link = parseLinkage(&idents, &cppmangle, &cppMangleOnly); - if (pAttrs->link != LINKdefault) - { - if (pAttrs->link != link) - { - error("conflicting linkage extern (%s) and extern (%s)", - linkageToChars(pAttrs->link), linkageToChars(link)); - } - else if (idents) - { - // Allow: - // extern(C++, foo) extern(C++, bar) void foo(); - // to be equivalent with: - // extern(C++, foo.bar) void foo(); - } - else - error("redundant linkage extern (%s)", linkageToChars(pAttrs->link)); - } - pAttrs->link = link; - this->linkage = link; - a = parseBlock(pLastDecl, pAttrs); - if (idents) - { - assert(link == LINKcpp); - assert(idents->length); - for (size_t i = idents->length; i;) - { - Identifier *id = (*idents)[--i]; - if (s) - { - a = new Dsymbols(); - a->push(s); - } - s = new Nspace(linkLoc, id, a, cppMangleOnly); - } - delete idents; - pAttrs->link = LINKdefault; - } - else if (pAttrs->link != LINKdefault) - { - s = new LinkDeclaration(pAttrs->link, a); - pAttrs->link = LINKdefault; - } - else if (cppmangle != CPPMANGLEdefault) - { - assert(link == LINKcpp); - s = new CPPMangleDeclaration(cppmangle, a); - } - break; - } - - case TOKprivate: prot = Prot::private_; goto Lprot; - case TOKpackage: prot = Prot::package_; goto Lprot; - case TOKprotected: prot = Prot::protected_; goto Lprot; - case TOKpublic: prot = Prot::public_; goto Lprot; - case TOKexport: prot = Prot::export_; goto Lprot; - Lprot: - { - if (pAttrs->protection.kind != Prot::undefined) - { - if (pAttrs->protection.kind != prot) - error("conflicting protection attribute `%s` and `%s`", - protectionToChars(pAttrs->protection.kind), protectionToChars(prot)); - else - error("redundant protection attribute `%s`", protectionToChars(prot)); - } - pAttrs->protection.kind = prot; - - nextToken(); - - // optional qualified package identifier to bind - // protection to - Identifiers *pkg_prot_idents = NULL; - if (pAttrs->protection.kind == Prot::package_ && token.value == TOKlparen) - { - pkg_prot_idents = parseQualifiedIdentifier("protection package"); - - if (pkg_prot_idents) - check(TOKrparen); - else - { - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - break; - } - } - - Loc attrloc = token.loc; - a = parseBlock(pLastDecl, pAttrs); - if (pAttrs->protection.kind != Prot::undefined) - { - if (pAttrs->protection.kind == Prot::package_ && pkg_prot_idents) - s = new ProtDeclaration(attrloc, pkg_prot_idents, a); - else - s = new ProtDeclaration(attrloc, pAttrs->protection, a); - - pAttrs->protection = Prot(Prot::undefined); - } - break; - } - - case TOKalign: - { - const Loc attrLoc = token.loc; - - nextToken(); - - Expression *e = NULL; // default - if (token.value == TOKlparen) - { - nextToken(); - e = parseAssignExp(); - check(TOKrparen); - } - - if (pAttrs->setAlignment) - { - const char *s1 = ""; - OutBuffer buf1; - if (e) - { - buf1.printf("(%s)", e->toChars()); - s1 = buf1.peekChars(); - } - error("redundant alignment attribute align%s", s1); - } - - pAttrs->setAlignment = true; - pAttrs->ealign = e; - a = parseBlock(pLastDecl, pAttrs); - if (pAttrs->setAlignment) - { - s = new AlignDeclaration(attrLoc, pAttrs->ealign, a); - pAttrs->setAlignment = false; - pAttrs->ealign = NULL; - } - break; - } - - case TOKpragma: - { - Expressions *args = NULL; - Loc loc = token.loc; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { - error("pragma(identifier) expected"); - goto Lerror; - } - Identifier *ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...) - else - check(TOKrparen); // pragma(identifier) - - Dsymbols *a2 = NULL; - if (token.value == TOKsemicolon) - { - /* Bugzilla 2354: Accept single semicolon as an empty - * DeclarationBlock following attribute. - * - * Attribute DeclarationBlock - * Pragma DeclDef - * ; - */ - nextToken(); - } - else - a2 = parseBlock(pLastDecl); - s = new PragmaDeclaration(loc, ident, args, a2); - break; - } - - case TOKdebug: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new DebugSymbol(token.loc, token.ident); - else if (token.value == TOKint32v || token.value == TOKint64v) - s = new DebugSymbol(token.loc, (unsigned)token.uns64value); - else - { - error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); - nextToken(); - break; - } - - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new VersionSymbol(token.loc, token.ident); - else if (token.value == TOKint32v || token.value == TOKint64v) - s = new VersionSymbol(token.loc, (unsigned)token.uns64value); - else - { - error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); - nextToken(); - break; - } - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - { - Dsymbols *athen; - if (token.value == TOKcolon) - athen = parseBlock(pLastDecl); - else - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = token.loc; - athen = parseBlock(pLastDecl); - lookingForElse = lookingForElseSave; - } - Dsymbols *aelse = NULL; - if (token.value == TOKelse) - { - Loc elseloc = token.loc; - nextToken(); - aelse = parseBlock(pLastDecl); - checkDanglingElse(elseloc); - } - s = new ConditionalDeclaration(condition, athen, aelse); - break; - } - - case TOKsemicolon: // empty declaration - //error("empty declaration"); - nextToken(); - continue; - - default: - error("declaration expected, not `%s`",token.toChars()); - Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - s = NULL; - continue; - } - - if (s) - { - if (!s->isAttribDeclaration()) - *pLastDecl = s; - decldefs->push(s); - addComment(s, pAttrs->comment); - } - else if (a && a->length) - { - decldefs->append(a); - } - } while (!once); - - linkage = linksave; - - return decldefs; -} - -/********************************************* - * Give error on redundant/conflicting storage class. - * - * TODO: remove deprecation in 2.068 and keep only error - */ - -StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc, - bool deprec) -{ - if ((storageClass & stc) || - (storageClass & STCin && stc & (STCconst | STCscope)) || - (stc & STCin && storageClass & (STCconst | STCscope))) - { - OutBuffer buf; - stcToBuffer(&buf, stc); - if (deprec) - deprecation("redundant attribute `%s`", buf.peekChars()); - else - error("redundant attribute `%s`", buf.peekChars()); - return storageClass | stc; - } - - storageClass |= stc; - - if (stc & (STCconst | STCimmutable | STCmanifest)) - { - StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest); - if (u & (u - 1)) - error("conflicting attribute `%s`", Token::toChars(token.value)); - } - if (stc & (STCgshared | STCshared | STCtls)) - { - StorageClass u = storageClass & (STCgshared | STCshared | STCtls); - if (u & (u - 1)) - error("conflicting attribute `%s`", Token::toChars(token.value)); - } - if (stc & (STCsafe | STCsystem | STCtrusted)) - { - StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted); - if (u & (u - 1)) - error("conflicting attribute `@%s`", token.toChars()); - } - - return storageClass; -} - -/*********************************************** - * Parse attribute, lexer is on '@'. - * Input: - * pudas array of UDAs to append to - * Returns: - * storage class if a predefined attribute; also scanner remains on identifier. - * 0 if not a predefined attribute - * *pudas set if user defined attribute, scanner is past UDA - * *pudas NULL if not a user defined attribute - */ - -StorageClass Parser::parseAttribute(Expressions **pudas) -{ - nextToken(); - Expressions *udas = NULL; - StorageClass stc = 0; - if (token.value == TOKidentifier) - { - if (token.ident == Id::property) - stc = STCproperty; - else if (token.ident == Id::nogc) - stc = STCnogc; - else if (token.ident == Id::safe) - stc = STCsafe; - else if (token.ident == Id::trusted) - stc = STCtrusted; - else if (token.ident == Id::system) - stc = STCsystem; - else if (token.ident == Id::disable) - stc = STCdisable; - else if (token.ident == Id::future) - stc = STCfuture; - else - { - // Allow identifier, template instantiation, or function call - Expression *exp = parsePrimaryExp(); - if (token.value == TOKlparen) - { - Loc loc = token.loc; - exp = new CallExp(loc, exp, parseArguments()); - } - - udas = new Expressions(); - udas->push(exp); - } - } - else if (token.value == TOKlparen) - { - // @( ArgumentList ) - // Concatenate with existing - if (peekNext() == TOKrparen) - error("empty attribute list is not allowed"); - udas = parseArguments(); - } - else - { - error("@identifier or @(ArgumentList) expected, not @%s", token.toChars()); - } - - if (stc) - { - } - else if (udas) - { - *pudas = UserAttributeDeclaration::concat(*pudas, udas); - } - else - error("valid attributes are @property, @safe, @trusted, @system, @disable"); - return stc; -} - -/*********************************************** - * Parse const/immutable/shared/inout/nothrow/pure postfix - */ - -StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas) -{ - while (1) - { - StorageClass stc; - switch (token.value) - { - case TOKconst: stc = STCconst; break; - case TOKimmutable: stc = STCimmutable; break; - case TOKshared: stc = STCshared; break; - case TOKwild: stc = STCwild; break; - case TOKnothrow: stc = STCnothrow; break; - case TOKpure: stc = STCpure; break; - case TOKreturn: stc = STCreturn; break; - case TOKscope: stc = STCscope; break; - case TOKat: - { - Expressions *udas = NULL; - stc = parseAttribute(&udas); - if (udas) - { - if (pudas) - *pudas = UserAttributeDeclaration::concat(*pudas, udas); - else - { - // Disallow: - // void function() @uda fp; - // () @uda { return 1; } - error("user-defined attributes cannot appear as postfixes"); - } - continue; - } - break; - } - - default: - return storageClass; - } - storageClass = appendStorageClass(storageClass, stc, true); - nextToken(); - } -} - -StorageClass Parser::parseTypeCtor() -{ - StorageClass storageClass = STCundefined; - - while (1) - { - if (peek(&token)->value == TOKlparen) - return storageClass; - - StorageClass stc; - switch (token.value) - { - case TOKconst: stc = STCconst; break; - case TOKimmutable: stc = STCimmutable; break; - case TOKshared: stc = STCshared; break; - case TOKwild: stc = STCwild; break; - - default: - return storageClass; - } - storageClass = appendStorageClass(storageClass, stc); - nextToken(); - } -} - -/******************************************** - * Parse declarations after an align, protection, or extern decl. - */ - -Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs) -{ - Dsymbols *a = NULL; - - //printf("parseBlock()\n"); - switch (token.value) - { - case TOKsemicolon: - error("declaration expected following attribute, not `;`"); - nextToken(); - break; - - case TOKeof: - error("declaration expected following attribute, not EOF"); - break; - - case TOKlcurly: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = Loc(); - - nextToken(); - a = parseDeclDefs(0, pLastDecl); - if (token.value != TOKrcurly) - { - /* { */ - error("matching `}` expected, not %s", token.toChars()); - } - else - nextToken(); - lookingForElse = lookingForElseSave; - break; - } - - case TOKcolon: - nextToken(); - a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket - break; - - default: - a = parseDeclDefs(1, pLastDecl, pAttrs); - break; - } - return a; -} - -/********************************** - * Parse a static assertion. - * Current token is 'static'. - */ - -StaticAssert *Parser::parseStaticAssert() -{ - Loc loc = token.loc; - Expression *exp; - Expression *msg = NULL; - - //printf("parseStaticAssert()\n"); - nextToken(); - nextToken(); - check(TOKlparen); - exp = parseAssignExp(); - if (token.value == TOKcomma) - { - nextToken(); - if (token.value != TOKrparen) - { - msg = parseAssignExp(); - if (token.value == TOKcomma) - nextToken(); - } - } - check(TOKrparen); - check(TOKsemicolon); - return new StaticAssert(loc, exp, msg); -} - -/*********************************** - * Parse typeof(expression). - * Current token is on the 'typeof'. - */ - -TypeQualified *Parser::parseTypeof() -{ - TypeQualified *t; - Loc loc = token.loc; - - nextToken(); - check(TOKlparen); - if (token.value == TOKreturn) // typeof(return) - { - nextToken(); - t = new TypeReturn(loc); - } - else - { - Expression *exp = parseExpression(); // typeof(expression) - t = new TypeTypeof(loc, exp); - } - check(TOKrparen); - return t; -} - -/*********************************** - * Parse __vector(type). - * Current token is on the '__vector'. - */ - -Type *Parser::parseVector() -{ - nextToken(); - check(TOKlparen); - Type *tb = parseType(); - check(TOKrparen); - return new TypeVector(tb); -} - -/*********************************** - * Parse: - * extern (linkage) - * extern (C++, namespaces) - * extern (C++, "namespace", "namespaces", ...) - * The parser is on the 'extern' token. - */ - -LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle, bool *pcppMangleOnly) -{ - Identifiers *idents = NULL; - CPPMANGLE cppmangle = CPPMANGLEdefault; - bool cppMangleOnly = false; - LINK link = LINKdefault; - nextToken(); - assert(token.value == TOKlparen); - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (id == Id::Windows) - link = LINKwindows; - else if (id == Id::D) - link = LINKd; - else if (id == Id::C) - { - link = LINKc; - if (token.value == TOKplusplus) - { - link = LINKcpp; - nextToken(); - if (token.value == TOKcomma) // , namespaces or class or struct - { - nextToken(); - if (token.value == TOKclass || token.value == TOKstruct) - { - cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct; - nextToken(); - } - else if (token.value == TOKstring) // extern(C++, "namespace", "namespaces") - { - cppMangleOnly = true; - idents = new Identifiers(); - - while (1) - { - StringExp *stringExp = (StringExp *)parsePrimaryExp(); - const char *name = stringExp->toPtr(); - if (stringExp->len == 0) - { - error("invalid zero length C++ namespace"); - idents = NULL; - break; - } - else if (!Identifier::isValidIdentifier(name)) - { - error("expected valid identifier for C++ namespace but got `%s`", name); - idents = NULL; - break; - } - idents->push(Identifier::idPool(name)); - if (token.value == TOKcomma) - { - nextToken(); - if (token.value != TOKstring) - { - error("string expected following `,` for C++ namespace, not `%s`", token.toChars()); - idents = NULL; - break; - } - } - else - break; - } - } - else - { - idents = new Identifiers(); - while (1) - { - if (token.value == TOKidentifier) - { - Identifier *idn = token.ident; - idents->push(idn); - nextToken(); - if (token.value == TOKdot) - { - nextToken(); - continue; - } - } - else - { - error("identifier expected for C++ namespace"); - idents = NULL; // error occurred, invalidate list of elements. - } - break; - } - } - } - } - } - else if (id == Id::Objective) // Looking for tokens "Objective-C" - { - if (token.value == TOKmin) - { - nextToken(); - if (token.ident == Id::C) - { - link = LINKobjc; - nextToken(); - } - else - goto LinvalidLinkage; - } - else - goto LinvalidLinkage; - } - else if (id == Id::System) - { - link = LINKsystem; - } - else - { - LinvalidLinkage: - error("valid linkage identifiers are D, C, C++, Objective-C, Windows, System"); - link = LINKd; - } - } - else - { - link = LINKd; // default - } - check(TOKrparen); - *pidents = idents; - *pcppmangle = cppmangle; - *pcppMangleOnly = cppMangleOnly; - return link; -} - -/*********************************** - * Parse ident1.ident2.ident3 - * - * Params: - * entity = what qualified identifier is expected to resolve into. - * Used only for better error message - * - * Returns: - * array of identifiers with actual qualified one stored last - */ -Identifiers *Parser::parseQualifiedIdentifier(const char *entity) -{ - Identifiers *qualified = NULL; - - do - { - nextToken(); - if (token.value != TOKidentifier) - { - error("%s expected as dot-separated identifiers, got `%s`", - entity, token.toChars()); - return NULL; - } - - Identifier *id = token.ident; - if (!qualified) - qualified = new Identifiers(); - qualified->push(id); - - nextToken(); - } while (token.value == TOKdot); - - return qualified; -} - -/************************************** - * Parse a debug conditional - */ - -Condition *Parser::parseDebugCondition() -{ - Condition *c; - - if (token.value == TOKlparen) - { - nextToken(); - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v || token.value == TOKint64v) - level = (unsigned)token.uns64value; - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - c = new DebugCondition(mod, level, id); - } - else - c = new DebugCondition(mod, 1, NULL); - return c; - -} - -/************************************** - * Parse a version conditional - */ - -Condition *Parser::parseVersionCondition() -{ - Condition *c; - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKlparen) - { - nextToken(); - /* Allow: - * version (unittest) - * version (assert) - * even though they are keywords - */ - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v || token.value == TOKint64v) - level = (unsigned)token.uns64value; - else if (token.value == TOKunittest) - id = Identifier::idPool(Token::toChars(TOKunittest)); - else if (token.value == TOKassert) - id = Identifier::idPool(Token::toChars(TOKassert)); - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - - } - else - error("(condition) expected following version"); - c = new VersionCondition(mod, level, id); - return c; - -} - -/*********************************************** - * static if (expression) - * body - * else - * body - * Current token is 'static'. - */ - -Condition *Parser::parseStaticIfCondition() -{ - Expression *exp; - Condition *condition; - Loc loc = token.loc; - - nextToken(); - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseAssignExp(); - check(TOKrparen); - } - else - { - error("(expression) expected following static if"); - exp = NULL; - } - condition = new StaticIfCondition(loc, exp); - return condition; -} - - -/***************************************** - * Parse a constructor definition: - * this(parameters) { body } - * or postblit: - * this(this) { body } - * or constructor template: - * this(templateparameters)(parameters) { body } - * Current token is 'this'. - */ - -Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs) -{ - Expressions *udas = NULL; - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen) - { - // this(this) { ... } - nextToken(); - nextToken(); - check(TOKrparen); - - stc = parsePostfix(stc, &udas); - if (stc & STCstatic) - error(loc, "postblit cannot be static"); - - PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - if (udas) - { - Dsymbols *a = new Dsymbols(); - a->push(f); - s = new UserAttributeDeclaration(udas, a); - } - return s; - } - - /* Look ahead to see if: - * this(...)(...) - * which is a constructor template - */ - TemplateParameters *tpl = NULL; - if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen) - { - tpl = parseTemplateParameterList(); - } - - /* Just a regular constructor - */ - VarArg varargs; - Parameters *parameters = parseParameters(&varargs); - stc = parsePostfix(stc, &udas); - if (varargs != VARARGnone || Parameter::dim(parameters) != 0) - { - if (stc & STCstatic) - error(loc, "constructor cannot be static"); - } - else if (StorageClass ss = stc & (STCshared | STCstatic)) // this() - { - if (ss == STCstatic) - error(loc, "use `static this()` to declare a static constructor"); - else if (ss == (STCshared | STCstatic)) - error(loc, "use `shared static this()` to declare a shared static constructor"); - } - - Expression *constraint = tpl ? parseConstraint() : NULL; - - Type *tf = new TypeFunction(ParameterList(parameters, varargs), - NULL, linkage, stc); // ReturnType -> auto - tf = tf->addSTC(stc); - - CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - if (udas) - { - Dsymbols *a = new Dsymbols(); - a->push(f); - s = new UserAttributeDeclaration(udas, a); - } - - if (tpl) - { - // Wrap a template around it - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(s); - s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs); - } - - return s; -} - -/***************************************** - * Parse a destructor definition: - * ~this() { body } - * Current token is '~'. - */ - -Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs) -{ - Expressions *udas = NULL; - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - stc = parsePostfix(stc, &udas); - if (StorageClass ss = stc & (STCshared | STCstatic)) - { - if (ss == STCstatic) - error(loc, "use `static ~this()` to declare a static destructor"); - else if (ss == (STCshared | STCstatic)) - error(loc, "use `shared static ~this()` to declare a shared static destructor"); - } - - DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - if (udas) - { - Dsymbols *a = new Dsymbols(); - a->push(f); - s = new UserAttributeDeclaration(udas, a); - } - return s; -} - -/***************************************** - * Parse a static constructor definition: - * static this() { body } - * Current token is 'static'. - */ - -Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs) -{ - //Expressions *udas = NULL; - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - nextToken(); - check(TOKlparen); - check(TOKrparen); - - stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc; - if (stc & STCshared) - error(loc, "use `shared static this()` to declare a shared static constructor"); - else if (stc & STCstatic) - appendStorageClass(stc, STCstatic); // complaint for the redundancy - else if (StorageClass modStc = stc & STC_TYPECTOR) - { - OutBuffer buf; - stcToBuffer(&buf, modStc); - error(loc, "static constructor cannot be %s", buf.peekChars()); - } - stc &= ~(STCstatic | STC_TYPECTOR); - - StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - return s; -} - -/***************************************** - * Parse a static destructor definition: - * static ~this() { body } - * Current token is 'static'. - */ - -Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs) -{ - Expressions *udas = NULL; - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc; - if (stc & STCshared) - error(loc, "use `shared static ~this()` to declare a shared static destructor"); - else if (stc & STCstatic) - appendStorageClass(stc, STCstatic); // complaint for the redundancy - else if (StorageClass modStc = stc & STC_TYPECTOR) - { - OutBuffer buf; - stcToBuffer(&buf, modStc); - error(loc, "static destructor cannot be %s", buf.peekChars()); - } - stc &= ~(STCstatic | STC_TYPECTOR); - - StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - if (udas) - { - Dsymbols *a = new Dsymbols(); - a->push(f); - s = new UserAttributeDeclaration(udas, a); - } - return s; -} - -/***************************************** - * Parse a shared static constructor definition: - * shared static this() { body } - * Current token is 'shared'. - */ - -Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs) -{ - //Expressions *udas = NULL; - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - nextToken(); - nextToken(); - check(TOKlparen); - check(TOKrparen); - - stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc; - if (StorageClass ss = stc & (STCshared | STCstatic)) - appendStorageClass(stc, ss); // complaint for the redundancy - else if (StorageClass modStc = stc & STC_TYPECTOR) - { - OutBuffer buf; - stcToBuffer(&buf, modStc); - error(loc, "shared static constructor cannot be %s", buf.peekChars()); - } - stc &= ~(STCstatic | STC_TYPECTOR); - - SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - return s; -} - -/***************************************** - * Parse a shared static destructor definition: - * shared static ~this() { body } - * Current token is 'shared'. - */ - -Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs) -{ - Expressions *udas = NULL; - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - nextToken(); - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc; - if (StorageClass ss = stc & (STCshared | STCstatic)) - appendStorageClass(stc, ss); // complaint for the redundancy - else if (StorageClass modStc = stc & STC_TYPECTOR) - { - OutBuffer buf; - stcToBuffer(&buf, modStc); - error(loc, "shared static destructor cannot be %s", buf.peekChars()); - } - stc &= ~(STCstatic | STC_TYPECTOR); - - SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - if (udas) - { - Dsymbols *a = new Dsymbols(); - a->push(f); - s = new UserAttributeDeclaration(udas, a); - } - return s; -} - -/***************************************** - * Parse an invariant definition: - * invariant { statements... } - * invariant() { statements... } - * invariant (expression); - * Current token is 'invariant'. - */ - -Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs) -{ - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - if (token.value == TOKlparen) // optional () or invariant (expression); - { - nextToken(); - if (token.value != TOKrparen) // invariant (expression); - { - Expression *e = parseAssignExp(); - Expression *msg = NULL; - if (token.value == TOKcomma) - { - nextToken(); - if (token.value != TOKrparen) - { - msg = parseAssignExp(); - if (token.value == TOKcomma) - nextToken(); - } - } - check(TOKrparen); - check(TOKsemicolon); - e = new AssertExp(loc, e, msg); - ExpStatement *fbody = new ExpStatement(loc, e); - InvariantDeclaration *f = new InvariantDeclaration(loc, token.loc, stc); - f->fbody = fbody; - return f; - } - else - { - nextToken(); - } - } - - InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc); - if (pAttrs) - pAttrs->storageClass = STCundefined; - f->fbody = parseStatement(PScurly); - return f; -} - -/***************************************** - * Parse a unittest definition: - * unittest { body } - * Current token is 'unittest'. - */ - -Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs) -{ - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - - const utf8_t *begPtr = token.ptr + 1; // skip '{' - const utf8_t *endPtr = NULL; - Statement *sbody = parseStatement(PScurly, &endPtr); - - /** Extract unittest body as a string. Must be done eagerly since memory - will be released by the lexer before doc gen. */ - char *docline = NULL; - if (global.params.doDocComments && endPtr > begPtr) - { - /* Remove trailing whitespaces */ - for (const utf8_t *p = endPtr - 1; - begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p) - { - endPtr = p; - } - - size_t len = endPtr - begPtr; - if (len > 0) - { - docline = (char *)mem.xmalloc(len + 2); - memcpy(docline, begPtr, len); - docline[len ] = '\n'; // Terminate all lines by LF - docline[len+1] = '\0'; - } - } - - UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline); - if (pAttrs) - pAttrs->storageClass = STCundefined; - f->fbody = sbody; - return f; -} - -/***************************************** - * Parse a new definition: - * new(parameters) { body } - * Current token is 'new'. - */ - -Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs) -{ - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - - VarArg varargs; - Parameters *parameters = parseParameters(&varargs); - NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - return s; -} - -/***************************************** - * Parse a delete definition: - * delete(parameters) { body } - * Current token is 'delete'. - */ - -Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs) -{ - Loc loc = token.loc; - StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; - - nextToken(); - - VarArg varargs; - Parameters *parameters = parseParameters(&varargs); - if (varargs != VARARGnone) - error("... not allowed in delete function parameter list"); - DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters); - if (pAttrs) - pAttrs->storageClass = STCundefined; - Dsymbol *s = parseContracts(f); - return s; -} - -/********************************************** - * Parse parameter list. - */ - -Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl) -{ - Parameters *parameters = new Parameters(); - VarArg varargs = VARARGnone; - int hasdefault = 0; - - check(TOKlparen); - while (1) - { - Identifier *ai = NULL; - Type *at; - StorageClass storageClass = 0; - StorageClass stc; - Expression *ae; - Expressions *udas = NULL; - - for (;1; nextToken()) - { - L3: - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = VARARGvariadic; - nextToken(); - break; - - case TOKconst: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCconst; - goto L2; - - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCimmutable; - goto L2; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCshared; - goto L2; - - case TOKwild: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCwild; - goto L2; - - case TOKat: - { - Expressions *exps = NULL; - StorageClass stc2 = parseAttribute(&exps); - if (stc2 == STCproperty || stc2 == STCnogc || - stc2 == STCdisable || stc2 == STCsafe || - stc2 == STCtrusted || stc2 == STCsystem) - { - error("`@%s` attribute for function parameter is not supported", token.toChars()); - } - else - { - udas = UserAttributeDeclaration::concat(udas, exps); - } - if (token.value == TOKdotdotdot) - error("variadic parameter cannot have user-defined attributes"); - if (stc2) - nextToken(); - goto L3; - // Don't call nextToken again. - } - - case TOKin: stc = STCin; goto L2; - case TOKout: stc = STCout; goto L2; - case TOKref: stc = STCref; goto L2; - case TOKlazy: stc = STClazy; goto L2; - case TOKscope: stc = STCscope; goto L2; - case TOKfinal: stc = STCfinal; goto L2; - case TOKauto: stc = STCauto; goto L2; - case TOKreturn: stc = STCreturn; goto L2; - L2: - storageClass = appendStorageClass(storageClass, stc); - continue; - - default: - Ldefault: - { stc = storageClass & (STCin | STCout | STCref | STClazy); - // if stc is not a power of 2 - if (stc & (stc - 1) && - !(stc == (STCin | STCref))) - error("incompatible parameter storage classes"); - //if ((storageClass & STCscope) && (storageClass & (STCref | STCout))) - //error("scope cannot be ref or out"); - - Token *t; - if (tpl && token.value == TOKidentifier && - (t = peek(&token), (t->value == TOKcomma || - t->value == TOKrparen || - t->value == TOKdotdotdot))) - { - Identifier *id = Identifier::generateId("__T"); - Loc loc = token.loc; - at = new TypeIdentifier(loc, id); - if (!*tpl) - *tpl = new TemplateParameters(); - TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); - (*tpl)->push(tp); - - ai = token.ident; - nextToken(); - } - else - at = parseType(&ai); - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for %s", - ai ? ai->toChars() : at->toChars()); - } - Parameter *param = new Parameter(storageClass, at, ai, ae, NULL); - if (udas) - { - Dsymbols *a = new Dsymbols(); - UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a); - param->userAttribDecl = udad; - } - if (token.value == TOKat) - { - Expressions *exps = NULL; - StorageClass stc2 = parseAttribute(&exps); - if (stc2 == STCproperty || stc2 == STCnogc || - stc2 == STCdisable || stc2 == STCsafe || - stc2 == STCtrusted || stc2 == STCsystem) - { - error("`@%s` attribute for function parameter is not supported", token.toChars()); - } - else - { - error("user-defined attributes cannot appear as postfixes", token.toChars()); - } - if (stc2) - nextToken(); - } - if (token.value == TOKdotdotdot) - { /* This is: - * at ai ... - */ - - if (storageClass & (STCout | STCref)) - error("variadic argument cannot be out or ref"); - varargs = VARARGtypesafe; - parameters->push(param); - nextToken(); - break; - } - parameters->push(param); - if (token.value == TOKcomma) - { nextToken(); - goto L1; - } - break; - } - } - break; - } - break; - - L1: ; - } - check(TOKrparen); - *pvarargs = varargs; - return parameters; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ - EnumDeclaration *e; - Identifier *id; - Type *memtype; - Loc loc = token.loc; - - // printf("Parser::parseEnum()\n"); - nextToken(); - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - if (token.value == TOKcolon) - { - nextToken(); - - int alt = 0; - Loc typeLoc = token.loc; - memtype = parseBasicType(); - memtype = parseDeclarator(memtype, &alt, NULL); - checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL); - } - else - memtype = NULL; - - e = new EnumDeclaration(loc, id, memtype); - if (token.value == TOKsemicolon && id) - nextToken(); - else if (token.value == TOKlcurly) - { - bool isAnonymousEnum = !id; - - //printf("enum definition\n"); - e->members = new Dsymbols(); - nextToken(); - const utf8_t *comment = token.blockComment; - while (token.value != TOKrcurly) - { - /* Can take the following forms... - * 1. ident - * 2. ident = value - * 3. type ident = value - * ... prefixed by valid attributes - */ - loc = token.loc; - - Type *type = NULL; - Identifier *ident = NULL; - - Expressions *udas = NULL; - StorageClass stc = STCundefined; - Expression *deprecationMessage = NULL; - - while (token.value != TOKrcurly && - token.value != TOKcomma && - token.value != TOKassign) - { - switch (token.value) - { - case TOKat: - if (StorageClass _stc = parseAttribute(&udas)) - { - if (_stc == STCdisable) - stc |= _stc; - else - { - OutBuffer buf; - stcToBuffer(&buf, _stc); - error("`%s` is not a valid attribute for enum members", buf.peekChars()); - } - nextToken(); - } - break; - case TOKdeprecated: - if (StorageClass _stc = parseDeprecatedAttribute(this, &deprecationMessage)) - { - stc |= _stc; - nextToken(); - } - break; - case TOKidentifier: - { - Token *tp = peek(&token); - if (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly) - { - ident = token.ident; - type = NULL; - nextToken(); - } - else - { - goto Ldefault; - } - break; - } - default: - Ldefault: - if (isAnonymousEnum) - { - type = parseType(&ident, NULL); - if (type == Type::terror) - { - type = NULL; - nextToken(); - } - } - else - { - error("`%s` is not a valid attribute for enum members", token.toChars()); - nextToken(); - } - break; - } - } - - if (type && type != Type::terror) - { - if (!ident) - error("no identifier for declarator %s", type->toChars()); - if (!isAnonymousEnum) - error("type only allowed if anonymous enum and no enum type"); - } - - Expression *value; - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - else - { - value = NULL; - if (type && type != Type::terror && isAnonymousEnum) - error("if type, there must be an initializer"); - } - - UserAttributeDeclaration *uad = NULL; - if (udas) - uad = new UserAttributeDeclaration(udas, NULL); - - DeprecatedDeclaration *dd = NULL; - if (deprecationMessage) - { - dd = new DeprecatedDeclaration(deprecationMessage, NULL); - stc |= STCdeprecated; - } - - EnumMember *em = new EnumMember(loc, ident, value, type, stc, uad, dd); - e->members->push(em); - - if (token.value == TOKrcurly) - ; - else - { - addComment(em, comment); - comment = NULL; - check(TOKcomma); - } - addComment(em, comment); - comment = token.blockComment; - - if (token.value == TOKeof) - { - error("premature end of file"); - break; - } - } - nextToken(); - } - else - error("enum declaration is invalid"); - - //printf("-parseEnum() %s\n", e->toChars()); - return e; -} - -/******************************** - * Parse struct, union, interface, class. - */ - -Dsymbol *Parser::parseAggregate() -{ - AggregateDeclaration *a = NULL; - int anon = 0; - Identifier *id; - TemplateParameters *tpl = NULL; - Expression *constraint = NULL; - Loc loc = token.loc; - TOK tok = token.value; - - //printf("Parser::parseAggregate()\n"); - nextToken(); - if (token.value != TOKidentifier) - { - id = NULL; - } - else - { - id = token.ident; - nextToken(); - - if (token.value == TOKlparen) - { - // Class template declaration. - // Gather template parameter list - tpl = parseTemplateParameterList(); - constraint = parseConstraint(); - } - } - - switch (tok) - { - case TOKclass: - case TOKinterface: - { - if (!id) - error(loc, "anonymous classes not allowed"); - - // Collect base class(es) - BaseClasses *baseclasses = NULL; - if (token.value == TOKcolon) - { - nextToken(); - baseclasses = parseBaseClasses(); - - if (tpl) - { - Expression *tempCons = parseConstraint(); - if (tempCons) - { - if (constraint) - error("members expected"); - else - constraint = tempCons; - } - } - - if (token.value != TOKlcurly) - error("members expected"); - } - - if (tok == TOKclass) - { - bool inObject = md && !md->packages && md->id == Id::object; - a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject); - } - else - a = new InterfaceDeclaration(loc, id, baseclasses); - break; - } - - case TOKstruct: - if (id) - { - bool inObject = md && !md->packages && md->id == Id::object; - a = new StructDeclaration(loc, id, inObject); - } - else - anon = 1; - break; - - case TOKunion: - if (id) - a = new UnionDeclaration(loc, id); - else - anon = 2; - break; - - default: - assert(0); - break; - } - if (a && token.value == TOKsemicolon) - { - nextToken(); - } - else if (token.value == TOKlcurly) - { - const Loc lookingForElseSave = lookingForElse; - lookingForElse = Loc(); - //printf("aggregate definition\n"); - nextToken(); - Dsymbols *decl = parseDeclDefs(0); - lookingForElse = lookingForElseSave; - if (token.value != TOKrcurly) - error("} expected following members in %s declaration at %s", - Token::toChars(tok), loc.toChars()); - nextToken(); - if (anon) - { - /* Anonymous structs/unions are more like attributes. - */ - return new AnonDeclaration(loc, anon == 2, decl); - } - else - a->members = decl; - } - else - { - error("{ } expected following %s declaration", Token::toChars(tok)); - a = new StructDeclaration(loc, NULL, false); - } - - if (tpl) - { - // Wrap a template around the aggregate declaration - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(a); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, id, tpl, constraint, decldefs); - return tempdecl; - } - - return a; -} - -/******************************************* - */ - -BaseClasses *Parser::parseBaseClasses() -{ - BaseClasses *baseclasses = new BaseClasses(); - - for (; 1; nextToken()) - { - bool prot = false; - Prot protection = Prot(Prot::public_); - switch (token.value) - { - case TOKprivate: - prot = true; - protection = Prot(Prot::private_); - nextToken(); - break; - case TOKpackage: - prot = true; - protection = Prot(Prot::package_); - nextToken(); - break; - case TOKprotected: - prot = true; - protection = Prot(Prot::protected_); - nextToken(); - break; - case TOKpublic: - prot = true; - protection = Prot(Prot::public_); - nextToken(); - break; - default: break; - } - if (prot) - error("use of base class protection is no longer supported"); - BaseClass *b = new BaseClass(parseBasicType()); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - } - return baseclasses; -} - -/************************************** - * Parse constraint. - * Constraint is of the form: - * if ( ConstraintExpression ) - */ - -Expression *Parser::parseConstraint() -{ Expression *e = NULL; - - if (token.value == TOKif) - { - nextToken(); // skip over 'if' - check(TOKlparen); - e = parseExpression(); - check(TOKrparen); - } - return e; -} - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin) -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Dsymbols *decldefs; - Expression *constraint = NULL; - Loc loc = token.loc; - - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following template"); - goto Lerr; - } - id = token.ident; - nextToken(); - tpl = parseTemplateParameterList(); - if (!tpl) - goto Lerr; - - constraint = parseConstraint(); - - if (token.value != TOKlcurly) - { - error("members of template declaration expected"); - goto Lerr; - } - else - decldefs = parseBlock(NULL); - - tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - * Input: - * flag 0: parsing "( list )" - * 1: parsing non-empty "list )" - */ - -TemplateParameters *Parser::parseTemplateParameterList(int flag) -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (!flag && token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (flag || token.value != TOKrparen) - { - int isvariadic = 0; - while (token.value != TOKrparen) - { - TemplateParameter *tp; - Loc loc; - Identifier *tp_ident = NULL; - Type *tp_spectype = NULL; - Type *tp_valtype = NULL; - Type *tp_defaulttype = NULL; - Expression *tp_specvalue = NULL; - Expression *tp_defaultvalue = NULL; - Token *t; - - // Get TemplateParameter - - // First, look ahead to see if it is a TypeParameter or a ValueParameter - t = peek(&token); - if (token.value == TOKalias) - { // AliasParameter - nextToken(); - loc = token.loc; // todo - Type *spectype = NULL; - if (isDeclaration(&token, 2, TOKreserved, NULL)) - { - spectype = parseType(&tp_ident); - } - else - { - if (token.value != TOKidentifier) - { - error("identifier expected for template alias parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - } - RootObject *spec = NULL; - if (token.value == TOKcolon) // : Type - { - nextToken(); - if (isDeclaration(&token, 0, TOKreserved, NULL)) - spec = parseType(); - else - spec = parseCondExp(); - } - RootObject *def = NULL; - if (token.value == TOKassign) // = Type - { - nextToken(); - if (isDeclaration(&token, 0, TOKreserved, NULL)) - def = parseType(); - else - def = parseCondExp(); - } - tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { - // TypeParameter - if (token.value != TOKidentifier) - { - error("identifier expected for template type parameter"); - goto Lerr; - } - loc = token.loc; - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { - // ident... - if (isvariadic) - error("variadic template parameter must be last"); - isvariadic = 1; - loc = token.loc; - tp_ident = token.ident; - nextToken(); - nextToken(); - tp = new TemplateTupleParameter(loc, tp_ident); - } - else if (token.value == TOKthis) - { - // ThisParameter - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected for template this parameter"); - goto Lerr; - } - loc = token.loc; - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else - { - // ValueParameter - loc = token.loc; // todo - tp_valtype = parseType(&tp_ident); - if (!tp_ident) - { - error("identifier expected for template value parameter"); - tp_ident = Identifier::idPool("error"); - } - if (token.value == TOKcolon) // : CondExpression - { - nextToken(); - tp_specvalue = parseCondExp(); - } - if (token.value == TOKassign) // = CondExpression - { - nextToken(); - tp_defaultvalue = parseDefaultInitExp(); - } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); - } - tpl->push(tp); - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen); -Lerr: - return tpl; -} - -/****************************************** - * Parse template mixin. - * mixin Foo; - * mixin Foo!(args); - * mixin a.b.c!(args).Foo!(args); - * mixin Foo!(args) identifier; - * mixin typeof(expr).identifier!(args); - */ - -Dsymbol *Parser::parseMixin() -{ - TemplateMixin *tm; - Identifier *id; - Objects *tiargs; - - //printf("parseMixin()\n"); - Loc locMixin = token.loc; - nextToken(); // skip 'mixin' - - Loc loc = token.loc; - TypeQualified *tqual = NULL; - if (token.value == TOKdot) - { - id = Id::empty; - } - else - { - if (token.value == TOKtypeof) - { - tqual = parseTypeof(); - check(TOKdot); - } - if (token.value != TOKidentifier) - { - error("identifier expected, not %s", token.toChars()); - id = Id::empty; - } - else - id = token.ident; - nextToken(); - } - - while (1) - { - tiargs = NULL; - if (token.value == TOKnot) - { - tiargs = parseTemplateArguments(); - } - - if (tiargs && token.value == TOKdot) - { - TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = tiargs; - if (!tqual) - tqual = new TypeInstance(loc, tempinst); - else - tqual->addInst(tempinst); - tiargs = NULL; - } - else - { - if (!tqual) - tqual = new TypeIdentifier(loc, id); - else - tqual->addIdent(id); - } - - if (token.value != TOKdot) - break; - - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following `.` instead of `%s`", token.toChars()); - break; - } - loc = token.loc; - id = token.ident; - nextToken(); - } - - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - tm = new TemplateMixin(locMixin, id, tqual, tiargs); - if (token.value != TOKsemicolon) - error("`;` expected after mixin"); - nextToken(); - - return tm; -} - -/****************************************** - * Parse template arguments. - * Input: - * current token is opening '!' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArguments() -{ - Objects *tiargs; - - nextToken(); - if (token.value == TOKlparen) - { - // ident!(template_arguments) - tiargs = parseTemplateArgumentList(); - } - else - { - // ident!template_argument - tiargs = parseTemplateSingleArgument(); - } - if (token.value == TOKnot) - { - TOK tok = peekNext(); - if (tok != TOKis && tok != TOKin) - { - error("multiple ! arguments are not allowed"); - Lagain: - nextToken(); - if (token.value == TOKlparen) - parseTemplateArgumentList(); - else - parseTemplateSingleArgument(); - if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin) - goto Lagain; - } - } - return tiargs; -} - -/*************************************** - * Parse a Type or an Expression - * Returns: - * RootObject representing the AST - */ -RootObject *Parser::parseTypeOrAssignExp(TOK endtoken) -{ - return isDeclaration(&token, 0, endtoken, NULL) - ? (RootObject *)parseType() // argument is a type - : (RootObject *)parseAssignExp(); // argument is an expression -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(', - * or ',' for __traits - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - Objects *tiargs = new Objects(); - TOK endtok = TOKrparen; - assert(token.value == TOKlparen || token.value == TOKcomma); - nextToken(); - - // Get TemplateArgumentList - while (token.value != endtok) - { - tiargs->push(parseTypeOrAssignExp()); - if (token.value != TOKcomma) - break; - nextToken(); - } - check(endtok, "template argument list"); - return tiargs; -} - -/***************************** - * Parse single template argument, to support the syntax: - * foo!arg - * Input: - * current token is the arg - */ - -Objects *Parser::parseTemplateSingleArgument() -{ - //printf("parseTemplateSingleArgument()\n"); - Objects *tiargs = new Objects(); - Type *ta; - switch (token.value) - { - case TOKidentifier: - ta = new TypeIdentifier(token.loc, token.ident); - goto LabelX; - - case TOKvector: - ta = parseVector(); - goto LabelX; - - case TOKvoid: ta = Type::tvoid; goto LabelX; - case TOKint8: ta = Type::tint8; goto LabelX; - case TOKuns8: ta = Type::tuns8; goto LabelX; - case TOKint16: ta = Type::tint16; goto LabelX; - case TOKuns16: ta = Type::tuns16; goto LabelX; - case TOKint32: ta = Type::tint32; goto LabelX; - case TOKuns32: ta = Type::tuns32; goto LabelX; - case TOKint64: ta = Type::tint64; goto LabelX; - case TOKuns64: ta = Type::tuns64; goto LabelX; - case TOKint128: ta = Type::tint128; goto LabelX; - case TOKuns128: ta = Type::tuns128; goto LabelX; - case TOKfloat32: ta = Type::tfloat32; goto LabelX; - case TOKfloat64: ta = Type::tfloat64; goto LabelX; - case TOKfloat80: ta = Type::tfloat80; goto LabelX; - case TOKimaginary32: ta = Type::timaginary32; goto LabelX; - case TOKimaginary64: ta = Type::timaginary64; goto LabelX; - case TOKimaginary80: ta = Type::timaginary80; goto LabelX; - case TOKcomplex32: ta = Type::tcomplex32; goto LabelX; - case TOKcomplex64: ta = Type::tcomplex64; goto LabelX; - case TOKcomplex80: ta = Type::tcomplex80; goto LabelX; - case TOKbool: ta = Type::tbool; goto LabelX; - case TOKchar: ta = Type::tchar; goto LabelX; - case TOKwchar: ta = Type::twchar; goto LabelX; - case TOKdchar: ta = Type::tdchar; goto LabelX; - LabelX: - tiargs->push(ta); - nextToken(); - break; - - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKint128v: - case TOKuns128v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKxstring: - case TOKfile: - case TOKfilefullpath: - case TOKline: - case TOKmodulestring: - case TOKfuncstring: - case TOKprettyfunc: - case TOKthis: - { // Template argument is an expression - Expression *ea = parsePrimaryExp(); - tiargs->push(ea); - break; - } - - default: - error("template argument expected following !"); - break; - } - return tiargs; -} - -Dsymbols *Parser::parseImport() -{ - Dsymbols *decldefs = new Dsymbols(); - Identifier *aliasid = NULL; - - int isstatic = token.value == TOKstatic; - if (isstatic) - nextToken(); - - //printf("Parser::parseImport()\n"); - do - { - L1: - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following import"); - break; - } - - Loc loc = token.loc; - Identifier *id = token.ident; - Identifiers *a = NULL; - nextToken(); - if (!aliasid && token.value == TOKassign) - { - aliasid = id; - goto L1; - } - while (token.value == TOKdot) - { - if (!a) - a = new Identifiers(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following package"); - break; - } - id = token.ident; - nextToken(); - } - - Import *s = new Import(loc, a, id, aliasid, isstatic); - decldefs->push(s); - - /* Look for - * : alias=name, alias=name; - * syntax. - */ - if (token.value == TOKcolon) - { - do - { - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following :"); - break; - } - Identifier *alias = token.ident; - Identifier *name; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following %s=", alias->toChars()); - break; - } - name = token.ident; - nextToken(); - } - else - { - name = alias; - alias = NULL; - } - s->addAlias(name, alias); - } while (token.value == TOKcomma); - break; // no comma-separated imports of this form - } - - aliasid = NULL; - } while (token.value == TOKcomma); - - if (token.value == TOKsemicolon) - nextToken(); - else - { - error("`;` expected"); - nextToken(); - } - - return decldefs; -} - -Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl) -{ - /* Take care of the storage class prefixes that - * serve as type attributes: - * const type - * immutable type - * shared type - * inout type - * inout const type - * shared const type - * shared inout type - * shared inout const type - */ - StorageClass stc = 0; - while (1) - { - switch (token.value) - { - case TOKconst: - if (peekNext() == TOKlparen) - break; // const as type constructor - stc |= STCconst; // const as storage class - nextToken(); - continue; - - case TOKimmutable: - if (peekNext() == TOKlparen) - break; - stc |= STCimmutable; - nextToken(); - continue; - - case TOKshared: - if (peekNext() == TOKlparen) - break; - stc |= STCshared; - nextToken(); - continue; - - case TOKwild: - if (peekNext() == TOKlparen) - break; - stc |= STCwild; - nextToken(); - continue; - - default: - break; - } - break; - } - - Loc typeLoc = token.loc; - - Type *t; - t = parseBasicType(); - - int alt = 0; - t = parseDeclarator(t, &alt, pident, ptpl); - checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL); - - t = t->addSTC(stc); - return t; -} - -Type *Parser::parseBasicType(bool dontLookDotIdents) -{ - Type *t; - Loc loc; - Identifier *id; - - //printf("parseBasicType()\n"); - switch (token.value) - { - case TOKvoid: t = Type::tvoid; goto LabelX; - case TOKint8: t = Type::tint8; goto LabelX; - case TOKuns8: t = Type::tuns8; goto LabelX; - case TOKint16: t = Type::tint16; goto LabelX; - case TOKuns16: t = Type::tuns16; goto LabelX; - case TOKint32: t = Type::tint32; goto LabelX; - case TOKuns32: t = Type::tuns32; goto LabelX; - case TOKint64: - t = Type::tint64; - nextToken(); - if (token.value == TOKint64) // if `long long` - { - error("use `long` for a 64 bit integer instead of `long long`"); - nextToken(); - } - else if (token.value == TOKfloat64) // if `long double` - { - error("use `real` instead of `long double`"); - t = Type::tfloat80; - nextToken(); - - } - break; - - case TOKuns64: t = Type::tuns64; goto LabelX; - case TOKint128: t = Type::tint128; goto LabelX; - case TOKuns128: t = Type::tuns128; goto LabelX; - case TOKfloat32: t = Type::tfloat32; goto LabelX; - case TOKfloat64: t = Type::tfloat64; goto LabelX; - case TOKfloat80: t = Type::tfloat80; goto LabelX; - case TOKimaginary32: t = Type::timaginary32; goto LabelX; - case TOKimaginary64: t = Type::timaginary64; goto LabelX; - case TOKimaginary80: t = Type::timaginary80; goto LabelX; - case TOKcomplex32: t = Type::tcomplex32; goto LabelX; - case TOKcomplex64: t = Type::tcomplex64; goto LabelX; - case TOKcomplex80: t = Type::tcomplex80; goto LabelX; - case TOKbool: t = Type::tbool; goto LabelX; - case TOKchar: t = Type::tchar; goto LabelX; - case TOKwchar: t = Type::twchar; goto LabelX; - case TOKdchar: t = Type::tdchar; goto LabelX; - LabelX: - nextToken(); - break; - - case TOKthis: - case TOKsuper: - case TOKidentifier: - loc = token.loc; - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - // ident!(template_arguments) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArguments(); - t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents); - } - else - { - t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents); - } - break; - - case TOKmixin: - // https://dlang.org/spec/expression.html#mixin_types - loc = token.loc; - nextToken(); - if (token.value != TOKlparen) - error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`"); - t = new TypeMixin(loc, parseArguments()); - break; - - case TOKdot: - // Leading . as in .foo - t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents); - break; - - case TOKtypeof: - // typeof(expression) - t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents); - break; - - case TOKvector: - t = parseVector(); - break; - - case TOKtraits: - if (TraitsExp *te = (TraitsExp *) parsePrimaryExp()) - { - if (te->ident && te->args) - { - t = new TypeTraits(token.loc, te); - break; - } - } - t = new TypeError(); - break; - - case TOKconst: - // const(type) - nextToken(); - check(TOKlparen); - t = parseType()->addSTC(STCconst); - check(TOKrparen); - break; - - case TOKimmutable: - // immutable(type) - nextToken(); - check(TOKlparen); - t = parseType()->addSTC(STCimmutable); - check(TOKrparen); - break; - - case TOKshared: - // shared(type) - nextToken(); - check(TOKlparen); - t = parseType()->addSTC(STCshared); - check(TOKrparen); - break; - - case TOKwild: - // wild(type) - nextToken(); - check(TOKlparen); - t = parseType()->addSTC(STCwild); - check(TOKrparen); - break; - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::terror; - break; - } - return t; -} - -Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents) -{ - Type *maybeArray = NULL; - // See https://issues.dlang.org/show_bug.cgi?id=1215 - // A basic type can look like MyType (typical case), but also: - // MyType.T -> A type - // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple) - // MyType[expr].T -> A type. - // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type - // (iif MyType[expr].T is a Ttuple) - while (1) - { - switch (token.value) - { - case TOKdot: - { - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following `.` instead of `%s`", token.toChars()); - break; - } - if (maybeArray) - { - // This is actually a TypeTuple index, not an {a/s}array. - // We need to have a while loop to unwind all index taking: - // T[e1][e2].U -> T, addIndex(e1), addIndex(e2) - Objects dimStack; - Type *t = maybeArray; - while (true) - { - if (t->ty == Tsarray) - { - // The index expression is an Expression. - TypeSArray *a = (TypeSArray *)t; - dimStack.push(a->dim->syntaxCopy()); - t = a->next->syntaxCopy(); - } - else if (t->ty == Taarray) - { - // The index expression is a Type. It will be interpreted as an expression at semantic time. - TypeAArray *a = (TypeAArray *)t; - dimStack.push(a->index->syntaxCopy()); - t = a->next->syntaxCopy(); - } - else - { - break; - } - } - assert(dimStack.length > 0); - // We're good. Replay indices in the reverse order. - tid = (TypeQualified *)t; - while (dimStack.length) - { - tid->addIndex(dimStack.pop()); - } - maybeArray = NULL; - } - Loc loc = token.loc; - Identifier *id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArguments(); - tid->addInst(tempinst); - } - else - tid->addIdent(id); - continue; - } - case TOKlbracket: - { - if (dontLookDotIdents) // workaround for Bugzilla 14911 - goto Lend; - - nextToken(); - Type *t = maybeArray ? maybeArray : (Type *)tid; - if (token.value == TOKrbracket) - { - // It's a dynamic array, and we're done: - // T[].U does not make sense. - t = new TypeDArray(t); - nextToken(); - return t; - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { - // This can be one of two things: - // 1 - an associative array declaration, T[type] - // 2 - an associative array declaration, T[expr] - // These can only be disambiguated later. - Type *index = parseType(); // [ type ] - maybeArray = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - // This can be one of three things: - // 1 - an static array declaration, T[expr] - // 2 - a slice, T[expr .. expr] - // 3 - a template parameter pack index expression, T[expr].U - // 1 and 3 can only be disambiguated later. - //printf("it's type[expression]\n"); - inBrackets++; - Expression *e = parseAssignExp(); // [ expression ] - if (token.value == TOKslice) - { - // It's a slice, and we're done. - nextToken(); - Expression *e2 = parseAssignExp(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - inBrackets--; - check(TOKrbracket); - return t; - } - else - { - maybeArray = new TypeSArray(t, e); - inBrackets--; - check(TOKrbracket); - continue; - } - } - break; - } - default: - goto Lend; - } - } -Lend: - return maybeArray ? maybeArray : (Type *)tid; -} - -/****************************************** - * Parse things that follow the initial type t. - * t * - * t [] - * t [type] - * t [expression] - * t [expression .. expression] - * t function - * t delegate - */ - -Type *Parser::parseBasicType2(Type *t) -{ - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: - // Handle []. Make sure things like - // int[3][1] a; - // is (array[1] of array[3] of int) - nextToken(); - if (token.value == TOKrbracket) - { - t = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { - // It's an associative array declaration - //printf("it's an associative array\n"); - Type *index = parseType(); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's type[expression]\n"); - inBrackets++; - Expression *e = parseAssignExp(); // [ expression ] - if (token.value == TOKslice) - { - nextToken(); - Expression *e2 = parseAssignExp(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - { - t = new TypeSArray(t,e); - } - inBrackets--; - check(TOKrbracket); - } - continue; - - case TOKdelegate: - case TOKfunction: - { - // Handle delegate declaration: - // t delegate(parameter list) nothrow pure - // t function(parameter list) nothrow pure - TOK save = token.value; - nextToken(); - - VarArg varargs; - Parameters *parameters = parseParameters(&varargs); - - StorageClass stc = parsePostfix(STCundefined, NULL); - TypeFunction *tf = new TypeFunction(ParameterList(parameters, varargs), - t, linkage, stc); - if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn)) - { - if (save == TOKfunction) - error("const/immutable/shared/inout/return attributes are only valid for non-static member functions"); - else - tf = (TypeFunction *)tf->addSTC(stc); - } - - if (save == TOKdelegate) - t = new TypeDelegate(tf); - else - t = new TypePointer(tf); // pointer to function - continue; - } - - default: - return t; - } - assert(0); - } - assert(0); - return NULL; -} - -Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident, - TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas) -{ - //printf("parseDeclarator(tpl = %p)\n", tpl); - t = parseBasicType2(t); - - Type *ts; - switch (token.value) - { - case TOKidentifier: - if (pident) - *pident = token.ident; - else - error("unexpected identifier `%s` in declarator", token.ident->toChars()); - ts = t; - nextToken(); - break; - - case TOKlparen: - { - // like: T (*fp)(); - // like: T ((*fp))(); - if (peekNext() == TOKmul || - peekNext() == TOKlparen) - { - /* Parse things with parentheses around the identifier, like: - * int (*ident[3])[] - * although the D style would be: - * int[]*[3] ident - */ - *palt |= 1; - nextToken(); - ts = parseDeclarator(t, palt, pident); - check(TOKrparen); - break; - } - ts = t; - - Token *peekt = &token; - /* Completely disallow C-style things like: - * T (a); - * Improve error messages for the common bug of a missing return type - * by looking to see if (a) looks like a parameter list. - */ - if (isParameters(&peekt)) - { - error("function declaration without return type. (Note that constructors are always named `this`)"); - } - else - error("unexpected ( in declarator"); - break; - } - - default: - ts = t; - break; - } - - // parse DeclaratorSuffixes - while (1) - { - switch (token.value) - { -#if CARRAYDECL - /* Support C style array syntax: - * int ident[] - * as opposed to D-style: - * int[] ident - */ - case TOKlbracket: - { - // This is the old C-style post [] syntax. - TypeNext *ta; - nextToken(); - if (token.value == TOKrbracket) - { - // It's a dynamic array - ta = new TypeDArray(t); // [] - nextToken(); - *palt |= 2; - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { - // It's an associative array - //printf("it's an associative array\n"); - Type *index = parseType(); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - *palt |= 2; - } - else - { - //printf("It's a static array\n"); - Expression *e = parseAssignExp(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - *palt |= 2; - } - - /* Insert ta into - * ts -> ... -> t - * so that - * ts -> ... -> ta -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { - if (tpl) - { - Token *tk = peekPastParen(&token); - if (tk->value == TOKlparen) - { - /* Look ahead to see if this is (...)(...), - * i.e. a function template declaration - */ - //printf("function template declaration\n"); - - // Gather template parameter list - *tpl = parseTemplateParameterList(); - } - else if (tk->value == TOKassign) - { - /* or (...) =, - * i.e. a variable template declaration - */ - //printf("variable template declaration\n"); - *tpl = parseTemplateParameterList(); - break; - } - } - - VarArg varargs; - Parameters *parameters = parseParameters(&varargs); - - /* Parse const/immutable/shared/inout/nothrow/pure/return postfix - */ - StorageClass stc = parsePostfix(storageClass, pudas); - // merge prefix storage classes - Type *tf = new TypeFunction(ParameterList(parameters, varargs), - t, linkage, stc); - tf = tf->addSTC(stc); - if (pdisable) - *pdisable = stc & STCdisable ? 1 : 0; - - /* Insert tf into - * ts -> ... -> t - * so that - * ts -> ... -> tf -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next) - ; - *pt = tf; - break; - } - default: break; - } - break; - } - - return ts; -} - -void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link, - bool &setAlignment, Expression *&ealign, Expressions *&udas) -{ - StorageClass stc; - bool sawLinkage = false; // seen a linkage declaration - - while (1) - { - switch (token.value) - { - case TOKconst: - if (peek(&token)->value == TOKlparen) - break; // const as type constructor - stc = STCconst; // const as storage class - goto L1; - - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - break; - stc = STCimmutable; - goto L1; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - break; - stc = STCshared; - goto L1; - - case TOKwild: - if (peek(&token)->value == TOKlparen) - break; - stc = STCwild; - goto L1; - - case TOKstatic: stc = STCstatic; goto L1; - case TOKfinal: stc = STCfinal; goto L1; - case TOKauto: stc = STCauto; goto L1; - case TOKscope: stc = STCscope; goto L1; - case TOKoverride: stc = STCoverride; goto L1; - case TOKabstract: stc = STCabstract; goto L1; - case TOKsynchronized: stc = STCsynchronized; goto L1; - case TOKdeprecated: stc = STCdeprecated; goto L1; - case TOKnothrow: stc = STCnothrow; goto L1; - case TOKpure: stc = STCpure; goto L1; - case TOKref: stc = STCref; goto L1; - case TOKgshared: stc = STCgshared; goto L1; - case TOKenum: stc = STCmanifest; goto L1; - case TOKat: - { - stc = parseAttribute(&udas); - if (stc) - goto L1; - continue; - } - L1: - storage_class = appendStorageClass(storage_class, stc); - nextToken(); - continue; - - case TOKextern: - { - if (peek(&token)->value != TOKlparen) - { - stc = STCextern; - goto L1; - } - - if (sawLinkage) - error("redundant linkage declaration"); - sawLinkage = true; - Identifiers *idents = NULL; - CPPMANGLE cppmangle = CPPMANGLEdefault; - bool cppMangleOnly = false; - link = parseLinkage(&idents, &cppmangle, &cppMangleOnly); - if (idents) - { - error("C++ name spaces not allowed here"); - delete idents; - } - if (cppmangle != CPPMANGLEdefault) - { - error("C++ mangle declaration not allowed here"); - } - continue; - } - - case TOKalign: - { - nextToken(); - setAlignment = true; - if (token.value == TOKlparen) - { - nextToken(); - ealign = parseExpression(); - check(TOKrparen); - } - continue; - } - default: - break; - } - break; - } -} - -static void parseAttributes(Parser *p, bool &hasParsedAttributes, - StorageClass &storage_class, LINK &link, bool &setAlignment, - Expression *&ealign, Expressions *&udas) -{ - if (hasParsedAttributes) // only parse once - return; - hasParsedAttributes = true; - udas = NULL; - storage_class = STCundefined; - link = p->linkage; - setAlignment = false; - ealign = NULL; - p->parseStorageClasses(storage_class, link, setAlignment, ealign, udas); -} - -/********************************** - * Parse Declarations. - * These can be: - * 1. declarations at global/class level - * 2. declarations at statement level - * Return array of Declaration *'s. - */ - -Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment) -{ - StorageClass storage_class = STCundefined; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - TOK tok = TOKreserved; - LINK link = linkage; - bool setAlignment = false; - Expression *ealign = NULL; - Loc loc = token.loc; - Expressions *udas = NULL; - Token *tk; - - //printf("parseDeclarations() %s\n", token.toChars()); - if (!comment) - comment = token.blockComment; - - if (autodecl) - { - ts = NULL; // infer type - goto L2; - } - - if (token.value == TOKalias) - { - tok = token.value; - nextToken(); - - /* Look for: - * alias identifier this; - */ - if (token.value == TOKidentifier && peekNext() == TOKthis) - { - AliasThis *s = new AliasThis(loc, token.ident); - nextToken(); - check(TOKthis); - check(TOKsemicolon); - Dsymbols *a = new Dsymbols(); - a->push(s); - addComment(s, comment); - return a; - } - /* Look for: - * alias identifier = type; - * alias identifier(...) = type; - */ - if (token.value == TOKidentifier && - skipParensIf(peek(&token), &tk) && - tk->value == TOKassign) - { - Dsymbols *a = new Dsymbols(); - while (1) - { - ident = token.ident; - nextToken(); - TemplateParameters *tpl = NULL; - if (token.value == TOKlparen) - tpl = parseTemplateParameterList(); - check(TOKassign); - - bool hasParsedAttributes = false; - if (token.value == TOKat) - { - parseAttributes(this, hasParsedAttributes, - storage_class, link, setAlignment, ealign, udas); - } - - Declaration *v; - Dsymbol *s; - - // try to parse function type: - // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes - bool attributesAppended = false; - const StorageClass funcStc = parseTypeCtor(); - Token *tlu = &token; - if (token.value != TOKfunction && - token.value != TOKdelegate && - isBasicType(&tlu) && tlu && - tlu->value == TOKlparen) - { - VarArg vargs; - Type *tret = parseBasicType(); - Parameters *prms = parseParameters(&vargs); - ParameterList pl = ParameterList(prms, vargs); - - parseAttributes(this, hasParsedAttributes, - storage_class, link, setAlignment, ealign, udas); - if (udas) - error("user-defined attributes not allowed for `alias` declarations"); - - attributesAppended = true; - storage_class = appendStorageClass(storage_class, funcStc); - Type *tf = new TypeFunction(pl, tret, link, storage_class); - v = new AliasDeclaration(loc, ident, tf); - } - else if (token.value == TOKfunction || - token.value == TOKdelegate || - (token.value == TOKlparen && - skipAttributes(peekPastParen(&token), &tk) && - (tk->value == TOKgoesto || tk->value == TOKlcurly)) || - token.value == TOKlcurly || - (token.value == TOKidentifier && peekNext() == TOKgoesto) || - (token.value == TOKref && peekNext() == TOKlparen && - skipAttributes(peekPastParen(peek(&token)), &tk) && - (tk->value == TOKgoesto || tk->value == TOKlcurly))) - { - // function (parameters) { statements... } - // delegate (parameters) { statements... } - // (parameters) { statements... } - // (parameters) => expression - // { statements... } - // identifier => expression - // ref (parameters) { statements... } - // ref (parameters) => expression - - s = parseFunctionLiteral(); - - if (udas != NULL) - { - if (storage_class != 0) - error("Cannot put a storage-class in an alias declaration."); - // shouldn't have set these variables - assert(link == linkage && !setAlignment && ealign == NULL); - TemplateDeclaration *tpl_ = (TemplateDeclaration *) s; - assert(tpl_ != NULL && tpl_->members->length == 1); - FuncLiteralDeclaration *fd = (FuncLiteralDeclaration *) (*tpl_->members)[0]; - TypeFunction *tf = (TypeFunction *) fd->type; - assert(tf->parameterList.length() > 0); - Dsymbols *as = new Dsymbols(); - (*tf->parameterList.parameters)[0]->userAttribDecl = new UserAttributeDeclaration(udas, as); - } - v = new AliasDeclaration(loc, ident, s); - } - else - { - // StorageClasses type - parseAttributes(this, hasParsedAttributes, - storage_class, link, setAlignment, ealign, udas); - if (udas) - error("user-defined attributes not allowed for %s declarations", Token::toChars(tok)); - - t = parseType(); - v = new AliasDeclaration(loc, ident, t); - } - if (!attributesAppended) - storage_class = appendStorageClass(storage_class, funcStc); - v->storage_class = storage_class; - - s = v; - if (tpl) - { - Dsymbols *a2 = new Dsymbols(); - a2->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, ident, tpl, NULL, a2); - s = tempdecl; - } - if (setAlignment) - { - Dsymbols *ax = new Dsymbols(); - ax->push(s); - s = new AlignDeclaration(v->loc, ealign, ax); - } - if (link != linkage) - { - Dsymbols *a2 = new Dsymbols(); - a2->push(s); - s = new LinkDeclaration(link, a2); - } - a->push(s); - - switch (token.value) - { - case TOKsemicolon: - nextToken(); - addComment(s, comment); - break; - case TOKcomma: - nextToken(); - addComment(s, comment); - if (token.value != TOKidentifier) - { - error("identifier expected following comma, not %s", token.toChars()); - break; - } - if (peekNext() != TOKassign && peekNext() != TOKlparen) - { - error("= expected following identifier"); - nextToken(); - break; - } - continue; - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - break; - } - return a; - } - - // alias StorageClasses type ident; - } - - parseStorageClasses(storage_class, link, setAlignment, ealign, udas); - - if (token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKinterface) - { - Dsymbol *s = parseAggregate(); - Dsymbols *a = new Dsymbols(); - a->push(s); - - if (storage_class) - { - s = new StorageClassDeclaration(storage_class, a); - a = new Dsymbols(); - a->push(s); - } - if (setAlignment) - { - s = new AlignDeclaration(s->loc, ealign, a); - a = new Dsymbols(); - a->push(s); - } - if (link != linkage) - { - s = new LinkDeclaration(link, a); - a = new Dsymbols(); - a->push(s); - } - if (udas) - { - s = new UserAttributeDeclaration(udas, a); - a = new Dsymbols(); - a->push(s); - } - - addComment(s, comment); - return a; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - * storage_class identifier(...) = initializer; - */ - if ((storage_class || udas) && - token.value == TOKidentifier && - skipParensIf(peek(&token), &tk) && - tk->value == TOKassign) - { - Dsymbols *a = parseAutoDeclarations(storage_class, comment); - if (udas) - { - Dsymbol *s = new UserAttributeDeclaration(udas, a); - a = new Dsymbols(); - a->push(s); - } - return a; - } - - /* Look for return type inference for template functions. - */ - if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) && - skipAttributes(tk, &tk) && - (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || tk->value == TOKout || - tk->value == TOKdo || (tk->value == TOKidentifier && tk->ident == Id::_body))) - { - ts = NULL; - } - else - { - ts = parseBasicType(); - ts = parseBasicType2(ts); - } - -L2: - tfirst = NULL; - Dsymbols *a = new Dsymbols(); - - if (pAttrs) - { - storage_class |= pAttrs->storageClass; - //pAttrs->storageClass = STCundefined; - } - - while (1) - { - TemplateParameters *tpl = NULL; - int disable; - int alt = 0; - - loc = token.loc; - ident = NULL; - t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas); - assert(t); - if (!tfirst) - tfirst = t; - else if (t != tfirst) - error("multiple declarations must have the same type, not %s and %s", - tfirst->toChars(), t->toChars()); - bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign); - if (ident) - checkCstyleTypeSyntax(loc, t, alt, ident); - else if (!isThis) - error("no identifier for declarator %s", t->toChars()); - - if (tok == TOKalias) - { - Declaration *v; - Initializer *init = NULL; - - /* Aliases can no longer have multiple declarators, storage classes, - * linkages, or auto declarations. - * These never made any sense, anyway. - * The code below needs to be fixed to reject them. - * The grammar has already been fixed to preclude them. - */ - - if (udas) - error("user-defined attributes not allowed for %s declarations", Token::toChars(tok)); - - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - if (init) - { - if (isThis) - error("cannot use syntax `alias this = %s`, use `alias %s this` instead", - init->toChars(), init->toChars()); - else - error("alias cannot have initializer"); - } - v = new AliasDeclaration(loc, ident, t); - - v->storage_class = storage_class; - if (pAttrs) - { - /* AliasDeclaration distinguish @safe, @system, @trusted atttributes - * on prefix and postfix. - * @safe alias void function() FP1; - * alias @safe void function() FP2; // FP2 is not @safe - * alias void function() @safe FP3; - */ - pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted); - } - Dsymbol *s = v; - - if (link != linkage) - { - Dsymbols *ax = new Dsymbols(); - ax->push(v); - s = new LinkDeclaration(link, ax); - } - a->push(s); - switch (token.value) - { - case TOKsemicolon: - nextToken(); - addComment(s, comment); - break; - - case TOKcomma: - nextToken(); - addComment(s, comment); - continue; - - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - } - else if (t->ty == Tfunction) - { - Expression *constraint = NULL; - - //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class); - FuncDeclaration *f = - new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t); - if (pAttrs) - pAttrs->storageClass = STCundefined; - if (tpl) - constraint = parseConstraint(); - Dsymbol *s = parseContracts(f); - Identifier *tplIdent = s->ident; - if (link != linkage) - { - Dsymbols *ax = new Dsymbols(); - ax->push(s); - s = new LinkDeclaration(link, ax); - } - if (udas) - { - Dsymbols *ax = new Dsymbols(); - ax->push(s); - s = new UserAttributeDeclaration(udas, ax); - } - - /* A template parameter list means it's a function template - */ - if (tpl) - { - // Wrap a template around the function declaration - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs); - s = tempdecl; - - if (storage_class & STCstatic) - { - assert(f->storage_class & STCstatic); - f->storage_class &= ~STCstatic; - - Dsymbols *ax = new Dsymbols(); - ax->push(s); - s = new StorageClassDeclaration(STCstatic, ax); - } - } - a->push(s); - addComment(s, comment); - } - else if (ident) - { - Initializer *init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - - VarDeclaration *v = new VarDeclaration(loc, t, ident, init); - v->storage_class = storage_class; - if (pAttrs) - pAttrs->storageClass = STCundefined; - - Dsymbol *s = v; - - if (tpl && init) - { - Dsymbols *a2 = new Dsymbols(); - a2->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0); - s = tempdecl; - } - if (link != linkage) - { - Dsymbols *ax = new Dsymbols(); - ax->push(s); - s = new LinkDeclaration(link, ax); - } - if (udas) - { - Dsymbols *ax = new Dsymbols(); - ax->push(s); - s = new UserAttributeDeclaration(udas, ax); - } - a->push(s); - switch (token.value) - { - case TOKsemicolon: - nextToken(); - addComment(s, comment); - break; - - case TOKcomma: - nextToken(); - addComment(s, comment); - continue; - - default: - error("semicolon expected, not `%s`", token.toChars()); - break; - } - } - break; - } - return a; -} - -Dsymbol *Parser::parseFunctionLiteral() -{ - Loc loc = token.loc; - - TemplateParameters *tpl = NULL; - Parameters *parameters = NULL; - VarArg varargs = VARARGnone; - Type *tret = NULL; - StorageClass stc = 0; - TOK save = TOKreserved; - - switch (token.value) - { - case TOKfunction: - case TOKdelegate: - save = token.value; - nextToken(); - if (token.value == TOKref) - { - // function ref (parameters) { statements... } - // delegate ref (parameters) { statements... } - stc = STCref; - nextToken(); - } - if (token.value != TOKlparen && token.value != TOKlcurly) - { - // function type (parameters) { statements... } - // delegate type (parameters) { statements... } - tret = parseBasicType(); - tret = parseBasicType2(tret); // function return type - } - - if (token.value == TOKlparen) - { - // function (parameters) { statements... } - // delegate (parameters) { statements... } - } - else - { - // function { statements... } - // delegate { statements... } - break; - } - goto LTOKlparen; - - case TOKref: - // ref (parameters) => expression - // ref (parameters) { statements... } - stc = STCref; - nextToken(); - goto LTOKlparen; - - case TOKlparen: - LTOKlparen: - { - // (parameters) => expression - // (parameters) { statements... } - parameters = parseParameters(&varargs, &tpl); - stc = parsePostfix(stc, NULL); - if (StorageClass modStc = stc & STC_TYPECTOR) - { - if (save == TOKfunction) - { - OutBuffer buf; - stcToBuffer(&buf, modStc); - error("function literal cannot be %s", buf.peekChars()); - } - else - save = TOKdelegate; - } - break; - } - case TOKlcurly: - // { statements... } - break; - - case TOKidentifier: - { - // identifier => expression - parameters = new Parameters(); - Identifier *id = Identifier::generateId("__T"); - Type *t = new TypeIdentifier(loc, id); - parameters->push(new Parameter(0, t, token.ident, NULL, NULL)); - - tpl = new TemplateParameters(); - TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); - tpl->push(tp); - - nextToken(); - break; - } - default: - assert(0); - } - - if (!parameters) - parameters = new Parameters(); - TypeFunction *tf = new TypeFunction(ParameterList(parameters, varargs), - tret, linkage, stc); - tf = (TypeFunction *)tf->addSTC(stc); - FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL); - - if (token.value == TOKgoesto) - { - check(TOKgoesto); - Loc returnloc = token.loc; - Expression *ae = parseAssignExp(); - fd->fbody = new ReturnStatement(returnloc, ae); - fd->endloc = token.loc; - } - else - { - parseContracts(fd); - } - - if (tpl) - { - // Wrap a template around function fd - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(fd); - return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true); - } - else - return fd; -} - -/***************************************** - * Parse auto declarations of the form: - * storageClass ident = init, ident = init, ... ; - * and return the array of them. - * Starts with token on the first ident. - * Ends with scanner past closing ';' - */ - -Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment) -{ - //printf("parseAutoDeclarations\n"); - Token *tk; - Dsymbols *a = new Dsymbols; - - while (1) - { - Loc loc = token.loc; - Identifier *ident = token.ident; - nextToken(); // skip over ident - - TemplateParameters *tpl = NULL; - if (token.value == TOKlparen) - tpl = parseTemplateParameterList(); - - check(TOKassign); // skip over '=' - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storageClass; - - Dsymbol *s = v; - if (tpl) - { - Dsymbols *a2 = new Dsymbols(); - a2->push(v); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0); - s = tempdecl; - } - a->push(s); - switch (token.value) - { - case TOKsemicolon: - nextToken(); - addComment(s, comment); - break; - - case TOKcomma: - nextToken(); - if (!(token.value == TOKidentifier && - skipParensIf(peek(&token), &tk) && - tk->value == TOKassign)) - { - error("identifier expected following comma"); - break; - } - addComment(s, comment); - continue; - - default: - error("semicolon expected following auto declaration, not `%s`", token.toChars()); - break; - } - break; - } - return a; -} - -/***************************************** - * Parse contracts following function declaration. - */ - -FuncDeclaration *Parser::parseContracts(FuncDeclaration *f) -{ - LINK linksave = linkage; - - bool literal = f->isFuncLiteralDeclaration() != NULL; - - // The following is irrelevant, as it is overridden by sc->linkage in - // TypeFunction::semantic - linkage = LINKd; // nested functions have D linkage - bool requireDo = false; -L1: - switch (token.value) - { - case TOKlcurly: - if (requireDo) - error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); - f->endloc = endloc; - break; - - case TOKidentifier: - if (token.ident != Id::_body) - goto Ldefault; - /* fall through */ - - case TOKdo: - nextToken(); - f->fbody = parseStatement(PScurly); - f->endloc = endloc; - break; - - case TOKin: - { - // in { statements... } - // in (expression) - Loc loc = token.loc; - nextToken(); - if (!f->frequires) - { - f->frequires = new Statements(); - } - if (token.value == TOKlparen) - { - nextToken(); - Expression *e = parseAssignExp(); - Expression *msg = NULL; - if (token.value == TOKcomma) - { - nextToken(); - if (token.value != TOKrparen) - { - msg = parseAssignExp(); - if (token.value == TOKcomma) - nextToken(); - } - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - f->frequires->push(new ExpStatement(loc, e)); - requireDo = false; - } - else - { - f->frequires->push(parseStatement(PScurly | PSscope)); - requireDo = true; - } - goto L1; - } - - case TOKout: - { - // out { statements... } - // out (; expression) - // out (identifier) { statements... } - // out (identifier; expression) - Loc loc = token.loc; - nextToken(); - if (!f->fensures) - { - f->fensures = new Ensures(); - } - Identifier *id = NULL; - if (token.value != TOKlcurly) - { - check(TOKlparen); - if (token.value != TOKidentifier && token.value != TOKsemicolon) - error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars()); - if (token.value != TOKsemicolon) - { - id = token.ident; - nextToken(); - } - if (token.value == TOKsemicolon) - { - nextToken(); - Expression *e = parseAssignExp(); - Expression *msg = NULL; - if (token.value == TOKcomma) - { - nextToken(); - if (token.value != TOKrparen) - { - msg = parseAssignExp(); - if (token.value == TOKcomma) - nextToken(); - } - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - f->fensures->push(Ensure(id, new ExpStatement(loc, e))); - requireDo = false; - goto L1; - } - check(TOKrparen); - } - f->fensures->push(Ensure(id, parseStatement(PScurly | PSscope))); - requireDo = true; - goto L1; - } - - case TOKsemicolon: - if (!literal) - { - // Bugzilla 15799: Semicolon becomes a part of function declaration - // only when 'do' is not required - if (!requireDo) - nextToken(); - break; - } - /* fall through */ - - default: - Ldefault: - if (literal) - { - const char *sbody = requireDo ? "do " : ""; - error("missing %s{ ... } for function literal", sbody); - } - else if (!requireDo) // allow these even with no body - { - error("semicolon expected following function declaration"); - } - break; - } - if (literal && !f->fbody) - { - // Set empty function body for error recovery - f->fbody = new CompoundStatement(Loc(), (Statement *)NULL); - } - - linkage = linksave; - - return f; -} - -/***************************************** - * Parse initializer for variable declaration. - */ - -Initializer *Parser::parseInitializer() -{ - StructInitializer *is; - ArrayInitializer *ia; - ExpInitializer *ie; - Expression *e; - Identifier *id; - Initializer *value; - int comma; - Loc loc = token.loc; - Token *t; - int braces; - int brackets; - - switch (token.value) - { - case TOKlcurly: - /* Scan ahead to see if it is a struct initializer or - * a function literal. - * If it contains a ';', it is a function literal. - * Treat { } as a struct initializer. - */ - braces = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKsemicolon: - case TOKreturn: - goto Lexpression; - - case TOKlcurly: - braces++; - continue; - - case TOKrcurly: - if (--braces == 0) - break; - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - is = new StructInitializer(loc); - nextToken(); - comma = 2; - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (comma == 1) - error("comma expected separating field initializers"); - t = peek(&token); - if (t->value == TOKcolon) - { - id = token.ident; - nextToken(); - nextToken(); // skip over ':' - } - else - { id = NULL; - } - value = parseInitializer(); - is->addInit(id, value); - comma = 1; - continue; - - case TOKcomma: - if (comma == 2) - error("expression expected, not `,`"); - nextToken(); - comma = 2; - continue; - - case TOKrcurly: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found EOF instead of initializer"); - break; - - default: - if (comma == 1) - error("comma expected separating field initializers"); - value = parseInitializer(); - is->addInit(NULL, value); - comma = 1; - continue; - //error("found `%s` instead of field initializer", token.toChars()); - //break; - } - break; - } - return is; - - case TOKlbracket: - /* Scan ahead to see if it is an array initializer or - * an expression. - * If it ends with a ';' ',' or '}', it is an array initializer. - */ - brackets = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brackets++; - continue; - - case TOKrbracket: - if (--brackets == 0) - { t = peek(t); - if (t->value != TOKsemicolon && - t->value != TOKcomma && - t->value != TOKrbracket && - t->value != TOKrcurly) - goto Lexpression; - break; - } - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - ia = new ArrayInitializer(loc); - nextToken(); - comma = 2; - while (1) - { - switch (token.value) - { - default: - if (comma == 1) - { error("comma expected separating array initializers, not %s", token.toChars()); - nextToken(); - break; - } - e = parseAssignExp(); - if (!e) - break; - if (token.value == TOKcolon) - { - nextToken(); - value = parseInitializer(); - } - else - { value = new ExpInitializer(e->loc, e); - e = NULL; - } - ia->addInit(e, value); - comma = 1; - continue; - - case TOKlcurly: - case TOKlbracket: - if (comma == 1) - error("comma expected separating array initializers, not %s", token.toChars()); - value = parseInitializer(); - if (token.value == TOKcolon) - { - nextToken(); - e = initializerToExpression(value); - value = parseInitializer(); - } - else - e = NULL; - ia->addInit(e, value); - comma = 1; - continue; - - case TOKcomma: - if (comma == 2) - error("expression expected, not `,`"); - nextToken(); - comma = 2; - continue; - - case TOKrbracket: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found `%s` instead of array initializer", token.toChars()); - break; - } - break; - } - return ia; - - case TOKvoid: - t = peek(&token); - if (t->value == TOKsemicolon || t->value == TOKcomma) - { - nextToken(); - return new VoidInitializer(loc); - } - goto Lexpression; - - default: - Lexpression: - e = parseAssignExp(); - ie = new ExpInitializer(loc, e); - return ie; - } -} - -/***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. - */ - -Expression *Parser::parseDefaultInitExp() -{ - if (token.value == TOKfile || - token.value == TOKfilefullpath || - token.value == TOKline || - token.value == TOKmodulestring || - token.value == TOKfuncstring || - token.value == TOKprettyfunc) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKrparen) - { - Expression *e = NULL; - if (token.value == TOKfile) - e = new FileInitExp(token.loc, TOKfile); - else if (token.value == TOKfilefullpath) - e = new FileInitExp(token.loc, TOKfilefullpath); - else if (token.value == TOKline) - e = new LineInitExp(token.loc); - else if (token.value == TOKmodulestring) - e = new ModuleInitExp(token.loc); - else if (token.value == TOKfuncstring) - e = new FuncInitExp(token.loc); - else if (token.value == TOKprettyfunc) - e = new PrettyFuncInitExp(token.loc); - else - assert(0); - nextToken(); - return e; - } - } - - Expression *e = parseAssignExp(); - return e; -} - -/***************************************** - */ - -void Parser::checkDanglingElse(Loc elseloc) -{ - if (token.value != TOKelse && - token.value != TOKcatch && - token.value != TOKfinally && - lookingForElse.linnum != 0) - { - warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); - } -} - -void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident) -{ - if (!alt) - return; - - const char *sp = !ident ? "" : " "; - const char *s = !ident ? "" : ident->toChars(); - if (alt & 1) // contains C-style function pointer syntax - error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t->toChars(), sp, s); - else - ::warning(loc, "instead of C-style syntax, use D-style syntax `%s%s%s`", t->toChars(), sp, s); - -} - -/***************************************** - * Parses `foreach` statements, `static foreach` statements and - * `static foreach` declarations. The template parameter - * `isStatic` is true, iff a `static foreach` should be parsed. - * If `isStatic` is true, `isDecl` can be true to indicate that a - * `static foreach` declaration should be parsed. - */ -Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl) -{ - TOK op = token.value; - - nextToken(); - check(TOKlparen); - - Parameters *parameters = new Parameters(); - - while (1) - { - Identifier *ai = NULL; - Type *at; - - StorageClass storageClass = 0; - StorageClass stc = 0; - Lagain: - if (stc) - { - storageClass = appendStorageClass(storageClass, stc); - nextToken(); - } - switch (token.value) - { - case TOKref: - stc = STCref; - goto Lagain; - - case TOKenum: - stc = STCmanifest; - goto Lagain; - - case TOKalias: - storageClass = appendStorageClass(storageClass, STCalias); - nextToken(); - break; - - case TOKconst: - if (peekNext() != TOKlparen) - { - stc = STCconst; - goto Lagain; - } - break; - - case TOKimmutable: - if (peekNext() != TOKlparen) - { - stc = STCimmutable; - goto Lagain; - } - break; - - case TOKshared: - if (peekNext() != TOKlparen) - { - stc = STCshared; - goto Lagain; - } - break; - - case TOKwild: - if (peekNext() != TOKlparen) - { - stc = STCwild; - goto Lagain; - } - break; - - default: - break; - } - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { ai = token.ident; - at = NULL; // infer argument type - nextToken(); - goto Larg; - } - } - at = parseType(&ai); - if (!ai) - error("no identifier for declarator %s", at->toChars()); - Larg: - Parameter *p = new Parameter(storageClass, at, ai, NULL, NULL); - parameters->push(p); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKsemicolon); - - Expression *aggr = parseExpression(); - if (token.value == TOKslice && parameters->length == 1) - { - Parameter *p = (*parameters)[0]; - delete parameters; - nextToken(); - Expression *upr = parseExpression(); - check(TOKrparen); - Loc endloc; - Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL; - if (isRange) - *isRange = true; - return new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc); - } - else - { - check(TOKrparen); - Loc endloc; - Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL; - if (isRange) - *isRange = false; - return new ForeachStatement(loc, op, parameters, aggr, body, endloc); - } -} - -Dsymbol *Parser::parseForeachStaticDecl(Loc loc, Dsymbol **pLastDecl) -{ - nextToken(); - - bool isRange = false; - Statement *s = parseForeach(loc, &isRange, true); - - return new StaticForeachDeclaration( - new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s, - isRange ? (ForeachRangeStatement *)s : NULL), - parseBlock(pLastDecl) - ); -} - -Statement *Parser::parseForeachStatic(Loc loc) -{ - nextToken(); - - bool isRange = false; - Statement *s = parseForeach(loc, &isRange, false); - - return new StaticForeachStatement(loc, - new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s, - isRange ? (ForeachRangeStatement *)s : NULL) - ); -} - -/***************************************** - * Input: - * flags PSxxxx - * Output: - * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement - */ - -Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc) -{ - Statement *s = NULL; - Condition *cond; - Statement *ifbody; - Statement *elsebody; - bool isfinal; - Loc loc = token.loc; - - //printf("parseStatement()\n"); - - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); - - switch (token.value) - { - case TOKidentifier: - { /* A leading identifier can be a declaration, label, or expression. - * The easiest case to check first is label: - */ - Token *t = peek(&token); - if (t->value == TOKcolon) - { - Token *nt = peek(t); - if (nt->value == TOKcolon) - { - // skip ident:: - nextToken(); - nextToken(); - nextToken(); - error("use `.` for member lookup, not `::`"); - break; - } - // It's a label - Identifier *ident = token.ident; - nextToken(); - nextToken(); - if (token.value == TOKrcurly) - s = NULL; - else if (token.value == TOKlcurly) - s = parseStatement(PScurly | PSscope); - else - s = parseStatement(PSsemi_ok); - s = new LabelStatement(loc, ident, s); - break; - } - } - /* fall through */ - case TOKdot: - case TOKtypeof: - case TOKvector: - case TOKtraits: - /* Bugzilla 15163: If tokens can be handled as - * old C-style declaration or D expression, prefer the latter. - */ - if (isDeclaration(&token, 3, TOKreserved, NULL)) - goto Ldeclaration; - else - goto Lexp; - break; - - case TOKassert: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKint128v: - case TOKuns128v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKstring: - case TOKxstring: - case TOKlparen: - case TOKcast: - case TOKmul: - case TOKmin: - case TOKadd: - case TOKtilde: - case TOKnot: - case TOKplusplus: - case TOKminusminus: - case TOKnew: - case TOKdelete: - case TOKdelegate: - case TOKfunction: - case TOKtypeid: - case TOKis: - case TOKlbracket: - case TOKfile: - case TOKfilefullpath: - case TOKline: - case TOKmodulestring: - case TOKfuncstring: - case TOKprettyfunc: - Lexp: - { - Expression *exp = parseExpression(); - check(TOKsemicolon, "statement"); - s = new ExpStatement(loc, exp); - break; - } - - case TOKstatic: - { // Look ahead to see if it's static assert() or static if() - - Token *t = peek(&token); - if (t->value == TOKassert) - { - s = new StaticAssertStatement(parseStaticAssert()); - break; - } - if (t->value == TOKif) - { - cond = parseStaticIfCondition(); - goto Lcondition; - } - else if (t->value == TOKforeach || t->value == TOKforeach_reverse) - { - s = parseForeachStatic(loc); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - } - if (t->value == TOKimport) - { - Dsymbols *imports = parseImport(); - s = new ImportStatement(loc, imports); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - } - goto Ldeclaration; - } - - case TOKfinal: - if (peekNext() == TOKswitch) - { - nextToken(); - isfinal = true; - goto Lswitch; - } - goto Ldeclaration; - - case TOKwchar: case TOKdchar: - case TOKbool: case TOKchar: - case TOKint8: case TOKuns8: - case TOKint16: case TOKuns16: - case TOKint32: case TOKuns32: - case TOKint64: case TOKuns64: - case TOKint128: case TOKuns128: - case TOKfloat32: case TOKfloat64: case TOKfloat80: - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: - case TOKvoid: - // bug 7773: int.max is always a part of expression - if (peekNext() == TOKdot) - goto Lexp; - if (peekNext() == TOKlparen) - goto Lexp; - /* fall through */ - - case TOKalias: - case TOKconst: - case TOKauto: - case TOKabstract: - case TOKextern: - case TOKalign: - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKdeprecated: - case TOKnothrow: - case TOKpure: - case TOKref: - case TOKgshared: - case TOKat: - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - Ldeclaration: - { - Dsymbols *a = parseDeclarations(false, NULL, NULL); - if (a->length > 1) - { - Statements *as = new Statements(); - as->reserve(a->length); - for (size_t i = 0; i < a->length; i++) - { - Dsymbol *d = (*a)[i]; - s = new ExpStatement(loc, d); - as->push(s); - } - s = new CompoundDeclarationStatement(loc, as); - } - else if (a->length == 1) - { - Dsymbol *d = (*a)[0]; - s = new ExpStatement(loc, d); - } - else - s = new ExpStatement(loc, (Expression *)NULL); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - } - - case TOKenum: - { /* Determine if this is a manifest constant declaration, - * or a conventional enum. - */ - Dsymbol *d; - Token *t = peek(&token); - if (t->value == TOKlcurly || t->value == TOKcolon) - d = parseEnum(); - else if (t->value != TOKidentifier) - goto Ldeclaration; - else - { - t = peek(t); - if (t->value == TOKlcurly || t->value == TOKcolon || - t->value == TOKsemicolon) - d = parseEnum(); - else - goto Ldeclaration; - } - s = new ExpStatement(loc, d); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - } - - case TOKmixin: - { - if (isDeclaration(&token, 3, TOKreserved, NULL)) - goto Ldeclaration; - Token *t = peek(&token); - if (t->value == TOKlparen) - { - // mixin(string) - Expression *e = parseAssignExp(); - check(TOKsemicolon); - if (e->op == TOKmixin) - { - CompileExp *cpe = (CompileExp *)e; - s = new CompileStatement(loc, cpe->exps); - } - else - { - s = new ExpStatement(loc, e); - } - break; - } - Dsymbol *d = parseMixin(); - s = new ExpStatement(loc, d); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - } - - case TOKlcurly: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = Loc(); - - nextToken(); - //if (token.value == TOKsemicolon) - //error("use `{ }` for an empty statement, not a `;`"); - Statements *statements = new Statements(); - while (token.value != TOKrcurly && token.value != TOKeof) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - if (endPtr) *endPtr = token.ptr; - endloc = token.loc; - if (pEndloc) - { - *pEndloc = token.loc; - pEndloc = NULL; // don't set it again - } - s = new CompoundStatement(loc, statements); - if (flags & (PSscope | PScurlyscope)) - s = new ScopeStatement(loc, s, token.loc); - check(TOKrcurly, "compound statement"); - lookingForElse = lookingForElseSave; - break; - } - - case TOKwhile: - { - nextToken(); - check(TOKlparen); - Expression *condition = parseExpression(); - check(TOKrparen); - Loc endloc; - Statement *body = parseStatement(PSscope, NULL, &endloc); - s = new WhileStatement(loc, condition, body, endloc); - break; - } - - case TOKsemicolon: - if (!(flags & PSsemi_ok)) - { - if (flags & PSsemi) - deprecation("use `{ }` for an empty statement, not a `;`"); - else - error("use `{ }` for an empty statement, not a `;`"); - } - nextToken(); - s = new ExpStatement(loc, (Expression *)NULL); - break; - - case TOKdo: - { Statement *body; - Expression *condition; - - nextToken(); - Loc lookingForElseSave = lookingForElse; - lookingForElse = Loc(); - body = parseStatement(PSscope); - lookingForElse = lookingForElseSave; - check(TOKwhile); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - if (token.value == TOKsemicolon) - nextToken(); - else - error("terminating `;` required after do-while statement"); - s = new DoStatement(loc, body, condition, token.loc); - break; - } - - case TOKfor: - { - Statement *init; - Expression *condition; - Expression *increment; - - nextToken(); - check(TOKlparen); - if (token.value == TOKsemicolon) - { init = NULL; - nextToken(); - } - else - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = Loc(); - init = parseStatement(0); - lookingForElse = lookingForElseSave; - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; - nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - Loc endloc; - Statement *body = parseStatement(PSscope, NULL, &endloc); - s = new ForStatement(loc, init, condition, increment, body, endloc); - break; - } - - case TOKforeach: - case TOKforeach_reverse: - { - s = parseForeach(loc, NULL, false); - break; - } - - case TOKif: - { - Parameter *param = NULL; - Expression *condition; - - nextToken(); - check(TOKlparen); - - StorageClass storageClass = 0; - StorageClass stc = 0; - LagainStc: - if (stc) - { - storageClass = appendStorageClass(storageClass, stc); - nextToken(); - } - switch (token.value) - { - case TOKref: - stc = STCref; - goto LagainStc; - case TOKauto: - stc = STCauto; - goto LagainStc; - case TOKconst: - if (peekNext() != TOKlparen) - { - stc = STCconst; - goto LagainStc; - } - break; - case TOKimmutable: - if (peekNext() != TOKlparen) - { - stc = STCimmutable; - goto LagainStc; - } - break; - case TOKshared: - if (peekNext() != TOKlparen) - { - stc = STCshared; - goto LagainStc; - } - break; - case TOKwild: - if (peekNext() != TOKlparen) - { - stc = STCwild; - goto LagainStc; - } - break; - default: - break; - } - - if (storageClass != 0 && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - Identifier *ai = token.ident; - Type *at = NULL; // infer parameter type - nextToken(); - check(TOKassign); - param = new Parameter(storageClass, at, ai, NULL, NULL); - } - else if (isDeclaration(&token, 2, TOKassign, NULL)) - { - Identifier *ai; - Type *at = parseType(&ai); - check(TOKassign); - param = new Parameter(storageClass, at, ai, NULL, NULL); - } - - condition = parseExpression(); - check(TOKrparen); - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; - ifbody = parseStatement(PSscope); - lookingForElse = lookingForElseSave; - } - if (token.value == TOKelse) - { - Loc elseloc = token.loc; - nextToken(); - elsebody = parseStatement(PSscope); - checkDanglingElse(elseloc); - } - else - elsebody = NULL; - if (condition && ifbody) - s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc); - else - s = NULL; // don't propagate parsing errors - break; - } - - case TOKscope: - if (peek(&token)->value != TOKlparen) - goto Ldeclaration; // scope used as storage class - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("scope identifier expected"); - goto Lerror; - } - else - { TOK t = TOKon_scope_exit; - Identifier *id = token.ident; - - if (id == Id::exit) - t = TOKon_scope_exit; - else if (id == Id::failure) - t = TOKon_scope_failure; - else if (id == Id::success) - t = TOKon_scope_success; - else - error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - Statement *st = parseStatement(PSscope); - s = new ScopeGuardStatement(loc, t, st); - break; - } - - case TOKdebug: - nextToken(); - if (token.value == TOKassign) - { - error("debug conditions can only be declared at module scope"); - nextToken(); - nextToken(); - goto Lerror; - } - cond = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - if (token.value == TOKassign) - { - error("version conditions can only be declared at module scope"); - nextToken(); - nextToken(); - goto Lerror; - } - cond = parseVersionCondition(); - goto Lcondition; - - Lcondition: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; - ifbody = parseStatement(0); - lookingForElse = lookingForElseSave; - } - elsebody = NULL; - if (token.value == TOKelse) - { - Loc elseloc = token.loc; - nextToken(); - elsebody = parseStatement(0); - checkDanglingElse(elseloc); - } - s = new ConditionalStatement(loc, cond, ifbody, elsebody); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...); - else - check(TOKrparen); // pragma(identifier); - if (token.value == TOKsemicolon) - { nextToken(); - body = NULL; - } - else - body = parseStatement(PSsemi); - s = new PragmaStatement(loc, ident, args, body); - break; - } - - case TOKswitch: - isfinal = false; - goto Lswitch; - - Lswitch: - { - nextToken(); - check(TOKlparen); - Expression *condition = parseExpression(); - check(TOKrparen); - Statement *body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body, isfinal); - break; - } - - case TOKcase: - { Expression *exp; - Expressions cases; // array of Expression's - Expression *last = NULL; - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - check(TOKcolon); - - /* case exp: .. case last: - */ - if (token.value == TOKslice) - { - if (cases.length > 1) - error("only one case allowed for start of case range"); - nextToken(); - check(TOKcase); - last = parseAssignExp(); - check(TOKcolon); - } - - if (flags & PScurlyscope) - { - Statements *statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKeof && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - } - else - s = parseStatement(PSsemi | PScurlyscope); - s = new ScopeStatement(loc, s, token.loc); - - if (last) - { - s = new CaseRangeStatement(loc, exp, last, s); - } - else - { - // Keep cases in order by building the case statements backwards - for (size_t i = cases.length; i; i--) - { - exp = cases[i - 1]; - s = new CaseStatement(loc, exp, s); - } - } - break; - } - - case TOKdefault: - { - nextToken(); - check(TOKcolon); - - if (flags & PScurlyscope) - { - Statements *statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKeof && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - } - else - s = parseStatement(PSsemi | PScurlyscope); - s = new ScopeStatement(loc, s, token.loc); - s = new DefaultStatement(loc, s); - break; - } - - case TOKreturn: - { Expression *exp; - - nextToken(); - if (token.value == TOKsemicolon) - exp = NULL; - else - exp = parseExpression(); - check(TOKsemicolon, "return statement"); - s = new ReturnStatement(loc, exp); - break; - } - - case TOKbreak: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "break statement"); - s = new BreakStatement(loc, ident); - break; - } - - case TOKcontinue: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "continue statement"); - s = new ContinueStatement(loc, ident); - break; - } - - case TOKgoto: - { Identifier *ident; - - nextToken(); - if (token.value == TOKdefault) - { - nextToken(); - s = new GotoDefaultStatement(loc); - } - else if (token.value == TOKcase) - { - Expression *exp = NULL; - - nextToken(); - if (token.value != TOKsemicolon) - exp = parseExpression(); - s = new GotoCaseStatement(loc, exp); - } - else - { - if (token.value != TOKidentifier) - { - error("identifier expected following goto"); - ident = NULL; - } - else - { - ident = token.ident; - nextToken(); - } - s = new GotoStatement(loc, ident); - } - check(TOKsemicolon, "goto statement"); - break; - } - - case TOKsynchronized: - { Expression *exp; - Statement *body; - - Token *t = peek(&token); - if (skipAttributes(t, &t) && t->value == TOKclass) - goto Ldeclaration; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseExpression(); - check(TOKrparen); - } - else - exp = NULL; - body = parseStatement(PSscope); - s = new SynchronizedStatement(loc, exp, body); - break; - } - - case TOKwith: - { Expression *exp; - Statement *body; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WithStatement(loc, exp, body, token.loc); - break; - } - - case TOKtry: - { Statement *body; - Catches *catches = NULL; - Statement *finalbody = NULL; - - nextToken(); - Loc lookingForElseSave = lookingForElse; - lookingForElse = Loc(); - body = parseStatement(PSscope); - lookingForElse = lookingForElseSave; - while (token.value == TOKcatch) - { - Statement *handler; - Catch *c; - Type *t; - Identifier *id; - Loc catchloc = token.loc; - - nextToken(); - if (token.value == TOKlcurly || token.value != TOKlparen) - { - t = NULL; - id = NULL; - } - else - { - check(TOKlparen); - id = NULL; - t = parseType(&id); - check(TOKrparen); - } - handler = parseStatement(0); - c = new Catch(catchloc, t, id, handler); - if (!catches) - catches = new Catches(); - catches->push(c); - } - - if (token.value == TOKfinally) - { - nextToken(); - finalbody = parseStatement(PSscope); - } - - s = body; - if (!catches && !finalbody) - error("catch or finally expected following try"); - else - { if (catches) - s = new TryCatchStatement(loc, body, catches); - if (finalbody) - s = new TryFinallyStatement(loc, s, finalbody); - } - break; - } - - case TOKthrow: - { Expression *exp; - - nextToken(); - exp = parseExpression(); - check(TOKsemicolon, "throw statement"); - s = new ThrowStatement(loc, exp); - break; - } - - case TOKasm: - { - // Parse the asm block into a sequence of AsmStatements, - // each AsmStatement is one instruction. - // Separate out labels. - // Defer parsing of AsmStatements until semantic processing. - - Loc labelloc; - - nextToken(); - StorageClass stc = parsePostfix(STCundefined, NULL); - if (stc & (STCconst | STCimmutable | STCshared | STCwild)) - error("const/immutable/shared/inout attributes are not allowed on asm blocks"); - - check(TOKlcurly); - Token *toklist = NULL; - Token **ptoklist = &toklist; - Identifier *label = NULL; - Statements *statements = new Statements(); - size_t nestlevel = 0; - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (!toklist) - { - // Look ahead to see if it is a label - Token *t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - label = token.ident; - labelloc = token.loc; - nextToken(); - nextToken(); - continue; - } - } - goto Ldefault; - - case TOKlcurly: - ++nestlevel; - goto Ldefault; - - case TOKrcurly: - if (nestlevel > 0) - { - --nestlevel; - goto Ldefault; - } - - if (toklist || label) - { - error("asm statements must end in `;`"); - } - break; - - case TOKsemicolon: - if (nestlevel != 0) - error("mismatched number of curly brackets"); - - s = NULL; - if (toklist || label) - { - // Create AsmStatement from list of tokens we've saved - s = new AsmStatement(token.loc, toklist); - toklist = NULL; - ptoklist = &toklist; - if (label) - { s = new LabelStatement(labelloc, label, s); - label = NULL; - } - statements->push(s); - } - nextToken(); - continue; - - case TOKeof: - /* { */ - error("matching `}` expected, not end of file"); - goto Lerror; - /* fall through */ - - default: - Ldefault: - *ptoklist = Token::alloc(); - memcpy(*ptoklist, &token, sizeof(Token)); - ptoklist = &(*ptoklist)->next; - *ptoklist = NULL; - - nextToken(); - continue; - } - break; - } - s = new CompoundAsmStatement(loc, statements, stc); - nextToken(); - break; - } - - case TOKimport: - { - Dsymbols *imports = parseImport(); - s = new ImportStatement(loc, imports); - if (flags & PSscope) - s = new ScopeStatement(loc, s, token.loc); - break; - } - - case TOKtemplate: - { - Dsymbol *d = parseTemplateDeclaration(); - s = new ExpStatement(loc, d); - break; - } - - default: - error("found `%s` instead of statement", token.toChars()); - goto Lerror; - - Lerror: - while (token.value != TOKrcurly && - token.value != TOKsemicolon && - token.value != TOKeof) - nextToken(); - if (token.value == TOKsemicolon) - nextToken(); - s = NULL; - break; - } - if (pEndloc) - *pEndloc = token.loc; - return s; -} - -void Parser::check(TOK value) -{ - check(token.loc, value); -} - -void Parser::check(Loc loc, TOK value) -{ - if (token.value != value) - error(loc, "found `%s` when expecting `%s`", token.toChars(), Token::toChars(value)); - nextToken(); -} - -void Parser::check(TOK value, const char *string) -{ - if (token.value != value) - error("found `%s` when expecting `%s` following %s", - token.toChars(), Token::toChars(value), string); - nextToken(); -} - -void Parser::checkParens(TOK value, Expression *e) -{ - if (precedence[e->op] == PREC_rel && !e->parens) - error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value)); -} - -/************************************ - * Determine if the scanner is sitting on the start of a declaration. - * Input: - * needId 0 no identifier - * 1 identifier optional - * 2 must have identifier - * 3 must have identifier, but don't recognize old C-style syntax. - * Output: - * if *pt is not NULL, it is set to the ending token, which would be endtok - */ - -bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt) -{ - //printf("isDeclaration(needId = %d)\n", needId); - int haveId = 0; - int haveTpl = 0; - - while (1) - { - if ((t->value == TOKconst || - t->value == TOKimmutable || - t->value == TOKwild || - t->value == TOKshared) && - peek(t)->value != TOKlparen) - { - /* const type - * immutable type - * shared type - * wild type - */ - t = peek(t); - continue; - } - break; - } - - if (!isBasicType(&t)) - { - goto Lisnot; - } - if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3)) - goto Lisnot; - if ((needId == 0 && !haveId) || - (needId == 1) || - (needId == 2 && haveId) || - (needId == 3 && haveId)) - { - if (pt) - *pt = t; - goto Lis; - } - else - goto Lisnot; - -Lis: - //printf("\tis declaration, t = %s\n", t->toChars()); - return true; - -Lisnot: - //printf("\tis not declaration\n"); - return false; -} - -bool Parser::isBasicType(Token **pt) -{ - // This code parallels parseBasicType() - Token *t = *pt; - - switch (t->value) - { - case TOKwchar: case TOKdchar: - case TOKbool: case TOKchar: - case TOKint8: case TOKuns8: - case TOKint16: case TOKuns16: - case TOKint32: case TOKuns32: - case TOKint64: case TOKuns64: - case TOKint128: case TOKuns128: - case TOKfloat32: case TOKfloat64: case TOKfloat80: - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: - case TOKvoid: - t = peek(t); - break; - - case TOKidentifier: - L5: - t = peek(t); - if (t->value == TOKnot) - { - goto L4; - } - goto L3; - while (1) - { - L2: - t = peek(t); - L3: - if (t->value == TOKdot) - { - Ldot: - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - if (t->value != TOKnot) - goto L3; - L4: - /* Seen a ! - * Look for: - * !( args ), !identifier, etc. - */ - t = peek(t); - switch (t->value) - { - case TOKidentifier: - goto L5; - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - goto L3; - case TOKwchar: case TOKdchar: - case TOKbool: case TOKchar: - case TOKint8: case TOKuns8: - case TOKint16: case TOKuns16: - case TOKint32: case TOKuns32: - case TOKint64: case TOKuns64: - case TOKint128: case TOKuns128: - case TOKfloat32: case TOKfloat64: case TOKfloat80: - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: - case TOKvoid: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKint128v: - case TOKuns128v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKxstring: - case TOKfile: - case TOKfilefullpath: - case TOKline: - case TOKmodulestring: - case TOKfuncstring: - case TOKprettyfunc: - goto L2; - default: - goto Lfalse; - } - } - else - break; - } - break; - - case TOKdot: - goto Ldot; - - case TOKtypeof: - case TOKvector: - case TOKmixin: - /* typeof(exp).identifier... - */ - t = peek(t); - if (!skipParens(t, &t)) - goto Lfalse; - goto L3; - - case TOKtraits: - { - // __traits(getMember - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - Token *lp = t; - t = peek(t); - if (t->value != TOKidentifier || t->ident != Id::getMember) - goto Lfalse; - if (!skipParens(lp, &lp)) - goto Lfalse; - // we are in a lookup for decl VS statement - // so we expect a declarator following __trait if it's a type. - // other usages wont be ambiguous (alias, template instance, type qual, etc.) - if (lp->value != TOKidentifier) - goto Lfalse; - - break; - } - - case TOKconst: - case TOKimmutable: - case TOKshared: - case TOKwild: - // const(type) or immutable(type) or shared(type) or wild(type) - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - t = peek(t); - if (!isDeclaration(t, 0, TOKrparen, &t)) - { - goto Lfalse; - } - t = peek(t); - break; - - default: - goto Lfalse; - } - *pt = t; - //printf("is\n"); - return true; - -Lfalse: - //printf("is not\n"); - return false; -} - -bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax) -{ // This code parallels parseDeclarator() - Token *t = *pt; - int parens; - - //printf("Parser::isDeclarator() %s\n", t->toChars()); - if (t->value == TOKassign) - return false; - - while (1) - { - parens = false; - switch (t->value) - { - case TOKmul: - //case TOKand: - t = peek(t); - continue; - - case TOKlbracket: - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { - // It's an associative array declaration - t = peek(t); - - // ...[type].ident - if (t->value == TOKdot && peek(t)->value == TOKidentifier) - { - t = peek(t); - t = peek(t); - } - } - else - { - // [ expression ] - // [ expression .. expression ] - if (!isExpression(&t)) - return false; - if (t->value == TOKslice) - { - t = peek(t); - if (!isExpression(&t)) - return false; - if (t->value != TOKrbracket) - return false; - t = peek(t); - } - else - { - if (t->value != TOKrbracket) - return false; - t = peek(t); - - // ...[index].ident - if (t->value == TOKdot && peek(t)->value == TOKidentifier) - { - t = peek(t); - t = peek(t); - } - } - } - continue; - - case TOKidentifier: - if (*haveId) - return false; - *haveId = true; - t = peek(t); - break; - - case TOKlparen: - if (!allowAltSyntax) - return false; // Do not recognize C-style declarations. - - t = peek(t); - - if (t->value == TOKrparen) - return false; // () is not a declarator - - /* Regard ( identifier ) as not a declarator - * BUG: what about ( *identifier ) in - * f(*p)(x); - * where f is a class instance with overloaded () ? - * Should we just disallow C-style function pointer declarations? - */ - if (t->value == TOKidentifier) - { Token *t2 = peek(t); - if (t2->value == TOKrparen) - return false; - } - - - if (!isDeclarator(&t, haveId, NULL, TOKrparen)) - return false; - t = peek(t); - parens = true; - break; - - case TOKdelegate: - case TOKfunction: - t = peek(t); - if (!isParameters(&t)) - return false; - skipAttributes(t, &t); - continue; - default: break; - } - break; - } - - while (1) - { - switch (t->value) - { -#if CARRAYDECL - case TOKlbracket: - parens = false; - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - if (!isExpression(&t)) - return false; - if (t->value != TOKrbracket) - return false; - t = peek(t); - } - continue; -#endif - - case TOKlparen: - parens = false; - if (Token *tk = peekPastParen(t)) - { - if (tk->value == TOKlparen) - { - if (!haveTpl) return false; - *haveTpl = 1; - t = tk; - } - else if (tk->value == TOKassign) - { - if (!haveTpl) return false; - *haveTpl = 1; - *pt = tk; - return true; - } - } - if (!isParameters(&t)) - return false; - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKpure: - case TOKnothrow: - case TOKreturn: - case TOKscope: - t = peek(t); - continue; - case TOKat: - t = peek(t); // skip '@' - t = peek(t); // skip identifier - continue; - default: - break; - } - break; - } - continue; - - case TOKidentifier: - if (t->ident != Id::_body) - goto Ldefault; - /* fall through */ - - // Valid tokens that follow a declaration - case TOKrparen: - case TOKrbracket: - case TOKassign: - case TOKcomma: - case TOKdotdotdot: - case TOKsemicolon: - case TOKlcurly: - case TOKin: - case TOKout: - case TOKdo: - LTOKdo: - // The !parens is to disallow unnecessary parentheses - if (!parens && (endtok == TOKreserved || endtok == t->value)) - { - *pt = t; - return true; - } - return false; - - case TOKif: - return haveTpl ? true : false; - - // Used for mixin type parsing - case TOKeof: - if (endtok == TOKeof) - goto LTOKdo; - return false; - - default: - Ldefault: - return false; - } - } - assert(0); -} - - -bool Parser::isParameters(Token **pt) -{ // This code parallels parseParameters() - Token *t = *pt; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return false; - - t = peek(t); - for (;1; t = peek(t)) - { - L1: - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - - case TOKin: - case TOKout: - case TOKref: - case TOKlazy: - case TOKscope: - case TOKfinal: - case TOKauto: - case TOKreturn: - continue; - - case TOKconst: - case TOKimmutable: - case TOKshared: - case TOKwild: - t = peek(t); - if (t->value == TOKlparen) - { - t = peek(t); - if (!isDeclaration(t, 0, TOKrparen, &t)) - return false; - t = peek(t); // skip past closing ')' - goto L2; - } - goto L1; - - default: - { if (!isBasicType(&t)) - return false; - L2: - int tmp = false; - if (t->value != TOKdotdotdot && - !isDeclarator(&t, &tmp, NULL, TOKreserved)) - return false; - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return false; - } - if (t->value == TOKdotdotdot) - { - t = peek(t); - break; - } - } - if (t->value == TOKcomma) - { - continue; - } - break; - } - break; - } - if (t->value != TOKrparen) - return false; - t = peek(t); - *pt = t; - return true; -} - -bool Parser::isExpression(Token **pt) -{ - // This is supposed to determine if something is an expression. - // What it actually does is scan until a closing right bracket - // is found. - - Token *t = *pt; - int brnest = 0; - int panest = 0; - int curlynest = 0; - - for (;; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brnest++; - continue; - - case TOKrbracket: - if (--brnest >= 0) - continue; - break; - - case TOKlparen: - panest++; - continue; - - case TOKcomma: - if (brnest || panest) - continue; - break; - - case TOKrparen: - if (--panest >= 0) - continue; - break; - - case TOKlcurly: - curlynest++; - continue; - - case TOKrcurly: - if (--curlynest >= 0) - continue; - return false; - - case TOKslice: - if (brnest) - continue; - break; - - case TOKsemicolon: - if (curlynest) - continue; - return false; - - case TOKeof: - return false; - - default: - continue; - } - break; - } - - *pt = t; - return true; -} - -/******************************************* - * Skip parens, brackets. - * Input: - * t is on opening ( - * Output: - * *pt is set to closing token, which is ')' on success - * Returns: - * true successful - * false some parsing error - */ - -bool Parser::skipParens(Token *t, Token **pt) -{ - if (t->value != TOKlparen) - return false; - - int parens = 0; - - while (1) - { - switch (t->value) - { - case TOKlparen: - parens++; - break; - - case TOKrparen: - parens--; - if (parens < 0) - goto Lfalse; - if (parens == 0) - goto Ldone; - break; - - case TOKeof: - goto Lfalse; - - default: - break; - } - t = peek(t); - } - - Ldone: - if (pt) - *pt = peek(t); // skip found rparen - return true; - - Lfalse: - return false; -} - -bool Parser::skipParensIf(Token *t, Token **pt) -{ - if (t->value != TOKlparen) - { - if (pt) - *pt = t; - return true; - } - return skipParens(t, pt); -} - -/******************************************* - * Skip attributes. - * Input: - * t is on a candidate attribute - * Output: - * *pt is set to first non-attribute token on success - * Returns: - * true successful - * false some parsing error - */ - -bool Parser::skipAttributes(Token *t, Token **pt) -{ - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKfinal: - case TOKauto: - case TOKscope: - case TOKoverride: - case TOKabstract: - case TOKsynchronized: - break; - case TOKdeprecated: - if (peek(t)->value == TOKlparen) - { - t = peek(t); - if (!skipParens(t, &t)) - goto Lerror; - // t is on the next of closing parenthesis - continue; - } - break; - case TOKnothrow: - case TOKpure: - case TOKref: - case TOKgshared: - case TOKreturn: - //case TOKmanifest: - break; - case TOKat: - t = peek(t); - if (t->value == TOKidentifier) - { - /* @identifier - * @identifier!arg - * @identifier!(arglist) - * any of the above followed by (arglist) - * @predefined_attribute - */ - if (t->ident == Id::property || - t->ident == Id::nogc || - t->ident == Id::safe || - t->ident == Id::trusted || - t->ident == Id::system || - t->ident == Id::disable) - break; - t = peek(t); - if (t->value == TOKnot) - { - t = peek(t); - if (t->value == TOKlparen) - { - // @identifier!(arglist) - if (!skipParens(t, &t)) - goto Lerror; - // t is on the next of closing parenthesis - } - else - { - // @identifier!arg - // Do low rent skipTemplateArgument - if (t->value == TOKvector) - { - // identifier!__vector(type) - t = peek(t); - if (!skipParens(t, &t)) - goto Lerror; - } - else - t = peek(t); - } - } - if (t->value == TOKlparen) - { - if (!skipParens(t, &t)) - goto Lerror; - // t is on the next of closing parenthesis - continue; - } - continue; - } - if (t->value == TOKlparen) - { - // @( ArgumentList ) - if (!skipParens(t, &t)) - goto Lerror; - // t is on the next of closing parenthesis - continue; - } - goto Lerror; - default: - goto Ldone; - } - t = peek(t); - } - - Ldone: - if (pt) - *pt = t; - return true; - - Lerror: - return false; -} - -/********************************* Expression Parser ***************************/ - -Expression *Parser::parsePrimaryExp() -{ - Expression *e; - Type *t; - Identifier *id; - Loc loc = token.loc; - - //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); - switch (token.value) - { - case TOKidentifier: - { - Token *t1 = peek(&token); - Token *t2 = peek(t1); - if (t1->value == TOKmin && t2->value == TOKgt) - { - // skip ident. - nextToken(); - nextToken(); - nextToken(); - error("use `.` for member lookup, not `->`"); - goto Lerr; - } - - if (peekNext() == TOKgoesto) - goto case_delegate; - - id = token.ident; - nextToken(); - TOK save; - if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin) - { - // identifier!(template-argument-list) - TemplateInstance *tempinst; - tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArguments(); - e = new ScopeExp(loc, tempinst); - } - else - e = new IdentifierExp(loc, id); - break; - } - - case TOKdollar: - if (!inBrackets) - error("`$` is valid only inside [] of index or slice"); - e = new DollarExp(loc); - nextToken(); - break; - - case TOKdot: - // Signal global scope '.' operator with "" identifier - e = new IdentifierExp(loc, Id::empty); - break; - - case TOKthis: - e = new ThisExp(loc); - nextToken(); - break; - - case TOKsuper: - e = new SuperExp(loc); - nextToken(); - break; - - case TOKint32v: - e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); - nextToken(); - break; - - case TOKuns32v: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); - nextToken(); - break; - - case TOKint64v: - e = new IntegerExp(loc, token.int64value, Type::tint64); - nextToken(); - break; - - case TOKuns64v: - e = new IntegerExp(loc, token.uns64value, Type::tuns64); - nextToken(); - break; - - case TOKfloat32v: - e = new RealExp(loc, token.floatvalue, Type::tfloat32); - nextToken(); - break; - - case TOKfloat64v: - e = new RealExp(loc, token.floatvalue, Type::tfloat64); - nextToken(); - break; - - case TOKfloat80v: - e = new RealExp(loc, token.floatvalue, Type::tfloat80); - nextToken(); - break; - - case TOKimaginary32v: - e = new RealExp(loc, token.floatvalue, Type::timaginary32); - nextToken(); - break; - - case TOKimaginary64v: - e = new RealExp(loc, token.floatvalue, Type::timaginary64); - nextToken(); - break; - - case TOKimaginary80v: - e = new RealExp(loc, token.floatvalue, Type::timaginary80); - nextToken(); - break; - - case TOKnull: - e = new NullExp(loc); - nextToken(); - break; - - case TOKfile: - { - const char *s = loc.filename ? loc.filename : mod->ident->toChars(); - e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0); - nextToken(); - break; - } - - case TOKfilefullpath: - { - assert(loc.filename); // __FILE_FULL_PATH__ does not work with an invalid location - const char *s = FileName::toAbsolute(loc.filename); - e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0); - nextToken(); - break; - } - - case TOKline: - e = new IntegerExp(loc, loc.linnum, Type::tint32); - nextToken(); - break; - - case TOKmodulestring: - { - const char *s = md ? md->toChars() : mod->toChars(); - e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0); - nextToken(); - break; - } - - case TOKfuncstring: - e = new FuncInitExp(loc); - nextToken(); - break; - - case TOKprettyfunc: - e = new PrettyFuncInitExp(loc); - nextToken(); - break; - - case TOKtrue: - e = new IntegerExp(loc, 1, Type::tbool); - nextToken(); - break; - - case TOKfalse: - e = new IntegerExp(loc, 0, Type::tbool); - nextToken(); - break; - - case TOKcharv: - e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); - nextToken(); - break; - - case TOKwcharv: - e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); - nextToken(); - break; - - case TOKdcharv: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); - nextToken(); - break; - - case TOKstring: - case TOKxstring: - { - // cat adjacent strings - utf8_t *s = token.ustring; - size_t len = token.len; - unsigned char postfix = token.postfix; - while (1) - { - const Token prev = token; - nextToken(); - if (token.value == TOKstring || - token.value == TOKxstring) - { - if (token.postfix) - { if (token.postfix != postfix) - error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); - postfix = token.postfix; - } - - deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead", - prev.toChars(), token.toChars()); - - size_t len1 = len; - size_t len2 = token.len; - len = len1 + len2; - utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t)); - memcpy(s2, s, len1 * sizeof(utf8_t)); - memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t)); - s = s2; - } - else - break; - } - e = new StringExp(loc, s, len, postfix); - break; - } - - case TOKvoid: t = Type::tvoid; goto LabelX; - case TOKint8: t = Type::tint8; goto LabelX; - case TOKuns8: t = Type::tuns8; goto LabelX; - case TOKint16: t = Type::tint16; goto LabelX; - case TOKuns16: t = Type::tuns16; goto LabelX; - case TOKint32: t = Type::tint32; goto LabelX; - case TOKuns32: t = Type::tuns32; goto LabelX; - case TOKint64: t = Type::tint64; goto LabelX; - case TOKuns64: t = Type::tuns64; goto LabelX; - case TOKint128: t = Type::tint128; goto LabelX; - case TOKuns128: t = Type::tuns128; goto LabelX; - case TOKfloat32: t = Type::tfloat32; goto LabelX; - case TOKfloat64: t = Type::tfloat64; goto LabelX; - case TOKfloat80: t = Type::tfloat80; goto LabelX; - case TOKimaginary32: t = Type::timaginary32; goto LabelX; - case TOKimaginary64: t = Type::timaginary64; goto LabelX; - case TOKimaginary80: t = Type::timaginary80; goto LabelX; - case TOKcomplex32: t = Type::tcomplex32; goto LabelX; - case TOKcomplex64: t = Type::tcomplex64; goto LabelX; - case TOKcomplex80: t = Type::tcomplex80; goto LabelX; - case TOKbool: t = Type::tbool; goto LabelX; - case TOKchar: t = Type::tchar; goto LabelX; - case TOKwchar: t = Type::twchar; goto LabelX; - case TOKdchar: t = Type::tdchar; goto LabelX; - LabelX: - nextToken(); - if (token.value == TOKlparen) - { - e = new TypeExp(loc, t); - e = new CallExp(loc, e, parseArguments()); - break; - } - check(TOKdot, t->toChars()); - if (token.value != TOKidentifier) - { error("found `%s` when expecting identifier following `%s.`", token.toChars(), t->toChars()); - goto Lerr; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - break; - - case TOKtypeof: - { - t = parseTypeof(); - e = new TypeExp(loc, t); - break; - } - - case TOKvector: - { - t = parseVector(); - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { - nextToken(); - check(TOKlparen, "typeid"); - RootObject *o = parseTypeOrAssignExp(); - check(TOKrparen); - e = new TypeidExp(loc, o); - break; - } - - case TOKtraits: - { /* __traits(identifier, args...) - */ - Identifier *ident; - Objects *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("__traits(identifier, args...) expected"); - goto Lerr; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma) - args = parseTemplateArgumentList(); // __traits(identifier, args...) - else - check(TOKrparen); // __traits(identifier) - - e = new TraitsExp(loc, ident, args); - break; - } - - case TOKis: - { - Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - TOK tok = TOKreserved; - TOK tok2 = TOKreserved; - TemplateParameters *tpl = NULL; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKidentifier && peekNext() == TOKlparen) - { - error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars()); - nextToken(); - Token *tempTok = peekPastParen(&token); - memcpy(&token, tempTok, sizeof(Token)); - goto Lerr; - } - targ = parseType(&ident); - if (token.value == TOKcolon || token.value == TOKequal) - { - tok = token.value; - nextToken(); - if (tok == TOKequal && - (token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKsuper || - token.value == TOKenum || - token.value == TOKinterface || - token.value == TOKmodule || - token.value == TOKpackage || - token.value == TOKargTypes || - token.value == TOKparameters || - (token.value == TOKconst && peek(&token)->value == TOKrparen) || - (token.value == TOKimmutable && peek(&token)->value == TOKrparen) || - (token.value == TOKshared && peek(&token)->value == TOKrparen) || - (token.value == TOKwild && peek(&token)->value == TOKrparen) || - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn || - (token.value == TOKvector && peek(&token)->value == TOKrparen))) - { - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseType(); - } - } - if (tspec) - { - if (token.value == TOKcomma) - tpl = parseTemplateParameterList(1); - else - { - tpl = new TemplateParameters(); - check(TOKrparen); - } - } - else - check(TOKrparen); - } - else - { - error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl); - break; - } - - case TOKassert: - { Expression *msg = NULL; - - nextToken(); - check(TOKlparen, "assert"); - e = parseAssignExp(); - if (token.value == TOKcomma) - { - nextToken(); - if (token.value != TOKrparen) - { - msg = parseAssignExp(); - if (token.value == TOKcomma) - nextToken(); - } - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - break; - } - - case TOKmixin: - { - // https://dlang.org/spec/expression.html#mixin_expressions - nextToken(); - if (token.value != TOKlparen) - error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`"); - e = new CompileExp(loc, parseArguments()); - break; - } - - case TOKimport: - { - nextToken(); - check(TOKlparen, "import"); - e = parseAssignExp(); - check(TOKrparen); - e = new ImportExp(loc, e); - break; - } - - case TOKnew: - e = parseNewExp(NULL); - break; - - case TOKref: - { - if (peekNext() == TOKlparen) - { - Token *tk = peekPastParen(peek(&token)); - if (skipAttributes(tk, &tk) && - (tk->value == TOKgoesto || tk->value == TOKlcurly)) - { - // ref (arguments) => expression - // ref (arguments) { statements... } - goto case_delegate; - } - } - nextToken(); - error("found `%s` when expecting function literal following `ref`", token.toChars()); - goto Lerr; - } - - case TOKlparen: - { - Token *tk = peekPastParen(&token); - if (skipAttributes(tk, &tk) && - (tk->value == TOKgoesto || tk->value == TOKlcurly)) - { - // (arguments) => expression - // (arguments) { statements... } - goto case_delegate; - } - - // ( expression ) - nextToken(); - e = parseExpression(); - e->parens = 1; - check(loc, TOKrparen); - break; - } - - case TOKlbracket: - { /* Parse array literals and associative array literals: - * [ value, value, value ... ] - * [ key:value, key:value, key:value ... ] - */ - Expressions *values = new Expressions(); - Expressions *keys = NULL; - - nextToken(); - while (token.value != TOKrbracket && token.value != TOKeof) - { - e = parseAssignExp(); - if (token.value == TOKcolon && (keys || values->length == 0)) - { nextToken(); - if (!keys) - keys = new Expressions(); - keys->push(e); - e = parseAssignExp(); - } - else if (keys) - { error("`key:value` expected for associative array literal"); - delete keys; - keys = NULL; - } - values->push(e); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - check(loc, TOKrbracket); - - if (keys) - e = new AssocArrayLiteralExp(loc, keys, values); - else - e = new ArrayLiteralExp(loc, NULL, values); - break; - } - - case TOKlcurly: - case TOKfunction: - case TOKdelegate: - case_delegate: - { - Dsymbol *s = parseFunctionLiteral(); - e = new FuncExp(loc, s); - break; - } - - default: - error("expression expected, not `%s`", token.toChars()); - Lerr: - // Anything for e, as long as it's not NULL - e = new IntegerExp(loc, 0, Type::tint32); - nextToken(); - break; - } - return e; -} - -Expression *Parser::parsePostExp(Expression *e) -{ - Loc loc; - - while (1) - { - loc = token.loc; - switch (token.value) - { - case TOKdot: - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin) - { - Objects *tiargs = parseTemplateArguments(); - e = new DotTemplateInstanceExp(loc, e, id, tiargs); - } - else - e = new DotIdExp(loc, e, id); - continue; - } - else if (token.value == TOKnew) - { - e = parseNewExp(e); - continue; - } - else - error("identifier expected following `.`, not `%s`", token.toChars()); - break; - - case TOKplusplus: - e = new PostExp(TOKplusplus, loc, e); - break; - - case TOKminusminus: - e = new PostExp(TOKminusminus, loc, e); - break; - - case TOKlparen: - e = new CallExp(loc, e, parseArguments()); - continue; - - case TOKlbracket: - { // array dereferences: - // array[index] - // array[] - // array[lwr .. upr] - Expression *index; - Expression *upr; - Expressions *arguments = new Expressions(); - - inBrackets++; - nextToken(); - while (token.value != TOKrbracket && token.value != TOKeof) - { - index = parseAssignExp(); - if (token.value == TOKslice) - { - // array[..., lwr..upr, ...] - nextToken(); - upr = parseAssignExp(); - arguments->push(new IntervalExp(loc, index, upr)); - } - else - arguments->push(index); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - check(TOKrbracket); - inBrackets--; - e = new ArrayExp(loc, e, arguments); - continue; - } - - default: - return e; - } - nextToken(); - } -} - -Expression *Parser::parseUnaryExp() -{ - Expression *e; - Loc loc = token.loc; - - switch (token.value) - { - case TOKand: - nextToken(); - e = parseUnaryExp(); - e = new AddrExp(loc, e); - break; - - case TOKplusplus: - nextToken(); - e = parseUnaryExp(); - //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - e = new PreExp(TOKpreplusplus, loc, e); - break; - - case TOKminusminus: - nextToken(); - e = parseUnaryExp(); - //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - e = new PreExp(TOKpreminusminus, loc, e); - break; - - case TOKmul: - nextToken(); - e = parseUnaryExp(); - e = new PtrExp(loc, e); - break; - - case TOKmin: - nextToken(); - e = parseUnaryExp(); - e = new NegExp(loc, e); - break; - - case TOKadd: - nextToken(); - e = parseUnaryExp(); - e = new UAddExp(loc, e); - break; - - case TOKnot: - nextToken(); - e = parseUnaryExp(); - e = new NotExp(loc, e); - break; - - case TOKtilde: - nextToken(); - e = parseUnaryExp(); - e = new ComExp(loc, e); - break; - - case TOKdelete: - nextToken(); - e = parseUnaryExp(); - e = new DeleteExp(loc, e, false); - break; - - case TOKcast: // cast(type) expression - { - nextToken(); - check(TOKlparen); - /* Look for cast(), cast(const), cast(immutable), - * cast(shared), cast(shared const), cast(wild), cast(shared wild) - */ - unsigned char m = 0; - while (1) - { - switch (token.value) - { - case TOKconst: - if (peekNext() == TOKlparen) - break; // const as type constructor - m |= MODconst; // const as storage class - nextToken(); - continue; - - case TOKimmutable: - if (peekNext() == TOKlparen) - break; - m |= MODimmutable; - nextToken(); - continue; - - case TOKshared: - if (peekNext() == TOKlparen) - break; - m |= MODshared; - nextToken(); - continue; - - case TOKwild: - if (peekNext() == TOKlparen) - break; - m |= MODwild; - nextToken(); - continue; - - default: - break; - } - break; - } - if (token.value == TOKrparen) - { - nextToken(); - e = parseUnaryExp(); - e = new CastExp(loc, e, m); - } - else - { - Type *t = parseType(); // cast( type ) - t = t->addMod(m); // cast( const type ) - check(TOKrparen); - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - } - break; - } - - case TOKwild: - case TOKshared: - case TOKconst: - case TOKimmutable: // immutable(type)(arguments) / immutable(type).init - { - StorageClass stc = parseTypeCtor(); - Type *t = parseBasicType(); - t = t->addSTC(stc); - e = new TypeExp(loc, t); - if (stc == 0 && token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { - error("identifier expected following (type)."); - return NULL; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - e = parsePostExp(e); - break; - } - else if (token.value != TOKlparen) - { - error("(arguments) expected following %s", t->toChars()); - return e; - } - e = new CallExp(loc, e, parseArguments()); - break; - } - - - case TOKlparen: - { Token *tk; - - tk = peek(&token); -#if CCASTSYNTAX - // If cast - if (isDeclaration(tk, 0, TOKrparen, &tk)) - { - tk = peek(tk); // skip over right parenthesis - switch (tk->value) - { - case TOKnot: - tk = peek(tk); - if (tk->value == TOKis || tk->value == TOKin) // !is or !in - break; - /* fall through */ - - case TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKdelete: - case TOKnew: - case TOKlparen: - case TOKidentifier: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKint128v: - case TOKuns128v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKfunction: - case TOKdelegate: - case TOKtypeof: - case TOKtraits: - case TOKvector: - case TOKfile: - case TOKfilefullpath: - case TOKline: - case TOKmodulestring: - case TOKfuncstring: - case TOKprettyfunc: - case TOKwchar: case TOKdchar: - case TOKbool: case TOKchar: - case TOKint8: case TOKuns8: - case TOKint16: case TOKuns16: - case TOKint32: case TOKuns32: - case TOKint64: case TOKuns64: - case TOKint128: case TOKuns128: - case TOKfloat32: case TOKfloat64: case TOKfloat80: - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: - case TOKvoid: - { // (type) una_exp - Type *t; - - nextToken(); - t = parseType(); - check(TOKrparen); - - // if .identifier - // or .identifier!( ... ) - if (token.value == TOKdot) - { - if (peekNext() != TOKidentifier && peekNext() != TOKnew) - { - error("identifier or new keyword expected following (...)."); - return NULL; - } - e = new TypeExp(loc, t); - e->parens = 1; - e = parsePostExp(e); - } - else - { - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - error("C style cast illegal, use %s", e->toChars()); - } - return e; - } - default: - break; - } - } -#endif - e = parsePrimaryExp(); - e = parsePostExp(e); - break; - } - default: - e = parsePrimaryExp(); - e = parsePostExp(e); - break; - } - assert(e); - - // ^^ is right associative and has higher precedence than the unary operators - while (token.value == TOKpow) - { - nextToken(); - Expression *e2 = parseUnaryExp(); - e = new PowExp(loc, e, e2); - } - - return e; -} - -Expression *Parser::parseMulExp() -{ - Expression *e; - Expression *e2; - Loc loc = token.loc; - - e = parseUnaryExp(); - while (1) - { - switch (token.value) - { - case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; - case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; - case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseAddExp() -{ - Expression *e; - Expression *e2; - Loc loc = token.loc; - - e = parseMulExp(); - while (1) - { - switch (token.value) - { - case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; - case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; - case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseShiftExp() -{ - Expression *e; - Expression *e2; - Loc loc = token.loc; - - e = parseAddExp(); - while (1) - { - switch (token.value) - { - case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; - case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; - case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseCmpExp() -{ - Expression *e; - Expression *e2; - Token *t; - Loc loc = token.loc; - - e = parseShiftExp(); - TOK op = token.value; - - switch (op) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseShiftExp(); - e = new EqualExp(op, loc, e, e2); - break; - - case TOKis: - op = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value == TOKin) - { - nextToken(); - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - e = new NotExp(loc, e); - break; - } - if (t->value != TOKis) - break; - nextToken(); - op = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseShiftExp(); - e = new IdentityExp(op, loc, e, e2); - break; - - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - break; - - default: - break; - } - return e; -} - -Expression *Parser::parseAndExp() -{ - Loc loc = token.loc; - - Expression *e = parseCmpExp(); - while (token.value == TOKand) - { - checkParens(TOKand, e); - nextToken(); - Expression *e2 = parseCmpExp(); - checkParens(TOKand, e2); - e = new AndExp(loc,e,e2); - loc = token.loc; - } - return e; -} - -Expression *Parser::parseXorExp() -{ - Loc loc = token.loc; - - Expression *e = parseAndExp(); - while (token.value == TOKxor) - { - checkParens(TOKxor, e); - nextToken(); - Expression *e2 = parseAndExp(); - checkParens(TOKxor, e2); - e = new XorExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrExp() -{ - Loc loc = token.loc; - - Expression *e = parseXorExp(); - while (token.value == TOKor) - { - checkParens(TOKor, e); - nextToken(); - Expression *e2 = parseXorExp(); - checkParens(TOKor, e2); - e = new OrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseAndAndExp() -{ - Expression *e; - Expression *e2; - Loc loc = token.loc; - - e = parseOrExp(); - while (token.value == TOKandand) - { - nextToken(); - e2 = parseOrExp(); - e = new LogicalExp(loc, TOKandand, e, e2); - } - return e; -} - -Expression *Parser::parseOrOrExp() -{ - Expression *e; - Expression *e2; - Loc loc = token.loc; - - e = parseAndAndExp(); - while (token.value == TOKoror) - { - nextToken(); - e2 = parseAndAndExp(); - e = new LogicalExp(loc, TOKoror, e, e2); - } - return e; -} - -Expression *Parser::parseCondExp() -{ - Expression *e; - Expression *e1; - Expression *e2; - Loc loc = token.loc; - - e = parseOrOrExp(); - if (token.value == TOKquestion) - { - nextToken(); - e1 = parseExpression(); - check(TOKcolon); - e2 = parseCondExp(); - e = new CondExp(loc, e, e1, e2); - } - return e; -} - -Expression *Parser::parseAssignExp() -{ - Expression *e; - Expression *e2; - Loc loc; - - e = parseCondExp(); - while (1) - { - loc = token.loc; - switch (token.value) - { - case TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue; - case TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue; - case TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue; - case TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue; - case TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue; - case TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue; - case TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue; - case TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue; - case TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue; - case TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue; - case TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue; - case TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue; - case TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue; - case TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue; - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseExpression() -{ - Expression *e; - Expression *e2; - Loc loc = token.loc; - - //printf("Parser::parseExpression() loc = %d\n", loc.linnum); - e = parseAssignExp(); - while (token.value == TOKcomma) - { - nextToken(); - e2 = parseAssignExp(); - e = new CommaExp(loc, e, e2, false); - loc = token.loc; - } - return e; -} - - -/************************* - * Collect argument list. - * Assume current token is ',', '(' or '['. - */ - -Expressions *Parser::parseArguments() -{ // function call - Expressions *arguments; - Expression *arg; - TOK endtok; - - arguments = new Expressions(); - if (token.value == TOKlbracket) - endtok = TOKrbracket; - else - endtok = TOKrparen; - - { - nextToken(); - while (token.value != endtok && token.value != TOKeof) - { - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == endtok) - break; - check(TOKcomma); - } - check(endtok); - } - return arguments; -} - -/******************************************* - */ - -Expression *Parser::parseNewExp(Expression *thisexp) -{ - Type *t; - Expressions *newargs; - Expressions *arguments = NULL; - Loc loc = token.loc; - - nextToken(); - newargs = NULL; - if (token.value == TOKlparen) - { - newargs = parseArguments(); - } - - // An anonymous nested class starts with "class" - if (token.value == TOKclass) - { - nextToken(); - if (token.value == TOKlparen) - arguments = parseArguments(); - - BaseClasses *baseclasses = NULL; - if (token.value != TOKlcurly) - baseclasses = parseBaseClasses(); - - Identifier *id = NULL; - Dsymbols *members = NULL; - - if (token.value != TOKlcurly) - { - error("{ members } expected for anonymous class"); - } - else - { - nextToken(); - members = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("class member expected"); - nextToken(); - } - - ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, members, false); - Expression *e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); - - return e; - } - - StorageClass stc = parseTypeCtor(); - t = parseBasicType(true); - t = parseBasicType2(t); - t = t->addSTC(stc); - if (t->ty == Taarray) - { - TypeAArray *taa = (TypeAArray *)t; - Type *index = taa->index; - - Expression *edim = typeToExpression(index); - if (!edim) - { - error("need size of rightmost array, not type %s", index->toChars()); - return new NullExp(loc); - } - t = new TypeSArray(taa->next, edim); - } - else if (t->ty == Tsarray) - { - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } - Expression *e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, const utf8_t *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); - token.lineComment = NULL; -} - - -/********************************** - * Set operator precedence for each operator. - */ - -PREC precedence[TOKMAX]; - -struct PrecedenceInitializer -{ - PrecedenceInitializer(); -}; - -static PrecedenceInitializer precedenceinitializer; - -PrecedenceInitializer::PrecedenceInitializer() -{ - for (size_t i = 0; i < TOKMAX; i++) - precedence[i] = PREC_zero; - - precedence[TOKtype] = PREC_expr; - precedence[TOKerror] = PREC_expr; - - precedence[TOKtypeof] = PREC_primary; - precedence[TOKmixin] = PREC_primary; - precedence[TOKimport] = PREC_primary; - - precedence[TOKdotvar] = PREC_primary; - precedence[TOKscope] = PREC_primary; - precedence[TOKidentifier] = PREC_primary; - precedence[TOKthis] = PREC_primary; - precedence[TOKsuper] = PREC_primary; - precedence[TOKint64] = PREC_primary; - precedence[TOKfloat64] = PREC_primary; - precedence[TOKcomplex80] = PREC_primary; - precedence[TOKnull] = PREC_primary; - precedence[TOKstring] = PREC_primary; - precedence[TOKarrayliteral] = PREC_primary; - precedence[TOKassocarrayliteral] = PREC_primary; - precedence[TOKclassreference] = PREC_primary; - precedence[TOKfile] = PREC_primary; - precedence[TOKfilefullpath] = PREC_primary; - precedence[TOKline] = PREC_primary; - precedence[TOKmodulestring] = PREC_primary; - precedence[TOKfuncstring] = PREC_primary; - precedence[TOKprettyfunc] = PREC_primary; - precedence[TOKtypeid] = PREC_primary; - precedence[TOKis] = PREC_primary; - precedence[TOKassert] = PREC_primary; - precedence[TOKhalt] = PREC_primary; - precedence[TOKtemplate] = PREC_primary; - precedence[TOKdsymbol] = PREC_primary; - precedence[TOKfunction] = PREC_primary; - precedence[TOKvar] = PREC_primary; - precedence[TOKsymoff] = PREC_primary; - precedence[TOKstructliteral] = PREC_primary; - precedence[TOKarraylength] = PREC_primary; - precedence[TOKdelegateptr] = PREC_primary; - precedence[TOKdelegatefuncptr] = PREC_primary; - precedence[TOKremove] = PREC_primary; - precedence[TOKtuple] = PREC_primary; - precedence[TOKtraits] = PREC_primary; - precedence[TOKdefault] = PREC_primary; - precedence[TOKoverloadset] = PREC_primary; - precedence[TOKvoid] = PREC_primary; - precedence[TOKvectorarray] = PREC_primary; - - // post - precedence[TOKdotti] = PREC_primary; - precedence[TOKdotid] = PREC_primary; - precedence[TOKdottd] = PREC_primary; - precedence[TOKdot] = PREC_primary; - precedence[TOKdottype] = PREC_primary; -// precedence[TOKarrow] = PREC_primary; - precedence[TOKplusplus] = PREC_primary; - precedence[TOKminusminus] = PREC_primary; - precedence[TOKpreplusplus] = PREC_primary; - precedence[TOKpreminusminus] = PREC_primary; - precedence[TOKcall] = PREC_primary; - precedence[TOKslice] = PREC_primary; - precedence[TOKarray] = PREC_primary; - precedence[TOKindex] = PREC_primary; - - precedence[TOKdelegate] = PREC_unary; - precedence[TOKaddress] = PREC_unary; - precedence[TOKstar] = PREC_unary; - precedence[TOKneg] = PREC_unary; - precedence[TOKuadd] = PREC_unary; - precedence[TOKnot] = PREC_unary; - precedence[TOKtilde] = PREC_unary; - precedence[TOKdelete] = PREC_unary; - precedence[TOKnew] = PREC_unary; - precedence[TOKnewanonclass] = PREC_unary; - precedence[TOKcast] = PREC_unary; - - precedence[TOKvector] = PREC_unary; - precedence[TOKpow] = PREC_pow; - - precedence[TOKmul] = PREC_mul; - precedence[TOKdiv] = PREC_mul; - precedence[TOKmod] = PREC_mul; - - precedence[TOKadd] = PREC_add; - precedence[TOKmin] = PREC_add; - precedence[TOKcat] = PREC_add; - - precedence[TOKshl] = PREC_shift; - precedence[TOKshr] = PREC_shift; - precedence[TOKushr] = PREC_shift; - - precedence[TOKlt] = PREC_rel; - precedence[TOKle] = PREC_rel; - precedence[TOKgt] = PREC_rel; - precedence[TOKge] = PREC_rel; - precedence[TOKunord] = PREC_rel; - precedence[TOKlg] = PREC_rel; - precedence[TOKleg] = PREC_rel; - precedence[TOKule] = PREC_rel; - precedence[TOKul] = PREC_rel; - precedence[TOKuge] = PREC_rel; - precedence[TOKug] = PREC_rel; - precedence[TOKue] = PREC_rel; - precedence[TOKin] = PREC_rel; - - /* Note that we changed precedence, so that < and != have the same - * precedence. This change is in the parser, too. - */ - precedence[TOKequal] = PREC_rel; - precedence[TOKnotequal] = PREC_rel; - precedence[TOKidentity] = PREC_rel; - precedence[TOKnotidentity] = PREC_rel; - - precedence[TOKand] = PREC_and; - - precedence[TOKxor] = PREC_xor; - - precedence[TOKor] = PREC_or; - - precedence[TOKandand] = PREC_andand; - - precedence[TOKoror] = PREC_oror; - - precedence[TOKquestion] = PREC_cond; - - precedence[TOKassign] = PREC_assign; - precedence[TOKconstruct] = PREC_assign; - precedence[TOKblit] = PREC_assign; - precedence[TOKaddass] = PREC_assign; - precedence[TOKminass] = PREC_assign; - precedence[TOKcatass] = PREC_assign; - precedence[TOKmulass] = PREC_assign; - precedence[TOKdivass] = PREC_assign; - precedence[TOKmodass] = PREC_assign; - precedence[TOKpowass] = PREC_assign; - precedence[TOKshlass] = PREC_assign; - precedence[TOKshrass] = PREC_assign; - precedence[TOKushrass] = PREC_assign; - precedence[TOKandass] = PREC_assign; - precedence[TOKorass] = PREC_assign; - precedence[TOKxorass] = PREC_assign; - - precedence[TOKcomma] = PREC_expr; - precedence[TOKdeclaration] = PREC_expr; - - precedence[TOKinterval] = PREC_assign; -} |