2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 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 2004
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 C array declarations, such as
60 // Support left-to-right array declarations
61 #define LTORARRAYDECL 1
64 Parser::Parser(Module
*module
, unsigned char *base
, unsigned length
, int doDocComment
)
65 : Lexer(module
, base
, 0, length
, doDocComment
, 0, module
->isDltFile
)
67 //printf("Parser::Parser()\n");
70 dltNormalMode
= FALSE
;
73 startBlockTok
= TOKlcurly
;
74 //nextToken(); // start up the scanner
77 DltParser::DltParser(Module
*module
, unsigned char *base
, unsigned length
, int doDocComment
)
78 : Parser(module
, base
, length
, doDocComment
)
80 //printf("DltParser::DltParser(%s)\n", module->ident->string);
81 startBlockTok
= TOKcolon
;
82 dltNormalMode
= TRUE
; // becomes false if we find a "module dlt.*"
85 Array
*Parser::parseModule()
89 // ModuleDeclation leads off
91 if (token
.value
== TOKmodule
)
93 unsigned char *comment
= token
.blockComment
;
96 if (token
.value
!= TOKidentifier
)
97 { error("Identifier expected following module");
107 if (dltSyntax
&& id
== Id::dlt
)
108 dltNormalMode
= FALSE
;
110 while (nextToken() == TOKdot
)
116 if (token
.value
!= TOKidentifier
)
117 { error("Identifier expected following package");
123 md
= new ModuleDeclaration(a
, id
);
125 TOK end
= dltSyntax
? TOKendline
: TOKsemicolon
;
126 if (token
.value
!= end
)
127 error("%s expected following module declaration instead of %s", Token::toChars(end
), token
.toChars());
130 addComment(mod
, comment
);
134 decldefs
= parseDeclDefs(0);
135 if (token
.value
!= TOKeof
)
136 { error("unrecognized declaration '%s'", token
.toChars());
142 // Check for global variables
143 for (int i
= 0; i
< decldefs
->dim
; i
++)
145 Dsymbol
*d
= (Dsymbol
*) decldefs
->data
[i
];
146 if (d
->isVarDeclaration()) {
147 error("no global variables (%s) allowed in Delight; "
148 "try const, or put it in a class", d
->toChars());
156 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
162 Array
*Parser::parseDeclDefs(int once
)
169 Condition
*condition
;
170 unsigned char *comment
;
172 //printf("Parser::parseDeclDefs()\n");
173 decldefs
= new Array();
176 comment
= token
.blockComment
;
190 s
= parseAggregate();
194 s
= parseImport(decldefs
, 0);
198 s
= (Dsymbol
*)parseTemplateDeclaration();
202 { Loc loc
= this->loc
;
203 if (peek(&token
)->value
== TOKlparen
)
206 check(TOKlparen
, "mixin");
207 Expression
*e
= parseAssignExp();
210 s
= new CompileDeclaration(loc
, e
);
224 a
= parseDeclarations();
238 s
= parseInvariant();
240 if (peek(&token
)->value
== TOKlcurly
)
241 s
= parseInvariant();
268 if (token
.value
== TOKthis
)
270 s
= parseStaticCtor();
272 error("no static constructors in Delight");
274 else if (token
.value
== TOKtilde
)
276 s
= parseStaticDtor();
278 error("no static destructors in Delight");
280 else if (token
.value
== TOKassert
)
281 s
= parseStaticAssert();
282 else if (token
.value
== TOKif
)
283 { condition
= parseStaticIfCondition();
286 if (token
.value
== TOKelse
)
288 aelse
= parseBlock();
290 s
= new StaticIfDeclaration(condition
, a
, aelse
);
293 else if (token
.value
== TOKimport
)
295 s
= parseImport(decldefs
, 1);
299 if (dltNormalMode
&& token
.value
!= TOKclass
)
300 error("no static variables in Delight");
310 case TOKconst
: stc
= STCconst
; goto Lstc
;
311 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
312 case TOKauto
: stc
= STCauto
; goto Lstc
;
313 case TOKscope
: stc
= STCscope
; goto Lstc
;
314 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
315 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
316 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
317 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
324 case TOKconst
: stc
|= STCconst
; goto Lstc
;
325 case TOKfinal
: stc
|= STCfinal
; goto Lstc
;
326 case TOKauto
: stc
|= STCauto
; goto Lstc
;
327 case TOKscope
: stc
|= STCscope
; goto Lstc
;
328 case TOKoverride
: stc
|= STCoverride
; goto Lstc
;
329 case TOKabstract
: stc
|= STCabstract
; goto Lstc
;
330 case TOKsynchronized
: stc
|= STCsynchronized
; goto Lstc
;
331 case TOKdeprecated
: stc
|= STCdeprecated
; goto Lstc
;
332 //case TOKinvariant: stc |= STCinvariant; goto Lstc;
337 /* Look for auto initializers:
338 * storage_class identifier = initializer;
340 if (token
.value
== TOKidentifier
&&
341 peek(&token
)->value
== TOKassign
)
345 Identifier
*ident
= token
.ident
;
348 Initializer
*init
= parseInitializer();
349 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
350 v
->storage_class
= stc
;
352 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
356 else if (token
.value
== TOKcomma
)
359 if (token
.value
== TOKidentifier
&&
360 peek(&token
)->value
== TOKassign
)
363 addComment(s
, comment
);
367 error("Identifier expected following comma");
370 error("%s expected following declaration, not '%s'", endToken(), token
.toChars());
376 s
= new StorageClassDeclaration(stc
, a
);
381 if (peek(&token
)->value
!= TOKlparen
)
386 enum LINK linksave
= linkage
;
387 linkage
= parseLinkage();
389 s
= new LinkDeclaration(linkage
, a
);
393 error("access to external symbols can be done only by dlt.* modules");
396 case TOKprivate
: prot
= PROTprivate
; goto Lprot
;
397 case TOKpackage
: prot
= PROTpackage
; goto Lprot
;
398 case TOKprotected
: prot
= PROTprotected
; goto Lprot
;
399 case TOKpublic
: prot
= PROTpublic
; goto Lprot
;
400 case TOKexport
: prot
= PROTexport
; goto Lprot
;
405 s
= new ProtDeclaration(prot
, a
);
413 if (token
.value
== TOKlparen
)
416 if (token
.value
== TOKint32v
)
417 n
= (unsigned)token
.uns64value
;
419 { error("integer expected, not %s", token
.toChars());
426 n
= global
.structalign
; // default
429 s
= new AlignDeclaration(n
, a
);
435 Expressions
*args
= NULL
;
439 if (token
.value
!= TOKidentifier
)
440 { error("pragma(identifier expected");
445 if (token
.value
== TOKcomma
)
446 args
= parseArguments(); // pragma(identifier, args...)
448 check(TOKrparen
); // pragma(identifier)
450 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
455 a
= parseDeclDefs(0);
460 s
= new PragmaDeclaration(loc
, ident
, args
, a
);
466 if (token
.value
== TOKassign
)
469 if (token
.value
== TOKidentifier
)
470 s
= new DebugSymbol(loc
, token
.ident
);
471 else if (token
.value
== TOKint32v
)
472 s
= new DebugSymbol(loc
, (unsigned)token
.uns64value
);
474 { error("identifier or integer expected, not %s", token
.toChars());
478 if (token
.value
!= TOKsemicolon
)
479 error("semicolon expected");
484 condition
= parseDebugCondition();
489 if (token
.value
== TOKassign
)
492 if (token
.value
== TOKidentifier
)
493 s
= new VersionSymbol(loc
, token
.ident
);
494 else if (token
.value
== TOKint32v
)
495 s
= new VersionSymbol(loc
, (unsigned)token
.uns64value
);
497 { error("identifier or integer expected, not %s", token
.toChars());
501 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
)
502 error("%s expected after version assignment", endToken());
506 condition
= parseVersionCondition();
512 if (token
.value
== TOKelse
)
514 aelse
= parseBlock();
516 s
= new ConditionalDeclaration(condition
, a
, aelse
);
519 case TOKsemicolon
: // empty declaration
524 error("Declaration expected, not '%s'",token
.toChars());
526 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
&& token
.value
!= TOKeof
)
534 addComment(s
, comment
);
541 /********************************************
542 * Parse declarations after an align, protection, or extern decl.
545 Array
*Parser::parseBlock()
550 //printf("Parser::parseBlock()\n");
554 error("declaration expected following attribute, not ';'");
560 a
= parseDeclDefs(0);
561 if (token
.value
!= TOKrcurly
)
563 error("matching '}' expected, not %s", token
.toChars());
574 a
= parseDeclDefs(0); // grab declarations up to closing curly bracket
579 a
= parseDeclDefs(1);
585 Array
*DltParser::parseBlock()
595 error("declaration expected following attribute, not %s", token
.toChars());
601 a
= parseDeclDefs(0);
602 if (token
.value
!= TOKrcurly
)
604 error("matching end-of-block expected, not %s", token
.toChars());
611 a
= parseDeclDefs(1);
617 /**********************************
618 * Parse a static assertion.
621 StaticAssert
*Parser::parseStaticAssert()
625 Expression
*msg
= NULL
;
627 //printf("parseStaticAssert()\n");
630 exp
= parseAssignExp();
631 if (token
.value
== TOKcomma
)
633 msg
= parseAssignExp();
636 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
) {
638 return new StaticAssert(loc
, exp
, msg
);
640 error("expected %s after static assert", endToken());
644 /***********************************
645 * Parse extern (linkage)
646 * The parser is on the 'extern' token.
649 enum LINK
Parser::parseLinkage()
651 enum LINK link
= LINKdefault
;
653 assert(token
.value
== TOKlparen
);
655 if (token
.value
== TOKidentifier
)
656 { Identifier
*id
= token
.ident
;
659 if (id
== Id::Windows
)
661 else if (id
== Id::Pascal
)
663 else if (id
== Id::D
)
665 else if (id
== Id::C
)
668 if (token
.value
== TOKplusplus
)
673 else if (id
== Id::System
)
676 link
= d_gcc_is_target_win32() ? LINKwindows
: LINKc
;
687 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
693 link
= LINKd
; // default
699 /**************************************
700 * Parse a debug conditional
703 Condition
*Parser::parseDebugCondition()
707 if (token
.value
== TOKlparen
)
711 Identifier
*id
= NULL
;
713 if (token
.value
== TOKidentifier
)
715 else if (token
.value
== TOKint32v
)
716 level
= (unsigned)token
.uns64value
;
718 error("identifier or integer expected, not %s", token
.toChars());
721 c
= new DebugCondition(mod
, level
, id
);
722 if (dltSyntax
&& token
.value
!= TOKcolon
)
723 error("expected colon after debug(), not '%s'", token
.toChars());
725 if (dltSyntax
&& token
.value
!= TOKcolon
)
726 error("expected ':' or '(' after 'debug', not '%s'", token
.toChars());
727 c
= new DebugCondition(mod
, 1, NULL
);
733 /**************************************
734 * Parse a version conditional
737 Condition
*Parser::parseVersionCondition()
741 Identifier
*id
= NULL
;
743 if (token
.value
== TOKlparen
)
746 if (token
.value
== TOKidentifier
)
748 else if (token
.value
== TOKint32v
)
749 level
= (unsigned)token
.uns64value
;
753 * even though unittest is a keyword
755 else if (token
.value
== TOKunittest
)
756 id
= Lexer::idPool(Token::toChars(TOKunittest
));
759 error("identifier or integer expected, not %s", token
.toChars());
765 error("(condition) expected following version");
766 c
= new VersionCondition(mod
, level
, id
);
771 /***********************************************
772 * static if (expression)
778 Condition
*Parser::parseStaticIfCondition()
780 Condition
*condition
;
787 exp
= parseAssignExp();
790 condition
= new StaticIfCondition(loc
, exp
);
795 /*****************************************
796 * Parse a constructor definition:
797 * this(arguments) { body }
798 * Current token is 'this'.
801 CtorDeclaration
*Parser::parseCtor()
804 Arguments
*arguments
;
809 arguments
= parseParameters(&varargs
);
810 f
= new CtorDeclaration(loc
, 0, arguments
, varargs
);
815 /*****************************************
816 * Parse a destructor definition:
818 * Current token is '~'.
821 DtorDeclaration
*Parser::parseDtor()
831 f
= new DtorDeclaration(loc
, 0);
836 /*****************************************
837 * Parse a static constructor definition:
838 * static this() { body }
839 * Current token is 'this'.
842 StaticCtorDeclaration
*Parser::parseStaticCtor()
844 StaticCtorDeclaration
*f
;
851 f
= new StaticCtorDeclaration(loc
, 0);
856 /*****************************************
857 * Parse a static destructor definition:
858 * static ~this() { body }
859 * Current token is '~'.
862 StaticDtorDeclaration
*Parser::parseStaticDtor()
864 StaticDtorDeclaration
*f
;
872 f
= new StaticDtorDeclaration(loc
, 0);
877 /*****************************************
878 * Parse an invariant definition:
880 * Current token is 'invariant'.
883 InvariantDeclaration
*Parser::parseInvariant()
885 InvariantDeclaration
*f
;
889 if (token
.value
== TOKlparen
) // optional ()
895 f
= new InvariantDeclaration(loc
, 0);
896 f
->fbody
= parseStatement(PScurly
);
900 /*****************************************
901 * Parse a unittest definition:
903 * Current token is 'unittest'.
906 UnitTestDeclaration
*Parser::parseUnitTest()
908 UnitTestDeclaration
*f
;
914 body
= parseStatement(PScurly
);
916 f
= new UnitTestDeclaration(loc
, this->loc
);
921 /*****************************************
922 * Parse a new definition:
923 * new(arguments) { body }
924 * Current token is 'new'.
927 NewDeclaration
*Parser::parseNew()
930 Arguments
*arguments
;
935 arguments
= parseParameters(&varargs
);
936 f
= new NewDeclaration(loc
, 0, arguments
, varargs
);
941 /*****************************************
942 * Parse a delete definition:
943 * delete(arguments) { body }
944 * Current token is 'delete'.
947 DeleteDeclaration
*Parser::parseDelete()
949 DeleteDeclaration
*f
;
950 Arguments
*arguments
;
955 arguments
= parseParameters(&varargs
);
957 error("... not allowed in delete function parameter list");
958 f
= new DeleteDeclaration(loc
, 0, arguments
);
963 /**********************************************
964 * Parse parameter list.
967 Arguments
*Parser::parseParameters(int *pvarargs
)
969 Arguments
*arguments
= new Arguments();
979 unsigned storageClass
;
983 storageClass
= STCin
; // parameter is "in" by default
995 storageClass
= STCin
;
1000 storageClass
= STCout
;
1006 storageClass
= STCref
;
1011 storageClass
= STClazy
;
1017 tb
= parseBasicType();
1018 at
= parseDeclarator(tb
, &ai
);
1020 if (token
.value
== TOKassign
) // = defaultArg
1022 ae
= parseAssignExp();
1027 error("default argument expected for %s",
1028 ai
? ai
->toChars() : at
->toChars());
1030 if (token
.value
== TOKdotdotdot
)
1035 if (storageClass
& (STCout
| STCref
))
1036 error("variadic argument cannot be out or ref");
1038 a
= new Argument(storageClass
, at
, ai
, ae
);
1043 a
= new Argument(storageClass
, at
, ai
, ae
);
1045 if (token
.value
== TOKcomma
)
1054 *pvarargs
= varargs
;
1059 /*************************************
1062 EnumDeclaration
*Parser::parseEnum()
1063 { EnumDeclaration
*e
;
1066 Loc loc
= this->loc
;
1068 //printf("Parser::parseEnum()\n");
1070 if (token
.value
== TOKidentifier
)
1077 if (token
.value
== (dltSyntax
? TOKextends
: TOKcolon
))
1080 t
= parseBasicType();
1085 e
= new EnumDeclaration(loc
, id
, t
);
1086 if (token
.value
== TOKsemicolon
&& id
)
1088 else if (token
.value
== startBlockTok
)
1090 //printf("enum definition\n");
1091 e
->members
= new Array();
1093 unsigned char *comment
= token
.blockComment
;
1095 while (token
.value
!= TOKrcurly
)
1097 if (token
.value
== TOKidentifier
)
1103 ident
= token
.ident
;
1106 if (token
.value
== TOKassign
)
1109 value
= parseAssignExp();
1111 em
= new EnumMember(loc
, ident
, value
);
1112 e
->members
->push(em
);
1114 if (token
.value
== TOKrcurly
)
1117 { addComment(em
, comment
);
1122 addComment(em
, comment
);
1123 comment
= token
.blockComment
;
1126 { error("enum member expected");
1133 error("enum declaration is invalid");
1138 Dsymbol
*Parser::parseAggregate()
1139 { AggregateDeclaration
*a
= NULL
;
1143 TemplateParameters
*tpl
= NULL
;
1145 //printf("Parser::parseAggregate()\n");
1148 if (token
.value
!= TOKidentifier
)
1155 if (token
.value
== TOKlparen
)
1156 { // Class template declaration.
1158 // Gather template parameter list
1159 tpl
= parseTemplateParameterList();
1163 Loc loc
= this->loc
;
1169 error("anonymous classes not allowed");
1171 // Collect base class(es)
1172 BaseClasses
*baseclasses
= parseBaseClasses();
1173 if (baseclasses
&& token
.value
!= startBlockTok
) {
1174 error("members expected");
1177 if (tok
== TOKclass
)
1178 a
= new ClassDeclaration(loc
, id
, baseclasses
);
1180 a
= new InterfaceDeclaration(loc
, id
, baseclasses
);
1186 a
= new StructDeclaration(loc
, id
);
1193 a
= new UnionDeclaration(loc
, id
);
1202 if (a
&& token
.value
== (dltSyntax
? TOKendline
: TOKsemicolon
))
1205 else if (token
.value
== startBlockTok
)
1207 //printf("aggregate definition\n");
1210 Array
*decl
= parseDeclDefs(0);
1211 if (token
.value
!= TOKrcurly
)
1212 error("end-of-block expected following member declarations in aggregate");
1216 /* Anonymous structs/unions are more like attributes.
1218 return new AnonDeclaration(loc
, anon
- 1, decl
);
1225 error("%s expected following aggregate declaration", Token::toChars(startBlockTok
));
1226 a
= new StructDeclaration(loc
, NULL
);
1231 TemplateDeclaration
*tempdecl
;
1233 // Wrap a template around the aggregate declaration
1234 decldefs
= new Array();
1236 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
, dltSyntax
);
1243 /*******************************************
1246 /* If current token is TOKcolon, TOKextends or TOKimplements, return
1247 * the bases. Otherwise, return null.
1249 BaseClasses
*Parser::parseBaseClasses()
1251 enum PROT protection
= PROTpublic
;
1252 int type
; // 1 = extends, 2 = implements, 3 = unknown
1255 if (token
.value
== TOKextends
)
1257 else if (token
.value
== TOKimplements
)
1262 if (token
.value
== TOKcolon
)
1270 BaseClasses
*baseclasses
= new BaseClasses();
1272 for (; 1; nextToken())
1274 switch (token
.value
)
1279 protection
= PROTprivate
;
1282 protection
= PROTpackage
;
1285 protection
= PROTprotected
;
1288 protection
= PROTpublic
;
1291 error("base classes expected instead of %s", token
.toChars());
1294 BaseClass
*b
= new BaseClass(parseBasicType(), protection
);
1295 baseclasses
->push(b
);
1297 protection
= PROTpublic
;
1299 switch (token
.value
) {
1304 error("extends part must come before implements");
1306 error("only one extends is permitted");
1312 error("separate implemented interfaces with commas");
1320 /**************************************
1321 * Parse a TemplateDeclaration.
1324 TemplateDeclaration
*Parser::parseTemplateDeclaration()
1326 TemplateDeclaration
*tempdecl
;
1328 TemplateParameters
*tpl
;
1330 Loc loc
= this->loc
;
1333 if (token
.value
!= TOKidentifier
)
1334 { error("TemplateIdentifier expected following template");
1339 tpl
= parseTemplateParameterList();
1343 if (token
.value
!= startBlockTok
)
1344 { error("members of template declaration expected");
1350 decldefs
= parseDeclDefs(0);
1351 if (token
.value
!= TOKrcurly
)
1352 { error("template member expected");
1358 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
, dltSyntax
);
1365 /******************************************
1366 * Parse template parameter list.
1369 TemplateParameters
*Parser::parseTemplateParameterList()
1371 TemplateParameters
*tpl
= new TemplateParameters();
1373 if (token
.value
!= TOKlparen
)
1374 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1379 // Get array of TemplateParameters
1380 if (token
.value
!= TOKrparen
)
1381 { int isvariadic
= 0;
1384 { TemplateParameter
*tp
;
1385 Identifier
*tp_ident
= NULL
;
1386 Type
*tp_spectype
= NULL
;
1387 Type
*tp_valtype
= NULL
;
1388 Type
*tp_defaulttype
= NULL
;
1389 Expression
*tp_specvalue
= NULL
;
1390 Expression
*tp_defaultvalue
= NULL
;
1393 // Get TemplateParameter
1395 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1397 if (token
.value
== TOKalias
)
1400 if (token
.value
!= TOKidentifier
)
1401 { error("Identifier expected for template parameter");
1404 tp_ident
= token
.ident
;
1406 if (token
.value
== TOKcolon
) // : Type
1409 tp_spectype
= parseBasicType();
1410 tp_spectype
= parseDeclarator(tp_spectype
, NULL
);
1412 if (token
.value
== TOKassign
) // = Type
1415 tp_defaulttype
= parseBasicType();
1416 tp_defaulttype
= parseDeclarator(tp_defaulttype
, NULL
);
1418 tp
= new TemplateAliasParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1420 else if (t
->value
== TOKcolon
|| t
->value
== TOKassign
||
1421 t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
1423 if (token
.value
!= TOKidentifier
)
1424 { error("Identifier expected for template parameter");
1427 tp_ident
= token
.ident
;
1429 if (token
.value
== TOKcolon
) // : Type
1432 tp_spectype
= parseBasicType();
1433 tp_spectype
= parseDeclarator(tp_spectype
, NULL
);
1435 if (token
.value
== TOKassign
) // = Type
1438 tp_defaulttype
= parseBasicType();
1439 tp_defaulttype
= parseDeclarator(tp_defaulttype
, NULL
);
1441 tp
= new TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1443 else if (token
.value
== TOKidentifier
&& t
->value
== TOKdotdotdot
)
1446 error("variadic template parameter must be last");
1448 tp_ident
= token
.ident
;
1451 tp
= new TemplateTupleParameter(loc
, tp_ident
);
1455 tp_valtype
= parseBasicType();
1456 tp_valtype
= parseDeclarator(tp_valtype
, &tp_ident
);
1459 error("no identifier for template value parameter");
1460 tp_ident
= new Identifier("error", TOKidentifier
);
1462 if (token
.value
== TOKcolon
) // : CondExpression
1465 tp_specvalue
= parseCondExp();
1467 if (token
.value
== TOKassign
) // = CondExpression
1470 tp_defaultvalue
= parseCondExp();
1472 tp
= new TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1475 if (token
.value
!= TOKcomma
)
1485 /******************************************
1486 * Parse template mixin.
1489 * mixin a.b.c!(args).Foo!(args);
1490 * mixin Foo!(args) identifier;
1491 * mixin typeof(expr).identifier!(args);
1494 Dsymbol
*Parser::parseMixin()
1502 //printf("parseMixin()\n");
1505 if (token
.value
== TOKdot
)
1511 if (token
.value
== TOKtypeof
)
1516 exp
= parseExpression();
1518 tqual
= new TypeTypeof(loc
, exp
);
1521 if (token
.value
!= TOKidentifier
)
1523 error("identifier expected, not %s", token
.toChars());
1530 idents
= new Array();
1534 if (token
.value
== TOKnot
)
1537 tiargs
= parseTemplateArgumentList();
1540 if (token
.value
!= TOKdot
)
1544 { TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
1545 tempinst
->tiargs
= tiargs
;
1546 id
= (Identifier
*)tempinst
;
1552 if (token
.value
!= TOKidentifier
)
1553 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1561 if (token
.value
== TOKidentifier
)
1569 tm
= new TemplateMixin(loc
, id
, tqual
, idents
, tiargs
);
1570 if (token
.value
!= TOKsemicolon
)
1571 error("';' expected after mixin");
1580 /******************************************
1581 * Parse template argument list.
1583 * current token is opening '('
1585 * current token is one after closing ')'
1588 Objects
*Parser::parseTemplateArgumentList()
1590 //printf("Parser::parseTemplateArgumentList()\n");
1591 Objects
*tiargs
= new Objects();
1592 if (token
.value
!= TOKlparen
)
1593 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1598 // Get TemplateArgumentList
1599 if (token
.value
!= TOKrparen
)
1603 // See if it is an Expression or a Type
1604 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
1608 // Get TemplateArgument
1609 ta
= parseBasicType();
1610 ta
= parseDeclarator(ta
, NULL
);
1617 ea
= parseAssignExp();
1620 if (token
.value
!= TOKcomma
)
1625 check(TOKrparen
, "template argument list");
1629 Import
*Parser::parseImport(Array
*decldefs
, int isstatic
)
1632 Identifier
*aliasid
= NULL
;
1636 //printf("Parser::parseImport()\n");
1641 if (token
.value
!= TOKidentifier
)
1642 { error("Identifier expected following import");
1650 if (!aliasid
&& token
.value
== TOKassign
)
1655 while (token
.value
== TOKdot
)
1661 if (token
.value
!= TOKidentifier
)
1662 { error("Identifier expected following package");
1669 s
= new Import(loc
, a
, token
.ident
, aliasid
, isstatic
);
1673 * : alias=name, alias=name;
1676 if (token
.value
== TOKcolon
)
1685 if (dltSyntax
&& token
.value
== TOKrcurly
)
1687 if (token
.value
!= TOKidentifier
)
1688 { error("Identifier expected following :");
1691 alias
= token
.ident
;
1693 if (token
.value
== TOKassign
)
1696 if (token
.value
!= TOKidentifier
)
1697 { error("Identifier expected following %s=", alias
->toChars());
1707 s
->addAlias(name
, alias
);
1708 if (token
.value
!= TOKcomma
&& token
.value
!= TOKendline
)
1722 } while (token
.value
== TOKcomma
);
1724 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
1728 error("%s expected", endToken());
1735 Type
*Parser::parseBasicType()
1739 TemplateInstance
*tempinst
;
1741 //printf("parseBasicType()\n");
1742 switch (token
.value
)
1744 CASE_BASIC_TYPES_X(t
):
1751 if (token
.value
== TOKnot
)
1754 tempinst
= new TemplateInstance(loc
, id
);
1755 tempinst
->tiargs
= parseTemplateArgumentList();
1756 tid
= new TypeInstance(loc
, tempinst
);
1760 tid
= new TypeIdentifier(loc
, id
);
1762 while (token
.value
== TOKdot
)
1764 if (token
.value
!= TOKidentifier
)
1765 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1770 if (token
.value
== TOKnot
)
1773 tempinst
= new TemplateInstance(loc
, id
);
1774 tempinst
->tiargs
= parseTemplateArgumentList();
1775 tid
->addIdent((Identifier
*)tempinst
);
1792 exp
= parseExpression();
1794 tid
= new TypeTypeof(loc
, exp
);
1799 error("basic type expected, not %s", token
.toChars());
1806 Type
*Parser::parseBasicType2(Type
*t
)
1811 //printf("parseBasicType2()\n");
1814 switch (token
.value
)
1817 t
= new TypePointer(t
);
1823 // Handle []. Make sure things like
1825 // is (array[1] of array[3] of int)
1827 if (token
.value
== TOKrbracket
)
1829 t
= new TypeDArray(t
); // []
1832 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
1833 { // It's an associative array declaration
1836 //printf("it's an associative array\n");
1837 index
= parseBasicType();
1838 index
= parseDeclarator(index
, NULL
); // [ type ]
1839 t
= new TypeAArray(t
, index
);
1844 //printf("it's [expression]\n");
1846 Expression
*e
= parseExpression(); // [ expression ]
1847 if (token
.value
== TOKslice
)
1851 e2
= parseExpression(); // [ exp .. exp ]
1852 t
= new TypeSlice(t
, e
, e2
);
1855 t
= new TypeSArray(t
,e
);
1861 // Handle []. Make sure things like
1863 // is (array[3] of array[1] of int)
1865 while (token
.value
== TOKlbracket
)
1868 if (token
.value
== TOKrbracket
)
1870 ta
= new TypeDArray(t
); // []
1873 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
1874 { // It's an associative array declaration
1877 //printf("it's an associative array\n");
1878 index
= parseBasicType();
1879 index
= parseDeclarator(index
, NULL
); // [ type ]
1881 ta
= new TypeAArray(t
, index
);
1885 //printf("it's [expression]\n");
1886 Expression
*e
= parseExpression(); // [ expression ]
1887 ta
= new TypeSArray(t
,e
);
1891 for (pt
= &ts
; *pt
!= t
; pt
= &(*pt
)->next
)
1901 { // Handle delegate declaration:
1902 // t delegate(parameter list)
1903 // t function(parameter list)
1904 Arguments
*arguments
;
1906 enum TOK save
= token
.value
;
1909 arguments
= parseParameters(&varargs
);
1910 t
= new TypeFunction(arguments
, t
, varargs
, linkage
);
1911 if (save
== TOKdelegate
)
1912 t
= new TypeDelegate(t
);
1914 t
= new TypePointer(t
); // pointer to function
1924 error("Type %s cannot be null; ? is pointless", old
->toChars());
1928 // fall-through to default
1941 // Don't wrap it yet, because that confuses resolve()
1942 ((TypeIdentifier
*) ts
)->maybe
= 1;
1945 // TypeMaybe will unwrap itself later if this isn't a nullable type
1954 Type
*Parser::parseDeclarator(Type
*t
, Identifier
**pident
, TemplateParameters
**tpl
)
1958 //printf("parseDeclarator(tpl = %p)\n", tpl);
1959 t
= parseBasicType2(t
);
1961 switch (token
.value
)
1966 *pident
= token
.ident
;
1968 error("unexpected identifer '%s' in declarator", token
.ident
->toChars());
1975 ts
= parseDeclarator(t
, pident
);
1986 switch (token
.value
)
1990 { // This is the old C-style post [] syntax.
1992 if (token
.value
== TOKrbracket
)
1994 ta
= new TypeDArray(t
); // []
1997 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
1998 { // It's an associative array declaration
2001 //printf("it's an associative array\n");
2002 index
= parseBasicType();
2003 index
= parseDeclarator(index
, NULL
); // [ type ]
2005 ta
= new TypeAArray(t
, index
);
2009 //printf("it's [expression]\n");
2010 Expression
*e
= parseExpression(); // [ expression ]
2011 ta
= new TypeSArray(t
, e
);
2015 for (pt
= &ts
; *pt
!= t
; pt
= &(*pt
)->next
)
2022 { Arguments
*arguments
;
2027 /* Look ahead to see if this is (...)(...),
2028 * i.e. a function template declaration
2030 if (peekPastParen(&token
)->value
== TOKlparen
)
2031 { // It's a function template declaration
2032 //printf("function template declaration\n");
2034 // Gather template parameter list
2035 *tpl
= parseTemplateParameterList();
2039 arguments
= parseParameters(&varargs
);
2040 Type
*ta
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2042 for (pt
= &ts
; *pt
!= t
; pt
= &(*pt
)->next
)
2054 /**********************************
2055 * Return array of Declaration *'s.
2058 Array
*Parser::parseDeclarations()
2060 enum STC storage_class
;
2068 unsigned char *comment
= token
.blockComment
;
2069 enum LINK link
= linkage
;
2071 //printf("parseDeclarations()\n");
2072 switch (token
.value
)
2085 storage_class
= STCundefined
;
2088 switch (token
.value
)
2090 case TOKconst
: stc
= STCconst
; goto L1
;
2091 case TOKstatic
: stc
= STCstatic
; goto L1
;
2092 case TOKfinal
: stc
= STCfinal
; goto L1
;
2093 case TOKauto
: stc
= STCauto
; goto L1
;
2094 case TOKscope
: stc
= STCscope
; goto L1
;
2095 case TOKoverride
: stc
= STCoverride
; goto L1
;
2096 case TOKabstract
: stc
= STCabstract
; goto L1
;
2097 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
2098 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
2100 if (storage_class
& stc
)
2101 error("redundant storage class '%s'", token
.toChars());
2102 storage_class
= (STC
) (storage_class
| stc
);
2107 if (peek(&token
)->value
!= TOKlparen
)
2112 link
= parseLinkage();
2123 /* Look for auto initializers:
2124 * storage_class identifier = initializer;
2126 while (storage_class
&&
2127 token
.value
== TOKidentifier
&&
2128 peek(&token
)->value
== TOKassign
)
2130 ident
= token
.ident
;
2133 Initializer
*init
= parseInitializer();
2134 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
2135 v
->storage_class
= storage_class
;
2137 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
2140 addComment(v
, comment
);
2142 else if (token
.value
== TOKcomma
)
2145 if (!(token
.value
== TOKidentifier
&& peek(&token
)->value
== TOKassign
))
2147 error("Identifier expected following comma");
2153 error("%s expected following auto declaration, not '%s'", endToken(), token
.toChars());
2157 if (token
.value
== TOKclass
)
2158 { AggregateDeclaration
*s
;
2160 s
= (AggregateDeclaration
*)parseAggregate();
2161 s
->storage_class
|= storage_class
;
2163 addComment(s
, comment
);
2167 ts
= parseBasicType();
2168 ts
= parseBasicType2(ts
);
2173 Loc loc
= this->loc
;
2174 TemplateParameters
*tpl
= NULL
;
2177 t
= parseDeclarator(ts
, &ident
, &tpl
);
2181 else if (t
!= tfirst
)
2182 error("multiple declarations must have the same type, not %s and %s",
2183 tfirst
->toChars(), t
->toChars());
2185 error("no identifier for declarator %s", t
->toChars());
2187 if (tok
== TOKtypedef
|| tok
== TOKalias
)
2193 /* Unwrap maybe qualifiers from aliases.
2194 * Otherwise, it thinks we're aliasing types when we're not.
2196 if (t
->ty
== Tmaybe
) {
2202 if (token
.value
== TOKassign
)
2205 init
= parseInitializer();
2207 if (tok
== TOKtypedef
)
2208 v
= new TypedefDeclaration(loc
, ident
, t
, init
);
2211 error("alias cannot have initializer");
2212 v
= new AliasDeclaration(loc
, ident
, t
);
2214 v
->storage_class
= storage_class
;
2215 if (link
== linkage
)
2219 Array
*ax
= new Array();
2221 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2224 switch (token
.value
)
2225 { case TOKsemicolon
:
2228 addComment(v
, comment
);
2233 addComment(v
, comment
);
2237 error("%s expected to close %s declaration", endToken(), Token::toChars(tok
));
2241 else if (t
->ty
== Tfunction
)
2242 { FuncDeclaration
*f
;
2245 f
= new FuncDeclaration(loc
, 0, ident
, storage_class
, t
);
2246 addComment(f
, comment
);
2248 addComment(f
, NULL
);
2249 if (link
== linkage
)
2255 Array
*ax
= new Array();
2257 s
= new LinkDeclaration(link
, ax
);
2259 if (tpl
) // it's a function template
2261 TemplateDeclaration
*tempdecl
;
2263 // Wrap a template around the aggregate declaration
2264 decldefs
= new Array();
2266 tempdecl
= new TemplateDeclaration(loc
, s
->ident
, tpl
, decldefs
, dltSyntax
);
2269 addComment(s
, comment
);
2273 { VarDeclaration
*v
;
2277 if (token
.value
== TOKassign
)
2280 init
= parseInitializer();
2282 v
= new VarDeclaration(loc
, t
, ident
, init
);
2283 v
->storage_class
= storage_class
;
2284 if (link
== linkage
)
2288 Array
*ax
= new Array();
2290 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2293 switch (token
.value
)
2297 addComment(v
, comment
);
2302 addComment(v
, comment
);
2306 addComment(v
, comment
);
2310 error("%s expected, not '%s'", endToken(), token
.toChars());
2319 /*****************************************
2320 * Parse contracts following function declaration.
2323 void Parser::parseContracts(FuncDeclaration
*f
)
2326 enum LINK linksave
= linkage
;
2328 // The following is irrelevant, as it is overridden by sc->linkage in
2329 // TypeFunction::semantic
2330 linkage
= LINKd
; // nested functions have D linkage
2332 switch (token
.value
)
2336 if (token
.value
!= startBlockTok
)
2337 error("use %s to start a new block", Token::toChars(startBlockTok
));
2338 if (f
->frequire
|| f
->fensure
)
2339 error("missing body { ... } after in or out");
2340 f
->fbody
= parseStatement(PSsemi
| PScolon
);
2346 f
->fbody
= parseStatement(PScurly
);
2352 error("unexpected semi-colon after function declaration");
2355 if (f
->frequire
|| f
->fensure
)
2356 error("missing body { ... } after in or out");
2360 #if 0 // Do we want this for function declarations, so we can do:
2361 // int x, y, foo(), z;
2367 #if 0 // Dumped feature
2370 f
->fthrows
= new Array();
2375 tb
= parseBasicType();
2376 f
->fthrows
->push(tb
);
2377 if (token
.value
== TOKcomma
)
2390 error("redundant 'in' statement");
2391 f
->frequire
= parseStatement(PScurly
| PSscope
);
2395 // parse: out (identifier) { statement }
2397 if (token
.value
!= startBlockTok
)
2400 if (token
.value
!= TOKidentifier
)
2401 error("(identifier) following 'out' expected, not %s", token
.toChars());
2402 f
->outId
= token
.ident
;
2407 error("redundant 'out' statement");
2408 f
->fensure
= parseStatement(PScurly
| PSscope
);
2412 error("%s expected following function declaration", endToken());
2418 /*****************************************
2421 Initializer
*Parser::parseInitializer()
2423 StructInitializer
*is
;
2424 ArrayInitializer
*ia
;
2430 Loc loc
= this->loc
;
2434 switch (token
.value
)
2437 /* Scan ahead to see if it is a struct initializer or
2438 * a function literal.
2439 * If it contains a ';', it is a function literal.
2440 * Treat { } as a struct initializer.
2443 for (t
= peek(&token
); 1; t
= peek(t
))
2469 is
= new StructInitializer(loc
);
2474 switch (token
.value
)
2478 error("comma expected separating field initializers");
2480 if (t
->value
== TOKcolon
)
2484 nextToken(); // skip over ':'
2489 value
= parseInitializer();
2490 is
->addInit(id
, value
);
2499 case TOKrcurly
: // allow trailing comma's
2504 error("found EOF instead of initializer");
2508 value
= parseInitializer();
2509 is
->addInit(NULL
, value
);
2512 //error("found '%s' instead of field initializer", token.toChars());
2520 ia
= new ArrayInitializer(loc
);
2525 switch (token
.value
)
2529 { error("comma expected separating array initializers, not %s", token
.toChars());
2533 e
= parseAssignExp();
2536 if (token
.value
== TOKcolon
)
2539 value
= parseInitializer();
2542 { value
= new ExpInitializer(e
->loc
, e
);
2545 ia
->addInit(e
, value
);
2552 error("comma expected separating array initializers, not %s", token
.toChars());
2553 value
= parseInitializer();
2554 ia
->addInit(NULL
, value
);
2563 case TOKrbracket
: // allow trailing comma's
2568 error("found '%s' instead of array initializer", token
.toChars());
2577 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
|| t
->value
== TOKendline
)
2580 return new VoidInitializer(loc
);
2586 e
= parseAssignExp();
2587 ie
= new ExpInitializer(loc
, e
);
2592 Statement
*Parser::logStatement(int level
) {
2594 if (token
.value
!= TOKlparen
)
2595 error(loc
, "found '%s' when expecting '('", token
.toChars());
2596 return new LogStatement(loc
, level
, parseArguments());
2599 /*****************************************
2604 Statement
*DltParser::parseStatement(int flags
)
2607 if (flags
& (PScolon
| PSscope
))
2609 return Parser::parseStatement(flags
);
2612 Statement
*Parser::parseStatement(int flags
)
2615 Condition
*condition
;
2617 Statement
*elsebody
;
2618 Loc loc
= this->loc
;
2620 //printf("parseStatement()\n");
2622 if ((flags
& PScurly
) && token
.value
!= startBlockTok
)
2623 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
2625 int tok
= token
.value
;
2627 switch (token
.value
)
2632 // Need to look ahead to see if it is a declaration, label, or expression
2634 if (t
->value
== TOKcolon
)
2638 ident
= token
.ident
;
2641 s
= parseStatement(PSsemi
);
2642 s
= new LabelStatement(loc
, ident
, s
);
2646 // fallthrough to TOKdot
2649 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2665 case TOKimaginary32v
:
2666 case TOKimaginary64v
:
2667 case TOKimaginary80v
:
2692 exp
= parseExpression();
2694 check(TOKsemicolon
, "statement");
2695 s
= new ExpStatement(loc
, exp
);
2700 { // Look ahead to see if it's static assert() or static if()
2704 if (t
->value
== TOKassert
)
2707 s
= new StaticAssertStatement(parseStaticAssert());
2710 if (t
->value
== TOKif
)
2713 condition
= parseStaticIfCondition();
2717 error("no static variables in Delight");
2733 a
= parseDeclarations();
2736 Statements
*as
= new Statements();
2737 as
->reserve(a
->dim
);
2738 for (int i
= 0; i
< a
->dim
; i
++)
2740 Dsymbol
*d
= (Dsymbol
*)a
->data
[i
];
2741 s
= new DeclarationStatement(loc
, d
);
2744 s
= new CompoundStatement(loc
, as
);
2746 else if (a
->dim
== 1)
2748 Dsymbol
*d
= (Dsymbol
*)a
->data
[0];
2749 s
= new DeclarationStatement(loc
, d
);
2753 if (flags
& PSscope
)
2754 s
= new ScopeStatement(loc
, s
);
2764 d
= parseAggregate();
2765 s
= new DeclarationStatement(loc
, d
);
2773 s
= new DeclarationStatement(loc
, d
);
2779 if (t
->value
== TOKlparen
)
2782 check(TOKlparen
, "mixin");
2783 Expression
*e
= parseAssignExp();
2786 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
2787 error("expected newline after mixin(), not '%s'", token
.toChars());
2790 check(TOKsemicolon
);
2792 s
= new CompileStatement(loc
, e
);
2795 Dsymbol
*d
= parseMixin();
2796 s
= new DeclarationStatement(loc
, d
);
2802 { Statements
*statements
;
2804 if (token
.value
!= startBlockTok
)
2805 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
2809 statements
= new Statements();
2810 while (token
.value
!= TOKrcurly
)
2812 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
2816 s
= new CompoundStatement(loc
, statements
);
2817 if (flags
& (PSscope
| PScurlyscope
))
2818 s
= new ScopeStatement(loc
, s
);
2823 case TOKlog_error
: s
= logStatement(LogStatement::Error
); break;
2824 case TOKlog_warning
: s
= logStatement(LogStatement::Warn
); break;
2825 case TOKlog_info
: s
= logStatement(LogStatement::Info
); break;
2826 case TOKlog_trace
: s
= logStatement(LogStatement::Trace
); break;
2829 { Expression
*condition
;
2834 condition
= parseExpression();
2836 body
= parseStatement(PSscope
);
2837 s
= new WhileStatement(loc
, condition
, body
);
2842 if (!(flags
& PSsemi
))
2843 error("use '{ }' for an empty statement, not a ';'");
2845 s
= new ExpStatement(loc
, NULL
);
2850 Expression
*condition
;
2853 body
= parseStatement(PSscope
);
2856 condition
= parseExpression();
2858 s
= new DoStatement(loc
, body
, condition
);
2865 Expression
*condition
;
2866 Expression
*increment
;
2871 if (token
.value
== TOKlparen
) {
2872 /* for (init; cond; incr): ... */
2874 if (token
.value
== TOKsemicolon
)
2879 { init
= parseStatement(0);
2881 check(TOKsemicolon
);
2883 if (token
.value
== TOKsemicolon
)
2890 condition
= parseExpression();
2891 check(TOKsemicolon
, "for condition");
2893 if (token
.value
== TOKrparen
)
2898 { increment
= parseExpression();
2901 body
= parseStatement(PSscope
);
2902 s
= new ForStatement(loc
, init
, condition
, increment
, body
);
2904 s
= new ScopeStatement(loc
, s
);
2905 } else if (dltSyntax
)
2912 case TOKforeach_reverse
:
2914 /* for var in seq: ... */
2915 /* for index, var in seq: ... */
2916 Arguments
*arguments
;
2921 enum TOK op
= (TOK
) tok
;
2928 TOK inTok
= dltSyntax
? TOKin
: TOKsemicolon
;
2930 arguments
= new Arguments();
2935 Identifier
*ai
= NULL
;
2937 unsigned storageClass
;
2940 storageClass
= STCin
;
2941 if (token
.value
== TOKinout
|| token
.value
== TOKref
)
2942 { storageClass
= STCref
;
2945 if (token
.value
== TOKidentifier
)
2947 Token
*t
= peek(&token
);
2948 if (t
->value
== TOKcomma
|| t
->value
== inTok
)
2950 at
= NULL
; // infer argument type
2955 tb
= parseBasicType();
2956 at
= parseDeclarator(tb
, &ai
);
2958 error("no identifier for declarator %s", at
->toChars());
2960 a
= new Argument(storageClass
, at
, ai
, NULL
);
2962 if (token
.value
== TOKcomma
)
2971 aggr
= parseExpression();
2975 if (token
.value
== TOKreversed
) {
2976 op
= TOKforeach_reverse
;
2983 body
= parseStatement(PScolon
);
2984 s
= new ForeachStatement(loc
, op
, arguments
, aggr
, body
);
2989 { Argument
*arg
= NULL
;
2990 Expression
*condition
;
2992 Statement
*elsebody
;
2997 if (token
.value
== TOKauto
)
3000 if (token
.value
== TOKidentifier
)
3002 Token
*t
= peek(&token
);
3003 if (t
->value
== TOKassign
)
3005 arg
= new Argument(STCin
, NULL
, token
.ident
, NULL
);
3010 { error("= expected following auto identifier");
3015 { error("identifier expected following auto");
3019 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
3025 tb
= parseBasicType();
3026 at
= parseDeclarator(tb
, &ai
);
3028 arg
= new Argument(STCin
, at
, ai
, NULL
);
3031 // Check for " ident;"
3032 else if (token
.value
== TOKidentifier
&& !dltSyntax
)
3034 Token
*t
= peek(&token
);
3035 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
3037 arg
= new Argument(STCin
, NULL
, token
.ident
, NULL
);
3040 if (1 || !global
.params
.useDeprecated
)
3041 error("if (v; e) is deprecated, use if (auto v = e)");
3045 condition
= parseExpression();
3047 ifbody
= parseStatement(PSscope
);
3048 if (token
.value
== TOKelse
)
3053 if (token
.value
== TOKcolon
) {
3054 elsebody
= parseStatement(PSscope
);
3055 } else if (token
.value
== TOKif
) {
3056 elsebody
= parseStatement(0);
3058 error("Expected 'else:' or 'else if', not 'else %s'", token
.toChars());
3063 elsebody
= parseStatement(PSscope
);
3067 s
= new IfStatement(loc
, arg
, condition
, ifbody
, elsebody
);
3072 if (peek(&token
)->value
!= TOKlparen
)
3073 goto Ldeclaration
; // scope used as storage class
3076 if (token
.value
!= TOKidentifier
)
3077 { error("scope identifier expected");
3081 { TOK t
= TOKon_scope_exit
;
3082 Identifier
*id
= token
.ident
;
3085 t
= TOKon_scope_exit
;
3086 else if (id
== Id::failure
)
3087 t
= TOKon_scope_failure
;
3088 else if (id
== Id::success
)
3089 t
= TOKon_scope_success
;
3091 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
3094 Statement
*st
= parseStatement(PScolon
| PScurlyscope
);
3095 s
= new OnScopeStatement(loc
, t
, st
);
3101 condition
= parseDebugCondition();
3106 condition
= parseVersionCondition();
3110 if (dltSyntax
&& token
.value
!= TOKcolon
)
3111 error("expected colon after condition, not '%s'", token
.toChars());
3112 ifbody
= parseStatement(PScolon
/*PSsemi*/);
3114 if (token
.value
== TOKelse
)
3117 elsebody
= parseStatement(PScolon
/*PSsemi*/);
3119 s
= new ConditionalStatement(loc
, condition
, ifbody
, elsebody
);
3123 { Identifier
*ident
;
3124 Expressions
*args
= NULL
;
3129 if (token
.value
!= TOKidentifier
)
3130 { error("pragma(identifier expected");
3133 ident
= token
.ident
;
3135 if (token
.value
== TOKcomma
)
3136 args
= parseArguments(); // pragma(identifier, args...);
3138 check(TOKrparen
); // pragma(identifier);
3139 if (token
.value
== TOKsemicolon
)
3144 body
= parseStatement(PSsemi
| PScolon
);
3145 s
= new PragmaStatement(loc
, ident
, args
, body
);
3150 { Expression
*condition
;
3155 condition
= parseExpression();
3157 body
= parseStatement(PSscope
| PScolon
);
3158 s
= new SwitchStatement(loc
, condition
, body
);
3164 Statements
*statements
;
3165 Array cases
; // array of Expression's
3170 exp
= parseAssignExp();
3172 if (token
.value
!= TOKcomma
)
3178 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3184 statements
= new Statements();
3185 while (token
.value
!= TOKcase
&&
3186 token
.value
!= TOKdefault
&&
3187 token
.value
!= TOKrcurly
)
3189 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3191 s
= new CompoundStatement(loc
, statements
);
3194 s
= new ScopeStatement(loc
, s
);
3196 // Keep cases in order by building the case statements backwards
3197 for (int i
= cases
.dim
; i
; i
--)
3199 exp
= (Expression
*)cases
.data
[i
- 1];
3200 s
= new CaseStatement(loc
, exp
, s
);
3207 Statements
*statements
;
3213 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3219 statements
= new Statements();
3220 while (token
.value
!= TOKcase
&&
3221 token
.value
!= TOKdefault
&&
3222 token
.value
!= TOKrcurly
)
3224 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3226 s
= new CompoundStatement(loc
, statements
);
3229 s
= new ScopeStatement(loc
, s
);
3230 s
= new DefaultStatement(loc
, s
);
3238 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
3241 exp
= parseExpression();
3244 check(TOKsemicolon
, "return statement");
3245 else if (token
.value
!= TOKendline
) {
3246 error("Expected end-of-line after return statement, but found '%s'", token
.toChars());
3249 s
= new ReturnStatement(loc
, exp
);
3254 { Identifier
*ident
;
3257 if (token
.value
== TOKidentifier
)
3258 { ident
= token
.ident
;
3263 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3264 error("expected %s after break, not '%s'", endToken(), token
.toChars());
3268 s
= new BreakStatement(loc
, ident
);
3273 { Identifier
*ident
;
3276 if (token
.value
== TOKidentifier
)
3277 { ident
= token
.ident
;
3282 check(TOKsemicolon
, "continue statement");
3283 s
= new ContinueStatement(loc
, ident
);
3288 { Identifier
*ident
;
3291 if (token
.value
== TOKdefault
)
3294 s
= new GotoDefaultStatement(loc
);
3296 else if (token
.value
== TOKcase
)
3298 Expression
*exp
= NULL
;
3301 if (token
.value
!= TOKsemicolon
)
3302 exp
= parseExpression();
3303 s
= new GotoCaseStatement(loc
, exp
);
3307 if (token
.value
!= TOKidentifier
)
3308 { error("Identifier expected following goto");
3312 { ident
= token
.ident
;
3315 s
= new GotoStatement(loc
, ident
);
3317 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3318 error("expected %s after goto statement, not '%s'", endToken(), token
.toChars());
3323 case TOKsynchronized
:
3328 if (token
.value
== TOKlparen
)
3331 exp
= parseExpression();
3336 body
= parseStatement(PSscope
);
3337 s
= new SynchronizedStatement(loc
, exp
, body
);
3347 exp
= parseExpression();
3349 body
= parseStatement(PSscope
);
3350 s
= new WithStatement(loc
, exp
, body
);
3356 Array
*catches
= NULL
;
3357 Statement
*finalbody
= NULL
;
3360 body
= parseStatement(PSscope
);
3361 while (token
.value
== TOKcatch
)
3367 Loc loc
= this->loc
;
3370 if (token
.value
== startBlockTok
)
3378 t
= parseBasicType();
3380 t
= parseDeclarator(t
, &id
);
3383 handler
= parseStatement(PScolon
);
3384 c
= new Catch(loc
, t
, id
, handler
);
3386 catches
= new Array();
3390 if (token
.value
== TOKfinally
)
3392 finalbody
= parseStatement(PScolon
);
3396 if (!catches
&& !finalbody
)
3397 error("catch or finally expected following try");
3400 s
= new TryCatchStatement(loc
, body
, catches
);
3402 s
= new TryFinallyStatement(loc
, s
, finalbody
);
3411 exp
= parseExpression();
3412 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3413 error("%s expected after throw statement, not '%s'", endToken(), token
.toChars());
3417 s
= new ThrowStatement(loc
, exp
);
3423 s
= parseStatement(PSsemi
| PScurlyscope
);
3424 s
= new VolatileStatement(loc
, s
);
3428 { Statements
*statements
;
3434 // Parse the asm block into a sequence of AsmStatements,
3435 // each AsmStatement is one instruction.
3436 // Separate out labels.
3437 // Defer parsing of AsmStatements until semantic processing.
3440 #if GDC_EXTENDED_ASM_SYNTAX
3441 if (token
.value
== TOKlparen
)
3448 check(startBlockTok
);
3450 ptoklist
= &toklist
;
3452 statements
= new Statements();
3455 switch (token
.value
)
3460 // Look ahead to see if it is a label
3462 if (t
->value
== TOKcolon
)
3464 label
= token
.ident
;
3465 labelloc
= this->loc
;
3474 if (toklist
|| label
)
3476 error("asm statements must end in ';'");
3483 if (toklist
|| label
)
3484 { // Create AsmStatement from list of tokens we've saved
3485 s
= new AsmStatement(this->loc
, toklist
);
3487 ptoklist
= &toklist
;
3489 { s
= new LabelStatement(labelloc
, label
, s
);
3492 statements
->push(s
);
3499 error("matching '}' expected, not end of file");
3504 // If the first token is a string or '(', parse as extended asm.
3508 statements
->push(s
);
3511 // ...else, drop through.
3515 *ptoklist
= new Token();
3516 memcpy(*ptoklist
, &token
, sizeof(Token
));
3517 ptoklist
= &(*ptoklist
)->next
;
3525 s
= new CompoundStatement(loc
, statements
);
3531 error("found '%s' instead of statement", token
.toChars());
3535 while (token
.value
!= TOKrcurly
&&
3536 token
.value
!= TOKsemicolon
&&
3537 token
.value
!= TOKeof
)
3539 if (token
.value
== TOKsemicolon
)
3548 Statement
*Parser::parseExtAsm(int expect_rparen
)
3550 Expression
* insnTemplate
;
3551 Expressions
* args
= NULL
;
3552 Array
* argNames
= NULL
;
3553 Expressions
* argConstraints
= NULL
;
3554 int nOutputArgs
= 0;
3555 Expressions
* clobbers
= NULL
;
3556 bool isInputPhase
= false; // Output operands first, then input.
3558 insnTemplate
= parseExpression();
3559 if (token
.value
== TOKrparen
|| token
.value
== TOKsemicolon
)
3563 Expression
* arg
= NULL
;
3564 Identifier
* name
= NULL
;
3565 Expression
* constraint
= NULL
;
3567 switch (token
.value
)
3578 error("unterminated statement");
3582 if (token
.value
== TOKidentifier
)
3588 error("expected identifier after '['");
3592 constraint
= parsePrimaryExp();
3593 if (constraint
->op
!= TOKstring
)
3594 error("expected constant string constraint for operand");
3595 arg
= parseAssignExp();
3598 args
= new Expressions
;
3599 argConstraints
= new Expressions
;
3600 argNames
= new Array
;
3603 argNames
->push(name
);
3604 argConstraints
->push(constraint
);
3608 if (token
.value
== TOKcomma
)
3615 isInputPhase
= true;
3622 Expression
* clobber
;
3624 switch (token
.value
)
3631 error("unterminated statement");
3634 clobber
= parseAssignExp();
3635 if (clobber
->op
!= TOKstring
)
3636 error("expected constant string constraint for clobber name");
3638 clobbers
= new Expressions
;
3639 clobbers
->push(clobber
);
3641 if (token
.value
== TOKcomma
)
3650 check(TOKsemicolon
);
3652 return new ExtAsmStatement(loc
, insnTemplate
, args
, argNames
,
3653 argConstraints
, nOutputArgs
, clobbers
);
3656 void Parser::optionalEndline() {
3657 while (token
.value
== TOKendline
) {
3662 void Parser::check(enum TOK value
)
3667 void Parser::check(Loc loc
, enum TOK value
)
3669 if (token
.value
!= value
)
3670 error(loc
, "found '%s' when expecting '%s'", token
.toChars(), Token::toChars(value
));
3674 void Parser::check(enum TOK value
, char *string
)
3676 if (token
.value
!= value
)
3677 error("found '%s' when expecting '%s' following '%s'",
3678 token
.toChars(), Token::toChars(value
), string
);
3682 char *Parser::endToken()
3687 char *DltParser::endToken()
3692 void Parser::checkLParen() { check(TOKlparen
); }
3693 void Parser::checkRParen() { check(TOKrparen
); }
3695 void DltParser::checkLParen() { }
3696 void DltParser::checkRParen() { }
3698 /************************************
3699 * Determine if the scanner is sitting on the start of a declaration.
3701 * needId 0 no identifier
3702 * 1 identifier optional
3703 * 2 must have identifier
3706 int Parser::isDeclaration(Token
*t
, int needId
, enum TOK endtok
, Token
**pt
)
3710 if (!isBasicType(&t
))
3712 if (!isDeclarator(&t
, &haveId
, endtok
))
3715 (needId
== 0 && !haveId
) ||
3716 (needId
== 2 && haveId
))
3725 int Parser::isBasicType(Token
**pt
)
3727 // This code parallels parseBasicType()
3740 if (t
->value
== TOKnot
)
3750 if (t
->value
== TOKdot
)
3754 if (t
->value
!= TOKidentifier
)
3757 if (t
->value
!= TOKnot
)
3761 if (t
->value
!= TOKlparen
)
3763 if (!skipParens(t
, &t
))
3775 /* typeof(exp).identifier...
3778 if (t
->value
!= TOKlparen
)
3780 if (!skipParens(t
, &t
))
3794 int Parser::isDeclarator(Token
**pt
, int *haveId
, enum TOK endtok
)
3795 { // This code parallels parseDeclarator()
3799 //printf("Parser::isDeclarator()\n");
3801 if (t
->value
== TOKassign
)
3817 if (t
->value
== TOKrbracket
)
3821 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
3822 { // It's an associative array declaration
3828 // [ expression .. expression ]
3829 if (!isExpression(&t
))
3831 if (t
->value
== TOKslice
)
3833 if (!isExpression(&t
))
3836 if (t
->value
!= TOKrbracket
)
3852 if (t
->value
== TOKrparen
)
3853 return FALSE
; // () is not a declarator
3855 /* Regard ( identifier ) as not a declarator
3856 * BUG: what about ( *identifier ) in
3858 * where f is a class instance with overloaded () ?
3859 * Should we just disallow C-style function pointer declarations?
3861 if (t
->value
== TOKidentifier
)
3862 { Token
*t2
= peek(t
);
3863 if (t2
->value
== TOKrparen
)
3868 if (!isDeclarator(&t
, haveId
, TOKrparen
))
3877 if (!isParameters(&t
))
3892 if (t
->value
== TOKrbracket
)
3896 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
3897 { // It's an associative array declaration
3903 if (!isExpression(&t
))
3905 if (t
->value
!= TOKrbracket
)
3914 if (!isParameters(&t
))
3918 // Valid tokens that follow a declaration
3927 // The !parens is to disallow unnecessary parentheses
3928 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
3941 int Parser::isParameters(Token
**pt
)
3942 { // This code parallels parseParameters()
3946 //printf("isParameters()\n");
3947 if (t
->value
!= TOKlparen
)
3969 if (!isBasicType(&t
))
3972 if (t
->value
!= TOKdotdotdot
&&
3973 !isDeclarator(&t
, &tmp
, TOKreserved
))
3975 if (t
->value
== TOKassign
)
3977 if (!isExpression(&t
))
3980 if (t
->value
== TOKdotdotdot
)
3985 if (t
->value
== TOKcomma
)
3993 if (t
->value
!= TOKrparen
)
4000 int Parser::isExpression(Token
**pt
)
4002 // This is supposed to determine if something is an expression.
4003 // What it actually does is scan until a closing right bracket
4010 for (;; t
= peek(t
))
4028 if (brnest
|| panest
)
4055 /**********************************************
4057 * instance foo.bar(parameters...)
4059 * if (pt), *pt is set to the token following the closing )
4061 * 1 it's valid instance syntax
4062 * 0 invalid instance syntax
4065 int Parser::isTemplateInstance(Token
*t
, Token
**pt
)
4068 if (t
->value
!= TOKdot
)
4070 if (t
->value
!= TOKidentifier
)
4074 while (t
->value
== TOKdot
)
4077 if (t
->value
!= TOKidentifier
)
4081 if (t
->value
!= TOKlparen
)
4084 // Skip over the template arguments
4093 if (!skipParens(t
, &t
))
4109 if (t
->value
!= TOKcomma
)
4112 if (t
->value
!= TOKrparen
)
4123 /*******************************************
4124 * Skip parens, brackets.
4128 * *pt is set to closing token, which is ')' on success
4131 * 0 some parsing error
4134 int Parser::skipParens(Token
*t
, Token
**pt
)
4173 /********************************* Expression Parser ***************************/
4175 Expression
*Parser::parsePrimaryExp()
4180 Loc loc
= this->loc
;
4182 switch (token
.value
)
4187 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4188 { // identifier!(template-argument-list)
4189 TemplateInstance
*tempinst
;
4191 tempinst
= new TemplateInstance(loc
, id
);
4193 tempinst
->tiargs
= parseTemplateArgumentList();
4194 e
= new ScopeExp(loc
, tempinst
);
4197 e
= new IdentifierExp(loc
, id
);
4202 error("'$' is valid only inside [] of index or slice");
4203 e
= new DollarExp(loc
);
4208 // Signal global scope '.' operator with "" identifier
4209 e
= new IdentifierExp(loc
, Id::empty
);
4213 e
= new ThisExp(loc
);
4218 e
= new SuperExp(loc
);
4223 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
4228 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
4233 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
4238 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
4243 e
= new RealExp(loc
, token
.float80value
, Type::tfloat32
);
4248 e
= new RealExp(loc
, token
.float80value
, Type::tfloat64
);
4253 e
= new RealExp(loc
, token
.float80value
, Type::tfloat80
);
4257 case TOKimaginary32v
:
4258 e
= new RealExp(loc
, token
.float80value
, Type::timaginary32
);
4262 case TOKimaginary64v
:
4263 e
= new RealExp(loc
, token
.float80value
, Type::timaginary64
);
4267 case TOKimaginary80v
:
4268 e
= new RealExp(loc
, token
.float80value
, Type::timaginary80
);
4273 e
= new NullExp(loc
);
4278 e
= new IntegerExp(loc
, 1, Type::tbool
);
4283 e
= new IntegerExp(loc
, 0, Type::tbool
);
4288 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tchar
);
4293 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::twchar
);
4298 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
4305 unsigned char postfix
;
4307 // cat adjacent strings
4310 postfix
= token
.postfix
;
4314 if (token
.value
== TOKstring
)
4320 { if (token
.postfix
!= postfix
)
4321 error("mismatched string literal postfixes '%c' and '%c'", postfix
, token
.postfix
);
4322 postfix
= token
.postfix
;
4328 s2
= (unsigned char *)mem
.malloc((len
+ 1) * sizeof(unsigned char));
4329 memcpy(s2
, s
, len1
* sizeof(unsigned char));
4330 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(unsigned char));
4336 e
= new StringExp(loc
, s
, len
, postfix
);
4340 CASE_BASIC_TYPES_X(t
):
4343 check(TOKdot
, t
->toChars());
4344 if (token
.value
!= TOKidentifier
)
4345 { error("found '%s' when expecting identifier following '%s.'", token
.toChars(), t
->toChars());
4348 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4357 exp
= parseExpression();
4359 t
= new TypeTypeof(loc
, exp
);
4360 if (token
.value
== TOKdot
)
4362 e
= new TypeExp(loc
, t
);
4370 check(TOKlparen
, "typeid");
4371 t
= parseBasicType();
4372 t
= parseDeclarator(t
,NULL
); // ( type )
4374 e
= new TypeidExp(loc
, t
);
4380 Identifier
*ident
= NULL
;
4382 enum TOK tok
= TOKreserved
;
4383 enum TOK tok2
= TOKreserved
;
4384 Loc loc
= this->loc
;
4387 if (token
.value
== TOKlparen
)
4390 targ
= parseBasicType();
4391 targ
= parseDeclarator(targ
, &ident
);
4392 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
4396 if (tok
== TOKequal
&&
4397 (token
.value
== TOKtypedef
||
4398 token
.value
== TOKstruct
||
4399 token
.value
== TOKunion
||
4400 token
.value
== TOKclass
||
4401 token
.value
== TOKsuper
||
4402 token
.value
== TOKenum
||
4403 token
.value
== TOKinterface
||
4404 token
.value
== TOKfunction
||
4405 token
.value
== TOKdelegate
||
4406 token
.value
== TOKreturn
))
4413 tspec
= parseBasicType();
4414 tspec
= parseDeclarator(tspec
, NULL
);
4420 { error("(type identifier : specialization) expected following is");
4423 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
);
4428 { Expression
*msg
= NULL
;
4433 e
= parseAssignExp();
4434 if (token
.value
== (dltSyntax
? TOKelse
: TOKcomma
))
4436 msg
= parseAssignExp();
4437 } else if (token
.value
== TOKcomma
)
4438 error("Suspicious comma after assert; try 'else' instead");
4441 e
= new AssertExp(loc
, e
, msg
);
4448 check(TOKlparen
, "mixin");
4449 e
= parseAssignExp();
4451 e
= new CompileExp(loc
, e
);
4458 check(TOKlparen
, "import");
4459 e
= parseAssignExp();
4461 e
= new FileExp(loc
, e
);
4466 if (peekPastParen(&token
)->value
== TOKlcurly
)
4467 { // (arguments) { statements... }
4473 e
= parseExpression();
4474 check(loc
, TOKrparen
);
4478 { /* Parse array literals and associative array literals:
4479 * [ value, value, value ... ]
4480 * [ key:value, key:value, key:value ... ]
4482 Expressions
*values
= new Expressions();
4483 Expressions
*keys
= NULL
;
4486 if (token
.value
!= TOKrbracket
)
4490 Expression
*e
= parseAssignExp();
4491 if (token
.value
== TOKcolon
&& (keys
|| values
->dim
== 0))
4494 keys
= new Expressions();
4496 e
= parseAssignExp();
4499 { error("'key:value' expected for associative array literal");
4504 if (token
.value
== TOKrbracket
)
4512 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
4514 e
= new ArrayLiteralExp(loc
, values
);
4519 // { statements... }
4529 /* function type(parameters) { body }
4530 * delegate type(parameters) { body }
4532 Arguments
*arguments
;
4534 FuncLiteralDeclaration
*fd
;
4537 if (token
.value
== TOKlcurly
)
4541 arguments
= new Arguments();
4545 if (token
.value
== TOKlparen
)
4549 t
= parseBasicType();
4550 t
= parseBasicType2(t
); // function return type
4552 arguments
= parseParameters(&varargs
);
4554 t
= new TypeFunction(arguments
, t
, varargs
, linkage
);
4555 fd
= new FuncLiteralDeclaration(loc
, 0, t
, save
, NULL
);
4557 e
= new FuncExp(loc
, fd
);
4562 error("expression expected, not '%s'", token
.toChars());
4564 // Anything for e, as long as it's not NULL
4565 e
= new IntegerExp(loc
, 0, Type::tint32
);
4569 return parsePostExp(e
);
4572 Expression
*Parser::parsePostExp(Expression
*e
)
4579 switch (token
.value
)
4583 if (token
.value
== TOKidentifier
)
4584 { Identifier
*id
= token
.ident
;
4587 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4588 { // identifier!(template-argument-list)
4589 TemplateInstance
*tempinst
;
4591 tempinst
= new TemplateInstance(loc
, id
);
4593 tempinst
->tiargs
= parseTemplateArgumentList();
4594 e
= new DotTemplateInstanceExp(loc
, e
, tempinst
);
4597 e
= new DotIdExp(loc
, e
, id
);
4600 else if (token
.value
== TOKnew
)
4606 error("identifier expected following '.', not '%s'", token
.toChars());
4610 e
= new PostExp(TOKplusplus
, loc
, e
);
4614 e
= new PostExp(TOKminusminus
, loc
, e
);
4618 e
= new CallExp(loc
, e
, parseArguments());
4622 { // array dereferences:
4625 // array[lwr .. upr]
4631 if (token
.value
== TOKrbracket
)
4633 e
= new SliceExp(loc
, e
, NULL
, NULL
);
4638 index
= parseAssignExp();
4639 if (token
.value
== TOKslice
)
4640 { // array[lwr .. upr]
4642 upr
= parseAssignExp();
4643 e
= new SliceExp(loc
, e
, index
, upr
);
4646 { // array[index, i2, i3, i4, ...]
4647 Expressions
*arguments
= new Expressions();
4648 arguments
->push(index
);
4649 if (token
.value
== TOKcomma
)
4655 arg
= parseAssignExp();
4656 arguments
->push(arg
);
4657 if (token
.value
== TOKrbracket
)
4662 e
= new ArrayExp(loc
, e
, arguments
);
4677 Expression
*Parser::parseUnaryExp()
4679 Loc loc
= this->loc
;
4681 switch (token
.value
)
4685 e
= parseUnaryExp();
4686 e
= new AddrExp(loc
, e
);
4691 e
= parseUnaryExp();
4692 e
= new AddAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
4697 e
= parseUnaryExp();
4698 e
= new MinAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
4703 e
= parseUnaryExp();
4704 e
= new PtrExp(loc
, e
);
4709 e
= parseUnaryExp();
4710 e
= new NegExp(loc
, e
);
4715 e
= parseUnaryExp();
4716 e
= new UAddExp(loc
, e
);
4721 e
= parseUnaryExp();
4722 e
= new NotExp(loc
, e
);
4727 e
= parseUnaryExp();
4728 e
= new ComExp(loc
, e
);
4733 e
= parseUnaryExp();
4734 e
= new DeleteExp(loc
, e
);
4738 e
= parseNewExp(NULL
);
4741 case TOKcast
: // cast(type) expression
4746 t
= parseBasicType();
4747 t
= parseDeclarator(t
,NULL
); // ( type )
4750 e
= parseUnaryExp();
4751 e
= new CastExp(loc
, e
, t
);
4761 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
4763 tk
= peek(tk
); // skip over right parenthesis
4783 case TOKimaginary32v
:
4784 case TOKimaginary64v
:
4785 case TOKimaginary80v
:
4803 CASE_BASIC_TYPES
: // (type)int.size
4808 t
= parseBasicType();
4809 t
= parseDeclarator(t
,NULL
);
4813 if (token
.value
== TOKdot
)
4816 if (token
.value
!= TOKidentifier
)
4817 { error("Identifier expected following (type).");
4820 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4822 e
= parsePostExp(e
);
4826 e
= parseUnaryExp();
4827 e
= new CastExp(loc
, e
, t
);
4828 error("C style cast illegal, use %s", e
->toChars());
4835 e
= parsePrimaryExp();
4839 e
= parsePrimaryExp();
4846 Expression
*Parser::parseMulExp()
4849 Loc loc
= this->loc
;
4851 e
= parseUnaryExp();
4854 switch (token
.value
)
4856 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
4857 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
4858 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
4868 Expression
*Parser::parseAddExp()
4871 Loc loc
= this->loc
;
4876 switch (token
.value
)
4878 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
4879 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
4880 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
4890 Expression
*Parser::parseShiftExp()
4893 Loc loc
= this->loc
;
4898 switch (token
.value
)
4900 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
4901 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
4902 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
4912 Expression
*Parser::parseRelExp()
4916 Loc loc
= this->loc
;
4918 e
= parseShiftExp();
4921 switch (token
.value
)
4937 e2
= parseShiftExp();
4938 e
= new CmpExp(op
, loc
, e
, e2
);
4943 e2
= parseShiftExp();
4944 e
= new InExp(loc
, e
, e2
);
4955 Expression
*Parser::parseEqualExp()
4959 Loc loc
= this->loc
;
4963 { enum TOK value
= token
.value
;
4971 e
= new EqualExp(value
, loc
, e
, e2
);
4975 error("'===' is no longer legal, use 'is' instead");
4978 case TOKnotidentity
:
4979 error("'!==' is no longer legal, use '!is' instead");
4983 value
= TOKidentity
;
4988 error("next: %s", t
->toChars());
4989 if (t
->value
== TOKnot
)
4992 value
= TOKnotidentity
;
4999 // Attempt to identify '!is'
5001 if (t
->value
!= TOKis
)
5004 value
= TOKnotidentity
;
5010 e
= new IdentityExp(value
, loc
, e
, e2
);
5021 Expression
*Parser::parseCmpExp()
5025 Loc loc
= this->loc
;
5027 e
= parseShiftExp();
5028 enum TOK op
= token
.value
;
5035 e2
= parseShiftExp();
5036 e
= new EqualExp(op
, loc
, e
, e2
);
5044 if (t
->value
== TOKnot
)
5047 op
= TOKnotidentity
;
5054 // Attempt to identify '!is'
5056 if (t
->value
!= TOKis
)
5059 op
= TOKnotidentity
;
5064 e2
= parseShiftExp();
5065 e
= new IdentityExp(op
, loc
, e
, e2
);
5081 e2
= parseShiftExp();
5082 e
= new CmpExp(op
, loc
, e
, e2
);
5087 e2
= parseShiftExp();
5088 e
= new InExp(loc
, e
, e2
);
5097 Expression
*Parser::parseAndExp()
5100 Loc loc
= this->loc
;
5102 if (global
.params
.Dversion
== 1)
5104 e
= parseEqualExp();
5105 while (token
.value
== TOKand
)
5108 e2
= parseEqualExp();
5109 e
= new AndExp(loc
,e
,e2
);
5116 while (token
.value
== TOKand
)
5120 e
= new AndExp(loc
,e
,e2
);
5127 Expression
*Parser::parseXorExp()
5130 Loc loc
= this->loc
;
5133 while (token
.value
== TOKxor
)
5137 e
= new XorExp(loc
, e
, e2
);
5142 Expression
*Parser::parseOrExp()
5145 Loc loc
= this->loc
;
5148 while (token
.value
== TOKor
)
5152 e
= new OrExp(loc
, e
, e2
);
5157 Expression
*Parser::parseAndAndExp()
5160 Loc loc
= this->loc
;
5163 while (token
.value
== TOKandand
)
5167 e
= new AndAndExp(loc
, e
, e2
);
5172 Expression
*Parser::parseOrOrExp()
5175 Loc loc
= this->loc
;
5177 e
= parseAndAndExp();
5178 while (token
.value
== TOKoror
)
5181 e2
= parseAndAndExp();
5182 e
= new OrOrExp(loc
, e
, e2
);
5187 Expression
*Parser::parseCondExp()
5191 Loc loc
= this->loc
;
5194 if (token
.value
== TOKquestion
)
5197 e1
= parseExpression();
5199 e2
= parseCondExp();
5200 e
= new CondExp(loc
, e
, e1
, e2
);
5205 Expression
*DltParser::parseCondExp()
5209 Loc loc
= this->loc
;
5212 if (token
.value
== TOKif
)
5215 e1
= parseExpression();
5217 e2
= parseCondExp();
5218 e
= new CondExp(loc
, e1
, e
, e2
);
5223 Expression
*Parser::parseAssignExp()
5232 switch (token
.value
)
5234 #define X(tok,ector) \
5235 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5237 X(TOKassign
, AssignExp
);
5238 X(TOKaddass
, AddAssignExp
);
5239 X(TOKminass
, MinAssignExp
);
5240 X(TOKmulass
, MulAssignExp
);
5241 X(TOKdivass
, DivAssignExp
);
5242 X(TOKmodass
, ModAssignExp
);
5243 X(TOKandass
, AndAssignExp
);
5244 X(TOKorass
, OrAssignExp
);
5245 X(TOKxorass
, XorAssignExp
);
5246 X(TOKshlass
, ShlAssignExp
);
5247 X(TOKshrass
, ShrAssignExp
);
5248 X(TOKushrass
, UshrAssignExp
);
5249 X(TOKcatass
, CatAssignExp
);
5260 Expression
*Parser::parseExpression()
5263 Loc loc
= this->loc
;
5265 //printf("Parser::parseExpression()\n");
5266 e
= parseAssignExp();
5267 while (token
.value
== TOKcomma
)
5270 e2
= parseAssignExp();
5271 e
= new CommaExp(loc
, e
, e2
);
5278 /*************************
5279 * Collect argument list.
5280 * Assume current token is '(' or '['.
5283 Expressions
*Parser::parseArguments()
5285 Expressions
*arguments
;
5289 arguments
= new Expressions();
5290 if (token
.value
== TOKlbracket
)
5291 endtok
= TOKrbracket
;
5297 if (token
.value
!= endtok
)
5301 arg
= parseAssignExp();
5302 arguments
->push(arg
);
5303 if (token
.value
== endtok
)
5313 /*******************************************
5316 Expression
*Parser::parseNewExp(Expression
*thisexp
)
5318 Expressions
*newargs
;
5319 Expressions
*arguments
= NULL
;
5321 Loc loc
= this->loc
;
5325 if (token
.value
== TOKlparen
)
5327 newargs
= parseArguments();
5330 // An anonymous nested class starts with "class"
5331 if (token
.value
== TOKclass
)
5334 if (token
.value
== TOKlparen
)
5335 arguments
= parseArguments();
5337 BaseClasses
*baseclasses
= NULL
;
5338 if (token
.value
!= TOKlcurly
)
5339 baseclasses
= parseBaseClasses();
5341 Identifier
*id
= NULL
;
5342 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
);
5344 if (token
.value
!= TOKlcurly
)
5345 { error("{ members } expected for anonymous class");
5351 Array
*decl
= parseDeclDefs(0);
5352 if (token
.value
!= TOKrcurly
)
5353 error("class member expected");
5358 e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
5364 t
= parseBasicType();
5365 t
= parseBasicType2(t
);
5366 if (t
->ty
== Taarray
)
5368 Type
*index
= ((TypeAArray
*)t
)->index
;
5370 Expression
*e
= index
->toExpression();
5372 { arguments
= new Expressions();
5374 t
= new TypeDArray(t
->next
);
5378 error("need size of rightmost array, not type %s", index
->toChars());
5379 return new NullExp(loc
);
5382 else if (t
->ty
== Tsarray
)
5384 TypeSArray
*tsa
= (TypeSArray
*)t
;
5385 Expression
*e
= tsa
->dim
;
5387 arguments
= new Expressions();
5389 t
= new TypeDArray(t
->next
);
5391 else if (token
.value
== TOKlparen
)
5393 arguments
= parseArguments();
5396 t
= parseBasicType();
5397 while (token
.value
== TOKmul
)
5398 { t
= new TypePointer(t
);
5401 if (token
.value
== TOKlbracket
)
5406 e
= parseAssignExp();
5407 arguments
= new Array();
5410 t
= parseDeclarator(t
, NULL
);
5411 t
= new TypeDArray(t
);
5413 else if (token
.value
== TOKlparen
)
5414 arguments
= parseArguments();
5416 e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
5420 /**********************************************
5423 void Parser::addComment(Dsymbol
*s
, unsigned char *blockComment
)
5425 s
->addComment(combineComments(blockComment
, token
.lineComment
));
5429 /********************************* ***************************/