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, module
->isDltFile
)
64 //printf("Parser::Parser()\n");
67 dltNormalMode
= FALSE
;
70 startBlockTok
= TOKlcurly
;
71 //nextToken(); // start up the scanner
74 DltParser::DltParser(Module
*module
, unsigned char *base
, unsigned length
, int doDocComment
)
75 : Parser(module
, base
, length
, doDocComment
)
77 //printf("DltParser::DltParser(%s)\n", module->ident->string);
78 startBlockTok
= TOKcolon
;
79 dltNormalMode
= TRUE
; // becomes false if we find a "module dlt.*" or _externals
82 Array
*Parser::parseModule()
86 // ModuleDeclation leads off
88 if (token
.value
== TOKmodule
)
90 unsigned char *comment
= token
.blockComment
;
93 if (token
.value
!= TOKidentifier
)
94 { error("Identifier expected following module");
104 if (dltSyntax
&& (id
== Id::dlt
|| id
== Id::_externals
))
105 dltNormalMode
= FALSE
;
107 while (nextToken() == TOKdot
)
113 if (token
.value
!= TOKidentifier
)
114 { error("Identifier expected following package");
120 md
= new ModuleDeclaration(a
, id
);
122 TOK end
= dltSyntax
? TOKendline
: TOKsemicolon
;
123 if (token
.value
!= end
)
124 error("%s expected following module declaration instead of %s", Token::toChars(end
), token
.toChars());
127 addComment(mod
, comment
);
131 decldefs
= parseDeclDefs(0);
132 if (token
.value
!= TOKeof
)
133 { error("unrecognized declaration '%s'", token
.toChars());
139 // Check for global variables
140 for (int i
= 0; i
< decldefs
->dim
; i
++)
142 Dsymbol
*d
= (Dsymbol
*) decldefs
->data
[i
];
143 if (d
->isVarDeclaration()) {
144 error(d
->loc
, "no global variables (%s) allowed in Delight; "
145 "try const, or put it in a class", d
->toChars());
153 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
159 Array
*Parser::parseDeclDefs(int once
)
166 unsigned storageClass
;
167 Condition
*condition
;
168 unsigned char *comment
;
170 //printf("Parser::parseDeclDefs()\n");
171 decldefs
= new Array();
174 comment
= token
.blockComment
;
182 { /* Determine if this is a manifest constant declaration,
183 * or a conventional enum.
185 Token
*t
= peek(&token
);
186 if (t
->value
== startBlockTok
||
187 t
->value
== (dltSyntax
? TOKextends
: TOKcolon
))
191 else if (t
->value
!= TOKidentifier
)
196 if (t
->value
== startBlockTok
||
197 t
->value
== (dltSyntax
? TOKextends
: TOKcolon
) ||
198 t
->value
== TOKsemicolon
)
210 s
= parseAggregate();
214 s
= parseImport(decldefs
, 0);
218 s
= (Dsymbol
*)parseTemplateDeclaration();
222 { Loc loc
= this->loc
;
223 if (peek(&token
)->value
== TOKlparen
)
226 check(TOKlparen
, "mixin");
227 Expression
*e
= parseAssignExp();
230 s
= new CompileDeclaration(loc
, e
);
244 a
= parseDeclarations();
263 if (t
->value
== TOKlparen
)
265 if (peek(t
)->value
== TOKrparen
)
266 // invariant() forms start of class invariant
267 s
= parseInvariant();
298 if (token
.value
== TOKthis
)
300 s
= parseStaticCtor();
302 error("no static constructors in Delight");
304 else if (token
.value
== TOKtilde
)
306 s
= parseStaticDtor();
308 error("no static destructors in Delight");
310 else if (token
.value
== TOKassert
)
311 s
= parseStaticAssert();
312 else if (token
.value
== TOKif
)
313 { condition
= parseStaticIfCondition();
316 if (token
.value
== TOKelse
)
318 aelse
= parseBlock();
320 s
= new StaticIfDeclaration(condition
, a
, aelse
);
323 else if (token
.value
== TOKimport
)
325 s
= parseImport(decldefs
, 1);
339 if (peek(&token
)->value
== TOKlparen
)
344 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
345 case TOKauto
: stc
= STCauto
; goto Lstc
;
346 case TOKscope
: stc
= STCscope
; goto Lstc
;
347 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
348 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
349 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
350 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
351 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
352 case TOKpure
: stc
= STCpure
; goto Lstc
;
353 case TOKtls
: stc
= STCtls
; goto Lstc
;
354 //case TOKmanifest: stc = STCmanifest; goto Lstc;
357 if (storageClass
& stc
)
358 error("redundant storage class %s", Token::toChars(token
.value
));
360 unsigned u
= storageClass
| stc
;
361 u
&= STCconst
| STCinvariant
| STCmanifest
;
363 error("conflicting storage class %s", Token::toChars(token
.value
));
372 // If followed by a (, it is not a storage class
373 if (peek(&token
)->value
== TOKlparen
)
375 if (token
.value
== TOKconst
)
380 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
381 case TOKauto
: stc
= STCauto
; goto Lstc
;
382 case TOKscope
: stc
= STCscope
; goto Lstc
;
383 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
384 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
385 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
386 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
387 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
388 case TOKpure
: stc
= STCpure
; goto Lstc
;
389 case TOKtls
: stc
= STCtls
; goto Lstc
;
390 //case TOKmanifest: stc = STCmanifest; goto Lstc;
395 /* Look for auto initializers:
396 * storage_class identifier = initializer;
398 if (token
.value
== TOKidentifier
&&
399 peek(&token
)->value
== TOKassign
)
403 Identifier
*ident
= token
.ident
;
406 Initializer
*init
= parseInitializer();
407 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
408 v
->storage_class
= storageClass
;
409 v
->dltNormalMode
= dltNormalMode
;
411 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
415 else if (token
.value
== TOKcomma
)
418 if (token
.value
== TOKidentifier
&&
419 peek(&token
)->value
== TOKassign
)
422 addComment(s
, comment
);
426 error("Identifier expected following comma");
429 error("%s expected following declaration, not '%s'", endToken(), token
.toChars());
435 s
= new StorageClassDeclaration(storageClass
, a
);
440 if (peek(&token
)->value
!= TOKlparen
)
445 enum LINK linksave
= linkage
;
446 linkage
= parseLinkage();
448 s
= new LinkDeclaration(linkage
, a
);
452 error("access to external symbols can be done only by dlt.* modules");
455 case TOKprivate
: prot
= PROTprivate
; goto Lprot
;
456 case TOKpackage
: prot
= PROTpackage
; goto Lprot
;
457 case TOKprotected
: prot
= PROTprotected
; goto Lprot
;
458 case TOKpublic
: prot
= PROTpublic
; goto Lprot
;
459 case TOKexport
: prot
= PROTexport
; goto Lprot
;
470 error("redundant protection attribute");
474 s
= new ProtDeclaration(prot
, a
);
482 if (token
.value
== TOKlparen
)
485 if (token
.value
== TOKint32v
)
486 n
= (unsigned)token
.uns64value
;
488 { error("integer expected, not %s", token
.toChars());
495 n
= global
.structalign
; // default
498 s
= new AlignDeclaration(n
, a
);
504 Expressions
*args
= NULL
;
508 if (token
.value
!= TOKidentifier
)
509 { error("pragma(identifier expected");
514 if (token
.value
== TOKcomma
)
515 args
= parseArguments(); // pragma(identifier, args...)
517 check(TOKrparen
); // pragma(identifier)
519 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
524 a
= parseDeclDefs(0);
529 s
= new PragmaDeclaration(loc
, ident
, args
, a
);
535 if (token
.value
== TOKassign
)
538 if (token
.value
== TOKidentifier
)
539 s
= new DebugSymbol(loc
, token
.ident
);
540 else if (token
.value
== TOKint32v
)
541 s
= new DebugSymbol(loc
, (unsigned)token
.uns64value
);
543 { error("identifier or integer expected, not %s", token
.toChars());
547 if (token
.value
!= TOKsemicolon
)
548 error("semicolon expected");
553 condition
= parseDebugCondition();
558 if (token
.value
== TOKassign
)
561 if (token
.value
== TOKidentifier
)
562 s
= new VersionSymbol(loc
, token
.ident
);
563 else if (token
.value
== TOKint32v
)
564 s
= new VersionSymbol(loc
, (unsigned)token
.uns64value
);
566 { error("identifier or integer expected, not %s", token
.toChars());
570 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
)
571 error("%s expected after version assignment", endToken());
575 condition
= parseVersionCondition();
581 if (token
.value
== TOKelse
)
583 aelse
= parseBlock();
585 s
= new ConditionalDeclaration(condition
, a
, aelse
);
588 case TOKsemicolon
: // empty declaration
593 error("Declaration expected, not '%s'",token
.toChars());
595 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
&& token
.value
!= TOKeof
)
603 addComment(s
, comment
);
610 /********************************************
611 * Parse declarations after an align, protection, or extern decl.
614 Array
*Parser::parseBlock()
619 //printf("Parser::parseBlock()\n");
623 error("declaration expected following attribute, not ';'");
629 a
= parseDeclDefs(0);
630 if (token
.value
!= TOKrcurly
)
632 error("matching '}' expected, not %s", token
.toChars());
643 a
= parseDeclDefs(0); // grab declarations up to closing curly bracket
648 a
= parseDeclDefs(1);
654 Array
*DltParser::parseBlock()
664 error("declaration expected following attribute, not %s", token
.toChars());
670 a
= parseDeclDefs(0);
671 if (token
.value
!= TOKrcurly
)
673 error("matching end-of-block expected, not %s", token
.toChars());
680 a
= parseDeclDefs(1);
686 /**********************************
687 * Parse a static assertion.
690 StaticAssert
*Parser::parseStaticAssert()
694 Expression
*msg
= NULL
;
696 //printf("parseStaticAssert()\n");
699 exp
= parseAssignExp();
700 if (token
.value
== TOKcomma
)
702 msg
= parseAssignExp();
705 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
) {
707 return new StaticAssert(loc
, exp
, msg
);
709 error("expected %s after static assert", endToken());
712 /***********************************
713 * Parse typeof(expression).
714 * Current token is on the 'typeof'.
717 TypeQualified
*Parser::parseTypeof()
723 if (token
.value
== TOKreturn
) // typeof(return)
726 t
= new TypeReturn(loc
);
729 { Expression
*exp
= parseExpression(); // typeof(expression)
730 t
= new TypeTypeof(loc
, exp
);
736 /***********************************
737 * Parse extern (linkage)
738 * The parser is on the 'extern' token.
741 enum LINK
Parser::parseLinkage()
743 enum LINK link
= LINKdefault
;
745 assert(token
.value
== TOKlparen
);
747 if (token
.value
== TOKidentifier
)
748 { Identifier
*id
= token
.ident
;
751 if (id
== Id::Windows
)
753 else if (id
== Id::Pascal
)
755 else if (id
== Id::D
)
757 else if (id
== Id::GObject
)
759 else if (id
== Id::C
)
762 if (token
.value
== TOKplusplus
)
767 else if (id
== Id::System
)
770 link
= d_gcc_is_target_win32() ? LINKwindows
: LINKc
;
781 error("valid linkage identifiers are D, C, C++, GObject, Pascal, Windows, System");
787 link
= LINKd
; // default
793 /**************************************
794 * Parse a debug conditional
797 Condition
*Parser::parseDebugCondition()
801 if (token
.value
== TOKlparen
)
805 Identifier
*id
= NULL
;
807 if (token
.value
== TOKidentifier
)
809 else if (token
.value
== TOKint32v
)
810 level
= (unsigned)token
.uns64value
;
812 error("identifier or integer expected, not %s", token
.toChars());
815 c
= new DebugCondition(mod
, level
, id
);
816 if (dltSyntax
&& token
.value
!= TOKcolon
)
817 error("expected colon after debug(), not '%s'", token
.toChars());
819 if (dltSyntax
&& token
.value
!= TOKcolon
)
820 error("expected ':' or '(' after 'debug', not '%s'", token
.toChars());
821 c
= new DebugCondition(mod
, 1, NULL
);
827 /**************************************
828 * Parse a version conditional
831 Condition
*Parser::parseVersionCondition()
835 Identifier
*id
= NULL
;
837 if (token
.value
== TOKlparen
)
840 if (token
.value
== TOKidentifier
)
842 else if (token
.value
== TOKint32v
)
843 level
= (unsigned)token
.uns64value
;
847 * even though unittest is a keyword
849 else if (token
.value
== TOKunittest
)
850 id
= Lexer::idPool(Token::toChars(TOKunittest
));
853 error("identifier or integer expected, not %s", token
.toChars());
859 error("(condition) expected following version");
860 c
= new VersionCondition(mod
, level
, id
);
865 /***********************************************
866 * static if (expression)
872 Condition
*Parser::parseStaticIfCondition()
874 Condition
*condition
;
881 exp
= parseAssignExp();
884 condition
= new StaticIfCondition(loc
, exp
);
889 /*****************************************
890 * Parse a constructor definition:
891 * this(arguments) { body }
893 * this(this) { body }
894 * Current token is 'this'.
897 FuncDeclaration
*Parser::parseCtor()
902 if (token
.value
== TOKlparen
&& peek(&token
)->value
== TOKthis
)
903 { // this(this) { ... }
907 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, 0);
912 Arguments
*arguments
= parseParameters(&varargs
);
913 CtorDeclaration
*f
= new CtorDeclaration(loc
, 0, arguments
, varargs
);
918 /*****************************************
919 * Parse a postblit definition:
921 * Current token is '='.
924 PostBlitDeclaration
*Parser::parsePostBlit()
933 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, 0);
938 /*****************************************
939 * Parse a destructor definition:
941 * Current token is '~'.
944 DtorDeclaration
*Parser::parseDtor()
954 f
= new DtorDeclaration(loc
, 0);
959 /*****************************************
960 * Parse a static constructor definition:
961 * static this() { body }
962 * Current token is 'this'.
965 StaticCtorDeclaration
*Parser::parseStaticCtor()
967 StaticCtorDeclaration
*f
;
974 f
= new StaticCtorDeclaration(loc
, 0);
979 /*****************************************
980 * Parse a static destructor definition:
981 * static ~this() { body }
982 * Current token is '~'.
985 StaticDtorDeclaration
*Parser::parseStaticDtor()
987 StaticDtorDeclaration
*f
;
995 f
= new StaticDtorDeclaration(loc
, 0);
1000 /*****************************************
1001 * Parse an invariant definition:
1002 * invariant { body }
1003 * Current token is 'invariant'.
1006 InvariantDeclaration
*Parser::parseInvariant()
1008 InvariantDeclaration
*f
;
1009 Loc loc
= this->loc
;
1014 if (token
.value
== TOKlparen
)
1019 f
= new InvariantDeclaration(loc
, 0);
1020 f
->fbody
= parseStatement(PScurly
);
1024 /*****************************************
1025 * Parse a unittest definition:
1027 * Current token is 'unittest'.
1030 UnitTestDeclaration
*Parser::parseUnitTest()
1032 UnitTestDeclaration
*f
;
1034 Loc loc
= this->loc
;
1038 body
= parseStatement(PScurly
);
1040 f
= new UnitTestDeclaration(loc
, this->loc
);
1045 /*****************************************
1046 * Parse a new definition:
1047 * new(arguments) { body }
1048 * Current token is 'new'.
1051 NewDeclaration
*Parser::parseNew()
1054 Arguments
*arguments
;
1056 Loc loc
= this->loc
;
1059 arguments
= parseParameters(&varargs
);
1060 f
= new NewDeclaration(loc
, 0, arguments
, varargs
);
1065 /*****************************************
1066 * Parse a delete definition:
1067 * delete(arguments) { body }
1068 * Current token is 'delete'.
1071 DeleteDeclaration
*Parser::parseDelete()
1073 DeleteDeclaration
*f
;
1074 Arguments
*arguments
;
1076 Loc loc
= this->loc
;
1079 arguments
= parseParameters(&varargs
);
1081 error("... not allowed in delete function parameter list");
1082 f
= new DeleteDeclaration(loc
, 0, arguments
);
1087 /**********************************************
1088 * Parse parameter list.
1091 Arguments
*Parser::parseParameters(int *pvarargs
)
1093 Arguments
*arguments
= new Arguments();
1103 unsigned storageClass
;
1108 storageClass
= 0; // parameter is "in" by default
1109 for (;1; nextToken())
1111 switch (token
.value
)
1122 if (peek(&token
)->value
== TOKlparen
)
1128 if (peek(&token
)->value
== TOKlparen
)
1133 case TOKin
: stc
= STCin
; goto L2
;
1134 case TOKout
: stc
= STCout
; goto L2
;
1136 case TOKref
: stc
= STCref
; goto L2
;
1137 case TOKlazy
: stc
= STClazy
; goto L2
;
1138 case TOKscope
: stc
= STCscope
; goto L2
;
1139 case TOKfinal
: stc
= STCfinal
; goto L2
;
1140 case TOKstatic
: stc
= STCstatic
; goto L2
;
1142 if (storageClass
& stc
||
1143 (storageClass
& STCin
&& stc
& (STCconst
| STCscope
)) ||
1144 (stc
& STCin
&& storageClass
& (STCconst
| STCscope
))
1146 error("redundant storage class %s", Token::toChars(token
.value
));
1147 storageClass
|= stc
;
1149 unsigned u
= storageClass
& (STCconst
| STCinvariant
);
1151 error("conflicting storage class %s", Token::toChars(token
.value
));
1157 stc
= storageClass
& (STCin
| STCout
| STCref
| STClazy
);
1158 if (stc
& (stc
- 1)) // if stc is not a power of 2
1159 error("incompatible parameter storage classes");
1160 if ((storageClass
& (STCconst
| STCout
)) == (STCconst
| STCout
))
1161 error("out cannot be const");
1162 if ((storageClass
& (STCinvariant
| STCout
)) == (STCinvariant
| STCout
))
1163 error("out cannot be invariant");
1164 if ((storageClass
& STCscope
) &&
1165 (storageClass
& (STCref
| STCout
)))
1166 error("scope cannot be ref or out");
1167 at
= parseType(&ai
);
1169 if (token
.value
== TOKassign
) // = defaultArg
1171 ae
= parseDefaultInitExp();
1176 error("default argument expected for %s",
1177 ai
? ai
->toChars() : at
->toChars());
1179 if (token
.value
== TOKdotdotdot
)
1184 if (storageClass
& (STCout
| STCref
))
1185 error("variadic argument cannot be out or ref");
1187 a
= new Argument(storageClass
, at
, ai
, ae
);
1192 a
= new Argument(storageClass
, at
, ai
, ae
);
1194 if (token
.value
== TOKcomma
)
1207 *pvarargs
= varargs
;
1212 /*************************************
1215 EnumDeclaration
*Parser::parseEnum()
1216 { EnumDeclaration
*e
;
1219 Loc loc
= this->loc
;
1221 //printf("Parser::parseEnum()\n");
1223 if (token
.value
== TOKidentifier
)
1230 if (token
.value
== (dltSyntax
? TOKextends
: TOKcolon
))
1233 memtype
= parseBasicType();
1234 memtype
= parseDeclarator(memtype
, NULL
, NULL
);
1239 e
= new EnumDeclaration(loc
, id
, memtype
);
1240 if ((token
.value
== TOKsemicolon
|| token
.value
== TOKendline
) && id
)
1242 else if (token
.value
== startBlockTok
)
1244 //printf("enum definition\n");
1245 e
->members
= new Array();
1247 unsigned char *comment
= token
.blockComment
;
1249 while (token
.value
!= TOKrcurly
)
1251 /* Can take the following forms:
1254 * 3. type ident = value
1261 Token
*tp
= peek(&token
);
1262 if (token
.value
== TOKidentifier
&&
1263 (tp
->value
== TOKassign
|| tp
->value
== TOKcomma
||
1264 tp
->value
== TOKendline
|| tp
->value
== TOKrcurly
))
1266 ident
= token
.ident
;
1272 type
= parseType(&ident
, NULL
);
1274 error("type only allowed if anonymous enum and no enum type");
1278 if (token
.value
== TOKassign
)
1281 value
= parseAssignExp();
1286 error("if type, there must be an initializer");
1289 EnumMember
*em
= new EnumMember(loc
, ident
, value
, type
);
1290 e
->members
->push(em
);
1294 if (token
.value
== TOKcomma
)
1296 else if (token
.value
!= TOKendline
)
1297 error("expected comma or newline after %s, not %s",
1298 em
->toChars(), token
.toChars());
1302 if (token
.value
== TOKrcurly
)
1305 { addComment(em
, comment
);
1310 addComment(em
, comment
);
1311 comment
= token
.blockComment
;
1316 error("enum declaration is invalid");
1317 //printf("-parseEnum() %s\n", e->toChars());
1321 Dsymbol
*Parser::parseAggregate()
1322 { AggregateDeclaration
*a
= NULL
;
1326 TemplateParameters
*tpl
= NULL
;
1328 //printf("Parser::parseAggregate()\n");
1331 if (token
.value
!= TOKidentifier
)
1338 if (token
.value
== TOKlparen
)
1339 { // Class template declaration.
1341 // Gather template parameter list
1342 tpl
= parseTemplateParameterList();
1346 Loc loc
= this->loc
;
1352 error("anonymous classes not allowed");
1354 // Collect base class(es)
1355 BaseClasses
*baseclasses
= parseBaseClasses();
1356 if (baseclasses
&& token
.value
!= startBlockTok
) {
1357 error("members expected");
1360 if (tok
== TOKclass
)
1361 a
= new ClassDeclaration(loc
, id
, baseclasses
, linkage
);
1363 a
= new InterfaceDeclaration(loc
, id
, baseclasses
, linkage
);
1369 a
= new StructDeclaration(loc
, id
);
1376 a
= new UnionDeclaration(loc
, id
);
1385 if (a
&& token
.value
== (dltSyntax
? TOKendline
: TOKsemicolon
))
1388 else if (token
.value
== startBlockTok
)
1390 //printf("aggregate definition\n");
1393 Array
*decl
= parseDeclDefs(0);
1394 if (token
.value
!= TOKrcurly
)
1395 error("end-of-block expected following member declarations in aggregate");
1399 /* Anonymous structs/unions are more like attributes.
1401 return new AnonDeclaration(loc
, anon
- 1, decl
);
1408 error("%s expected following aggregate declaration", Token::toChars(startBlockTok
));
1409 a
= new StructDeclaration(loc
, NULL
);
1414 TemplateDeclaration
*tempdecl
;
1416 // Wrap a template around the aggregate declaration
1417 decldefs
= new Array();
1419 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
, dltSyntax
);
1426 /*******************************************
1429 /* If current token is TOKcolon, TOKextends or TOKimplements, return
1430 * the bases. Otherwise, return null.
1432 BaseClasses
*Parser::parseBaseClasses()
1434 enum PROT protection
= PROTpublic
;
1435 int type
; // 1 = extends, 2 = implements, 3 = unknown
1438 if (token
.value
== TOKextends
)
1440 else if (token
.value
== TOKimplements
)
1445 if (token
.value
== TOKcolon
)
1453 BaseClasses
*baseclasses
= new BaseClasses();
1455 for (; 1; nextToken())
1457 enum PROT protection
= PROTpublic
;
1458 switch (token
.value
)
1461 protection
= PROTprivate
;
1465 protection
= PROTpackage
;
1469 protection
= PROTprotected
;
1473 protection
= PROTpublic
;
1477 if (token
.value
== TOKidentifier
)
1479 BaseClass
*b
= new BaseClass(parseBasicType(), protection
);
1480 baseclasses
->push(b
);
1482 switch (token
.value
) {
1487 error("extends part must come before implements");
1489 error("only one extends is permitted");
1495 error("separate implemented interfaces with commas");
1502 error("base classes expected instead of %s", token
.toChars());
1509 /**************************************
1510 * Parse a TemplateDeclaration.
1513 TemplateDeclaration
*Parser::parseTemplateDeclaration()
1515 TemplateDeclaration
*tempdecl
;
1517 TemplateParameters
*tpl
;
1519 Loc loc
= this->loc
;
1522 if (token
.value
!= TOKidentifier
)
1523 { error("TemplateIdentifier expected following template");
1528 tpl
= parseTemplateParameterList();
1532 if (token
.value
!= startBlockTok
)
1533 { error("members of template declaration expected");
1539 decldefs
= parseDeclDefs(0);
1540 if (token
.value
!= TOKrcurly
)
1541 { error("template member expected");
1547 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
, dltSyntax
);
1554 /******************************************
1555 * Parse template parameter list.
1557 * flag 0: parsing "( list )"
1558 * 1: parsing non-empty "list )"
1561 TemplateParameters
*Parser::parseTemplateParameterList(int flag
)
1563 TemplateParameters
*tpl
= new TemplateParameters();
1565 if (!flag
&& token
.value
!= TOKlparen
)
1566 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1571 // Get array of TemplateParameters
1572 if (flag
|| token
.value
!= TOKrparen
)
1573 { int isvariadic
= 0;
1576 { TemplateParameter
*tp
;
1577 Identifier
*tp_ident
= NULL
;
1578 Type
*tp_spectype
= NULL
;
1579 Type
*tp_valtype
= NULL
;
1580 Type
*tp_defaulttype
= NULL
;
1581 Expression
*tp_specvalue
= NULL
;
1582 Expression
*tp_defaultvalue
= NULL
;
1585 // Get TemplateParameter
1587 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1589 if (token
.value
== TOKalias
)
1592 if (token
.value
!= TOKidentifier
)
1593 { error("Identifier expected for template parameter");
1596 tp_ident
= token
.ident
;
1598 if (token
.value
== TOKcolon
) // : Type
1601 tp_spectype
= parseType();
1603 if (token
.value
== TOKassign
) // = Type
1606 tp_defaulttype
= parseType();
1608 tp
= new TemplateAliasParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1610 else if (t
->value
== TOKcolon
|| t
->value
== TOKassign
||
1611 t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
1613 if (token
.value
!= TOKidentifier
)
1614 { error("Identifier expected for template parameter");
1617 tp_ident
= token
.ident
;
1619 if (token
.value
== TOKcolon
) // : Type
1622 tp_spectype
= parseType();
1624 if (token
.value
== TOKassign
) // = Type
1627 tp_defaulttype
= parseType();
1629 tp
= new TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1631 else if (token
.value
== TOKidentifier
&& t
->value
== TOKdotdotdot
)
1634 error("variadic template parameter must be last");
1636 tp_ident
= token
.ident
;
1639 tp
= new TemplateTupleParameter(loc
, tp_ident
);
1641 else if (token
.value
== TOKthis
)
1644 if (token
.value
!= TOKidentifier
)
1645 { error("Identifier expected for template parameter");
1648 tp_ident
= token
.ident
;
1650 if (token
.value
== TOKcolon
) // : Type
1653 tp_spectype
= parseType();
1655 if (token
.value
== TOKassign
) // = Type
1658 tp_defaulttype
= parseType();
1660 tp
= new TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1664 tp_valtype
= parseType(&tp_ident
);
1667 error("no identifier for template value parameter");
1668 tp_ident
= new Identifier("error", TOKidentifier
);
1670 if (token
.value
== TOKcolon
) // : CondExpression
1673 tp_specvalue
= parseCondExp();
1675 if (token
.value
== TOKassign
) // = CondExpression
1678 tp_defaultvalue
= parseDefaultInitExp();
1680 tp
= new TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1683 if (token
.value
!= TOKcomma
)
1693 /******************************************
1694 * Parse template mixin.
1697 * mixin a.b.c!(args).Foo!(args);
1698 * mixin Foo!(args) identifier;
1699 * mixin typeof(expr).identifier!(args);
1702 Dsymbol
*Parser::parseMixin()
1710 //printf("parseMixin()\n");
1713 if (token
.value
== TOKdot
)
1719 if (token
.value
== TOKtypeof
)
1721 tqual
= parseTypeof();
1724 if (token
.value
!= TOKidentifier
)
1726 error("identifier expected, not %s", token
.toChars());
1733 idents
= new Array();
1737 if (token
.value
== TOKnot
)
1740 tiargs
= parseTemplateArgumentList();
1743 if (token
.value
!= TOKdot
)
1747 { TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
1748 tempinst
->tiargs
= tiargs
;
1749 id
= (Identifier
*)tempinst
;
1755 if (token
.value
!= TOKidentifier
)
1756 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1764 if (token
.value
== TOKidentifier
)
1772 tm
= new TemplateMixin(loc
, id
, tqual
, idents
, tiargs
);
1775 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
)
1776 error("newline expected after mixin");
1778 if (token
.value
!= TOKsemicolon
)
1779 error("';' expected after mixin");
1789 /******************************************
1790 * Parse template argument list.
1792 * current token is opening '('
1794 * current token is one after closing ')'
1797 Objects
*Parser::parseTemplateArgumentList()
1799 //printf("Parser::parseTemplateArgumentList()\n");
1800 if (token
.value
!= TOKlparen
)
1801 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1802 return new Objects();
1804 return parseTemplateArgumentList2();
1807 Objects
*Parser::parseTemplateArgumentList2()
1809 Objects
*tiargs
= new Objects();
1812 // Get TemplateArgumentList
1813 if (token
.value
!= TOKrparen
)
1817 // See if it is an Expression or a Type
1818 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
1822 // Get TemplateArgument
1830 ea
= parseAssignExp();
1833 if (token
.value
!= TOKcomma
)
1838 check(TOKrparen
, "template argument list");
1842 Import
*Parser::parseImport(Array
*decldefs
, int isstatic
)
1845 Identifier
*aliasid
= NULL
;
1849 if (dltSyntax
&& isstatic
)
1850 error("Delight imports are static by default");
1852 //printf("Parser::parseImport()\n");
1857 if (token
.value
!= TOKidentifier
)
1858 { error("Identifier expected following import");
1866 if (!aliasid
&& token
.value
== TOKassign
)
1871 while (token
.value
== TOKdot
)
1877 if (token
.value
!= TOKidentifier
)
1878 { error("Identifier expected following package");
1885 s
= new Import(loc
, a
, token
.ident
, aliasid
, isstatic
);
1889 * : alias=name, alias=name;
1892 if (token
.value
== TOKcolon
)
1901 if (dltSyntax
&& token
.value
== TOKrcurly
)
1903 if (dltSyntax
&& token
.value
== TOKmul
)
1910 if (token
.value
!= TOKidentifier
)
1911 { error("Identifier expected following :");
1914 alias
= token
.ident
;
1916 if (token
.value
== TOKassign
)
1919 if (token
.value
!= TOKidentifier
)
1920 { error("Identifier expected following %s=", alias
->toChars());
1930 s
->addAlias(name
, alias
);
1931 if (token
.value
!= TOKcomma
&& token
.value
!= TOKendline
)
1942 } else if (dltSyntax
) {
1947 } while (token
.value
== TOKcomma
);
1949 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
1953 error("%s expected", endToken());
1960 Type
*Parser::parseType(Identifier
**pident
, TemplateParameters
**tpl
)
1963 if (token
.value
== TOKconst
&& peek(&token
)->value
!= TOKlparen
)
1968 t
= parseType(pident
, tpl
);
1972 else if (token
.value
== TOKinvariant
&& peek(&token
)->value
!= TOKlparen
)
1977 t
= parseType(pident
, tpl
);
1978 t
= t
->makeInvariant();
1982 t
= parseBasicType();
1983 t
= parseDeclarator(t
, pident
, tpl
);
1987 Type
*Parser::parseBasicType()
1991 TemplateInstance
*tempinst
;
1993 //printf("parseBasicType()\n");
1994 switch (token
.value
)
1996 CASE_BASIC_TYPES_X(t
):
2003 if (token
.value
== TOKnot
)
2006 tempinst
= new TemplateInstance(loc
, id
);
2007 tempinst
->tiargs
= parseTemplateArgumentList();
2008 tid
= new TypeInstance(loc
, tempinst
);
2012 tid
= new TypeIdentifier(loc
, id
);
2014 while (token
.value
== TOKdot
)
2016 if (token
.value
!= TOKidentifier
)
2017 { error("identifier expected following '.' instead of '%s'", token
.toChars());
2022 if (token
.value
== TOKnot
)
2025 tempinst
= new TemplateInstance(loc
, id
);
2026 tempinst
->tiargs
= parseTemplateArgumentList();
2027 tid
->addIdent((Identifier
*)tempinst
);
2041 tid
= parseTypeof();
2060 t
= t
->makeInvariant();
2064 error("basic type expected, not %s", token
.toChars());
2071 Type
*Parser::parseBasicType2(Type
*t
)
2076 //printf("parseBasicType2()\n");
2079 switch (token
.value
)
2082 t
= new TypePointer(t
);
2087 // Handle []. Make sure things like
2089 // is (array[1] of array[3] of int)
2091 if (token
.value
== TOKrbracket
)
2093 t
= new TypeDArray(t
); // []
2096 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2097 { // It's an associative array declaration
2100 //printf("it's an associative array\n");
2101 index
= parseType(); // [ type ]
2102 t
= new TypeAArray(t
, index
);
2107 //printf("it's [expression]\n");
2109 Expression
*e
= parseExpression(); // [ expression ]
2110 if (token
.value
== TOKslice
)
2114 e2
= parseExpression(); // [ exp .. exp ]
2115 t
= new TypeSlice(t
, e
, e2
);
2118 t
= new TypeSArray(t
,e
);
2126 { // Handle delegate declaration:
2127 // t delegate(parameter list)
2128 // t function(parameter list)
2129 Arguments
*arguments
;
2131 bool ispure
= false;
2132 bool isnothrow
= false;
2133 enum TOK save
= token
.value
;
2136 arguments
= parseParameters(&varargs
);
2139 if (token
.value
== TOKpure
)
2141 else if (token
.value
== TOKnothrow
)
2147 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2148 tf
->ispure
= ispure
;
2149 tf
->isnothrow
= isnothrow
;
2150 if (save
== TOKdelegate
)
2151 t
= new TypeDelegate(tf
);
2153 t
= new TypePointer(tf
); // pointer to function
2158 // Allow maybe annotations even for D code. Makes it easier to adapt
2159 // D interfaces for Delight
2163 t
= t
->maybe(false);
2165 error("Type %s cannot be null; ? is pointless", old
->toChars());
2169 // fall-through to default
2181 Type
*Parser::parseDeclarator(Type
*t
, Identifier
**pident
, TemplateParameters
**tpl
)
2184 //printf("parseDeclarator(tpl = %p)\n", tpl);
2185 t
= parseBasicType2(t
);
2187 switch (token
.value
)
2192 *pident
= token
.ident
;
2194 error("unexpected identifer '%s' in declarator", token
.ident
->toChars());
2200 /* Parse things with parentheses around the identifier, like:
2202 * although the D style would be:
2206 ts
= parseDeclarator(t
, pident
);
2217 switch (token
.value
)
2220 /* Support C style array syntax:
2222 * as opposed to D-style:
2226 { // This is the old C-style post [] syntax.
2230 error("use 'type[] var', not 'type var[]'");
2233 if (token
.value
== TOKrbracket
)
2234 { // It's a dynamic array
2235 ta
= new TypeDArray(t
); // []
2238 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2239 { // It's an associative array
2241 //printf("it's an associative array\n");
2242 Type
*index
= parseType(); // [ type ]
2244 ta
= new TypeAArray(t
, index
);
2248 //printf("It's a static array\n");
2249 Expression
*e
= parseExpression(); // [ expression ]
2250 ta
= new TypeSArray(t
, e
);
2257 * ts -> ... -> ta -> t
2260 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2270 /* Look ahead to see if this is (...)(...),
2271 * i.e. a function template declaration
2273 if (peekPastParen(&token
)->value
== TOKlparen
)
2275 //printf("function template declaration\n");
2277 // Gather template parameter list
2278 *tpl
= parseTemplateParameterList();
2283 Arguments
*arguments
= parseParameters(&varargs
);
2284 Type
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2286 /* Parse const/invariant/nothrow postfix
2290 switch (token
.value
)
2293 tf
= tf
->makeConst();
2298 tf
= tf
->makeInvariant();
2303 ((TypeFunction
*)tf
)->isnothrow
= 1;
2308 ((TypeFunction
*)tf
)->ispure
= 1;
2318 * ts -> ... -> tf -> t
2321 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2333 /**********************************
2334 * Return array of Declaration *'s.
2337 Array
*Parser::parseDeclarations()
2339 enum STC storage_class
;
2347 unsigned char *comment
= token
.blockComment
;
2348 enum LINK link
= linkage
;
2350 //printf("parseDeclarations() %s\n", token.toChars());
2351 switch (token
.value
)
2364 storage_class
= STCundefined
;
2367 switch (token
.value
)
2370 if (peek(&token
)->value
== TOKlparen
)
2376 if (peek(&token
)->value
== TOKlparen
)
2381 case TOKstatic
: stc
= STCstatic
; goto L1
;
2382 case TOKfinal
: stc
= STCfinal
; goto L1
;
2383 case TOKauto
: stc
= STCauto
; goto L1
;
2384 case TOKscope
: stc
= STCscope
; goto L1
;
2385 case TOKoverride
: stc
= STCoverride
; goto L1
;
2386 case TOKabstract
: stc
= STCabstract
; goto L1
;
2387 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
2388 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
2389 case TOKnothrow
: stc
= STCnothrow
; goto L1
;
2390 case TOKpure
: stc
= STCpure
; goto L1
;
2391 case TOKtls
: stc
= STCtls
; goto L1
;
2392 case TOKenum
: stc
= STCmanifest
; goto L1
;
2394 if (storage_class
& stc
)
2395 error("redundant storage class '%s'", token
.toChars());
2396 storage_class
= (STC
) (storage_class
| stc
);
2398 unsigned u
= storage_class
;
2399 u
&= STCconst
| STCinvariant
| STCmanifest
;
2401 error("conflicting storage class %s", Token::toChars(token
.value
));
2407 if (peek(&token
)->value
!= TOKlparen
)
2412 link
= parseLinkage();
2423 /* Look for auto initializers:
2424 * storage_class identifier = initializer;
2426 while (storage_class
&&
2427 token
.value
== TOKidentifier
&&
2428 peek(&token
)->value
== TOKassign
)
2430 ident
= token
.ident
;
2433 Initializer
*init
= parseInitializer();
2434 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
2435 v
->storage_class
= storage_class
;
2436 v
->dltNormalMode
= dltNormalMode
;
2438 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
2441 addComment(v
, comment
);
2443 else if (token
.value
== TOKcomma
)
2446 if (!(token
.value
== TOKidentifier
&& peek(&token
)->value
== TOKassign
))
2448 error("Identifier expected following comma");
2454 error("%s expected following auto declaration, not '%s'", endToken(), token
.toChars());
2458 if (token
.value
== TOKclass
)
2459 { AggregateDeclaration
*s
;
2461 s
= (AggregateDeclaration
*)parseAggregate();
2462 s
->storage_class
|= storage_class
;
2464 addComment(s
, comment
);
2468 ts
= parseBasicType();
2469 ts
= parseBasicType2(ts
);
2474 Loc loc
= this->loc
;
2475 TemplateParameters
*tpl
= NULL
;
2478 t
= parseDeclarator(ts
, &ident
, &tpl
);
2482 else if (t
!= tfirst
)
2483 error("multiple declarations must have the same type, not %s and %s",
2484 tfirst
->toChars(), t
->toChars());
2486 error("no identifier for declarator %s", t
->toChars());
2488 if (tok
== TOKtypedef
|| tok
== TOKalias
)
2493 if (token
.value
== TOKassign
)
2496 init
= parseInitializer();
2498 if (tok
== TOKtypedef
)
2499 v
= new TypedefDeclaration(loc
, ident
, t
, init
);
2502 error("alias cannot have initializer");
2503 v
= new AliasDeclaration(loc
, ident
, t
);
2505 v
->storage_class
= storage_class
;
2506 if (link
== linkage
)
2510 Array
*ax
= new Array();
2512 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2515 switch (token
.value
)
2516 { case TOKsemicolon
:
2519 addComment(v
, comment
);
2524 addComment(v
, comment
);
2528 error("%s expected to close %s declaration", endToken(), Token::toChars(tok
));
2532 else if (t
->ty
== Tfunction
)
2533 { FuncDeclaration
*f
;
2536 f
= new FuncDeclaration(loc
, 0, ident
, storage_class
, t
);
2537 addComment(f
, comment
);
2539 addComment(f
, NULL
);
2540 if (link
== linkage
)
2546 Array
*ax
= new Array();
2548 s
= new LinkDeclaration(link
, ax
);
2550 if (tpl
) // it's a function template
2552 TemplateDeclaration
*tempdecl
;
2554 // Wrap a template around the aggregate declaration
2555 decldefs
= new Array();
2557 tempdecl
= new TemplateDeclaration(loc
, s
->ident
, tpl
, decldefs
, dltSyntax
);
2560 addComment(s
, comment
);
2564 { VarDeclaration
*v
;
2568 if (token
.value
== TOKassign
)
2571 init
= parseInitializer();
2573 v
= new VarDeclaration(loc
, t
, ident
, init
);
2575 v
->requirePointerInit
= true;
2576 v
->storage_class
= storage_class
;
2577 v
->dltNormalMode
= dltNormalMode
;
2578 if (link
== linkage
)
2582 Array
*ax
= new Array();
2584 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2587 switch (token
.value
)
2591 addComment(v
, comment
);
2596 addComment(v
, comment
);
2600 addComment(v
, comment
);
2604 error("%s expected, not '%s'", endToken(), token
.toChars());
2613 /*****************************************
2614 * Parse contracts following function declaration.
2617 void Parser::parseContracts(FuncDeclaration
*f
)
2620 enum LINK linksave
= linkage
;
2622 // The following is irrelevant, as it is overridden by sc->linkage in
2623 // TypeFunction::semantic
2624 linkage
= LINKd
; // nested functions have D linkage
2626 switch (token
.value
)
2630 if (token
.value
!= startBlockTok
)
2631 error("use %s to start a new block", Token::toChars(startBlockTok
));
2632 if (f
->frequire
|| f
->fensure
)
2633 error("missing body { ... } after in or out");
2634 f
->fbody
= parseStatement(PSsemi
| PScolon
);
2640 f
->fbody
= parseStatement(PScurly
);
2646 error("unexpected semi-colon after function declaration");
2649 if (f
->frequire
|| f
->fensure
)
2650 error("missing body { ... } after in or out");
2654 #if 0 // Do we want this for function declarations, so we can do:
2655 // int x, y, foo(), z;
2661 #if 0 // Dumped feature
2664 f
->fthrows
= new Array();
2669 tb
= parseBasicType();
2670 f
->fthrows
->push(tb
);
2671 if (token
.value
== TOKcomma
)
2684 error("redundant 'in' statement");
2685 f
->frequire
= parseStatement(PScurly
| PSscope
);
2689 // parse: out (identifier) { statement }
2691 if (token
.value
!= startBlockTok
)
2694 if (token
.value
!= TOKidentifier
)
2695 error("(identifier) following 'out' expected, not %s", token
.toChars());
2696 f
->outId
= token
.ident
;
2701 error("redundant 'out' statement");
2702 f
->fensure
= parseStatement(PScurly
| PSscope
);
2706 error("%s expected following function declaration", endToken());
2712 /*****************************************
2715 Initializer
*Parser::parseInitializer()
2717 StructInitializer
*is
;
2718 ArrayInitializer
*ia
;
2724 Loc loc
= this->loc
;
2728 switch (token
.value
)
2731 /* Scan ahead to see if it is a struct initializer or
2732 * a function literal.
2733 * If it contains a ';', it is a function literal.
2734 * Treat { } as a struct initializer.
2737 for (t
= peek(&token
); 1; t
= peek(t
))
2763 is
= new StructInitializer(loc
);
2768 switch (token
.value
)
2772 error("comma expected separating field initializers");
2774 if (t
->value
== TOKcolon
)
2778 nextToken(); // skip over ':'
2783 value
= parseInitializer();
2784 is
->addInit(id
, value
);
2793 case TOKrcurly
: // allow trailing comma's
2798 error("found EOF instead of initializer");
2802 value
= parseInitializer();
2803 is
->addInit(NULL
, value
);
2806 //error("found '%s' instead of field initializer", token.toChars());
2814 ia
= new ArrayInitializer(loc
);
2819 switch (token
.value
)
2823 { error("comma expected separating array initializers, not %s", token
.toChars());
2827 e
= parseAssignExp();
2830 if (token
.value
== TOKcolon
)
2833 value
= parseInitializer();
2836 { value
= new ExpInitializer(e
->loc
, e
);
2839 ia
->addInit(e
, value
);
2846 error("comma expected separating array initializers, not %s", token
.toChars());
2847 value
= parseInitializer();
2848 ia
->addInit(NULL
, value
);
2857 case TOKrbracket
: // allow trailing comma's
2862 error("found '%s' instead of array initializer", token
.toChars());
2871 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
|| t
->value
== TOKendline
)
2874 return new VoidInitializer(loc
);
2880 e
= parseAssignExp();
2881 ie
= new ExpInitializer(loc
, e
);
2886 /*****************************************
2887 * Parses default argument initializer expression that is an assign expression,
2888 * with special handling for __FILE__ and __LINE__.
2891 Expression
*Parser::parseDefaultInitExp()
2893 if (token
.value
== TOKfile
||
2894 token
.value
== TOKline
)
2896 Token
*t
= peek(&token
);
2897 if (t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
2900 if (token
.value
== TOKfile
)
2901 e
= new FileInitExp(loc
);
2903 e
= new LineInitExp(loc
);
2909 Expression
*e
= parseAssignExp();
2913 Statement
*Parser::logStatement(int level
) {
2915 if (token
.value
!= TOKlparen
)
2916 error(loc
, "found '%s' when expecting '('", token
.toChars());
2917 return new LogStatement(loc
, level
, parseArguments());
2920 /*****************************************
2925 Statement
*DltParser::parseStatement(int flags
)
2928 if (flags
& (PScolon
| PSscope
))
2930 return Parser::parseStatement(flags
);
2933 Statement
*Parser::parseStatement(int flags
)
2936 Condition
*condition
;
2938 Statement
*elsebody
;
2939 Loc loc
= this->loc
;
2941 //printf("parseStatement()\n");
2943 if ((flags
& PScurly
) && token
.value
!= startBlockTok
)
2944 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
2946 int tok
= token
.value
;
2948 switch (token
.value
)
2953 // Need to look ahead to see if it is a declaration, label, or expression
2955 if (t
->value
== TOKcolon
)
2959 ident
= token
.ident
;
2962 s
= parseStatement(PSsemi
);
2963 s
= new LabelStatement(loc
, ident
, s
);
2967 // fallthrough to TOKdot
2970 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2986 case TOKimaginary32v
:
2987 case TOKimaginary64v
:
2988 case TOKimaginary80v
:
3016 exp
= parseExpression();
3018 check(TOKsemicolon
, "statement");
3019 s
= new ExpStatement(loc
, exp
);
3024 { // Look ahead to see if it's static assert() or static if()
3028 if (t
->value
== TOKassert
)
3031 s
= new StaticAssertStatement(parseStaticAssert());
3034 if (t
->value
== TOKif
)
3037 condition
= parseStaticIfCondition();
3041 error("no static variables in Delight");
3057 a
= parseDeclarations();
3060 Statements
*as
= new Statements();
3061 as
->reserve(a
->dim
);
3062 for (int i
= 0; i
< a
->dim
; i
++)
3064 Dsymbol
*d
= (Dsymbol
*)a
->data
[i
];
3065 s
= new DeclarationStatement(loc
, d
);
3068 s
= new CompoundStatement(loc
, as
);
3070 else if (a
->dim
== 1)
3072 Dsymbol
*d
= (Dsymbol
*)a
->data
[0];
3073 s
= new DeclarationStatement(loc
, d
);
3077 if (flags
& PSscope
)
3078 s
= new ScopeStatement(loc
, s
);
3088 d
= parseAggregate();
3089 s
= new DeclarationStatement(loc
, d
);
3094 { /* Determine if this is a manifest constant declaration,
3095 * or a conventional enum.
3098 Token
*t
= peek(&token
);
3099 if (t
->value
== startBlockTok
||
3100 t
->value
== (dltSyntax
? TOKextends
: TOKcolon
))
3104 else if (t
->value
!= TOKidentifier
)
3109 if (t
->value
== startBlockTok
||
3110 t
->value
== (dltSyntax
? TOKextends
: TOKcolon
) ||
3111 t
->value
== TOKsemicolon
)
3116 s
= new DeclarationStatement(loc
, d
);
3122 if (t
->value
== TOKlparen
)
3125 check(TOKlparen
, "mixin");
3126 Expression
*e
= parseAssignExp();
3129 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3130 error("expected newline after mixin(), not '%s'", token
.toChars());
3133 check(TOKsemicolon
);
3135 s
= new CompileStatement(loc
, e
);
3138 Dsymbol
*d
= parseMixin();
3139 s
= new DeclarationStatement(loc
, d
);
3145 { Statements
*statements
;
3147 if (token
.value
!= startBlockTok
)
3148 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
3152 statements
= new Statements();
3153 while (token
.value
!= TOKrcurly
)
3155 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3159 s
= new CompoundStatement(loc
, statements
);
3160 if (flags
& (PSscope
| PScurlyscope
))
3161 s
= new ScopeStatement(loc
, s
);
3166 case TOKlog_error
: s
= logStatement(LogStatement::Error
); break;
3167 case TOKlog_warning
: s
= logStatement(LogStatement::Warn
); break;
3168 case TOKlog_info
: s
= logStatement(LogStatement::Info
); break;
3169 case TOKlog_trace
: s
= logStatement(LogStatement::Trace
); break;
3172 { Expression
*condition
;
3177 condition
= parseExpression();
3179 body
= parseStatement(PSscope
);
3180 s
= new WhileStatement(loc
, condition
, body
);
3185 if (!(flags
& PSsemi
))
3186 error("use '{ }' for an empty statement, not a ';'");
3188 s
= new ExpStatement(loc
, NULL
);
3193 Expression
*condition
;
3196 body
= parseStatement(PSscope
);
3199 condition
= parseExpression();
3201 s
= new DoStatement(loc
, body
, condition
);
3208 Expression
*condition
;
3209 Expression
*increment
;
3214 if (token
.value
== TOKlparen
) {
3215 /* for (init; cond; incr): ... */
3217 if (token
.value
== TOKsemicolon
)
3222 { init
= parseStatement(0);
3224 check(TOKsemicolon
);
3226 if (token
.value
== TOKsemicolon
)
3233 condition
= parseExpression();
3234 check(TOKsemicolon
, "for condition");
3236 if (token
.value
== TOKrparen
)
3241 { increment
= parseExpression();
3244 body
= parseStatement(PSscope
);
3245 s
= new ForStatement(loc
, init
, condition
, increment
, body
);
3247 s
= new ScopeStatement(loc
, s
);
3248 } else if (dltSyntax
)
3255 case TOKforeach_reverse
:
3257 /* for var in seq: ... */
3258 /* for index, var in seq: ... */
3259 Arguments
*arguments
;
3264 enum TOK op
= (TOK
) tok
;
3267 op
= TOKforeach
; // Delight foreach syntax
3273 TOK inTok
= dltSyntax
? TOKin
: TOKsemicolon
;
3275 arguments
= new Arguments();
3280 Identifier
*ai
= NULL
;
3282 unsigned storageClass
;
3286 if (token
.value
== TOKinout
|| token
.value
== TOKref
)
3287 { storageClass
= STCref
;
3290 if (token
.value
== TOKidentifier
)
3292 Token
*t
= peek(&token
);
3293 if (t
->value
== TOKcomma
|| t
->value
== inTok
)
3295 at
= NULL
; // infer argument type
3300 at
= parseType(&ai
);
3302 error("no identifier for declarator %s", at
->toChars());
3304 a
= new Argument(storageClass
, at
, ai
, NULL
);
3306 if (token
.value
== TOKcomma
)
3315 aggr
= parseExpression();
3316 if (token
.value
== TOKslice
&& arguments
->dim
== 1)
3318 Argument
*a
= (Argument
*)arguments
->data
[0];
3321 Expression
*upr
= parseExpression();
3323 if (token
.value
== TOKreserved
)
3325 op
= TOKforeach_reverse
;
3328 body
= parseStatement(0);
3329 s
= new ForeachRangeStatement(loc
, op
, a
, aggr
, upr
, body
);
3334 if (token
.value
== TOKreversed
)
3336 op
= TOKforeach_reverse
;
3339 body
= parseStatement(0);
3340 s
= new ForeachStatement(loc
, op
, arguments
, aggr
, body
);
3346 { Argument
*arg
= NULL
;
3347 Expression
*condition
;
3349 Statement
*elsebody
;
3354 if (token
.value
== TOKauto
)
3357 if (token
.value
== TOKidentifier
)
3359 Token
*t
= peek(&token
);
3360 if (t
->value
== TOKassign
)
3362 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3367 { error("= expected following auto identifier");
3372 { error("identifier expected following auto");
3376 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
3381 at
= parseType(&ai
);
3383 arg
= new Argument(0, at
, ai
, NULL
);
3386 // Check for " ident;"
3387 else if (token
.value
== TOKidentifier
&& !dltSyntax
)
3389 Token
*t
= peek(&token
);
3390 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
3392 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3395 if (1 || !global
.params
.useDeprecated
)
3396 error("if (v; e) is deprecated, use if (auto v = e)");
3400 condition
= parseExpression();
3402 ifbody
= parseStatement(PSscope
);
3403 if (token
.value
== TOKelse
)
3408 if (token
.value
== TOKcolon
) {
3409 elsebody
= parseStatement(PSscope
);
3410 } else if (token
.value
== TOKif
) {
3411 elsebody
= parseStatement(0);
3413 error("Expected 'else:' or 'else if', not 'else %s'", token
.toChars());
3418 elsebody
= parseStatement(PSscope
);
3422 s
= new IfStatement(loc
, arg
, condition
, ifbody
, elsebody
);
3427 if (peek(&token
)->value
!= TOKlparen
)
3428 goto Ldeclaration
; // scope used as storage class
3431 if (token
.value
!= TOKidentifier
)
3432 { error("scope identifier expected");
3436 { TOK t
= TOKon_scope_exit
;
3437 Identifier
*id
= token
.ident
;
3440 t
= TOKon_scope_exit
;
3441 else if (id
== Id::failure
)
3442 t
= TOKon_scope_failure
;
3443 else if (id
== Id::success
)
3444 t
= TOKon_scope_success
;
3446 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
3449 Statement
*st
= parseStatement(PScolon
| PScurlyscope
);
3450 s
= new OnScopeStatement(loc
, t
, st
);
3456 condition
= parseDebugCondition();
3461 condition
= parseVersionCondition();
3465 if (dltSyntax
&& token
.value
!= TOKcolon
)
3466 error("expected colon after condition, not '%s'", token
.toChars());
3467 ifbody
= parseStatement(PScolon
/*PSsemi*/);
3469 if (token
.value
== TOKelse
)
3472 elsebody
= parseStatement(PScolon
/*PSsemi*/);
3474 s
= new ConditionalStatement(loc
, condition
, ifbody
, elsebody
);
3478 { Identifier
*ident
;
3479 Expressions
*args
= NULL
;
3484 if (token
.value
!= TOKidentifier
)
3485 { error("pragma(identifier expected");
3488 ident
= token
.ident
;
3490 if (token
.value
== TOKcomma
)
3491 args
= parseArguments(); // pragma(identifier, args...);
3493 check(TOKrparen
); // pragma(identifier);
3494 if (token
.value
== TOKsemicolon
)
3499 body
= parseStatement(PSsemi
| PScolon
);
3500 s
= new PragmaStatement(loc
, ident
, args
, body
);
3505 { Expression
*condition
;
3510 condition
= parseExpression();
3512 body
= parseStatement(PSscope
| PScolon
);
3513 s
= new SwitchStatement(loc
, condition
, body
);
3519 Statements
*statements
;
3520 Array cases
; // array of Expression's
3525 exp
= parseAssignExp();
3527 if (token
.value
!= TOKcomma
)
3533 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3539 statements
= new Statements();
3540 while (token
.value
!= TOKcase
&&
3541 token
.value
!= TOKdefault
&&
3542 token
.value
!= TOKrcurly
)
3544 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3546 s
= new CompoundStatement(loc
, statements
);
3549 s
= new ScopeStatement(loc
, s
);
3551 // Keep cases in order by building the case statements backwards
3552 for (int i
= cases
.dim
; i
; i
--)
3554 exp
= (Expression
*)cases
.data
[i
- 1];
3555 s
= new CaseStatement(loc
, exp
, s
);
3562 Statements
*statements
;
3568 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3574 statements
= new Statements();
3575 while (token
.value
!= TOKcase
&&
3576 token
.value
!= TOKdefault
&&
3577 token
.value
!= TOKrcurly
)
3579 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3581 s
= new CompoundStatement(loc
, statements
);
3584 s
= new ScopeStatement(loc
, s
);
3585 s
= new DefaultStatement(loc
, s
);
3593 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
3596 exp
= parseExpression();
3599 check(TOKsemicolon
, "return statement");
3600 else if (token
.value
!= TOKendline
) {
3601 error("Expected end-of-line after return statement, but found '%s'", token
.toChars());
3604 s
= new ReturnStatement(loc
, exp
);
3609 { Identifier
*ident
;
3612 if (token
.value
== TOKidentifier
)
3613 { ident
= token
.ident
;
3618 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3619 error("expected %s after break, not '%s'", endToken(), token
.toChars());
3623 s
= new BreakStatement(loc
, ident
);
3628 { Identifier
*ident
;
3631 if (token
.value
== TOKidentifier
)
3632 { ident
= token
.ident
;
3638 check(TOKsemicolon
, "continue statement");
3639 else if (token
.value
!= TOKendline
&& token
.value
!= TOKsemicolon
) {
3640 error("Expected end-of-line after continue statement, but found '%s'", token
.toChars());
3642 s
= new ContinueStatement(loc
, ident
);
3647 { Identifier
*ident
;
3650 if (token
.value
== TOKdefault
)
3653 s
= new GotoDefaultStatement(loc
);
3655 else if (token
.value
== TOKcase
)
3657 Expression
*exp
= NULL
;
3660 if (token
.value
!= TOKsemicolon
)
3661 exp
= parseExpression();
3662 s
= new GotoCaseStatement(loc
, exp
);
3666 if (token
.value
!= TOKidentifier
)
3667 { error("Identifier expected following goto");
3671 { ident
= token
.ident
;
3674 s
= new GotoStatement(loc
, ident
);
3678 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3679 error("expected %s after goto statement, not '%s'", endToken(), token
.toChars());
3683 check(TOKsemicolon
);
3687 case TOKsynchronized
:
3692 if (token
.value
== TOKlparen
)
3695 exp
= parseExpression();
3700 body
= parseStatement(PSscope
);
3701 s
= new SynchronizedStatement(loc
, exp
, body
);
3711 exp
= parseExpression();
3713 body
= parseStatement(PSscope
);
3714 s
= new WithStatement(loc
, exp
, body
);
3720 Array
*catches
= NULL
;
3721 Statement
*finalbody
= NULL
;
3724 body
= parseStatement(PSscope
);
3725 while (token
.value
== TOKcatch
)
3731 Loc loc
= this->loc
;
3734 if (token
.value
== startBlockTok
)
3746 handler
= parseStatement(PScolon
);
3747 c
= new Catch(loc
, t
, id
, handler
);
3749 catches
= new Array();
3753 if (token
.value
== TOKfinally
)
3755 finalbody
= parseStatement(PScolon
);
3759 if (!catches
&& !finalbody
)
3760 error("catch or finally expected following try");
3763 s
= new TryCatchStatement(loc
, body
, catches
);
3765 s
= new TryFinallyStatement(loc
, s
, finalbody
);
3774 exp
= parseExpression();
3775 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3776 error("%s expected after throw statement, not '%s'", endToken(), token
.toChars());
3780 s
= new ThrowStatement(loc
, exp
);
3786 s
= parseStatement(PSsemi
| PScurlyscope
);
3787 if (!global
.params
.useDeprecated
)
3788 error("volatile statements deprecated; used synchronized statements instead");
3789 s
= new VolatileStatement(loc
, s
);
3793 { Statements
*statements
;
3799 // Parse the asm block into a sequence of AsmStatements,
3800 // each AsmStatement is one instruction.
3801 // Separate out labels.
3802 // Defer parsing of AsmStatements until semantic processing.
3805 #if GDC_EXTENDED_ASM_SYNTAX
3806 if (token
.value
== TOKlparen
)
3813 check(startBlockTok
);
3815 ptoklist
= &toklist
;
3817 statements
= new Statements();
3820 switch (token
.value
)
3825 // Look ahead to see if it is a label
3827 if (t
->value
== TOKcolon
)
3829 label
= token
.ident
;
3830 labelloc
= this->loc
;
3839 if (toklist
|| label
)
3841 error("asm statements must end in ';'");
3848 if (toklist
|| label
)
3849 { // Create AsmStatement from list of tokens we've saved
3850 s
= new AsmStatement(this->loc
, toklist
);
3852 ptoklist
= &toklist
;
3854 { s
= new LabelStatement(labelloc
, label
, s
);
3857 statements
->push(s
);
3864 error("matching '}' expected, not end of file");
3869 // If the first token is a string or '(', parse as extended asm.
3873 statements
->push(s
);
3876 // ...else, drop through.
3880 *ptoklist
= new Token();
3881 memcpy(*ptoklist
, &token
, sizeof(Token
));
3882 ptoklist
= &(*ptoklist
)->next
;
3890 s
= new CompoundStatement(loc
, statements
);
3896 error("found '%s' instead of statement", token
.toChars());
3900 while (token
.value
!= TOKrcurly
&&
3901 token
.value
!= TOKsemicolon
&&
3902 token
.value
!= TOKeof
)
3904 if (token
.value
== TOKsemicolon
)
3913 Statement
*Parser::parseExtAsm(int expect_rparen
)
3915 Expression
* insnTemplate
;
3916 Expressions
* args
= NULL
;
3917 Array
* argNames
= NULL
;
3918 Expressions
* argConstraints
= NULL
;
3919 int nOutputArgs
= 0;
3920 Expressions
* clobbers
= NULL
;
3921 bool isInputPhase
= false; // Output operands first, then input.
3923 insnTemplate
= parseExpression();
3924 if (token
.value
== TOKrparen
|| token
.value
== TOKsemicolon
)
3928 Expression
* arg
= NULL
;
3929 Identifier
* name
= NULL
;
3930 Expression
* constraint
= NULL
;
3932 switch (token
.value
)
3943 error("unterminated statement");
3947 if (token
.value
== TOKidentifier
)
3953 error("expected identifier after '['");
3957 constraint
= parsePrimaryExp();
3958 if (constraint
->op
!= TOKstring
)
3959 error("expected constant string constraint for operand");
3960 arg
= parseAssignExp();
3963 args
= new Expressions
;
3964 argConstraints
= new Expressions
;
3965 argNames
= new Array
;
3968 argNames
->push(name
);
3969 argConstraints
->push(constraint
);
3973 if (token
.value
== TOKcomma
)
3980 isInputPhase
= true;
3987 Expression
* clobber
;
3989 switch (token
.value
)
3996 error("unterminated statement");
3999 clobber
= parseAssignExp();
4000 if (clobber
->op
!= TOKstring
)
4001 error("expected constant string constraint for clobber name");
4003 clobbers
= new Expressions
;
4004 clobbers
->push(clobber
);
4006 if (token
.value
== TOKcomma
)
4015 check(TOKsemicolon
);
4017 return new ExtAsmStatement(loc
, insnTemplate
, args
, argNames
,
4018 argConstraints
, nOutputArgs
, clobbers
);
4021 void Parser::optionalEndline() {
4022 while (token
.value
== TOKendline
) {
4027 void Parser::check(enum TOK value
)
4032 void Parser::check(Loc loc
, enum TOK value
)
4034 if (token
.value
!= value
)
4035 error(loc
, "found '%s' when expecting '%s'", token
.toChars(), Token::toChars(value
));
4039 void Parser::check(enum TOK value
, char *string
)
4041 if (token
.value
!= value
)
4042 error("found '%s' when expecting '%s' following '%s'",
4043 token
.toChars(), Token::toChars(value
), string
);
4047 char *Parser::endToken()
4052 char *DltParser::endToken()
4057 void Parser::checkLParen() { check(TOKlparen
); }
4058 void Parser::checkRParen() { check(TOKrparen
); }
4060 void DltParser::checkLParen() { }
4061 void DltParser::checkRParen() { }
4063 /************************************
4064 * Determine if the scanner is sitting on the start of a declaration.
4066 * needId 0 no identifier
4067 * 1 identifier optional
4068 * 2 must have identifier
4071 int Parser::isDeclaration(Token
*t
, int needId
, enum TOK endtok
, Token
**pt
)
4075 if ((t
->value
== TOKconst
|| t
->value
== TOKinvariant
) &&
4076 peek(t
)->value
!= TOKlparen
)
4083 if (!isBasicType(&t
))
4085 if (!isDeclarator(&t
, &haveId
, endtok
))
4088 (needId
== 0 && !haveId
) ||
4089 (needId
== 2 && haveId
))
4098 int Parser::isBasicType(Token
**pt
)
4100 // This code parallels parseBasicType()
4114 if (t
->value
== TOKnot
)
4124 if (t
->value
== TOKdot
)
4128 if (t
->value
!= TOKidentifier
)
4131 if (t
->value
!= TOKnot
)
4135 if (t
->value
!= TOKlparen
)
4137 if (!skipParens(t
, &t
))
4149 /* typeof(exp).identifier...
4152 if (t
->value
!= TOKlparen
)
4154 if (!skipParens(t
, &t
))
4160 // const(type) or invariant(type)
4162 if (t
->value
!= TOKlparen
)
4165 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
4180 int Parser::isDeclarator(Token
**pt
, int *haveId
, enum TOK endtok
)
4181 { // This code parallels parseDeclarator()
4185 //printf("Parser::isDeclarator()\n");
4187 if (t
->value
== TOKassign
)
4203 if (t
->value
== TOKrbracket
)
4207 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
4208 { // It's an associative array declaration
4214 // [ expression .. expression ]
4215 if (!isExpression(&t
))
4217 if (t
->value
== TOKslice
)
4219 if (!isExpression(&t
))
4222 if (t
->value
!= TOKrbracket
)
4238 if (t
->value
== TOKrparen
)
4239 return FALSE
; // () is not a declarator
4241 /* Regard ( identifier ) as not a declarator
4242 * BUG: what about ( *identifier ) in
4244 * where f is a class instance with overloaded () ?
4245 * Should we just disallow C-style function pointer declarations?
4247 if (t
->value
== TOKidentifier
)
4248 { Token
*t2
= peek(t
);
4249 if (t2
->value
== TOKrparen
)
4254 if (!isDeclarator(&t
, haveId
, TOKrparen
))
4263 if (!isParameters(&t
))
4278 if (t
->value
== TOKrbracket
)
4282 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
4283 { // It's an associative array declaration
4289 if (!isExpression(&t
))
4291 if (t
->value
!= TOKrbracket
)
4300 if (!isParameters(&t
))
4302 if (t
->value
== TOKconst
|| t
->value
== TOKinvariant
)
4306 // Valid tokens that follow a declaration
4316 if ((dltSyntax
&& t
->value
== TOKlcurly
) ||
4317 (!dltSyntax
&& t
->value
== TOKcolon
)) {
4321 // The !parens is to disallow unnecessary parentheses
4322 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
4335 int Parser::isParameters(Token
**pt
)
4336 { // This code parallels parseParameters()
4340 //printf("isParameters()\n");
4341 if (t
->value
!= TOKlparen
)
4345 for (;1; t
= peek(t
))
4368 if (!isBasicType(&t
))
4371 if (t
->value
!= TOKdotdotdot
&&
4372 !isDeclarator(&t
, &tmp
, TOKreserved
))
4374 if (t
->value
== TOKassign
)
4376 if (!isExpression(&t
))
4379 if (t
->value
== TOKdotdotdot
)
4384 if (t
->value
== TOKcomma
)
4392 if (t
->value
!= TOKrparen
)
4399 int Parser::isExpression(Token
**pt
)
4401 // This is supposed to determine if something is an expression.
4402 // What it actually does is scan until a closing right bracket
4410 for (;; t
= peek(t
))
4428 if (brnest
|| panest
)
4442 if (--curlynest
>= 0)
4469 /**********************************************
4471 * instance foo.bar(parameters...)
4473 * if (pt), *pt is set to the token following the closing )
4475 * 1 it's valid instance syntax
4476 * 0 invalid instance syntax
4479 int Parser::isTemplateInstance(Token
*t
, Token
**pt
)
4482 if (t
->value
!= TOKdot
)
4484 if (t
->value
!= TOKidentifier
)
4488 while (t
->value
== TOKdot
)
4491 if (t
->value
!= TOKidentifier
)
4495 if (t
->value
!= TOKlparen
)
4498 // Skip over the template arguments
4507 if (!skipParens(t
, &t
))
4523 if (t
->value
!= TOKcomma
)
4526 if (t
->value
!= TOKrparen
)
4537 /*******************************************
4538 * Skip parens, brackets.
4542 * *pt is set to closing token, which is ')' on success
4545 * 0 some parsing error
4548 int Parser::skipParens(Token
*t
, Token
**pt
)
4587 /********************************* Expression Parser ***************************/
4589 Expression
*Parser::parsePrimaryExp()
4594 Loc loc
= this->loc
;
4596 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4597 switch (token
.value
)
4602 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4603 { // identifier!(template-argument-list)
4604 TemplateInstance
*tempinst
;
4606 tempinst
= new TemplateInstance(loc
, id
);
4608 tempinst
->tiargs
= parseTemplateArgumentList();
4609 e
= new ScopeExp(loc
, tempinst
);
4612 e
= new IdentifierExp(loc
, id
);
4617 error("'$' is valid only inside [] of index or slice");
4618 e
= new DollarExp(loc
);
4623 // Signal global scope '.' operator with "" identifier
4624 e
= new IdentifierExp(loc
, Id::empty
);
4628 e
= new ThisExp(loc
);
4633 e
= new SuperExp(loc
);
4638 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
4643 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
4648 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
4653 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
4658 e
= new RealExp(loc
, token
.float80value
, Type::tfloat32
);
4663 e
= new RealExp(loc
, token
.float80value
, Type::tfloat64
);
4668 e
= new RealExp(loc
, token
.float80value
, Type::tfloat80
);
4672 case TOKimaginary32v
:
4673 e
= new RealExp(loc
, token
.float80value
, Type::timaginary32
);
4677 case TOKimaginary64v
:
4678 e
= new RealExp(loc
, token
.float80value
, Type::timaginary64
);
4682 case TOKimaginary80v
:
4683 e
= new RealExp(loc
, token
.float80value
, Type::timaginary80
);
4688 e
= new NullExp(loc
);
4689 ((NullExp
*) e
)->dUnchecked
= !dltSyntax
;
4694 { char *s
= loc
.filename
? loc
.filename
: mod
->ident
->toChars();
4695 e
= new StringExp(loc
, s
, strlen(s
), 0);
4701 e
= new IntegerExp(loc
, loc
.linnum
, Type::tint32
);
4706 e
= new IntegerExp(loc
, 1, Type::tbool
);
4711 e
= new IntegerExp(loc
, 0, Type::tbool
);
4716 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tchar
);
4721 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::twchar
);
4726 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
4733 unsigned char postfix
;
4735 // cat adjacent strings
4738 postfix
= token
.postfix
;
4742 if (token
.value
== TOKstring
)
4748 { if (token
.postfix
!= postfix
)
4749 error("mismatched string literal postfixes '%c' and '%c'", postfix
, token
.postfix
);
4750 postfix
= token
.postfix
;
4756 s2
= (unsigned char *)mem
.malloc((len
+ 1) * sizeof(unsigned char));
4757 memcpy(s2
, s
, len1
* sizeof(unsigned char));
4758 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(unsigned char));
4764 e
= new StringExp(loc
, s
, len
, postfix
);
4768 CASE_BASIC_TYPES_X(t
):
4771 check(TOKdot
, t
->toChars());
4772 if (token
.value
!= TOKidentifier
)
4773 { error("found '%s' when expecting identifier following '%s.'", token
.toChars(), t
->toChars());
4776 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4783 if (token
.value
== TOKdot
)
4785 e
= new TypeExp(loc
, t
);
4793 check(TOKlparen
, "typeid");
4794 t
= parseType(); // ( type )
4796 e
= new TypeidExp(loc
, t
);
4801 { /* __traits(identifier, args...)
4804 Objects
*args
= NULL
;
4808 if (token
.value
!= TOKidentifier
)
4809 { error("__traits(identifier, args...) expected");
4812 ident
= token
.ident
;
4814 if (token
.value
== TOKcomma
)
4815 args
= parseTemplateArgumentList2(); // __traits(identifier, args...)
4817 check(TOKrparen
); // __traits(identifier)
4819 e
= new TraitsExp(loc
, ident
, args
);
4825 Identifier
*ident
= NULL
;
4827 enum TOK tok
= TOKreserved
;
4828 enum TOK tok2
= TOKreserved
;
4829 TemplateParameters
*tpl
= NULL
;
4830 Loc loc
= this->loc
;
4833 if (token
.value
== TOKlparen
)
4836 targ
= parseType(&ident
);
4837 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
4841 if (tok
== TOKequal
&&
4842 (token
.value
== TOKtypedef
||
4843 token
.value
== TOKstruct
||
4844 token
.value
== TOKunion
||
4845 token
.value
== TOKclass
||
4846 token
.value
== TOKsuper
||
4847 token
.value
== TOKenum
||
4848 token
.value
== TOKinterface
||
4849 token
.value
== TOKconst
&& peek(&token
)->value
== TOKrparen
||
4850 token
.value
== TOKinvariant
&& peek(&token
)->value
== TOKrparen
||
4851 token
.value
== TOKfunction
||
4852 token
.value
== TOKdelegate
||
4853 token
.value
== TOKreturn
))
4860 tspec
= parseType();
4865 if (token
.value
== TOKcomma
)
4866 tpl
= parseTemplateParameterList(1);
4868 { tpl
= new TemplateParameters();
4871 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, ident
, NULL
, NULL
);
4878 { error("(type identifier : specialization) expected following is");
4881 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
4886 { Expression
*msg
= NULL
;
4891 e
= parseAssignExp();
4892 if (token
.value
== (dltSyntax
? TOKelse
: TOKcomma
))
4894 msg
= parseAssignExp();
4895 } else if (token
.value
== TOKcomma
)
4896 error("Suspicious comma after assert; try 'else' instead");
4899 e
= new AssertExp(loc
, e
, msg
);
4906 check(TOKlparen
, "mixin");
4907 e
= parseAssignExp();
4909 e
= new CompileExp(loc
, e
);
4916 check(TOKlparen
, "import");
4917 e
= parseAssignExp();
4919 e
= new FileExp(loc
, e
);
4924 if (peekPastParen(&token
)->value
== startBlockTok
)
4925 { // (arguments) { statements... }
4931 e
= parseExpression();
4932 check(loc
, TOKrparen
);
4936 { /* Parse array literals and associative array literals:
4937 * [ value, value, value ... ]
4938 * [ key:value, key:value, key:value ... ]
4940 Expressions
*values
= new Expressions();
4941 Expressions
*keys
= NULL
;
4944 if (token
.value
!= TOKrbracket
)
4948 Expression
*e
= parseAssignExp();
4949 if (token
.value
== TOKcolon
&& (keys
|| values
->dim
== 0))
4952 keys
= new Expressions();
4954 e
= parseAssignExp();
4957 { error("'key:value' expected for associative array literal");
4962 if (token
.value
== TOKrbracket
)
4970 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
4972 e
= new ArrayLiteralExp(loc
, values
);
4977 // { statements... }
4987 /* function type(parameters) { body }
4988 * delegate type(parameters) { body }
4989 * (parameters) { body }
4992 Arguments
*arguments
;
4994 FuncLiteralDeclaration
*fd
;
4996 bool isnothrow
= false;
4997 bool ispure
= false;
4999 if (token
.value
== startBlockTok
)
5003 arguments
= new Arguments();
5007 if (token
.value
== TOKlparen
)
5011 t
= parseBasicType();
5012 t
= parseBasicType2(t
); // function return type
5014 arguments
= parseParameters(&varargs
);
5017 if (token
.value
== TOKpure
)
5019 else if (token
.value
== TOKnothrow
)
5026 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
5027 tf
->ispure
= ispure
;
5028 tf
->isnothrow
= isnothrow
;
5029 fd
= new FuncLiteralDeclaration(loc
, 0, tf
, save
, NULL
);
5034 indent
--; // This colon doesn't start a new indent level
5035 fd
->fbody
= new ReturnStatement(loc
, parseAssignExp());
5042 e
= new FuncExp(loc
, fd
);
5047 error("expression expected, not '%s'", token
.toChars());
5049 // Anything for e, as long as it's not NULL
5050 e
= new IntegerExp(loc
, 0, Type::tint32
);
5054 return parsePostExp(e
);
5057 Expression
*Parser::parsePostExp(Expression
*e
)
5064 switch (token
.value
)
5068 if (token
.value
== TOKidentifier
)
5069 { Identifier
*id
= token
.ident
;
5072 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
5073 { // identifier!(template-argument-list)
5074 TemplateInstance
*tempinst
;
5076 tempinst
= new TemplateInstance(loc
, id
);
5078 tempinst
->tiargs
= parseTemplateArgumentList();
5079 e
= new DotTemplateInstanceExp(loc
, e
, tempinst
);
5082 e
= new DotIdExp(loc
, e
, id
);
5085 else if (token
.value
== TOKnew
)
5091 error("identifier expected following '.', not '%s'", token
.toChars());
5095 e
= new PostExp(TOKplusplus
, loc
, e
);
5099 e
= new PostExp(TOKminusminus
, loc
, e
);
5103 e
= new CallExp(loc
, e
, parseArguments());
5107 { // array dereferences:
5110 // array[lwr .. upr]
5116 if (token
.value
== TOKrbracket
)
5118 e
= new SliceExp(loc
, e
, NULL
, NULL
);
5123 index
= parseAssignExp();
5124 if (token
.value
== TOKslice
)
5125 { // array[lwr .. upr]
5127 upr
= parseAssignExp();
5128 e
= new SliceExp(loc
, e
, index
, upr
);
5131 { // array[index, i2, i3, i4, ...]
5132 Expressions
*arguments
= new Expressions();
5133 arguments
->push(index
);
5134 if (token
.value
== TOKcomma
)
5140 arg
= parseAssignExp();
5141 arguments
->push(arg
);
5142 if (token
.value
== TOKrbracket
)
5147 e
= new ArrayExp(loc
, e
, arguments
);
5162 Expression
*Parser::parseUnaryExp()
5164 Loc loc
= this->loc
;
5166 switch (token
.value
)
5170 e
= parseUnaryExp();
5171 e
= new AddrExp(loc
, e
);
5176 e
= parseUnaryExp();
5177 e
= new AddAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
5182 e
= parseUnaryExp();
5183 e
= new MinAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
5188 e
= parseUnaryExp();
5189 e
= new PtrExp(loc
, e
);
5194 e
= parseUnaryExp();
5195 e
= new NegExp(loc
, e
);
5200 e
= parseUnaryExp();
5201 e
= new UAddExp(loc
, e
);
5206 e
= parseUnaryExp();
5207 e
= new NotExp(loc
, e
);
5212 e
= parseUnaryExp();
5213 e
= new ComExp(loc
, e
);
5218 e
= parseUnaryExp();
5219 e
= new DeleteExp(loc
, e
);
5223 e
= parseNewExp(NULL
);
5226 case TOKcast
: // cast(type) expression
5231 /* Look for cast(const) and cast(invariant)
5233 if ((token
.value
== TOKconst
|| token
.value
== TOKinvariant
) &&
5234 peek(&token
)->value
== TOKrparen
)
5235 { enum TOK tok
= token
.value
;
5238 e
= parseUnaryExp();
5239 e
= new CastExp(loc
, e
, tok
);
5243 t
= parseType(); // ( type )
5245 e
= parseUnaryExp();
5246 e
= new CastExp(loc
, e
, t
);
5257 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
5259 tk
= peek(tk
); // skip over right parenthesis
5279 case TOKimaginary32v
:
5280 case TOKimaginary64v
:
5281 case TOKimaginary80v
:
5301 CASE_BASIC_TYPES
: // (type)int.size
5310 if (token
.value
== TOKdot
)
5313 if (token
.value
!= TOKidentifier
)
5314 { error("Identifier expected following (type).");
5317 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
5319 e
= parsePostExp(e
);
5323 e
= parseUnaryExp();
5324 e
= new CastExp(loc
, e
, t
);
5325 error("C style cast illegal, use %s", e
->toChars());
5332 e
= parsePrimaryExp();
5336 e
= parsePrimaryExp();
5343 Expression
*Parser::parseMulExp()
5346 Loc loc
= this->loc
;
5348 e
= parseUnaryExp();
5351 switch (token
.value
)
5353 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
5354 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
5355 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
5365 Expression
*Parser::parseAddExp()
5368 Loc loc
= this->loc
;
5373 switch (token
.value
)
5375 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
5376 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
5377 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
5387 Expression
*Parser::parseShiftExp()
5390 Loc loc
= this->loc
;
5395 switch (token
.value
)
5397 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
5398 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
5399 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
5409 Expression
*Parser::parseRelExp()
5413 Loc loc
= this->loc
;
5415 e
= parseShiftExp();
5418 switch (token
.value
)
5434 e2
= parseShiftExp();
5435 e
= new CmpExp(op
, loc
, e
, e2
);
5440 e2
= parseShiftExp();
5441 e
= new InExp(loc
, e
, e2
);
5452 Expression
*Parser::parseEqualExp()
5456 Loc loc
= this->loc
;
5460 { enum TOK value
= token
.value
;
5468 e
= new EqualExp(value
, loc
, e
, e2
);
5472 error("'===' is no longer legal, use 'is' instead");
5475 case TOKnotidentity
:
5476 error("'!==' is no longer legal, use '!is' instead");
5480 value
= TOKidentity
;
5485 error("next: %s", t
->toChars());
5486 if (t
->value
== TOKnot
)
5489 value
= TOKnotidentity
;
5496 // Attempt to identify '!is'
5498 if (t
->value
!= TOKis
)
5501 value
= TOKnotidentity
;
5507 e
= new IdentityExp(value
, loc
, e
, e2
);
5518 Expression
*Parser::parseCmpExp()
5522 Loc loc
= this->loc
;
5524 e
= parseShiftExp();
5525 enum TOK op
= token
.value
;
5532 e2
= parseShiftExp();
5533 e
= new EqualExp(op
, loc
, e
, e2
);
5541 if (t
->value
== TOKnot
)
5544 op
= TOKnotidentity
;
5551 // Attempt to identify '!is'
5553 if (t
->value
!= TOKis
)
5556 op
= TOKnotidentity
;
5561 e2
= parseShiftExp();
5562 e
= new IdentityExp(op
, loc
, e
, e2
);
5578 e2
= parseShiftExp();
5579 e
= new CmpExp(op
, loc
, e
, e2
);
5584 e2
= parseShiftExp();
5585 e
= new InExp(loc
, e
, e2
);
5594 Expression
*Parser::parseAndExp()
5597 Loc loc
= this->loc
;
5599 if (global
.params
.Dversion
== 1)
5601 e
= parseEqualExp();
5602 while (token
.value
== TOKand
)
5605 e2
= parseEqualExp();
5606 e
= new AndExp(loc
,e
,e2
);
5613 while (token
.value
== TOKand
)
5617 e
= new AndExp(loc
,e
,e2
);
5624 Expression
*Parser::parseXorExp()
5627 Loc loc
= this->loc
;
5630 while (token
.value
== TOKxor
)
5634 e
= new XorExp(loc
, e
, e2
);
5639 Expression
*Parser::parseOrExp()
5642 Loc loc
= this->loc
;
5645 while (token
.value
== TOKor
)
5649 e
= new OrExp(loc
, e
, e2
);
5654 Expression
*Parser::parseAndAndExp()
5657 Loc loc
= this->loc
;
5660 while (token
.value
== TOKandand
)
5664 e
= new AndAndExp(loc
, e
, e2
);
5669 Expression
*Parser::parseOrOrExp()
5672 Loc loc
= this->loc
;
5674 e
= parseAndAndExp();
5675 while (token
.value
== TOKoror
)
5678 e2
= parseAndAndExp();
5679 e
= new OrOrExp(loc
, e
, e2
);
5684 Expression
*Parser::parseCondExp()
5688 Loc loc
= this->loc
;
5691 if (token
.value
== TOKquestion
)
5694 e1
= parseExpression();
5696 e2
= parseCondExp();
5697 e
= new CondExp(loc
, e
, e1
, e2
);
5702 Expression
*DltParser::parseCondExp()
5706 Loc loc
= this->loc
;
5709 if (token
.value
== TOKif
)
5712 e1
= parseExpression();
5714 e2
= parseCondExp();
5715 e
= new CondExp(loc
, e1
, e
, e2
);
5720 Expression
*Parser::parseAssignExp()
5729 switch (token
.value
)
5731 #define X(tok,ector) \
5732 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5734 X(TOKassign
, AssignExp
);
5735 X(TOKaddass
, AddAssignExp
);
5736 X(TOKminass
, MinAssignExp
);
5737 X(TOKmulass
, MulAssignExp
);
5738 X(TOKdivass
, DivAssignExp
);
5739 X(TOKmodass
, ModAssignExp
);
5740 X(TOKandass
, AndAssignExp
);
5741 X(TOKorass
, OrAssignExp
);
5742 X(TOKxorass
, XorAssignExp
);
5743 X(TOKshlass
, ShlAssignExp
);
5744 X(TOKshrass
, ShrAssignExp
);
5745 X(TOKushrass
, UshrAssignExp
);
5746 X(TOKcatass
, CatAssignExp
);
5757 Expression
*Parser::parseExpression()
5760 Loc loc
= this->loc
;
5762 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5763 e
= parseAssignExp();
5764 while (token
.value
== TOKcomma
)
5767 e2
= parseAssignExp();
5768 e
= new CommaExp(loc
, e
, e2
);
5775 /*************************
5776 * Collect argument list.
5777 * Assume current token is '(' or '['.
5780 Expressions
*Parser::parseArguments()
5782 Expressions
*arguments
;
5786 arguments
= new Expressions();
5787 if (token
.value
== TOKlbracket
)
5788 endtok
= TOKrbracket
;
5794 if (token
.value
!= endtok
)
5798 arg
= parseAssignExp();
5799 arguments
->push(arg
);
5800 if (token
.value
== endtok
)
5810 /*******************************************
5813 Expression
*Parser::parseNewExp(Expression
*thisexp
)
5815 Expressions
*newargs
;
5816 Expressions
*arguments
= NULL
;
5818 Loc loc
= this->loc
;
5822 if (token
.value
== TOKlparen
)
5824 newargs
= parseArguments();
5827 // An anonymous nested class starts with "class"
5828 if (token
.value
== TOKclass
)
5833 error("no anonymous classes in Delight");
5835 if (token
.value
== TOKlparen
)
5836 arguments
= parseArguments();
5838 BaseClasses
*baseclasses
= NULL
;
5839 if (token
.value
!= TOKlcurly
)
5840 baseclasses
= parseBaseClasses();
5842 Identifier
*id
= NULL
;
5843 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
, linkage
);
5845 if (token
.value
!= startBlockTok
)
5846 { error("{ members } expected for anonymous class");
5852 Array
*decl
= parseDeclDefs(0);
5853 if (token
.value
!= TOKrcurly
)
5854 error("class member expected");
5859 e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
5864 t
= parseBasicType();
5865 t
= parseBasicType2(t
);
5866 if (t
->ty
== Taarray
)
5867 { TypeAArray
*taa
= (TypeAArray
*)t
;
5868 Type
*index
= taa
->index
;
5870 Expression
*e
= index
->toExpression();
5872 { arguments
= new Expressions();
5874 t
= new TypeDArray(taa
->next
);
5878 error("need size of rightmost array, not type %s", index
->toChars());
5879 return new NullExp(loc
);
5882 else if (t
->ty
== Tsarray
)
5884 TypeSArray
*tsa
= (TypeSArray
*)t
;
5885 Expression
*e
= tsa
->dim
;
5887 arguments
= new Expressions();
5889 t
= new TypeDArray(tsa
->next
);
5891 else if (token
.value
== TOKlparen
)
5893 arguments
= parseArguments();
5895 e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
5899 /**********************************************
5902 void Parser::addComment(Dsymbol
*s
, unsigned char *blockComment
)
5904 s
->addComment(combineComments(blockComment
, token
.lineComment
));
5908 /********************************* ***************************/