2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, September 2007
28 #include "staticassert.h"
29 #include "expression.h"
30 #include "statement.h"
34 #include "declaration.h"
35 #include "aggregate.h"
40 #include "d-dmd-gcc.h"
43 // How multiple declarations are parsed.
52 // Support C cast syntax:
56 // Support postfix C array declarations, such as
61 Parser::Parser(Module
*module
, unsigned char *base
, unsigned length
, int doDocComment
)
62 : Lexer(module
, base
, 0, length
, doDocComment
, 0)
64 //printf("Parser::Parser()\n");
69 //nextToken(); // start up the scanner
72 Array
*Parser::parseModule()
76 // ModuleDeclation leads off
77 if (token
.value
== TOKmodule
)
79 unsigned char *comment
= token
.blockComment
;
82 if (token
.value
!= TOKidentifier
)
83 { error("Identifier expected following module");
92 while (nextToken() == TOKdot
)
98 if (token
.value
!= TOKidentifier
)
99 { error("Identifier expected following package");
105 md
= new ModuleDeclaration(a
, id
);
107 if (token
.value
!= TOKsemicolon
)
108 error("';' expected following module declaration instead of %s", token
.toChars());
110 addComment(mod
, comment
);
114 decldefs
= parseDeclDefs(0);
115 if (token
.value
!= TOKeof
)
116 { error("unrecognized declaration");
122 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
128 Array
*Parser::parseDeclDefs(int once
)
135 unsigned storageClass
;
136 Condition
*condition
;
137 unsigned char *comment
;
139 //printf("Parser::parseDeclDefs()\n");
140 decldefs
= new Array();
143 comment
= token
.blockComment
;
148 { /* Determine if this is a manifest constant declaration,
149 * or a conventional enum.
151 Token
*t
= peek(&token
);
152 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
154 else if (t
->value
!= TOKidentifier
)
159 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
160 t
->value
== TOKsemicolon
)
172 s
= parseAggregate();
176 s
= parseImport(decldefs
, 0);
180 s
= (Dsymbol
*)parseTemplateDeclaration();
184 { Loc loc
= this->loc
;
185 if (peek(&token
)->value
== TOKlparen
)
188 check(TOKlparen
, "mixin");
189 Expression
*e
= parseAssignExp();
192 s
= new CompileDeclaration(loc
, e
);
206 a
= parseDeclarations();
225 if (t
->value
== TOKlparen
)
227 if (peek(t
)->value
== TOKrparen
)
228 // invariant() forms start of class invariant
229 s
= parseInvariant();
260 if (token
.value
== TOKthis
)
261 s
= parseStaticCtor();
262 else if (token
.value
== TOKtilde
)
263 s
= parseStaticDtor();
264 else if (token
.value
== TOKassert
)
265 s
= parseStaticAssert();
266 else if (token
.value
== TOKif
)
267 { condition
= parseStaticIfCondition();
270 if (token
.value
== TOKelse
)
272 aelse
= parseBlock();
274 s
= new StaticIfDeclaration(condition
, a
, aelse
);
277 else if (token
.value
== TOKimport
)
279 s
= parseImport(decldefs
, 1);
288 if (peek(&token
)->value
== TOKlparen
)
293 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
294 case TOKauto
: stc
= STCauto
; goto Lstc
;
295 case TOKscope
: stc
= STCscope
; goto Lstc
;
296 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
297 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
298 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
299 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
300 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
301 case TOKpure
: stc
= STCpure
; goto Lstc
;
302 case TOKtls
: stc
= STCtls
; goto Lstc
;
303 //case TOKmanifest: stc = STCmanifest; goto Lstc;
306 if (storageClass
& stc
)
307 error("redundant storage class %s", Token::toChars(token
.value
));
309 unsigned u
= storageClass
| stc
;
310 u
&= STCconst
| STCinvariant
| STCmanifest
;
312 error("conflicting storage class %s", Token::toChars(token
.value
));
321 // If followed by a (, it is not a storage class
322 if (peek(&token
)->value
== TOKlparen
)
324 if (token
.value
== TOKconst
)
329 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
330 case TOKauto
: stc
= STCauto
; goto Lstc
;
331 case TOKscope
: stc
= STCscope
; goto Lstc
;
332 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
333 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
334 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
335 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
336 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
337 case TOKpure
: stc
= STCpure
; goto Lstc
;
338 case TOKtls
: stc
= STCtls
; goto Lstc
;
339 //case TOKmanifest: stc = STCmanifest; goto Lstc;
344 /* Look for auto initializers:
345 * storage_class identifier = initializer;
347 if (token
.value
== TOKidentifier
&&
348 peek(&token
)->value
== TOKassign
)
352 Identifier
*ident
= token
.ident
;
355 Initializer
*init
= parseInitializer();
356 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
357 v
->storage_class
= storageClass
;
359 if (token
.value
== TOKsemicolon
)
363 else if (token
.value
== TOKcomma
)
366 if (token
.value
== TOKidentifier
&&
367 peek(&token
)->value
== TOKassign
)
370 addComment(s
, comment
);
374 error("Identifier expected following comma");
377 error("semicolon expected following auto declaration, not '%s'", token
.toChars());
383 s
= new StorageClassDeclaration(storageClass
, a
);
388 if (peek(&token
)->value
!= TOKlparen
)
393 enum LINK linksave
= linkage
;
394 linkage
= parseLinkage();
396 s
= new LinkDeclaration(linkage
, a
);
400 case TOKprivate
: prot
= PROTprivate
; goto Lprot
;
401 case TOKpackage
: prot
= PROTpackage
; goto Lprot
;
402 case TOKprotected
: prot
= PROTprotected
; goto Lprot
;
403 case TOKpublic
: prot
= PROTpublic
; goto Lprot
;
404 case TOKexport
: prot
= PROTexport
; goto Lprot
;
415 error("redundant protection attribute");
419 s
= new ProtDeclaration(prot
, a
);
427 if (token
.value
== TOKlparen
)
430 if (token
.value
== TOKint32v
)
431 n
= (unsigned)token
.uns64value
;
433 { error("integer expected, not %s", token
.toChars());
440 n
= global
.structalign
; // default
443 s
= new AlignDeclaration(n
, a
);
449 Expressions
*args
= NULL
;
453 if (token
.value
!= TOKidentifier
)
454 { error("pragma(identifier expected");
459 if (token
.value
== TOKcomma
)
460 args
= parseArguments(); // pragma(identifier, args...)
462 check(TOKrparen
); // pragma(identifier)
464 if (token
.value
== TOKsemicolon
)
468 s
= new PragmaDeclaration(loc
, ident
, args
, a
);
474 if (token
.value
== TOKassign
)
477 if (token
.value
== TOKidentifier
)
478 s
= new DebugSymbol(loc
, token
.ident
);
479 else if (token
.value
== TOKint32v
)
480 s
= new DebugSymbol(loc
, (unsigned)token
.uns64value
);
482 { error("identifier or integer expected, not %s", token
.toChars());
486 if (token
.value
!= TOKsemicolon
)
487 error("semicolon expected");
492 condition
= parseDebugCondition();
497 if (token
.value
== TOKassign
)
500 if (token
.value
== TOKidentifier
)
501 s
= new VersionSymbol(loc
, token
.ident
);
502 else if (token
.value
== TOKint32v
)
503 s
= new VersionSymbol(loc
, (unsigned)token
.uns64value
);
505 { error("identifier or integer expected, not %s", token
.toChars());
509 if (token
.value
!= TOKsemicolon
)
510 error("semicolon expected");
514 condition
= parseVersionCondition();
520 if (token
.value
== TOKelse
)
522 aelse
= parseBlock();
524 s
= new ConditionalDeclaration(condition
, a
, aelse
);
527 case TOKsemicolon
: // empty declaration
532 error("Declaration expected, not '%s'",token
.toChars());
534 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
542 addComment(s
, comment
);
549 /********************************************
550 * Parse declarations after an align, protection, or extern decl.
553 Array
*Parser::parseBlock()
558 //printf("parseBlock()\n");
562 error("declaration expected following attribute, not ';'");
568 a
= parseDeclDefs(0);
569 if (token
.value
!= TOKrcurly
)
571 error("matching '}' expected, not %s", token
.toChars());
582 a
= parseDeclDefs(0); // grab declarations up to closing curly bracket
587 a
= parseDeclDefs(1);
593 /**********************************
594 * Parse a static assertion.
597 StaticAssert
*Parser::parseStaticAssert()
601 Expression
*msg
= NULL
;
603 //printf("parseStaticAssert()\n");
606 exp
= parseAssignExp();
607 if (token
.value
== TOKcomma
)
609 msg
= parseAssignExp();
613 return new StaticAssert(loc
, exp
, msg
);
616 /***********************************
617 * Parse typeof(expression).
618 * Current token is on the 'typeof'.
621 TypeQualified
*Parser::parseTypeof()
627 if (token
.value
== TOKreturn
) // typeof(return)
630 t
= new TypeReturn(loc
);
633 { Expression
*exp
= parseExpression(); // typeof(expression)
634 t
= new TypeTypeof(loc
, exp
);
640 /***********************************
641 * Parse extern (linkage)
642 * The parser is on the 'extern' token.
645 enum LINK
Parser::parseLinkage()
647 enum LINK link
= LINKdefault
;
649 assert(token
.value
== TOKlparen
);
651 if (token
.value
== TOKidentifier
)
652 { Identifier
*id
= token
.ident
;
655 if (id
== Id::Windows
)
657 else if (id
== Id::Pascal
)
659 else if (id
== Id::D
)
661 else if (id
== Id::C
)
664 if (token
.value
== TOKplusplus
)
669 else if (id
== Id::System
)
672 link
= d_gcc_is_target_win32() ? LINKwindows
: LINKc
;
683 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
689 link
= LINKd
; // default
695 /**************************************
696 * Parse a debug conditional
699 Condition
*Parser::parseDebugCondition()
703 if (token
.value
== TOKlparen
)
707 Identifier
*id
= NULL
;
709 if (token
.value
== TOKidentifier
)
711 else if (token
.value
== TOKint32v
)
712 level
= (unsigned)token
.uns64value
;
714 error("identifier or integer expected, not %s", token
.toChars());
717 c
= new DebugCondition(mod
, level
, id
);
720 c
= new DebugCondition(mod
, 1, NULL
);
725 /**************************************
726 * Parse a version conditional
729 Condition
*Parser::parseVersionCondition()
733 Identifier
*id
= NULL
;
735 if (token
.value
== TOKlparen
)
738 if (token
.value
== TOKidentifier
)
740 else if (token
.value
== TOKint32v
)
741 level
= (unsigned)token
.uns64value
;
745 * even though unittest is a keyword
747 else if (token
.value
== TOKunittest
)
748 id
= Lexer::idPool(Token::toChars(TOKunittest
));
751 error("identifier or integer expected, not %s", token
.toChars());
757 error("(condition) expected following version");
758 c
= new VersionCondition(mod
, level
, id
);
763 /***********************************************
764 * static if (expression)
770 Condition
*Parser::parseStaticIfCondition()
772 Condition
*condition
;
778 if (token
.value
== TOKlparen
)
781 exp
= parseAssignExp();
785 { error("(expression) expected following static if");
788 condition
= new StaticIfCondition(loc
, exp
);
793 /*****************************************
794 * Parse a constructor definition:
795 * this(arguments) { body }
797 * this(this) { body }
798 * Current token is 'this'.
801 FuncDeclaration
*Parser::parseCtor()
806 if (token
.value
== TOKlparen
&& peek(&token
)->value
== TOKthis
)
807 { // this(this) { ... }
811 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, 0);
816 Arguments
*arguments
= parseParameters(&varargs
);
817 CtorDeclaration
*f
= new CtorDeclaration(loc
, 0, arguments
, varargs
);
822 /*****************************************
823 * Parse a postblit definition:
825 * Current token is '='.
828 PostBlitDeclaration
*Parser::parsePostBlit()
837 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, 0);
842 /*****************************************
843 * Parse a destructor definition:
845 * Current token is '~'.
848 DtorDeclaration
*Parser::parseDtor()
858 f
= new DtorDeclaration(loc
, 0);
863 /*****************************************
864 * Parse a static constructor definition:
865 * static this() { body }
866 * Current token is 'this'.
869 StaticCtorDeclaration
*Parser::parseStaticCtor()
871 StaticCtorDeclaration
*f
;
878 f
= new StaticCtorDeclaration(loc
, 0);
883 /*****************************************
884 * Parse a static destructor definition:
885 * static ~this() { body }
886 * Current token is '~'.
889 StaticDtorDeclaration
*Parser::parseStaticDtor()
891 StaticDtorDeclaration
*f
;
899 f
= new StaticDtorDeclaration(loc
, 0);
904 /*****************************************
905 * Parse an invariant definition:
907 * Current token is 'invariant'.
910 InvariantDeclaration
*Parser::parseInvariant()
912 InvariantDeclaration
*f
;
918 if (token
.value
== TOKlparen
)
923 f
= new InvariantDeclaration(loc
, 0);
924 f
->fbody
= parseStatement(PScurly
);
928 /*****************************************
929 * Parse a unittest definition:
931 * Current token is 'unittest'.
934 UnitTestDeclaration
*Parser::parseUnitTest()
936 UnitTestDeclaration
*f
;
942 body
= parseStatement(PScurly
);
944 f
= new UnitTestDeclaration(loc
, this->loc
);
949 /*****************************************
950 * Parse a new definition:
951 * new(arguments) { body }
952 * Current token is 'new'.
955 NewDeclaration
*Parser::parseNew()
958 Arguments
*arguments
;
963 arguments
= parseParameters(&varargs
);
964 f
= new NewDeclaration(loc
, 0, arguments
, varargs
);
969 /*****************************************
970 * Parse a delete definition:
971 * delete(arguments) { body }
972 * Current token is 'delete'.
975 DeleteDeclaration
*Parser::parseDelete()
977 DeleteDeclaration
*f
;
978 Arguments
*arguments
;
983 arguments
= parseParameters(&varargs
);
985 error("... not allowed in delete function parameter list");
986 f
= new DeleteDeclaration(loc
, 0, arguments
);
991 /**********************************************
992 * Parse parameter list.
995 Arguments
*Parser::parseParameters(int *pvarargs
)
997 Arguments
*arguments
= new Arguments();
1007 unsigned storageClass
;
1012 storageClass
= 0; // parameter is "in" by default
1013 for (;1; nextToken())
1015 switch (token
.value
)
1026 if (peek(&token
)->value
== TOKlparen
)
1032 if (peek(&token
)->value
== TOKlparen
)
1037 case TOKin
: stc
= STCin
; goto L2
;
1038 case TOKout
: stc
= STCout
; goto L2
;
1040 case TOKref
: stc
= STCref
; goto L2
;
1041 case TOKlazy
: stc
= STClazy
; goto L2
;
1042 case TOKscope
: stc
= STCscope
; goto L2
;
1043 case TOKfinal
: stc
= STCfinal
; goto L2
;
1044 case TOKstatic
: stc
= STCstatic
; goto L2
;
1046 if (storageClass
& stc
||
1047 (storageClass
& STCin
&& stc
& (STCconst
| STCscope
)) ||
1048 (stc
& STCin
&& storageClass
& (STCconst
| STCscope
))
1050 error("redundant storage class %s", Token::toChars(token
.value
));
1051 storageClass
|= stc
;
1053 unsigned u
= storageClass
& (STCconst
| STCinvariant
);
1055 error("conflicting storage class %s", Token::toChars(token
.value
));
1061 stc
= storageClass
& (STCin
| STCout
| STCref
| STClazy
);
1062 if (stc
& (stc
- 1)) // if stc is not a power of 2
1063 error("incompatible parameter storage classes");
1064 if ((storageClass
& (STCconst
| STCout
)) == (STCconst
| STCout
))
1065 error("out cannot be const");
1066 if ((storageClass
& (STCinvariant
| STCout
)) == (STCinvariant
| STCout
))
1067 error("out cannot be invariant");
1068 if ((storageClass
& STCscope
) &&
1069 (storageClass
& (STCref
| STCout
)))
1070 error("scope cannot be ref or out");
1071 at
= parseType(&ai
);
1073 if (token
.value
== TOKassign
) // = defaultArg
1075 ae
= parseDefaultInitExp();
1080 error("default argument expected for %s",
1081 ai
? ai
->toChars() : at
->toChars());
1083 if (token
.value
== TOKdotdotdot
)
1088 if (storageClass
& (STCout
| STCref
))
1089 error("variadic argument cannot be out or ref");
1091 a
= new Argument(storageClass
, at
, ai
, ae
);
1096 a
= new Argument(storageClass
, at
, ai
, ae
);
1098 if (token
.value
== TOKcomma
)
1111 *pvarargs
= varargs
;
1116 /*************************************
1119 EnumDeclaration
*Parser::parseEnum()
1120 { EnumDeclaration
*e
;
1123 Loc loc
= this->loc
;
1125 //printf("Parser::parseEnum()\n");
1127 if (token
.value
== TOKidentifier
)
1134 if (token
.value
== TOKcolon
)
1137 memtype
= parseBasicType();
1138 memtype
= parseDeclarator(memtype
, NULL
, NULL
);
1143 e
= new EnumDeclaration(loc
, id
, memtype
);
1144 if (token
.value
== TOKsemicolon
&& id
)
1146 else if (token
.value
== TOKlcurly
)
1148 //printf("enum definition\n");
1149 e
->members
= new Array();
1151 unsigned char *comment
= token
.blockComment
;
1152 while (token
.value
!= TOKrcurly
)
1154 /* Can take the following forms:
1157 * 3. type ident = value
1164 Token
*tp
= peek(&token
);
1165 if (token
.value
== TOKidentifier
&&
1166 (tp
->value
== TOKassign
|| tp
->value
== TOKcomma
|| tp
->value
== TOKrcurly
))
1168 ident
= token
.ident
;
1174 type
= parseType(&ident
, NULL
);
1176 error("type only allowed if anonymous enum and no enum type");
1180 if (token
.value
== TOKassign
)
1183 value
= parseAssignExp();
1188 error("if type, there must be an initializer");
1191 EnumMember
*em
= new EnumMember(loc
, ident
, value
, type
);
1192 e
->members
->push(em
);
1194 if (token
.value
== TOKrcurly
)
1197 { addComment(em
, comment
);
1201 addComment(em
, comment
);
1202 comment
= token
.blockComment
;
1207 error("enum declaration is invalid");
1208 //printf("-parseEnum() %s\n", e->toChars());
1212 Dsymbol
*Parser::parseAggregate()
1213 { AggregateDeclaration
*a
= NULL
;
1217 TemplateParameters
*tpl
= NULL
;
1219 //printf("Parser::parseAggregate()\n");
1222 if (token
.value
!= TOKidentifier
)
1229 if (token
.value
== TOKlparen
)
1230 { // Class template declaration.
1232 // Gather template parameter list
1233 tpl
= parseTemplateParameterList();
1237 Loc loc
= this->loc
;
1243 error("anonymous classes not allowed");
1245 // Collect base class(es)
1246 BaseClasses
*baseclasses
= NULL
;
1247 if (token
.value
== TOKcolon
)
1250 baseclasses
= parseBaseClasses();
1252 if (token
.value
!= TOKlcurly
)
1253 error("members expected");
1256 if (tok
== TOKclass
)
1257 a
= new ClassDeclaration(loc
, id
, baseclasses
);
1259 a
= new InterfaceDeclaration(loc
, id
, baseclasses
);
1265 a
= new StructDeclaration(loc
, id
);
1272 a
= new UnionDeclaration(loc
, id
);
1281 if (a
&& token
.value
== TOKsemicolon
)
1284 else if (token
.value
== TOKlcurly
)
1286 //printf("aggregate definition\n");
1288 Array
*decl
= parseDeclDefs(0);
1289 if (token
.value
!= TOKrcurly
)
1290 error("} expected following member declarations in aggregate");
1294 /* Anonymous structs/unions are more like attributes.
1296 return new AnonDeclaration(loc
, anon
- 1, decl
);
1303 error("{ } expected following aggregate declaration");
1304 a
= new StructDeclaration(loc
, NULL
);
1309 TemplateDeclaration
*tempdecl
;
1311 // Wrap a template around the aggregate declaration
1312 decldefs
= new Array();
1314 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
);
1321 /*******************************************
1324 BaseClasses
*Parser::parseBaseClasses()
1326 BaseClasses
*baseclasses
= new BaseClasses();
1328 for (; 1; nextToken())
1330 enum PROT protection
= PROTpublic
;
1331 switch (token
.value
)
1334 protection
= PROTprivate
;
1338 protection
= PROTpackage
;
1342 protection
= PROTprotected
;
1346 protection
= PROTpublic
;
1350 if (token
.value
== TOKidentifier
)
1352 BaseClass
*b
= new BaseClass(parseBasicType(), protection
);
1353 baseclasses
->push(b
);
1354 if (token
.value
!= TOKcomma
)
1359 error("base classes expected instead of %s", token
.toChars());
1366 /**************************************
1367 * Parse a TemplateDeclaration.
1370 TemplateDeclaration
*Parser::parseTemplateDeclaration()
1372 TemplateDeclaration
*tempdecl
;
1374 TemplateParameters
*tpl
;
1376 Loc loc
= this->loc
;
1379 if (token
.value
!= TOKidentifier
)
1380 { error("TemplateIdentifier expected following template");
1385 tpl
= parseTemplateParameterList();
1389 if (token
.value
!= TOKlcurly
)
1390 { error("members of template declaration expected");
1396 decldefs
= parseDeclDefs(0);
1397 if (token
.value
!= TOKrcurly
)
1398 { error("template member expected");
1404 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
);
1411 /******************************************
1412 * Parse template parameter list.
1414 * flag 0: parsing "( list )"
1415 * 1: parsing non-empty "list )"
1418 TemplateParameters
*Parser::parseTemplateParameterList(int flag
)
1420 TemplateParameters
*tpl
= new TemplateParameters();
1422 if (!flag
&& token
.value
!= TOKlparen
)
1423 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1428 // Get array of TemplateParameters
1429 if (flag
|| token
.value
!= TOKrparen
)
1430 { int isvariadic
= 0;
1433 { TemplateParameter
*tp
;
1434 Identifier
*tp_ident
= NULL
;
1435 Type
*tp_spectype
= NULL
;
1436 Type
*tp_valtype
= NULL
;
1437 Type
*tp_defaulttype
= NULL
;
1438 Expression
*tp_specvalue
= NULL
;
1439 Expression
*tp_defaultvalue
= NULL
;
1442 // Get TemplateParameter
1444 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1446 if (token
.value
== TOKalias
)
1449 if (token
.value
!= TOKidentifier
)
1450 { error("Identifier expected for template parameter");
1453 tp_ident
= token
.ident
;
1455 if (token
.value
== TOKcolon
) // : Type
1458 tp_spectype
= parseType();
1460 if (token
.value
== TOKassign
) // = Type
1463 tp_defaulttype
= parseType();
1465 tp
= new TemplateAliasParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1467 else if (t
->value
== TOKcolon
|| t
->value
== TOKassign
||
1468 t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
1470 if (token
.value
!= TOKidentifier
)
1471 { error("Identifier expected for template parameter");
1474 tp_ident
= token
.ident
;
1476 if (token
.value
== TOKcolon
) // : Type
1479 tp_spectype
= parseType();
1481 if (token
.value
== TOKassign
) // = Type
1484 tp_defaulttype
= parseType();
1486 tp
= new TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1488 else if (token
.value
== TOKidentifier
&& t
->value
== TOKdotdotdot
)
1491 error("variadic template parameter must be last");
1493 tp_ident
= token
.ident
;
1496 tp
= new TemplateTupleParameter(loc
, tp_ident
);
1498 else if (token
.value
== TOKthis
)
1501 if (token
.value
!= TOKidentifier
)
1502 { error("Identifier expected for template parameter");
1505 tp_ident
= token
.ident
;
1507 if (token
.value
== TOKcolon
) // : Type
1510 tp_spectype
= parseType();
1512 if (token
.value
== TOKassign
) // = Type
1515 tp_defaulttype
= parseType();
1517 tp
= new TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1521 tp_valtype
= parseType(&tp_ident
);
1524 error("no identifier for template value parameter");
1525 tp_ident
= new Identifier("error", TOKidentifier
);
1527 if (token
.value
== TOKcolon
) // : CondExpression
1530 tp_specvalue
= parseCondExp();
1532 if (token
.value
== TOKassign
) // = CondExpression
1535 tp_defaultvalue
= parseDefaultInitExp();
1537 tp
= new TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1540 if (token
.value
!= TOKcomma
)
1550 /******************************************
1551 * Parse template mixin.
1554 * mixin a.b.c!(args).Foo!(args);
1555 * mixin Foo!(args) identifier;
1556 * mixin typeof(expr).identifier!(args);
1559 Dsymbol
*Parser::parseMixin()
1567 //printf("parseMixin()\n");
1570 if (token
.value
== TOKdot
)
1576 if (token
.value
== TOKtypeof
)
1578 tqual
= parseTypeof();
1581 if (token
.value
!= TOKidentifier
)
1583 error("identifier expected, not %s", token
.toChars());
1590 idents
= new Array();
1594 if (token
.value
== TOKnot
)
1597 tiargs
= parseTemplateArgumentList();
1600 if (token
.value
!= TOKdot
)
1604 { TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
1605 tempinst
->tiargs
= tiargs
;
1606 id
= (Identifier
*)tempinst
;
1612 if (token
.value
!= TOKidentifier
)
1613 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1621 if (token
.value
== TOKidentifier
)
1629 tm
= new TemplateMixin(loc
, id
, tqual
, idents
, tiargs
);
1630 if (token
.value
!= TOKsemicolon
)
1631 error("';' expected after mixin");
1640 /******************************************
1641 * Parse template argument list.
1643 * current token is opening '('
1645 * current token is one after closing ')'
1648 Objects
*Parser::parseTemplateArgumentList()
1650 //printf("Parser::parseTemplateArgumentList()\n");
1651 if (token
.value
!= TOKlparen
)
1652 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1653 return new Objects();
1655 return parseTemplateArgumentList2();
1658 Objects
*Parser::parseTemplateArgumentList2()
1660 Objects
*tiargs
= new Objects();
1663 // Get TemplateArgumentList
1664 if (token
.value
!= TOKrparen
)
1668 // See if it is an Expression or a Type
1669 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
1673 // Get TemplateArgument
1681 ea
= parseAssignExp();
1684 if (token
.value
!= TOKcomma
)
1689 check(TOKrparen
, "template argument list");
1693 Import
*Parser::parseImport(Array
*decldefs
, int isstatic
)
1696 Identifier
*aliasid
= NULL
;
1700 //printf("Parser::parseImport()\n");
1705 if (token
.value
!= TOKidentifier
)
1706 { error("Identifier expected following import");
1714 if (!aliasid
&& token
.value
== TOKassign
)
1719 while (token
.value
== TOKdot
)
1725 if (token
.value
!= TOKidentifier
)
1726 { error("Identifier expected following package");
1733 s
= new Import(loc
, a
, token
.ident
, aliasid
, isstatic
);
1737 * : alias=name, alias=name;
1740 if (token
.value
== TOKcolon
)
1747 if (token
.value
!= TOKidentifier
)
1748 { error("Identifier expected following :");
1751 alias
= token
.ident
;
1753 if (token
.value
== TOKassign
)
1756 if (token
.value
!= TOKidentifier
)
1757 { error("Identifier expected following %s=", alias
->toChars());
1767 s
->addAlias(name
, alias
);
1768 } while (token
.value
== TOKcomma
);
1769 break; // no comma-separated imports of this form
1773 } while (token
.value
== TOKcomma
);
1775 if (token
.value
== TOKsemicolon
)
1779 error("';' expected");
1786 Type
*Parser::parseType(Identifier
**pident
, TemplateParameters
**tpl
)
1789 if (token
.value
== TOKconst
&& peek(&token
)->value
!= TOKlparen
)
1794 t
= parseType(pident
, tpl
);
1798 else if (token
.value
== TOKinvariant
&& peek(&token
)->value
!= TOKlparen
)
1803 t
= parseType(pident
, tpl
);
1804 t
= t
->makeInvariant();
1808 t
= parseBasicType();
1809 t
= parseDeclarator(t
, pident
, tpl
);
1813 Type
*Parser::parseBasicType()
1817 TemplateInstance
*tempinst
;
1819 //printf("parseBasicType()\n");
1820 switch (token
.value
)
1822 CASE_BASIC_TYPES_X(t
):
1829 if (token
.value
== TOKnot
)
1832 tempinst
= new TemplateInstance(loc
, id
);
1833 tempinst
->tiargs
= parseTemplateArgumentList();
1834 tid
= new TypeInstance(loc
, tempinst
);
1838 tid
= new TypeIdentifier(loc
, id
);
1840 while (token
.value
== TOKdot
)
1842 if (token
.value
!= TOKidentifier
)
1843 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1848 if (token
.value
== TOKnot
)
1851 tempinst
= new TemplateInstance(loc
, id
);
1852 tempinst
->tiargs
= parseTemplateArgumentList();
1853 tid
->addIdent((Identifier
*)tempinst
);
1867 tid
= parseTypeof();
1886 t
= t
->makeInvariant();
1890 error("basic type expected, not %s", token
.toChars());
1897 Type
*Parser::parseBasicType2(Type
*t
)
1902 //printf("parseBasicType2()\n");
1905 switch (token
.value
)
1908 t
= new TypePointer(t
);
1913 // Handle []. Make sure things like
1915 // is (array[1] of array[3] of int)
1917 if (token
.value
== TOKrbracket
)
1919 t
= new TypeDArray(t
); // []
1922 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
1923 { // It's an associative array declaration
1926 //printf("it's an associative array\n");
1927 index
= parseType(); // [ type ]
1928 t
= new TypeAArray(t
, index
);
1933 //printf("it's [expression]\n");
1935 Expression
*e
= parseExpression(); // [ expression ]
1936 if (token
.value
== TOKslice
)
1940 e2
= parseExpression(); // [ exp .. exp ]
1941 t
= new TypeSlice(t
, e
, e2
);
1944 t
= new TypeSArray(t
,e
);
1952 { // Handle delegate declaration:
1953 // t delegate(parameter list)
1954 // t function(parameter list)
1955 Arguments
*arguments
;
1957 bool ispure
= false;
1958 bool isnothrow
= false;
1959 enum TOK save
= token
.value
;
1962 arguments
= parseParameters(&varargs
);
1965 if (token
.value
== TOKpure
)
1967 else if (token
.value
== TOKnothrow
)
1973 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
1974 tf
->ispure
= ispure
;
1975 tf
->isnothrow
= isnothrow
;
1976 if (save
== TOKdelegate
)
1977 t
= new TypeDelegate(tf
);
1979 t
= new TypePointer(tf
); // pointer to function
1992 Type
*Parser::parseDeclarator(Type
*t
, Identifier
**pident
, TemplateParameters
**tpl
)
1995 //printf("parseDeclarator(tpl = %p)\n", tpl);
1996 t
= parseBasicType2(t
);
1998 switch (token
.value
)
2003 *pident
= token
.ident
;
2005 error("unexpected identifer '%s' in declarator", token
.ident
->toChars());
2011 /* Parse things with parentheses around the identifier, like:
2013 * although the D style would be:
2017 ts
= parseDeclarator(t
, pident
);
2028 switch (token
.value
)
2031 /* Support C style array syntax:
2033 * as opposed to D-style:
2037 { // This is the old C-style post [] syntax.
2040 if (token
.value
== TOKrbracket
)
2041 { // It's a dynamic array
2042 ta
= new TypeDArray(t
); // []
2045 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2046 { // It's an associative array
2048 //printf("it's an associative array\n");
2049 Type
*index
= parseType(); // [ type ]
2051 ta
= new TypeAArray(t
, index
);
2055 //printf("It's a static array\n");
2056 Expression
*e
= parseExpression(); // [ expression ]
2057 ta
= new TypeSArray(t
, e
);
2064 * ts -> ... -> ta -> t
2067 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2077 /* Look ahead to see if this is (...)(...),
2078 * i.e. a function template declaration
2080 if (peekPastParen(&token
)->value
== TOKlparen
)
2082 //printf("function template declaration\n");
2084 // Gather template parameter list
2085 *tpl
= parseTemplateParameterList();
2090 Arguments
*arguments
= parseParameters(&varargs
);
2091 Type
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2093 /* Parse const/invariant/nothrow postfix
2097 switch (token
.value
)
2100 tf
= tf
->makeConst();
2105 tf
= tf
->makeInvariant();
2110 ((TypeFunction
*)tf
)->isnothrow
= 1;
2115 ((TypeFunction
*)tf
)->ispure
= 1;
2125 * ts -> ... -> tf -> t
2128 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2140 /**********************************
2141 * Return array of Declaration *'s.
2144 Array
*Parser::parseDeclarations()
2146 enum STC storage_class
;
2154 unsigned char *comment
= token
.blockComment
;
2155 enum LINK link
= linkage
;
2157 //printf("parseDeclarations() %s\n", token.toChars());
2158 switch (token
.value
)
2171 storage_class
= STCundefined
;
2174 switch (token
.value
)
2177 if (peek(&token
)->value
== TOKlparen
)
2183 if (peek(&token
)->value
== TOKlparen
)
2188 case TOKstatic
: stc
= STCstatic
; goto L1
;
2189 case TOKfinal
: stc
= STCfinal
; goto L1
;
2190 case TOKauto
: stc
= STCauto
; goto L1
;
2191 case TOKscope
: stc
= STCscope
; goto L1
;
2192 case TOKoverride
: stc
= STCoverride
; goto L1
;
2193 case TOKabstract
: stc
= STCabstract
; goto L1
;
2194 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
2195 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
2196 case TOKnothrow
: stc
= STCnothrow
; goto L1
;
2197 case TOKpure
: stc
= STCpure
; goto L1
;
2198 case TOKtls
: stc
= STCtls
; goto L1
;
2199 case TOKenum
: stc
= STCmanifest
; goto L1
;
2201 if (storage_class
& stc
)
2202 error("redundant storage class '%s'", token
.toChars());
2203 storage_class
= (STC
) (storage_class
| stc
);
2205 unsigned u
= storage_class
;
2206 u
&= STCconst
| STCinvariant
| STCmanifest
;
2208 error("conflicting storage class %s", Token::toChars(token
.value
));
2214 if (peek(&token
)->value
!= TOKlparen
)
2219 link
= parseLinkage();
2230 /* Look for auto initializers:
2231 * storage_class identifier = initializer;
2233 while (storage_class
&&
2234 token
.value
== TOKidentifier
&&
2235 peek(&token
)->value
== TOKassign
)
2237 ident
= token
.ident
;
2240 Initializer
*init
= parseInitializer();
2241 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
2242 v
->storage_class
= storage_class
;
2244 if (token
.value
== TOKsemicolon
)
2247 addComment(v
, comment
);
2249 else if (token
.value
== TOKcomma
)
2252 if (!(token
.value
== TOKidentifier
&& peek(&token
)->value
== TOKassign
))
2254 error("Identifier expected following comma");
2260 error("semicolon expected following auto declaration, not '%s'", token
.toChars());
2264 if (token
.value
== TOKclass
)
2265 { AggregateDeclaration
*s
;
2267 s
= (AggregateDeclaration
*)parseAggregate();
2268 s
->storage_class
|= storage_class
;
2270 addComment(s
, comment
);
2274 ts
= parseBasicType();
2275 ts
= parseBasicType2(ts
);
2280 Loc loc
= this->loc
;
2281 TemplateParameters
*tpl
= NULL
;
2284 t
= parseDeclarator(ts
, &ident
, &tpl
);
2288 else if (t
!= tfirst
)
2289 error("multiple declarations must have the same type, not %s and %s",
2290 tfirst
->toChars(), t
->toChars());
2292 error("no identifier for declarator %s", t
->toChars());
2294 if (tok
== TOKtypedef
|| tok
== TOKalias
)
2299 if (token
.value
== TOKassign
)
2302 init
= parseInitializer();
2304 if (tok
== TOKtypedef
)
2305 v
= new TypedefDeclaration(loc
, ident
, t
, init
);
2308 error("alias cannot have initializer");
2309 v
= new AliasDeclaration(loc
, ident
, t
);
2311 v
->storage_class
= storage_class
;
2312 if (link
== linkage
)
2316 Array
*ax
= new Array();
2318 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2321 switch (token
.value
)
2322 { case TOKsemicolon
:
2324 addComment(v
, comment
);
2329 addComment(v
, comment
);
2333 error("semicolon expected to close %s declaration", Token::toChars(tok
));
2337 else if (t
->ty
== Tfunction
)
2338 { FuncDeclaration
*f
;
2341 f
= new FuncDeclaration(loc
, 0, ident
, storage_class
, t
);
2342 addComment(f
, comment
);
2344 addComment(f
, NULL
);
2345 if (link
== linkage
)
2351 Array
*ax
= new Array();
2353 s
= new LinkDeclaration(link
, ax
);
2355 if (tpl
) // it's a function template
2357 TemplateDeclaration
*tempdecl
;
2359 // Wrap a template around the aggregate declaration
2360 decldefs
= new Array();
2362 tempdecl
= new TemplateDeclaration(loc
, s
->ident
, tpl
, decldefs
);
2365 addComment(s
, comment
);
2369 { VarDeclaration
*v
;
2373 if (token
.value
== TOKassign
)
2376 init
= parseInitializer();
2378 v
= new VarDeclaration(loc
, t
, ident
, init
);
2379 v
->storage_class
= storage_class
;
2380 if (link
== linkage
)
2384 Array
*ax
= new Array();
2386 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2389 switch (token
.value
)
2390 { case TOKsemicolon
:
2392 addComment(v
, comment
);
2397 addComment(v
, comment
);
2401 error("semicolon expected, not '%s'", token
.toChars());
2410 /*****************************************
2411 * Parse contracts following function declaration.
2414 void Parser::parseContracts(FuncDeclaration
*f
)
2417 enum LINK linksave
= linkage
;
2419 // The following is irrelevant, as it is overridden by sc->linkage in
2420 // TypeFunction::semantic
2421 linkage
= LINKd
; // nested functions have D linkage
2423 switch (token
.value
)
2426 if (f
->frequire
|| f
->fensure
)
2427 error("missing body { ... } after in or out");
2428 f
->fbody
= parseStatement(PSsemi
);
2434 f
->fbody
= parseStatement(PScurly
);
2439 if (f
->frequire
|| f
->fensure
)
2440 error("missing body { ... } after in or out");
2444 #if 0 // Do we want this for function declarations, so we can do:
2445 // int x, y, foo(), z;
2451 #if 0 // Dumped feature
2454 f
->fthrows
= new Array();
2459 tb
= parseBasicType();
2460 f
->fthrows
->push(tb
);
2461 if (token
.value
== TOKcomma
)
2474 error("redundant 'in' statement");
2475 f
->frequire
= parseStatement(PScurly
| PSscope
);
2479 // parse: out (identifier) { statement }
2481 if (token
.value
!= TOKlcurly
)
2484 if (token
.value
!= TOKidentifier
)
2485 error("(identifier) following 'out' expected, not %s", token
.toChars());
2486 f
->outId
= token
.ident
;
2491 error("redundant 'out' statement");
2492 f
->fensure
= parseStatement(PScurly
| PSscope
);
2496 error("semicolon expected following function declaration");
2502 /*****************************************
2505 Initializer
*Parser::parseInitializer()
2507 StructInitializer
*is
;
2508 ArrayInitializer
*ia
;
2514 Loc loc
= this->loc
;
2518 switch (token
.value
)
2521 /* Scan ahead to see if it is a struct initializer or
2522 * a function literal.
2523 * If it contains a ';', it is a function literal.
2524 * Treat { } as a struct initializer.
2527 for (t
= peek(&token
); 1; t
= peek(t
))
2553 is
= new StructInitializer(loc
);
2558 switch (token
.value
)
2562 error("comma expected separating field initializers");
2564 if (t
->value
== TOKcolon
)
2568 nextToken(); // skip over ':'
2573 value
= parseInitializer();
2574 is
->addInit(id
, value
);
2583 case TOKrcurly
: // allow trailing comma's
2588 error("found EOF instead of initializer");
2592 value
= parseInitializer();
2593 is
->addInit(NULL
, value
);
2596 //error("found '%s' instead of field initializer", token.toChars());
2604 ia
= new ArrayInitializer(loc
);
2609 switch (token
.value
)
2613 { error("comma expected separating array initializers, not %s", token
.toChars());
2617 e
= parseAssignExp();
2620 if (token
.value
== TOKcolon
)
2623 value
= parseInitializer();
2626 { value
= new ExpInitializer(e
->loc
, e
);
2629 ia
->addInit(e
, value
);
2636 error("comma expected separating array initializers, not %s", token
.toChars());
2637 value
= parseInitializer();
2638 ia
->addInit(NULL
, value
);
2647 case TOKrbracket
: // allow trailing comma's
2652 error("found '%s' instead of array initializer", token
.toChars());
2661 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
)
2664 return new VoidInitializer(loc
);
2670 e
= parseAssignExp();
2671 ie
= new ExpInitializer(loc
, e
);
2676 /*****************************************
2677 * Parses default argument initializer expression that is an assign expression,
2678 * with special handling for __FILE__ and __LINE__.
2681 Expression
*Parser::parseDefaultInitExp()
2683 if (token
.value
== TOKfile
||
2684 token
.value
== TOKline
)
2686 Token
*t
= peek(&token
);
2687 if (t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
2690 if (token
.value
== TOKfile
)
2691 e
= new FileInitExp(loc
);
2693 e
= new LineInitExp(loc
);
2699 Expression
*e
= parseAssignExp();
2703 /*****************************************
2708 Statement
*Parser::parseStatement(int flags
)
2711 Condition
*condition
;
2713 Statement
*elsebody
;
2714 Loc loc
= this->loc
;
2716 //printf("parseStatement()\n");
2718 if (flags
& PScurly
&& token
.value
!= TOKlcurly
)
2719 error("statement expected to be { }, not %s", token
.toChars());
2721 switch (token
.value
)
2724 // Need to look ahead to see if it is a declaration, label, or expression
2726 if (t
->value
== TOKcolon
)
2730 ident
= token
.ident
;
2733 s
= parseStatement(PSsemi
);
2734 s
= new LabelStatement(loc
, ident
, s
);
2737 // fallthrough to TOKdot
2740 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2756 case TOKimaginary32v
:
2757 case TOKimaginary64v
:
2758 case TOKimaginary80v
:
2786 exp
= parseExpression();
2787 check(TOKsemicolon
, "statement");
2788 s
= new ExpStatement(loc
, exp
);
2793 { // Look ahead to see if it's static assert() or static if()
2797 if (t
->value
== TOKassert
)
2800 s
= new StaticAssertStatement(parseStaticAssert());
2803 if (t
->value
== TOKif
)
2806 condition
= parseStaticIfCondition();
2824 a
= parseDeclarations();
2827 Statements
*as
= new Statements();
2828 as
->reserve(a
->dim
);
2829 for (int i
= 0; i
< a
->dim
; i
++)
2831 Dsymbol
*d
= (Dsymbol
*)a
->data
[i
];
2832 s
= new DeclarationStatement(loc
, d
);
2835 s
= new CompoundStatement(loc
, as
);
2837 else if (a
->dim
== 1)
2839 Dsymbol
*d
= (Dsymbol
*)a
->data
[0];
2840 s
= new DeclarationStatement(loc
, d
);
2844 if (flags
& PSscope
)
2845 s
= new ScopeStatement(loc
, s
);
2855 d
= parseAggregate();
2856 s
= new DeclarationStatement(loc
, d
);
2861 { /* Determine if this is a manifest constant declaration,
2862 * or a conventional enum.
2865 Token
*t
= peek(&token
);
2866 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
2868 else if (t
->value
!= TOKidentifier
)
2873 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
2874 t
->value
== TOKsemicolon
)
2879 s
= new DeclarationStatement(loc
, d
);
2885 if (t
->value
== TOKlparen
)
2888 check(TOKlparen
, "mixin");
2889 Expression
*e
= parseAssignExp();
2891 check(TOKsemicolon
);
2892 s
= new CompileStatement(loc
, e
);
2895 Dsymbol
*d
= parseMixin();
2896 s
= new DeclarationStatement(loc
, d
);
2901 { Statements
*statements
;
2904 statements
= new Statements();
2905 while (token
.value
!= TOKrcurly
)
2907 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
2910 s
= new CompoundStatement(loc
, statements
);
2911 if (flags
& (PSscope
| PScurlyscope
))
2912 s
= new ScopeStatement(loc
, s
);
2918 { Expression
*condition
;
2923 condition
= parseExpression();
2925 body
= parseStatement(PSscope
);
2926 s
= new WhileStatement(loc
, condition
, body
);
2931 if (!(flags
& PSsemi
))
2932 error("use '{ }' for an empty statement, not a ';'");
2934 s
= new ExpStatement(loc
, NULL
);
2939 Expression
*condition
;
2942 body
= parseStatement(PSscope
);
2945 condition
= parseExpression();
2947 s
= new DoStatement(loc
, body
, condition
);
2954 Expression
*condition
;
2955 Expression
*increment
;
2960 if (token
.value
== TOKsemicolon
)
2965 { init
= parseStatement(0);
2967 if (token
.value
== TOKsemicolon
)
2974 condition
= parseExpression();
2975 check(TOKsemicolon
, "for condition");
2977 if (token
.value
== TOKrparen
)
2982 { increment
= parseExpression();
2985 body
= parseStatement(PSscope
);
2986 s
= new ForStatement(loc
, init
, condition
, increment
, body
);
2988 s
= new ScopeStatement(loc
, s
);
2993 case TOKforeach_reverse
:
2995 enum TOK op
= token
.value
;
2996 Arguments
*arguments
;
3005 arguments
= new Arguments();
3010 Identifier
*ai
= NULL
;
3012 unsigned storageClass
;
3016 if (token
.value
== TOKinout
|| token
.value
== TOKref
)
3017 { storageClass
= STCref
;
3020 if (token
.value
== TOKidentifier
)
3022 Token
*t
= peek(&token
);
3023 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
3025 at
= NULL
; // infer argument type
3030 at
= parseType(&ai
);
3032 error("no identifier for declarator %s", at
->toChars());
3034 a
= new Argument(storageClass
, at
, ai
, NULL
);
3036 if (token
.value
== TOKcomma
)
3042 check(TOKsemicolon
);
3044 aggr
= parseExpression();
3045 if (token
.value
== TOKslice
&& arguments
->dim
== 1)
3047 Argument
*a
= (Argument
*)arguments
->data
[0];
3050 Expression
*upr
= parseExpression();
3052 body
= parseStatement(0);
3053 s
= new ForeachRangeStatement(loc
, op
, a
, aggr
, upr
, body
);
3058 body
= parseStatement(0);
3059 s
= new ForeachStatement(loc
, op
, arguments
, aggr
, body
);
3065 { Argument
*arg
= NULL
;
3066 Expression
*condition
;
3068 Statement
*elsebody
;
3073 if (token
.value
== TOKauto
)
3076 if (token
.value
== TOKidentifier
)
3078 Token
*t
= peek(&token
);
3079 if (t
->value
== TOKassign
)
3081 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3086 { error("= expected following auto identifier");
3091 { error("identifier expected following auto");
3095 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
3100 at
= parseType(&ai
);
3102 arg
= new Argument(0, at
, ai
, NULL
);
3105 // Check for " ident;"
3106 else if (token
.value
== TOKidentifier
)
3108 Token
*t
= peek(&token
);
3109 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
3111 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3114 if (1 || !global
.params
.useDeprecated
)
3115 error("if (v; e) is deprecated, use if (auto v = e)");
3119 condition
= parseExpression();
3121 ifbody
= parseStatement(PSscope
);
3122 if (token
.value
== TOKelse
)
3125 elsebody
= parseStatement(PSscope
);
3129 s
= new IfStatement(loc
, arg
, condition
, ifbody
, elsebody
);
3134 if (peek(&token
)->value
!= TOKlparen
)
3135 goto Ldeclaration
; // scope used as storage class
3138 if (token
.value
!= TOKidentifier
)
3139 { error("scope identifier expected");
3143 { TOK t
= TOKon_scope_exit
;
3144 Identifier
*id
= token
.ident
;
3147 t
= TOKon_scope_exit
;
3148 else if (id
== Id::failure
)
3149 t
= TOKon_scope_failure
;
3150 else if (id
== Id::success
)
3151 t
= TOKon_scope_success
;
3153 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
3156 Statement
*st
= parseStatement(PScurlyscope
);
3157 s
= new OnScopeStatement(loc
, t
, st
);
3163 condition
= parseDebugCondition();
3168 condition
= parseVersionCondition();
3172 ifbody
= parseStatement(0 /*PSsemi*/);
3174 if (token
.value
== TOKelse
)
3177 elsebody
= parseStatement(0 /*PSsemi*/);
3179 s
= new ConditionalStatement(loc
, condition
, ifbody
, elsebody
);
3183 { Identifier
*ident
;
3184 Expressions
*args
= NULL
;
3189 if (token
.value
!= TOKidentifier
)
3190 { error("pragma(identifier expected");
3193 ident
= token
.ident
;
3195 if (token
.value
== TOKcomma
)
3196 args
= parseArguments(); // pragma(identifier, args...);
3198 check(TOKrparen
); // pragma(identifier);
3199 if (token
.value
== TOKsemicolon
)
3204 body
= parseStatement(PSsemi
);
3205 s
= new PragmaStatement(loc
, ident
, args
, body
);
3210 { Expression
*condition
;
3215 condition
= parseExpression();
3217 body
= parseStatement(PSscope
);
3218 s
= new SwitchStatement(loc
, condition
, body
);
3224 Statements
*statements
;
3225 Array cases
; // array of Expression's
3230 exp
= parseAssignExp();
3232 if (token
.value
!= TOKcomma
)
3237 statements
= new Statements();
3238 while (token
.value
!= TOKcase
&&
3239 token
.value
!= TOKdefault
&&
3240 token
.value
!= TOKrcurly
)
3242 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3244 s
= new CompoundStatement(loc
, statements
);
3245 s
= new ScopeStatement(loc
, s
);
3247 // Keep cases in order by building the case statements backwards
3248 for (int i
= cases
.dim
; i
; i
--)
3250 exp
= (Expression
*)cases
.data
[i
- 1];
3251 s
= new CaseStatement(loc
, exp
, s
);
3258 Statements
*statements
;
3263 statements
= new Statements();
3264 while (token
.value
!= TOKcase
&&
3265 token
.value
!= TOKdefault
&&
3266 token
.value
!= TOKrcurly
)
3268 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3270 s
= new CompoundStatement(loc
, statements
);
3271 s
= new ScopeStatement(loc
, s
);
3272 s
= new DefaultStatement(loc
, s
);
3280 if (token
.value
== TOKsemicolon
)
3283 exp
= parseExpression();
3284 check(TOKsemicolon
, "return statement");
3285 s
= new ReturnStatement(loc
, exp
);
3290 { Identifier
*ident
;
3293 if (token
.value
== TOKidentifier
)
3294 { ident
= token
.ident
;
3299 check(TOKsemicolon
, "break statement");
3300 s
= new BreakStatement(loc
, ident
);
3305 { Identifier
*ident
;
3308 if (token
.value
== TOKidentifier
)
3309 { ident
= token
.ident
;
3314 check(TOKsemicolon
, "continue statement");
3315 s
= new ContinueStatement(loc
, ident
);
3320 { Identifier
*ident
;
3323 if (token
.value
== TOKdefault
)
3326 s
= new GotoDefaultStatement(loc
);
3328 else if (token
.value
== TOKcase
)
3330 Expression
*exp
= NULL
;
3333 if (token
.value
!= TOKsemicolon
)
3334 exp
= parseExpression();
3335 s
= new GotoCaseStatement(loc
, exp
);
3339 if (token
.value
!= TOKidentifier
)
3340 { error("Identifier expected following goto");
3344 { ident
= token
.ident
;
3347 s
= new GotoStatement(loc
, ident
);
3349 check(TOKsemicolon
, "goto statement");
3353 case TOKsynchronized
:
3358 if (token
.value
== TOKlparen
)
3361 exp
= parseExpression();
3366 body
= parseStatement(PSscope
);
3367 s
= new SynchronizedStatement(loc
, exp
, body
);
3377 exp
= parseExpression();
3379 body
= parseStatement(PSscope
);
3380 s
= new WithStatement(loc
, exp
, body
);
3386 Array
*catches
= NULL
;
3387 Statement
*finalbody
= NULL
;
3390 body
= parseStatement(PSscope
);
3391 while (token
.value
== TOKcatch
)
3397 Loc loc
= this->loc
;
3400 if (token
.value
== TOKlcurly
)
3412 handler
= parseStatement(0);
3413 c
= new Catch(loc
, t
, id
, handler
);
3415 catches
= new Array();
3419 if (token
.value
== TOKfinally
)
3421 finalbody
= parseStatement(0);
3425 if (!catches
&& !finalbody
)
3426 error("catch or finally expected following try");
3429 s
= new TryCatchStatement(loc
, body
, catches
);
3431 s
= new TryFinallyStatement(loc
, s
, finalbody
);
3440 exp
= parseExpression();
3441 check(TOKsemicolon
, "throw statement");
3442 s
= new ThrowStatement(loc
, exp
);
3448 s
= parseStatement(PSsemi
| PScurlyscope
);
3449 if (!global
.params
.useDeprecated
)
3450 error("volatile statements deprecated; used synchronized statements instead");
3451 s
= new VolatileStatement(loc
, s
);
3455 { Statements
*statements
;
3461 // Parse the asm block into a sequence of AsmStatements,
3462 // each AsmStatement is one instruction.
3463 // Separate out labels.
3464 // Defer parsing of AsmStatements until semantic processing.
3467 #if GDC_EXTENDED_ASM_SYNTAX
3468 if (token
.value
== TOKlparen
)
3477 ptoklist
= &toklist
;
3479 statements
= new Statements();
3482 switch (token
.value
)
3487 // Look ahead to see if it is a label
3489 if (t
->value
== TOKcolon
)
3491 label
= token
.ident
;
3492 labelloc
= this->loc
;
3501 if (toklist
|| label
)
3503 error("asm statements must end in ';'");
3509 if (toklist
|| label
)
3510 { // Create AsmStatement from list of tokens we've saved
3511 s
= new AsmStatement(this->loc
, toklist
);
3513 ptoklist
= &toklist
;
3515 { s
= new LabelStatement(labelloc
, label
, s
);
3518 statements
->push(s
);
3525 error("matching '}' expected, not end of file");
3530 // If the first token is a string or '(', parse as extended asm.
3534 statements
->push(s
);
3537 // ...else, drop through.
3541 *ptoklist
= new Token();
3542 memcpy(*ptoklist
, &token
, sizeof(Token
));
3543 ptoklist
= &(*ptoklist
)->next
;
3551 s
= new CompoundStatement(loc
, statements
);
3557 error("found '%s' instead of statement", token
.toChars());
3561 while (token
.value
!= TOKrcurly
&&
3562 token
.value
!= TOKsemicolon
&&
3563 token
.value
!= TOKeof
)
3565 if (token
.value
== TOKsemicolon
)
3574 Statement
*Parser::parseExtAsm(int expect_rparen
)
3576 Expression
* insnTemplate
;
3577 Expressions
* args
= NULL
;
3578 Array
* argNames
= NULL
;
3579 Expressions
* argConstraints
= NULL
;
3580 int nOutputArgs
= 0;
3581 Expressions
* clobbers
= NULL
;
3582 bool isInputPhase
= false; // Output operands first, then input.
3584 insnTemplate
= parseExpression();
3585 if (token
.value
== TOKrparen
|| token
.value
== TOKsemicolon
)
3589 Expression
* arg
= NULL
;
3590 Identifier
* name
= NULL
;
3591 Expression
* constraint
= NULL
;
3593 switch (token
.value
)
3604 error("unterminated statement");
3608 if (token
.value
== TOKidentifier
)
3614 error("expected identifier after '['");
3618 constraint
= parsePrimaryExp();
3619 if (constraint
->op
!= TOKstring
)
3620 error("expected constant string constraint for operand");
3621 arg
= parseAssignExp();
3624 args
= new Expressions
;
3625 argConstraints
= new Expressions
;
3626 argNames
= new Array
;
3629 argNames
->push(name
);
3630 argConstraints
->push(constraint
);
3634 if (token
.value
== TOKcomma
)
3641 isInputPhase
= true;
3648 Expression
* clobber
;
3650 switch (token
.value
)
3657 error("unterminated statement");
3660 clobber
= parseAssignExp();
3661 if (clobber
->op
!= TOKstring
)
3662 error("expected constant string constraint for clobber name");
3664 clobbers
= new Expressions
;
3665 clobbers
->push(clobber
);
3667 if (token
.value
== TOKcomma
)
3676 check(TOKsemicolon
);
3678 return new ExtAsmStatement(loc
, insnTemplate
, args
, argNames
,
3679 argConstraints
, nOutputArgs
, clobbers
);
3682 void Parser::check(enum TOK value
)
3687 void Parser::check(Loc loc
, enum TOK value
)
3689 if (token
.value
!= value
)
3690 error(loc
, "found '%s' when expecting '%s'", token
.toChars(), Token::toChars(value
));
3694 void Parser::check(enum TOK value
, char *string
)
3696 if (token
.value
!= value
)
3697 error("found '%s' when expecting '%s' following '%s'",
3698 token
.toChars(), Token::toChars(value
), string
);
3702 /************************************
3703 * Determine if the scanner is sitting on the start of a declaration.
3705 * needId 0 no identifier
3706 * 1 identifier optional
3707 * 2 must have identifier
3710 int Parser::isDeclaration(Token
*t
, int needId
, enum TOK endtok
, Token
**pt
)
3714 if ((t
->value
== TOKconst
|| t
->value
== TOKinvariant
) &&
3715 peek(t
)->value
!= TOKlparen
)
3722 if (!isBasicType(&t
))
3724 if (!isDeclarator(&t
, &haveId
, endtok
))
3727 (needId
== 0 && !haveId
) ||
3728 (needId
== 2 && haveId
))
3737 int Parser::isBasicType(Token
**pt
)
3739 // This code parallels parseBasicType()
3753 if (t
->value
== TOKnot
)
3763 if (t
->value
== TOKdot
)
3767 if (t
->value
!= TOKidentifier
)
3770 if (t
->value
!= TOKnot
)
3774 if (t
->value
!= TOKlparen
)
3776 if (!skipParens(t
, &t
))
3788 /* typeof(exp).identifier...
3791 if (t
->value
!= TOKlparen
)
3793 if (!skipParens(t
, &t
))
3799 // const(type) or invariant(type)
3801 if (t
->value
!= TOKlparen
)
3804 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
3819 int Parser::isDeclarator(Token
**pt
, int *haveId
, enum TOK endtok
)
3820 { // This code parallels parseDeclarator()
3824 //printf("Parser::isDeclarator()\n");
3826 if (t
->value
== TOKassign
)
3841 if (t
->value
== TOKrbracket
)
3845 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
3846 { // It's an associative array declaration
3852 // [ expression .. expression ]
3853 if (!isExpression(&t
))
3855 if (t
->value
== TOKslice
)
3857 if (!isExpression(&t
))
3860 if (t
->value
!= TOKrbracket
)
3876 if (t
->value
== TOKrparen
)
3877 return FALSE
; // () is not a declarator
3879 /* Regard ( identifier ) as not a declarator
3880 * BUG: what about ( *identifier ) in
3882 * where f is a class instance with overloaded () ?
3883 * Should we just disallow C-style function pointer declarations?
3885 if (t
->value
== TOKidentifier
)
3886 { Token
*t2
= peek(t
);
3887 if (t2
->value
== TOKrparen
)
3892 if (!isDeclarator(&t
, haveId
, TOKrparen
))
3901 if (!isParameters(&t
))
3916 if (t
->value
== TOKrbracket
)
3920 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
3921 { // It's an associative array declaration
3927 if (!isExpression(&t
))
3929 if (t
->value
!= TOKrbracket
)
3938 if (!isParameters(&t
))
3940 if (t
->value
== TOKconst
|| t
->value
== TOKinvariant
)
3944 // Valid tokens that follow a declaration
3952 // The !parens is to disallow unnecessary parentheses
3953 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
3966 int Parser::isParameters(Token
**pt
)
3967 { // This code parallels parseParameters()
3971 //printf("isParameters()\n");
3972 if (t
->value
!= TOKlparen
)
3976 for (;1; t
= peek(t
))
3999 if (!isBasicType(&t
))
4002 if (t
->value
!= TOKdotdotdot
&&
4003 !isDeclarator(&t
, &tmp
, TOKreserved
))
4005 if (t
->value
== TOKassign
)
4007 if (!isExpression(&t
))
4010 if (t
->value
== TOKdotdotdot
)
4015 if (t
->value
== TOKcomma
)
4023 if (t
->value
!= TOKrparen
)
4030 int Parser::isExpression(Token
**pt
)
4032 // This is supposed to determine if something is an expression.
4033 // What it actually does is scan until a closing right bracket
4041 for (;; t
= peek(t
))
4059 if (brnest
|| panest
)
4073 if (--curlynest
>= 0)
4100 /**********************************************
4102 * instance foo.bar(parameters...)
4104 * if (pt), *pt is set to the token following the closing )
4106 * 1 it's valid instance syntax
4107 * 0 invalid instance syntax
4110 int Parser::isTemplateInstance(Token
*t
, Token
**pt
)
4113 if (t
->value
!= TOKdot
)
4115 if (t
->value
!= TOKidentifier
)
4119 while (t
->value
== TOKdot
)
4122 if (t
->value
!= TOKidentifier
)
4126 if (t
->value
!= TOKlparen
)
4129 // Skip over the template arguments
4138 if (!skipParens(t
, &t
))
4154 if (t
->value
!= TOKcomma
)
4157 if (t
->value
!= TOKrparen
)
4168 /*******************************************
4169 * Skip parens, brackets.
4173 * *pt is set to closing token, which is ')' on success
4176 * 0 some parsing error
4179 int Parser::skipParens(Token
*t
, Token
**pt
)
4218 /********************************* Expression Parser ***************************/
4220 Expression
*Parser::parsePrimaryExp()
4225 Loc loc
= this->loc
;
4227 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4228 switch (token
.value
)
4233 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4234 { // identifier!(template-argument-list)
4235 TemplateInstance
*tempinst
;
4237 tempinst
= new TemplateInstance(loc
, id
);
4239 tempinst
->tiargs
= parseTemplateArgumentList();
4240 e
= new ScopeExp(loc
, tempinst
);
4243 e
= new IdentifierExp(loc
, id
);
4248 error("'$' is valid only inside [] of index or slice");
4249 e
= new DollarExp(loc
);
4254 // Signal global scope '.' operator with "" identifier
4255 e
= new IdentifierExp(loc
, Id::empty
);
4259 e
= new ThisExp(loc
);
4264 e
= new SuperExp(loc
);
4269 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
4274 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
4279 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
4284 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
4289 e
= new RealExp(loc
, token
.float80value
, Type::tfloat32
);
4294 e
= new RealExp(loc
, token
.float80value
, Type::tfloat64
);
4299 e
= new RealExp(loc
, token
.float80value
, Type::tfloat80
);
4303 case TOKimaginary32v
:
4304 e
= new RealExp(loc
, token
.float80value
, Type::timaginary32
);
4308 case TOKimaginary64v
:
4309 e
= new RealExp(loc
, token
.float80value
, Type::timaginary64
);
4313 case TOKimaginary80v
:
4314 e
= new RealExp(loc
, token
.float80value
, Type::timaginary80
);
4319 e
= new NullExp(loc
);
4324 { char *s
= loc
.filename
? loc
.filename
: mod
->ident
->toChars();
4325 e
= new StringExp(loc
, s
, strlen(s
), 0);
4331 e
= new IntegerExp(loc
, loc
.linnum
, Type::tint32
);
4336 e
= new IntegerExp(loc
, 1, Type::tbool
);
4341 e
= new IntegerExp(loc
, 0, Type::tbool
);
4346 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tchar
);
4351 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::twchar
);
4356 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
4363 unsigned char postfix
;
4365 // cat adjacent strings
4368 postfix
= token
.postfix
;
4372 if (token
.value
== TOKstring
)
4378 { if (token
.postfix
!= postfix
)
4379 error("mismatched string literal postfixes '%c' and '%c'", postfix
, token
.postfix
);
4380 postfix
= token
.postfix
;
4386 s2
= (unsigned char *)mem
.malloc((len
+ 1) * sizeof(unsigned char));
4387 memcpy(s2
, s
, len1
* sizeof(unsigned char));
4388 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(unsigned char));
4394 e
= new StringExp(loc
, s
, len
, postfix
);
4398 CASE_BASIC_TYPES_X(t
):
4401 check(TOKdot
, t
->toChars());
4402 if (token
.value
!= TOKidentifier
)
4403 { error("found '%s' when expecting identifier following '%s.'", token
.toChars(), t
->toChars());
4406 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4413 if (token
.value
== TOKdot
)
4415 e
= new TypeExp(loc
, t
);
4423 check(TOKlparen
, "typeid");
4424 t
= parseType(); // ( type )
4426 e
= new TypeidExp(loc
, t
);
4431 { /* __traits(identifier, args...)
4434 Objects
*args
= NULL
;
4438 if (token
.value
!= TOKidentifier
)
4439 { error("__traits(identifier, args...) expected");
4442 ident
= token
.ident
;
4444 if (token
.value
== TOKcomma
)
4445 args
= parseTemplateArgumentList2(); // __traits(identifier, args...)
4447 check(TOKrparen
); // __traits(identifier)
4449 e
= new TraitsExp(loc
, ident
, args
);
4455 Identifier
*ident
= NULL
;
4457 enum TOK tok
= TOKreserved
;
4458 enum TOK tok2
= TOKreserved
;
4459 TemplateParameters
*tpl
= NULL
;
4460 Loc loc
= this->loc
;
4463 if (token
.value
== TOKlparen
)
4466 targ
= parseType(&ident
);
4467 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
4471 if (tok
== TOKequal
&&
4472 (token
.value
== TOKtypedef
||
4473 token
.value
== TOKstruct
||
4474 token
.value
== TOKunion
||
4475 token
.value
== TOKclass
||
4476 token
.value
== TOKsuper
||
4477 token
.value
== TOKenum
||
4478 token
.value
== TOKinterface
||
4479 token
.value
== TOKconst
&& peek(&token
)->value
== TOKrparen
||
4480 token
.value
== TOKinvariant
&& peek(&token
)->value
== TOKrparen
||
4481 token
.value
== TOKfunction
||
4482 token
.value
== TOKdelegate
||
4483 token
.value
== TOKreturn
))
4490 tspec
= parseType();
4495 if (token
.value
== TOKcomma
)
4496 tpl
= parseTemplateParameterList(1);
4498 { tpl
= new TemplateParameters();
4501 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, ident
, NULL
, NULL
);
4508 { error("(type identifier : specialization) expected following is");
4511 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
4516 { Expression
*msg
= NULL
;
4519 check(TOKlparen
, "assert");
4520 e
= parseAssignExp();
4521 if (token
.value
== TOKcomma
)
4523 msg
= parseAssignExp();
4526 e
= new AssertExp(loc
, e
, msg
);
4533 check(TOKlparen
, "mixin");
4534 e
= parseAssignExp();
4536 e
= new CompileExp(loc
, e
);
4543 check(TOKlparen
, "import");
4544 e
= parseAssignExp();
4546 e
= new FileExp(loc
, e
);
4551 if (peekPastParen(&token
)->value
== TOKlcurly
)
4552 { // (arguments) { statements... }
4558 e
= parseExpression();
4559 check(loc
, TOKrparen
);
4563 { /* Parse array literals and associative array literals:
4564 * [ value, value, value ... ]
4565 * [ key:value, key:value, key:value ... ]
4567 Expressions
*values
= new Expressions();
4568 Expressions
*keys
= NULL
;
4571 if (token
.value
!= TOKrbracket
)
4575 Expression
*e
= parseAssignExp();
4576 if (token
.value
== TOKcolon
&& (keys
|| values
->dim
== 0))
4579 keys
= new Expressions();
4581 e
= parseAssignExp();
4584 { error("'key:value' expected for associative array literal");
4589 if (token
.value
== TOKrbracket
)
4597 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
4599 e
= new ArrayLiteralExp(loc
, values
);
4604 // { statements... }
4614 /* function type(parameters) { body }
4615 * delegate type(parameters) { body }
4616 * (parameters) { body }
4619 Arguments
*arguments
;
4621 FuncLiteralDeclaration
*fd
;
4623 bool isnothrow
= false;
4624 bool ispure
= false;
4626 if (token
.value
== TOKlcurly
)
4630 arguments
= new Arguments();
4634 if (token
.value
== TOKlparen
)
4638 t
= parseBasicType();
4639 t
= parseBasicType2(t
); // function return type
4641 arguments
= parseParameters(&varargs
);
4644 if (token
.value
== TOKpure
)
4646 else if (token
.value
== TOKnothrow
)
4653 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
4654 tf
->ispure
= ispure
;
4655 tf
->isnothrow
= isnothrow
;
4656 fd
= new FuncLiteralDeclaration(loc
, 0, tf
, save
, NULL
);
4658 e
= new FuncExp(loc
, fd
);
4663 error("expression expected, not '%s'", token
.toChars());
4665 // Anything for e, as long as it's not NULL
4666 e
= new IntegerExp(loc
, 0, Type::tint32
);
4670 return parsePostExp(e
);
4673 Expression
*Parser::parsePostExp(Expression
*e
)
4680 switch (token
.value
)
4684 if (token
.value
== TOKidentifier
)
4685 { Identifier
*id
= token
.ident
;
4688 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4689 { // identifier!(template-argument-list)
4690 TemplateInstance
*tempinst
;
4692 tempinst
= new TemplateInstance(loc
, id
);
4694 tempinst
->tiargs
= parseTemplateArgumentList();
4695 e
= new DotTemplateInstanceExp(loc
, e
, tempinst
);
4698 e
= new DotIdExp(loc
, e
, id
);
4701 else if (token
.value
== TOKnew
)
4707 error("identifier expected following '.', not '%s'", token
.toChars());
4711 e
= new PostExp(TOKplusplus
, loc
, e
);
4715 e
= new PostExp(TOKminusminus
, loc
, e
);
4719 e
= new CallExp(loc
, e
, parseArguments());
4723 { // array dereferences:
4726 // array[lwr .. upr]
4732 if (token
.value
== TOKrbracket
)
4734 e
= new SliceExp(loc
, e
, NULL
, NULL
);
4739 index
= parseAssignExp();
4740 if (token
.value
== TOKslice
)
4741 { // array[lwr .. upr]
4743 upr
= parseAssignExp();
4744 e
= new SliceExp(loc
, e
, index
, upr
);
4747 { // array[index, i2, i3, i4, ...]
4748 Expressions
*arguments
= new Expressions();
4749 arguments
->push(index
);
4750 if (token
.value
== TOKcomma
)
4756 arg
= parseAssignExp();
4757 arguments
->push(arg
);
4758 if (token
.value
== TOKrbracket
)
4763 e
= new ArrayExp(loc
, e
, arguments
);
4778 Expression
*Parser::parseUnaryExp()
4780 Loc loc
= this->loc
;
4782 switch (token
.value
)
4786 e
= parseUnaryExp();
4787 e
= new AddrExp(loc
, e
);
4792 e
= parseUnaryExp();
4793 e
= new AddAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
4798 e
= parseUnaryExp();
4799 e
= new MinAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
4804 e
= parseUnaryExp();
4805 e
= new PtrExp(loc
, e
);
4810 e
= parseUnaryExp();
4811 e
= new NegExp(loc
, e
);
4816 e
= parseUnaryExp();
4817 e
= new UAddExp(loc
, e
);
4822 e
= parseUnaryExp();
4823 e
= new NotExp(loc
, e
);
4828 e
= parseUnaryExp();
4829 e
= new ComExp(loc
, e
);
4834 e
= parseUnaryExp();
4835 e
= new DeleteExp(loc
, e
);
4839 e
= parseNewExp(NULL
);
4842 case TOKcast
: // cast(type) expression
4847 /* Look for cast(const) and cast(invariant)
4849 if ((token
.value
== TOKconst
|| token
.value
== TOKinvariant
) &&
4850 peek(&token
)->value
== TOKrparen
)
4851 { enum TOK tok
= token
.value
;
4854 e
= parseUnaryExp();
4855 e
= new CastExp(loc
, e
, tok
);
4859 t
= parseType(); // ( type )
4861 e
= parseUnaryExp();
4862 e
= new CastExp(loc
, e
, t
);
4873 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
4875 tk
= peek(tk
); // skip over right parenthesis
4895 case TOKimaginary32v
:
4896 case TOKimaginary64v
:
4897 case TOKimaginary80v
:
4917 CASE_BASIC_TYPES
: // (type)int.size
4926 if (token
.value
== TOKdot
)
4929 if (token
.value
!= TOKidentifier
)
4930 { error("Identifier expected following (type).");
4933 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4935 e
= parsePostExp(e
);
4939 e
= parseUnaryExp();
4940 e
= new CastExp(loc
, e
, t
);
4941 error("C style cast illegal, use %s", e
->toChars());
4948 e
= parsePrimaryExp();
4952 e
= parsePrimaryExp();
4959 Expression
*Parser::parseMulExp()
4962 Loc loc
= this->loc
;
4964 e
= parseUnaryExp();
4967 switch (token
.value
)
4969 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
4970 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
4971 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
4981 Expression
*Parser::parseAddExp()
4984 Loc loc
= this->loc
;
4989 switch (token
.value
)
4991 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
4992 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
4993 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
5003 Expression
*Parser::parseShiftExp()
5006 Loc loc
= this->loc
;
5011 switch (token
.value
)
5013 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
5014 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
5015 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
5025 Expression
*Parser::parseRelExp()
5029 Loc loc
= this->loc
;
5031 e
= parseShiftExp();
5034 switch (token
.value
)
5050 e2
= parseShiftExp();
5051 e
= new CmpExp(op
, loc
, e
, e2
);
5056 e2
= parseShiftExp();
5057 e
= new InExp(loc
, e
, e2
);
5068 Expression
*Parser::parseEqualExp()
5072 Loc loc
= this->loc
;
5076 { enum TOK value
= token
.value
;
5084 e
= new EqualExp(value
, loc
, e
, e2
);
5088 error("'===' is no longer legal, use 'is' instead");
5091 case TOKnotidentity
:
5092 error("'!==' is no longer legal, use '!is' instead");
5096 value
= TOKidentity
;
5100 // Attempt to identify '!is'
5102 if (t
->value
!= TOKis
)
5105 value
= TOKnotidentity
;
5111 e
= new IdentityExp(value
, loc
, e
, e2
);
5122 Expression
*Parser::parseCmpExp()
5126 Loc loc
= this->loc
;
5128 e
= parseShiftExp();
5129 enum TOK op
= token
.value
;
5136 e2
= parseShiftExp();
5137 e
= new EqualExp(op
, loc
, e
, e2
);
5145 // Attempt to identify '!is'
5147 if (t
->value
!= TOKis
)
5150 op
= TOKnotidentity
;
5155 e2
= parseShiftExp();
5156 e
= new IdentityExp(op
, loc
, e
, e2
);
5172 e2
= parseShiftExp();
5173 e
= new CmpExp(op
, loc
, e
, e2
);
5178 e2
= parseShiftExp();
5179 e
= new InExp(loc
, e
, e2
);
5188 Expression
*Parser::parseAndExp()
5191 Loc loc
= this->loc
;
5193 if (global
.params
.Dversion
== 1)
5195 e
= parseEqualExp();
5196 while (token
.value
== TOKand
)
5199 e2
= parseEqualExp();
5200 e
= new AndExp(loc
,e
,e2
);
5207 while (token
.value
== TOKand
)
5211 e
= new AndExp(loc
,e
,e2
);
5218 Expression
*Parser::parseXorExp()
5221 Loc loc
= this->loc
;
5224 while (token
.value
== TOKxor
)
5228 e
= new XorExp(loc
, e
, e2
);
5233 Expression
*Parser::parseOrExp()
5236 Loc loc
= this->loc
;
5239 while (token
.value
== TOKor
)
5243 e
= new OrExp(loc
, e
, e2
);
5248 Expression
*Parser::parseAndAndExp()
5251 Loc loc
= this->loc
;
5254 while (token
.value
== TOKandand
)
5258 e
= new AndAndExp(loc
, e
, e2
);
5263 Expression
*Parser::parseOrOrExp()
5266 Loc loc
= this->loc
;
5268 e
= parseAndAndExp();
5269 while (token
.value
== TOKoror
)
5272 e2
= parseAndAndExp();
5273 e
= new OrOrExp(loc
, e
, e2
);
5278 Expression
*Parser::parseCondExp()
5282 Loc loc
= this->loc
;
5285 if (token
.value
== TOKquestion
)
5288 e1
= parseExpression();
5290 e2
= parseCondExp();
5291 e
= new CondExp(loc
, e
, e1
, e2
);
5296 Expression
*Parser::parseAssignExp()
5305 switch (token
.value
)
5307 #define X(tok,ector) \
5308 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5310 X(TOKassign
, AssignExp
);
5311 X(TOKaddass
, AddAssignExp
);
5312 X(TOKminass
, MinAssignExp
);
5313 X(TOKmulass
, MulAssignExp
);
5314 X(TOKdivass
, DivAssignExp
);
5315 X(TOKmodass
, ModAssignExp
);
5316 X(TOKandass
, AndAssignExp
);
5317 X(TOKorass
, OrAssignExp
);
5318 X(TOKxorass
, XorAssignExp
);
5319 X(TOKshlass
, ShlAssignExp
);
5320 X(TOKshrass
, ShrAssignExp
);
5321 X(TOKushrass
, UshrAssignExp
);
5322 X(TOKcatass
, CatAssignExp
);
5333 Expression
*Parser::parseExpression()
5336 Loc loc
= this->loc
;
5338 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5339 e
= parseAssignExp();
5340 while (token
.value
== TOKcomma
)
5343 e2
= parseAssignExp();
5344 e
= new CommaExp(loc
, e
, e2
);
5351 /*************************
5352 * Collect argument list.
5353 * Assume current token is '(' or '['.
5356 Expressions
*Parser::parseArguments()
5358 Expressions
*arguments
;
5362 arguments
= new Expressions();
5363 if (token
.value
== TOKlbracket
)
5364 endtok
= TOKrbracket
;
5370 if (token
.value
!= endtok
)
5374 arg
= parseAssignExp();
5375 arguments
->push(arg
);
5376 if (token
.value
== endtok
)
5386 /*******************************************
5389 Expression
*Parser::parseNewExp(Expression
*thisexp
)
5391 Expressions
*newargs
;
5392 Expressions
*arguments
= NULL
;
5394 Loc loc
= this->loc
;
5398 if (token
.value
== TOKlparen
)
5400 newargs
= parseArguments();
5403 // An anonymous nested class starts with "class"
5404 if (token
.value
== TOKclass
)
5407 if (token
.value
== TOKlparen
)
5408 arguments
= parseArguments();
5410 BaseClasses
*baseclasses
= NULL
;
5411 if (token
.value
!= TOKlcurly
)
5412 baseclasses
= parseBaseClasses();
5414 Identifier
*id
= NULL
;
5415 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
);
5417 if (token
.value
!= TOKlcurly
)
5418 { error("{ members } expected for anonymous class");
5424 Array
*decl
= parseDeclDefs(0);
5425 if (token
.value
!= TOKrcurly
)
5426 error("class member expected");
5431 e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
5436 t
= parseBasicType();
5437 t
= parseBasicType2(t
);
5438 if (t
->ty
== Taarray
)
5439 { TypeAArray
*taa
= (TypeAArray
*)t
;
5440 Type
*index
= taa
->index
;
5442 Expression
*e
= index
->toExpression();
5444 { arguments
= new Expressions();
5446 t
= new TypeDArray(taa
->next
);
5450 error("need size of rightmost array, not type %s", index
->toChars());
5451 return new NullExp(loc
);
5454 else if (t
->ty
== Tsarray
)
5456 TypeSArray
*tsa
= (TypeSArray
*)t
;
5457 Expression
*e
= tsa
->dim
;
5459 arguments
= new Expressions();
5461 t
= new TypeDArray(tsa
->next
);
5463 else if (token
.value
== TOKlparen
)
5465 arguments
= parseArguments();
5467 e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
5471 /**********************************************
5474 void Parser::addComment(Dsymbol
*s
, unsigned char *blockComment
)
5476 s
->addComment(combineComments(blockComment
, token
.lineComment
));
5480 /********************************* ***************************/