aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/parse.c')
-rw-r--r--gcc/d/dmd/parse.c8492
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;
-}