2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
11 // This is the D parser
15 #include <string.h> // strlen(),memcpy()
17 #include "root/rmem.h"
26 #include "staticassert.h"
27 #include "expression.h"
28 #include "statement.h"
32 #include "declaration.h"
33 #include "aggregate.h"
37 #include "aliasthis.h"
41 Expression
*typeToExpression(Type
*t
);
43 // Support C cast syntax:
47 // Support postfix C array declarations, such as
51 Parser::Parser(Module
*module
, const utf8_t
*base
, size_t length
, bool doDocComment
)
52 : Lexer(module
? module
->srcfile
->toChars() : NULL
, base
, 0, length
, doDocComment
, false)
54 //printf("Parser::Parser()\n");
60 lookingForElse
= Loc();
61 //nextToken(); // start up the scanner
64 /*********************
65 * Use this constructor for string mixins.
67 * loc location in source file of mixin
69 Parser::Parser(Loc loc
, Module
*module
, const utf8_t
*base
, size_t length
, bool doDocComment
)
70 : Lexer(module
? module
->srcfile
->toChars() : NULL
, base
, 0, length
, doDocComment
, false)
72 //printf("Parser::Parser()\n");
78 /* Create a pseudo-filename for the mixin string, as it may not even exist
81 char *filename
= (char *)mem
.xmalloc(strlen(loc
.filename
) + 7 + sizeof(loc
.linnum
) * 3 + 1);
82 sprintf(filename
, "%s-mixin-%d", loc
.filename
, (int)loc
.linnum
);
83 scanloc
.filename
= filename
;
92 lookingForElse
= Loc();
93 //nextToken(); // start up the scanner
96 Dsymbols
*Parser::parseModule()
98 const utf8_t
*comment
= token
.blockComment
;
99 bool isdeprecated
= false;
100 Expression
*msg
= NULL
;
101 Expressions
*udas
= NULL
;
105 if (skipAttributes(&token
, &tk
) && tk
->value
== TOKmodule
)
107 while (token
.value
!= TOKmodule
)
113 // deprecated (...) module ...
116 error("there is only one deprecation attribute allowed for module declaration");
123 if (token
.value
== TOKlparen
)
126 msg
= parseAssignExp();
133 Expressions
*exps
= NULL
;
134 StorageClass stc
= parseAttribute(&exps
);
136 if (stc
== STCproperty
|| stc
== STCnogc
|| stc
== STCdisable
||
137 stc
== STCsafe
|| stc
== STCtrusted
|| stc
== STCsystem
)
139 error("@%s attribute for module declaration is not supported", token
.toChars());
143 udas
= UserAttributeDeclaration::concat(udas
, exps
);
151 error("'module' expected instead of %s", token
.toChars());
161 Dsymbols
*a
= new Dsymbols();
162 UserAttributeDeclaration
*udad
= new UserAttributeDeclaration(udas
, a
);
163 mod
->userAttribDecl
= udad
;
166 // ModuleDeclation leads off
167 if (token
.value
== TOKmodule
)
172 if (token
.value
!= TOKidentifier
)
174 error("identifier expected following module");
179 Identifiers
*a
= NULL
;
183 while (nextToken() == TOKdot
)
186 a
= new Identifiers();
189 if (token
.value
!= TOKidentifier
)
191 error("identifier expected following package");
197 md
= new ModuleDeclaration(loc
, a
, id
);
198 md
->isdeprecated
= isdeprecated
;
201 if (token
.value
!= TOKsemicolon
)
202 error("';' expected following module declaration instead of %s", token
.toChars());
204 addComment(mod
, comment
);
208 decldefs
= parseDeclDefs(0);
209 if (token
.value
!= TOKeof
)
211 error(token
.loc
, "unrecognized declaration");
217 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
220 return new Dsymbols();
223 struct PrefixAttributes
225 StorageClass storageClass
;
232 const utf8_t
*comment
;
235 : storageClass(STCundefined
),
238 protection(PROTundefined
),
247 Dsymbols
*Parser::parseDeclDefs(int once
, Dsymbol
**pLastDecl
, PrefixAttributes
*pAttrs
)
249 Dsymbol
*lastDecl
= NULL
; // used to link unittest to its previous declaration
251 pLastDecl
= &lastDecl
;
253 LINK linksave
= linkage
; // save global state
255 //printf("Parser::parseDeclDefs()\n");
256 Dsymbols
*decldefs
= new Dsymbols();
263 PrefixAttributes attrs
;
264 if (!once
|| !pAttrs
)
267 pAttrs
->comment
= token
.blockComment
;
271 Condition
*condition
;
279 /* Determine if this is a manifest constant declaration,
280 * or a conventional enum.
282 Token
*t
= peek(&token
);
283 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
285 else if (t
->value
!= TOKidentifier
)
290 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
291 t
->value
== TOKsemicolon
)
305 s
= (Dsymbol
*)parseTemplateDeclaration();
317 check(TOKlparen
, "mixin");
318 Expression
*e
= parseAssignExp();
321 s
= new CompileDeclaration(loc
, e
);
327 s
= (Dsymbol
*)parseTemplateDeclaration(true);
337 case TOKwchar
: case TOKdchar
:
338 case TOKbool
: case TOKchar
:
339 case TOKint8
: case TOKuns8
:
340 case TOKint16
: case TOKuns16
:
341 case TOKint32
: case TOKuns32
:
342 case TOKint64
: case TOKuns64
:
343 case TOKint128
: case TOKuns128
:
344 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
345 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
346 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
359 a
= parseDeclarations(false, pAttrs
, pAttrs
->comment
);
361 *pLastDecl
= (*a
)[a
->dim
-1];
365 if (peekNext() == TOKdot
)
368 s
= parseCtor(pAttrs
);
372 s
= parseDtor(pAttrs
);
377 Token
*t
= peek(&token
);
378 if ((t
->value
== TOKlparen
&& peek(t
)->value
== TOKrparen
) ||
379 t
->value
== TOKlcurly
)
383 s
= parseInvariant(pAttrs
);
387 error("invariant body expected, not '%s'", token
.toChars());
394 if (global
.params
.useUnitTests
|| global
.params
.doDocComments
|| global
.params
.doHdrGeneration
)
396 s
= parseUnitTest(pAttrs
);
398 (*pLastDecl
)->ddocUnittest
= (UnitTestDeclaration
*)s
;
402 // Skip over unittest block by counting { }
422 error(loc
, "closing } of unittest not found before end of file");
430 // Workaround 14894. Add an empty unittest declaration to keep
431 // the number of symbols in this scope independent of -unittest.
432 s
= new UnitTestDeclaration(loc
, token
.loc
, STCundefined
, NULL
);
437 s
= parseNew(pAttrs
);
441 s
= parseDelete(pAttrs
);
446 error("declaration expected, not '%s'",token
.toChars());
452 error("declaration expected, not '%s'", token
.toChars());
457 TOK next
= peekNext();
459 s
= parseStaticCtor(pAttrs
);
460 else if (next
== TOKtilde
)
461 s
= parseStaticDtor(pAttrs
);
462 else if (next
== TOKassert
)
463 s
= parseStaticAssert();
464 else if (next
== TOKif
)
466 condition
= parseStaticIfCondition();
468 if (token
.value
== TOKcolon
)
469 athen
= parseBlock(pLastDecl
);
472 Loc lookingForElseSave
= lookingForElse
;
473 lookingForElse
= token
.loc
;
474 athen
= parseBlock(pLastDecl
);
475 lookingForElse
= lookingForElseSave
;
477 Dsymbols
*aelse
= NULL
;
478 if (token
.value
== TOKelse
)
480 Loc elseloc
= token
.loc
;
482 aelse
= parseBlock(pLastDecl
);
483 checkDanglingElse(elseloc
);
485 s
= new StaticIfDeclaration(condition
, athen
, aelse
);
487 else if (next
== TOKimport
)
501 if (peekNext() == TOKlparen
)
507 if (peekNext() == TOKlparen
)
514 TOK next
= peekNext();
515 if (next
== TOKlparen
)
517 if (next
== TOKstatic
)
519 TOK next2
= peekNext2();
520 if (next2
== TOKthis
)
522 s
= parseSharedStaticCtor(pAttrs
);
525 if (next2
== TOKtilde
)
527 s
= parseSharedStaticDtor(pAttrs
);
536 if (peekNext() == TOKlparen
)
541 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
542 case TOKauto
: stc
= STCauto
; goto Lstc
;
543 case TOKscope
: stc
= STCscope
; goto Lstc
;
544 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
545 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
546 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
547 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
548 case TOKpure
: stc
= STCpure
; goto Lstc
;
549 case TOKref
: stc
= STCref
; goto Lstc
;
550 case TOKgshared
: stc
= STCgshared
; goto Lstc
;
551 //case TOKmanifest: stc = STCmanifest; goto Lstc;
554 Expressions
*exps
= NULL
;
555 stc
= parseAttribute(&exps
);
557 goto Lstc
; // it's a predefined attribute
558 // no redundant/conflicting check for UDAs
559 pAttrs
->udas
= UserAttributeDeclaration::concat(pAttrs
->udas
, exps
);
563 pAttrs
->storageClass
= appendStorageClass(pAttrs
->storageClass
, stc
);
569 /* Look for auto initializers:
570 * storage_class identifier = initializer;
571 * storage_class identifier(...) = initializer;
573 if (token
.value
== TOKidentifier
&&
574 skipParensIf(peek(&token
), &tk
) &&
575 tk
->value
== TOKassign
)
577 a
= parseAutoDeclarations(pAttrs
->storageClass
, pAttrs
->comment
);
578 pAttrs
->storageClass
= STCundefined
;
580 *pLastDecl
= (*a
)[a
->dim
-1];
583 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
589 /* Look for return type inference for template functions.
591 if (token
.value
== TOKidentifier
&& skipParens(peek(&token
), &tk
) && skipAttributes(tk
, &tk
) &&
592 (tk
->value
== TOKlparen
|| tk
->value
== TOKlcurly
|| tk
->value
== TOKin
||
593 tk
->value
== TOKout
|| tk
->value
== TOKdo
||
594 (tk
->value
== TOKidentifier
&& tk
->ident
== Id::_body
))
597 a
= parseDeclarations(true, pAttrs
, pAttrs
->comment
);
599 *pLastDecl
= (*a
)[a
->dim
-1];
602 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
608 a
= parseBlock(pLastDecl
, pAttrs
);
609 if (pAttrs
->storageClass
!= STCundefined
)
611 s
= new StorageClassDeclaration(pAttrs
->storageClass
, a
);
612 pAttrs
->storageClass
= STCundefined
;
621 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
628 if (peek(&token
)->value
!= TOKlparen
)
635 Expression
*e
= parseAssignExp();
639 error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'",
640 pAttrs
->depmsg
->toChars(), e
->toChars());
643 a
= parseBlock(pLastDecl
, pAttrs
);
646 s
= new DeprecatedDeclaration(pAttrs
->depmsg
, a
);
647 pAttrs
->depmsg
= NULL
;
654 if (peekNext() == TOKrbracket
)
655 error("empty attribute list is not allowed");
656 error("use @(attributes) instead of [attributes]");
657 Expressions
*exps
= parseArguments();
658 // no redundant/conflicting check for UDAs
660 pAttrs
->udas
= UserAttributeDeclaration::concat(pAttrs
->udas
, exps
);
661 a
= parseBlock(pLastDecl
, pAttrs
);
664 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
672 if (peek(&token
)->value
!= TOKlparen
)
678 Loc linkLoc
= token
.loc
;
679 Identifiers
*idents
= NULL
;
680 CPPMANGLE cppmangle
= CPPMANGLEdefault
;
681 LINK link
= parseLinkage(&idents
, &cppmangle
);
682 if (pAttrs
->link
!= LINKdefault
)
684 if (pAttrs
->link
!= link
)
686 error("conflicting linkage extern (%s) and extern (%s)",
687 linkageToChars(pAttrs
->link
), linkageToChars(link
));
692 // extern(C++, foo) extern(C++, bar) void foo();
693 // to be equivalent with:
694 // extern(C++, foo.bar) void foo();
697 error("redundant linkage extern (%s)", linkageToChars(pAttrs
->link
));
700 this->linkage
= link
;
701 a
= parseBlock(pLastDecl
, pAttrs
);
704 assert(link
== LINKcpp
);
706 for (size_t i
= idents
->dim
; i
;)
708 Identifier
*id
= (*idents
)[--i
];
714 s
= new Nspace(linkLoc
, id
, a
);
717 pAttrs
->link
= LINKdefault
;
719 else if (pAttrs
->link
!= LINKdefault
)
721 s
= new LinkDeclaration(pAttrs
->link
, a
);
722 pAttrs
->link
= LINKdefault
;
724 else if (cppmangle
!= CPPMANGLEdefault
)
726 assert(link
== LINKcpp
);
727 s
= new CPPMangleDeclaration(cppmangle
, a
);
732 case TOKprivate
: prot
= PROTprivate
; goto Lprot
;
733 case TOKpackage
: prot
= PROTpackage
; goto Lprot
;
734 case TOKprotected
: prot
= PROTprotected
; goto Lprot
;
735 case TOKpublic
: prot
= PROTpublic
; goto Lprot
;
736 case TOKexport
: prot
= PROTexport
; goto Lprot
;
739 if (pAttrs
->protection
.kind
!= PROTundefined
)
741 if (pAttrs
->protection
.kind
!= prot
)
742 error("conflicting protection attribute '%s' and '%s'",
743 protectionToChars(pAttrs
->protection
.kind
), protectionToChars(prot
));
745 error("redundant protection attribute '%s'", protectionToChars(prot
));
747 pAttrs
->protection
.kind
= prot
;
751 // optional qualified package identifier to bind
753 Identifiers
*pkg_prot_idents
= NULL
;
754 if (pAttrs
->protection
.kind
== PROTpackage
&& token
.value
== TOKlparen
)
756 pkg_prot_idents
= parseQualifiedIdentifier("protection package");
762 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
769 Loc attrloc
= token
.loc
;
770 a
= parseBlock(pLastDecl
, pAttrs
);
771 if (pAttrs
->protection
.kind
!= PROTundefined
)
773 if (pAttrs
->protection
.kind
== PROTpackage
&& pkg_prot_idents
)
774 s
= new ProtDeclaration(attrloc
, pkg_prot_idents
, a
);
776 s
= new ProtDeclaration(attrloc
, pAttrs
->protection
, a
);
778 pAttrs
->protection
= Prot(PROTundefined
);
785 const Loc attrLoc
= token
.loc
;
789 Expression
*e
= NULL
; // default
790 if (token
.value
== TOKlparen
)
793 e
= parseAssignExp();
797 if (pAttrs
->setAlignment
)
803 buf1
.printf("(%s)", e
->toChars());
804 s1
= buf1
.peekString();
806 error("redundant alignment attribute align%s", s1
);
809 pAttrs
->setAlignment
= true;
811 a
= parseBlock(pLastDecl
, pAttrs
);
812 if (pAttrs
->setAlignment
)
814 s
= new AlignDeclaration(attrLoc
, pAttrs
->ealign
, a
);
815 pAttrs
->setAlignment
= false;
816 pAttrs
->ealign
= NULL
;
823 Expressions
*args
= NULL
;
828 if (token
.value
!= TOKidentifier
)
830 error("pragma(identifier) expected");
833 Identifier
*ident
= token
.ident
;
835 if (token
.value
== TOKcomma
&& peekNext() != TOKrparen
)
836 args
= parseArguments(); // pragma(identifier, args...)
838 check(TOKrparen
); // pragma(identifier)
841 if (token
.value
== TOKsemicolon
)
843 /* Bugzilla 2354: Accept single semicolon as an empty
844 * DeclarationBlock following attribute.
846 * Attribute DeclarationBlock
853 a2
= parseBlock(pLastDecl
);
854 s
= new PragmaDeclaration(loc
, ident
, args
, a2
);
860 if (token
.value
== TOKassign
)
863 if (token
.value
== TOKidentifier
)
864 s
= new DebugSymbol(token
.loc
, token
.ident
);
865 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
866 s
= new DebugSymbol(token
.loc
, (unsigned)token
.uns64value
);
869 error("identifier or integer expected, not %s", token
.toChars());
873 if (token
.value
!= TOKsemicolon
)
874 error("semicolon expected");
879 condition
= parseDebugCondition();
884 if (token
.value
== TOKassign
)
887 if (token
.value
== TOKidentifier
)
888 s
= new VersionSymbol(token
.loc
, token
.ident
);
889 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
890 s
= new VersionSymbol(token
.loc
, (unsigned)token
.uns64value
);
893 error("identifier or integer expected, not %s", token
.toChars());
897 if (token
.value
!= TOKsemicolon
)
898 error("semicolon expected");
902 condition
= parseVersionCondition();
908 if (token
.value
== TOKcolon
)
909 athen
= parseBlock(pLastDecl
);
912 Loc lookingForElseSave
= lookingForElse
;
913 lookingForElse
= token
.loc
;
914 athen
= parseBlock(pLastDecl
);
915 lookingForElse
= lookingForElseSave
;
917 Dsymbols
*aelse
= NULL
;
918 if (token
.value
== TOKelse
)
920 Loc elseloc
= token
.loc
;
922 aelse
= parseBlock(pLastDecl
);
923 checkDanglingElse(elseloc
);
925 s
= new ConditionalDeclaration(condition
, athen
, aelse
);
929 case TOKsemicolon
: // empty declaration
930 //error("empty declaration");
935 error("declaration expected, not '%s'",token
.toChars());
937 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
946 if (!s
->isAttribDeclaration())
949 addComment(s
, pAttrs
->comment
);
951 else if (a
&& a
->dim
)
962 /*********************************************
963 * Give error on redundant/conflicting storage class.
965 * TODO: remove deprecation in 2.068 and keep only error
968 StorageClass
Parser::appendStorageClass(StorageClass storageClass
, StorageClass stc
,
971 if ((storageClass
& stc
) ||
972 (storageClass
& STCin
&& stc
& (STCconst
| STCscope
)) ||
973 (stc
& STCin
&& storageClass
& (STCconst
| STCscope
)))
976 stcToBuffer(&buf
, stc
);
978 deprecation("redundant attribute '%s'", buf
.peekString());
980 error("redundant attribute '%s'", buf
.peekString());
981 return storageClass
| stc
;
986 if (stc
& (STCconst
| STCimmutable
| STCmanifest
))
988 StorageClass u
= storageClass
& (STCconst
| STCimmutable
| STCmanifest
);
990 error("conflicting attribute '%s'", Token::toChars(token
.value
));
992 if (stc
& (STCgshared
| STCshared
| STCtls
))
994 StorageClass u
= storageClass
& (STCgshared
| STCshared
| STCtls
);
996 error("conflicting attribute '%s'", Token::toChars(token
.value
));
998 if (stc
& (STCsafe
| STCsystem
| STCtrusted
))
1000 StorageClass u
= storageClass
& (STCsafe
| STCsystem
| STCtrusted
);
1002 error("conflicting attribute '@%s'", token
.toChars());
1005 return storageClass
;
1008 /***********************************************
1009 * Parse attribute, lexer is on '@'.
1011 * pudas array of UDAs to append to
1013 * storage class if a predefined attribute; also scanner remains on identifier.
1014 * 0 if not a predefined attribute
1015 * *pudas set if user defined attribute, scanner is past UDA
1016 * *pudas NULL if not a user defined attribute
1019 StorageClass
Parser::parseAttribute(Expressions
**pudas
)
1022 Expressions
*udas
= NULL
;
1023 StorageClass stc
= 0;
1024 if (token
.value
== TOKidentifier
)
1026 if (token
.ident
== Id::property
)
1028 else if (token
.ident
== Id::nogc
)
1030 else if (token
.ident
== Id::safe
)
1032 else if (token
.ident
== Id::trusted
)
1034 else if (token
.ident
== Id::system
)
1036 else if (token
.ident
== Id::disable
)
1038 else if (token
.ident
== Id::future
)
1042 // Allow identifier, template instantiation, or function call
1043 Expression
*exp
= parsePrimaryExp();
1044 if (token
.value
== TOKlparen
)
1046 Loc loc
= token
.loc
;
1047 exp
= new CallExp(loc
, exp
, parseArguments());
1050 udas
= new Expressions();
1054 else if (token
.value
== TOKlparen
)
1056 // @( ArgumentList )
1057 // Concatenate with existing
1058 if (peekNext() == TOKrparen
)
1059 error("empty attribute list is not allowed");
1060 udas
= parseArguments();
1064 error("@identifier or @(ArgumentList) expected, not @%s", token
.toChars());
1072 *pudas
= UserAttributeDeclaration::concat(*pudas
, udas
);
1075 error("valid attributes are @property, @safe, @trusted, @system, @disable");
1079 /***********************************************
1080 * Parse const/immutable/shared/inout/nothrow/pure postfix
1083 StorageClass
Parser::parsePostfix(StorageClass storageClass
, Expressions
**pudas
)
1088 switch (token
.value
)
1090 case TOKconst
: stc
= STCconst
; break;
1091 case TOKimmutable
: stc
= STCimmutable
; break;
1092 case TOKshared
: stc
= STCshared
; break;
1093 case TOKwild
: stc
= STCwild
; break;
1094 case TOKnothrow
: stc
= STCnothrow
; break;
1095 case TOKpure
: stc
= STCpure
; break;
1096 case TOKreturn
: stc
= STCreturn
; break;
1097 case TOKscope
: stc
= STCscope
; break;
1100 Expressions
*udas
= NULL
;
1101 stc
= parseAttribute(&udas
);
1105 *pudas
= UserAttributeDeclaration::concat(*pudas
, udas
);
1109 // void function() @uda fp;
1110 // () @uda { return 1; }
1111 error("user defined attributes cannot appear as postfixes");
1119 return storageClass
;
1121 storageClass
= appendStorageClass(storageClass
, stc
, true);
1126 StorageClass
Parser::parseTypeCtor()
1128 StorageClass storageClass
= STCundefined
;
1132 if (peek(&token
)->value
== TOKlparen
)
1133 return storageClass
;
1136 switch (token
.value
)
1138 case TOKconst
: stc
= STCconst
; break;
1139 case TOKimmutable
: stc
= STCimmutable
; break;
1140 case TOKshared
: stc
= STCshared
; break;
1141 case TOKwild
: stc
= STCwild
; break;
1144 return storageClass
;
1146 storageClass
= appendStorageClass(storageClass
, stc
);
1151 /********************************************
1152 * Parse declarations after an align, protection, or extern decl.
1155 Dsymbols
*Parser::parseBlock(Dsymbol
**pLastDecl
, PrefixAttributes
*pAttrs
)
1159 //printf("parseBlock()\n");
1160 switch (token
.value
)
1163 error("declaration expected following attribute, not ';'");
1168 error("declaration expected following attribute, not EOF");
1173 Loc lookingForElseSave
= lookingForElse
;
1174 lookingForElse
= Loc();
1177 a
= parseDeclDefs(0, pLastDecl
);
1178 if (token
.value
!= TOKrcurly
)
1181 error("matching '}' expected, not %s", token
.toChars());
1185 lookingForElse
= lookingForElseSave
;
1191 a
= parseDeclDefs(0, pLastDecl
); // grab declarations up to closing curly bracket
1195 a
= parseDeclDefs(1, pLastDecl
, pAttrs
);
1201 /**********************************
1202 * Parse a static assertion.
1203 * Current token is 'static'.
1206 StaticAssert
*Parser::parseStaticAssert()
1208 Loc loc
= token
.loc
;
1210 Expression
*msg
= NULL
;
1212 //printf("parseStaticAssert()\n");
1216 exp
= parseAssignExp();
1217 if (token
.value
== TOKcomma
)
1220 if (token
.value
!= TOKrparen
)
1222 msg
= parseAssignExp();
1223 if (token
.value
== TOKcomma
)
1228 check(TOKsemicolon
);
1229 return new StaticAssert(loc
, exp
, msg
);
1232 /***********************************
1233 * Parse typeof(expression).
1234 * Current token is on the 'typeof'.
1237 TypeQualified
*Parser::parseTypeof()
1240 Loc loc
= token
.loc
;
1244 if (token
.value
== TOKreturn
) // typeof(return)
1247 t
= new TypeReturn(loc
);
1251 Expression
*exp
= parseExpression(); // typeof(expression)
1252 t
= new TypeTypeof(loc
, exp
);
1258 /***********************************
1259 * Parse __vector(type).
1260 * Current token is on the '__vector'.
1263 Type
*Parser::parseVector()
1267 Type
*tb
= parseType();
1269 return new TypeVector(tb
);
1272 /***********************************
1275 * extern (C++, namespaces)
1276 * The parser is on the 'extern' token.
1279 LINK
Parser::parseLinkage(Identifiers
**pidents
, CPPMANGLE
*pcppmangle
)
1281 Identifiers
*idents
= NULL
;
1282 CPPMANGLE cppmangle
= CPPMANGLEdefault
;
1283 LINK link
= LINKdefault
;
1285 assert(token
.value
== TOKlparen
);
1287 if (token
.value
== TOKidentifier
)
1288 { Identifier
*id
= token
.ident
;
1291 if (id
== Id::Windows
)
1293 else if (id
== Id::Pascal
)
1295 else if (id
== Id::D
)
1297 else if (id
== Id::C
)
1300 if (token
.value
== TOKplusplus
)
1304 if (token
.value
== TOKcomma
) // , namespaces or class or struct
1307 if (token
.value
== TOKclass
|| token
.value
== TOKstruct
)
1309 cppmangle
= token
.value
== TOKclass
? CPPMANGLEclass
: CPPMANGLEstruct
;
1314 idents
= new Identifiers();
1317 if (token
.value
== TOKidentifier
)
1319 Identifier
*idn
= token
.ident
;
1322 if (token
.value
== TOKdot
)
1330 error("identifier expected for C++ namespace");
1331 idents
= NULL
; // error occurred, invalidate list of elements.
1339 else if (id
== Id::Objective
) // Looking for tokens "Objective-C"
1341 if (token
.value
== TOKmin
)
1344 if (token
.ident
== Id::C
)
1350 goto LinvalidLinkage
;
1353 goto LinvalidLinkage
;
1355 else if (id
== Id::System
)
1362 error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
1368 link
= LINKd
; // default
1372 *pcppmangle
= cppmangle
;
1376 /***********************************
1377 * Parse ident1.ident2.ident3
1380 * entity = what qualified identifier is expected to resolve into.
1381 * Used only for better error message
1384 * array of identifiers with actual qualified one stored last
1386 Identifiers
*Parser::parseQualifiedIdentifier(const char *entity
)
1388 Identifiers
*qualified
= NULL
;
1393 if (token
.value
!= TOKidentifier
)
1395 error("%s expected as dot-separated identifiers, got '%s'",
1396 entity
, token
.toChars());
1400 Identifier
*id
= token
.ident
;
1402 qualified
= new Identifiers();
1403 qualified
->push(id
);
1406 } while (token
.value
== TOKdot
);
1411 /**************************************
1412 * Parse a debug conditional
1415 Condition
*Parser::parseDebugCondition()
1419 if (token
.value
== TOKlparen
)
1423 Identifier
*id
= NULL
;
1425 if (token
.value
== TOKidentifier
)
1427 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
1428 level
= (unsigned)token
.uns64value
;
1430 error("identifier or integer expected, not %s", token
.toChars());
1433 c
= new DebugCondition(mod
, level
, id
);
1436 c
= new DebugCondition(mod
, 1, NULL
);
1441 /**************************************
1442 * Parse a version conditional
1445 Condition
*Parser::parseVersionCondition()
1449 Identifier
*id
= NULL
;
1451 if (token
.value
== TOKlparen
)
1455 * version (unittest)
1457 * even though they are keywords
1459 if (token
.value
== TOKidentifier
)
1461 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
1462 level
= (unsigned)token
.uns64value
;
1463 else if (token
.value
== TOKunittest
)
1464 id
= Identifier::idPool(Token::toChars(TOKunittest
));
1465 else if (token
.value
== TOKassert
)
1466 id
= Identifier::idPool(Token::toChars(TOKassert
));
1468 error("identifier or integer expected, not %s", token
.toChars());
1474 error("(condition) expected following version");
1475 c
= new VersionCondition(mod
, level
, id
);
1480 /***********************************************
1481 * static if (expression)
1485 * Current token is 'static'.
1488 Condition
*Parser::parseStaticIfCondition()
1491 Condition
*condition
;
1492 Loc loc
= token
.loc
;
1496 if (token
.value
== TOKlparen
)
1499 exp
= parseAssignExp();
1504 error("(expression) expected following static if");
1507 condition
= new StaticIfCondition(loc
, exp
);
1512 /*****************************************
1513 * Parse a constructor definition:
1514 * this(parameters) { body }
1516 * this(this) { body }
1517 * or constructor template:
1518 * this(templateparameters)(parameters) { body }
1519 * Current token is 'this'.
1522 Dsymbol
*Parser::parseCtor(PrefixAttributes
*pAttrs
)
1524 Expressions
*udas
= NULL
;
1525 Loc loc
= token
.loc
;
1526 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1529 if (token
.value
== TOKlparen
&& peekNext() == TOKthis
&& peekNext2() == TOKrparen
)
1531 // this(this) { ... }
1536 stc
= parsePostfix(stc
, &udas
);
1537 if (stc
& STCstatic
)
1538 error(loc
, "postblit cannot be static");
1540 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, Loc(), stc
, Id::postblit
);
1542 pAttrs
->storageClass
= STCundefined
;
1543 Dsymbol
*s
= parseContracts(f
);
1546 Dsymbols
*a
= new Dsymbols();
1548 s
= new UserAttributeDeclaration(udas
, a
);
1553 /* Look ahead to see if:
1555 * which is a constructor template
1557 TemplateParameters
*tpl
= NULL
;
1558 if (token
.value
== TOKlparen
&& peekPastParen(&token
)->value
== TOKlparen
)
1560 tpl
= parseTemplateParameterList();
1563 /* Just a regular constructor
1566 Parameters
*parameters
= parseParameters(&varargs
);
1567 stc
= parsePostfix(stc
, &udas
);
1568 if (varargs
!= 0 || Parameter::dim(parameters
) != 0)
1570 if (stc
& STCstatic
)
1571 error(loc
, "constructor cannot be static");
1573 else if (StorageClass ss
= stc
& (STCshared
| STCstatic
)) // this()
1575 if (ss
== STCstatic
)
1576 error(loc
, "use 'static this()' to declare a static constructor");
1577 else if (ss
== (STCshared
| STCstatic
))
1578 error(loc
, "use 'shared static this()' to declare a shared static constructor");
1581 Expression
*constraint
= tpl
? parseConstraint() : NULL
;
1583 Type
*tf
= new TypeFunction(parameters
, NULL
, varargs
, linkage
, stc
); // RetrunType -> auto
1584 tf
= tf
->addSTC(stc
);
1586 CtorDeclaration
*f
= new CtorDeclaration(loc
, Loc(), stc
, tf
);
1588 pAttrs
->storageClass
= STCundefined
;
1589 Dsymbol
*s
= parseContracts(f
);
1592 Dsymbols
*a
= new Dsymbols();
1594 s
= new UserAttributeDeclaration(udas
, a
);
1599 // Wrap a template around it
1600 Dsymbols
*decldefs
= new Dsymbols();
1602 s
= new TemplateDeclaration(loc
, f
->ident
, tpl
, constraint
, decldefs
);
1608 /*****************************************
1609 * Parse a destructor definition:
1611 * Current token is '~'.
1614 Dsymbol
*Parser::parseDtor(PrefixAttributes
*pAttrs
)
1616 Expressions
*udas
= NULL
;
1617 Loc loc
= token
.loc
;
1618 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1625 stc
= parsePostfix(stc
, &udas
);
1626 if (StorageClass ss
= stc
& (STCshared
| STCstatic
))
1628 if (ss
== STCstatic
)
1629 error(loc
, "use 'static ~this()' to declare a static destructor");
1630 else if (ss
== (STCshared
| STCstatic
))
1631 error(loc
, "use 'shared static ~this()' to declare a shared static destructor");
1634 DtorDeclaration
*f
= new DtorDeclaration(loc
, Loc(), stc
, Id::dtor
);
1636 pAttrs
->storageClass
= STCundefined
;
1637 Dsymbol
*s
= parseContracts(f
);
1640 Dsymbols
*a
= new Dsymbols();
1642 s
= new UserAttributeDeclaration(udas
, a
);
1647 /*****************************************
1648 * Parse a static constructor definition:
1649 * static this() { body }
1650 * Current token is 'static'.
1653 Dsymbol
*Parser::parseStaticCtor(PrefixAttributes
*pAttrs
)
1655 //Expressions *udas = NULL;
1656 Loc loc
= token
.loc
;
1657 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1664 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, NULL
) | stc
;
1665 if (stc
& STCshared
)
1666 error(loc
, "use 'shared static this()' to declare a shared static constructor");
1667 else if (stc
& STCstatic
)
1668 appendStorageClass(stc
, STCstatic
); // complaint for the redundancy
1669 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1672 stcToBuffer(&buf
, modStc
);
1673 error(loc
, "static constructor cannot be %s", buf
.peekString());
1675 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1677 StaticCtorDeclaration
*f
= new StaticCtorDeclaration(loc
, Loc(), stc
);
1679 pAttrs
->storageClass
= STCundefined
;
1680 Dsymbol
*s
= parseContracts(f
);
1684 /*****************************************
1685 * Parse a static destructor definition:
1686 * static ~this() { body }
1687 * Current token is 'static'.
1690 Dsymbol
*Parser::parseStaticDtor(PrefixAttributes
*pAttrs
)
1692 Expressions
*udas
= NULL
;
1693 Loc loc
= token
.loc
;
1694 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1702 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, &udas
) | stc
;
1703 if (stc
& STCshared
)
1704 error(loc
, "use 'shared static ~this()' to declare a shared static destructor");
1705 else if (stc
& STCstatic
)
1706 appendStorageClass(stc
, STCstatic
); // complaint for the redundancy
1707 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1710 stcToBuffer(&buf
, modStc
);
1711 error(loc
, "static destructor cannot be %s", buf
.peekString());
1713 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1715 StaticDtorDeclaration
*f
= new StaticDtorDeclaration(loc
, Loc(), stc
);
1717 pAttrs
->storageClass
= STCundefined
;
1718 Dsymbol
*s
= parseContracts(f
);
1721 Dsymbols
*a
= new Dsymbols();
1723 s
= new UserAttributeDeclaration(udas
, a
);
1728 /*****************************************
1729 * Parse a shared static constructor definition:
1730 * shared static this() { body }
1731 * Current token is 'shared'.
1734 Dsymbol
*Parser::parseSharedStaticCtor(PrefixAttributes
*pAttrs
)
1736 //Expressions *udas = NULL;
1737 Loc loc
= token
.loc
;
1738 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1746 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, NULL
) | stc
;
1747 if (StorageClass ss
= stc
& (STCshared
| STCstatic
))
1748 appendStorageClass(stc
, ss
); // complaint for the redundancy
1749 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1752 stcToBuffer(&buf
, modStc
);
1753 error(loc
, "shared static constructor cannot be %s", buf
.peekString());
1755 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1757 SharedStaticCtorDeclaration
*f
= new SharedStaticCtorDeclaration(loc
, Loc(), stc
);
1759 pAttrs
->storageClass
= STCundefined
;
1760 Dsymbol
*s
= parseContracts(f
);
1764 /*****************************************
1765 * Parse a shared static destructor definition:
1766 * shared static ~this() { body }
1767 * Current token is 'shared'.
1770 Dsymbol
*Parser::parseSharedStaticDtor(PrefixAttributes
*pAttrs
)
1772 Expressions
*udas
= NULL
;
1773 Loc loc
= token
.loc
;
1774 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1783 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, &udas
) | stc
;
1784 if (StorageClass ss
= stc
& (STCshared
| STCstatic
))
1785 appendStorageClass(stc
, ss
); // complaint for the redundancy
1786 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1789 stcToBuffer(&buf
, modStc
);
1790 error(loc
, "shared static destructor cannot be %s", buf
.peekString());
1792 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1794 SharedStaticDtorDeclaration
*f
= new SharedStaticDtorDeclaration(loc
, Loc(), stc
);
1796 pAttrs
->storageClass
= STCundefined
;
1797 Dsymbol
*s
= parseContracts(f
);
1800 Dsymbols
*a
= new Dsymbols();
1802 s
= new UserAttributeDeclaration(udas
, a
);
1807 /*****************************************
1808 * Parse an invariant definition:
1809 * invariant() { body }
1810 * Current token is 'invariant'.
1813 Dsymbol
*Parser::parseInvariant(PrefixAttributes
*pAttrs
)
1815 Loc loc
= token
.loc
;
1816 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1819 if (token
.value
== TOKlparen
) // optional ()
1825 InvariantDeclaration
*f
= new InvariantDeclaration(loc
, Loc(), stc
);
1827 pAttrs
->storageClass
= STCundefined
;
1828 f
->fbody
= parseStatement(PScurly
);
1832 /*****************************************
1833 * Parse a unittest definition:
1835 * Current token is 'unittest'.
1838 Dsymbol
*Parser::parseUnitTest(PrefixAttributes
*pAttrs
)
1840 Loc loc
= token
.loc
;
1841 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1845 const utf8_t
*begPtr
= token
.ptr
+ 1; // skip '{'
1846 const utf8_t
*endPtr
= NULL
;
1847 Statement
*sbody
= parseStatement(PScurly
, &endPtr
);
1849 /** Extract unittest body as a string. Must be done eagerly since memory
1850 will be released by the lexer before doc gen. */
1851 char *docline
= NULL
;
1852 if (global
.params
.doDocComments
&& endPtr
> begPtr
)
1854 /* Remove trailing whitespaces */
1855 for (const utf8_t
*p
= endPtr
- 1;
1856 begPtr
<= p
&& (*p
== ' ' || *p
== '\r' || *p
== '\n' || *p
== '\t'); --p
)
1861 size_t len
= endPtr
- begPtr
;
1864 docline
= (char *)mem
.xmalloc(len
+ 2);
1865 memcpy(docline
, begPtr
, len
);
1866 docline
[len
] = '\n'; // Terminate all lines by LF
1867 docline
[len
+1] = '\0';
1871 UnitTestDeclaration
*f
= new UnitTestDeclaration(loc
, token
.loc
, stc
, docline
);
1873 pAttrs
->storageClass
= STCundefined
;
1878 /*****************************************
1879 * Parse a new definition:
1880 * new(parameters) { body }
1881 * Current token is 'new'.
1884 Dsymbol
*Parser::parseNew(PrefixAttributes
*pAttrs
)
1886 Loc loc
= token
.loc
;
1887 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1892 Parameters
*parameters
= parseParameters(&varargs
);
1893 NewDeclaration
*f
= new NewDeclaration(loc
, Loc(), stc
, parameters
, varargs
);
1895 pAttrs
->storageClass
= STCundefined
;
1896 Dsymbol
*s
= parseContracts(f
);
1900 /*****************************************
1901 * Parse a delete definition:
1902 * delete(parameters) { body }
1903 * Current token is 'delete'.
1906 Dsymbol
*Parser::parseDelete(PrefixAttributes
*pAttrs
)
1908 Loc loc
= token
.loc
;
1909 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1914 Parameters
*parameters
= parseParameters(&varargs
);
1916 error("... not allowed in delete function parameter list");
1917 DeleteDeclaration
*f
= new DeleteDeclaration(loc
, Loc(), stc
, parameters
);
1919 pAttrs
->storageClass
= STCundefined
;
1920 Dsymbol
*s
= parseContracts(f
);
1924 /**********************************************
1925 * Parse parameter list.
1928 Parameters
*Parser::parseParameters(int *pvarargs
, TemplateParameters
**tpl
)
1930 Parameters
*parameters
= new Parameters();
1937 Identifier
*ai
= NULL
;
1939 StorageClass storageClass
= 0;
1943 for (;1; nextToken())
1945 switch (token
.value
)
1956 if (peek(&token
)->value
== TOKlparen
)
1962 if (peek(&token
)->value
== TOKlparen
)
1968 if (peek(&token
)->value
== TOKlparen
)
1974 if (peek(&token
)->value
== TOKlparen
)
1979 case TOKin
: stc
= STCin
; goto L2
;
1980 case TOKout
: stc
= STCout
; goto L2
;
1981 case TOKref
: stc
= STCref
; goto L2
;
1982 case TOKlazy
: stc
= STClazy
; goto L2
;
1983 case TOKscope
: stc
= STCscope
; goto L2
;
1984 case TOKfinal
: stc
= STCfinal
; goto L2
;
1985 case TOKauto
: stc
= STCauto
; goto L2
;
1986 case TOKreturn
: stc
= STCreturn
; goto L2
;
1988 storageClass
= appendStorageClass(storageClass
, stc
);
1993 { stc
= storageClass
& (STCin
| STCout
| STCref
| STClazy
);
1994 // if stc is not a power of 2
1995 if (stc
& (stc
- 1) &&
1996 !(stc
== (STCin
| STCref
)))
1997 error("incompatible parameter storage classes");
1998 //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
1999 //error("scope cannot be ref or out");
2002 if (tpl
&& token
.value
== TOKidentifier
&&
2003 (t
= peek(&token
), (t
->value
== TOKcomma
||
2004 t
->value
== TOKrparen
||
2005 t
->value
== TOKdotdotdot
)))
2007 Identifier
*id
= Identifier::generateId("__T");
2008 Loc loc
= token
.loc
;
2009 at
= new TypeIdentifier(loc
, id
);
2011 *tpl
= new TemplateParameters();
2012 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, id
, NULL
, NULL
);
2019 at
= parseType(&ai
);
2021 if (token
.value
== TOKassign
) // = defaultArg
2023 ae
= parseDefaultInitExp();
2028 error("default argument expected for %s",
2029 ai
? ai
->toChars() : at
->toChars());
2031 if (token
.value
== TOKdotdotdot
)
2036 if (storageClass
& (STCout
| STCref
))
2037 error("variadic argument cannot be out or ref");
2039 parameters
->push(new Parameter(storageClass
, at
, ai
, ae
));
2043 parameters
->push(new Parameter(storageClass
, at
, ai
, ae
));
2044 if (token
.value
== TOKcomma
)
2058 *pvarargs
= varargs
;
2063 /*************************************
2066 EnumDeclaration
*Parser::parseEnum()
2071 Loc loc
= token
.loc
;
2073 //printf("Parser::parseEnum()\n");
2075 if (token
.value
== TOKidentifier
)
2083 if (token
.value
== TOKcolon
)
2088 Loc typeLoc
= token
.loc
;
2089 memtype
= parseBasicType();
2090 memtype
= parseDeclarator(memtype
, &alt
, NULL
);
2091 checkCstyleTypeSyntax(typeLoc
, memtype
, alt
, NULL
);
2096 e
= new EnumDeclaration(loc
, id
, memtype
);
2097 if (token
.value
== TOKsemicolon
&& id
)
2099 else if (token
.value
== TOKlcurly
)
2101 //printf("enum definition\n");
2102 e
->members
= new Dsymbols();
2104 const utf8_t
*comment
= token
.blockComment
;
2105 while (token
.value
!= TOKrcurly
)
2107 /* Can take the following forms:
2110 * 3. type ident = value
2116 Identifier
*ident
= NULL
;
2117 Token
*tp
= peek(&token
);
2118 if (token
.value
== TOKidentifier
&&
2119 (tp
->value
== TOKassign
|| tp
->value
== TOKcomma
|| tp
->value
== TOKrcurly
))
2121 ident
= token
.ident
;
2127 type
= parseType(&ident
, NULL
);
2129 error("no identifier for declarator %s", type
->toChars());
2131 error("type only allowed if anonymous enum and no enum type");
2135 if (token
.value
== TOKassign
)
2138 value
= parseAssignExp();
2144 error("if type, there must be an initializer");
2147 EnumMember
*em
= new EnumMember(loc
, ident
, value
, type
);
2148 e
->members
->push(em
);
2150 if (token
.value
== TOKrcurly
)
2154 addComment(em
, comment
);
2158 addComment(em
, comment
);
2159 comment
= token
.blockComment
;
2161 if (token
.value
== TOKeof
)
2163 error("premature end of file");
2170 error("enum declaration is invalid");
2172 //printf("-parseEnum() %s\n", e->toChars());
2176 /********************************
2177 * Parse struct, union, interface, class.
2180 Dsymbol
*Parser::parseAggregate()
2182 AggregateDeclaration
*a
= NULL
;
2185 TemplateParameters
*tpl
= NULL
;
2186 Expression
*constraint
= NULL
;
2187 Loc loc
= token
.loc
;
2188 TOK tok
= token
.value
;
2190 //printf("Parser::parseAggregate()\n");
2192 if (token
.value
!= TOKidentifier
)
2201 if (token
.value
== TOKlparen
)
2203 // Class template declaration.
2204 // Gather template parameter list
2205 tpl
= parseTemplateParameterList();
2206 constraint
= parseConstraint();
2216 error(loc
, "anonymous classes not allowed");
2218 // Collect base class(es)
2219 BaseClasses
*baseclasses
= NULL
;
2220 if (token
.value
== TOKcolon
)
2223 baseclasses
= parseBaseClasses();
2227 Expression
*tempCons
= parseConstraint();
2231 error("members expected");
2233 constraint
= tempCons
;
2237 if (token
.value
!= TOKlcurly
)
2238 error("members expected");
2241 if (tok
== TOKclass
)
2243 bool inObject
= md
&& !md
->packages
&& md
->id
== Id::object
;
2244 a
= new ClassDeclaration(loc
, id
, baseclasses
, NULL
, inObject
);
2247 a
= new InterfaceDeclaration(loc
, id
, baseclasses
);
2254 bool inObject
= md
&& !md
->packages
&& md
->id
== Id::object
;
2255 a
= new StructDeclaration(loc
, id
, inObject
);
2263 a
= new UnionDeclaration(loc
, id
);
2272 if (a
&& token
.value
== TOKsemicolon
)
2276 else if (token
.value
== TOKlcurly
)
2278 const Loc lookingForElseSave
= lookingForElse
;
2279 lookingForElse
= Loc();
2280 //printf("aggregate definition\n");
2282 Dsymbols
*decl
= parseDeclDefs(0);
2283 lookingForElse
= lookingForElseSave
;
2284 if (token
.value
!= TOKrcurly
)
2285 error("} expected following members in %s declaration at %s",
2286 Token::toChars(tok
), loc
.toChars());
2290 /* Anonymous structs/unions are more like attributes.
2292 return new AnonDeclaration(loc
, anon
== 2, decl
);
2299 error("{ } expected following %s declaration", Token::toChars(tok
));
2300 a
= new StructDeclaration(loc
, NULL
, false);
2305 // Wrap a template around the aggregate declaration
2306 Dsymbols
*decldefs
= new Dsymbols();
2308 TemplateDeclaration
*tempdecl
=
2309 new TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
);
2316 /*******************************************
2319 BaseClasses
*Parser::parseBaseClasses()
2321 BaseClasses
*baseclasses
= new BaseClasses();
2323 for (; 1; nextToken())
2326 Prot protection
= Prot(PROTpublic
);
2327 switch (token
.value
)
2331 protection
= Prot(PROTprivate
);
2336 protection
= Prot(PROTpackage
);
2341 protection
= Prot(PROTprotected
);
2346 protection
= Prot(PROTpublic
);
2352 error("use of base class protection is no longer supported");
2353 BaseClass
*b
= new BaseClass(parseBasicType());
2354 baseclasses
->push(b
);
2355 if (token
.value
!= TOKcomma
)
2361 /**************************************
2363 * Constraint is of the form:
2364 * if ( ConstraintExpression )
2367 Expression
*Parser::parseConstraint()
2368 { Expression
*e
= NULL
;
2370 if (token
.value
== TOKif
)
2372 nextToken(); // skip over 'if'
2374 e
= parseExpression();
2380 /**************************************
2381 * Parse a TemplateDeclaration.
2384 TemplateDeclaration
*Parser::parseTemplateDeclaration(bool ismixin
)
2386 TemplateDeclaration
*tempdecl
;
2388 TemplateParameters
*tpl
;
2390 Expression
*constraint
= NULL
;
2391 Loc loc
= token
.loc
;
2394 if (token
.value
!= TOKidentifier
)
2396 error("identifier expected following template");
2401 tpl
= parseTemplateParameterList();
2405 constraint
= parseConstraint();
2407 if (token
.value
!= TOKlcurly
)
2409 error("members of template declaration expected");
2413 decldefs
= parseBlock(NULL
);
2415 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
, ismixin
);
2422 /******************************************
2423 * Parse template parameter list.
2425 * flag 0: parsing "( list )"
2426 * 1: parsing non-empty "list )"
2429 TemplateParameters
*Parser::parseTemplateParameterList(int flag
)
2431 TemplateParameters
*tpl
= new TemplateParameters();
2433 if (!flag
&& token
.value
!= TOKlparen
)
2434 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
2439 // Get array of TemplateParameters
2440 if (flag
|| token
.value
!= TOKrparen
)
2443 while (token
.value
!= TOKrparen
)
2445 TemplateParameter
*tp
;
2447 Identifier
*tp_ident
= NULL
;
2448 Type
*tp_spectype
= NULL
;
2449 Type
*tp_valtype
= NULL
;
2450 Type
*tp_defaulttype
= NULL
;
2451 Expression
*tp_specvalue
= NULL
;
2452 Expression
*tp_defaultvalue
= NULL
;
2455 // Get TemplateParameter
2457 // First, look ahead to see if it is a TypeParameter or a ValueParameter
2459 if (token
.value
== TOKalias
)
2462 loc
= token
.loc
; // todo
2463 Type
*spectype
= NULL
;
2464 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2466 spectype
= parseType(&tp_ident
);
2470 if (token
.value
!= TOKidentifier
)
2472 error("identifier expected for template alias parameter");
2475 tp_ident
= token
.ident
;
2478 RootObject
*spec
= NULL
;
2479 if (token
.value
== TOKcolon
) // : Type
2482 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
2485 spec
= parseCondExp();
2487 RootObject
*def
= NULL
;
2488 if (token
.value
== TOKassign
) // = Type
2491 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
2494 def
= parseCondExp();
2496 tp
= new TemplateAliasParameter(loc
, tp_ident
, spectype
, spec
, def
);
2498 else if (t
->value
== TOKcolon
|| t
->value
== TOKassign
||
2499 t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
2502 if (token
.value
!= TOKidentifier
)
2504 error("identifier expected for template type parameter");
2508 tp_ident
= token
.ident
;
2510 if (token
.value
== TOKcolon
) // : Type
2513 tp_spectype
= parseType();
2515 if (token
.value
== TOKassign
) // = Type
2518 tp_defaulttype
= parseType();
2520 tp
= new TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
2522 else if (token
.value
== TOKidentifier
&& t
->value
== TOKdotdotdot
)
2526 error("variadic template parameter must be last");
2529 tp_ident
= token
.ident
;
2532 tp
= new TemplateTupleParameter(loc
, tp_ident
);
2534 else if (token
.value
== TOKthis
)
2538 if (token
.value
!= TOKidentifier
)
2540 error("identifier expected for template this parameter");
2544 tp_ident
= token
.ident
;
2546 if (token
.value
== TOKcolon
) // : Type
2549 tp_spectype
= parseType();
2551 if (token
.value
== TOKassign
) // = Type
2554 tp_defaulttype
= parseType();
2556 tp
= new TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
2561 loc
= token
.loc
; // todo
2562 tp_valtype
= parseType(&tp_ident
);
2565 error("identifier expected for template value parameter");
2566 tp_ident
= Identifier::idPool("error");
2568 if (token
.value
== TOKcolon
) // : CondExpression
2571 tp_specvalue
= parseCondExp();
2573 if (token
.value
== TOKassign
) // = CondExpression
2576 tp_defaultvalue
= parseDefaultInitExp();
2578 tp
= new TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
2581 if (token
.value
!= TOKcomma
)
2591 /******************************************
2592 * Parse template mixin.
2595 * mixin a.b.c!(args).Foo!(args);
2596 * mixin Foo!(args) identifier;
2597 * mixin typeof(expr).identifier!(args);
2600 Dsymbol
*Parser::parseMixin()
2606 //printf("parseMixin()\n");
2607 Loc locMixin
= token
.loc
;
2608 nextToken(); // skip 'mixin'
2610 Loc loc
= token
.loc
;
2611 TypeQualified
*tqual
= NULL
;
2612 if (token
.value
== TOKdot
)
2618 if (token
.value
== TOKtypeof
)
2620 tqual
= parseTypeof();
2623 if (token
.value
!= TOKidentifier
)
2625 error("identifier expected, not %s", token
.toChars());
2636 if (token
.value
== TOKnot
)
2638 tiargs
= parseTemplateArguments();
2641 if (tiargs
&& token
.value
== TOKdot
)
2643 TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
2644 tempinst
->tiargs
= tiargs
;
2646 tqual
= new TypeInstance(loc
, tempinst
);
2648 tqual
->addInst(tempinst
);
2654 tqual
= new TypeIdentifier(loc
, id
);
2656 tqual
->addIdent(id
);
2659 if (token
.value
!= TOKdot
)
2663 if (token
.value
!= TOKidentifier
)
2665 error("identifier expected following '.' instead of '%s'", token
.toChars());
2673 if (token
.value
== TOKidentifier
)
2681 tm
= new TemplateMixin(locMixin
, id
, tqual
, tiargs
);
2682 if (token
.value
!= TOKsemicolon
)
2683 error("';' expected after mixin");
2689 /******************************************
2690 * Parse template arguments.
2692 * current token is opening '!'
2694 * current token is one after closing ')'
2697 Objects
*Parser::parseTemplateArguments()
2702 if (token
.value
== TOKlparen
)
2704 // ident!(template_arguments)
2705 tiargs
= parseTemplateArgumentList();
2709 // ident!template_argument
2710 tiargs
= parseTemplateSingleArgument();
2712 if (token
.value
== TOKnot
)
2714 TOK tok
= peekNext();
2715 if (tok
!= TOKis
&& tok
!= TOKin
)
2717 error("multiple ! arguments are not allowed");
2720 if (token
.value
== TOKlparen
)
2721 parseTemplateArgumentList();
2723 parseTemplateSingleArgument();
2724 if (token
.value
== TOKnot
&& (tok
= peekNext()) != TOKis
&& tok
!= TOKin
)
2731 /******************************************
2732 * Parse template argument list.
2734 * current token is opening '(',
2735 * or ',' for __traits
2737 * current token is one after closing ')'
2740 Objects
*Parser::parseTemplateArgumentList()
2742 //printf("Parser::parseTemplateArgumentList()\n");
2743 Objects
*tiargs
= new Objects();
2744 TOK endtok
= TOKrparen
;
2745 assert(token
.value
== TOKlparen
|| token
.value
== TOKcomma
);
2748 // Get TemplateArgumentList
2749 while (token
.value
!= endtok
)
2751 // See if it is an Expression or a Type
2752 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
2753 { // Template argument is a type
2754 Type
*ta
= parseType();
2758 { // Template argument is an expression
2759 Expression
*ea
= parseAssignExp();
2762 if (token
.value
!= TOKcomma
)
2766 check(endtok
, "template argument list");
2770 /*****************************
2771 * Parse single template argument, to support the syntax:
2774 * current token is the arg
2777 Objects
*Parser::parseTemplateSingleArgument()
2779 //printf("parseTemplateSingleArgument()\n");
2780 Objects
*tiargs
= new Objects();
2782 switch (token
.value
)
2785 ta
= new TypeIdentifier(token
.loc
, token
.ident
);
2792 case TOKvoid
: ta
= Type::tvoid
; goto LabelX
;
2793 case TOKint8
: ta
= Type::tint8
; goto LabelX
;
2794 case TOKuns8
: ta
= Type::tuns8
; goto LabelX
;
2795 case TOKint16
: ta
= Type::tint16
; goto LabelX
;
2796 case TOKuns16
: ta
= Type::tuns16
; goto LabelX
;
2797 case TOKint32
: ta
= Type::tint32
; goto LabelX
;
2798 case TOKuns32
: ta
= Type::tuns32
; goto LabelX
;
2799 case TOKint64
: ta
= Type::tint64
; goto LabelX
;
2800 case TOKuns64
: ta
= Type::tuns64
; goto LabelX
;
2801 case TOKint128
: ta
= Type::tint128
; goto LabelX
;
2802 case TOKuns128
: ta
= Type::tuns128
; goto LabelX
;
2803 case TOKfloat32
: ta
= Type::tfloat32
; goto LabelX
;
2804 case TOKfloat64
: ta
= Type::tfloat64
; goto LabelX
;
2805 case TOKfloat80
: ta
= Type::tfloat80
; goto LabelX
;
2806 case TOKimaginary32
: ta
= Type::timaginary32
; goto LabelX
;
2807 case TOKimaginary64
: ta
= Type::timaginary64
; goto LabelX
;
2808 case TOKimaginary80
: ta
= Type::timaginary80
; goto LabelX
;
2809 case TOKcomplex32
: ta
= Type::tcomplex32
; goto LabelX
;
2810 case TOKcomplex64
: ta
= Type::tcomplex64
; goto LabelX
;
2811 case TOKcomplex80
: ta
= Type::tcomplex80
; goto LabelX
;
2812 case TOKbool
: ta
= Type::tbool
; goto LabelX
;
2813 case TOKchar
: ta
= Type::tchar
; goto LabelX
;
2814 case TOKwchar
: ta
= Type::twchar
; goto LabelX
;
2815 case TOKdchar
: ta
= Type::tdchar
; goto LabelX
;
2830 case TOKimaginary32v
:
2831 case TOKimaginary64v
:
2832 case TOKimaginary80v
:
2842 case TOKfilefullpath
:
2844 case TOKmodulestring
:
2848 { // Template argument is an expression
2849 Expression
*ea
= parsePrimaryExp();
2855 error("template argument expected following !");
2861 Dsymbols
*Parser::parseImport()
2863 Dsymbols
*decldefs
= new Dsymbols();
2864 Identifier
*aliasid
= NULL
;
2866 int isstatic
= token
.value
== TOKstatic
;
2870 //printf("Parser::parseImport()\n");
2875 if (token
.value
!= TOKidentifier
)
2877 error("identifier expected following import");
2881 Loc loc
= token
.loc
;
2882 Identifier
*id
= token
.ident
;
2883 Identifiers
*a
= NULL
;
2885 if (!aliasid
&& token
.value
== TOKassign
)
2890 while (token
.value
== TOKdot
)
2893 a
= new Identifiers();
2896 if (token
.value
!= TOKidentifier
)
2898 error("identifier expected following package");
2905 Import
*s
= new Import(loc
, a
, id
, aliasid
, isstatic
);
2909 * : alias=name, alias=name;
2912 if (token
.value
== TOKcolon
)
2917 if (token
.value
!= TOKidentifier
)
2919 error("identifier expected following :");
2922 Identifier
*alias
= token
.ident
;
2925 if (token
.value
== TOKassign
)
2928 if (token
.value
!= TOKidentifier
)
2930 error("identifier expected following %s=", alias
->toChars());
2941 s
->addAlias(name
, alias
);
2942 } while (token
.value
== TOKcomma
);
2943 break; // no comma-separated imports of this form
2947 } while (token
.value
== TOKcomma
);
2949 if (token
.value
== TOKsemicolon
)
2953 error("';' expected");
2960 Type
*Parser::parseType(Identifier
**pident
, TemplateParameters
**ptpl
)
2962 /* Take care of the storage class prefixes that
2963 * serve as type attributes:
2971 * shared inout const type
2973 StorageClass stc
= 0;
2976 switch (token
.value
)
2979 if (peekNext() == TOKlparen
)
2980 break; // const as type constructor
2981 stc
|= STCconst
; // const as storage class
2986 if (peekNext() == TOKlparen
)
2988 stc
|= STCimmutable
;
2993 if (peekNext() == TOKlparen
)
3000 if (peekNext() == TOKlparen
)
3012 Loc typeLoc
= token
.loc
;
3015 t
= parseBasicType();
3018 t
= parseDeclarator(t
, &alt
, pident
, ptpl
);
3019 checkCstyleTypeSyntax(typeLoc
, t
, alt
, pident
? *pident
: NULL
);
3025 Type
*Parser::parseBasicType(bool dontLookDotIdents
)
3031 //printf("parseBasicType()\n");
3032 switch (token
.value
)
3034 case TOKvoid
: t
= Type::tvoid
; goto LabelX
;
3035 case TOKint8
: t
= Type::tint8
; goto LabelX
;
3036 case TOKuns8
: t
= Type::tuns8
; goto LabelX
;
3037 case TOKint16
: t
= Type::tint16
; goto LabelX
;
3038 case TOKuns16
: t
= Type::tuns16
; goto LabelX
;
3039 case TOKint32
: t
= Type::tint32
; goto LabelX
;
3040 case TOKuns32
: t
= Type::tuns32
; goto LabelX
;
3041 case TOKint64
: t
= Type::tint64
; goto LabelX
;
3042 case TOKuns64
: t
= Type::tuns64
; goto LabelX
;
3043 case TOKint128
: t
= Type::tint128
; goto LabelX
;
3044 case TOKuns128
: t
= Type::tuns128
; goto LabelX
;
3045 case TOKfloat32
: t
= Type::tfloat32
; goto LabelX
;
3046 case TOKfloat64
: t
= Type::tfloat64
; goto LabelX
;
3047 case TOKfloat80
: t
= Type::tfloat80
; goto LabelX
;
3048 case TOKimaginary32
: t
= Type::timaginary32
; goto LabelX
;
3049 case TOKimaginary64
: t
= Type::timaginary64
; goto LabelX
;
3050 case TOKimaginary80
: t
= Type::timaginary80
; goto LabelX
;
3051 case TOKcomplex32
: t
= Type::tcomplex32
; goto LabelX
;
3052 case TOKcomplex64
: t
= Type::tcomplex64
; goto LabelX
;
3053 case TOKcomplex80
: t
= Type::tcomplex80
; goto LabelX
;
3054 case TOKbool
: t
= Type::tbool
; goto LabelX
;
3055 case TOKchar
: t
= Type::tchar
; goto LabelX
;
3056 case TOKwchar
: t
= Type::twchar
; goto LabelX
;
3057 case TOKdchar
: t
= Type::tdchar
; goto LabelX
;
3068 if (token
.value
== TOKnot
)
3070 // ident!(template_arguments)
3071 TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
3072 tempinst
->tiargs
= parseTemplateArguments();
3073 t
= parseBasicTypeStartingAt(new TypeInstance(loc
, tempinst
), dontLookDotIdents
);
3077 t
= parseBasicTypeStartingAt(new TypeIdentifier(loc
, id
), dontLookDotIdents
);
3082 // Leading . as in .foo
3083 t
= parseBasicTypeStartingAt(new TypeIdentifier(token
.loc
, Id::empty
), dontLookDotIdents
);
3087 // typeof(expression)
3088 t
= parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents
);
3099 t
= parseType()->addSTC(STCconst
);
3107 t
= parseType()->addSTC(STCimmutable
);
3115 t
= parseType()->addSTC(STCshared
);
3123 t
= parseType()->addSTC(STCwild
);
3128 error("basic type expected, not %s", token
.toChars());
3135 Type
*Parser::parseBasicTypeStartingAt(TypeQualified
*tid
, bool dontLookDotIdents
)
3137 Type
*maybeArray
= NULL
;
3138 // See https://issues.dlang.org/show_bug.cgi?id=1215
3139 // A basic type can look like MyType (typical case), but also:
3140 // MyType.T -> A type
3141 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3142 // MyType[expr].T -> A type.
3143 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3144 // (iif MyType[expr].T is a Ttuple)
3147 switch (token
.value
)
3152 if (token
.value
!= TOKidentifier
)
3154 error("identifier expected following '.' instead of '%s'", token
.toChars());
3159 // This is actually a TypeTuple index, not an {a/s}array.
3160 // We need to have a while loop to unwind all index taking:
3161 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3163 Type
*t
= maybeArray
;
3166 if (t
->ty
== Tsarray
)
3168 // The index expression is an Expression.
3169 TypeSArray
*a
= (TypeSArray
*)t
;
3170 dimStack
.push(a
->dim
->syntaxCopy());
3171 t
= a
->next
->syntaxCopy();
3173 else if (t
->ty
== Taarray
)
3175 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3176 TypeAArray
*a
= (TypeAArray
*)t
;
3177 dimStack
.push(a
->index
->syntaxCopy());
3178 t
= a
->next
->syntaxCopy();
3185 assert(dimStack
.dim
> 0);
3186 // We're good. Replay indices in the reverse order.
3187 tid
= (TypeQualified
*)t
;
3188 while (dimStack
.dim
)
3190 tid
->addIndex(dimStack
.pop());
3194 Loc loc
= token
.loc
;
3195 Identifier
*id
= token
.ident
;
3197 if (token
.value
== TOKnot
)
3199 TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
3200 tempinst
->tiargs
= parseTemplateArguments();
3201 tid
->addInst(tempinst
);
3209 if (dontLookDotIdents
) // workaround for Bugzilla 14911
3213 Type
*t
= maybeArray
? maybeArray
: (Type
*)tid
;
3214 if (token
.value
== TOKrbracket
)
3216 // It's a dynamic array, and we're done:
3217 // T[].U does not make sense.
3218 t
= new TypeDArray(t
);
3222 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
3224 // This can be one of two things:
3225 // 1 - an associative array declaration, T[type]
3226 // 2 - an associative array declaration, T[expr]
3227 // These can only be disambiguated later.
3228 Type
*index
= parseType(); // [ type ]
3229 maybeArray
= new TypeAArray(t
, index
);
3234 // This can be one of three things:
3235 // 1 - an static array declaration, T[expr]
3236 // 2 - a slice, T[expr .. expr]
3237 // 3 - a template parameter pack index expression, T[expr].U
3238 // 1 and 3 can only be disambiguated later.
3239 //printf("it's type[expression]\n");
3241 Expression
*e
= parseAssignExp(); // [ expression ]
3242 if (token
.value
== TOKslice
)
3244 // It's a slice, and we're done.
3246 Expression
*e2
= parseAssignExp(); // [ exp .. exp ]
3247 t
= new TypeSlice(t
, e
, e2
);
3254 maybeArray
= new TypeSArray(t
, e
);
3267 return maybeArray
? maybeArray
: (Type
*)tid
;
3270 /******************************************
3271 * Parse things that follow the initial type t.
3276 * t [expression .. expression]
3281 Type
*Parser::parseBasicType2(Type
*t
)
3283 //printf("parseBasicType2()\n");
3286 switch (token
.value
)
3289 t
= new TypePointer(t
);
3294 // Handle []. Make sure things like
3296 // is (array[1] of array[3] of int)
3298 if (token
.value
== TOKrbracket
)
3300 t
= new TypeDArray(t
); // []
3303 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
3305 // It's an associative array declaration
3306 //printf("it's an associative array\n");
3307 Type
*index
= parseType(); // [ type ]
3308 t
= new TypeAArray(t
, index
);
3313 //printf("it's type[expression]\n");
3315 Expression
*e
= parseAssignExp(); // [ expression ]
3316 if (token
.value
== TOKslice
)
3319 Expression
*e2
= parseAssignExp(); // [ exp .. exp ]
3320 t
= new TypeSlice(t
, e
, e2
);
3324 t
= new TypeSArray(t
,e
);
3334 // Handle delegate declaration:
3335 // t delegate(parameter list) nothrow pure
3336 // t function(parameter list) nothrow pure
3337 TOK save
= token
.value
;
3341 Parameters
*parameters
= parseParameters(&varargs
);
3343 StorageClass stc
= parsePostfix(STCundefined
, NULL
);
3344 TypeFunction
*tf
= new TypeFunction(parameters
, t
, varargs
, linkage
, stc
);
3345 if (stc
& (STCconst
| STCimmutable
| STCshared
| STCwild
| STCreturn
))
3347 if (save
== TOKfunction
)
3348 error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
3350 tf
= (TypeFunction
*)tf
->addSTC(stc
);
3353 if (save
== TOKdelegate
)
3354 t
= new TypeDelegate(tf
);
3356 t
= new TypePointer(tf
); // pointer to function
3369 Type
*Parser::parseDeclarator(Type
*t
, int *palt
, Identifier
**pident
,
3370 TemplateParameters
**tpl
, StorageClass storageClass
, int *pdisable
, Expressions
**pudas
)
3372 //printf("parseDeclarator(tpl = %p)\n", tpl);
3373 t
= parseBasicType2(t
);
3376 switch (token
.value
)
3380 *pident
= token
.ident
;
3382 error("unexpected identifer '%s' in declarator", token
.ident
->toChars());
3390 // like: T ((*fp))();
3391 if (peekNext() == TOKmul
||
3392 peekNext() == TOKlparen
)
3394 /* Parse things with parentheses around the identifier, like:
3396 * although the D style would be:
3401 ts
= parseDeclarator(t
, palt
, pident
);
3407 Token
*peekt
= &token
;
3408 /* Completely disallow C-style things like:
3410 * Improve error messages for the common bug of a missing return type
3411 * by looking to see if (a) looks like a parameter list.
3413 if (isParameters(&peekt
))
3415 error("function declaration without return type. (Note that constructors are always named 'this')");
3418 error("unexpected ( in declarator");
3427 // parse DeclaratorSuffixes
3430 switch (token
.value
)
3433 /* Support C style array syntax:
3435 * as opposed to D-style:
3440 // This is the old C-style post [] syntax.
3443 if (token
.value
== TOKrbracket
)
3445 // It's a dynamic array
3446 ta
= new TypeDArray(t
); // []
3450 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
3452 // It's an associative array
3453 //printf("it's an associative array\n");
3454 Type
*index
= parseType(); // [ type ]
3456 ta
= new TypeAArray(t
, index
);
3461 //printf("It's a static array\n");
3462 Expression
*e
= parseAssignExp(); // [ expression ]
3463 ta
= new TypeSArray(t
, e
);
3471 * ts -> ... -> ta -> t
3474 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
3484 Token
*tk
= peekPastParen(&token
);
3485 if (tk
->value
== TOKlparen
)
3487 /* Look ahead to see if this is (...)(...),
3488 * i.e. a function template declaration
3490 //printf("function template declaration\n");
3492 // Gather template parameter list
3493 *tpl
= parseTemplateParameterList();
3495 else if (tk
->value
== TOKassign
)
3498 * i.e. a variable template declaration
3500 //printf("variable template declaration\n");
3501 *tpl
= parseTemplateParameterList();
3507 Parameters
*parameters
= parseParameters(&varargs
);
3509 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
3511 StorageClass stc
= parsePostfix(storageClass
, pudas
);
3512 // merge prefix storage classes
3513 Type
*tf
= new TypeFunction(parameters
, t
, varargs
, linkage
, stc
);
3514 tf
= tf
->addSTC(stc
);
3516 *pdisable
= stc
& STCdisable
? 1 : 0;
3521 * ts -> ... -> tf -> t
3524 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
3537 void Parser::parseStorageClasses(StorageClass
&storage_class
, LINK
&link
,
3538 bool &setAlignment
, Expression
*&ealign
, Expressions
*&udas
)
3541 bool sawLinkage
= false; // seen a linkage declaration
3545 switch (token
.value
)
3548 if (peek(&token
)->value
== TOKlparen
)
3549 break; // const as type constructor
3550 stc
= STCconst
; // const as storage class
3554 if (peek(&token
)->value
== TOKlparen
)
3560 if (peek(&token
)->value
== TOKlparen
)
3566 if (peek(&token
)->value
== TOKlparen
)
3571 case TOKstatic
: stc
= STCstatic
; goto L1
;
3572 case TOKfinal
: stc
= STCfinal
; goto L1
;
3573 case TOKauto
: stc
= STCauto
; goto L1
;
3574 case TOKscope
: stc
= STCscope
; goto L1
;
3575 case TOKoverride
: stc
= STCoverride
; goto L1
;
3576 case TOKabstract
: stc
= STCabstract
; goto L1
;
3577 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
3578 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
3579 case TOKnothrow
: stc
= STCnothrow
; goto L1
;
3580 case TOKpure
: stc
= STCpure
; goto L1
;
3581 case TOKref
: stc
= STCref
; goto L1
;
3582 case TOKgshared
: stc
= STCgshared
; goto L1
;
3583 case TOKenum
: stc
= STCmanifest
; goto L1
;
3586 stc
= parseAttribute(&udas
);
3592 storage_class
= appendStorageClass(storage_class
, stc
);
3598 if (peek(&token
)->value
!= TOKlparen
)
3605 error("redundant linkage declaration");
3607 Identifiers
*idents
= NULL
;
3608 CPPMANGLE cppmangle
= CPPMANGLEdefault
;
3609 link
= parseLinkage(&idents
, &cppmangle
);
3612 error("C++ name spaces not allowed here");
3615 if (cppmangle
!= CPPMANGLEdefault
)
3617 error("C++ mangle declaration not allowed here");
3625 setAlignment
= true;
3626 if (token
.value
== TOKlparen
)
3629 ealign
= parseExpression();
3641 /**********************************
3642 * Parse Declarations.
3644 * 1. declarations at global/class level
3645 * 2. declarations at statement level
3646 * Return array of Declaration *'s.
3649 Dsymbols
*Parser::parseDeclarations(bool autodecl
, PrefixAttributes
*pAttrs
, const utf8_t
*comment
)
3651 StorageClass storage_class
= STCundefined
;
3656 TOK tok
= TOKreserved
;
3657 LINK link
= linkage
;
3658 bool setAlignment
= false;
3659 Expression
*ealign
= NULL
;
3660 Loc loc
= token
.loc
;
3661 Expressions
*udas
= NULL
;
3664 //printf("parseDeclarations() %s\n", token.toChars());
3666 comment
= token
.blockComment
;
3670 ts
= NULL
; // infer type
3674 if (token
.value
== TOKalias
)
3680 * alias identifier this;
3682 if (token
.value
== TOKidentifier
&& peekNext() == TOKthis
)
3684 AliasThis
*s
= new AliasThis(loc
, token
.ident
);
3687 check(TOKsemicolon
);
3688 Dsymbols
*a
= new Dsymbols();
3690 addComment(s
, comment
);
3694 * alias identifier = type;
3695 * alias identifier(...) = type;
3697 if (token
.value
== TOKidentifier
&&
3698 skipParensIf(peek(&token
), &tk
) &&
3699 tk
->value
== TOKassign
)
3701 Dsymbols
*a
= new Dsymbols();
3704 ident
= token
.ident
;
3706 TemplateParameters
*tpl
= NULL
;
3707 if (token
.value
== TOKlparen
)
3708 tpl
= parseTemplateParameterList();
3712 if (token
.value
== TOKfunction
||
3713 token
.value
== TOKdelegate
||
3714 (token
.value
== TOKlparen
&&
3715 skipAttributes(peekPastParen(&token
), &tk
) &&
3716 (tk
->value
== TOKgoesto
|| tk
->value
== TOKlcurly
)) ||
3717 token
.value
== TOKlcurly
||
3718 (token
.value
== TOKidentifier
&& peekNext() == TOKgoesto
))
3720 // function (parameters) { statements... }
3721 // delegate (parameters) { statements... }
3722 // (parameters) { statements... }
3723 // (parameters) => expression
3724 // { statements... }
3725 // identifier => expression
3727 Dsymbol
*s
= parseFunctionLiteral();
3728 v
= new AliasDeclaration(loc
, ident
, s
);
3732 // StorageClasses type
3734 storage_class
= STCundefined
;
3736 setAlignment
= false;
3739 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
);
3742 error("user defined attributes not allowed for %s declarations", Token::toChars(tok
));
3745 v
= new AliasDeclaration(loc
, ident
, t
);
3747 v
->storage_class
= storage_class
;
3752 Dsymbols
*a2
= new Dsymbols();
3754 TemplateDeclaration
*tempdecl
=
3755 new TemplateDeclaration(loc
, ident
, tpl
, NULL
, a2
);
3760 Dsymbols
*ax
= new Dsymbols();
3762 s
= new AlignDeclaration(v
->loc
, ealign
, ax
);
3764 if (link
!= linkage
)
3766 Dsymbols
*a2
= new Dsymbols();
3768 s
= new LinkDeclaration(link
, a2
);
3772 switch (token
.value
)
3776 addComment(s
, comment
);
3780 addComment(s
, comment
);
3781 if (token
.value
!= TOKidentifier
)
3783 error("identifier expected following comma, not %s", token
.toChars());
3786 if (peekNext() != TOKassign
&& peekNext() != TOKlparen
)
3788 error("= expected following identifier");
3794 error("semicolon expected to close %s declaration", Token::toChars(tok
));
3802 // alias StorageClasses type ident;
3805 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
);
3807 if (token
.value
== TOKstruct
||
3808 token
.value
== TOKunion
||
3809 token
.value
== TOKclass
||
3810 token
.value
== TOKinterface
)
3812 Dsymbol
*s
= parseAggregate();
3813 Dsymbols
*a
= new Dsymbols();
3818 s
= new StorageClassDeclaration(storage_class
, a
);
3824 s
= new AlignDeclaration(s
->loc
, ealign
, a
);
3828 if (link
!= linkage
)
3830 s
= new LinkDeclaration(link
, a
);
3836 s
= new UserAttributeDeclaration(udas
, a
);
3841 addComment(s
, comment
);
3845 /* Look for auto initializers:
3846 * storage_class identifier = initializer;
3847 * storage_class identifier(...) = initializer;
3849 if ((storage_class
|| udas
) &&
3850 token
.value
== TOKidentifier
&&
3851 skipParensIf(peek(&token
), &tk
) &&
3852 tk
->value
== TOKassign
)
3854 Dsymbols
*a
= parseAutoDeclarations(storage_class
, comment
);
3857 Dsymbol
*s
= new UserAttributeDeclaration(udas
, a
);
3864 /* Look for return type inference for template functions.
3866 if ((storage_class
|| udas
) && token
.value
== TOKidentifier
&& skipParens(peek(&token
), &tk
) &&
3867 skipAttributes(tk
, &tk
) &&
3868 (tk
->value
== TOKlparen
|| tk
->value
== TOKlcurly
|| tk
->value
== TOKin
|| tk
->value
== TOKout
||
3869 tk
->value
== TOKdo
|| (tk
->value
== TOKidentifier
&& tk
->ident
== Id::_body
)))
3875 ts
= parseBasicType();
3876 ts
= parseBasicType2(ts
);
3881 Dsymbols
*a
= new Dsymbols();
3885 storage_class
|= pAttrs
->storageClass
;
3886 //pAttrs->storageClass = STCundefined;
3891 TemplateParameters
*tpl
= NULL
;
3897 t
= parseDeclarator(ts
, &alt
, &ident
, &tpl
, storage_class
, &disable
, &udas
);
3901 else if (t
!= tfirst
)
3902 error("multiple declarations must have the same type, not %s and %s",
3903 tfirst
->toChars(), t
->toChars());
3904 bool isThis
= (t
->ty
== Tident
&& ((TypeIdentifier
*)t
)->ident
== Id::This
&& token
.value
== TOKassign
);
3906 checkCstyleTypeSyntax(loc
, t
, alt
, ident
);
3908 error("no identifier for declarator %s", t
->toChars());
3910 if (tok
== TOKalias
)
3913 Initializer
*init
= NULL
;
3915 /* Aliases can no longer have multiple declarators, storage classes,
3916 * linkages, or auto declarations.
3917 * These never made any sense, anyway.
3918 * The code below needs to be fixed to reject them.
3919 * The grammar has already been fixed to preclude them.
3923 error("user defined attributes not allowed for %s declarations", Token::toChars(tok
));
3925 if (token
.value
== TOKassign
)
3928 init
= parseInitializer();
3933 error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
3934 init
->toChars(), init
->toChars());
3936 error("alias cannot have initializer");
3938 v
= new AliasDeclaration(loc
, ident
, t
);
3940 v
->storage_class
= storage_class
;
3943 /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
3944 * on prefix and postfix.
3945 * @safe alias void function() FP1;
3946 * alias @safe void function() FP2; // FP2 is not @safe
3947 * alias void function() @safe FP3;
3949 pAttrs
->storageClass
&= (STCsafe
| STCsystem
| STCtrusted
);
3953 if (link
!= linkage
)
3955 Dsymbols
*ax
= new Dsymbols();
3957 s
= new LinkDeclaration(link
, ax
);
3960 switch (token
.value
)
3964 addComment(s
, comment
);
3969 addComment(s
, comment
);
3973 error("semicolon expected to close %s declaration", Token::toChars(tok
));
3977 else if (t
->ty
== Tfunction
)
3979 Expression
*constraint
= NULL
;
3981 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
3982 FuncDeclaration
*f
=
3983 new FuncDeclaration(loc
, Loc(), ident
, storage_class
| (disable
? STCdisable
: 0), t
);
3985 pAttrs
->storageClass
= STCundefined
;
3987 constraint
= parseConstraint();
3988 Dsymbol
*s
= parseContracts(f
);
3989 Identifier
*tplIdent
= s
->ident
;
3990 if (link
!= linkage
)
3992 Dsymbols
*ax
= new Dsymbols();
3994 s
= new LinkDeclaration(link
, ax
);
3998 Dsymbols
*ax
= new Dsymbols();
4000 s
= new UserAttributeDeclaration(udas
, ax
);
4003 /* A template parameter list means it's a function template
4007 // Wrap a template around the function declaration
4008 Dsymbols
*decldefs
= new Dsymbols();
4010 TemplateDeclaration
*tempdecl
=
4011 new TemplateDeclaration(loc
, tplIdent
, tpl
, constraint
, decldefs
);
4014 if (storage_class
& STCstatic
)
4016 assert(f
->storage_class
& STCstatic
);
4017 f
->storage_class
&= ~STCstatic
;
4019 Dsymbols
*ax
= new Dsymbols();
4021 s
= new StorageClassDeclaration(STCstatic
, ax
);
4025 addComment(s
, comment
);
4029 Initializer
*init
= NULL
;
4030 if (token
.value
== TOKassign
)
4033 init
= parseInitializer();
4036 VarDeclaration
*v
= new VarDeclaration(loc
, t
, ident
, init
);
4037 v
->storage_class
= storage_class
;
4039 pAttrs
->storageClass
= STCundefined
;
4045 Dsymbols
*a2
= new Dsymbols();
4047 TemplateDeclaration
*tempdecl
=
4048 new TemplateDeclaration(loc
, ident
, tpl
, NULL
, a2
, 0);
4051 if (link
!= linkage
)
4053 Dsymbols
*ax
= new Dsymbols();
4055 s
= new LinkDeclaration(link
, ax
);
4059 Dsymbols
*ax
= new Dsymbols();
4061 s
= new UserAttributeDeclaration(udas
, ax
);
4064 switch (token
.value
)
4068 addComment(s
, comment
);
4073 addComment(s
, comment
);
4077 error("semicolon expected, not '%s'", token
.toChars());
4086 Dsymbol
*Parser::parseFunctionLiteral()
4088 Loc loc
= token
.loc
;
4090 TemplateParameters
*tpl
= NULL
;
4091 Parameters
*parameters
= NULL
;
4094 StorageClass stc
= 0;
4095 TOK save
= TOKreserved
;
4097 switch (token
.value
)
4103 if (token
.value
!= TOKlparen
&& token
.value
!= TOKlcurly
)
4105 // function type (parameters) { statements... }
4106 // delegate type (parameters) { statements... }
4107 tret
= parseBasicType();
4108 tret
= parseBasicType2(tret
); // function return type
4111 if (token
.value
== TOKlparen
)
4113 // function (parameters) { statements... }
4114 // delegate (parameters) { statements... }
4118 // function { statements... }
4119 // delegate { statements... }
4126 // (parameters) => expression
4127 // (parameters) { statements... }
4128 parameters
= parseParameters(&varargs
, &tpl
);
4129 stc
= parsePostfix(STCundefined
, NULL
);
4130 if (StorageClass modStc
= stc
& STC_TYPECTOR
)
4132 if (save
== TOKfunction
)
4135 stcToBuffer(&buf
, modStc
);
4136 error("function literal cannot be %s", buf
.peekString());
4144 // { statements... }
4149 // identifier => expression
4150 parameters
= new Parameters();
4151 Identifier
*id
= Identifier::generateId("__T");
4152 Type
*t
= new TypeIdentifier(loc
, id
);
4153 parameters
->push(new Parameter(0, t
, token
.ident
, NULL
));
4155 tpl
= new TemplateParameters();
4156 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, id
, NULL
, NULL
);
4167 parameters
= new Parameters();
4168 TypeFunction
*tf
= new TypeFunction(parameters
, tret
, varargs
, linkage
, stc
);
4169 tf
= (TypeFunction
*)tf
->addSTC(stc
);
4170 FuncLiteralDeclaration
*fd
= new FuncLiteralDeclaration(loc
, Loc(), tf
, save
, NULL
);
4172 if (token
.value
== TOKgoesto
)
4175 Loc returnloc
= token
.loc
;
4176 Expression
*ae
= parseAssignExp();
4177 fd
->fbody
= new ReturnStatement(returnloc
, ae
);
4178 fd
->endloc
= token
.loc
;
4187 // Wrap a template around function fd
4188 Dsymbols
*decldefs
= new Dsymbols();
4190 return new TemplateDeclaration(fd
->loc
, fd
->ident
, tpl
, NULL
, decldefs
, false, true);
4196 /*****************************************
4197 * Parse auto declarations of the form:
4198 * storageClass ident = init, ident = init, ... ;
4199 * and return the array of them.
4200 * Starts with token on the first ident.
4201 * Ends with scanner past closing ';'
4204 Dsymbols
*Parser::parseAutoDeclarations(StorageClass storageClass
, const utf8_t
*comment
)
4206 //printf("parseAutoDeclarations\n");
4208 Dsymbols
*a
= new Dsymbols
;
4212 Loc loc
= token
.loc
;
4213 Identifier
*ident
= token
.ident
;
4214 nextToken(); // skip over ident
4216 TemplateParameters
*tpl
= NULL
;
4217 if (token
.value
== TOKlparen
)
4218 tpl
= parseTemplateParameterList();
4220 check(TOKassign
); // skip over '='
4221 Initializer
*init
= parseInitializer();
4222 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
4223 v
->storage_class
= storageClass
;
4228 Dsymbols
*a2
= new Dsymbols();
4230 TemplateDeclaration
*tempdecl
=
4231 new TemplateDeclaration(loc
, ident
, tpl
, NULL
, a2
, 0);
4235 switch (token
.value
)
4239 addComment(s
, comment
);
4244 if (!(token
.value
== TOKidentifier
&&
4245 skipParensIf(peek(&token
), &tk
) &&
4246 tk
->value
== TOKassign
))
4248 error("identifier expected following comma");
4251 addComment(s
, comment
);
4255 error("semicolon expected following auto declaration, not '%s'", token
.toChars());
4263 /*****************************************
4264 * Parse contracts following function declaration.
4267 FuncDeclaration
*Parser::parseContracts(FuncDeclaration
*f
)
4269 LINK linksave
= linkage
;
4271 bool literal
= f
->isFuncLiteralDeclaration() != NULL
;
4273 // The following is irrelevant, as it is overridden by sc->linkage in
4274 // TypeFunction::semantic
4275 linkage
= LINKd
; // nested functions have D linkage
4277 switch (token
.value
)
4280 if (f
->frequire
|| f
->fensure
)
4281 error("missing body { ... } after in or out");
4282 f
->fbody
= parseStatement(PSsemi
);
4287 if (token
.ident
!= Id::_body
)
4293 f
->fbody
= parseStatement(PScurly
);
4300 error("redundant 'in' statement");
4301 f
->frequire
= parseStatement(PScurly
| PSscope
);
4305 // parse: out (identifier) { statement }
4307 if (token
.value
!= TOKlcurly
)
4310 if (token
.value
!= TOKidentifier
)
4311 error("(identifier) following 'out' expected, not %s", token
.toChars());
4312 f
->outId
= token
.ident
;
4317 error("redundant 'out' statement");
4318 f
->fensure
= parseStatement(PScurly
| PSscope
);
4324 // Bugzilla 15799: Semicolon becomes a part of function declaration
4325 // only when neither of contracts exists.
4326 if (!f
->frequire
&& !f
->fensure
)
4336 const char *sbody
= (f
->frequire
|| f
->fensure
) ? "body " : "";
4337 error("missing %s{ ... } for function literal", sbody
);
4339 else if (!f
->frequire
&& !f
->fensure
) // allow these even with no body
4341 error("semicolon expected following function declaration");
4345 if (literal
&& !f
->fbody
)
4347 // Set empty function body for error recovery
4348 f
->fbody
= new CompoundStatement(Loc(), (Statement
*)NULL
);
4356 /*****************************************
4357 * Parse initializer for variable declaration.
4360 Initializer
*Parser::parseInitializer()
4362 StructInitializer
*is
;
4363 ArrayInitializer
*ia
;
4369 Loc loc
= token
.loc
;
4374 switch (token
.value
)
4377 /* Scan ahead to see if it is a struct initializer or
4378 * a function literal.
4379 * If it contains a ';', it is a function literal.
4380 * Treat { } as a struct initializer.
4383 for (t
= peek(&token
); 1; t
= peek(t
))
4409 is
= new StructInitializer(loc
);
4414 switch (token
.value
)
4418 error("comma expected separating field initializers");
4420 if (t
->value
== TOKcolon
)
4424 nextToken(); // skip over ':'
4429 value
= parseInitializer();
4430 is
->addInit(id
, value
);
4436 error("expression expected, not ','");
4441 case TOKrcurly
: // allow trailing comma's
4446 error("found EOF instead of initializer");
4451 error("comma expected separating field initializers");
4452 value
= parseInitializer();
4453 is
->addInit(NULL
, value
);
4456 //error("found '%s' instead of field initializer", token.toChars());
4464 /* Scan ahead to see if it is an array initializer or
4466 * If it ends with a ';' ',' or '}', it is an array initializer.
4469 for (t
= peek(&token
); 1; t
= peek(t
))
4478 if (--brackets
== 0)
4480 if (t
->value
!= TOKsemicolon
&&
4481 t
->value
!= TOKcomma
&&
4482 t
->value
!= TOKrbracket
&&
4483 t
->value
!= TOKrcurly
)
4498 ia
= new ArrayInitializer(loc
);
4503 switch (token
.value
)
4507 { error("comma expected separating array initializers, not %s", token
.toChars());
4511 e
= parseAssignExp();
4514 if (token
.value
== TOKcolon
)
4517 value
= parseInitializer();
4520 { value
= new ExpInitializer(e
->loc
, e
);
4523 ia
->addInit(e
, value
);
4530 error("comma expected separating array initializers, not %s", token
.toChars());
4531 value
= parseInitializer();
4532 if (token
.value
== TOKcolon
)
4535 e
= initializerToExpression(value
);
4536 value
= parseInitializer();
4540 ia
->addInit(e
, value
);
4546 error("expression expected, not ','");
4551 case TOKrbracket
: // allow trailing comma's
4556 error("found '%s' instead of array initializer", token
.toChars());
4565 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
)
4568 return new VoidInitializer(loc
);
4574 e
= parseAssignExp();
4575 ie
= new ExpInitializer(loc
, e
);
4580 /*****************************************
4581 * Parses default argument initializer expression that is an assign expression,
4582 * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
4585 Expression
*Parser::parseDefaultInitExp()
4587 if (token
.value
== TOKfile
||
4588 token
.value
== TOKfilefullpath
||
4589 token
.value
== TOKline
||
4590 token
.value
== TOKmodulestring
||
4591 token
.value
== TOKfuncstring
||
4592 token
.value
== TOKprettyfunc
)
4594 Token
*t
= peek(&token
);
4595 if (t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
4597 Expression
*e
= NULL
;
4598 if (token
.value
== TOKfile
)
4599 e
= new FileInitExp(token
.loc
, TOKfile
);
4600 else if (token
.value
== TOKfilefullpath
)
4601 e
= new FileInitExp(token
.loc
, TOKfilefullpath
);
4602 else if (token
.value
== TOKline
)
4603 e
= new LineInitExp(token
.loc
);
4604 else if (token
.value
== TOKmodulestring
)
4605 e
= new ModuleInitExp(token
.loc
);
4606 else if (token
.value
== TOKfuncstring
)
4607 e
= new FuncInitExp(token
.loc
);
4608 else if (token
.value
== TOKprettyfunc
)
4609 e
= new PrettyFuncInitExp(token
.loc
);
4617 Expression
*e
= parseAssignExp();
4621 /*****************************************
4624 void Parser::checkDanglingElse(Loc elseloc
)
4626 if (token
.value
!= TOKelse
&&
4627 token
.value
!= TOKcatch
&&
4628 token
.value
!= TOKfinally
&&
4629 lookingForElse
.linnum
!= 0)
4631 warning(elseloc
, "else is dangling, add { } after condition at %s", lookingForElse
.toChars());
4635 void Parser::checkCstyleTypeSyntax(Loc loc
, Type
*t
, int alt
, Identifier
*ident
)
4640 const char *sp
= !ident
? "" : " ";
4641 const char *s
= !ident
? "" : ident
->toChars();
4642 if (alt
& 1) // contains C-style function pointer syntax
4643 error(loc
, "instead of C-style syntax, use D-style '%s%s%s'", t
->toChars(), sp
, s
);
4645 ::warning(loc
, "instead of C-style syntax, use D-style syntax '%s%s%s'", t
->toChars(), sp
, s
);
4649 /*****************************************
4653 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
4656 Statement
*Parser::parseStatement(int flags
, const utf8_t
** endPtr
, Loc
*pEndloc
)
4658 Statement
*s
= NULL
;
4661 Statement
*elsebody
;
4663 Loc loc
= token
.loc
;
4665 //printf("parseStatement()\n");
4667 if (flags
& PScurly
&& token
.value
!= TOKlcurly
)
4668 error("statement expected to be { }, not %s", token
.toChars());
4670 switch (token
.value
)
4673 { /* A leading identifier can be a declaration, label, or expression.
4674 * The easiest case to check first is label:
4676 Token
*t
= peek(&token
);
4677 if (t
->value
== TOKcolon
)
4679 Token
*nt
= peek(t
);
4680 if (nt
->value
== TOKcolon
)
4686 error("use `.` for member lookup, not `::`");
4690 Identifier
*ident
= token
.ident
;
4693 if (token
.value
== TOKrcurly
)
4695 else if (token
.value
== TOKlcurly
)
4696 s
= parseStatement(PScurly
| PSscope
);
4698 s
= parseStatement(PSsemi_ok
);
4699 s
= new LabelStatement(loc
, ident
, s
);
4707 /* Bugzilla 15163: If tokens can be handled as
4708 * old C-style declaration or D expression, prefer the latter.
4710 if (isDeclaration(&token
, 3, TOKreserved
, NULL
))
4728 case TOKimaginary32v
:
4729 case TOKimaginary64v
:
4730 case TOKimaginary80v
:
4757 case TOKfilefullpath
:
4759 case TOKmodulestring
:
4764 Expression
*exp
= parseExpression();
4765 check(TOKsemicolon
, "statement");
4766 s
= new ExpStatement(loc
, exp
);
4771 { // Look ahead to see if it's static assert() or static if()
4773 Token
*t
= peek(&token
);
4774 if (t
->value
== TOKassert
)
4776 s
= new StaticAssertStatement(parseStaticAssert());
4779 if (t
->value
== TOKif
)
4781 cond
= parseStaticIfCondition();
4784 if (t
->value
== TOKimport
)
4786 Dsymbols
*imports
= parseImport();
4787 s
= new ImportStatement(loc
, imports
);
4788 if (flags
& PSscope
)
4789 s
= new ScopeStatement(loc
, s
, token
.loc
);
4796 if (peekNext() == TOKswitch
)
4804 case TOKwchar
: case TOKdchar
:
4805 case TOKbool
: case TOKchar
:
4806 case TOKint8
: case TOKuns8
:
4807 case TOKint16
: case TOKuns16
:
4808 case TOKint32
: case TOKuns32
:
4809 case TOKint64
: case TOKuns64
:
4810 case TOKint128
: case TOKuns128
:
4811 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
4812 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
4813 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
4815 // bug 7773: int.max is always a part of expression
4816 if (peekNext() == TOKdot
)
4818 if (peekNext() == TOKlparen
)
4843 Dsymbols
*a
= parseDeclarations(false, NULL
, NULL
);
4846 Statements
*as
= new Statements();
4847 as
->reserve(a
->dim
);
4848 for (size_t i
= 0; i
< a
->dim
; i
++)
4850 Dsymbol
*d
= (*a
)[i
];
4851 s
= new ExpStatement(loc
, d
);
4854 s
= new CompoundDeclarationStatement(loc
, as
);
4856 else if (a
->dim
== 1)
4858 Dsymbol
*d
= (*a
)[0];
4859 s
= new ExpStatement(loc
, d
);
4862 s
= new ExpStatement(loc
, (Expression
*)NULL
);
4863 if (flags
& PSscope
)
4864 s
= new ScopeStatement(loc
, s
, token
.loc
);
4869 { /* Determine if this is a manifest constant declaration,
4870 * or a conventional enum.
4873 Token
*t
= peek(&token
);
4874 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
4876 else if (t
->value
!= TOKidentifier
)
4881 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
4882 t
->value
== TOKsemicolon
)
4887 s
= new ExpStatement(loc
, d
);
4888 if (flags
& PSscope
)
4889 s
= new ScopeStatement(loc
, s
, token
.loc
);
4894 { Token
*t
= peek(&token
);
4895 if (t
->value
== TOKlparen
)
4897 Expression
*e
= parseAssignExp();
4898 check(TOKsemicolon
);
4899 if (e
->op
== TOKmixin
)
4901 CompileExp
*cpe
= (CompileExp
*)e
;
4902 s
= new CompileStatement(loc
, cpe
->e1
);
4906 s
= new ExpStatement(loc
, e
);
4910 Dsymbol
*d
= parseMixin();
4911 s
= new ExpStatement(loc
, d
);
4912 if (flags
& PSscope
)
4913 s
= new ScopeStatement(loc
, s
, token
.loc
);
4919 Loc lookingForElseSave
= lookingForElse
;
4920 lookingForElse
= Loc();
4923 //if (token.value == TOKsemicolon)
4924 //error("use '{ }' for an empty statement, not a ';'");
4925 Statements
*statements
= new Statements();
4926 while (token
.value
!= TOKrcurly
&& token
.value
!= TOKeof
)
4928 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
4930 if (endPtr
) *endPtr
= token
.ptr
;
4934 *pEndloc
= token
.loc
;
4935 pEndloc
= NULL
; // don't set it again
4937 s
= new CompoundStatement(loc
, statements
);
4938 if (flags
& (PSscope
| PScurlyscope
))
4939 s
= new ScopeStatement(loc
, s
, token
.loc
);
4940 check(TOKrcurly
, "compound statement");
4941 lookingForElse
= lookingForElseSave
;
4949 Expression
*condition
= parseExpression();
4952 Statement
*body
= parseStatement(PSscope
, NULL
, &endloc
);
4953 s
= new WhileStatement(loc
, condition
, body
, endloc
);
4958 if (!(flags
& PSsemi_ok
))
4961 deprecation("use '{ }' for an empty statement, not a ';'");
4963 error("use '{ }' for an empty statement, not a ';'");
4966 s
= new ExpStatement(loc
, (Expression
*)NULL
);
4971 Expression
*condition
;
4974 Loc lookingForElseSave
= lookingForElse
;
4975 lookingForElse
= Loc();
4976 body
= parseStatement(PSscope
);
4977 lookingForElse
= lookingForElseSave
;
4980 condition
= parseExpression();
4982 if (token
.value
== TOKsemicolon
)
4985 error("terminating ';' required after do-while statement");
4986 s
= new DoStatement(loc
, body
, condition
, token
.loc
);
4993 Expression
*condition
;
4994 Expression
*increment
;
4998 if (token
.value
== TOKsemicolon
)
5004 Loc lookingForElseSave
= lookingForElse
;
5005 lookingForElse
= Loc();
5006 init
= parseStatement(0);
5007 lookingForElse
= lookingForElseSave
;
5009 if (token
.value
== TOKsemicolon
)
5016 condition
= parseExpression();
5017 check(TOKsemicolon
, "for condition");
5019 if (token
.value
== TOKrparen
)
5024 { increment
= parseExpression();
5028 Statement
*body
= parseStatement(PSscope
, NULL
, &endloc
);
5029 s
= new ForStatement(loc
, init
, condition
, increment
, body
, endloc
);
5034 case TOKforeach_reverse
:
5036 TOK op
= token
.value
;
5041 Parameters
*parameters
= new Parameters();
5045 Identifier
*ai
= NULL
;
5048 StorageClass storageClass
= 0;
5049 StorageClass stc
= 0;
5053 storageClass
= appendStorageClass(storageClass
, stc
);
5056 switch (token
.value
)
5063 if (peekNext() != TOKlparen
)
5070 if (peekNext() != TOKlparen
)
5077 if (peekNext() != TOKlparen
)
5084 if (peekNext() != TOKlparen
)
5093 if (token
.value
== TOKidentifier
)
5095 Token
*t
= peek(&token
);
5096 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
5098 at
= NULL
; // infer argument type
5103 at
= parseType(&ai
);
5105 error("no identifier for declarator %s", at
->toChars());
5107 Parameter
*p
= new Parameter(storageClass
, at
, ai
, NULL
);
5108 parameters
->push(p
);
5109 if (token
.value
== TOKcomma
)
5115 check(TOKsemicolon
);
5117 Expression
*aggr
= parseExpression();
5118 if (token
.value
== TOKslice
&& parameters
->dim
== 1)
5120 Parameter
*p
= (*parameters
)[0];
5123 Expression
*upr
= parseExpression();
5126 Statement
*body
= parseStatement(0, NULL
, &endloc
);
5127 s
= new ForeachRangeStatement(loc
, op
, p
, aggr
, upr
, body
, endloc
);
5133 Statement
*body
= parseStatement(0, NULL
, &endloc
);
5134 s
= new ForeachStatement(loc
, op
, parameters
, aggr
, body
, endloc
);
5141 Parameter
*param
= NULL
;
5142 Expression
*condition
;
5147 StorageClass storageClass
= 0;
5148 StorageClass stc
= 0;
5152 storageClass
= appendStorageClass(storageClass
, stc
);
5155 switch (token
.value
)
5164 if (peekNext() != TOKlparen
)
5171 if (peekNext() != TOKlparen
)
5178 if (peekNext() != TOKlparen
)
5185 if (peekNext() != TOKlparen
)
5195 if (storageClass
!= 0 &&
5196 token
.value
== TOKidentifier
&&
5197 peek(&token
)->value
== TOKassign
)
5199 Identifier
*ai
= token
.ident
;
5200 Type
*at
= NULL
; // infer parameter type
5203 param
= new Parameter(storageClass
, at
, ai
, NULL
);
5205 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
5208 Type
*at
= parseType(&ai
);
5210 param
= new Parameter(storageClass
, at
, ai
, NULL
);
5213 condition
= parseExpression();
5216 Loc lookingForElseSave
= lookingForElse
;
5217 lookingForElse
= loc
;
5218 ifbody
= parseStatement(PSscope
);
5219 lookingForElse
= lookingForElseSave
;
5221 if (token
.value
== TOKelse
)
5223 Loc elseloc
= token
.loc
;
5225 elsebody
= parseStatement(PSscope
);
5226 checkDanglingElse(elseloc
);
5230 if (condition
&& ifbody
)
5231 s
= new IfStatement(loc
, param
, condition
, ifbody
, elsebody
, token
.loc
);
5233 s
= NULL
; // don't propagate parsing errors
5238 if (peek(&token
)->value
!= TOKlparen
)
5239 goto Ldeclaration
; // scope used as storage class
5242 if (token
.value
!= TOKidentifier
)
5243 { error("scope identifier expected");
5247 { TOK t
= TOKon_scope_exit
;
5248 Identifier
*id
= token
.ident
;
5251 t
= TOKon_scope_exit
;
5252 else if (id
== Id::failure
)
5253 t
= TOKon_scope_failure
;
5254 else if (id
== Id::success
)
5255 t
= TOKon_scope_success
;
5257 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
5260 Statement
*st
= parseStatement(PSscope
);
5261 s
= new OnScopeStatement(loc
, t
, st
);
5267 if (token
.value
== TOKassign
)
5269 error("debug conditions can only be declared at module scope");
5274 cond
= parseDebugCondition();
5279 if (token
.value
== TOKassign
)
5281 error("version conditions can only be declared at module scope");
5286 cond
= parseVersionCondition();
5291 Loc lookingForElseSave
= lookingForElse
;
5292 lookingForElse
= loc
;
5293 ifbody
= parseStatement(0);
5294 lookingForElse
= lookingForElseSave
;
5297 if (token
.value
== TOKelse
)
5299 Loc elseloc
= token
.loc
;
5301 elsebody
= parseStatement(0);
5302 checkDanglingElse(elseloc
);
5304 s
= new ConditionalStatement(loc
, cond
, ifbody
, elsebody
);
5305 if (flags
& PSscope
)
5306 s
= new ScopeStatement(loc
, s
, token
.loc
);
5310 { Identifier
*ident
;
5311 Expressions
*args
= NULL
;
5316 if (token
.value
!= TOKidentifier
)
5317 { error("pragma(identifier expected");
5320 ident
= token
.ident
;
5322 if (token
.value
== TOKcomma
&& peekNext() != TOKrparen
)
5323 args
= parseArguments(); // pragma(identifier, args...);
5325 check(TOKrparen
); // pragma(identifier);
5326 if (token
.value
== TOKsemicolon
)
5331 body
= parseStatement(PSsemi
);
5332 s
= new PragmaStatement(loc
, ident
, args
, body
);
5344 Expression
*condition
= parseExpression();
5346 Statement
*body
= parseStatement(PSscope
);
5347 s
= new SwitchStatement(loc
, condition
, body
, isfinal
);
5353 Expressions cases
; // array of Expression's
5354 Expression
*last
= NULL
;
5359 exp
= parseAssignExp();
5361 if (token
.value
!= TOKcomma
)
5366 /* case exp: .. case last:
5368 if (token
.value
== TOKslice
)
5371 error("only one case allowed for start of case range");
5374 last
= parseAssignExp();
5378 if (flags
& PScurlyscope
)
5380 Statements
*statements
= new Statements();
5381 while (token
.value
!= TOKcase
&&
5382 token
.value
!= TOKdefault
&&
5383 token
.value
!= TOKeof
&&
5384 token
.value
!= TOKrcurly
)
5386 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
5388 s
= new CompoundStatement(loc
, statements
);
5391 s
= parseStatement(PSsemi
| PScurlyscope
);
5392 s
= new ScopeStatement(loc
, s
, token
.loc
);
5396 s
= new CaseRangeStatement(loc
, exp
, last
, s
);
5400 // Keep cases in order by building the case statements backwards
5401 for (size_t i
= cases
.dim
; i
; i
--)
5404 s
= new CaseStatement(loc
, exp
, s
);
5415 if (flags
& PScurlyscope
)
5417 Statements
*statements
= new Statements();
5418 while (token
.value
!= TOKcase
&&
5419 token
.value
!= TOKdefault
&&
5420 token
.value
!= TOKeof
&&
5421 token
.value
!= TOKrcurly
)
5423 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
5425 s
= new CompoundStatement(loc
, statements
);
5428 s
= parseStatement(PSsemi
| PScurlyscope
);
5429 s
= new ScopeStatement(loc
, s
, token
.loc
);
5430 s
= new DefaultStatement(loc
, s
);
5438 if (token
.value
== TOKsemicolon
)
5441 exp
= parseExpression();
5442 check(TOKsemicolon
, "return statement");
5443 s
= new ReturnStatement(loc
, exp
);
5448 { Identifier
*ident
;
5451 if (token
.value
== TOKidentifier
)
5452 { ident
= token
.ident
;
5457 check(TOKsemicolon
, "break statement");
5458 s
= new BreakStatement(loc
, ident
);
5463 { Identifier
*ident
;
5466 if (token
.value
== TOKidentifier
)
5467 { ident
= token
.ident
;
5472 check(TOKsemicolon
, "continue statement");
5473 s
= new ContinueStatement(loc
, ident
);
5478 { Identifier
*ident
;
5481 if (token
.value
== TOKdefault
)
5484 s
= new GotoDefaultStatement(loc
);
5486 else if (token
.value
== TOKcase
)
5488 Expression
*exp
= NULL
;
5491 if (token
.value
!= TOKsemicolon
)
5492 exp
= parseExpression();
5493 s
= new GotoCaseStatement(loc
, exp
);
5497 if (token
.value
!= TOKidentifier
)
5499 error("identifier expected following goto");
5504 ident
= token
.ident
;
5507 s
= new GotoStatement(loc
, ident
);
5509 check(TOKsemicolon
, "goto statement");
5513 case TOKsynchronized
:
5517 Token
*t
= peek(&token
);
5518 if (skipAttributes(t
, &t
) && t
->value
== TOKclass
)
5522 if (token
.value
== TOKlparen
)
5525 exp
= parseExpression();
5530 body
= parseStatement(PSscope
);
5531 s
= new SynchronizedStatement(loc
, exp
, body
);
5541 exp
= parseExpression();
5543 body
= parseStatement(PSscope
);
5544 s
= new WithStatement(loc
, exp
, body
, token
.loc
);
5550 Catches
*catches
= NULL
;
5551 Statement
*finalbody
= NULL
;
5554 Loc lookingForElseSave
= lookingForElse
;
5555 lookingForElse
= Loc();
5556 body
= parseStatement(PSscope
);
5557 lookingForElse
= lookingForElseSave
;
5558 while (token
.value
== TOKcatch
)
5564 Loc catchloc
= token
.loc
;
5567 if (token
.value
== TOKlcurly
|| token
.value
!= TOKlparen
)
5579 handler
= parseStatement(0);
5580 c
= new Catch(catchloc
, t
, id
, handler
);
5582 catches
= new Catches();
5586 if (token
.value
== TOKfinally
)
5589 finalbody
= parseStatement(PSscope
);
5593 if (!catches
&& !finalbody
)
5594 error("catch or finally expected following try");
5597 s
= new TryCatchStatement(loc
, body
, catches
);
5599 s
= new TryFinallyStatement(loc
, s
, finalbody
);
5608 exp
= parseExpression();
5609 check(TOKsemicolon
, "throw statement");
5610 s
= new ThrowStatement(loc
, exp
);
5616 // Parse the asm block into a sequence of AsmStatements,
5617 // each AsmStatement is one instruction.
5618 // Separate out labels.
5619 // Defer parsing of AsmStatements until semantic processing.
5624 StorageClass stc
= parsePostfix(STCundefined
, NULL
);
5625 if (stc
& (STCconst
| STCimmutable
| STCshared
| STCwild
))
5626 error("const/immutable/shared/inout attributes are not allowed on asm blocks");
5629 Token
*toklist
= NULL
;
5630 Token
**ptoklist
= &toklist
;
5631 Identifier
*label
= NULL
;
5632 Statements
*statements
= new Statements();
5633 size_t nestlevel
= 0;
5636 switch (token
.value
)
5641 // Look ahead to see if it is a label
5642 Token
*t
= peek(&token
);
5643 if (t
->value
== TOKcolon
)
5645 label
= token
.ident
;
5646 labelloc
= token
.loc
;
5665 if (toklist
|| label
)
5667 error("asm statements must end in ';'");
5673 error("mismatched number of curly brackets");
5676 if (toklist
|| label
)
5678 // Create AsmStatement from list of tokens we've saved
5679 s
= new AsmStatement(token
.loc
, toklist
);
5681 ptoklist
= &toklist
;
5683 { s
= new LabelStatement(labelloc
, label
, s
);
5686 statements
->push(s
);
5693 error("matching '}' expected, not end of file");
5699 *ptoklist
= Token::alloc();
5700 memcpy(*ptoklist
, &token
, sizeof(Token
));
5701 ptoklist
= &(*ptoklist
)->next
;
5709 s
= new CompoundAsmStatement(loc
, statements
, stc
);
5716 Dsymbols
*imports
= parseImport();
5717 s
= new ImportStatement(loc
, imports
);
5718 if (flags
& PSscope
)
5719 s
= new ScopeStatement(loc
, s
, token
.loc
);
5725 Dsymbol
*d
= parseTemplateDeclaration();
5726 s
= new ExpStatement(loc
, d
);
5731 error("found '%s' instead of statement", token
.toChars());
5735 while (token
.value
!= TOKrcurly
&&
5736 token
.value
!= TOKsemicolon
&&
5737 token
.value
!= TOKeof
)
5739 if (token
.value
== TOKsemicolon
)
5745 *pEndloc
= token
.loc
;
5749 void Parser::check(TOK value
)
5751 check(token
.loc
, value
);
5754 void Parser::check(Loc loc
, TOK value
)
5756 if (token
.value
!= value
)
5757 error(loc
, "found '%s' when expecting '%s'", token
.toChars(), Token::toChars(value
));
5761 void Parser::check(TOK value
, const char *string
)
5763 if (token
.value
!= value
)
5764 error("found '%s' when expecting '%s' following %s",
5765 token
.toChars(), Token::toChars(value
), string
);
5769 void Parser::checkParens(TOK value
, Expression
*e
)
5771 if (precedence
[e
->op
] == PREC_rel
&& !e
->parens
)
5772 error(e
->loc
, "%s must be parenthesized when next to operator %s", e
->toChars(), Token::toChars(value
));
5775 /************************************
5776 * Determine if the scanner is sitting on the start of a declaration.
5778 * needId 0 no identifier
5779 * 1 identifier optional
5780 * 2 must have identifier
5781 * 3 must have identifier, but don't recognize old C-style syntax.
5783 * if *pt is not NULL, it is set to the ending token, which would be endtok
5786 bool Parser::isDeclaration(Token
*t
, int needId
, TOK endtok
, Token
**pt
)
5788 //printf("isDeclaration(needId = %d)\n", needId);
5794 if ((t
->value
== TOKconst
||
5795 t
->value
== TOKimmutable
||
5796 t
->value
== TOKwild
||
5797 t
->value
== TOKshared
) &&
5798 peek(t
)->value
!= TOKlparen
)
5811 if (!isBasicType(&t
))
5815 if (!isDeclarator(&t
, &haveId
, &haveTpl
, endtok
, needId
!= 3))
5817 if (needId
== 1 || (needId
== 0 && !haveId
) || ((needId
== 2 || needId
== 3) && haveId
))
5827 //printf("\tis declaration, t = %s\n", t->toChars());
5831 //printf("\tis not declaration\n");
5835 bool Parser::isBasicType(Token
**pt
)
5837 // This code parallels parseBasicType()
5842 case TOKwchar
: case TOKdchar
:
5843 case TOKbool
: case TOKchar
:
5844 case TOKint8
: case TOKuns8
:
5845 case TOKint16
: case TOKuns16
:
5846 case TOKint32
: case TOKuns32
:
5847 case TOKint64
: case TOKuns64
:
5848 case TOKint128
: case TOKuns128
:
5849 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
5850 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
5851 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
5859 if (t
->value
== TOKnot
)
5869 if (t
->value
== TOKdot
)
5873 if (t
->value
!= TOKidentifier
)
5876 if (t
->value
!= TOKnot
)
5881 * !( args ), !identifier, etc.
5889 if (!skipParens(t
, &t
))
5892 case TOKwchar
: case TOKdchar
:
5893 case TOKbool
: case TOKchar
:
5894 case TOKint8
: case TOKuns8
:
5895 case TOKint16
: case TOKuns16
:
5896 case TOKint32
: case TOKuns32
:
5897 case TOKint64
: case TOKuns64
:
5898 case TOKint128
: case TOKuns128
:
5899 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
5900 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
5901 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
5912 case TOKimaginary32v
:
5913 case TOKimaginary64v
:
5914 case TOKimaginary80v
:
5924 case TOKfilefullpath
:
5926 case TOKmodulestring
:
5944 /* typeof(exp).identifier...
5947 if (!skipParens(t
, &t
))
5955 // const(type) or immutable(type) or shared(type) or wild(type)
5957 if (t
->value
!= TOKlparen
)
5960 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
5975 //printf("is not\n");
5979 bool Parser::isDeclarator(Token
**pt
, int *haveId
, int *haveTpl
, TOK endtok
, bool allowAltSyntax
)
5980 { // This code parallels parseDeclarator()
5984 //printf("Parser::isDeclarator() %s\n", t->toChars());
5985 if (t
->value
== TOKassign
)
6000 if (t
->value
== TOKrbracket
)
6004 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
6006 // It's an associative array declaration
6010 if (t
->value
== TOKdot
&& peek(t
)->value
== TOKidentifier
)
6019 // [ expression .. expression ]
6020 if (!isExpression(&t
))
6022 if (t
->value
== TOKslice
)
6025 if (!isExpression(&t
))
6027 if (t
->value
!= TOKrbracket
)
6033 if (t
->value
!= TOKrbracket
)
6038 if (t
->value
== TOKdot
&& peek(t
)->value
== TOKidentifier
)
6055 if (!allowAltSyntax
)
6056 return false; // Do not recognize C-style declarations.
6060 if (t
->value
== TOKrparen
)
6061 return false; // () is not a declarator
6063 /* Regard ( identifier ) as not a declarator
6064 * BUG: what about ( *identifier ) in
6066 * where f is a class instance with overloaded () ?
6067 * Should we just disallow C-style function pointer declarations?
6069 if (t
->value
== TOKidentifier
)
6070 { Token
*t2
= peek(t
);
6071 if (t2
->value
== TOKrparen
)
6076 if (!isDeclarator(&t
, haveId
, NULL
, TOKrparen
))
6085 if (!isParameters(&t
))
6087 skipAttributes(t
, &t
);
6102 if (t
->value
== TOKrbracket
)
6106 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
6107 { // It's an associative array declaration
6113 if (!isExpression(&t
))
6115 if (t
->value
!= TOKrbracket
)
6124 if (Token
*tk
= peekPastParen(t
))
6126 if (tk
->value
== TOKlparen
)
6128 if (!haveTpl
) return false;
6132 else if (tk
->value
== TOKassign
)
6134 if (!haveTpl
) return false;
6140 if (!isParameters(&t
))
6157 t
= peek(t
); // skip '@'
6158 t
= peek(t
); // skip identifier
6168 if (t
->ident
!= Id::_body
)
6172 // Valid tokens that follow a declaration
6183 // The !parens is to disallow unnecessary parentheses
6184 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
6191 return haveTpl
? true : false;
6202 bool Parser::isParameters(Token
**pt
)
6203 { // This code parallels parseParameters()
6206 //printf("isParameters()\n");
6207 if (t
->value
!= TOKlparen
)
6211 for (;1; t
= peek(t
))
6238 if (t
->value
== TOKlparen
)
6241 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
6243 t
= peek(t
); // skip past closing ')'
6249 { if (!isBasicType(&t
))
6253 if (t
->value
!= TOKdotdotdot
&&
6254 !isDeclarator(&t
, &tmp
, NULL
, TOKreserved
))
6256 if (t
->value
== TOKassign
)
6258 if (!isExpression(&t
))
6261 if (t
->value
== TOKdotdotdot
)
6267 if (t
->value
== TOKcomma
)
6275 if (t
->value
!= TOKrparen
)
6282 bool Parser::isExpression(Token
**pt
)
6284 // This is supposed to determine if something is an expression.
6285 // What it actually does is scan until a closing right bracket
6293 for (;; t
= peek(t
))
6311 if (brnest
|| panest
)
6325 if (--curlynest
>= 0)
6352 /*******************************************
6353 * Skip parens, brackets.
6357 * *pt is set to closing token, which is ')' on success
6360 * false some parsing error
6363 bool Parser::skipParens(Token
*t
, Token
**pt
)
6365 if (t
->value
!= TOKlparen
)
6397 *pt
= peek(t
); // skip found rparen
6404 bool Parser::skipParensIf(Token
*t
, Token
**pt
)
6406 if (t
->value
!= TOKlparen
)
6412 return skipParens(t
, pt
);
6415 /*******************************************
6418 * t is on a candidate attribute
6420 * *pt is set to first non-attribute token on success
6423 * false some parsing error
6426 bool Parser::skipAttributes(Token
*t
, Token
**pt
)
6441 case TOKsynchronized
:
6444 if (peek(t
)->value
== TOKlparen
)
6447 if (!skipParens(t
, &t
))
6449 // t is on the next of closing parenthesis
6462 if (t
->value
== TOKidentifier
)
6466 * @identifier!(arglist)
6467 * any of the above followed by (arglist)
6468 * @predefined_attribute
6470 if (t
->ident
== Id::property
||
6471 t
->ident
== Id::nogc
||
6472 t
->ident
== Id::safe
||
6473 t
->ident
== Id::trusted
||
6474 t
->ident
== Id::system
||
6475 t
->ident
== Id::disable
)
6478 if (t
->value
== TOKnot
)
6481 if (t
->value
== TOKlparen
)
6483 // @identifier!(arglist)
6484 if (!skipParens(t
, &t
))
6486 // t is on the next of closing parenthesis
6491 // Do low rent skipTemplateArgument
6492 if (t
->value
== TOKvector
)
6494 // identifier!__vector(type)
6496 if (!skipParens(t
, &t
))
6503 if (t
->value
== TOKlparen
)
6505 if (!skipParens(t
, &t
))
6507 // t is on the next of closing parenthesis
6512 if (t
->value
== TOKlparen
)
6514 // @( ArgumentList )
6515 if (!skipParens(t
, &t
))
6517 // t is on the next of closing parenthesis
6536 /********************************* Expression Parser ***************************/
6538 Expression
*Parser::parsePrimaryExp()
6543 Loc loc
= token
.loc
;
6545 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
6546 switch (token
.value
)
6550 Token
*t1
= peek(&token
);
6551 Token
*t2
= peek(t1
);
6552 if (t1
->value
== TOKmin
&& t2
->value
== TOKgt
)
6558 error("use `.` for member lookup, not `->`");
6562 if (peekNext() == TOKgoesto
)
6568 if (token
.value
== TOKnot
&& (save
= peekNext()) != TOKis
&& save
!= TOKin
)
6570 // identifier!(template-argument-list)
6571 TemplateInstance
*tempinst
;
6572 tempinst
= new TemplateInstance(loc
, id
);
6573 tempinst
->tiargs
= parseTemplateArguments();
6574 e
= new ScopeExp(loc
, tempinst
);
6577 e
= new IdentifierExp(loc
, id
);
6583 error("'$' is valid only inside [] of index or slice");
6584 e
= new DollarExp(loc
);
6589 // Signal global scope '.' operator with "" identifier
6590 e
= new IdentifierExp(loc
, Id::empty
);
6594 e
= new ThisExp(loc
);
6599 e
= new SuperExp(loc
);
6604 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
6609 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
6614 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
6619 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
6624 e
= new RealExp(loc
, token
.floatvalue
, Type::tfloat32
);
6629 e
= new RealExp(loc
, token
.floatvalue
, Type::tfloat64
);
6634 e
= new RealExp(loc
, token
.floatvalue
, Type::tfloat80
);
6638 case TOKimaginary32v
:
6639 e
= new RealExp(loc
, token
.floatvalue
, Type::timaginary32
);
6643 case TOKimaginary64v
:
6644 e
= new RealExp(loc
, token
.floatvalue
, Type::timaginary64
);
6648 case TOKimaginary80v
:
6649 e
= new RealExp(loc
, token
.floatvalue
, Type::timaginary80
);
6654 e
= new NullExp(loc
);
6660 const char *s
= loc
.filename
? loc
.filename
: mod
->ident
->toChars();
6661 e
= new StringExp(loc
, const_cast<char *>(s
), strlen(s
), 0);
6666 case TOKfilefullpath
:
6668 const char *srcfile
= mod
->srcfile
->name
->toChars();
6670 if (loc
.filename
&& !FileName::equals(loc
.filename
, srcfile
))
6673 s
= FileName::combine(mod
->srcfilePath
, srcfile
);
6674 e
= new StringExp(loc
, const_cast<char *>(s
), strlen(s
), 0);
6680 e
= new IntegerExp(loc
, loc
.linnum
, Type::tint32
);
6684 case TOKmodulestring
:
6686 const char *s
= md
? md
->toChars() : mod
->toChars();
6687 e
= new StringExp(loc
, const_cast<char *>(s
), strlen(s
), 0);
6693 e
= new FuncInitExp(loc
);
6698 e
= new PrettyFuncInitExp(loc
);
6703 e
= new IntegerExp(loc
, 1, Type::tbool
);
6708 e
= new IntegerExp(loc
, 0, Type::tbool
);
6713 e
= new IntegerExp(loc
, (d_uns8
)token
.uns64value
, Type::tchar
);
6718 e
= new IntegerExp(loc
, (d_uns16
)token
.uns64value
, Type::twchar
);
6723 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
6730 // cat adjacent strings
6731 utf8_t
*s
= token
.ustring
;
6732 size_t len
= token
.len
;
6733 unsigned char postfix
= token
.postfix
;
6736 const Token prev
= token
;
6738 if (token
.value
== TOKstring
||
6739 token
.value
== TOKxstring
)
6742 { if (token
.postfix
!= postfix
)
6743 error("mismatched string literal postfixes '%c' and '%c'", postfix
, token
.postfix
);
6744 postfix
= token
.postfix
;
6747 deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
6748 prev
.toChars(), token
.toChars());
6751 size_t len2
= token
.len
;
6753 utf8_t
*s2
= (utf8_t
*)mem
.xmalloc((len
+ 1) * sizeof(utf8_t
));
6754 memcpy(s2
, s
, len1
* sizeof(utf8_t
));
6755 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(utf8_t
));
6761 e
= new StringExp(loc
, s
, len
, postfix
);
6765 case TOKvoid
: t
= Type::tvoid
; goto LabelX
;
6766 case TOKint8
: t
= Type::tint8
; goto LabelX
;
6767 case TOKuns8
: t
= Type::tuns8
; goto LabelX
;
6768 case TOKint16
: t
= Type::tint16
; goto LabelX
;
6769 case TOKuns16
: t
= Type::tuns16
; goto LabelX
;
6770 case TOKint32
: t
= Type::tint32
; goto LabelX
;
6771 case TOKuns32
: t
= Type::tuns32
; goto LabelX
;
6772 case TOKint64
: t
= Type::tint64
; goto LabelX
;
6773 case TOKuns64
: t
= Type::tuns64
; goto LabelX
;
6774 case TOKint128
: t
= Type::tint128
; goto LabelX
;
6775 case TOKuns128
: t
= Type::tuns128
; goto LabelX
;
6776 case TOKfloat32
: t
= Type::tfloat32
; goto LabelX
;
6777 case TOKfloat64
: t
= Type::tfloat64
; goto LabelX
;
6778 case TOKfloat80
: t
= Type::tfloat80
; goto LabelX
;
6779 case TOKimaginary32
: t
= Type::timaginary32
; goto LabelX
;
6780 case TOKimaginary64
: t
= Type::timaginary64
; goto LabelX
;
6781 case TOKimaginary80
: t
= Type::timaginary80
; goto LabelX
;
6782 case TOKcomplex32
: t
= Type::tcomplex32
; goto LabelX
;
6783 case TOKcomplex64
: t
= Type::tcomplex64
; goto LabelX
;
6784 case TOKcomplex80
: t
= Type::tcomplex80
; goto LabelX
;
6785 case TOKbool
: t
= Type::tbool
; goto LabelX
;
6786 case TOKchar
: t
= Type::tchar
; goto LabelX
;
6787 case TOKwchar
: t
= Type::twchar
; goto LabelX
;
6788 case TOKdchar
: t
= Type::tdchar
; goto LabelX
;
6791 if (token
.value
== TOKlparen
)
6793 e
= new TypeExp(loc
, t
);
6794 e
= new CallExp(loc
, e
, parseArguments());
6797 check(TOKdot
, t
->toChars());
6798 if (token
.value
!= TOKidentifier
)
6799 { error("found '%s' when expecting identifier following '%s.'", token
.toChars(), t
->toChars());
6802 e
= typeDotIdExp(loc
, t
, token
.ident
);
6809 e
= new TypeExp(loc
, t
);
6816 e
= new TypeExp(loc
, t
);
6823 check(TOKlparen
, "typeid");
6825 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
6826 { // argument is a type
6830 { // argument is an expression
6831 o
= parseAssignExp();
6834 e
= new TypeidExp(loc
, o
);
6839 { /* __traits(identifier, args...)
6842 Objects
*args
= NULL
;
6846 if (token
.value
!= TOKidentifier
)
6847 { error("__traits(identifier, args...) expected");
6850 ident
= token
.ident
;
6852 if (token
.value
== TOKcomma
)
6853 args
= parseTemplateArgumentList(); // __traits(identifier, args...)
6855 check(TOKrparen
); // __traits(identifier)
6857 e
= new TraitsExp(loc
, ident
, args
);
6864 Identifier
*ident
= NULL
;
6866 TOK tok
= TOKreserved
;
6867 TOK tok2
= TOKreserved
;
6868 TemplateParameters
*tpl
= NULL
;
6871 if (token
.value
== TOKlparen
)
6874 targ
= parseType(&ident
);
6875 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
6879 if (tok
== TOKequal
&&
6880 (token
.value
== TOKstruct
||
6881 token
.value
== TOKunion
||
6882 token
.value
== TOKclass
||
6883 token
.value
== TOKsuper
||
6884 token
.value
== TOKenum
||
6885 token
.value
== TOKinterface
||
6886 token
.value
== TOKargTypes
||
6887 token
.value
== TOKparameters
||
6888 (token
.value
== TOKconst
&& peek(&token
)->value
== TOKrparen
) ||
6889 (token
.value
== TOKimmutable
&& peek(&token
)->value
== TOKrparen
) ||
6890 (token
.value
== TOKshared
&& peek(&token
)->value
== TOKrparen
) ||
6891 (token
.value
== TOKwild
&& peek(&token
)->value
== TOKrparen
) ||
6892 token
.value
== TOKfunction
||
6893 token
.value
== TOKdelegate
||
6894 token
.value
== TOKreturn
||
6895 (token
.value
== TOKvector
&& peek(&token
)->value
== TOKrparen
)))
6902 tspec
= parseType();
6907 if (token
.value
== TOKcomma
)
6908 tpl
= parseTemplateParameterList(1);
6911 tpl
= new TemplateParameters();
6920 error("(type identifier : specialization) expected following is");
6923 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
6928 { Expression
*msg
= NULL
;
6931 check(TOKlparen
, "assert");
6932 e
= parseAssignExp();
6933 if (token
.value
== TOKcomma
)
6936 if (token
.value
!= TOKrparen
)
6938 msg
= parseAssignExp();
6939 if (token
.value
== TOKcomma
)
6944 e
= new AssertExp(loc
, e
, msg
);
6951 check(TOKlparen
, "mixin");
6952 e
= parseAssignExp();
6954 e
= new CompileExp(loc
, e
);
6961 check(TOKlparen
, "import");
6962 e
= parseAssignExp();
6964 e
= new ImportExp(loc
, e
);
6969 e
= parseNewExp(NULL
);
6974 Token
*tk
= peekPastParen(&token
);
6975 if (skipAttributes(tk
, &tk
) &&
6976 (tk
->value
== TOKgoesto
|| tk
->value
== TOKlcurly
))
6978 // (arguments) => expression
6979 // (arguments) { statements... }
6985 e
= parseExpression();
6987 check(loc
, TOKrparen
);
6992 { /* Parse array literals and associative array literals:
6993 * [ value, value, value ... ]
6994 * [ key:value, key:value, key:value ... ]
6996 Expressions
*values
= new Expressions();
6997 Expressions
*keys
= NULL
;
7000 while (token
.value
!= TOKrbracket
&& token
.value
!= TOKeof
)
7002 e
= parseAssignExp();
7003 if (token
.value
== TOKcolon
&& (keys
|| values
->dim
== 0))
7006 keys
= new Expressions();
7008 e
= parseAssignExp();
7011 { error("'key:value' expected for associative array literal");
7016 if (token
.value
== TOKrbracket
)
7020 check(loc
, TOKrbracket
);
7023 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
7025 e
= new ArrayLiteralExp(loc
, values
);
7034 Dsymbol
*s
= parseFunctionLiteral();
7035 e
= new FuncExp(loc
, s
);
7040 error("expression expected, not '%s'", token
.toChars());
7042 // Anything for e, as long as it's not NULL
7043 e
= new IntegerExp(loc
, 0, Type::tint32
);
7050 Expression
*Parser::parsePostExp(Expression
*e
)
7057 switch (token
.value
)
7061 if (token
.value
== TOKidentifier
)
7062 { Identifier
*id
= token
.ident
;
7065 if (token
.value
== TOKnot
&& peekNext() != TOKis
&& peekNext() != TOKin
)
7067 Objects
*tiargs
= parseTemplateArguments();
7068 e
= new DotTemplateInstanceExp(loc
, e
, id
, tiargs
);
7071 e
= new DotIdExp(loc
, e
, id
);
7074 else if (token
.value
== TOKnew
)
7080 error("identifier expected following '.', not '%s'", token
.toChars());
7084 e
= new PostExp(TOKplusplus
, loc
, e
);
7088 e
= new PostExp(TOKminusminus
, loc
, e
);
7092 e
= new CallExp(loc
, e
, parseArguments());
7096 { // array dereferences:
7099 // array[lwr .. upr]
7102 Expressions
*arguments
= new Expressions();
7106 while (token
.value
!= TOKrbracket
&& token
.value
!= TOKeof
)
7108 index
= parseAssignExp();
7109 if (token
.value
== TOKslice
)
7111 // array[..., lwr..upr, ...]
7113 upr
= parseAssignExp();
7114 arguments
->push(new IntervalExp(loc
, index
, upr
));
7117 arguments
->push(index
);
7118 if (token
.value
== TOKrbracket
)
7124 e
= new ArrayExp(loc
, e
, arguments
);
7135 Expression
*Parser::parseUnaryExp()
7138 Loc loc
= token
.loc
;
7140 switch (token
.value
)
7144 e
= parseUnaryExp();
7145 e
= new AddrExp(loc
, e
);
7150 e
= parseUnaryExp();
7151 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7152 e
= new PreExp(TOKpreplusplus
, loc
, e
);
7157 e
= parseUnaryExp();
7158 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7159 e
= new PreExp(TOKpreminusminus
, loc
, e
);
7164 e
= parseUnaryExp();
7165 e
= new PtrExp(loc
, e
);
7170 e
= parseUnaryExp();
7171 e
= new NegExp(loc
, e
);
7176 e
= parseUnaryExp();
7177 e
= new UAddExp(loc
, e
);
7182 e
= parseUnaryExp();
7183 e
= new NotExp(loc
, e
);
7188 e
= parseUnaryExp();
7189 e
= new ComExp(loc
, e
);
7194 e
= parseUnaryExp();
7195 e
= new DeleteExp(loc
, e
, false);
7198 case TOKcast
: // cast(type) expression
7202 /* Look for cast(), cast(const), cast(immutable),
7203 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
7205 unsigned char m
= 0;
7208 switch (token
.value
)
7211 if (peekNext() == TOKlparen
)
7212 break; // const as type constructor
7213 m
|= MODconst
; // const as storage class
7218 if (peekNext() == TOKlparen
)
7225 if (peekNext() == TOKlparen
)
7232 if (peekNext() == TOKlparen
)
7243 if (token
.value
== TOKrparen
)
7246 e
= parseUnaryExp();
7247 e
= new CastExp(loc
, e
, m
);
7251 Type
*t
= parseType(); // cast( type )
7252 t
= t
->addMod(m
); // cast( const type )
7254 e
= parseUnaryExp();
7255 e
= new CastExp(loc
, e
, t
);
7263 case TOKimmutable
: // immutable(type)(arguments) / immutable(type).init
7265 StorageClass stc
= parseTypeCtor();
7266 Type
*t
= parseBasicType();
7268 e
= new TypeExp(loc
, t
);
7269 if (stc
== 0 && token
.value
== TOKdot
)
7272 if (token
.value
!= TOKidentifier
)
7274 error("identifier expected following (type).");
7277 e
= typeDotIdExp(loc
, t
, token
.ident
);
7279 e
= parsePostExp(e
);
7282 else if (token
.value
!= TOKlparen
)
7284 error("(arguments) expected following %s", t
->toChars());
7287 e
= new CallExp(loc
, e
, parseArguments());
7298 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
7300 tk
= peek(tk
); // skip over right parenthesis
7305 if (tk
->value
== TOKis
|| tk
->value
== TOKin
) // !is or !in
7327 case TOKimaginary32v
:
7328 case TOKimaginary64v
:
7329 case TOKimaginary80v
:
7342 case TOKfilefullpath
:
7344 case TOKmodulestring
:
7347 case TOKwchar
: case TOKdchar
:
7348 case TOKbool
: case TOKchar
:
7349 case TOKint8
: case TOKuns8
:
7350 case TOKint16
: case TOKuns16
:
7351 case TOKint32
: case TOKuns32
:
7352 case TOKint64
: case TOKuns64
:
7353 case TOKint128
: case TOKuns128
:
7354 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
7355 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
7356 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
7366 // or .identifier!( ... )
7367 if (token
.value
== TOKdot
)
7369 if (peekNext() != TOKidentifier
&& peekNext() != TOKnew
)
7371 error("identifier or new keyword expected following (...).");
7374 e
= new TypeExp(loc
, t
);
7375 e
= parsePostExp(e
);
7379 e
= parseUnaryExp();
7380 e
= new CastExp(loc
, e
, t
);
7381 error("C style cast illegal, use %s", e
->toChars());
7390 e
= parsePrimaryExp();
7391 e
= parsePostExp(e
);
7395 e
= parsePrimaryExp();
7396 e
= parsePostExp(e
);
7401 // ^^ is right associative and has higher precedence than the unary operators
7402 while (token
.value
== TOKpow
)
7405 Expression
*e2
= parseUnaryExp();
7406 e
= new PowExp(loc
, e
, e2
);
7412 Expression
*Parser::parseMulExp()
7416 Loc loc
= token
.loc
;
7418 e
= parseUnaryExp();
7421 switch (token
.value
)
7423 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
7424 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
7425 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
7435 Expression
*Parser::parseAddExp()
7439 Loc loc
= token
.loc
;
7444 switch (token
.value
)
7446 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
7447 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
7448 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
7458 Expression
*Parser::parseShiftExp()
7462 Loc loc
= token
.loc
;
7467 switch (token
.value
)
7469 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
7470 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
7471 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
7481 Expression
*Parser::parseCmpExp()
7486 Loc loc
= token
.loc
;
7488 e
= parseShiftExp();
7489 TOK op
= token
.value
;
7496 e2
= parseShiftExp();
7497 e
= new EqualExp(op
, loc
, e
, e2
);
7505 // Attempt to identify '!is'
7507 if (t
->value
== TOKin
)
7511 e2
= parseShiftExp();
7512 e
= new InExp(loc
, e
, e2
);
7513 e
= new NotExp(loc
, e
);
7516 if (t
->value
!= TOKis
)
7519 op
= TOKnotidentity
;
7524 e2
= parseShiftExp();
7525 e
= new IdentityExp(op
, loc
, e
, e2
);
7541 e2
= parseShiftExp();
7542 e
= new CmpExp(op
, loc
, e
, e2
);
7547 e2
= parseShiftExp();
7548 e
= new InExp(loc
, e
, e2
);
7557 Expression
*Parser::parseAndExp()
7559 Loc loc
= token
.loc
;
7561 Expression
*e
= parseCmpExp();
7562 while (token
.value
== TOKand
)
7564 checkParens(TOKand
, e
);
7566 Expression
*e2
= parseCmpExp();
7567 checkParens(TOKand
, e2
);
7568 e
= new AndExp(loc
,e
,e2
);
7574 Expression
*Parser::parseXorExp()
7576 Loc loc
= token
.loc
;
7578 Expression
*e
= parseAndExp();
7579 while (token
.value
== TOKxor
)
7581 checkParens(TOKxor
, e
);
7583 Expression
*e2
= parseAndExp();
7584 checkParens(TOKxor
, e2
);
7585 e
= new XorExp(loc
, e
, e2
);
7590 Expression
*Parser::parseOrExp()
7592 Loc loc
= token
.loc
;
7594 Expression
*e
= parseXorExp();
7595 while (token
.value
== TOKor
)
7597 checkParens(TOKor
, e
);
7599 Expression
*e2
= parseXorExp();
7600 checkParens(TOKor
, e2
);
7601 e
= new OrExp(loc
, e
, e2
);
7606 Expression
*Parser::parseAndAndExp()
7610 Loc loc
= token
.loc
;
7613 while (token
.value
== TOKandand
)
7617 e
= new AndAndExp(loc
, e
, e2
);
7622 Expression
*Parser::parseOrOrExp()
7626 Loc loc
= token
.loc
;
7628 e
= parseAndAndExp();
7629 while (token
.value
== TOKoror
)
7632 e2
= parseAndAndExp();
7633 e
= new OrOrExp(loc
, e
, e2
);
7638 Expression
*Parser::parseCondExp()
7643 Loc loc
= token
.loc
;
7646 if (token
.value
== TOKquestion
)
7649 e1
= parseExpression();
7651 e2
= parseCondExp();
7652 e
= new CondExp(loc
, e
, e1
, e2
);
7657 Expression
*Parser::parseAssignExp()
7667 switch (token
.value
)
7669 case TOKassign
: nextToken(); e2
= parseAssignExp(); e
= new AssignExp(loc
,e
,e2
); continue;
7670 case TOKaddass
: nextToken(); e2
= parseAssignExp(); e
= new AddAssignExp(loc
,e
,e2
); continue;
7671 case TOKminass
: nextToken(); e2
= parseAssignExp(); e
= new MinAssignExp(loc
,e
,e2
); continue;
7672 case TOKmulass
: nextToken(); e2
= parseAssignExp(); e
= new MulAssignExp(loc
,e
,e2
); continue;
7673 case TOKdivass
: nextToken(); e2
= parseAssignExp(); e
= new DivAssignExp(loc
,e
,e2
); continue;
7674 case TOKmodass
: nextToken(); e2
= parseAssignExp(); e
= new ModAssignExp(loc
,e
,e2
); continue;
7675 case TOKpowass
: nextToken(); e2
= parseAssignExp(); e
= new PowAssignExp(loc
,e
,e2
); continue;
7676 case TOKandass
: nextToken(); e2
= parseAssignExp(); e
= new AndAssignExp(loc
,e
,e2
); continue;
7677 case TOKorass
: nextToken(); e2
= parseAssignExp(); e
= new OrAssignExp(loc
,e
,e2
); continue;
7678 case TOKxorass
: nextToken(); e2
= parseAssignExp(); e
= new XorAssignExp(loc
,e
,e2
); continue;
7679 case TOKshlass
: nextToken(); e2
= parseAssignExp(); e
= new ShlAssignExp(loc
,e
,e2
); continue;
7680 case TOKshrass
: nextToken(); e2
= parseAssignExp(); e
= new ShrAssignExp(loc
,e
,e2
); continue;
7681 case TOKushrass
: nextToken(); e2
= parseAssignExp(); e
= new UshrAssignExp(loc
,e
,e2
); continue;
7682 case TOKcatass
: nextToken(); e2
= parseAssignExp(); e
= new CatAssignExp(loc
,e
,e2
); continue;
7691 Expression
*Parser::parseExpression()
7695 Loc loc
= token
.loc
;
7697 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
7698 e
= parseAssignExp();
7699 while (token
.value
== TOKcomma
)
7702 e2
= parseAssignExp();
7703 e
= new CommaExp(loc
, e
, e2
, false);
7710 /*************************
7711 * Collect argument list.
7712 * Assume current token is ',', '(' or '['.
7715 Expressions
*Parser::parseArguments()
7717 Expressions
*arguments
;
7721 arguments
= new Expressions();
7722 if (token
.value
== TOKlbracket
)
7723 endtok
= TOKrbracket
;
7729 while (token
.value
!= endtok
&& token
.value
!= TOKeof
)
7731 arg
= parseAssignExp();
7732 arguments
->push(arg
);
7733 if (token
.value
== endtok
)
7742 /*******************************************
7745 Expression
*Parser::parseNewExp(Expression
*thisexp
)
7748 Expressions
*newargs
;
7749 Expressions
*arguments
= NULL
;
7750 Loc loc
= token
.loc
;
7754 if (token
.value
== TOKlparen
)
7756 newargs
= parseArguments();
7759 // An anonymous nested class starts with "class"
7760 if (token
.value
== TOKclass
)
7763 if (token
.value
== TOKlparen
)
7764 arguments
= parseArguments();
7766 BaseClasses
*baseclasses
= NULL
;
7767 if (token
.value
!= TOKlcurly
)
7768 baseclasses
= parseBaseClasses();
7770 Identifier
*id
= NULL
;
7771 Dsymbols
*members
= NULL
;
7773 if (token
.value
!= TOKlcurly
)
7775 error("{ members } expected for anonymous class");
7780 members
= parseDeclDefs(0);
7781 if (token
.value
!= TOKrcurly
)
7782 error("class member expected");
7786 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
, members
, false);
7787 Expression
*e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
7792 StorageClass stc
= parseTypeCtor();
7793 t
= parseBasicType(true);
7794 t
= parseBasicType2(t
);
7796 if (t
->ty
== Taarray
)
7798 TypeAArray
*taa
= (TypeAArray
*)t
;
7799 Type
*index
= taa
->index
;
7801 Expression
*edim
= typeToExpression(index
);
7804 error("need size of rightmost array, not type %s", index
->toChars());
7805 return new NullExp(loc
);
7807 t
= new TypeSArray(taa
->next
, edim
);
7809 else if (t
->ty
== Tsarray
)
7812 else if (token
.value
== TOKlparen
)
7814 arguments
= parseArguments();
7816 Expression
*e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
7820 /**********************************************
7823 void Parser::addComment(Dsymbol
*s
, const utf8_t
*blockComment
)
7825 s
->addComment(combineComments(blockComment
, token
.lineComment
));
7826 token
.lineComment
= NULL
;
7830 /**********************************
7831 * Set operator precedence for each operator.
7834 PREC precedence
[TOKMAX
];
7836 struct PrecedenceInitializer
7838 PrecedenceInitializer();
7841 static PrecedenceInitializer precedenceinitializer
;
7843 PrecedenceInitializer::PrecedenceInitializer()
7845 for (size_t i
= 0; i
< TOKMAX
; i
++)
7846 precedence
[i
] = PREC_zero
;
7848 precedence
[TOKtype
] = PREC_expr
;
7849 precedence
[TOKerror
] = PREC_expr
;
7851 precedence
[TOKtypeof
] = PREC_primary
;
7852 precedence
[TOKmixin
] = PREC_primary
;
7853 precedence
[TOKimport
] = PREC_primary
;
7855 precedence
[TOKdotvar
] = PREC_primary
;
7856 precedence
[TOKscope
] = PREC_primary
;
7857 precedence
[TOKidentifier
] = PREC_primary
;
7858 precedence
[TOKthis
] = PREC_primary
;
7859 precedence
[TOKsuper
] = PREC_primary
;
7860 precedence
[TOKint64
] = PREC_primary
;
7861 precedence
[TOKfloat64
] = PREC_primary
;
7862 precedence
[TOKcomplex80
] = PREC_primary
;
7863 precedence
[TOKnull
] = PREC_primary
;
7864 precedence
[TOKstring
] = PREC_primary
;
7865 precedence
[TOKarrayliteral
] = PREC_primary
;
7866 precedence
[TOKassocarrayliteral
] = PREC_primary
;
7867 precedence
[TOKclassreference
] = PREC_primary
;
7868 precedence
[TOKfile
] = PREC_primary
;
7869 precedence
[TOKfilefullpath
] = PREC_primary
;
7870 precedence
[TOKline
] = PREC_primary
;
7871 precedence
[TOKmodulestring
] = PREC_primary
;
7872 precedence
[TOKfuncstring
] = PREC_primary
;
7873 precedence
[TOKprettyfunc
] = PREC_primary
;
7874 precedence
[TOKtypeid
] = PREC_primary
;
7875 precedence
[TOKis
] = PREC_primary
;
7876 precedence
[TOKassert
] = PREC_primary
;
7877 precedence
[TOKhalt
] = PREC_primary
;
7878 precedence
[TOKtemplate
] = PREC_primary
;
7879 precedence
[TOKdsymbol
] = PREC_primary
;
7880 precedence
[TOKfunction
] = PREC_primary
;
7881 precedence
[TOKvar
] = PREC_primary
;
7882 precedence
[TOKsymoff
] = PREC_primary
;
7883 precedence
[TOKstructliteral
] = PREC_primary
;
7884 precedence
[TOKarraylength
] = PREC_primary
;
7885 precedence
[TOKdelegateptr
] = PREC_primary
;
7886 precedence
[TOKdelegatefuncptr
] = PREC_primary
;
7887 precedence
[TOKremove
] = PREC_primary
;
7888 precedence
[TOKtuple
] = PREC_primary
;
7889 precedence
[TOKtraits
] = PREC_primary
;
7890 precedence
[TOKdefault
] = PREC_primary
;
7891 precedence
[TOKoverloadset
] = PREC_primary
;
7892 precedence
[TOKvoid
] = PREC_primary
;
7895 precedence
[TOKdotti
] = PREC_primary
;
7896 precedence
[TOKdotid
] = PREC_primary
;
7897 precedence
[TOKdottd
] = PREC_primary
;
7898 precedence
[TOKdot
] = PREC_primary
;
7899 precedence
[TOKdottype
] = PREC_primary
;
7900 // precedence[TOKarrow] = PREC_primary;
7901 precedence
[TOKplusplus
] = PREC_primary
;
7902 precedence
[TOKminusminus
] = PREC_primary
;
7903 precedence
[TOKpreplusplus
] = PREC_primary
;
7904 precedence
[TOKpreminusminus
] = PREC_primary
;
7905 precedence
[TOKcall
] = PREC_primary
;
7906 precedence
[TOKslice
] = PREC_primary
;
7907 precedence
[TOKarray
] = PREC_primary
;
7908 precedence
[TOKindex
] = PREC_primary
;
7910 precedence
[TOKdelegate
] = PREC_unary
;
7911 precedence
[TOKaddress
] = PREC_unary
;
7912 precedence
[TOKstar
] = PREC_unary
;
7913 precedence
[TOKneg
] = PREC_unary
;
7914 precedence
[TOKuadd
] = PREC_unary
;
7915 precedence
[TOKnot
] = PREC_unary
;
7916 precedence
[TOKtilde
] = PREC_unary
;
7917 precedence
[TOKdelete
] = PREC_unary
;
7918 precedence
[TOKnew
] = PREC_unary
;
7919 precedence
[TOKnewanonclass
] = PREC_unary
;
7920 precedence
[TOKcast
] = PREC_unary
;
7922 precedence
[TOKvector
] = PREC_unary
;
7923 precedence
[TOKpow
] = PREC_pow
;
7925 precedence
[TOKmul
] = PREC_mul
;
7926 precedence
[TOKdiv
] = PREC_mul
;
7927 precedence
[TOKmod
] = PREC_mul
;
7929 precedence
[TOKadd
] = PREC_add
;
7930 precedence
[TOKmin
] = PREC_add
;
7931 precedence
[TOKcat
] = PREC_add
;
7933 precedence
[TOKshl
] = PREC_shift
;
7934 precedence
[TOKshr
] = PREC_shift
;
7935 precedence
[TOKushr
] = PREC_shift
;
7937 precedence
[TOKlt
] = PREC_rel
;
7938 precedence
[TOKle
] = PREC_rel
;
7939 precedence
[TOKgt
] = PREC_rel
;
7940 precedence
[TOKge
] = PREC_rel
;
7941 precedence
[TOKunord
] = PREC_rel
;
7942 precedence
[TOKlg
] = PREC_rel
;
7943 precedence
[TOKleg
] = PREC_rel
;
7944 precedence
[TOKule
] = PREC_rel
;
7945 precedence
[TOKul
] = PREC_rel
;
7946 precedence
[TOKuge
] = PREC_rel
;
7947 precedence
[TOKug
] = PREC_rel
;
7948 precedence
[TOKue
] = PREC_rel
;
7949 precedence
[TOKin
] = PREC_rel
;
7951 /* Note that we changed precedence, so that < and != have the same
7952 * precedence. This change is in the parser, too.
7954 precedence
[TOKequal
] = PREC_rel
;
7955 precedence
[TOKnotequal
] = PREC_rel
;
7956 precedence
[TOKidentity
] = PREC_rel
;
7957 precedence
[TOKnotidentity
] = PREC_rel
;
7959 precedence
[TOKand
] = PREC_and
;
7961 precedence
[TOKxor
] = PREC_xor
;
7963 precedence
[TOKor
] = PREC_or
;
7965 precedence
[TOKandand
] = PREC_andand
;
7967 precedence
[TOKoror
] = PREC_oror
;
7969 precedence
[TOKquestion
] = PREC_cond
;
7971 precedence
[TOKassign
] = PREC_assign
;
7972 precedence
[TOKconstruct
] = PREC_assign
;
7973 precedence
[TOKblit
] = PREC_assign
;
7974 precedence
[TOKaddass
] = PREC_assign
;
7975 precedence
[TOKminass
] = PREC_assign
;
7976 precedence
[TOKcatass
] = PREC_assign
;
7977 precedence
[TOKmulass
] = PREC_assign
;
7978 precedence
[TOKdivass
] = PREC_assign
;
7979 precedence
[TOKmodass
] = PREC_assign
;
7980 precedence
[TOKpowass
] = PREC_assign
;
7981 precedence
[TOKshlass
] = PREC_assign
;
7982 precedence
[TOKshrass
] = PREC_assign
;
7983 precedence
[TOKushrass
] = PREC_assign
;
7984 precedence
[TOKandass
] = PREC_assign
;
7985 precedence
[TOKorass
] = PREC_assign
;
7986 precedence
[TOKxorass
] = PREC_assign
;
7988 precedence
[TOKcomma
] = PREC_expr
;
7989 precedence
[TOKdeclaration
] = PREC_expr
;
7991 precedence
[TOKinterval
] = PREC_assign
;