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("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
== TOKlcurly
|| t
->value
== TOKcolon
)
188 else if (t
->value
!= TOKidentifier
)
193 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
194 t
->value
== TOKsemicolon
)
206 s
= parseAggregate();
210 s
= parseImport(decldefs
, 0);
214 s
= (Dsymbol
*)parseTemplateDeclaration();
218 { Loc loc
= this->loc
;
219 if (peek(&token
)->value
== TOKlparen
)
222 check(TOKlparen
, "mixin");
223 Expression
*e
= parseAssignExp();
226 s
= new CompileDeclaration(loc
, e
);
240 a
= parseDeclarations();
259 if (t
->value
== TOKlparen
)
261 if (peek(t
)->value
== TOKrparen
)
262 // invariant() forms start of class invariant
263 s
= parseInvariant();
294 if (token
.value
== TOKthis
)
296 s
= parseStaticCtor();
298 error("no static constructors in Delight");
300 else if (token
.value
== TOKtilde
)
302 s
= parseStaticDtor();
304 error("no static destructors in Delight");
306 else if (token
.value
== TOKassert
)
307 s
= parseStaticAssert();
308 else if (token
.value
== TOKif
)
309 { condition
= parseStaticIfCondition();
312 if (token
.value
== TOKelse
)
314 aelse
= parseBlock();
316 s
= new StaticIfDeclaration(condition
, a
, aelse
);
319 else if (token
.value
== TOKimport
)
321 s
= parseImport(decldefs
, 1);
335 if (peek(&token
)->value
== TOKlparen
)
340 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
341 case TOKauto
: stc
= STCauto
; goto Lstc
;
342 case TOKscope
: stc
= STCscope
; goto Lstc
;
343 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
344 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
345 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
346 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
347 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
348 case TOKpure
: stc
= STCpure
; goto Lstc
;
349 case TOKtls
: stc
= STCtls
; goto Lstc
;
350 //case TOKmanifest: stc = STCmanifest; goto Lstc;
353 if (storageClass
& stc
)
354 error("redundant storage class %s", Token::toChars(token
.value
));
356 unsigned u
= storageClass
| stc
;
357 u
&= STCconst
| STCinvariant
| STCmanifest
;
359 error("conflicting storage class %s", Token::toChars(token
.value
));
368 // If followed by a (, it is not a storage class
369 if (peek(&token
)->value
== TOKlparen
)
371 if (token
.value
== TOKconst
)
376 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
377 case TOKauto
: stc
= STCauto
; goto Lstc
;
378 case TOKscope
: stc
= STCscope
; goto Lstc
;
379 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
380 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
381 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
382 case TOKdeprecated
: stc
= STCdeprecated
; goto Lstc
;
383 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
384 case TOKpure
: stc
= STCpure
; goto Lstc
;
385 case TOKtls
: stc
= STCtls
; goto Lstc
;
386 //case TOKmanifest: stc = STCmanifest; goto Lstc;
391 /* Look for auto initializers:
392 * storage_class identifier = initializer;
394 if (token
.value
== TOKidentifier
&&
395 peek(&token
)->value
== TOKassign
)
399 Identifier
*ident
= token
.ident
;
402 Initializer
*init
= parseInitializer();
403 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
404 v
->storage_class
= storageClass
;
405 v
->dltNormalMode
= dltNormalMode
;
407 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
411 else if (token
.value
== TOKcomma
)
414 if (token
.value
== TOKidentifier
&&
415 peek(&token
)->value
== TOKassign
)
418 addComment(s
, comment
);
422 error("Identifier expected following comma");
425 error("%s expected following declaration, not '%s'", endToken(), token
.toChars());
431 s
= new StorageClassDeclaration(storageClass
, a
);
436 if (peek(&token
)->value
!= TOKlparen
)
441 enum LINK linksave
= linkage
;
442 linkage
= parseLinkage();
444 s
= new LinkDeclaration(linkage
, a
);
448 error("access to external symbols can be done only by dlt.* modules");
451 case TOKprivate
: prot
= PROTprivate
; goto Lprot
;
452 case TOKpackage
: prot
= PROTpackage
; goto Lprot
;
453 case TOKprotected
: prot
= PROTprotected
; goto Lprot
;
454 case TOKpublic
: prot
= PROTpublic
; goto Lprot
;
455 case TOKexport
: prot
= PROTexport
; goto Lprot
;
466 error("redundant protection attribute");
470 s
= new ProtDeclaration(prot
, a
);
478 if (token
.value
== TOKlparen
)
481 if (token
.value
== TOKint32v
)
482 n
= (unsigned)token
.uns64value
;
484 { error("integer expected, not %s", token
.toChars());
491 n
= global
.structalign
; // default
494 s
= new AlignDeclaration(n
, a
);
500 Expressions
*args
= NULL
;
504 if (token
.value
!= TOKidentifier
)
505 { error("pragma(identifier expected");
510 if (token
.value
== TOKcomma
)
511 args
= parseArguments(); // pragma(identifier, args...)
513 check(TOKrparen
); // pragma(identifier)
515 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
520 a
= parseDeclDefs(0);
525 s
= new PragmaDeclaration(loc
, ident
, args
, a
);
531 if (token
.value
== TOKassign
)
534 if (token
.value
== TOKidentifier
)
535 s
= new DebugSymbol(loc
, token
.ident
);
536 else if (token
.value
== TOKint32v
)
537 s
= new DebugSymbol(loc
, (unsigned)token
.uns64value
);
539 { error("identifier or integer expected, not %s", token
.toChars());
543 if (token
.value
!= TOKsemicolon
)
544 error("semicolon expected");
549 condition
= parseDebugCondition();
554 if (token
.value
== TOKassign
)
557 if (token
.value
== TOKidentifier
)
558 s
= new VersionSymbol(loc
, token
.ident
);
559 else if (token
.value
== TOKint32v
)
560 s
= new VersionSymbol(loc
, (unsigned)token
.uns64value
);
562 { error("identifier or integer expected, not %s", token
.toChars());
566 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
)
567 error("%s expected after version assignment", endToken());
571 condition
= parseVersionCondition();
577 if (token
.value
== TOKelse
)
579 aelse
= parseBlock();
581 s
= new ConditionalDeclaration(condition
, a
, aelse
);
584 case TOKsemicolon
: // empty declaration
589 error("Declaration expected, not '%s'",token
.toChars());
591 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
&& token
.value
!= TOKeof
)
599 addComment(s
, comment
);
606 /********************************************
607 * Parse declarations after an align, protection, or extern decl.
610 Array
*Parser::parseBlock()
615 //printf("Parser::parseBlock()\n");
619 error("declaration expected following attribute, not ';'");
625 a
= parseDeclDefs(0);
626 if (token
.value
!= TOKrcurly
)
628 error("matching '}' expected, not %s", token
.toChars());
639 a
= parseDeclDefs(0); // grab declarations up to closing curly bracket
644 a
= parseDeclDefs(1);
650 Array
*DltParser::parseBlock()
660 error("declaration expected following attribute, not %s", token
.toChars());
666 a
= parseDeclDefs(0);
667 if (token
.value
!= TOKrcurly
)
669 error("matching end-of-block expected, not %s", token
.toChars());
676 a
= parseDeclDefs(1);
682 /**********************************
683 * Parse a static assertion.
686 StaticAssert
*Parser::parseStaticAssert()
690 Expression
*msg
= NULL
;
692 //printf("parseStaticAssert()\n");
695 exp
= parseAssignExp();
696 if (token
.value
== TOKcomma
)
698 msg
= parseAssignExp();
701 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
) {
703 return new StaticAssert(loc
, exp
, msg
);
705 error("expected %s after static assert", endToken());
708 /***********************************
709 * Parse typeof(expression).
710 * Current token is on the 'typeof'.
713 TypeQualified
*Parser::parseTypeof()
719 if (token
.value
== TOKreturn
) // typeof(return)
722 t
= new TypeReturn(loc
);
725 { Expression
*exp
= parseExpression(); // typeof(expression)
726 t
= new TypeTypeof(loc
, exp
);
732 /***********************************
733 * Parse extern (linkage)
734 * The parser is on the 'extern' token.
737 enum LINK
Parser::parseLinkage()
739 enum LINK link
= LINKdefault
;
741 assert(token
.value
== TOKlparen
);
743 if (token
.value
== TOKidentifier
)
744 { Identifier
*id
= token
.ident
;
747 if (id
== Id::Windows
)
749 else if (id
== Id::Pascal
)
751 else if (id
== Id::D
)
753 else if (id
== Id::C
)
756 if (token
.value
== TOKplusplus
)
761 else if (id
== Id::System
)
764 link
= d_gcc_is_target_win32() ? LINKwindows
: LINKc
;
775 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
781 link
= LINKd
; // default
787 /**************************************
788 * Parse a debug conditional
791 Condition
*Parser::parseDebugCondition()
795 if (token
.value
== TOKlparen
)
799 Identifier
*id
= NULL
;
801 if (token
.value
== TOKidentifier
)
803 else if (token
.value
== TOKint32v
)
804 level
= (unsigned)token
.uns64value
;
806 error("identifier or integer expected, not %s", token
.toChars());
809 c
= new DebugCondition(mod
, level
, id
);
810 if (dltSyntax
&& token
.value
!= TOKcolon
)
811 error("expected colon after debug(), not '%s'", token
.toChars());
813 if (dltSyntax
&& token
.value
!= TOKcolon
)
814 error("expected ':' or '(' after 'debug', not '%s'", token
.toChars());
815 c
= new DebugCondition(mod
, 1, NULL
);
821 /**************************************
822 * Parse a version conditional
825 Condition
*Parser::parseVersionCondition()
829 Identifier
*id
= NULL
;
831 if (token
.value
== TOKlparen
)
834 if (token
.value
== TOKidentifier
)
836 else if (token
.value
== TOKint32v
)
837 level
= (unsigned)token
.uns64value
;
841 * even though unittest is a keyword
843 else if (token
.value
== TOKunittest
)
844 id
= Lexer::idPool(Token::toChars(TOKunittest
));
847 error("identifier or integer expected, not %s", token
.toChars());
853 error("(condition) expected following version");
854 c
= new VersionCondition(mod
, level
, id
);
859 /***********************************************
860 * static if (expression)
866 Condition
*Parser::parseStaticIfCondition()
868 Condition
*condition
;
875 exp
= parseAssignExp();
878 condition
= new StaticIfCondition(loc
, exp
);
883 /*****************************************
884 * Parse a constructor definition:
885 * this(arguments) { body }
887 * this(this) { body }
888 * Current token is 'this'.
891 FuncDeclaration
*Parser::parseCtor()
896 if (token
.value
== TOKlparen
&& peek(&token
)->value
== TOKthis
)
897 { // this(this) { ... }
901 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, 0);
906 Arguments
*arguments
= parseParameters(&varargs
);
907 CtorDeclaration
*f
= new CtorDeclaration(loc
, 0, arguments
, varargs
);
912 /*****************************************
913 * Parse a postblit definition:
915 * Current token is '='.
918 PostBlitDeclaration
*Parser::parsePostBlit()
927 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, 0);
932 /*****************************************
933 * Parse a destructor definition:
935 * Current token is '~'.
938 DtorDeclaration
*Parser::parseDtor()
948 f
= new DtorDeclaration(loc
, 0);
953 /*****************************************
954 * Parse a static constructor definition:
955 * static this() { body }
956 * Current token is 'this'.
959 StaticCtorDeclaration
*Parser::parseStaticCtor()
961 StaticCtorDeclaration
*f
;
968 f
= new StaticCtorDeclaration(loc
, 0);
973 /*****************************************
974 * Parse a static destructor definition:
975 * static ~this() { body }
976 * Current token is '~'.
979 StaticDtorDeclaration
*Parser::parseStaticDtor()
981 StaticDtorDeclaration
*f
;
989 f
= new StaticDtorDeclaration(loc
, 0);
994 /*****************************************
995 * Parse an invariant definition:
997 * Current token is 'invariant'.
1000 InvariantDeclaration
*Parser::parseInvariant()
1002 InvariantDeclaration
*f
;
1003 Loc loc
= this->loc
;
1008 if (token
.value
== TOKlparen
)
1013 f
= new InvariantDeclaration(loc
, 0);
1014 f
->fbody
= parseStatement(PScurly
);
1018 /*****************************************
1019 * Parse a unittest definition:
1021 * Current token is 'unittest'.
1024 UnitTestDeclaration
*Parser::parseUnitTest()
1026 UnitTestDeclaration
*f
;
1028 Loc loc
= this->loc
;
1032 body
= parseStatement(PScurly
);
1034 f
= new UnitTestDeclaration(loc
, this->loc
);
1039 /*****************************************
1040 * Parse a new definition:
1041 * new(arguments) { body }
1042 * Current token is 'new'.
1045 NewDeclaration
*Parser::parseNew()
1048 Arguments
*arguments
;
1050 Loc loc
= this->loc
;
1053 arguments
= parseParameters(&varargs
);
1054 f
= new NewDeclaration(loc
, 0, arguments
, varargs
);
1059 /*****************************************
1060 * Parse a delete definition:
1061 * delete(arguments) { body }
1062 * Current token is 'delete'.
1065 DeleteDeclaration
*Parser::parseDelete()
1067 DeleteDeclaration
*f
;
1068 Arguments
*arguments
;
1070 Loc loc
= this->loc
;
1073 arguments
= parseParameters(&varargs
);
1075 error("... not allowed in delete function parameter list");
1076 f
= new DeleteDeclaration(loc
, 0, arguments
);
1081 /**********************************************
1082 * Parse parameter list.
1085 Arguments
*Parser::parseParameters(int *pvarargs
)
1087 Arguments
*arguments
= new Arguments();
1097 unsigned storageClass
;
1102 storageClass
= 0; // parameter is "in" by default
1103 for (;1; nextToken())
1105 switch (token
.value
)
1116 if (peek(&token
)->value
== TOKlparen
)
1122 if (peek(&token
)->value
== TOKlparen
)
1127 case TOKin
: stc
= STCin
; goto L2
;
1128 case TOKout
: stc
= STCout
; goto L2
;
1130 case TOKref
: stc
= STCref
; goto L2
;
1131 case TOKlazy
: stc
= STClazy
; goto L2
;
1132 case TOKscope
: stc
= STCscope
; goto L2
;
1133 case TOKfinal
: stc
= STCfinal
; goto L2
;
1134 case TOKstatic
: stc
= STCstatic
; goto L2
;
1136 if (storageClass
& stc
||
1137 (storageClass
& STCin
&& stc
& (STCconst
| STCscope
)) ||
1138 (stc
& STCin
&& storageClass
& (STCconst
| STCscope
))
1140 error("redundant storage class %s", Token::toChars(token
.value
));
1141 storageClass
|= stc
;
1143 unsigned u
= storageClass
& (STCconst
| STCinvariant
);
1145 error("conflicting storage class %s", Token::toChars(token
.value
));
1151 stc
= storageClass
& (STCin
| STCout
| STCref
| STClazy
);
1152 if (stc
& (stc
- 1)) // if stc is not a power of 2
1153 error("incompatible parameter storage classes");
1154 if ((storageClass
& (STCconst
| STCout
)) == (STCconst
| STCout
))
1155 error("out cannot be const");
1156 if ((storageClass
& (STCinvariant
| STCout
)) == (STCinvariant
| STCout
))
1157 error("out cannot be invariant");
1158 if ((storageClass
& STCscope
) &&
1159 (storageClass
& (STCref
| STCout
)))
1160 error("scope cannot be ref or out");
1161 at
= parseType(&ai
);
1163 if (token
.value
== TOKassign
) // = defaultArg
1165 ae
= parseDefaultInitExp();
1170 error("default argument expected for %s",
1171 ai
? ai
->toChars() : at
->toChars());
1173 if (token
.value
== TOKdotdotdot
)
1178 if (storageClass
& (STCout
| STCref
))
1179 error("variadic argument cannot be out or ref");
1181 a
= new Argument(storageClass
, at
, ai
, ae
);
1186 a
= new Argument(storageClass
, at
, ai
, ae
);
1188 if (token
.value
== TOKcomma
)
1201 *pvarargs
= varargs
;
1206 /*************************************
1209 EnumDeclaration
*Parser::parseEnum()
1210 { EnumDeclaration
*e
;
1213 Loc loc
= this->loc
;
1215 //printf("Parser::parseEnum()\n");
1217 if (token
.value
== TOKidentifier
)
1224 if (token
.value
== (dltSyntax
? TOKextends
: TOKcolon
))
1227 memtype
= parseBasicType();
1228 memtype
= parseDeclarator(memtype
, NULL
, NULL
);
1233 e
= new EnumDeclaration(loc
, id
, memtype
);
1234 if ((token
.value
== TOKsemicolon
|| token
.value
== TOKendline
) && id
)
1236 else if (token
.value
== startBlockTok
)
1238 //printf("enum definition\n");
1239 e
->members
= new Array();
1241 unsigned char *comment
= token
.blockComment
;
1243 while (token
.value
!= TOKrcurly
)
1245 /* Can take the following forms:
1248 * 3. type ident = value
1255 Token
*tp
= peek(&token
);
1256 if (token
.value
== TOKidentifier
&&
1257 (tp
->value
== TOKassign
|| tp
->value
== TOKcomma
||
1258 tp
->value
== TOKendline
|| tp
->value
== TOKrcurly
))
1260 ident
= token
.ident
;
1266 type
= parseType(&ident
, NULL
);
1268 error("type only allowed if anonymous enum and no enum type");
1272 if (token
.value
== TOKassign
)
1275 value
= parseAssignExp();
1280 error("if type, there must be an initializer");
1283 EnumMember
*em
= new EnumMember(loc
, ident
, value
, type
);
1284 e
->members
->push(em
);
1288 if (token
.value
== TOKcomma
)
1290 else if (token
.value
!= TOKendline
)
1291 error("expected comma or newline after %s, not %s",
1292 em
->toChars(), token
.toChars());
1296 if (token
.value
== TOKrcurly
)
1299 { addComment(em
, comment
);
1304 addComment(em
, comment
);
1305 comment
= token
.blockComment
;
1310 error("enum declaration is invalid");
1311 //printf("-parseEnum() %s\n", e->toChars());
1315 Dsymbol
*Parser::parseAggregate()
1316 { AggregateDeclaration
*a
= NULL
;
1320 TemplateParameters
*tpl
= NULL
;
1322 //printf("Parser::parseAggregate()\n");
1325 if (token
.value
!= TOKidentifier
)
1332 if (token
.value
== TOKlparen
)
1333 { // Class template declaration.
1335 // Gather template parameter list
1336 tpl
= parseTemplateParameterList();
1340 Loc loc
= this->loc
;
1346 error("anonymous classes not allowed");
1348 // Collect base class(es)
1349 BaseClasses
*baseclasses
= parseBaseClasses();
1350 if (baseclasses
&& token
.value
!= startBlockTok
) {
1351 error("members expected");
1354 if (tok
== TOKclass
)
1355 a
= new ClassDeclaration(loc
, id
, baseclasses
);
1357 a
= new InterfaceDeclaration(loc
, id
, baseclasses
);
1363 a
= new StructDeclaration(loc
, id
);
1370 a
= new UnionDeclaration(loc
, id
);
1379 if (a
&& token
.value
== (dltSyntax
? TOKendline
: TOKsemicolon
))
1382 else if (token
.value
== startBlockTok
)
1384 //printf("aggregate definition\n");
1387 Array
*decl
= parseDeclDefs(0);
1388 if (token
.value
!= TOKrcurly
)
1389 error("end-of-block expected following member declarations in aggregate");
1393 /* Anonymous structs/unions are more like attributes.
1395 return new AnonDeclaration(loc
, anon
- 1, decl
);
1402 error("%s expected following aggregate declaration", Token::toChars(startBlockTok
));
1403 a
= new StructDeclaration(loc
, NULL
);
1408 TemplateDeclaration
*tempdecl
;
1410 // Wrap a template around the aggregate declaration
1411 decldefs
= new Array();
1413 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
, dltSyntax
);
1420 /*******************************************
1423 /* If current token is TOKcolon, TOKextends or TOKimplements, return
1424 * the bases. Otherwise, return null.
1426 BaseClasses
*Parser::parseBaseClasses()
1428 enum PROT protection
= PROTpublic
;
1429 int type
; // 1 = extends, 2 = implements, 3 = unknown
1432 if (token
.value
== TOKextends
)
1434 else if (token
.value
== TOKimplements
)
1439 if (token
.value
== TOKcolon
)
1447 BaseClasses
*baseclasses
= new BaseClasses();
1449 for (; 1; nextToken())
1451 enum PROT protection
= PROTpublic
;
1452 switch (token
.value
)
1455 protection
= PROTprivate
;
1459 protection
= PROTpackage
;
1463 protection
= PROTprotected
;
1467 protection
= PROTpublic
;
1471 if (token
.value
== TOKidentifier
)
1473 BaseClass
*b
= new BaseClass(parseBasicType(), protection
);
1474 baseclasses
->push(b
);
1476 switch (token
.value
) {
1481 error("extends part must come before implements");
1483 error("only one extends is permitted");
1489 error("separate implemented interfaces with commas");
1496 error("base classes expected instead of %s", token
.toChars());
1503 /**************************************
1504 * Parse a TemplateDeclaration.
1507 TemplateDeclaration
*Parser::parseTemplateDeclaration()
1509 TemplateDeclaration
*tempdecl
;
1511 TemplateParameters
*tpl
;
1513 Loc loc
= this->loc
;
1516 if (token
.value
!= TOKidentifier
)
1517 { error("TemplateIdentifier expected following template");
1522 tpl
= parseTemplateParameterList();
1526 if (token
.value
!= startBlockTok
)
1527 { error("members of template declaration expected");
1533 decldefs
= parseDeclDefs(0);
1534 if (token
.value
!= TOKrcurly
)
1535 { error("template member expected");
1541 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, decldefs
, dltSyntax
);
1548 /******************************************
1549 * Parse template parameter list.
1551 * flag 0: parsing "( list )"
1552 * 1: parsing non-empty "list )"
1555 TemplateParameters
*Parser::parseTemplateParameterList(int flag
)
1557 TemplateParameters
*tpl
= new TemplateParameters();
1559 if (!flag
&& token
.value
!= TOKlparen
)
1560 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1565 // Get array of TemplateParameters
1566 if (flag
|| token
.value
!= TOKrparen
)
1567 { int isvariadic
= 0;
1570 { TemplateParameter
*tp
;
1571 Identifier
*tp_ident
= NULL
;
1572 Type
*tp_spectype
= NULL
;
1573 Type
*tp_valtype
= NULL
;
1574 Type
*tp_defaulttype
= NULL
;
1575 Expression
*tp_specvalue
= NULL
;
1576 Expression
*tp_defaultvalue
= NULL
;
1579 // Get TemplateParameter
1581 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1583 if (token
.value
== TOKalias
)
1586 if (token
.value
!= TOKidentifier
)
1587 { error("Identifier expected for template parameter");
1590 tp_ident
= token
.ident
;
1592 if (token
.value
== TOKcolon
) // : Type
1595 tp_spectype
= parseType();
1597 if (token
.value
== TOKassign
) // = Type
1600 tp_defaulttype
= parseType();
1602 tp
= new TemplateAliasParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1604 else if (t
->value
== TOKcolon
|| t
->value
== TOKassign
||
1605 t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
1607 if (token
.value
!= TOKidentifier
)
1608 { error("Identifier expected for template parameter");
1611 tp_ident
= token
.ident
;
1613 if (token
.value
== TOKcolon
) // : Type
1616 tp_spectype
= parseType();
1618 if (token
.value
== TOKassign
) // = Type
1621 tp_defaulttype
= parseType();
1623 tp
= new TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1625 else if (token
.value
== TOKidentifier
&& t
->value
== TOKdotdotdot
)
1628 error("variadic template parameter must be last");
1630 tp_ident
= token
.ident
;
1633 tp
= new TemplateTupleParameter(loc
, tp_ident
);
1635 else if (token
.value
== TOKthis
)
1638 if (token
.value
!= TOKidentifier
)
1639 { error("Identifier expected for template parameter");
1642 tp_ident
= token
.ident
;
1644 if (token
.value
== TOKcolon
) // : Type
1647 tp_spectype
= parseType();
1649 if (token
.value
== TOKassign
) // = Type
1652 tp_defaulttype
= parseType();
1654 tp
= new TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1658 tp_valtype
= parseType(&tp_ident
);
1661 error("no identifier for template value parameter");
1662 tp_ident
= new Identifier("error", TOKidentifier
);
1664 if (token
.value
== TOKcolon
) // : CondExpression
1667 tp_specvalue
= parseCondExp();
1669 if (token
.value
== TOKassign
) // = CondExpression
1672 tp_defaultvalue
= parseDefaultInitExp();
1674 tp
= new TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1677 if (token
.value
!= TOKcomma
)
1687 /******************************************
1688 * Parse template mixin.
1691 * mixin a.b.c!(args).Foo!(args);
1692 * mixin Foo!(args) identifier;
1693 * mixin typeof(expr).identifier!(args);
1696 Dsymbol
*Parser::parseMixin()
1704 //printf("parseMixin()\n");
1707 if (token
.value
== TOKdot
)
1713 if (token
.value
== TOKtypeof
)
1715 tqual
= parseTypeof();
1718 if (token
.value
!= TOKidentifier
)
1720 error("identifier expected, not %s", token
.toChars());
1727 idents
= new Array();
1731 if (token
.value
== TOKnot
)
1734 tiargs
= parseTemplateArgumentList();
1737 if (token
.value
!= TOKdot
)
1741 { TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
1742 tempinst
->tiargs
= tiargs
;
1743 id
= (Identifier
*)tempinst
;
1749 if (token
.value
!= TOKidentifier
)
1750 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1758 if (token
.value
== TOKidentifier
)
1766 tm
= new TemplateMixin(loc
, id
, tqual
, idents
, tiargs
);
1769 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
)
1770 error("newline expected after mixin");
1772 if (token
.value
!= TOKsemicolon
)
1773 error("';' expected after mixin");
1783 /******************************************
1784 * Parse template argument list.
1786 * current token is opening '('
1788 * current token is one after closing ')'
1791 Objects
*Parser::parseTemplateArgumentList()
1793 //printf("Parser::parseTemplateArgumentList()\n");
1794 if (token
.value
!= TOKlparen
)
1795 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1796 return new Objects();
1798 return parseTemplateArgumentList2();
1801 Objects
*Parser::parseTemplateArgumentList2()
1803 Objects
*tiargs
= new Objects();
1806 // Get TemplateArgumentList
1807 if (token
.value
!= TOKrparen
)
1811 // See if it is an Expression or a Type
1812 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
1816 // Get TemplateArgument
1824 ea
= parseAssignExp();
1827 if (token
.value
!= TOKcomma
)
1832 check(TOKrparen
, "template argument list");
1836 Import
*Parser::parseImport(Array
*decldefs
, int isstatic
)
1839 Identifier
*aliasid
= NULL
;
1843 if (dltSyntax
&& isstatic
)
1844 error("Delight imports are static by default");
1846 //printf("Parser::parseImport()\n");
1851 if (token
.value
!= TOKidentifier
)
1852 { error("Identifier expected following import");
1860 if (!aliasid
&& token
.value
== TOKassign
)
1865 while (token
.value
== TOKdot
)
1871 if (token
.value
!= TOKidentifier
)
1872 { error("Identifier expected following package");
1879 s
= new Import(loc
, a
, token
.ident
, aliasid
, isstatic
);
1883 * : alias=name, alias=name;
1886 if (token
.value
== TOKcolon
)
1895 if (dltSyntax
&& token
.value
== TOKrcurly
)
1897 if (dltSyntax
&& token
.value
== TOKmul
)
1904 if (token
.value
!= TOKidentifier
)
1905 { error("Identifier expected following :");
1908 alias
= token
.ident
;
1910 if (token
.value
== TOKassign
)
1913 if (token
.value
!= TOKidentifier
)
1914 { error("Identifier expected following %s=", alias
->toChars());
1924 s
->addAlias(name
, alias
);
1925 if (token
.value
!= TOKcomma
&& token
.value
!= TOKendline
)
1936 } else if (dltSyntax
) {
1941 } while (token
.value
== TOKcomma
);
1943 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
1947 error("%s expected", endToken());
1954 Type
*Parser::parseType(Identifier
**pident
, TemplateParameters
**tpl
)
1957 if (token
.value
== TOKconst
&& peek(&token
)->value
!= TOKlparen
)
1962 t
= parseType(pident
, tpl
);
1966 else if (token
.value
== TOKinvariant
&& peek(&token
)->value
!= TOKlparen
)
1971 t
= parseType(pident
, tpl
);
1972 t
= t
->makeInvariant();
1976 t
= parseBasicType();
1977 t
= parseDeclarator(t
, pident
, tpl
);
1981 Type
*Parser::parseBasicType()
1985 TemplateInstance
*tempinst
;
1987 //printf("parseBasicType()\n");
1988 switch (token
.value
)
1990 CASE_BASIC_TYPES_X(t
):
1997 if (token
.value
== TOKnot
)
2000 tempinst
= new TemplateInstance(loc
, id
);
2001 tempinst
->tiargs
= parseTemplateArgumentList();
2002 tid
= new TypeInstance(loc
, tempinst
);
2006 tid
= new TypeIdentifier(loc
, id
);
2008 while (token
.value
== TOKdot
)
2010 if (token
.value
!= TOKidentifier
)
2011 { error("identifier expected following '.' instead of '%s'", token
.toChars());
2016 if (token
.value
== TOKnot
)
2019 tempinst
= new TemplateInstance(loc
, id
);
2020 tempinst
->tiargs
= parseTemplateArgumentList();
2021 tid
->addIdent((Identifier
*)tempinst
);
2035 tid
= parseTypeof();
2054 t
= t
->makeInvariant();
2058 error("basic type expected, not %s", token
.toChars());
2065 Type
*Parser::parseBasicType2(Type
*t
)
2070 //printf("parseBasicType2()\n");
2073 switch (token
.value
)
2076 t
= new TypePointer(t
);
2081 // Handle []. Make sure things like
2083 // is (array[1] of array[3] of int)
2085 if (token
.value
== TOKrbracket
)
2087 t
= new TypeDArray(t
); // []
2090 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2091 { // It's an associative array declaration
2094 //printf("it's an associative array\n");
2095 index
= parseType(); // [ type ]
2096 t
= new TypeAArray(t
, index
);
2101 //printf("it's [expression]\n");
2103 Expression
*e
= parseExpression(); // [ expression ]
2104 if (token
.value
== TOKslice
)
2108 e2
= parseExpression(); // [ exp .. exp ]
2109 t
= new TypeSlice(t
, e
, e2
);
2112 t
= new TypeSArray(t
,e
);
2120 { // Handle delegate declaration:
2121 // t delegate(parameter list)
2122 // t function(parameter list)
2123 Arguments
*arguments
;
2125 bool ispure
= false;
2126 bool isnothrow
= false;
2127 enum TOK save
= token
.value
;
2130 arguments
= parseParameters(&varargs
);
2133 if (token
.value
== TOKpure
)
2135 else if (token
.value
== TOKnothrow
)
2141 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2142 tf
->ispure
= ispure
;
2143 tf
->isnothrow
= isnothrow
;
2144 if (save
== TOKdelegate
)
2145 t
= new TypeDelegate(tf
);
2147 t
= new TypePointer(tf
); // pointer to function
2152 // Allow maybe annotations even for D code. Makes it easier to adapt
2153 // D interfaces for Delight
2157 t
= t
->maybe(false);
2159 error("Type %s cannot be null; ? is pointless", old
->toChars());
2163 // fall-through to default
2175 Type
*Parser::parseDeclarator(Type
*t
, Identifier
**pident
, TemplateParameters
**tpl
)
2178 //printf("parseDeclarator(tpl = %p)\n", tpl);
2179 t
= parseBasicType2(t
);
2181 switch (token
.value
)
2186 *pident
= token
.ident
;
2188 error("unexpected identifer '%s' in declarator", token
.ident
->toChars());
2194 /* Parse things with parentheses around the identifier, like:
2196 * although the D style would be:
2200 ts
= parseDeclarator(t
, pident
);
2211 switch (token
.value
)
2214 /* Support C style array syntax:
2216 * as opposed to D-style:
2220 { // This is the old C-style post [] syntax.
2224 error("use 'type[] var', not 'type var[]'");
2227 if (token
.value
== TOKrbracket
)
2228 { // It's a dynamic array
2229 ta
= new TypeDArray(t
); // []
2232 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2233 { // It's an associative array
2235 //printf("it's an associative array\n");
2236 Type
*index
= parseType(); // [ type ]
2238 ta
= new TypeAArray(t
, index
);
2242 //printf("It's a static array\n");
2243 Expression
*e
= parseExpression(); // [ expression ]
2244 ta
= new TypeSArray(t
, e
);
2251 * ts -> ... -> ta -> t
2254 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2264 /* Look ahead to see if this is (...)(...),
2265 * i.e. a function template declaration
2267 if (peekPastParen(&token
)->value
== TOKlparen
)
2269 //printf("function template declaration\n");
2271 // Gather template parameter list
2272 *tpl
= parseTemplateParameterList();
2277 Arguments
*arguments
= parseParameters(&varargs
);
2278 Type
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2280 /* Parse const/invariant/nothrow postfix
2284 switch (token
.value
)
2287 tf
= tf
->makeConst();
2292 tf
= tf
->makeInvariant();
2297 ((TypeFunction
*)tf
)->isnothrow
= 1;
2302 ((TypeFunction
*)tf
)->ispure
= 1;
2312 * ts -> ... -> tf -> t
2315 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2327 /**********************************
2328 * Return array of Declaration *'s.
2331 Array
*Parser::parseDeclarations()
2333 enum STC storage_class
;
2341 unsigned char *comment
= token
.blockComment
;
2342 enum LINK link
= linkage
;
2344 //printf("parseDeclarations() %s\n", token.toChars());
2345 switch (token
.value
)
2358 storage_class
= STCundefined
;
2361 switch (token
.value
)
2364 if (peek(&token
)->value
== TOKlparen
)
2370 if (peek(&token
)->value
== TOKlparen
)
2375 case TOKstatic
: stc
= STCstatic
; goto L1
;
2376 case TOKfinal
: stc
= STCfinal
; goto L1
;
2377 case TOKauto
: stc
= STCauto
; goto L1
;
2378 case TOKscope
: stc
= STCscope
; goto L1
;
2379 case TOKoverride
: stc
= STCoverride
; goto L1
;
2380 case TOKabstract
: stc
= STCabstract
; goto L1
;
2381 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
2382 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
2383 case TOKnothrow
: stc
= STCnothrow
; goto L1
;
2384 case TOKpure
: stc
= STCpure
; goto L1
;
2385 case TOKtls
: stc
= STCtls
; goto L1
;
2386 case TOKenum
: stc
= STCmanifest
; goto L1
;
2388 if (storage_class
& stc
)
2389 error("redundant storage class '%s'", token
.toChars());
2390 storage_class
= (STC
) (storage_class
| stc
);
2392 unsigned u
= storage_class
;
2393 u
&= STCconst
| STCinvariant
| STCmanifest
;
2395 error("conflicting storage class %s", Token::toChars(token
.value
));
2401 if (peek(&token
)->value
!= TOKlparen
)
2406 link
= parseLinkage();
2417 /* Look for auto initializers:
2418 * storage_class identifier = initializer;
2420 while (storage_class
&&
2421 token
.value
== TOKidentifier
&&
2422 peek(&token
)->value
== TOKassign
)
2424 ident
= token
.ident
;
2427 Initializer
*init
= parseInitializer();
2428 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
2429 v
->storage_class
= storage_class
;
2430 v
->dltNormalMode
= dltNormalMode
;
2432 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
2435 addComment(v
, comment
);
2437 else if (token
.value
== TOKcomma
)
2440 if (!(token
.value
== TOKidentifier
&& peek(&token
)->value
== TOKassign
))
2442 error("Identifier expected following comma");
2448 error("%s expected following auto declaration, not '%s'", endToken(), token
.toChars());
2452 if (token
.value
== TOKclass
)
2453 { AggregateDeclaration
*s
;
2455 s
= (AggregateDeclaration
*)parseAggregate();
2456 s
->storage_class
|= storage_class
;
2458 addComment(s
, comment
);
2462 ts
= parseBasicType();
2463 ts
= parseBasicType2(ts
);
2468 Loc loc
= this->loc
;
2469 TemplateParameters
*tpl
= NULL
;
2472 t
= parseDeclarator(ts
, &ident
, &tpl
);
2476 else if (t
!= tfirst
)
2477 error("multiple declarations must have the same type, not %s and %s",
2478 tfirst
->toChars(), t
->toChars());
2480 error("no identifier for declarator %s", t
->toChars());
2482 if (tok
== TOKtypedef
|| tok
== TOKalias
)
2487 if (token
.value
== TOKassign
)
2490 init
= parseInitializer();
2492 if (tok
== TOKtypedef
)
2493 v
= new TypedefDeclaration(loc
, ident
, t
, init
);
2496 error("alias cannot have initializer");
2497 v
= new AliasDeclaration(loc
, ident
, t
);
2499 v
->storage_class
= storage_class
;
2500 if (link
== linkage
)
2504 Array
*ax
= new Array();
2506 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2509 switch (token
.value
)
2510 { case TOKsemicolon
:
2513 addComment(v
, comment
);
2518 addComment(v
, comment
);
2522 error("%s expected to close %s declaration", endToken(), Token::toChars(tok
));
2526 else if (t
->ty
== Tfunction
)
2527 { FuncDeclaration
*f
;
2530 f
= new FuncDeclaration(loc
, 0, ident
, storage_class
, t
);
2531 addComment(f
, comment
);
2533 addComment(f
, NULL
);
2534 if (link
== linkage
)
2540 Array
*ax
= new Array();
2542 s
= new LinkDeclaration(link
, ax
);
2544 if (tpl
) // it's a function template
2546 TemplateDeclaration
*tempdecl
;
2548 // Wrap a template around the aggregate declaration
2549 decldefs
= new Array();
2551 tempdecl
= new TemplateDeclaration(loc
, s
->ident
, tpl
, decldefs
, dltSyntax
);
2554 addComment(s
, comment
);
2558 { VarDeclaration
*v
;
2562 if (token
.value
== TOKassign
)
2565 init
= parseInitializer();
2567 v
= new VarDeclaration(loc
, t
, ident
, init
);
2569 v
->requirePointerInit
= true;
2570 v
->storage_class
= storage_class
;
2571 v
->dltNormalMode
= dltNormalMode
;
2572 if (link
== linkage
)
2576 Array
*ax
= new Array();
2578 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2581 switch (token
.value
)
2585 addComment(v
, comment
);
2590 addComment(v
, comment
);
2594 addComment(v
, comment
);
2598 error("%s expected, not '%s'", endToken(), token
.toChars());
2607 /*****************************************
2608 * Parse contracts following function declaration.
2611 void Parser::parseContracts(FuncDeclaration
*f
)
2614 enum LINK linksave
= linkage
;
2616 // The following is irrelevant, as it is overridden by sc->linkage in
2617 // TypeFunction::semantic
2618 linkage
= LINKd
; // nested functions have D linkage
2620 switch (token
.value
)
2624 if (token
.value
!= startBlockTok
)
2625 error("use %s to start a new block", Token::toChars(startBlockTok
));
2626 if (f
->frequire
|| f
->fensure
)
2627 error("missing body { ... } after in or out");
2628 f
->fbody
= parseStatement(PSsemi
| PScolon
);
2634 f
->fbody
= parseStatement(PScurly
);
2640 error("unexpected semi-colon after function declaration");
2643 if (f
->frequire
|| f
->fensure
)
2644 error("missing body { ... } after in or out");
2648 #if 0 // Do we want this for function declarations, so we can do:
2649 // int x, y, foo(), z;
2655 #if 0 // Dumped feature
2658 f
->fthrows
= new Array();
2663 tb
= parseBasicType();
2664 f
->fthrows
->push(tb
);
2665 if (token
.value
== TOKcomma
)
2678 error("redundant 'in' statement");
2679 f
->frequire
= parseStatement(PScurly
| PSscope
);
2683 // parse: out (identifier) { statement }
2685 if (token
.value
!= startBlockTok
)
2688 if (token
.value
!= TOKidentifier
)
2689 error("(identifier) following 'out' expected, not %s", token
.toChars());
2690 f
->outId
= token
.ident
;
2695 error("redundant 'out' statement");
2696 f
->fensure
= parseStatement(PScurly
| PSscope
);
2700 error("%s expected following function declaration", endToken());
2706 /*****************************************
2709 Initializer
*Parser::parseInitializer()
2711 StructInitializer
*is
;
2712 ArrayInitializer
*ia
;
2718 Loc loc
= this->loc
;
2722 switch (token
.value
)
2725 /* Scan ahead to see if it is a struct initializer or
2726 * a function literal.
2727 * If it contains a ';', it is a function literal.
2728 * Treat { } as a struct initializer.
2731 for (t
= peek(&token
); 1; t
= peek(t
))
2757 is
= new StructInitializer(loc
);
2762 switch (token
.value
)
2766 error("comma expected separating field initializers");
2768 if (t
->value
== TOKcolon
)
2772 nextToken(); // skip over ':'
2777 value
= parseInitializer();
2778 is
->addInit(id
, value
);
2787 case TOKrcurly
: // allow trailing comma's
2792 error("found EOF instead of initializer");
2796 value
= parseInitializer();
2797 is
->addInit(NULL
, value
);
2800 //error("found '%s' instead of field initializer", token.toChars());
2808 ia
= new ArrayInitializer(loc
);
2813 switch (token
.value
)
2817 { error("comma expected separating array initializers, not %s", token
.toChars());
2821 e
= parseAssignExp();
2824 if (token
.value
== TOKcolon
)
2827 value
= parseInitializer();
2830 { value
= new ExpInitializer(e
->loc
, e
);
2833 ia
->addInit(e
, value
);
2840 error("comma expected separating array initializers, not %s", token
.toChars());
2841 value
= parseInitializer();
2842 ia
->addInit(NULL
, value
);
2851 case TOKrbracket
: // allow trailing comma's
2856 error("found '%s' instead of array initializer", token
.toChars());
2865 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
|| t
->value
== TOKendline
)
2868 return new VoidInitializer(loc
);
2874 e
= parseAssignExp();
2875 ie
= new ExpInitializer(loc
, e
);
2880 /*****************************************
2881 * Parses default argument initializer expression that is an assign expression,
2882 * with special handling for __FILE__ and __LINE__.
2885 Expression
*Parser::parseDefaultInitExp()
2887 if (token
.value
== TOKfile
||
2888 token
.value
== TOKline
)
2890 Token
*t
= peek(&token
);
2891 if (t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
2894 if (token
.value
== TOKfile
)
2895 e
= new FileInitExp(loc
);
2897 e
= new LineInitExp(loc
);
2903 Expression
*e
= parseAssignExp();
2907 Statement
*Parser::logStatement(int level
) {
2909 if (token
.value
!= TOKlparen
)
2910 error(loc
, "found '%s' when expecting '('", token
.toChars());
2911 return new LogStatement(loc
, level
, parseArguments());
2914 /*****************************************
2919 Statement
*DltParser::parseStatement(int flags
)
2922 if (flags
& (PScolon
| PSscope
))
2924 return Parser::parseStatement(flags
);
2927 Statement
*Parser::parseStatement(int flags
)
2930 Condition
*condition
;
2932 Statement
*elsebody
;
2933 Loc loc
= this->loc
;
2935 //printf("parseStatement()\n");
2937 if ((flags
& PScurly
) && token
.value
!= startBlockTok
)
2938 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
2940 int tok
= token
.value
;
2942 switch (token
.value
)
2947 // Need to look ahead to see if it is a declaration, label, or expression
2949 if (t
->value
== TOKcolon
)
2953 ident
= token
.ident
;
2956 s
= parseStatement(PSsemi
);
2957 s
= new LabelStatement(loc
, ident
, s
);
2961 // fallthrough to TOKdot
2964 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2980 case TOKimaginary32v
:
2981 case TOKimaginary64v
:
2982 case TOKimaginary80v
:
3010 exp
= parseExpression();
3012 check(TOKsemicolon
, "statement");
3013 s
= new ExpStatement(loc
, exp
);
3018 { // Look ahead to see if it's static assert() or static if()
3022 if (t
->value
== TOKassert
)
3025 s
= new StaticAssertStatement(parseStaticAssert());
3028 if (t
->value
== TOKif
)
3031 condition
= parseStaticIfCondition();
3035 error("no static variables in Delight");
3051 a
= parseDeclarations();
3054 Statements
*as
= new Statements();
3055 as
->reserve(a
->dim
);
3056 for (int i
= 0; i
< a
->dim
; i
++)
3058 Dsymbol
*d
= (Dsymbol
*)a
->data
[i
];
3059 s
= new DeclarationStatement(loc
, d
);
3062 s
= new CompoundStatement(loc
, as
);
3064 else if (a
->dim
== 1)
3066 Dsymbol
*d
= (Dsymbol
*)a
->data
[0];
3067 s
= new DeclarationStatement(loc
, d
);
3071 if (flags
& PSscope
)
3072 s
= new ScopeStatement(loc
, s
);
3082 d
= parseAggregate();
3083 s
= new DeclarationStatement(loc
, d
);
3088 { /* Determine if this is a manifest constant declaration,
3089 * or a conventional enum.
3092 Token
*t
= peek(&token
);
3093 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
3095 else if (t
->value
!= TOKidentifier
)
3100 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
3101 t
->value
== TOKsemicolon
)
3106 s
= new DeclarationStatement(loc
, d
);
3112 if (t
->value
== TOKlparen
)
3115 check(TOKlparen
, "mixin");
3116 Expression
*e
= parseAssignExp();
3119 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3120 error("expected newline after mixin(), not '%s'", token
.toChars());
3123 check(TOKsemicolon
);
3125 s
= new CompileStatement(loc
, e
);
3128 Dsymbol
*d
= parseMixin();
3129 s
= new DeclarationStatement(loc
, d
);
3135 { Statements
*statements
;
3137 if (token
.value
!= startBlockTok
)
3138 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
3142 statements
= new Statements();
3143 while (token
.value
!= TOKrcurly
)
3145 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3149 s
= new CompoundStatement(loc
, statements
);
3150 if (flags
& (PSscope
| PScurlyscope
))
3151 s
= new ScopeStatement(loc
, s
);
3156 case TOKlog_error
: s
= logStatement(LogStatement::Error
); break;
3157 case TOKlog_warning
: s
= logStatement(LogStatement::Warn
); break;
3158 case TOKlog_info
: s
= logStatement(LogStatement::Info
); break;
3159 case TOKlog_trace
: s
= logStatement(LogStatement::Trace
); break;
3162 { Expression
*condition
;
3167 condition
= parseExpression();
3169 body
= parseStatement(PSscope
);
3170 s
= new WhileStatement(loc
, condition
, body
);
3175 if (!(flags
& PSsemi
))
3176 error("use '{ }' for an empty statement, not a ';'");
3178 s
= new ExpStatement(loc
, NULL
);
3183 Expression
*condition
;
3186 body
= parseStatement(PSscope
);
3189 condition
= parseExpression();
3191 s
= new DoStatement(loc
, body
, condition
);
3198 Expression
*condition
;
3199 Expression
*increment
;
3204 if (token
.value
== TOKlparen
) {
3205 /* for (init; cond; incr): ... */
3207 if (token
.value
== TOKsemicolon
)
3212 { init
= parseStatement(0);
3214 check(TOKsemicolon
);
3216 if (token
.value
== TOKsemicolon
)
3223 condition
= parseExpression();
3224 check(TOKsemicolon
, "for condition");
3226 if (token
.value
== TOKrparen
)
3231 { increment
= parseExpression();
3234 body
= parseStatement(PSscope
);
3235 s
= new ForStatement(loc
, init
, condition
, increment
, body
);
3237 s
= new ScopeStatement(loc
, s
);
3238 } else if (dltSyntax
)
3245 case TOKforeach_reverse
:
3247 /* for var in seq: ... */
3248 /* for index, var in seq: ... */
3249 Arguments
*arguments
;
3254 enum TOK op
= (TOK
) tok
;
3257 op
= TOKforeach
; // Delight foreach syntax
3263 TOK inTok
= dltSyntax
? TOKin
: TOKsemicolon
;
3265 arguments
= new Arguments();
3270 Identifier
*ai
= NULL
;
3272 unsigned storageClass
;
3276 if (token
.value
== TOKinout
|| token
.value
== TOKref
)
3277 { storageClass
= STCref
;
3280 if (token
.value
== TOKidentifier
)
3282 Token
*t
= peek(&token
);
3283 if (t
->value
== TOKcomma
|| t
->value
== inTok
)
3285 at
= NULL
; // infer argument type
3290 at
= parseType(&ai
);
3292 error("no identifier for declarator %s", at
->toChars());
3294 a
= new Argument(storageClass
, at
, ai
, NULL
);
3296 if (token
.value
== TOKcomma
)
3305 aggr
= parseExpression();
3306 if (token
.value
== TOKslice
&& arguments
->dim
== 1)
3308 Argument
*a
= (Argument
*)arguments
->data
[0];
3311 Expression
*upr
= parseExpression();
3313 if (token
.value
== TOKreserved
)
3315 op
= TOKforeach_reverse
;
3318 body
= parseStatement(0);
3319 s
= new ForeachRangeStatement(loc
, op
, a
, aggr
, upr
, body
);
3324 if (token
.value
== TOKreserved
)
3326 op
= TOKforeach_reverse
;
3329 body
= parseStatement(0);
3330 s
= new ForeachStatement(loc
, op
, arguments
, aggr
, body
);
3336 { Argument
*arg
= NULL
;
3337 Expression
*condition
;
3339 Statement
*elsebody
;
3344 if (token
.value
== TOKauto
)
3347 if (token
.value
== TOKidentifier
)
3349 Token
*t
= peek(&token
);
3350 if (t
->value
== TOKassign
)
3352 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3357 { error("= expected following auto identifier");
3362 { error("identifier expected following auto");
3366 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
3371 at
= parseType(&ai
);
3373 arg
= new Argument(0, at
, ai
, NULL
);
3376 // Check for " ident;"
3377 else if (token
.value
== TOKidentifier
&& !dltSyntax
)
3379 Token
*t
= peek(&token
);
3380 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
3382 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3385 if (1 || !global
.params
.useDeprecated
)
3386 error("if (v; e) is deprecated, use if (auto v = e)");
3390 condition
= parseExpression();
3392 ifbody
= parseStatement(PSscope
);
3393 if (token
.value
== TOKelse
)
3398 if (token
.value
== TOKcolon
) {
3399 elsebody
= parseStatement(PSscope
);
3400 } else if (token
.value
== TOKif
) {
3401 elsebody
= parseStatement(0);
3403 error("Expected 'else:' or 'else if', not 'else %s'", token
.toChars());
3408 elsebody
= parseStatement(PSscope
);
3412 s
= new IfStatement(loc
, arg
, condition
, ifbody
, elsebody
);
3417 if (peek(&token
)->value
!= TOKlparen
)
3418 goto Ldeclaration
; // scope used as storage class
3421 if (token
.value
!= TOKidentifier
)
3422 { error("scope identifier expected");
3426 { TOK t
= TOKon_scope_exit
;
3427 Identifier
*id
= token
.ident
;
3430 t
= TOKon_scope_exit
;
3431 else if (id
== Id::failure
)
3432 t
= TOKon_scope_failure
;
3433 else if (id
== Id::success
)
3434 t
= TOKon_scope_success
;
3436 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
3439 Statement
*st
= parseStatement(PScolon
| PScurlyscope
);
3440 s
= new OnScopeStatement(loc
, t
, st
);
3446 condition
= parseDebugCondition();
3451 condition
= parseVersionCondition();
3455 if (dltSyntax
&& token
.value
!= TOKcolon
)
3456 error("expected colon after condition, not '%s'", token
.toChars());
3457 ifbody
= parseStatement(PScolon
/*PSsemi*/);
3459 if (token
.value
== TOKelse
)
3462 elsebody
= parseStatement(PScolon
/*PSsemi*/);
3464 s
= new ConditionalStatement(loc
, condition
, ifbody
, elsebody
);
3468 { Identifier
*ident
;
3469 Expressions
*args
= NULL
;
3474 if (token
.value
!= TOKidentifier
)
3475 { error("pragma(identifier expected");
3478 ident
= token
.ident
;
3480 if (token
.value
== TOKcomma
)
3481 args
= parseArguments(); // pragma(identifier, args...);
3483 check(TOKrparen
); // pragma(identifier);
3484 if (token
.value
== TOKsemicolon
)
3489 body
= parseStatement(PSsemi
| PScolon
);
3490 s
= new PragmaStatement(loc
, ident
, args
, body
);
3495 { Expression
*condition
;
3500 condition
= parseExpression();
3502 body
= parseStatement(PSscope
| PScolon
);
3503 s
= new SwitchStatement(loc
, condition
, body
);
3509 Statements
*statements
;
3510 Array cases
; // array of Expression's
3515 exp
= parseAssignExp();
3517 if (token
.value
!= TOKcomma
)
3523 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3529 statements
= new Statements();
3530 while (token
.value
!= TOKcase
&&
3531 token
.value
!= TOKdefault
&&
3532 token
.value
!= TOKrcurly
)
3534 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3536 s
= new CompoundStatement(loc
, statements
);
3539 s
= new ScopeStatement(loc
, s
);
3541 // Keep cases in order by building the case statements backwards
3542 for (int i
= cases
.dim
; i
; i
--)
3544 exp
= (Expression
*)cases
.data
[i
- 1];
3545 s
= new CaseStatement(loc
, exp
, s
);
3552 Statements
*statements
;
3558 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3564 statements
= new Statements();
3565 while (token
.value
!= TOKcase
&&
3566 token
.value
!= TOKdefault
&&
3567 token
.value
!= TOKrcurly
)
3569 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3571 s
= new CompoundStatement(loc
, statements
);
3574 s
= new ScopeStatement(loc
, s
);
3575 s
= new DefaultStatement(loc
, s
);
3583 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
3586 exp
= parseExpression();
3589 check(TOKsemicolon
, "return statement");
3590 else if (token
.value
!= TOKendline
) {
3591 error("Expected end-of-line after return statement, but found '%s'", token
.toChars());
3594 s
= new ReturnStatement(loc
, exp
);
3599 { Identifier
*ident
;
3602 if (token
.value
== TOKidentifier
)
3603 { ident
= token
.ident
;
3608 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3609 error("expected %s after break, not '%s'", endToken(), token
.toChars());
3613 s
= new BreakStatement(loc
, ident
);
3618 { Identifier
*ident
;
3621 if (token
.value
== TOKidentifier
)
3622 { ident
= token
.ident
;
3627 check(TOKsemicolon
, "continue statement");
3628 s
= new ContinueStatement(loc
, ident
);
3633 { Identifier
*ident
;
3636 if (token
.value
== TOKdefault
)
3639 s
= new GotoDefaultStatement(loc
);
3641 else if (token
.value
== TOKcase
)
3643 Expression
*exp
= NULL
;
3646 if (token
.value
!= TOKsemicolon
)
3647 exp
= parseExpression();
3648 s
= new GotoCaseStatement(loc
, exp
);
3652 if (token
.value
!= TOKidentifier
)
3653 { error("Identifier expected following goto");
3657 { ident
= token
.ident
;
3660 s
= new GotoStatement(loc
, ident
);
3664 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3665 error("expected %s after goto statement, not '%s'", endToken(), token
.toChars());
3669 check(TOKsemicolon
);
3673 case TOKsynchronized
:
3678 if (token
.value
== TOKlparen
)
3681 exp
= parseExpression();
3686 body
= parseStatement(PSscope
);
3687 s
= new SynchronizedStatement(loc
, exp
, body
);
3697 exp
= parseExpression();
3699 body
= parseStatement(PSscope
);
3700 s
= new WithStatement(loc
, exp
, body
);
3706 Array
*catches
= NULL
;
3707 Statement
*finalbody
= NULL
;
3710 body
= parseStatement(PSscope
);
3711 while (token
.value
== TOKcatch
)
3717 Loc loc
= this->loc
;
3720 if (token
.value
== startBlockTok
)
3732 handler
= parseStatement(PScolon
);
3733 c
= new Catch(loc
, t
, id
, handler
);
3735 catches
= new Array();
3739 if (token
.value
== TOKfinally
)
3741 finalbody
= parseStatement(PScolon
);
3745 if (!catches
&& !finalbody
)
3746 error("catch or finally expected following try");
3749 s
= new TryCatchStatement(loc
, body
, catches
);
3751 s
= new TryFinallyStatement(loc
, s
, finalbody
);
3760 exp
= parseExpression();
3761 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3762 error("%s expected after throw statement, not '%s'", endToken(), token
.toChars());
3766 s
= new ThrowStatement(loc
, exp
);
3772 s
= parseStatement(PSsemi
| PScurlyscope
);
3773 if (!global
.params
.useDeprecated
)
3774 error("volatile statements deprecated; used synchronized statements instead");
3775 s
= new VolatileStatement(loc
, s
);
3779 { Statements
*statements
;
3785 // Parse the asm block into a sequence of AsmStatements,
3786 // each AsmStatement is one instruction.
3787 // Separate out labels.
3788 // Defer parsing of AsmStatements until semantic processing.
3791 #if GDC_EXTENDED_ASM_SYNTAX
3792 if (token
.value
== TOKlparen
)
3799 check(startBlockTok
);
3801 ptoklist
= &toklist
;
3803 statements
= new Statements();
3806 switch (token
.value
)
3811 // Look ahead to see if it is a label
3813 if (t
->value
== TOKcolon
)
3815 label
= token
.ident
;
3816 labelloc
= this->loc
;
3825 if (toklist
|| label
)
3827 error("asm statements must end in ';'");
3834 if (toklist
|| label
)
3835 { // Create AsmStatement from list of tokens we've saved
3836 s
= new AsmStatement(this->loc
, toklist
);
3838 ptoklist
= &toklist
;
3840 { s
= new LabelStatement(labelloc
, label
, s
);
3843 statements
->push(s
);
3850 error("matching '}' expected, not end of file");
3855 // If the first token is a string or '(', parse as extended asm.
3859 statements
->push(s
);
3862 // ...else, drop through.
3866 *ptoklist
= new Token();
3867 memcpy(*ptoklist
, &token
, sizeof(Token
));
3868 ptoklist
= &(*ptoklist
)->next
;
3876 s
= new CompoundStatement(loc
, statements
);
3882 error("found '%s' instead of statement", token
.toChars());
3886 while (token
.value
!= TOKrcurly
&&
3887 token
.value
!= TOKsemicolon
&&
3888 token
.value
!= TOKeof
)
3890 if (token
.value
== TOKsemicolon
)
3899 Statement
*Parser::parseExtAsm(int expect_rparen
)
3901 Expression
* insnTemplate
;
3902 Expressions
* args
= NULL
;
3903 Array
* argNames
= NULL
;
3904 Expressions
* argConstraints
= NULL
;
3905 int nOutputArgs
= 0;
3906 Expressions
* clobbers
= NULL
;
3907 bool isInputPhase
= false; // Output operands first, then input.
3909 insnTemplate
= parseExpression();
3910 if (token
.value
== TOKrparen
|| token
.value
== TOKsemicolon
)
3914 Expression
* arg
= NULL
;
3915 Identifier
* name
= NULL
;
3916 Expression
* constraint
= NULL
;
3918 switch (token
.value
)
3929 error("unterminated statement");
3933 if (token
.value
== TOKidentifier
)
3939 error("expected identifier after '['");
3943 constraint
= parsePrimaryExp();
3944 if (constraint
->op
!= TOKstring
)
3945 error("expected constant string constraint for operand");
3946 arg
= parseAssignExp();
3949 args
= new Expressions
;
3950 argConstraints
= new Expressions
;
3951 argNames
= new Array
;
3954 argNames
->push(name
);
3955 argConstraints
->push(constraint
);
3959 if (token
.value
== TOKcomma
)
3966 isInputPhase
= true;
3973 Expression
* clobber
;
3975 switch (token
.value
)
3982 error("unterminated statement");
3985 clobber
= parseAssignExp();
3986 if (clobber
->op
!= TOKstring
)
3987 error("expected constant string constraint for clobber name");
3989 clobbers
= new Expressions
;
3990 clobbers
->push(clobber
);
3992 if (token
.value
== TOKcomma
)
4001 check(TOKsemicolon
);
4003 return new ExtAsmStatement(loc
, insnTemplate
, args
, argNames
,
4004 argConstraints
, nOutputArgs
, clobbers
);
4007 void Parser::optionalEndline() {
4008 while (token
.value
== TOKendline
) {
4013 void Parser::check(enum TOK value
)
4018 void Parser::check(Loc loc
, enum TOK value
)
4020 if (token
.value
!= value
)
4021 error(loc
, "found '%s' when expecting '%s'", token
.toChars(), Token::toChars(value
));
4025 void Parser::check(enum TOK value
, char *string
)
4027 if (token
.value
!= value
)
4028 error("found '%s' when expecting '%s' following '%s'",
4029 token
.toChars(), Token::toChars(value
), string
);
4033 char *Parser::endToken()
4038 char *DltParser::endToken()
4043 void Parser::checkLParen() { check(TOKlparen
); }
4044 void Parser::checkRParen() { check(TOKrparen
); }
4046 void DltParser::checkLParen() { }
4047 void DltParser::checkRParen() { }
4049 /************************************
4050 * Determine if the scanner is sitting on the start of a declaration.
4052 * needId 0 no identifier
4053 * 1 identifier optional
4054 * 2 must have identifier
4057 int Parser::isDeclaration(Token
*t
, int needId
, enum TOK endtok
, Token
**pt
)
4061 if ((t
->value
== TOKconst
|| t
->value
== TOKinvariant
) &&
4062 peek(t
)->value
!= TOKlparen
)
4069 if (!isBasicType(&t
))
4071 if (!isDeclarator(&t
, &haveId
, endtok
))
4074 (needId
== 0 && !haveId
) ||
4075 (needId
== 2 && haveId
))
4084 int Parser::isBasicType(Token
**pt
)
4086 // This code parallels parseBasicType()
4100 if (t
->value
== TOKnot
)
4110 if (t
->value
== TOKdot
)
4114 if (t
->value
!= TOKidentifier
)
4117 if (t
->value
!= TOKnot
)
4121 if (t
->value
!= TOKlparen
)
4123 if (!skipParens(t
, &t
))
4135 /* typeof(exp).identifier...
4138 if (t
->value
!= TOKlparen
)
4140 if (!skipParens(t
, &t
))
4146 // const(type) or invariant(type)
4148 if (t
->value
!= TOKlparen
)
4151 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
4166 int Parser::isDeclarator(Token
**pt
, int *haveId
, enum TOK endtok
)
4167 { // This code parallels parseDeclarator()
4171 //printf("Parser::isDeclarator()\n");
4173 if (t
->value
== TOKassign
)
4189 if (t
->value
== TOKrbracket
)
4193 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
4194 { // It's an associative array declaration
4200 // [ expression .. expression ]
4201 if (!isExpression(&t
))
4203 if (t
->value
== TOKslice
)
4205 if (!isExpression(&t
))
4208 if (t
->value
!= TOKrbracket
)
4224 if (t
->value
== TOKrparen
)
4225 return FALSE
; // () is not a declarator
4227 /* Regard ( identifier ) as not a declarator
4228 * BUG: what about ( *identifier ) in
4230 * where f is a class instance with overloaded () ?
4231 * Should we just disallow C-style function pointer declarations?
4233 if (t
->value
== TOKidentifier
)
4234 { Token
*t2
= peek(t
);
4235 if (t2
->value
== TOKrparen
)
4240 if (!isDeclarator(&t
, haveId
, TOKrparen
))
4249 if (!isParameters(&t
))
4264 if (t
->value
== TOKrbracket
)
4268 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
4269 { // It's an associative array declaration
4275 if (!isExpression(&t
))
4277 if (t
->value
!= TOKrbracket
)
4286 if (!isParameters(&t
))
4288 if (t
->value
== TOKconst
|| t
->value
== TOKinvariant
)
4292 // Valid tokens that follow a declaration
4302 if ((dltSyntax
&& t
->value
== TOKlcurly
) ||
4303 (!dltSyntax
&& t
->value
== TOKcolon
)) {
4307 // The !parens is to disallow unnecessary parentheses
4308 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
4321 int Parser::isParameters(Token
**pt
)
4322 { // This code parallels parseParameters()
4326 //printf("isParameters()\n");
4327 if (t
->value
!= TOKlparen
)
4331 for (;1; t
= peek(t
))
4354 if (!isBasicType(&t
))
4357 if (t
->value
!= TOKdotdotdot
&&
4358 !isDeclarator(&t
, &tmp
, TOKreserved
))
4360 if (t
->value
== TOKassign
)
4362 if (!isExpression(&t
))
4365 if (t
->value
== TOKdotdotdot
)
4370 if (t
->value
== TOKcomma
)
4378 if (t
->value
!= TOKrparen
)
4385 int Parser::isExpression(Token
**pt
)
4387 // This is supposed to determine if something is an expression.
4388 // What it actually does is scan until a closing right bracket
4396 for (;; t
= peek(t
))
4414 if (brnest
|| panest
)
4428 if (--curlynest
>= 0)
4455 /**********************************************
4457 * instance foo.bar(parameters...)
4459 * if (pt), *pt is set to the token following the closing )
4461 * 1 it's valid instance syntax
4462 * 0 invalid instance syntax
4465 int Parser::isTemplateInstance(Token
*t
, Token
**pt
)
4468 if (t
->value
!= TOKdot
)
4470 if (t
->value
!= TOKidentifier
)
4474 while (t
->value
== TOKdot
)
4477 if (t
->value
!= TOKidentifier
)
4481 if (t
->value
!= TOKlparen
)
4484 // Skip over the template arguments
4493 if (!skipParens(t
, &t
))
4509 if (t
->value
!= TOKcomma
)
4512 if (t
->value
!= TOKrparen
)
4523 /*******************************************
4524 * Skip parens, brackets.
4528 * *pt is set to closing token, which is ')' on success
4531 * 0 some parsing error
4534 int Parser::skipParens(Token
*t
, Token
**pt
)
4573 /********************************* Expression Parser ***************************/
4575 Expression
*Parser::parsePrimaryExp()
4580 Loc loc
= this->loc
;
4582 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4583 switch (token
.value
)
4588 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4589 { // identifier!(template-argument-list)
4590 TemplateInstance
*tempinst
;
4592 tempinst
= new TemplateInstance(loc
, id
);
4594 tempinst
->tiargs
= parseTemplateArgumentList();
4595 e
= new ScopeExp(loc
, tempinst
);
4598 e
= new IdentifierExp(loc
, id
);
4603 error("'$' is valid only inside [] of index or slice");
4604 e
= new DollarExp(loc
);
4609 // Signal global scope '.' operator with "" identifier
4610 e
= new IdentifierExp(loc
, Id::empty
);
4614 e
= new ThisExp(loc
);
4619 e
= new SuperExp(loc
);
4624 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
4629 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
4634 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
4639 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
4644 e
= new RealExp(loc
, token
.float80value
, Type::tfloat32
);
4649 e
= new RealExp(loc
, token
.float80value
, Type::tfloat64
);
4654 e
= new RealExp(loc
, token
.float80value
, Type::tfloat80
);
4658 case TOKimaginary32v
:
4659 e
= new RealExp(loc
, token
.float80value
, Type::timaginary32
);
4663 case TOKimaginary64v
:
4664 e
= new RealExp(loc
, token
.float80value
, Type::timaginary64
);
4668 case TOKimaginary80v
:
4669 e
= new RealExp(loc
, token
.float80value
, Type::timaginary80
);
4674 e
= new NullExp(loc
);
4675 ((NullExp
*) e
)->dUnchecked
= !dltSyntax
;
4680 { char *s
= loc
.filename
? loc
.filename
: mod
->ident
->toChars();
4681 e
= new StringExp(loc
, s
, strlen(s
), 0);
4687 e
= new IntegerExp(loc
, loc
.linnum
, Type::tint32
);
4692 e
= new IntegerExp(loc
, 1, Type::tbool
);
4697 e
= new IntegerExp(loc
, 0, Type::tbool
);
4702 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tchar
);
4707 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::twchar
);
4712 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
4719 unsigned char postfix
;
4721 // cat adjacent strings
4724 postfix
= token
.postfix
;
4728 if (token
.value
== TOKstring
)
4734 { if (token
.postfix
!= postfix
)
4735 error("mismatched string literal postfixes '%c' and '%c'", postfix
, token
.postfix
);
4736 postfix
= token
.postfix
;
4742 s2
= (unsigned char *)mem
.malloc((len
+ 1) * sizeof(unsigned char));
4743 memcpy(s2
, s
, len1
* sizeof(unsigned char));
4744 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(unsigned char));
4750 e
= new StringExp(loc
, s
, len
, postfix
);
4754 CASE_BASIC_TYPES_X(t
):
4757 check(TOKdot
, t
->toChars());
4758 if (token
.value
!= TOKidentifier
)
4759 { error("found '%s' when expecting identifier following '%s.'", token
.toChars(), t
->toChars());
4762 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4769 if (token
.value
== TOKdot
)
4771 e
= new TypeExp(loc
, t
);
4779 check(TOKlparen
, "typeid");
4780 t
= parseType(); // ( type )
4782 e
= new TypeidExp(loc
, t
);
4787 { /* __traits(identifier, args...)
4790 Objects
*args
= NULL
;
4794 if (token
.value
!= TOKidentifier
)
4795 { error("__traits(identifier, args...) expected");
4798 ident
= token
.ident
;
4800 if (token
.value
== TOKcomma
)
4801 args
= parseTemplateArgumentList2(); // __traits(identifier, args...)
4803 check(TOKrparen
); // __traits(identifier)
4805 e
= new TraitsExp(loc
, ident
, args
);
4811 Identifier
*ident
= NULL
;
4813 enum TOK tok
= TOKreserved
;
4814 enum TOK tok2
= TOKreserved
;
4815 TemplateParameters
*tpl
= NULL
;
4816 Loc loc
= this->loc
;
4819 if (token
.value
== TOKlparen
)
4822 targ
= parseType(&ident
);
4823 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
4827 if (tok
== TOKequal
&&
4828 (token
.value
== TOKtypedef
||
4829 token
.value
== TOKstruct
||
4830 token
.value
== TOKunion
||
4831 token
.value
== TOKclass
||
4832 token
.value
== TOKsuper
||
4833 token
.value
== TOKenum
||
4834 token
.value
== TOKinterface
||
4835 token
.value
== TOKconst
&& peek(&token
)->value
== TOKrparen
||
4836 token
.value
== TOKinvariant
&& peek(&token
)->value
== TOKrparen
||
4837 token
.value
== TOKfunction
||
4838 token
.value
== TOKdelegate
||
4839 token
.value
== TOKreturn
))
4846 tspec
= parseType();
4851 if (token
.value
== TOKcomma
)
4852 tpl
= parseTemplateParameterList(1);
4854 { tpl
= new TemplateParameters();
4857 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, ident
, NULL
, NULL
);
4864 { error("(type identifier : specialization) expected following is");
4867 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
4872 { Expression
*msg
= NULL
;
4877 e
= parseAssignExp();
4878 if (token
.value
== (dltSyntax
? TOKelse
: TOKcomma
))
4880 msg
= parseAssignExp();
4881 } else if (token
.value
== TOKcomma
)
4882 error("Suspicious comma after assert; try 'else' instead");
4885 e
= new AssertExp(loc
, e
, msg
);
4892 check(TOKlparen
, "mixin");
4893 e
= parseAssignExp();
4895 e
= new CompileExp(loc
, e
);
4902 check(TOKlparen
, "import");
4903 e
= parseAssignExp();
4905 e
= new FileExp(loc
, e
);
4910 if (peekPastParen(&token
)->value
== startBlockTok
)
4911 { // (arguments) { statements... }
4917 e
= parseExpression();
4918 check(loc
, TOKrparen
);
4922 { /* Parse array literals and associative array literals:
4923 * [ value, value, value ... ]
4924 * [ key:value, key:value, key:value ... ]
4926 Expressions
*values
= new Expressions();
4927 Expressions
*keys
= NULL
;
4930 if (token
.value
!= TOKrbracket
)
4934 Expression
*e
= parseAssignExp();
4935 if (token
.value
== TOKcolon
&& (keys
|| values
->dim
== 0))
4938 keys
= new Expressions();
4940 e
= parseAssignExp();
4943 { error("'key:value' expected for associative array literal");
4948 if (token
.value
== TOKrbracket
)
4956 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
4958 e
= new ArrayLiteralExp(loc
, values
);
4963 // { statements... }
4973 /* function type(parameters) { body }
4974 * delegate type(parameters) { body }
4975 * (parameters) { body }
4978 Arguments
*arguments
;
4980 FuncLiteralDeclaration
*fd
;
4982 bool isnothrow
= false;
4983 bool ispure
= false;
4985 if (token
.value
== startBlockTok
)
4989 arguments
= new Arguments();
4993 if (token
.value
== TOKlparen
)
4997 t
= parseBasicType();
4998 t
= parseBasicType2(t
); // function return type
5000 arguments
= parseParameters(&varargs
);
5003 if (token
.value
== TOKpure
)
5005 else if (token
.value
== TOKnothrow
)
5012 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
5013 tf
->ispure
= ispure
;
5014 tf
->isnothrow
= isnothrow
;
5015 fd
= new FuncLiteralDeclaration(loc
, 0, tf
, save
, NULL
);
5020 indent
--; // This colon doesn't start a new indent level
5021 fd
->fbody
= new ReturnStatement(loc
, parseAssignExp());
5028 e
= new FuncExp(loc
, fd
);
5033 error("expression expected, not '%s'", token
.toChars());
5035 // Anything for e, as long as it's not NULL
5036 e
= new IntegerExp(loc
, 0, Type::tint32
);
5040 return parsePostExp(e
);
5043 Expression
*Parser::parsePostExp(Expression
*e
)
5050 switch (token
.value
)
5054 if (token
.value
== TOKidentifier
)
5055 { Identifier
*id
= token
.ident
;
5058 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
5059 { // identifier!(template-argument-list)
5060 TemplateInstance
*tempinst
;
5062 tempinst
= new TemplateInstance(loc
, id
);
5064 tempinst
->tiargs
= parseTemplateArgumentList();
5065 e
= new DotTemplateInstanceExp(loc
, e
, tempinst
);
5068 e
= new DotIdExp(loc
, e
, id
);
5071 else if (token
.value
== TOKnew
)
5077 error("identifier expected following '.', not '%s'", token
.toChars());
5081 e
= new PostExp(TOKplusplus
, loc
, e
);
5085 e
= new PostExp(TOKminusminus
, loc
, e
);
5089 e
= new CallExp(loc
, e
, parseArguments());
5093 { // array dereferences:
5096 // array[lwr .. upr]
5102 if (token
.value
== TOKrbracket
)
5104 e
= new SliceExp(loc
, e
, NULL
, NULL
);
5109 index
= parseAssignExp();
5110 if (token
.value
== TOKslice
)
5111 { // array[lwr .. upr]
5113 upr
= parseAssignExp();
5114 e
= new SliceExp(loc
, e
, index
, upr
);
5117 { // array[index, i2, i3, i4, ...]
5118 Expressions
*arguments
= new Expressions();
5119 arguments
->push(index
);
5120 if (token
.value
== TOKcomma
)
5126 arg
= parseAssignExp();
5127 arguments
->push(arg
);
5128 if (token
.value
== TOKrbracket
)
5133 e
= new ArrayExp(loc
, e
, arguments
);
5148 Expression
*Parser::parseUnaryExp()
5150 Loc loc
= this->loc
;
5152 switch (token
.value
)
5156 e
= parseUnaryExp();
5157 e
= new AddrExp(loc
, e
);
5162 e
= parseUnaryExp();
5163 e
= new AddAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
5168 e
= parseUnaryExp();
5169 e
= new MinAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
5174 e
= parseUnaryExp();
5175 e
= new PtrExp(loc
, e
);
5180 e
= parseUnaryExp();
5181 e
= new NegExp(loc
, e
);
5186 e
= parseUnaryExp();
5187 e
= new UAddExp(loc
, e
);
5192 e
= parseUnaryExp();
5193 e
= new NotExp(loc
, e
);
5198 e
= parseUnaryExp();
5199 e
= new ComExp(loc
, e
);
5204 e
= parseUnaryExp();
5205 e
= new DeleteExp(loc
, e
);
5209 e
= parseNewExp(NULL
);
5212 case TOKcast
: // cast(type) expression
5217 /* Look for cast(const) and cast(invariant)
5219 if ((token
.value
== TOKconst
|| token
.value
== TOKinvariant
) &&
5220 peek(&token
)->value
== TOKrparen
)
5221 { enum TOK tok
= token
.value
;
5224 e
= parseUnaryExp();
5225 e
= new CastExp(loc
, e
, tok
);
5229 t
= parseType(); // ( type )
5231 e
= parseUnaryExp();
5232 e
= new CastExp(loc
, e
, t
);
5243 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
5245 tk
= peek(tk
); // skip over right parenthesis
5265 case TOKimaginary32v
:
5266 case TOKimaginary64v
:
5267 case TOKimaginary80v
:
5287 CASE_BASIC_TYPES
: // (type)int.size
5296 if (token
.value
== TOKdot
)
5299 if (token
.value
!= TOKidentifier
)
5300 { error("Identifier expected following (type).");
5303 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
5305 e
= parsePostExp(e
);
5309 e
= parseUnaryExp();
5310 e
= new CastExp(loc
, e
, t
);
5311 error("C style cast illegal, use %s", e
->toChars());
5318 e
= parsePrimaryExp();
5322 e
= parsePrimaryExp();
5329 Expression
*Parser::parseMulExp()
5332 Loc loc
= this->loc
;
5334 e
= parseUnaryExp();
5337 switch (token
.value
)
5339 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
5340 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
5341 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
5351 Expression
*Parser::parseAddExp()
5354 Loc loc
= this->loc
;
5359 switch (token
.value
)
5361 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
5362 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
5363 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
5373 Expression
*Parser::parseShiftExp()
5376 Loc loc
= this->loc
;
5381 switch (token
.value
)
5383 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
5384 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
5385 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
5395 Expression
*Parser::parseRelExp()
5399 Loc loc
= this->loc
;
5401 e
= parseShiftExp();
5404 switch (token
.value
)
5420 e2
= parseShiftExp();
5421 e
= new CmpExp(op
, loc
, e
, e2
);
5426 e2
= parseShiftExp();
5427 e
= new InExp(loc
, e
, e2
);
5438 Expression
*Parser::parseEqualExp()
5442 Loc loc
= this->loc
;
5446 { enum TOK value
= token
.value
;
5454 e
= new EqualExp(value
, loc
, e
, e2
);
5458 error("'===' is no longer legal, use 'is' instead");
5461 case TOKnotidentity
:
5462 error("'!==' is no longer legal, use '!is' instead");
5466 value
= TOKidentity
;
5471 error("next: %s", t
->toChars());
5472 if (t
->value
== TOKnot
)
5475 value
= TOKnotidentity
;
5482 // Attempt to identify '!is'
5484 if (t
->value
!= TOKis
)
5487 value
= TOKnotidentity
;
5493 e
= new IdentityExp(value
, loc
, e
, e2
);
5504 Expression
*Parser::parseCmpExp()
5508 Loc loc
= this->loc
;
5510 e
= parseShiftExp();
5511 enum TOK op
= token
.value
;
5518 e2
= parseShiftExp();
5519 e
= new EqualExp(op
, loc
, e
, e2
);
5527 if (t
->value
== TOKnot
)
5530 op
= TOKnotidentity
;
5537 // Attempt to identify '!is'
5539 if (t
->value
!= TOKis
)
5542 op
= TOKnotidentity
;
5547 e2
= parseShiftExp();
5548 e
= new IdentityExp(op
, loc
, e
, e2
);
5564 e2
= parseShiftExp();
5565 e
= new CmpExp(op
, loc
, e
, e2
);
5570 e2
= parseShiftExp();
5571 e
= new InExp(loc
, e
, e2
);
5580 Expression
*Parser::parseAndExp()
5583 Loc loc
= this->loc
;
5585 if (global
.params
.Dversion
== 1)
5587 e
= parseEqualExp();
5588 while (token
.value
== TOKand
)
5591 e2
= parseEqualExp();
5592 e
= new AndExp(loc
,e
,e2
);
5599 while (token
.value
== TOKand
)
5603 e
= new AndExp(loc
,e
,e2
);
5610 Expression
*Parser::parseXorExp()
5613 Loc loc
= this->loc
;
5616 while (token
.value
== TOKxor
)
5620 e
= new XorExp(loc
, e
, e2
);
5625 Expression
*Parser::parseOrExp()
5628 Loc loc
= this->loc
;
5631 while (token
.value
== TOKor
)
5635 e
= new OrExp(loc
, e
, e2
);
5640 Expression
*Parser::parseAndAndExp()
5643 Loc loc
= this->loc
;
5646 while (token
.value
== TOKandand
)
5650 e
= new AndAndExp(loc
, e
, e2
);
5655 Expression
*Parser::parseOrOrExp()
5658 Loc loc
= this->loc
;
5660 e
= parseAndAndExp();
5661 while (token
.value
== TOKoror
)
5664 e2
= parseAndAndExp();
5665 e
= new OrOrExp(loc
, e
, e2
);
5670 Expression
*Parser::parseCondExp()
5674 Loc loc
= this->loc
;
5677 if (token
.value
== TOKquestion
)
5680 e1
= parseExpression();
5682 e2
= parseCondExp();
5683 e
= new CondExp(loc
, e
, e1
, e2
);
5688 Expression
*DltParser::parseCondExp()
5692 Loc loc
= this->loc
;
5695 if (token
.value
== TOKif
)
5698 e1
= parseExpression();
5700 e2
= parseCondExp();
5701 e
= new CondExp(loc
, e1
, e
, e2
);
5706 Expression
*Parser::parseAssignExp()
5715 switch (token
.value
)
5717 #define X(tok,ector) \
5718 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5720 X(TOKassign
, AssignExp
);
5721 X(TOKaddass
, AddAssignExp
);
5722 X(TOKminass
, MinAssignExp
);
5723 X(TOKmulass
, MulAssignExp
);
5724 X(TOKdivass
, DivAssignExp
);
5725 X(TOKmodass
, ModAssignExp
);
5726 X(TOKandass
, AndAssignExp
);
5727 X(TOKorass
, OrAssignExp
);
5728 X(TOKxorass
, XorAssignExp
);
5729 X(TOKshlass
, ShlAssignExp
);
5730 X(TOKshrass
, ShrAssignExp
);
5731 X(TOKushrass
, UshrAssignExp
);
5732 X(TOKcatass
, CatAssignExp
);
5743 Expression
*Parser::parseExpression()
5746 Loc loc
= this->loc
;
5748 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5749 e
= parseAssignExp();
5750 while (token
.value
== TOKcomma
)
5753 e2
= parseAssignExp();
5754 e
= new CommaExp(loc
, e
, e2
);
5761 /*************************
5762 * Collect argument list.
5763 * Assume current token is '(' or '['.
5766 Expressions
*Parser::parseArguments()
5768 Expressions
*arguments
;
5772 arguments
= new Expressions();
5773 if (token
.value
== TOKlbracket
)
5774 endtok
= TOKrbracket
;
5780 if (token
.value
!= endtok
)
5784 arg
= parseAssignExp();
5785 arguments
->push(arg
);
5786 if (token
.value
== endtok
)
5796 /*******************************************
5799 Expression
*Parser::parseNewExp(Expression
*thisexp
)
5801 Expressions
*newargs
;
5802 Expressions
*arguments
= NULL
;
5804 Loc loc
= this->loc
;
5808 if (token
.value
== TOKlparen
)
5810 newargs
= parseArguments();
5813 // An anonymous nested class starts with "class"
5814 if (token
.value
== TOKclass
)
5819 error("no anonymous classes in Delight");
5821 if (token
.value
== TOKlparen
)
5822 arguments
= parseArguments();
5824 BaseClasses
*baseclasses
= NULL
;
5825 if (token
.value
!= TOKlcurly
)
5826 baseclasses
= parseBaseClasses();
5828 Identifier
*id
= NULL
;
5829 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
);
5831 if (token
.value
!= startBlockTok
)
5832 { error("{ members } expected for anonymous class");
5838 Array
*decl
= parseDeclDefs(0);
5839 if (token
.value
!= TOKrcurly
)
5840 error("class member expected");
5845 e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
5850 t
= parseBasicType();
5851 t
= parseBasicType2(t
);
5852 if (t
->ty
== Taarray
)
5853 { TypeAArray
*taa
= (TypeAArray
*)t
;
5854 Type
*index
= taa
->index
;
5856 Expression
*e
= index
->toExpression();
5858 { arguments
= new Expressions();
5860 t
= new TypeDArray(taa
->next
);
5864 error("need size of rightmost array, not type %s", index
->toChars());
5865 return new NullExp(loc
);
5868 else if (t
->ty
== Tsarray
)
5870 TypeSArray
*tsa
= (TypeSArray
*)t
;
5871 Expression
*e
= tsa
->dim
;
5873 arguments
= new Expressions();
5875 t
= new TypeDArray(tsa
->next
);
5877 else if (token
.value
== TOKlparen
)
5879 arguments
= parseArguments();
5881 e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
5885 /**********************************************
5888 void Parser::addComment(Dsymbol
*s
, unsigned char *blockComment
)
5890 s
->addComment(combineComments(blockComment
, token
.lineComment
));
5894 /********************************* ***************************/