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.*"
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
)
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
);
1767 if (token
.value
!= TOKsemicolon
)
1768 error("';' expected after mixin");
1777 /******************************************
1778 * Parse template argument list.
1780 * current token is opening '('
1782 * current token is one after closing ')'
1785 Objects
*Parser::parseTemplateArgumentList()
1787 //printf("Parser::parseTemplateArgumentList()\n");
1788 if (token
.value
!= TOKlparen
)
1789 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1790 return new Objects();
1792 return parseTemplateArgumentList2();
1795 Objects
*Parser::parseTemplateArgumentList2()
1797 Objects
*tiargs
= new Objects();
1800 // Get TemplateArgumentList
1801 if (token
.value
!= TOKrparen
)
1805 // See if it is an Expression or a Type
1806 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
1810 // Get TemplateArgument
1818 ea
= parseAssignExp();
1821 if (token
.value
!= TOKcomma
)
1826 check(TOKrparen
, "template argument list");
1830 Import
*Parser::parseImport(Array
*decldefs
, int isstatic
)
1833 Identifier
*aliasid
= NULL
;
1837 //printf("Parser::parseImport()\n");
1842 if (token
.value
!= TOKidentifier
)
1843 { error("Identifier expected following import");
1851 if (!aliasid
&& token
.value
== TOKassign
)
1856 while (token
.value
== TOKdot
)
1862 if (token
.value
!= TOKidentifier
)
1863 { error("Identifier expected following package");
1870 s
= new Import(loc
, a
, token
.ident
, aliasid
, isstatic
);
1874 * : alias=name, alias=name;
1877 if (token
.value
== TOKcolon
)
1886 if (dltSyntax
&& token
.value
== TOKrcurly
)
1888 if (token
.value
!= TOKidentifier
)
1889 { error("Identifier expected following :");
1892 alias
= token
.ident
;
1894 if (token
.value
== TOKassign
)
1897 if (token
.value
!= TOKidentifier
)
1898 { error("Identifier expected following %s=", alias
->toChars());
1908 s
->addAlias(name
, alias
);
1909 if (token
.value
!= TOKcomma
&& token
.value
!= TOKendline
)
1923 } while (token
.value
== TOKcomma
);
1925 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
1929 error("%s expected", endToken());
1936 Type
*Parser::parseType(Identifier
**pident
, TemplateParameters
**tpl
)
1939 if (token
.value
== TOKconst
&& peek(&token
)->value
!= TOKlparen
)
1944 t
= parseType(pident
, tpl
);
1948 else if (token
.value
== TOKinvariant
&& peek(&token
)->value
!= TOKlparen
)
1953 t
= parseType(pident
, tpl
);
1954 t
= t
->makeInvariant();
1958 t
= parseBasicType();
1959 t
= parseDeclarator(t
, pident
, tpl
);
1963 Type
*Parser::parseBasicType()
1967 TemplateInstance
*tempinst
;
1969 //printf("parseBasicType()\n");
1970 switch (token
.value
)
1972 CASE_BASIC_TYPES_X(t
):
1979 if (token
.value
== TOKnot
)
1982 tempinst
= new TemplateInstance(loc
, id
);
1983 tempinst
->tiargs
= parseTemplateArgumentList();
1984 tid
= new TypeInstance(loc
, tempinst
);
1988 tid
= new TypeIdentifier(loc
, id
);
1990 while (token
.value
== TOKdot
)
1992 if (token
.value
!= TOKidentifier
)
1993 { error("identifier expected following '.' instead of '%s'", token
.toChars());
1998 if (token
.value
== TOKnot
)
2001 tempinst
= new TemplateInstance(loc
, id
);
2002 tempinst
->tiargs
= parseTemplateArgumentList();
2003 tid
->addIdent((Identifier
*)tempinst
);
2017 tid
= parseTypeof();
2036 t
= t
->makeInvariant();
2040 error("basic type expected, not %s", token
.toChars());
2047 Type
*Parser::parseBasicType2(Type
*t
)
2052 //printf("parseBasicType2()\n");
2055 switch (token
.value
)
2058 t
= new TypePointer(t
);
2063 // Handle []. Make sure things like
2065 // is (array[1] of array[3] of int)
2067 if (token
.value
== TOKrbracket
)
2069 t
= new TypeDArray(t
); // []
2072 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2073 { // It's an associative array declaration
2076 //printf("it's an associative array\n");
2077 index
= parseType(); // [ type ]
2078 t
= new TypeAArray(t
, index
);
2083 //printf("it's [expression]\n");
2085 Expression
*e
= parseExpression(); // [ expression ]
2086 if (token
.value
== TOKslice
)
2090 e2
= parseExpression(); // [ exp .. exp ]
2091 t
= new TypeSlice(t
, e
, e2
);
2094 t
= new TypeSArray(t
,e
);
2102 { // Handle delegate declaration:
2103 // t delegate(parameter list)
2104 // t function(parameter list)
2105 Arguments
*arguments
;
2107 bool ispure
= false;
2108 bool isnothrow
= false;
2109 enum TOK save
= token
.value
;
2112 arguments
= parseParameters(&varargs
);
2115 if (token
.value
== TOKpure
)
2117 else if (token
.value
== TOKnothrow
)
2123 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2124 tf
->ispure
= ispure
;
2125 tf
->isnothrow
= isnothrow
;
2126 if (save
== TOKdelegate
)
2127 t
= new TypeDelegate(tf
);
2129 t
= new TypePointer(tf
); // pointer to function
2137 t
= t
->maybe(false);
2139 error("Type %s cannot be null; ? is pointless", old
->toChars());
2143 // fall-through to default
2156 // Don't wrap it yet, because that confuses resolve()
2157 ((TypeIdentifier
*) ts
)->maybe
= 1;
2160 ts
= ts
->maybe(false);
2168 Type
*Parser::parseDeclarator(Type
*t
, Identifier
**pident
, TemplateParameters
**tpl
)
2171 //printf("parseDeclarator(tpl = %p)\n", tpl);
2172 t
= parseBasicType2(t
);
2174 switch (token
.value
)
2179 *pident
= token
.ident
;
2181 error("unexpected identifer '%s' in declarator", token
.ident
->toChars());
2187 /* Parse things with parentheses around the identifier, like:
2189 * although the D style would be:
2193 ts
= parseDeclarator(t
, pident
);
2204 switch (token
.value
)
2207 /* Support C style array syntax:
2209 * as opposed to D-style:
2213 { // This is the old C-style post [] syntax.
2217 error("use 'type[] var', not 'type var[]'");
2220 if (token
.value
== TOKrbracket
)
2221 { // It's a dynamic array
2222 ta
= new TypeDArray(t
); // []
2225 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
2226 { // It's an associative array
2228 //printf("it's an associative array\n");
2229 Type
*index
= parseType(); // [ type ]
2231 ta
= new TypeAArray(t
, index
);
2235 //printf("It's a static array\n");
2236 Expression
*e
= parseExpression(); // [ expression ]
2237 ta
= new TypeSArray(t
, e
);
2244 * ts -> ... -> ta -> t
2247 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2257 /* Look ahead to see if this is (...)(...),
2258 * i.e. a function template declaration
2260 if (peekPastParen(&token
)->value
== TOKlparen
)
2262 //printf("function template declaration\n");
2264 // Gather template parameter list
2265 *tpl
= parseTemplateParameterList();
2270 Arguments
*arguments
= parseParameters(&varargs
);
2271 Type
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
2273 /* Parse const/invariant/nothrow postfix
2277 switch (token
.value
)
2280 tf
= tf
->makeConst();
2285 tf
= tf
->makeInvariant();
2290 ((TypeFunction
*)tf
)->isnothrow
= 1;
2295 ((TypeFunction
*)tf
)->ispure
= 1;
2305 * ts -> ... -> tf -> t
2308 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
2320 /**********************************
2321 * Return array of Declaration *'s.
2324 Array
*Parser::parseDeclarations()
2326 enum STC storage_class
;
2334 unsigned char *comment
= token
.blockComment
;
2335 enum LINK link
= linkage
;
2337 //printf("parseDeclarations() %s\n", token.toChars());
2338 switch (token
.value
)
2351 storage_class
= STCundefined
;
2354 switch (token
.value
)
2357 if (peek(&token
)->value
== TOKlparen
)
2363 if (peek(&token
)->value
== TOKlparen
)
2368 case TOKstatic
: stc
= STCstatic
; goto L1
;
2369 case TOKfinal
: stc
= STCfinal
; goto L1
;
2370 case TOKauto
: stc
= STCauto
; goto L1
;
2371 case TOKscope
: stc
= STCscope
; goto L1
;
2372 case TOKoverride
: stc
= STCoverride
; goto L1
;
2373 case TOKabstract
: stc
= STCabstract
; goto L1
;
2374 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
2375 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
2376 case TOKnothrow
: stc
= STCnothrow
; goto L1
;
2377 case TOKpure
: stc
= STCpure
; goto L1
;
2378 case TOKtls
: stc
= STCtls
; goto L1
;
2379 case TOKenum
: stc
= STCmanifest
; goto L1
;
2381 if (storage_class
& stc
)
2382 error("redundant storage class '%s'", token
.toChars());
2383 storage_class
= (STC
) (storage_class
| stc
);
2385 unsigned u
= storage_class
;
2386 u
&= STCconst
| STCinvariant
| STCmanifest
;
2388 error("conflicting storage class %s", Token::toChars(token
.value
));
2394 if (peek(&token
)->value
!= TOKlparen
)
2399 link
= parseLinkage();
2410 /* Look for auto initializers:
2411 * storage_class identifier = initializer;
2413 while (storage_class
&&
2414 token
.value
== TOKidentifier
&&
2415 peek(&token
)->value
== TOKassign
)
2417 ident
= token
.ident
;
2420 Initializer
*init
= parseInitializer();
2421 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
2422 v
->storage_class
= storage_class
;
2423 v
->dltNormalMode
= dltNormalMode
;
2425 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
2428 addComment(v
, comment
);
2430 else if (token
.value
== TOKcomma
)
2433 if (!(token
.value
== TOKidentifier
&& peek(&token
)->value
== TOKassign
))
2435 error("Identifier expected following comma");
2441 error("%s expected following auto declaration, not '%s'", endToken(), token
.toChars());
2445 if (token
.value
== TOKclass
)
2446 { AggregateDeclaration
*s
;
2448 s
= (AggregateDeclaration
*)parseAggregate();
2449 s
->storage_class
|= storage_class
;
2451 addComment(s
, comment
);
2455 ts
= parseBasicType();
2456 ts
= parseBasicType2(ts
);
2461 Loc loc
= this->loc
;
2462 TemplateParameters
*tpl
= NULL
;
2465 t
= parseDeclarator(ts
, &ident
, &tpl
);
2469 else if (t
!= tfirst
)
2470 error("multiple declarations must have the same type, not %s and %s",
2471 tfirst
->toChars(), t
->toChars());
2473 error("no identifier for declarator %s", t
->toChars());
2475 if (tok
== TOKtypedef
|| tok
== TOKalias
)
2480 if (token
.value
== TOKassign
)
2483 init
= parseInitializer();
2485 if (tok
== TOKtypedef
)
2486 v
= new TypedefDeclaration(loc
, ident
, t
, init
);
2489 error("alias cannot have initializer");
2490 v
= new AliasDeclaration(loc
, ident
, t
);
2492 v
->storage_class
= storage_class
;
2493 if (link
== linkage
)
2497 Array
*ax
= new Array();
2499 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2502 switch (token
.value
)
2503 { case TOKsemicolon
:
2506 addComment(v
, comment
);
2511 addComment(v
, comment
);
2515 error("%s expected to close %s declaration", endToken(), Token::toChars(tok
));
2519 else if (t
->ty
== Tfunction
)
2520 { FuncDeclaration
*f
;
2523 f
= new FuncDeclaration(loc
, 0, ident
, storage_class
, t
);
2524 addComment(f
, comment
);
2526 addComment(f
, NULL
);
2527 if (link
== linkage
)
2533 Array
*ax
= new Array();
2535 s
= new LinkDeclaration(link
, ax
);
2537 if (tpl
) // it's a function template
2539 TemplateDeclaration
*tempdecl
;
2541 // Wrap a template around the aggregate declaration
2542 decldefs
= new Array();
2544 tempdecl
= new TemplateDeclaration(loc
, s
->ident
, tpl
, decldefs
, dltSyntax
);
2547 addComment(s
, comment
);
2551 { VarDeclaration
*v
;
2555 if (token
.value
== TOKassign
)
2558 init
= parseInitializer();
2560 v
= new VarDeclaration(loc
, t
, ident
, init
);
2562 v
->requirePointerInit
= true;
2563 v
->storage_class
= storage_class
;
2564 v
->dltNormalMode
= dltNormalMode
;
2565 if (link
== linkage
)
2569 Array
*ax
= new Array();
2571 Dsymbol
*s
= new LinkDeclaration(link
, ax
);
2574 switch (token
.value
)
2578 addComment(v
, comment
);
2583 addComment(v
, comment
);
2587 addComment(v
, comment
);
2591 error("%s expected, not '%s'", endToken(), token
.toChars());
2600 /*****************************************
2601 * Parse contracts following function declaration.
2604 void Parser::parseContracts(FuncDeclaration
*f
)
2607 enum LINK linksave
= linkage
;
2609 // The following is irrelevant, as it is overridden by sc->linkage in
2610 // TypeFunction::semantic
2611 linkage
= LINKd
; // nested functions have D linkage
2613 switch (token
.value
)
2617 if (token
.value
!= startBlockTok
)
2618 error("use %s to start a new block", Token::toChars(startBlockTok
));
2619 if (f
->frequire
|| f
->fensure
)
2620 error("missing body { ... } after in or out");
2621 f
->fbody
= parseStatement(PSsemi
| PScolon
);
2627 f
->fbody
= parseStatement(PScurly
);
2633 error("unexpected semi-colon after function declaration");
2636 if (f
->frequire
|| f
->fensure
)
2637 error("missing body { ... } after in or out");
2641 #if 0 // Do we want this for function declarations, so we can do:
2642 // int x, y, foo(), z;
2648 #if 0 // Dumped feature
2651 f
->fthrows
= new Array();
2656 tb
= parseBasicType();
2657 f
->fthrows
->push(tb
);
2658 if (token
.value
== TOKcomma
)
2671 error("redundant 'in' statement");
2672 f
->frequire
= parseStatement(PScurly
| PSscope
);
2676 // parse: out (identifier) { statement }
2678 if (token
.value
!= startBlockTok
)
2681 if (token
.value
!= TOKidentifier
)
2682 error("(identifier) following 'out' expected, not %s", token
.toChars());
2683 f
->outId
= token
.ident
;
2688 error("redundant 'out' statement");
2689 f
->fensure
= parseStatement(PScurly
| PSscope
);
2693 error("%s expected following function declaration", endToken());
2699 /*****************************************
2702 Initializer
*Parser::parseInitializer()
2704 StructInitializer
*is
;
2705 ArrayInitializer
*ia
;
2711 Loc loc
= this->loc
;
2715 switch (token
.value
)
2718 /* Scan ahead to see if it is a struct initializer or
2719 * a function literal.
2720 * If it contains a ';', it is a function literal.
2721 * Treat { } as a struct initializer.
2724 for (t
= peek(&token
); 1; t
= peek(t
))
2750 is
= new StructInitializer(loc
);
2755 switch (token
.value
)
2759 error("comma expected separating field initializers");
2761 if (t
->value
== TOKcolon
)
2765 nextToken(); // skip over ':'
2770 value
= parseInitializer();
2771 is
->addInit(id
, value
);
2780 case TOKrcurly
: // allow trailing comma's
2785 error("found EOF instead of initializer");
2789 value
= parseInitializer();
2790 is
->addInit(NULL
, value
);
2793 //error("found '%s' instead of field initializer", token.toChars());
2801 ia
= new ArrayInitializer(loc
);
2806 switch (token
.value
)
2810 { error("comma expected separating array initializers, not %s", token
.toChars());
2814 e
= parseAssignExp();
2817 if (token
.value
== TOKcolon
)
2820 value
= parseInitializer();
2823 { value
= new ExpInitializer(e
->loc
, e
);
2826 ia
->addInit(e
, value
);
2833 error("comma expected separating array initializers, not %s", token
.toChars());
2834 value
= parseInitializer();
2835 ia
->addInit(NULL
, value
);
2844 case TOKrbracket
: // allow trailing comma's
2849 error("found '%s' instead of array initializer", token
.toChars());
2858 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
|| t
->value
== TOKendline
)
2861 return new VoidInitializer(loc
);
2867 e
= parseAssignExp();
2868 ie
= new ExpInitializer(loc
, e
);
2873 /*****************************************
2874 * Parses default argument initializer expression that is an assign expression,
2875 * with special handling for __FILE__ and __LINE__.
2878 Expression
*Parser::parseDefaultInitExp()
2880 if (token
.value
== TOKfile
||
2881 token
.value
== TOKline
)
2883 Token
*t
= peek(&token
);
2884 if (t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
2887 if (token
.value
== TOKfile
)
2888 e
= new FileInitExp(loc
);
2890 e
= new LineInitExp(loc
);
2896 Expression
*e
= parseAssignExp();
2900 Statement
*Parser::logStatement(int level
) {
2902 if (token
.value
!= TOKlparen
)
2903 error(loc
, "found '%s' when expecting '('", token
.toChars());
2904 return new LogStatement(loc
, level
, parseArguments());
2907 /*****************************************
2912 Statement
*DltParser::parseStatement(int flags
)
2915 if (flags
& (PScolon
| PSscope
))
2917 return Parser::parseStatement(flags
);
2920 Statement
*Parser::parseStatement(int flags
)
2923 Condition
*condition
;
2925 Statement
*elsebody
;
2926 Loc loc
= this->loc
;
2928 //printf("parseStatement()\n");
2930 if ((flags
& PScurly
) && token
.value
!= startBlockTok
)
2931 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
2933 int tok
= token
.value
;
2935 switch (token
.value
)
2940 // Need to look ahead to see if it is a declaration, label, or expression
2942 if (t
->value
== TOKcolon
)
2946 ident
= token
.ident
;
2949 s
= parseStatement(PSsemi
);
2950 s
= new LabelStatement(loc
, ident
, s
);
2954 // fallthrough to TOKdot
2957 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2973 case TOKimaginary32v
:
2974 case TOKimaginary64v
:
2975 case TOKimaginary80v
:
3003 exp
= parseExpression();
3005 check(TOKsemicolon
, "statement");
3006 s
= new ExpStatement(loc
, exp
);
3011 { // Look ahead to see if it's static assert() or static if()
3015 if (t
->value
== TOKassert
)
3018 s
= new StaticAssertStatement(parseStaticAssert());
3021 if (t
->value
== TOKif
)
3024 condition
= parseStaticIfCondition();
3028 error("no static variables in Delight");
3044 a
= parseDeclarations();
3047 Statements
*as
= new Statements();
3048 as
->reserve(a
->dim
);
3049 for (int i
= 0; i
< a
->dim
; i
++)
3051 Dsymbol
*d
= (Dsymbol
*)a
->data
[i
];
3052 s
= new DeclarationStatement(loc
, d
);
3055 s
= new CompoundStatement(loc
, as
);
3057 else if (a
->dim
== 1)
3059 Dsymbol
*d
= (Dsymbol
*)a
->data
[0];
3060 s
= new DeclarationStatement(loc
, d
);
3064 if (flags
& PSscope
)
3065 s
= new ScopeStatement(loc
, s
);
3075 d
= parseAggregate();
3076 s
= new DeclarationStatement(loc
, d
);
3081 { /* Determine if this is a manifest constant declaration,
3082 * or a conventional enum.
3085 Token
*t
= peek(&token
);
3086 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
3088 else if (t
->value
!= TOKidentifier
)
3093 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
3094 t
->value
== TOKsemicolon
)
3099 s
= new DeclarationStatement(loc
, d
);
3105 if (t
->value
== TOKlparen
)
3108 check(TOKlparen
, "mixin");
3109 Expression
*e
= parseAssignExp();
3112 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3113 error("expected newline after mixin(), not '%s'", token
.toChars());
3116 check(TOKsemicolon
);
3118 s
= new CompileStatement(loc
, e
);
3121 Dsymbol
*d
= parseMixin();
3122 s
= new DeclarationStatement(loc
, d
);
3128 { Statements
*statements
;
3130 if (token
.value
!= startBlockTok
)
3131 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok
), token
.toChars());
3135 statements
= new Statements();
3136 while (token
.value
!= TOKrcurly
)
3138 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3142 s
= new CompoundStatement(loc
, statements
);
3143 if (flags
& (PSscope
| PScurlyscope
))
3144 s
= new ScopeStatement(loc
, s
);
3149 case TOKlog_error
: s
= logStatement(LogStatement::Error
); break;
3150 case TOKlog_warning
: s
= logStatement(LogStatement::Warn
); break;
3151 case TOKlog_info
: s
= logStatement(LogStatement::Info
); break;
3152 case TOKlog_trace
: s
= logStatement(LogStatement::Trace
); break;
3155 { Expression
*condition
;
3160 condition
= parseExpression();
3162 body
= parseStatement(PSscope
);
3163 s
= new WhileStatement(loc
, condition
, body
);
3168 if (!(flags
& PSsemi
))
3169 error("use '{ }' for an empty statement, not a ';'");
3171 s
= new ExpStatement(loc
, NULL
);
3176 Expression
*condition
;
3179 body
= parseStatement(PSscope
);
3182 condition
= parseExpression();
3184 s
= new DoStatement(loc
, body
, condition
);
3191 Expression
*condition
;
3192 Expression
*increment
;
3197 if (token
.value
== TOKlparen
) {
3198 /* for (init; cond; incr): ... */
3200 if (token
.value
== TOKsemicolon
)
3205 { init
= parseStatement(0);
3207 check(TOKsemicolon
);
3209 if (token
.value
== TOKsemicolon
)
3216 condition
= parseExpression();
3217 check(TOKsemicolon
, "for condition");
3219 if (token
.value
== TOKrparen
)
3224 { increment
= parseExpression();
3227 body
= parseStatement(PSscope
);
3228 s
= new ForStatement(loc
, init
, condition
, increment
, body
);
3230 s
= new ScopeStatement(loc
, s
);
3231 } else if (dltSyntax
)
3238 case TOKforeach_reverse
:
3240 /* for var in seq: ... */
3241 /* for index, var in seq: ... */
3242 Arguments
*arguments
;
3247 enum TOK op
= (TOK
) tok
;
3250 op
= TOKforeach
; // Delight foreach syntax
3256 TOK inTok
= dltSyntax
? TOKin
: TOKsemicolon
;
3258 arguments
= new Arguments();
3263 Identifier
*ai
= NULL
;
3265 unsigned storageClass
;
3269 if (token
.value
== TOKinout
|| token
.value
== TOKref
)
3270 { storageClass
= STCref
;
3273 if (token
.value
== TOKidentifier
)
3275 Token
*t
= peek(&token
);
3276 if (t
->value
== TOKcomma
|| t
->value
== inTok
)
3278 at
= NULL
; // infer argument type
3283 at
= parseType(&ai
);
3285 error("no identifier for declarator %s", at
->toChars());
3287 a
= new Argument(storageClass
, at
, ai
, NULL
);
3289 if (token
.value
== TOKcomma
)
3298 aggr
= parseExpression();
3299 if (token
.value
== TOKslice
&& arguments
->dim
== 1)
3301 Argument
*a
= (Argument
*)arguments
->data
[0];
3304 Expression
*upr
= parseExpression();
3306 if (token
.value
== TOKreserved
)
3308 op
= TOKforeach_reverse
;
3311 body
= parseStatement(0);
3312 s
= new ForeachRangeStatement(loc
, op
, a
, aggr
, upr
, body
);
3317 if (token
.value
== TOKreserved
)
3319 op
= TOKforeach_reverse
;
3322 body
= parseStatement(0);
3323 s
= new ForeachStatement(loc
, op
, arguments
, aggr
, body
);
3329 { Argument
*arg
= NULL
;
3330 Expression
*condition
;
3332 Statement
*elsebody
;
3337 if (token
.value
== TOKauto
)
3340 if (token
.value
== TOKidentifier
)
3342 Token
*t
= peek(&token
);
3343 if (t
->value
== TOKassign
)
3345 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3350 { error("= expected following auto identifier");
3355 { error("identifier expected following auto");
3359 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
3364 at
= parseType(&ai
);
3366 arg
= new Argument(0, at
, ai
, NULL
);
3369 // Check for " ident;"
3370 else if (token
.value
== TOKidentifier
&& !dltSyntax
)
3372 Token
*t
= peek(&token
);
3373 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
3375 arg
= new Argument(0, NULL
, token
.ident
, NULL
);
3378 if (1 || !global
.params
.useDeprecated
)
3379 error("if (v; e) is deprecated, use if (auto v = e)");
3383 condition
= parseExpression();
3385 ifbody
= parseStatement(PSscope
);
3386 if (token
.value
== TOKelse
)
3391 if (token
.value
== TOKcolon
) {
3392 elsebody
= parseStatement(PSscope
);
3393 } else if (token
.value
== TOKif
) {
3394 elsebody
= parseStatement(0);
3396 error("Expected 'else:' or 'else if', not 'else %s'", token
.toChars());
3401 elsebody
= parseStatement(PSscope
);
3405 s
= new IfStatement(loc
, arg
, condition
, ifbody
, elsebody
);
3410 if (peek(&token
)->value
!= TOKlparen
)
3411 goto Ldeclaration
; // scope used as storage class
3414 if (token
.value
!= TOKidentifier
)
3415 { error("scope identifier expected");
3419 { TOK t
= TOKon_scope_exit
;
3420 Identifier
*id
= token
.ident
;
3423 t
= TOKon_scope_exit
;
3424 else if (id
== Id::failure
)
3425 t
= TOKon_scope_failure
;
3426 else if (id
== Id::success
)
3427 t
= TOKon_scope_success
;
3429 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
3432 Statement
*st
= parseStatement(PScolon
| PScurlyscope
);
3433 s
= new OnScopeStatement(loc
, t
, st
);
3439 condition
= parseDebugCondition();
3444 condition
= parseVersionCondition();
3448 if (dltSyntax
&& token
.value
!= TOKcolon
)
3449 error("expected colon after condition, not '%s'", token
.toChars());
3450 ifbody
= parseStatement(PScolon
/*PSsemi*/);
3452 if (token
.value
== TOKelse
)
3455 elsebody
= parseStatement(PScolon
/*PSsemi*/);
3457 s
= new ConditionalStatement(loc
, condition
, ifbody
, elsebody
);
3461 { Identifier
*ident
;
3462 Expressions
*args
= NULL
;
3467 if (token
.value
!= TOKidentifier
)
3468 { error("pragma(identifier expected");
3471 ident
= token
.ident
;
3473 if (token
.value
== TOKcomma
)
3474 args
= parseArguments(); // pragma(identifier, args...);
3476 check(TOKrparen
); // pragma(identifier);
3477 if (token
.value
== TOKsemicolon
)
3482 body
= parseStatement(PSsemi
| PScolon
);
3483 s
= new PragmaStatement(loc
, ident
, args
, body
);
3488 { Expression
*condition
;
3493 condition
= parseExpression();
3495 body
= parseStatement(PSscope
| PScolon
);
3496 s
= new SwitchStatement(loc
, condition
, body
);
3502 Statements
*statements
;
3503 Array cases
; // array of Expression's
3508 exp
= parseAssignExp();
3510 if (token
.value
!= TOKcomma
)
3516 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3522 statements
= new Statements();
3523 while (token
.value
!= TOKcase
&&
3524 token
.value
!= TOKdefault
&&
3525 token
.value
!= TOKrcurly
)
3527 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3529 s
= new CompoundStatement(loc
, statements
);
3532 s
= new ScopeStatement(loc
, s
);
3534 // Keep cases in order by building the case statements backwards
3535 for (int i
= cases
.dim
; i
; i
--)
3537 exp
= (Expression
*)cases
.data
[i
- 1];
3538 s
= new CaseStatement(loc
, exp
, s
);
3545 Statements
*statements
;
3551 s
= parseStatement(PSsemi
| PScurlyscope
| PScolon
);
3557 statements
= new Statements();
3558 while (token
.value
!= TOKcase
&&
3559 token
.value
!= TOKdefault
&&
3560 token
.value
!= TOKrcurly
)
3562 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
3564 s
= new CompoundStatement(loc
, statements
);
3567 s
= new ScopeStatement(loc
, s
);
3568 s
= new DefaultStatement(loc
, s
);
3576 if (token
.value
== TOKsemicolon
|| token
.value
== TOKendline
)
3579 exp
= parseExpression();
3582 check(TOKsemicolon
, "return statement");
3583 else if (token
.value
!= TOKendline
) {
3584 error("Expected end-of-line after return statement, but found '%s'", token
.toChars());
3587 s
= new ReturnStatement(loc
, exp
);
3592 { Identifier
*ident
;
3595 if (token
.value
== TOKidentifier
)
3596 { ident
= token
.ident
;
3601 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3602 error("expected %s after break, not '%s'", endToken(), token
.toChars());
3606 s
= new BreakStatement(loc
, ident
);
3611 { Identifier
*ident
;
3614 if (token
.value
== TOKidentifier
)
3615 { ident
= token
.ident
;
3620 check(TOKsemicolon
, "continue statement");
3621 s
= new ContinueStatement(loc
, ident
);
3626 { Identifier
*ident
;
3629 if (token
.value
== TOKdefault
)
3632 s
= new GotoDefaultStatement(loc
);
3634 else if (token
.value
== TOKcase
)
3636 Expression
*exp
= NULL
;
3639 if (token
.value
!= TOKsemicolon
)
3640 exp
= parseExpression();
3641 s
= new GotoCaseStatement(loc
, exp
);
3645 if (token
.value
!= TOKidentifier
)
3646 { error("Identifier expected following goto");
3650 { ident
= token
.ident
;
3653 s
= new GotoStatement(loc
, ident
);
3657 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3658 error("expected %s after goto statement, not '%s'", endToken(), token
.toChars());
3662 check(TOKsemicolon
);
3666 case TOKsynchronized
:
3671 if (token
.value
== TOKlparen
)
3674 exp
= parseExpression();
3679 body
= parseStatement(PSscope
);
3680 s
= new SynchronizedStatement(loc
, exp
, body
);
3690 exp
= parseExpression();
3692 body
= parseStatement(PSscope
);
3693 s
= new WithStatement(loc
, exp
, body
);
3699 Array
*catches
= NULL
;
3700 Statement
*finalbody
= NULL
;
3703 body
= parseStatement(PSscope
);
3704 while (token
.value
== TOKcatch
)
3710 Loc loc
= this->loc
;
3713 if (token
.value
== startBlockTok
)
3725 handler
= parseStatement(PScolon
);
3726 c
= new Catch(loc
, t
, id
, handler
);
3728 catches
= new Array();
3732 if (token
.value
== TOKfinally
)
3734 finalbody
= parseStatement(PScolon
);
3738 if (!catches
&& !finalbody
)
3739 error("catch or finally expected following try");
3742 s
= new TryCatchStatement(loc
, body
, catches
);
3744 s
= new TryFinallyStatement(loc
, s
, finalbody
);
3753 exp
= parseExpression();
3754 if (token
.value
!= TOKsemicolon
&& token
.value
!= TOKendline
) {
3755 error("%s expected after throw statement, not '%s'", endToken(), token
.toChars());
3759 s
= new ThrowStatement(loc
, exp
);
3765 s
= parseStatement(PSsemi
| PScurlyscope
);
3766 if (!global
.params
.useDeprecated
)
3767 error("volatile statements deprecated; used synchronized statements instead");
3768 s
= new VolatileStatement(loc
, s
);
3772 { Statements
*statements
;
3778 // Parse the asm block into a sequence of AsmStatements,
3779 // each AsmStatement is one instruction.
3780 // Separate out labels.
3781 // Defer parsing of AsmStatements until semantic processing.
3784 #if GDC_EXTENDED_ASM_SYNTAX
3785 if (token
.value
== TOKlparen
)
3792 check(startBlockTok
);
3794 ptoklist
= &toklist
;
3796 statements
= new Statements();
3799 switch (token
.value
)
3804 // Look ahead to see if it is a label
3806 if (t
->value
== TOKcolon
)
3808 label
= token
.ident
;
3809 labelloc
= this->loc
;
3818 if (toklist
|| label
)
3820 error("asm statements must end in ';'");
3827 if (toklist
|| label
)
3828 { // Create AsmStatement from list of tokens we've saved
3829 s
= new AsmStatement(this->loc
, toklist
);
3831 ptoklist
= &toklist
;
3833 { s
= new LabelStatement(labelloc
, label
, s
);
3836 statements
->push(s
);
3843 error("matching '}' expected, not end of file");
3848 // If the first token is a string or '(', parse as extended asm.
3852 statements
->push(s
);
3855 // ...else, drop through.
3859 *ptoklist
= new Token();
3860 memcpy(*ptoklist
, &token
, sizeof(Token
));
3861 ptoklist
= &(*ptoklist
)->next
;
3869 s
= new CompoundStatement(loc
, statements
);
3875 error("found '%s' instead of statement", token
.toChars());
3879 while (token
.value
!= TOKrcurly
&&
3880 token
.value
!= TOKsemicolon
&&
3881 token
.value
!= TOKeof
)
3883 if (token
.value
== TOKsemicolon
)
3892 Statement
*Parser::parseExtAsm(int expect_rparen
)
3894 Expression
* insnTemplate
;
3895 Expressions
* args
= NULL
;
3896 Array
* argNames
= NULL
;
3897 Expressions
* argConstraints
= NULL
;
3898 int nOutputArgs
= 0;
3899 Expressions
* clobbers
= NULL
;
3900 bool isInputPhase
= false; // Output operands first, then input.
3902 insnTemplate
= parseExpression();
3903 if (token
.value
== TOKrparen
|| token
.value
== TOKsemicolon
)
3907 Expression
* arg
= NULL
;
3908 Identifier
* name
= NULL
;
3909 Expression
* constraint
= NULL
;
3911 switch (token
.value
)
3922 error("unterminated statement");
3926 if (token
.value
== TOKidentifier
)
3932 error("expected identifier after '['");
3936 constraint
= parsePrimaryExp();
3937 if (constraint
->op
!= TOKstring
)
3938 error("expected constant string constraint for operand");
3939 arg
= parseAssignExp();
3942 args
= new Expressions
;
3943 argConstraints
= new Expressions
;
3944 argNames
= new Array
;
3947 argNames
->push(name
);
3948 argConstraints
->push(constraint
);
3952 if (token
.value
== TOKcomma
)
3959 isInputPhase
= true;
3966 Expression
* clobber
;
3968 switch (token
.value
)
3975 error("unterminated statement");
3978 clobber
= parseAssignExp();
3979 if (clobber
->op
!= TOKstring
)
3980 error("expected constant string constraint for clobber name");
3982 clobbers
= new Expressions
;
3983 clobbers
->push(clobber
);
3985 if (token
.value
== TOKcomma
)
3994 check(TOKsemicolon
);
3996 return new ExtAsmStatement(loc
, insnTemplate
, args
, argNames
,
3997 argConstraints
, nOutputArgs
, clobbers
);
4000 void Parser::optionalEndline() {
4001 while (token
.value
== TOKendline
) {
4006 void Parser::check(enum TOK value
)
4011 void Parser::check(Loc loc
, enum TOK value
)
4013 if (token
.value
!= value
)
4014 error(loc
, "found '%s' when expecting '%s'", token
.toChars(), Token::toChars(value
));
4018 void Parser::check(enum TOK value
, char *string
)
4020 if (token
.value
!= value
)
4021 error("found '%s' when expecting '%s' following '%s'",
4022 token
.toChars(), Token::toChars(value
), string
);
4026 char *Parser::endToken()
4031 char *DltParser::endToken()
4036 void Parser::checkLParen() { check(TOKlparen
); }
4037 void Parser::checkRParen() { check(TOKrparen
); }
4039 void DltParser::checkLParen() { }
4040 void DltParser::checkRParen() { }
4042 /************************************
4043 * Determine if the scanner is sitting on the start of a declaration.
4045 * needId 0 no identifier
4046 * 1 identifier optional
4047 * 2 must have identifier
4050 int Parser::isDeclaration(Token
*t
, int needId
, enum TOK endtok
, Token
**pt
)
4054 if ((t
->value
== TOKconst
|| t
->value
== TOKinvariant
) &&
4055 peek(t
)->value
!= TOKlparen
)
4062 if (!isBasicType(&t
))
4064 if (!isDeclarator(&t
, &haveId
, endtok
))
4067 (needId
== 0 && !haveId
) ||
4068 (needId
== 2 && haveId
))
4077 int Parser::isBasicType(Token
**pt
)
4079 // This code parallels parseBasicType()
4093 if (t
->value
== TOKnot
)
4103 if (t
->value
== TOKdot
)
4107 if (t
->value
!= TOKidentifier
)
4110 if (t
->value
!= TOKnot
)
4114 if (t
->value
!= TOKlparen
)
4116 if (!skipParens(t
, &t
))
4128 /* typeof(exp).identifier...
4131 if (t
->value
!= TOKlparen
)
4133 if (!skipParens(t
, &t
))
4139 // const(type) or invariant(type)
4141 if (t
->value
!= TOKlparen
)
4144 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
4159 int Parser::isDeclarator(Token
**pt
, int *haveId
, enum TOK endtok
)
4160 { // This code parallels parseDeclarator()
4164 //printf("Parser::isDeclarator()\n");
4166 if (t
->value
== TOKassign
)
4182 if (t
->value
== TOKrbracket
)
4186 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
4187 { // It's an associative array declaration
4193 // [ expression .. expression ]
4194 if (!isExpression(&t
))
4196 if (t
->value
== TOKslice
)
4198 if (!isExpression(&t
))
4201 if (t
->value
!= TOKrbracket
)
4217 if (t
->value
== TOKrparen
)
4218 return FALSE
; // () is not a declarator
4220 /* Regard ( identifier ) as not a declarator
4221 * BUG: what about ( *identifier ) in
4223 * where f is a class instance with overloaded () ?
4224 * Should we just disallow C-style function pointer declarations?
4226 if (t
->value
== TOKidentifier
)
4227 { Token
*t2
= peek(t
);
4228 if (t2
->value
== TOKrparen
)
4233 if (!isDeclarator(&t
, haveId
, TOKrparen
))
4242 if (!isParameters(&t
))
4257 if (t
->value
== TOKrbracket
)
4261 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
4262 { // It's an associative array declaration
4268 if (!isExpression(&t
))
4270 if (t
->value
!= TOKrbracket
)
4279 if (!isParameters(&t
))
4281 if (t
->value
== TOKconst
|| t
->value
== TOKinvariant
)
4285 // Valid tokens that follow a declaration
4294 // The !parens is to disallow unnecessary parentheses
4295 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
4308 int Parser::isParameters(Token
**pt
)
4309 { // This code parallels parseParameters()
4313 //printf("isParameters()\n");
4314 if (t
->value
!= TOKlparen
)
4318 for (;1; t
= peek(t
))
4341 if (!isBasicType(&t
))
4344 if (t
->value
!= TOKdotdotdot
&&
4345 !isDeclarator(&t
, &tmp
, TOKreserved
))
4347 if (t
->value
== TOKassign
)
4349 if (!isExpression(&t
))
4352 if (t
->value
== TOKdotdotdot
)
4357 if (t
->value
== TOKcomma
)
4365 if (t
->value
!= TOKrparen
)
4372 int Parser::isExpression(Token
**pt
)
4374 // This is supposed to determine if something is an expression.
4375 // What it actually does is scan until a closing right bracket
4383 for (;; t
= peek(t
))
4401 if (brnest
|| panest
)
4415 if (--curlynest
>= 0)
4442 /**********************************************
4444 * instance foo.bar(parameters...)
4446 * if (pt), *pt is set to the token following the closing )
4448 * 1 it's valid instance syntax
4449 * 0 invalid instance syntax
4452 int Parser::isTemplateInstance(Token
*t
, Token
**pt
)
4455 if (t
->value
!= TOKdot
)
4457 if (t
->value
!= TOKidentifier
)
4461 while (t
->value
== TOKdot
)
4464 if (t
->value
!= TOKidentifier
)
4468 if (t
->value
!= TOKlparen
)
4471 // Skip over the template arguments
4480 if (!skipParens(t
, &t
))
4496 if (t
->value
!= TOKcomma
)
4499 if (t
->value
!= TOKrparen
)
4510 /*******************************************
4511 * Skip parens, brackets.
4515 * *pt is set to closing token, which is ')' on success
4518 * 0 some parsing error
4521 int Parser::skipParens(Token
*t
, Token
**pt
)
4560 /********************************* Expression Parser ***************************/
4562 Expression
*Parser::parsePrimaryExp()
4567 Loc loc
= this->loc
;
4569 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4570 switch (token
.value
)
4575 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
4576 { // identifier!(template-argument-list)
4577 TemplateInstance
*tempinst
;
4579 tempinst
= new TemplateInstance(loc
, id
);
4581 tempinst
->tiargs
= parseTemplateArgumentList();
4582 e
= new ScopeExp(loc
, tempinst
);
4585 e
= new IdentifierExp(loc
, id
);
4590 error("'$' is valid only inside [] of index or slice");
4591 e
= new DollarExp(loc
);
4596 // Signal global scope '.' operator with "" identifier
4597 e
= new IdentifierExp(loc
, Id::empty
);
4601 e
= new ThisExp(loc
);
4606 e
= new SuperExp(loc
);
4611 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
4616 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
4621 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
4626 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
4631 e
= new RealExp(loc
, token
.float80value
, Type::tfloat32
);
4636 e
= new RealExp(loc
, token
.float80value
, Type::tfloat64
);
4641 e
= new RealExp(loc
, token
.float80value
, Type::tfloat80
);
4645 case TOKimaginary32v
:
4646 e
= new RealExp(loc
, token
.float80value
, Type::timaginary32
);
4650 case TOKimaginary64v
:
4651 e
= new RealExp(loc
, token
.float80value
, Type::timaginary64
);
4655 case TOKimaginary80v
:
4656 e
= new RealExp(loc
, token
.float80value
, Type::timaginary80
);
4661 e
= new NullExp(loc
);
4662 ((NullExp
*) e
)->dUnchecked
= !dltSyntax
;
4667 { char *s
= loc
.filename
? loc
.filename
: mod
->ident
->toChars();
4668 e
= new StringExp(loc
, s
, strlen(s
), 0);
4674 e
= new IntegerExp(loc
, loc
.linnum
, Type::tint32
);
4679 e
= new IntegerExp(loc
, 1, Type::tbool
);
4684 e
= new IntegerExp(loc
, 0, Type::tbool
);
4689 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tchar
);
4694 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::twchar
);
4699 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
4706 unsigned char postfix
;
4708 // cat adjacent strings
4711 postfix
= token
.postfix
;
4715 if (token
.value
== TOKstring
)
4721 { if (token
.postfix
!= postfix
)
4722 error("mismatched string literal postfixes '%c' and '%c'", postfix
, token
.postfix
);
4723 postfix
= token
.postfix
;
4729 s2
= (unsigned char *)mem
.malloc((len
+ 1) * sizeof(unsigned char));
4730 memcpy(s2
, s
, len1
* sizeof(unsigned char));
4731 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(unsigned char));
4737 e
= new StringExp(loc
, s
, len
, postfix
);
4741 CASE_BASIC_TYPES_X(t
):
4744 check(TOKdot
, t
->toChars());
4745 if (token
.value
!= TOKidentifier
)
4746 { error("found '%s' when expecting identifier following '%s.'", token
.toChars(), t
->toChars());
4749 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
4756 if (token
.value
== TOKdot
)
4758 e
= new TypeExp(loc
, t
);
4766 check(TOKlparen
, "typeid");
4767 t
= parseType(); // ( type )
4769 e
= new TypeidExp(loc
, t
);
4774 { /* __traits(identifier, args...)
4777 Objects
*args
= NULL
;
4781 if (token
.value
!= TOKidentifier
)
4782 { error("__traits(identifier, args...) expected");
4785 ident
= token
.ident
;
4787 if (token
.value
== TOKcomma
)
4788 args
= parseTemplateArgumentList2(); // __traits(identifier, args...)
4790 check(TOKrparen
); // __traits(identifier)
4792 e
= new TraitsExp(loc
, ident
, args
);
4798 Identifier
*ident
= NULL
;
4800 enum TOK tok
= TOKreserved
;
4801 enum TOK tok2
= TOKreserved
;
4802 TemplateParameters
*tpl
= NULL
;
4803 Loc loc
= this->loc
;
4806 if (token
.value
== TOKlparen
)
4809 targ
= parseType(&ident
);
4810 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
4814 if (tok
== TOKequal
&&
4815 (token
.value
== TOKtypedef
||
4816 token
.value
== TOKstruct
||
4817 token
.value
== TOKunion
||
4818 token
.value
== TOKclass
||
4819 token
.value
== TOKsuper
||
4820 token
.value
== TOKenum
||
4821 token
.value
== TOKinterface
||
4822 token
.value
== TOKconst
&& peek(&token
)->value
== TOKrparen
||
4823 token
.value
== TOKinvariant
&& peek(&token
)->value
== TOKrparen
||
4824 token
.value
== TOKfunction
||
4825 token
.value
== TOKdelegate
||
4826 token
.value
== TOKreturn
))
4833 tspec
= parseType();
4838 if (token
.value
== TOKcomma
)
4839 tpl
= parseTemplateParameterList(1);
4841 { tpl
= new TemplateParameters();
4844 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, ident
, NULL
, NULL
);
4851 { error("(type identifier : specialization) expected following is");
4854 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
4859 { Expression
*msg
= NULL
;
4864 e
= parseAssignExp();
4865 if (token
.value
== (dltSyntax
? TOKelse
: TOKcomma
))
4867 msg
= parseAssignExp();
4868 } else if (token
.value
== TOKcomma
)
4869 error("Suspicious comma after assert; try 'else' instead");
4872 e
= new AssertExp(loc
, e
, msg
);
4879 check(TOKlparen
, "mixin");
4880 e
= parseAssignExp();
4882 e
= new CompileExp(loc
, e
);
4889 check(TOKlparen
, "import");
4890 e
= parseAssignExp();
4892 e
= new FileExp(loc
, e
);
4897 if (peekPastParen(&token
)->value
== TOKlcurly
)
4898 { // (arguments) { statements... }
4904 e
= parseExpression();
4905 check(loc
, TOKrparen
);
4909 { /* Parse array literals and associative array literals:
4910 * [ value, value, value ... ]
4911 * [ key:value, key:value, key:value ... ]
4913 Expressions
*values
= new Expressions();
4914 Expressions
*keys
= NULL
;
4917 if (token
.value
!= TOKrbracket
)
4921 Expression
*e
= parseAssignExp();
4922 if (token
.value
== TOKcolon
&& (keys
|| values
->dim
== 0))
4925 keys
= new Expressions();
4927 e
= parseAssignExp();
4930 { error("'key:value' expected for associative array literal");
4935 if (token
.value
== TOKrbracket
)
4943 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
4945 e
= new ArrayLiteralExp(loc
, values
);
4950 // { statements... }
4960 /* function type(parameters) { body }
4961 * delegate type(parameters) { body }
4962 * (parameters) { body }
4965 Arguments
*arguments
;
4967 FuncLiteralDeclaration
*fd
;
4969 bool isnothrow
= false;
4970 bool ispure
= false;
4972 if (token
.value
== startBlockTok
)
4976 arguments
= new Arguments();
4980 if (token
.value
== TOKlparen
)
4984 t
= parseBasicType();
4985 t
= parseBasicType2(t
); // function return type
4987 arguments
= parseParameters(&varargs
);
4990 if (token
.value
== TOKpure
)
4992 else if (token
.value
== TOKnothrow
)
4999 TypeFunction
*tf
= new TypeFunction(arguments
, t
, varargs
, linkage
);
5000 tf
->ispure
= ispure
;
5001 tf
->isnothrow
= isnothrow
;
5002 fd
= new FuncLiteralDeclaration(loc
, 0, tf
, save
, NULL
);
5007 indent
--; // This colon doesn't start a new indent level
5008 fd
->fbody
= new ReturnStatement(loc
, parseAssignExp());
5015 e
= new FuncExp(loc
, fd
);
5020 error("expression expected, not '%s'", token
.toChars());
5022 // Anything for e, as long as it's not NULL
5023 e
= new IntegerExp(loc
, 0, Type::tint32
);
5027 return parsePostExp(e
);
5030 Expression
*Parser::parsePostExp(Expression
*e
)
5037 switch (token
.value
)
5041 if (token
.value
== TOKidentifier
)
5042 { Identifier
*id
= token
.ident
;
5045 if (token
.value
== TOKnot
&& peek(&token
)->value
== TOKlparen
)
5046 { // identifier!(template-argument-list)
5047 TemplateInstance
*tempinst
;
5049 tempinst
= new TemplateInstance(loc
, id
);
5051 tempinst
->tiargs
= parseTemplateArgumentList();
5052 e
= new DotTemplateInstanceExp(loc
, e
, tempinst
);
5055 e
= new DotIdExp(loc
, e
, id
);
5058 else if (token
.value
== TOKnew
)
5064 error("identifier expected following '.', not '%s'", token
.toChars());
5068 e
= new PostExp(TOKplusplus
, loc
, e
);
5072 e
= new PostExp(TOKminusminus
, loc
, e
);
5076 e
= new CallExp(loc
, e
, parseArguments());
5080 { // array dereferences:
5083 // array[lwr .. upr]
5089 if (token
.value
== TOKrbracket
)
5091 e
= new SliceExp(loc
, e
, NULL
, NULL
);
5096 index
= parseAssignExp();
5097 if (token
.value
== TOKslice
)
5098 { // array[lwr .. upr]
5100 upr
= parseAssignExp();
5101 e
= new SliceExp(loc
, e
, index
, upr
);
5104 { // array[index, i2, i3, i4, ...]
5105 Expressions
*arguments
= new Expressions();
5106 arguments
->push(index
);
5107 if (token
.value
== TOKcomma
)
5113 arg
= parseAssignExp();
5114 arguments
->push(arg
);
5115 if (token
.value
== TOKrbracket
)
5120 e
= new ArrayExp(loc
, e
, arguments
);
5135 Expression
*Parser::parseUnaryExp()
5137 Loc loc
= this->loc
;
5139 switch (token
.value
)
5143 e
= parseUnaryExp();
5144 e
= new AddrExp(loc
, e
);
5149 e
= parseUnaryExp();
5150 e
= new AddAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
5155 e
= parseUnaryExp();
5156 e
= new MinAssignExp(loc
, e
, new IntegerExp(loc
, 1, Type::tint32
));
5161 e
= parseUnaryExp();
5162 e
= new PtrExp(loc
, e
);
5167 e
= parseUnaryExp();
5168 e
= new NegExp(loc
, e
);
5173 e
= parseUnaryExp();
5174 e
= new UAddExp(loc
, e
);
5179 e
= parseUnaryExp();
5180 e
= new NotExp(loc
, e
);
5185 e
= parseUnaryExp();
5186 e
= new ComExp(loc
, e
);
5191 e
= parseUnaryExp();
5192 e
= new DeleteExp(loc
, e
);
5196 e
= parseNewExp(NULL
);
5199 case TOKcast
: // cast(type) expression
5204 /* Look for cast(const) and cast(invariant)
5206 if ((token
.value
== TOKconst
|| token
.value
== TOKinvariant
) &&
5207 peek(&token
)->value
== TOKrparen
)
5208 { enum TOK tok
= token
.value
;
5211 e
= parseUnaryExp();
5212 e
= new CastExp(loc
, e
, tok
);
5216 t
= parseType(); // ( type )
5218 e
= parseUnaryExp();
5219 e
= new CastExp(loc
, e
, t
);
5230 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
5232 tk
= peek(tk
); // skip over right parenthesis
5252 case TOKimaginary32v
:
5253 case TOKimaginary64v
:
5254 case TOKimaginary80v
:
5274 CASE_BASIC_TYPES
: // (type)int.size
5283 if (token
.value
== TOKdot
)
5286 if (token
.value
!= TOKidentifier
)
5287 { error("Identifier expected following (type).");
5290 e
= new TypeDotIdExp(loc
, t
, token
.ident
);
5292 e
= parsePostExp(e
);
5296 e
= parseUnaryExp();
5297 e
= new CastExp(loc
, e
, t
);
5298 error("C style cast illegal, use %s", e
->toChars());
5305 e
= parsePrimaryExp();
5309 e
= parsePrimaryExp();
5316 Expression
*Parser::parseMulExp()
5319 Loc loc
= this->loc
;
5321 e
= parseUnaryExp();
5324 switch (token
.value
)
5326 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
5327 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
5328 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
5338 Expression
*Parser::parseAddExp()
5341 Loc loc
= this->loc
;
5346 switch (token
.value
)
5348 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
5349 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
5350 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
5360 Expression
*Parser::parseShiftExp()
5363 Loc loc
= this->loc
;
5368 switch (token
.value
)
5370 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
5371 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
5372 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
5382 Expression
*Parser::parseRelExp()
5386 Loc loc
= this->loc
;
5388 e
= parseShiftExp();
5391 switch (token
.value
)
5407 e2
= parseShiftExp();
5408 e
= new CmpExp(op
, loc
, e
, e2
);
5413 e2
= parseShiftExp();
5414 e
= new InExp(loc
, e
, e2
);
5425 Expression
*Parser::parseEqualExp()
5429 Loc loc
= this->loc
;
5433 { enum TOK value
= token
.value
;
5441 e
= new EqualExp(value
, loc
, e
, e2
);
5445 error("'===' is no longer legal, use 'is' instead");
5448 case TOKnotidentity
:
5449 error("'!==' is no longer legal, use '!is' instead");
5453 value
= TOKidentity
;
5458 error("next: %s", t
->toChars());
5459 if (t
->value
== TOKnot
)
5462 value
= TOKnotidentity
;
5469 // Attempt to identify '!is'
5471 if (t
->value
!= TOKis
)
5474 value
= TOKnotidentity
;
5480 e
= new IdentityExp(value
, loc
, e
, e2
);
5491 Expression
*Parser::parseCmpExp()
5495 Loc loc
= this->loc
;
5497 e
= parseShiftExp();
5498 enum TOK op
= token
.value
;
5505 e2
= parseShiftExp();
5506 e
= new EqualExp(op
, loc
, e
, e2
);
5514 if (t
->value
== TOKnot
)
5517 op
= TOKnotidentity
;
5524 // Attempt to identify '!is'
5526 if (t
->value
!= TOKis
)
5529 op
= TOKnotidentity
;
5534 e2
= parseShiftExp();
5535 e
= new IdentityExp(op
, loc
, e
, e2
);
5551 e2
= parseShiftExp();
5552 e
= new CmpExp(op
, loc
, e
, e2
);
5557 e2
= parseShiftExp();
5558 e
= new InExp(loc
, e
, e2
);
5567 Expression
*Parser::parseAndExp()
5570 Loc loc
= this->loc
;
5572 if (global
.params
.Dversion
== 1)
5574 e
= parseEqualExp();
5575 while (token
.value
== TOKand
)
5578 e2
= parseEqualExp();
5579 e
= new AndExp(loc
,e
,e2
);
5586 while (token
.value
== TOKand
)
5590 e
= new AndExp(loc
,e
,e2
);
5597 Expression
*Parser::parseXorExp()
5600 Loc loc
= this->loc
;
5603 while (token
.value
== TOKxor
)
5607 e
= new XorExp(loc
, e
, e2
);
5612 Expression
*Parser::parseOrExp()
5615 Loc loc
= this->loc
;
5618 while (token
.value
== TOKor
)
5622 e
= new OrExp(loc
, e
, e2
);
5627 Expression
*Parser::parseAndAndExp()
5630 Loc loc
= this->loc
;
5633 while (token
.value
== TOKandand
)
5637 e
= new AndAndExp(loc
, e
, e2
);
5642 Expression
*Parser::parseOrOrExp()
5645 Loc loc
= this->loc
;
5647 e
= parseAndAndExp();
5648 while (token
.value
== TOKoror
)
5651 e2
= parseAndAndExp();
5652 e
= new OrOrExp(loc
, e
, e2
);
5657 Expression
*Parser::parseCondExp()
5661 Loc loc
= this->loc
;
5664 if (token
.value
== TOKquestion
)
5667 e1
= parseExpression();
5669 e2
= parseCondExp();
5670 e
= new CondExp(loc
, e
, e1
, e2
);
5675 Expression
*DltParser::parseCondExp()
5679 Loc loc
= this->loc
;
5682 if (token
.value
== TOKif
)
5685 e1
= parseExpression();
5687 e2
= parseCondExp();
5688 e
= new CondExp(loc
, e1
, e
, e2
);
5693 Expression
*Parser::parseAssignExp()
5702 switch (token
.value
)
5704 #define X(tok,ector) \
5705 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5707 X(TOKassign
, AssignExp
);
5708 X(TOKaddass
, AddAssignExp
);
5709 X(TOKminass
, MinAssignExp
);
5710 X(TOKmulass
, MulAssignExp
);
5711 X(TOKdivass
, DivAssignExp
);
5712 X(TOKmodass
, ModAssignExp
);
5713 X(TOKandass
, AndAssignExp
);
5714 X(TOKorass
, OrAssignExp
);
5715 X(TOKxorass
, XorAssignExp
);
5716 X(TOKshlass
, ShlAssignExp
);
5717 X(TOKshrass
, ShrAssignExp
);
5718 X(TOKushrass
, UshrAssignExp
);
5719 X(TOKcatass
, CatAssignExp
);
5730 Expression
*Parser::parseExpression()
5733 Loc loc
= this->loc
;
5735 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5736 e
= parseAssignExp();
5737 while (token
.value
== TOKcomma
)
5740 e2
= parseAssignExp();
5741 e
= new CommaExp(loc
, e
, e2
);
5748 /*************************
5749 * Collect argument list.
5750 * Assume current token is '(' or '['.
5753 Expressions
*Parser::parseArguments()
5755 Expressions
*arguments
;
5759 arguments
= new Expressions();
5760 if (token
.value
== TOKlbracket
)
5761 endtok
= TOKrbracket
;
5767 if (token
.value
!= endtok
)
5771 arg
= parseAssignExp();
5772 arguments
->push(arg
);
5773 if (token
.value
== endtok
)
5783 /*******************************************
5786 Expression
*Parser::parseNewExp(Expression
*thisexp
)
5788 Expressions
*newargs
;
5789 Expressions
*arguments
= NULL
;
5791 Loc loc
= this->loc
;
5795 if (token
.value
== TOKlparen
)
5797 newargs
= parseArguments();
5800 // An anonymous nested class starts with "class"
5801 if (token
.value
== TOKclass
)
5806 error("no anonymous classes in Delight");
5808 if (token
.value
== TOKlparen
)
5809 arguments
= parseArguments();
5811 BaseClasses
*baseclasses
= NULL
;
5812 if (token
.value
!= TOKlcurly
)
5813 baseclasses
= parseBaseClasses();
5815 Identifier
*id
= NULL
;
5816 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
);
5818 if (token
.value
!= startBlockTok
)
5819 { error("{ members } expected for anonymous class");
5825 Array
*decl
= parseDeclDefs(0);
5826 if (token
.value
!= TOKrcurly
)
5827 error("class member expected");
5832 e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
5837 t
= parseBasicType();
5838 t
= parseBasicType2(t
);
5839 if (t
->ty
== Taarray
)
5840 { TypeAArray
*taa
= (TypeAArray
*)t
;
5841 Type
*index
= taa
->index
;
5843 Expression
*e
= index
->toExpression();
5845 { arguments
= new Expressions();
5847 t
= new TypeDArray(taa
->next
);
5851 error("need size of rightmost array, not type %s", index
->toChars());
5852 return new NullExp(loc
);
5855 else if (t
->ty
== Tsarray
)
5857 TypeSArray
*tsa
= (TypeSArray
*)t
;
5858 Expression
*e
= tsa
->dim
;
5860 arguments
= new Expressions();
5862 t
= new TypeDArray(tsa
->next
);
5864 else if (token
.value
== TOKlparen
)
5866 arguments
= parseArguments();
5868 e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
5872 /**********************************************
5875 void Parser::addComment(Dsymbol
*s
, unsigned char *blockComment
)
5877 s
->addComment(combineComments(blockComment
, token
.lineComment
));
5881 /********************************* ***************************/