2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
11 // This is the D parser
13 #include "root/dsystem.h" // strlen(),memcpy()
14 #include "root/rmem.h"
24 #include "staticassert.h"
25 #include "expression.h"
26 #include "statement.h"
30 #include "declaration.h"
31 #include "aggregate.h"
35 #include "aliasthis.h"
39 Expression
*typeToExpression(Type
*t
);
41 // Support C cast syntax:
45 // Support postfix C array declarations, such as
49 Parser::Parser(Module
*module
, const utf8_t
*base
, size_t length
, bool doDocComment
)
50 : Lexer(module
? module
->srcfile
->toChars() : NULL
, base
, 0, length
, doDocComment
, false)
52 //printf("Parser::Parser()\n");
58 lookingForElse
= Loc();
59 //nextToken(); // start up the scanner
62 /*********************
63 * Use this constructor for string mixins.
65 * loc location in source file of mixin
67 Parser::Parser(Loc loc
, Module
*module
, const utf8_t
*base
, size_t length
, bool doDocComment
)
68 : Lexer(module
? module
->srcfile
->toChars() : NULL
, base
, 0, length
, doDocComment
, false)
70 //printf("Parser::Parser()\n");
75 /* Create a pseudo-filename for the mixin string, as it may not even exist
78 char *filename
= (char *)mem
.xmalloc(strlen(loc
.filename
) + 7 + sizeof(loc
.linnum
) * 3 + 1);
79 sprintf(filename
, "%s-mixin-%d", loc
.filename
, (int)loc
.linnum
);
80 scanloc
.filename
= filename
;
88 lookingForElse
= Loc();
89 //nextToken(); // start up the scanner
92 Dsymbols
*Parser::parseModule()
94 const utf8_t
*comment
= token
.blockComment
;
95 bool isdeprecated
= false;
96 Expression
*msg
= NULL
;
97 Expressions
*udas
= NULL
;
101 if (skipAttributes(&token
, &tk
) && tk
->value
== TOKmodule
)
103 while (token
.value
!= TOKmodule
)
109 // deprecated (...) module ...
112 error("there is only one deprecation attribute allowed for module declaration");
119 if (token
.value
== TOKlparen
)
122 msg
= parseAssignExp();
129 Expressions
*exps
= NULL
;
130 StorageClass stc
= parseAttribute(&exps
);
132 if (stc
== STCproperty
|| stc
== STCnogc
|| stc
== STCdisable
||
133 stc
== STCsafe
|| stc
== STCtrusted
|| stc
== STCsystem
)
135 error("@%s attribute for module declaration is not supported", token
.toChars());
139 udas
= UserAttributeDeclaration::concat(udas
, exps
);
147 error("`module` expected instead of %s", token
.toChars());
157 Dsymbols
*a
= new Dsymbols();
158 UserAttributeDeclaration
*udad
= new UserAttributeDeclaration(udas
, a
);
159 mod
->userAttribDecl
= udad
;
162 // ModuleDeclation leads off
163 if (token
.value
== TOKmodule
)
168 if (token
.value
!= TOKidentifier
)
170 error("identifier expected following module");
175 Identifiers
*a
= NULL
;
179 while (nextToken() == TOKdot
)
182 a
= new Identifiers();
185 if (token
.value
!= TOKidentifier
)
187 error("identifier expected following package");
193 md
= new ModuleDeclaration(loc
, a
, id
);
194 md
->isdeprecated
= isdeprecated
;
197 if (token
.value
!= TOKsemicolon
)
198 error("`;` expected following module declaration instead of %s", token
.toChars());
200 addComment(mod
, comment
);
204 decldefs
= parseDeclDefs(0);
205 if (token
.value
!= TOKeof
)
207 error(token
.loc
, "unrecognized declaration");
213 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
216 return new Dsymbols();
219 static StorageClass
parseDeprecatedAttribute(Parser
*p
, Expression
**msg
)
221 if (p
->peekNext() != TOKlparen
)
222 return STCdeprecated
;
226 Expression
*e
= p
->parseAssignExp();
230 p
->error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`",
231 (*msg
)->toChars(), e
->toChars());
237 struct PrefixAttributes
239 StorageClass storageClass
;
246 const utf8_t
*comment
;
249 : storageClass(STCundefined
),
252 protection(Prot::undefined
),
261 Dsymbols
*Parser::parseDeclDefs(int once
, Dsymbol
**pLastDecl
, PrefixAttributes
*pAttrs
)
263 Dsymbol
*lastDecl
= NULL
; // used to link unittest to its previous declaration
265 pLastDecl
= &lastDecl
;
267 LINK linksave
= linkage
; // save global state
269 //printf("Parser::parseDeclDefs()\n");
270 Dsymbols
*decldefs
= new Dsymbols();
277 PrefixAttributes attrs
;
278 if (!once
|| !pAttrs
)
281 pAttrs
->comment
= token
.blockComment
;
285 Condition
*condition
;
293 /* Determine if this is a manifest constant declaration,
294 * or a conventional enum.
296 Token
*t
= peek(&token
);
297 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
299 else if (t
->value
!= TOKidentifier
)
304 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
305 t
->value
== TOKsemicolon
)
319 s
= (Dsymbol
*)parseTemplateDeclaration();
331 check(TOKlparen
, "mixin");
332 Expression
*e
= parseAssignExp();
335 s
= new CompileDeclaration(loc
, e
);
341 s
= (Dsymbol
*)parseTemplateDeclaration(true);
351 case TOKwchar
: case TOKdchar
:
352 case TOKbool
: case TOKchar
:
353 case TOKint8
: case TOKuns8
:
354 case TOKint16
: case TOKuns16
:
355 case TOKint32
: case TOKuns32
:
356 case TOKint64
: case TOKuns64
:
357 case TOKint128
: case TOKuns128
:
358 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
359 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
360 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
374 a
= parseDeclarations(false, pAttrs
, pAttrs
->comment
);
376 *pLastDecl
= (*a
)[a
->length
-1];
380 if (peekNext() == TOKdot
)
383 s
= parseCtor(pAttrs
);
387 s
= parseDtor(pAttrs
);
392 Token
*t
= peek(&token
);
393 if (t
->value
== TOKlparen
|| t
->value
== TOKlcurly
)
395 // invariant { statements... }
396 // invariant() { statements... }
397 // invariant (expression);
398 s
= parseInvariant(pAttrs
);
402 error("invariant body expected, not `%s`", token
.toChars());
409 if (global
.params
.useUnitTests
|| global
.params
.doDocComments
|| global
.params
.doHdrGeneration
)
411 s
= parseUnitTest(pAttrs
);
413 (*pLastDecl
)->ddocUnittest
= (UnitTestDeclaration
*)s
;
417 // Skip over unittest block by counting { }
437 error(loc
, "closing } of unittest not found before end of file");
445 // Workaround 14894. Add an empty unittest declaration to keep
446 // the number of symbols in this scope independent of -unittest.
447 s
= new UnitTestDeclaration(loc
, token
.loc
, STCundefined
, NULL
);
452 s
= parseNew(pAttrs
);
456 s
= parseDelete(pAttrs
);
461 error("declaration expected, not `%s`",token
.toChars());
467 error("declaration expected, not `%s`", token
.toChars());
472 TOK next
= peekNext();
474 s
= parseStaticCtor(pAttrs
);
475 else if (next
== TOKtilde
)
476 s
= parseStaticDtor(pAttrs
);
477 else if (next
== TOKassert
)
478 s
= parseStaticAssert();
479 else if (next
== TOKif
)
481 condition
= parseStaticIfCondition();
483 if (token
.value
== TOKcolon
)
484 athen
= parseBlock(pLastDecl
);
487 Loc lookingForElseSave
= lookingForElse
;
488 lookingForElse
= token
.loc
;
489 athen
= parseBlock(pLastDecl
);
490 lookingForElse
= lookingForElseSave
;
492 Dsymbols
*aelse
= NULL
;
493 if (token
.value
== TOKelse
)
495 Loc elseloc
= token
.loc
;
497 aelse
= parseBlock(pLastDecl
);
498 checkDanglingElse(elseloc
);
500 s
= new StaticIfDeclaration(condition
, athen
, aelse
);
502 else if (next
== TOKimport
)
507 else if (next
== TOKforeach
|| next
== TOKforeach_reverse
)
509 s
= parseForeachStaticDecl(token
.loc
, pLastDecl
);
520 if (peekNext() == TOKlparen
)
526 if (peekNext() == TOKlparen
)
533 TOK next
= peekNext();
534 if (next
== TOKlparen
)
536 if (next
== TOKstatic
)
538 TOK next2
= peekNext2();
539 if (next2
== TOKthis
)
541 s
= parseSharedStaticCtor(pAttrs
);
544 if (next2
== TOKtilde
)
546 s
= parseSharedStaticDtor(pAttrs
);
555 if (peekNext() == TOKlparen
)
560 case TOKfinal
: stc
= STCfinal
; goto Lstc
;
561 case TOKauto
: stc
= STCauto
; goto Lstc
;
562 case TOKscope
: stc
= STCscope
; goto Lstc
;
563 case TOKoverride
: stc
= STCoverride
; goto Lstc
;
564 case TOKabstract
: stc
= STCabstract
; goto Lstc
;
565 case TOKsynchronized
: stc
= STCsynchronized
; goto Lstc
;
566 case TOKnothrow
: stc
= STCnothrow
; goto Lstc
;
567 case TOKpure
: stc
= STCpure
; goto Lstc
;
568 case TOKref
: stc
= STCref
; goto Lstc
;
569 case TOKgshared
: stc
= STCgshared
; goto Lstc
;
570 //case TOKmanifest: stc = STCmanifest; goto Lstc;
573 Expressions
*exps
= NULL
;
574 stc
= parseAttribute(&exps
);
576 goto Lstc
; // it's a predefined attribute
577 // no redundant/conflicting check for UDAs
578 pAttrs
->udas
= UserAttributeDeclaration::concat(pAttrs
->udas
, exps
);
582 pAttrs
->storageClass
= appendStorageClass(pAttrs
->storageClass
, stc
);
588 /* Look for auto initializers:
589 * storage_class identifier = initializer;
590 * storage_class identifier(...) = initializer;
592 if (token
.value
== TOKidentifier
&&
593 skipParensIf(peek(&token
), &tk
) &&
594 tk
->value
== TOKassign
)
596 a
= parseAutoDeclarations(pAttrs
->storageClass
, pAttrs
->comment
);
597 pAttrs
->storageClass
= STCundefined
;
599 *pLastDecl
= (*a
)[a
->length
-1];
602 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
608 /* Look for return type inference for template functions.
610 if (token
.value
== TOKidentifier
&& skipParens(peek(&token
), &tk
) && skipAttributes(tk
, &tk
) &&
611 (tk
->value
== TOKlparen
|| tk
->value
== TOKlcurly
|| tk
->value
== TOKin
||
612 tk
->value
== TOKout
|| tk
->value
== TOKdo
||
613 (tk
->value
== TOKidentifier
&& tk
->ident
== Id::_body
))
616 a
= parseDeclarations(true, pAttrs
, pAttrs
->comment
);
618 *pLastDecl
= (*a
)[a
->length
-1];
621 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
627 a
= parseBlock(pLastDecl
, pAttrs
);
628 if (pAttrs
->storageClass
!= STCundefined
)
630 s
= new StorageClassDeclaration(pAttrs
->storageClass
, a
);
631 pAttrs
->storageClass
= STCundefined
;
640 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
647 if (StorageClass _stc
= parseDeprecatedAttribute(this, &pAttrs
->depmsg
))
652 a
= parseBlock(pLastDecl
, pAttrs
);
655 s
= new DeprecatedDeclaration(pAttrs
->depmsg
, a
);
656 pAttrs
->depmsg
= NULL
;
663 if (peekNext() == TOKrbracket
)
664 error("empty attribute list is not allowed");
665 error("use @(attributes) instead of [attributes]");
666 Expressions
*exps
= parseArguments();
667 // no redundant/conflicting check for UDAs
669 pAttrs
->udas
= UserAttributeDeclaration::concat(pAttrs
->udas
, exps
);
670 a
= parseBlock(pLastDecl
, pAttrs
);
673 s
= new UserAttributeDeclaration(pAttrs
->udas
, a
);
681 if (peek(&token
)->value
!= TOKlparen
)
687 Loc linkLoc
= token
.loc
;
688 Identifiers
*idents
= NULL
;
689 CPPMANGLE cppmangle
= CPPMANGLEdefault
;
690 bool cppMangleOnly
= false;
691 LINK link
= parseLinkage(&idents
, &cppmangle
, &cppMangleOnly
);
692 if (pAttrs
->link
!= LINKdefault
)
694 if (pAttrs
->link
!= link
)
696 error("conflicting linkage extern (%s) and extern (%s)",
697 linkageToChars(pAttrs
->link
), linkageToChars(link
));
702 // extern(C++, foo) extern(C++, bar) void foo();
703 // to be equivalent with:
704 // extern(C++, foo.bar) void foo();
707 error("redundant linkage extern (%s)", linkageToChars(pAttrs
->link
));
710 this->linkage
= link
;
711 a
= parseBlock(pLastDecl
, pAttrs
);
714 assert(link
== LINKcpp
);
715 assert(idents
->length
);
716 for (size_t i
= idents
->length
; i
;)
718 Identifier
*id
= (*idents
)[--i
];
724 s
= new Nspace(linkLoc
, id
, a
, cppMangleOnly
);
727 pAttrs
->link
= LINKdefault
;
729 else if (pAttrs
->link
!= LINKdefault
)
731 s
= new LinkDeclaration(pAttrs
->link
, a
);
732 pAttrs
->link
= LINKdefault
;
734 else if (cppmangle
!= CPPMANGLEdefault
)
736 assert(link
== LINKcpp
);
737 s
= new CPPMangleDeclaration(cppmangle
, a
);
742 case TOKprivate
: prot
= Prot::private_
; goto Lprot
;
743 case TOKpackage
: prot
= Prot::package_
; goto Lprot
;
744 case TOKprotected
: prot
= Prot::protected_
; goto Lprot
;
745 case TOKpublic
: prot
= Prot::public_
; goto Lprot
;
746 case TOKexport
: prot
= Prot::export_
; goto Lprot
;
749 if (pAttrs
->protection
.kind
!= Prot::undefined
)
751 if (pAttrs
->protection
.kind
!= prot
)
752 error("conflicting protection attribute `%s` and `%s`",
753 protectionToChars(pAttrs
->protection
.kind
), protectionToChars(prot
));
755 error("redundant protection attribute `%s`", protectionToChars(prot
));
757 pAttrs
->protection
.kind
= prot
;
761 // optional qualified package identifier to bind
763 Identifiers
*pkg_prot_idents
= NULL
;
764 if (pAttrs
->protection
.kind
== Prot::package_
&& token
.value
== TOKlparen
)
766 pkg_prot_idents
= parseQualifiedIdentifier("protection package");
772 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
779 Loc attrloc
= token
.loc
;
780 a
= parseBlock(pLastDecl
, pAttrs
);
781 if (pAttrs
->protection
.kind
!= Prot::undefined
)
783 if (pAttrs
->protection
.kind
== Prot::package_
&& pkg_prot_idents
)
784 s
= new ProtDeclaration(attrloc
, pkg_prot_idents
, a
);
786 s
= new ProtDeclaration(attrloc
, pAttrs
->protection
, a
);
788 pAttrs
->protection
= Prot(Prot::undefined
);
795 const Loc attrLoc
= token
.loc
;
799 Expression
*e
= NULL
; // default
800 if (token
.value
== TOKlparen
)
803 e
= parseAssignExp();
807 if (pAttrs
->setAlignment
)
813 buf1
.printf("(%s)", e
->toChars());
814 s1
= buf1
.peekChars();
816 error("redundant alignment attribute align%s", s1
);
819 pAttrs
->setAlignment
= true;
821 a
= parseBlock(pLastDecl
, pAttrs
);
822 if (pAttrs
->setAlignment
)
824 s
= new AlignDeclaration(attrLoc
, pAttrs
->ealign
, a
);
825 pAttrs
->setAlignment
= false;
826 pAttrs
->ealign
= NULL
;
833 Expressions
*args
= NULL
;
838 if (token
.value
!= TOKidentifier
)
840 error("pragma(identifier) expected");
843 Identifier
*ident
= token
.ident
;
845 if (token
.value
== TOKcomma
&& peekNext() != TOKrparen
)
846 args
= parseArguments(); // pragma(identifier, args...)
848 check(TOKrparen
); // pragma(identifier)
851 if (token
.value
== TOKsemicolon
)
853 /* Bugzilla 2354: Accept single semicolon as an empty
854 * DeclarationBlock following attribute.
856 * Attribute DeclarationBlock
863 a2
= parseBlock(pLastDecl
);
864 s
= new PragmaDeclaration(loc
, ident
, args
, a2
);
870 if (token
.value
== TOKassign
)
873 if (token
.value
== TOKidentifier
)
874 s
= new DebugSymbol(token
.loc
, token
.ident
);
875 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
876 s
= new DebugSymbol(token
.loc
, (unsigned)token
.uns64value
);
879 error("identifier or integer expected, not %s", token
.toChars());
883 if (token
.value
!= TOKsemicolon
)
884 error("semicolon expected");
889 condition
= parseDebugCondition();
894 if (token
.value
== TOKassign
)
897 if (token
.value
== TOKidentifier
)
898 s
= new VersionSymbol(token
.loc
, token
.ident
);
899 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
900 s
= new VersionSymbol(token
.loc
, (unsigned)token
.uns64value
);
903 error("identifier or integer expected, not %s", token
.toChars());
907 if (token
.value
!= TOKsemicolon
)
908 error("semicolon expected");
912 condition
= parseVersionCondition();
918 if (token
.value
== TOKcolon
)
919 athen
= parseBlock(pLastDecl
);
922 Loc lookingForElseSave
= lookingForElse
;
923 lookingForElse
= token
.loc
;
924 athen
= parseBlock(pLastDecl
);
925 lookingForElse
= lookingForElseSave
;
927 Dsymbols
*aelse
= NULL
;
928 if (token
.value
== TOKelse
)
930 Loc elseloc
= token
.loc
;
932 aelse
= parseBlock(pLastDecl
);
933 checkDanglingElse(elseloc
);
935 s
= new ConditionalDeclaration(condition
, athen
, aelse
);
939 case TOKsemicolon
: // empty declaration
940 //error("empty declaration");
945 error("declaration expected, not `%s`",token
.toChars());
947 while (token
.value
!= TOKsemicolon
&& token
.value
!= TOKeof
)
956 if (!s
->isAttribDeclaration())
959 addComment(s
, pAttrs
->comment
);
961 else if (a
&& a
->length
)
972 /*********************************************
973 * Give error on redundant/conflicting storage class.
975 * TODO: remove deprecation in 2.068 and keep only error
978 StorageClass
Parser::appendStorageClass(StorageClass storageClass
, StorageClass stc
,
981 if ((storageClass
& stc
) ||
982 (storageClass
& STCin
&& stc
& (STCconst
| STCscope
)) ||
983 (stc
& STCin
&& storageClass
& (STCconst
| STCscope
)))
986 stcToBuffer(&buf
, stc
);
988 deprecation("redundant attribute `%s`", buf
.peekChars());
990 error("redundant attribute `%s`", buf
.peekChars());
991 return storageClass
| stc
;
996 if (stc
& (STCconst
| STCimmutable
| STCmanifest
))
998 StorageClass u
= storageClass
& (STCconst
| STCimmutable
| STCmanifest
);
1000 error("conflicting attribute `%s`", Token::toChars(token
.value
));
1002 if (stc
& (STCgshared
| STCshared
| STCtls
))
1004 StorageClass u
= storageClass
& (STCgshared
| STCshared
| STCtls
);
1006 error("conflicting attribute `%s`", Token::toChars(token
.value
));
1008 if (stc
& (STCsafe
| STCsystem
| STCtrusted
))
1010 StorageClass u
= storageClass
& (STCsafe
| STCsystem
| STCtrusted
);
1012 error("conflicting attribute `@%s`", token
.toChars());
1015 return storageClass
;
1018 /***********************************************
1019 * Parse attribute, lexer is on '@'.
1021 * pudas array of UDAs to append to
1023 * storage class if a predefined attribute; also scanner remains on identifier.
1024 * 0 if not a predefined attribute
1025 * *pudas set if user defined attribute, scanner is past UDA
1026 * *pudas NULL if not a user defined attribute
1029 StorageClass
Parser::parseAttribute(Expressions
**pudas
)
1032 Expressions
*udas
= NULL
;
1033 StorageClass stc
= 0;
1034 if (token
.value
== TOKidentifier
)
1036 if (token
.ident
== Id::property
)
1038 else if (token
.ident
== Id::nogc
)
1040 else if (token
.ident
== Id::safe
)
1042 else if (token
.ident
== Id::trusted
)
1044 else if (token
.ident
== Id::system
)
1046 else if (token
.ident
== Id::disable
)
1048 else if (token
.ident
== Id::future
)
1052 // Allow identifier, template instantiation, or function call
1053 Expression
*exp
= parsePrimaryExp();
1054 if (token
.value
== TOKlparen
)
1056 Loc loc
= token
.loc
;
1057 exp
= new CallExp(loc
, exp
, parseArguments());
1060 udas
= new Expressions();
1064 else if (token
.value
== TOKlparen
)
1066 // @( ArgumentList )
1067 // Concatenate with existing
1068 if (peekNext() == TOKrparen
)
1069 error("empty attribute list is not allowed");
1070 udas
= parseArguments();
1074 error("@identifier or @(ArgumentList) expected, not @%s", token
.toChars());
1082 *pudas
= UserAttributeDeclaration::concat(*pudas
, udas
);
1085 error("valid attributes are @property, @safe, @trusted, @system, @disable");
1089 /***********************************************
1090 * Parse const/immutable/shared/inout/nothrow/pure postfix
1093 StorageClass
Parser::parsePostfix(StorageClass storageClass
, Expressions
**pudas
)
1098 switch (token
.value
)
1100 case TOKconst
: stc
= STCconst
; break;
1101 case TOKimmutable
: stc
= STCimmutable
; break;
1102 case TOKshared
: stc
= STCshared
; break;
1103 case TOKwild
: stc
= STCwild
; break;
1104 case TOKnothrow
: stc
= STCnothrow
; break;
1105 case TOKpure
: stc
= STCpure
; break;
1106 case TOKreturn
: stc
= STCreturn
; break;
1107 case TOKscope
: stc
= STCscope
; break;
1110 Expressions
*udas
= NULL
;
1111 stc
= parseAttribute(&udas
);
1115 *pudas
= UserAttributeDeclaration::concat(*pudas
, udas
);
1119 // void function() @uda fp;
1120 // () @uda { return 1; }
1121 error("user-defined attributes cannot appear as postfixes");
1129 return storageClass
;
1131 storageClass
= appendStorageClass(storageClass
, stc
, true);
1136 StorageClass
Parser::parseTypeCtor()
1138 StorageClass storageClass
= STCundefined
;
1142 if (peek(&token
)->value
== TOKlparen
)
1143 return storageClass
;
1146 switch (token
.value
)
1148 case TOKconst
: stc
= STCconst
; break;
1149 case TOKimmutable
: stc
= STCimmutable
; break;
1150 case TOKshared
: stc
= STCshared
; break;
1151 case TOKwild
: stc
= STCwild
; break;
1154 return storageClass
;
1156 storageClass
= appendStorageClass(storageClass
, stc
);
1161 /********************************************
1162 * Parse declarations after an align, protection, or extern decl.
1165 Dsymbols
*Parser::parseBlock(Dsymbol
**pLastDecl
, PrefixAttributes
*pAttrs
)
1169 //printf("parseBlock()\n");
1170 switch (token
.value
)
1173 error("declaration expected following attribute, not `;`");
1178 error("declaration expected following attribute, not EOF");
1183 Loc lookingForElseSave
= lookingForElse
;
1184 lookingForElse
= Loc();
1187 a
= parseDeclDefs(0, pLastDecl
);
1188 if (token
.value
!= TOKrcurly
)
1191 error("matching `}` expected, not %s", token
.toChars());
1195 lookingForElse
= lookingForElseSave
;
1201 a
= parseDeclDefs(0, pLastDecl
); // grab declarations up to closing curly bracket
1205 a
= parseDeclDefs(1, pLastDecl
, pAttrs
);
1211 /**********************************
1212 * Parse a static assertion.
1213 * Current token is 'static'.
1216 StaticAssert
*Parser::parseStaticAssert()
1218 Loc loc
= token
.loc
;
1220 Expression
*msg
= NULL
;
1222 //printf("parseStaticAssert()\n");
1226 exp
= parseAssignExp();
1227 if (token
.value
== TOKcomma
)
1230 if (token
.value
!= TOKrparen
)
1232 msg
= parseAssignExp();
1233 if (token
.value
== TOKcomma
)
1238 check(TOKsemicolon
);
1239 return new StaticAssert(loc
, exp
, msg
);
1242 /***********************************
1243 * Parse typeof(expression).
1244 * Current token is on the 'typeof'.
1247 TypeQualified
*Parser::parseTypeof()
1250 Loc loc
= token
.loc
;
1254 if (token
.value
== TOKreturn
) // typeof(return)
1257 t
= new TypeReturn(loc
);
1261 Expression
*exp
= parseExpression(); // typeof(expression)
1262 t
= new TypeTypeof(loc
, exp
);
1268 /***********************************
1269 * Parse __vector(type).
1270 * Current token is on the '__vector'.
1273 Type
*Parser::parseVector()
1277 Type
*tb
= parseType();
1279 return new TypeVector(tb
);
1282 /***********************************
1285 * extern (C++, namespaces)
1286 * extern (C++, "namespace", "namespaces", ...)
1287 * The parser is on the 'extern' token.
1290 LINK
Parser::parseLinkage(Identifiers
**pidents
, CPPMANGLE
*pcppmangle
, bool *pcppMangleOnly
)
1292 Identifiers
*idents
= NULL
;
1293 CPPMANGLE cppmangle
= CPPMANGLEdefault
;
1294 bool cppMangleOnly
= false;
1295 LINK link
= LINKdefault
;
1297 assert(token
.value
== TOKlparen
);
1299 if (token
.value
== TOKidentifier
)
1300 { Identifier
*id
= token
.ident
;
1303 if (id
== Id::Windows
)
1305 else if (id
== Id::D
)
1307 else if (id
== Id::C
)
1310 if (token
.value
== TOKplusplus
)
1314 if (token
.value
== TOKcomma
) // , namespaces or class or struct
1317 if (token
.value
== TOKclass
|| token
.value
== TOKstruct
)
1319 cppmangle
= token
.value
== TOKclass
? CPPMANGLEclass
: CPPMANGLEstruct
;
1322 else if (token
.value
== TOKstring
) // extern(C++, "namespace", "namespaces")
1324 cppMangleOnly
= true;
1325 idents
= new Identifiers();
1329 StringExp
*stringExp
= (StringExp
*)parsePrimaryExp();
1330 const char *name
= stringExp
->toPtr();
1331 if (stringExp
->len
== 0)
1333 error("invalid zero length C++ namespace");
1337 else if (!Identifier::isValidIdentifier(name
))
1339 error("expected valid identifer for C++ namespace but got `%s`", name
);
1343 idents
->push(Identifier::idPool(name
));
1344 if (token
.value
== TOKcomma
)
1347 if (token
.value
!= TOKstring
)
1349 error("string expected following `,` for C++ namespace, not `%s`", token
.toChars());
1360 idents
= new Identifiers();
1363 if (token
.value
== TOKidentifier
)
1365 Identifier
*idn
= token
.ident
;
1368 if (token
.value
== TOKdot
)
1376 error("identifier expected for C++ namespace");
1377 idents
= NULL
; // error occurred, invalidate list of elements.
1385 else if (id
== Id::Objective
) // Looking for tokens "Objective-C"
1387 if (token
.value
== TOKmin
)
1390 if (token
.ident
== Id::C
)
1396 goto LinvalidLinkage
;
1399 goto LinvalidLinkage
;
1401 else if (id
== Id::System
)
1408 error("valid linkage identifiers are D, C, C++, Objective-C, Windows, System");
1414 link
= LINKd
; // default
1418 *pcppmangle
= cppmangle
;
1419 *pcppMangleOnly
= cppMangleOnly
;
1423 /***********************************
1424 * Parse ident1.ident2.ident3
1427 * entity = what qualified identifier is expected to resolve into.
1428 * Used only for better error message
1431 * array of identifiers with actual qualified one stored last
1433 Identifiers
*Parser::parseQualifiedIdentifier(const char *entity
)
1435 Identifiers
*qualified
= NULL
;
1440 if (token
.value
!= TOKidentifier
)
1442 error("%s expected as dot-separated identifiers, got `%s`",
1443 entity
, token
.toChars());
1447 Identifier
*id
= token
.ident
;
1449 qualified
= new Identifiers();
1450 qualified
->push(id
);
1453 } while (token
.value
== TOKdot
);
1458 /**************************************
1459 * Parse a debug conditional
1462 Condition
*Parser::parseDebugCondition()
1466 if (token
.value
== TOKlparen
)
1470 Identifier
*id
= NULL
;
1472 if (token
.value
== TOKidentifier
)
1474 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
1475 level
= (unsigned)token
.uns64value
;
1477 error("identifier or integer expected, not %s", token
.toChars());
1480 c
= new DebugCondition(mod
, level
, id
);
1483 c
= new DebugCondition(mod
, 1, NULL
);
1488 /**************************************
1489 * Parse a version conditional
1492 Condition
*Parser::parseVersionCondition()
1496 Identifier
*id
= NULL
;
1498 if (token
.value
== TOKlparen
)
1502 * version (unittest)
1504 * even though they are keywords
1506 if (token
.value
== TOKidentifier
)
1508 else if (token
.value
== TOKint32v
|| token
.value
== TOKint64v
)
1509 level
= (unsigned)token
.uns64value
;
1510 else if (token
.value
== TOKunittest
)
1511 id
= Identifier::idPool(Token::toChars(TOKunittest
));
1512 else if (token
.value
== TOKassert
)
1513 id
= Identifier::idPool(Token::toChars(TOKassert
));
1515 error("identifier or integer expected, not %s", token
.toChars());
1521 error("(condition) expected following version");
1522 c
= new VersionCondition(mod
, level
, id
);
1527 /***********************************************
1528 * static if (expression)
1532 * Current token is 'static'.
1535 Condition
*Parser::parseStaticIfCondition()
1538 Condition
*condition
;
1539 Loc loc
= token
.loc
;
1543 if (token
.value
== TOKlparen
)
1546 exp
= parseAssignExp();
1551 error("(expression) expected following static if");
1554 condition
= new StaticIfCondition(loc
, exp
);
1559 /*****************************************
1560 * Parse a constructor definition:
1561 * this(parameters) { body }
1563 * this(this) { body }
1564 * or constructor template:
1565 * this(templateparameters)(parameters) { body }
1566 * Current token is 'this'.
1569 Dsymbol
*Parser::parseCtor(PrefixAttributes
*pAttrs
)
1571 Expressions
*udas
= NULL
;
1572 Loc loc
= token
.loc
;
1573 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1576 if (token
.value
== TOKlparen
&& peekNext() == TOKthis
&& peekNext2() == TOKrparen
)
1578 // this(this) { ... }
1583 stc
= parsePostfix(stc
, &udas
);
1584 if (stc
& STCstatic
)
1585 error(loc
, "postblit cannot be static");
1587 PostBlitDeclaration
*f
= new PostBlitDeclaration(loc
, Loc(), stc
, Id::postblit
);
1589 pAttrs
->storageClass
= STCundefined
;
1590 Dsymbol
*s
= parseContracts(f
);
1593 Dsymbols
*a
= new Dsymbols();
1595 s
= new UserAttributeDeclaration(udas
, a
);
1600 /* Look ahead to see if:
1602 * which is a constructor template
1604 TemplateParameters
*tpl
= NULL
;
1605 if (token
.value
== TOKlparen
&& peekPastParen(&token
)->value
== TOKlparen
)
1607 tpl
= parseTemplateParameterList();
1610 /* Just a regular constructor
1613 Parameters
*parameters
= parseParameters(&varargs
);
1614 stc
= parsePostfix(stc
, &udas
);
1615 if (varargs
!= VARARGnone
|| Parameter::dim(parameters
) != 0)
1617 if (stc
& STCstatic
)
1618 error(loc
, "constructor cannot be static");
1620 else if (StorageClass ss
= stc
& (STCshared
| STCstatic
)) // this()
1622 if (ss
== STCstatic
)
1623 error(loc
, "use `static this()` to declare a static constructor");
1624 else if (ss
== (STCshared
| STCstatic
))
1625 error(loc
, "use `shared static this()` to declare a shared static constructor");
1628 Expression
*constraint
= tpl
? parseConstraint() : NULL
;
1630 Type
*tf
= new TypeFunction(ParameterList(parameters
, varargs
),
1631 NULL
, linkage
, stc
); // ReturnType -> auto
1632 tf
= tf
->addSTC(stc
);
1634 CtorDeclaration
*f
= new CtorDeclaration(loc
, Loc(), stc
, tf
);
1636 pAttrs
->storageClass
= STCundefined
;
1637 Dsymbol
*s
= parseContracts(f
);
1640 Dsymbols
*a
= new Dsymbols();
1642 s
= new UserAttributeDeclaration(udas
, a
);
1647 // Wrap a template around it
1648 Dsymbols
*decldefs
= new Dsymbols();
1650 s
= new TemplateDeclaration(loc
, f
->ident
, tpl
, constraint
, decldefs
);
1656 /*****************************************
1657 * Parse a destructor definition:
1659 * Current token is '~'.
1662 Dsymbol
*Parser::parseDtor(PrefixAttributes
*pAttrs
)
1664 Expressions
*udas
= NULL
;
1665 Loc loc
= token
.loc
;
1666 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1673 stc
= parsePostfix(stc
, &udas
);
1674 if (StorageClass ss
= stc
& (STCshared
| STCstatic
))
1676 if (ss
== STCstatic
)
1677 error(loc
, "use `static ~this()` to declare a static destructor");
1678 else if (ss
== (STCshared
| STCstatic
))
1679 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
1682 DtorDeclaration
*f
= new DtorDeclaration(loc
, Loc(), stc
, Id::dtor
);
1684 pAttrs
->storageClass
= STCundefined
;
1685 Dsymbol
*s
= parseContracts(f
);
1688 Dsymbols
*a
= new Dsymbols();
1690 s
= new UserAttributeDeclaration(udas
, a
);
1695 /*****************************************
1696 * Parse a static constructor definition:
1697 * static this() { body }
1698 * Current token is 'static'.
1701 Dsymbol
*Parser::parseStaticCtor(PrefixAttributes
*pAttrs
)
1703 //Expressions *udas = NULL;
1704 Loc loc
= token
.loc
;
1705 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1712 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, NULL
) | stc
;
1713 if (stc
& STCshared
)
1714 error(loc
, "use `shared static this()` to declare a shared static constructor");
1715 else if (stc
& STCstatic
)
1716 appendStorageClass(stc
, STCstatic
); // complaint for the redundancy
1717 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1720 stcToBuffer(&buf
, modStc
);
1721 error(loc
, "static constructor cannot be %s", buf
.peekChars());
1723 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1725 StaticCtorDeclaration
*f
= new StaticCtorDeclaration(loc
, Loc(), stc
);
1727 pAttrs
->storageClass
= STCundefined
;
1728 Dsymbol
*s
= parseContracts(f
);
1732 /*****************************************
1733 * Parse a static destructor definition:
1734 * static ~this() { body }
1735 * Current token is 'static'.
1738 Dsymbol
*Parser::parseStaticDtor(PrefixAttributes
*pAttrs
)
1740 Expressions
*udas
= NULL
;
1741 Loc loc
= token
.loc
;
1742 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1750 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, &udas
) | stc
;
1751 if (stc
& STCshared
)
1752 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
1753 else if (stc
& STCstatic
)
1754 appendStorageClass(stc
, STCstatic
); // complaint for the redundancy
1755 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1758 stcToBuffer(&buf
, modStc
);
1759 error(loc
, "static destructor cannot be %s", buf
.peekChars());
1761 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1763 StaticDtorDeclaration
*f
= new StaticDtorDeclaration(loc
, Loc(), stc
);
1765 pAttrs
->storageClass
= STCundefined
;
1766 Dsymbol
*s
= parseContracts(f
);
1769 Dsymbols
*a
= new Dsymbols();
1771 s
= new UserAttributeDeclaration(udas
, a
);
1776 /*****************************************
1777 * Parse a shared static constructor definition:
1778 * shared static this() { body }
1779 * Current token is 'shared'.
1782 Dsymbol
*Parser::parseSharedStaticCtor(PrefixAttributes
*pAttrs
)
1784 //Expressions *udas = NULL;
1785 Loc loc
= token
.loc
;
1786 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1794 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, NULL
) | stc
;
1795 if (StorageClass ss
= stc
& (STCshared
| STCstatic
))
1796 appendStorageClass(stc
, ss
); // complaint for the redundancy
1797 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1800 stcToBuffer(&buf
, modStc
);
1801 error(loc
, "shared static constructor cannot be %s", buf
.peekChars());
1803 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1805 SharedStaticCtorDeclaration
*f
= new SharedStaticCtorDeclaration(loc
, Loc(), stc
);
1807 pAttrs
->storageClass
= STCundefined
;
1808 Dsymbol
*s
= parseContracts(f
);
1812 /*****************************************
1813 * Parse a shared static destructor definition:
1814 * shared static ~this() { body }
1815 * Current token is 'shared'.
1818 Dsymbol
*Parser::parseSharedStaticDtor(PrefixAttributes
*pAttrs
)
1820 Expressions
*udas
= NULL
;
1821 Loc loc
= token
.loc
;
1822 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1831 stc
= parsePostfix(stc
& ~STC_TYPECTOR
, &udas
) | stc
;
1832 if (StorageClass ss
= stc
& (STCshared
| STCstatic
))
1833 appendStorageClass(stc
, ss
); // complaint for the redundancy
1834 else if (StorageClass modStc
= stc
& STC_TYPECTOR
)
1837 stcToBuffer(&buf
, modStc
);
1838 error(loc
, "shared static destructor cannot be %s", buf
.peekChars());
1840 stc
&= ~(STCstatic
| STC_TYPECTOR
);
1842 SharedStaticDtorDeclaration
*f
= new SharedStaticDtorDeclaration(loc
, Loc(), stc
);
1844 pAttrs
->storageClass
= STCundefined
;
1845 Dsymbol
*s
= parseContracts(f
);
1848 Dsymbols
*a
= new Dsymbols();
1850 s
= new UserAttributeDeclaration(udas
, a
);
1855 /*****************************************
1856 * Parse an invariant definition:
1857 * invariant { statements... }
1858 * invariant() { statements... }
1859 * invariant (expression);
1860 * Current token is 'invariant'.
1863 Dsymbol
*Parser::parseInvariant(PrefixAttributes
*pAttrs
)
1865 Loc loc
= token
.loc
;
1866 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1869 if (token
.value
== TOKlparen
) // optional () or invariant (expression);
1872 if (token
.value
!= TOKrparen
) // invariant (expression);
1874 Expression
*e
= parseAssignExp();
1875 Expression
*msg
= NULL
;
1876 if (token
.value
== TOKcomma
)
1879 if (token
.value
!= TOKrparen
)
1881 msg
= parseAssignExp();
1882 if (token
.value
== TOKcomma
)
1887 check(TOKsemicolon
);
1888 e
= new AssertExp(loc
, e
, msg
);
1889 ExpStatement
*fbody
= new ExpStatement(loc
, e
);
1890 InvariantDeclaration
*f
= new InvariantDeclaration(loc
, token
.loc
, stc
);
1900 InvariantDeclaration
*f
= new InvariantDeclaration(loc
, Loc(), stc
);
1902 pAttrs
->storageClass
= STCundefined
;
1903 f
->fbody
= parseStatement(PScurly
);
1907 /*****************************************
1908 * Parse a unittest definition:
1910 * Current token is 'unittest'.
1913 Dsymbol
*Parser::parseUnitTest(PrefixAttributes
*pAttrs
)
1915 Loc loc
= token
.loc
;
1916 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1920 const utf8_t
*begPtr
= token
.ptr
+ 1; // skip '{'
1921 const utf8_t
*endPtr
= NULL
;
1922 Statement
*sbody
= parseStatement(PScurly
, &endPtr
);
1924 /** Extract unittest body as a string. Must be done eagerly since memory
1925 will be released by the lexer before doc gen. */
1926 char *docline
= NULL
;
1927 if (global
.params
.doDocComments
&& endPtr
> begPtr
)
1929 /* Remove trailing whitespaces */
1930 for (const utf8_t
*p
= endPtr
- 1;
1931 begPtr
<= p
&& (*p
== ' ' || *p
== '\r' || *p
== '\n' || *p
== '\t'); --p
)
1936 size_t len
= endPtr
- begPtr
;
1939 docline
= (char *)mem
.xmalloc(len
+ 2);
1940 memcpy(docline
, begPtr
, len
);
1941 docline
[len
] = '\n'; // Terminate all lines by LF
1942 docline
[len
+1] = '\0';
1946 UnitTestDeclaration
*f
= new UnitTestDeclaration(loc
, token
.loc
, stc
, docline
);
1948 pAttrs
->storageClass
= STCundefined
;
1953 /*****************************************
1954 * Parse a new definition:
1955 * new(parameters) { body }
1956 * Current token is 'new'.
1959 Dsymbol
*Parser::parseNew(PrefixAttributes
*pAttrs
)
1961 Loc loc
= token
.loc
;
1962 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1967 Parameters
*parameters
= parseParameters(&varargs
);
1968 NewDeclaration
*f
= new NewDeclaration(loc
, Loc(), stc
, parameters
, varargs
);
1970 pAttrs
->storageClass
= STCundefined
;
1971 Dsymbol
*s
= parseContracts(f
);
1975 /*****************************************
1976 * Parse a delete definition:
1977 * delete(parameters) { body }
1978 * Current token is 'delete'.
1981 Dsymbol
*Parser::parseDelete(PrefixAttributes
*pAttrs
)
1983 Loc loc
= token
.loc
;
1984 StorageClass stc
= pAttrs
? pAttrs
->storageClass
: STCundefined
;
1989 Parameters
*parameters
= parseParameters(&varargs
);
1990 if (varargs
!= VARARGnone
)
1991 error("... not allowed in delete function parameter list");
1992 DeleteDeclaration
*f
= new DeleteDeclaration(loc
, Loc(), stc
, parameters
);
1994 pAttrs
->storageClass
= STCundefined
;
1995 Dsymbol
*s
= parseContracts(f
);
1999 /**********************************************
2000 * Parse parameter list.
2003 Parameters
*Parser::parseParameters(VarArg
*pvarargs
, TemplateParameters
**tpl
)
2005 Parameters
*parameters
= new Parameters();
2006 VarArg varargs
= VARARGnone
;
2012 Identifier
*ai
= NULL
;
2014 StorageClass storageClass
= 0;
2017 Expressions
*udas
= NULL
;
2019 for (;1; nextToken())
2022 switch (token
.value
)
2028 varargs
= VARARGvariadic
;
2033 if (peek(&token
)->value
== TOKlparen
)
2039 if (peek(&token
)->value
== TOKlparen
)
2045 if (peek(&token
)->value
== TOKlparen
)
2051 if (peek(&token
)->value
== TOKlparen
)
2058 Expressions
*exps
= NULL
;
2059 StorageClass stc2
= parseAttribute(&exps
);
2060 if (stc2
== STCproperty
|| stc2
== STCnogc
||
2061 stc2
== STCdisable
|| stc2
== STCsafe
||
2062 stc2
== STCtrusted
|| stc2
== STCsystem
)
2064 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2068 udas
= UserAttributeDeclaration::concat(udas
, exps
);
2070 if (token
.value
== TOKdotdotdot
)
2071 error("variadic parameter cannot have user-defined attributes");
2075 // Don't call nextToken again.
2078 case TOKin
: stc
= STCin
; goto L2
;
2079 case TOKout
: stc
= STCout
; goto L2
;
2080 case TOKref
: stc
= STCref
; goto L2
;
2081 case TOKlazy
: stc
= STClazy
; goto L2
;
2082 case TOKscope
: stc
= STCscope
; goto L2
;
2083 case TOKfinal
: stc
= STCfinal
; goto L2
;
2084 case TOKauto
: stc
= STCauto
; goto L2
;
2085 case TOKreturn
: stc
= STCreturn
; goto L2
;
2087 storageClass
= appendStorageClass(storageClass
, stc
);
2092 { stc
= storageClass
& (STCin
| STCout
| STCref
| STClazy
);
2093 // if stc is not a power of 2
2094 if (stc
& (stc
- 1) &&
2095 !(stc
== (STCin
| STCref
)))
2096 error("incompatible parameter storage classes");
2097 //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
2098 //error("scope cannot be ref or out");
2101 if (tpl
&& token
.value
== TOKidentifier
&&
2102 (t
= peek(&token
), (t
->value
== TOKcomma
||
2103 t
->value
== TOKrparen
||
2104 t
->value
== TOKdotdotdot
)))
2106 Identifier
*id
= Identifier::generateId("__T");
2107 Loc loc
= token
.loc
;
2108 at
= new TypeIdentifier(loc
, id
);
2110 *tpl
= new TemplateParameters();
2111 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, id
, NULL
, NULL
);
2118 at
= parseType(&ai
);
2120 if (token
.value
== TOKassign
) // = defaultArg
2122 ae
= parseDefaultInitExp();
2127 error("default argument expected for %s",
2128 ai
? ai
->toChars() : at
->toChars());
2130 Parameter
*param
= new Parameter(storageClass
, at
, ai
, ae
, NULL
);
2133 Dsymbols
*a
= new Dsymbols();
2134 UserAttributeDeclaration
*udad
= new UserAttributeDeclaration(udas
, a
);
2135 param
->userAttribDecl
= udad
;
2137 if (token
.value
== TOKat
)
2139 Expressions
*exps
= NULL
;
2140 StorageClass stc2
= parseAttribute(&exps
);
2141 if (stc2
== STCproperty
|| stc2
== STCnogc
||
2142 stc2
== STCdisable
|| stc2
== STCsafe
||
2143 stc2
== STCtrusted
|| stc2
== STCsystem
)
2145 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2149 error("user-defined attributes cannot appear as postfixes", token
.toChars());
2154 if (token
.value
== TOKdotdotdot
)
2159 if (storageClass
& (STCout
| STCref
))
2160 error("variadic argument cannot be out or ref");
2161 varargs
= VARARGtypesafe
;
2162 parameters
->push(param
);
2166 parameters
->push(param
);
2167 if (token
.value
== TOKcomma
)
2181 *pvarargs
= varargs
;
2186 /*************************************
2189 EnumDeclaration
*Parser::parseEnum()
2194 Loc loc
= token
.loc
;
2196 // printf("Parser::parseEnum()\n");
2198 if (token
.value
== TOKidentifier
)
2206 if (token
.value
== TOKcolon
)
2211 Loc typeLoc
= token
.loc
;
2212 memtype
= parseBasicType();
2213 memtype
= parseDeclarator(memtype
, &alt
, NULL
);
2214 checkCstyleTypeSyntax(typeLoc
, memtype
, alt
, NULL
);
2219 e
= new EnumDeclaration(loc
, id
, memtype
);
2220 if (token
.value
== TOKsemicolon
&& id
)
2222 else if (token
.value
== TOKlcurly
)
2224 bool isAnonymousEnum
= !id
;
2226 //printf("enum definition\n");
2227 e
->members
= new Dsymbols();
2229 const utf8_t
*comment
= token
.blockComment
;
2230 while (token
.value
!= TOKrcurly
)
2232 /* Can take the following forms...
2235 * 3. type ident = value
2236 * ... prefixed by valid attributes
2241 Identifier
*ident
= NULL
;
2243 Expressions
*udas
= NULL
;
2244 StorageClass stc
= STCundefined
;
2245 Expression
*deprecationMessage
= NULL
;
2247 while (token
.value
!= TOKrcurly
&&
2248 token
.value
!= TOKcomma
&&
2249 token
.value
!= TOKassign
)
2251 switch (token
.value
)
2254 if (StorageClass _stc
= parseAttribute(&udas
))
2256 if (_stc
== STCdisable
)
2261 stcToBuffer(&buf
, _stc
);
2262 error("`%s` is not a valid attribute for enum members", buf
.peekChars());
2268 if (StorageClass _stc
= parseDeprecatedAttribute(this, &deprecationMessage
))
2276 Token
*tp
= peek(&token
);
2277 if (tp
->value
== TOKassign
|| tp
->value
== TOKcomma
|| tp
->value
== TOKrcurly
)
2279 ident
= token
.ident
;
2291 if (isAnonymousEnum
)
2293 type
= parseType(&ident
, NULL
);
2294 if (type
== Type::terror
)
2302 error("`%s` is not a valid attribute for enum members", token
.toChars());
2309 if (type
&& type
!= Type::terror
)
2312 error("no identifier for declarator %s", type
->toChars());
2313 if (!isAnonymousEnum
)
2314 error("type only allowed if anonymous enum and no enum type");
2318 if (token
.value
== TOKassign
)
2321 value
= parseAssignExp();
2326 if (type
&& type
!= Type::terror
&& isAnonymousEnum
)
2327 error("if type, there must be an initializer");
2330 UserAttributeDeclaration
*uad
= NULL
;
2332 uad
= new UserAttributeDeclaration(udas
, NULL
);
2334 DeprecatedDeclaration
*dd
= NULL
;
2335 if (deprecationMessage
)
2337 dd
= new DeprecatedDeclaration(deprecationMessage
, NULL
);
2338 stc
|= STCdeprecated
;
2341 EnumMember
*em
= new EnumMember(loc
, ident
, value
, type
, stc
, uad
, dd
);
2342 e
->members
->push(em
);
2344 if (token
.value
== TOKrcurly
)
2348 addComment(em
, comment
);
2352 addComment(em
, comment
);
2353 comment
= token
.blockComment
;
2355 if (token
.value
== TOKeof
)
2357 error("premature end of file");
2364 error("enum declaration is invalid");
2366 //printf("-parseEnum() %s\n", e->toChars());
2370 /********************************
2371 * Parse struct, union, interface, class.
2374 Dsymbol
*Parser::parseAggregate()
2376 AggregateDeclaration
*a
= NULL
;
2379 TemplateParameters
*tpl
= NULL
;
2380 Expression
*constraint
= NULL
;
2381 Loc loc
= token
.loc
;
2382 TOK tok
= token
.value
;
2384 //printf("Parser::parseAggregate()\n");
2386 if (token
.value
!= TOKidentifier
)
2395 if (token
.value
== TOKlparen
)
2397 // Class template declaration.
2398 // Gather template parameter list
2399 tpl
= parseTemplateParameterList();
2400 constraint
= parseConstraint();
2410 error(loc
, "anonymous classes not allowed");
2412 // Collect base class(es)
2413 BaseClasses
*baseclasses
= NULL
;
2414 if (token
.value
== TOKcolon
)
2417 baseclasses
= parseBaseClasses();
2421 Expression
*tempCons
= parseConstraint();
2425 error("members expected");
2427 constraint
= tempCons
;
2431 if (token
.value
!= TOKlcurly
)
2432 error("members expected");
2435 if (tok
== TOKclass
)
2437 bool inObject
= md
&& !md
->packages
&& md
->id
== Id::object
;
2438 a
= new ClassDeclaration(loc
, id
, baseclasses
, NULL
, inObject
);
2441 a
= new InterfaceDeclaration(loc
, id
, baseclasses
);
2448 bool inObject
= md
&& !md
->packages
&& md
->id
== Id::object
;
2449 a
= new StructDeclaration(loc
, id
, inObject
);
2457 a
= new UnionDeclaration(loc
, id
);
2466 if (a
&& token
.value
== TOKsemicolon
)
2470 else if (token
.value
== TOKlcurly
)
2472 const Loc lookingForElseSave
= lookingForElse
;
2473 lookingForElse
= Loc();
2474 //printf("aggregate definition\n");
2476 Dsymbols
*decl
= parseDeclDefs(0);
2477 lookingForElse
= lookingForElseSave
;
2478 if (token
.value
!= TOKrcurly
)
2479 error("} expected following members in %s declaration at %s",
2480 Token::toChars(tok
), loc
.toChars());
2484 /* Anonymous structs/unions are more like attributes.
2486 return new AnonDeclaration(loc
, anon
== 2, decl
);
2493 error("{ } expected following %s declaration", Token::toChars(tok
));
2494 a
= new StructDeclaration(loc
, NULL
, false);
2499 // Wrap a template around the aggregate declaration
2500 Dsymbols
*decldefs
= new Dsymbols();
2502 TemplateDeclaration
*tempdecl
=
2503 new TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
);
2510 /*******************************************
2513 BaseClasses
*Parser::parseBaseClasses()
2515 BaseClasses
*baseclasses
= new BaseClasses();
2517 for (; 1; nextToken())
2520 Prot protection
= Prot(Prot::public_
);
2521 switch (token
.value
)
2525 protection
= Prot(Prot::private_
);
2530 protection
= Prot(Prot::package_
);
2535 protection
= Prot(Prot::protected_
);
2540 protection
= Prot(Prot::public_
);
2546 error("use of base class protection is no longer supported");
2547 BaseClass
*b
= new BaseClass(parseBasicType());
2548 baseclasses
->push(b
);
2549 if (token
.value
!= TOKcomma
)
2555 /**************************************
2557 * Constraint is of the form:
2558 * if ( ConstraintExpression )
2561 Expression
*Parser::parseConstraint()
2562 { Expression
*e
= NULL
;
2564 if (token
.value
== TOKif
)
2566 nextToken(); // skip over 'if'
2568 e
= parseExpression();
2574 /**************************************
2575 * Parse a TemplateDeclaration.
2578 TemplateDeclaration
*Parser::parseTemplateDeclaration(bool ismixin
)
2580 TemplateDeclaration
*tempdecl
;
2582 TemplateParameters
*tpl
;
2584 Expression
*constraint
= NULL
;
2585 Loc loc
= token
.loc
;
2588 if (token
.value
!= TOKidentifier
)
2590 error("identifier expected following template");
2595 tpl
= parseTemplateParameterList();
2599 constraint
= parseConstraint();
2601 if (token
.value
!= TOKlcurly
)
2603 error("members of template declaration expected");
2607 decldefs
= parseBlock(NULL
);
2609 tempdecl
= new TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
, ismixin
);
2616 /******************************************
2617 * Parse template parameter list.
2619 * flag 0: parsing "( list )"
2620 * 1: parsing non-empty "list )"
2623 TemplateParameters
*Parser::parseTemplateParameterList(int flag
)
2625 TemplateParameters
*tpl
= new TemplateParameters();
2627 if (!flag
&& token
.value
!= TOKlparen
)
2628 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
2633 // Get array of TemplateParameters
2634 if (flag
|| token
.value
!= TOKrparen
)
2637 while (token
.value
!= TOKrparen
)
2639 TemplateParameter
*tp
;
2641 Identifier
*tp_ident
= NULL
;
2642 Type
*tp_spectype
= NULL
;
2643 Type
*tp_valtype
= NULL
;
2644 Type
*tp_defaulttype
= NULL
;
2645 Expression
*tp_specvalue
= NULL
;
2646 Expression
*tp_defaultvalue
= NULL
;
2649 // Get TemplateParameter
2651 // First, look ahead to see if it is a TypeParameter or a ValueParameter
2653 if (token
.value
== TOKalias
)
2656 loc
= token
.loc
; // todo
2657 Type
*spectype
= NULL
;
2658 if (isDeclaration(&token
, 2, TOKreserved
, NULL
))
2660 spectype
= parseType(&tp_ident
);
2664 if (token
.value
!= TOKidentifier
)
2666 error("identifier expected for template alias parameter");
2669 tp_ident
= token
.ident
;
2672 RootObject
*spec
= NULL
;
2673 if (token
.value
== TOKcolon
) // : Type
2676 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
2679 spec
= parseCondExp();
2681 RootObject
*def
= NULL
;
2682 if (token
.value
== TOKassign
) // = Type
2685 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
2688 def
= parseCondExp();
2690 tp
= new TemplateAliasParameter(loc
, tp_ident
, spectype
, spec
, def
);
2692 else if (t
->value
== TOKcolon
|| t
->value
== TOKassign
||
2693 t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
2696 if (token
.value
!= TOKidentifier
)
2698 error("identifier expected for template type parameter");
2702 tp_ident
= token
.ident
;
2704 if (token
.value
== TOKcolon
) // : Type
2707 tp_spectype
= parseType();
2709 if (token
.value
== TOKassign
) // = Type
2712 tp_defaulttype
= parseType();
2714 tp
= new TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
2716 else if (token
.value
== TOKidentifier
&& t
->value
== TOKdotdotdot
)
2720 error("variadic template parameter must be last");
2723 tp_ident
= token
.ident
;
2726 tp
= new TemplateTupleParameter(loc
, tp_ident
);
2728 else if (token
.value
== TOKthis
)
2732 if (token
.value
!= TOKidentifier
)
2734 error("identifier expected for template this parameter");
2738 tp_ident
= token
.ident
;
2740 if (token
.value
== TOKcolon
) // : Type
2743 tp_spectype
= parseType();
2745 if (token
.value
== TOKassign
) // = Type
2748 tp_defaulttype
= parseType();
2750 tp
= new TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
2755 loc
= token
.loc
; // todo
2756 tp_valtype
= parseType(&tp_ident
);
2759 error("identifier expected for template value parameter");
2760 tp_ident
= Identifier::idPool("error");
2762 if (token
.value
== TOKcolon
) // : CondExpression
2765 tp_specvalue
= parseCondExp();
2767 if (token
.value
== TOKassign
) // = CondExpression
2770 tp_defaultvalue
= parseDefaultInitExp();
2772 tp
= new TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
2775 if (token
.value
!= TOKcomma
)
2785 /******************************************
2786 * Parse template mixin.
2789 * mixin a.b.c!(args).Foo!(args);
2790 * mixin Foo!(args) identifier;
2791 * mixin typeof(expr).identifier!(args);
2794 Dsymbol
*Parser::parseMixin()
2800 //printf("parseMixin()\n");
2801 Loc locMixin
= token
.loc
;
2802 nextToken(); // skip 'mixin'
2804 Loc loc
= token
.loc
;
2805 TypeQualified
*tqual
= NULL
;
2806 if (token
.value
== TOKdot
)
2812 if (token
.value
== TOKtypeof
)
2814 tqual
= parseTypeof();
2817 if (token
.value
!= TOKidentifier
)
2819 error("identifier expected, not %s", token
.toChars());
2830 if (token
.value
== TOKnot
)
2832 tiargs
= parseTemplateArguments();
2835 if (tiargs
&& token
.value
== TOKdot
)
2837 TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
2838 tempinst
->tiargs
= tiargs
;
2840 tqual
= new TypeInstance(loc
, tempinst
);
2842 tqual
->addInst(tempinst
);
2848 tqual
= new TypeIdentifier(loc
, id
);
2850 tqual
->addIdent(id
);
2853 if (token
.value
!= TOKdot
)
2857 if (token
.value
!= TOKidentifier
)
2859 error("identifier expected following `.` instead of `%s`", token
.toChars());
2867 if (token
.value
== TOKidentifier
)
2875 tm
= new TemplateMixin(locMixin
, id
, tqual
, tiargs
);
2876 if (token
.value
!= TOKsemicolon
)
2877 error("`;` expected after mixin");
2883 /******************************************
2884 * Parse template arguments.
2886 * current token is opening '!'
2888 * current token is one after closing ')'
2891 Objects
*Parser::parseTemplateArguments()
2896 if (token
.value
== TOKlparen
)
2898 // ident!(template_arguments)
2899 tiargs
= parseTemplateArgumentList();
2903 // ident!template_argument
2904 tiargs
= parseTemplateSingleArgument();
2906 if (token
.value
== TOKnot
)
2908 TOK tok
= peekNext();
2909 if (tok
!= TOKis
&& tok
!= TOKin
)
2911 error("multiple ! arguments are not allowed");
2914 if (token
.value
== TOKlparen
)
2915 parseTemplateArgumentList();
2917 parseTemplateSingleArgument();
2918 if (token
.value
== TOKnot
&& (tok
= peekNext()) != TOKis
&& tok
!= TOKin
)
2925 /******************************************
2926 * Parse template argument list.
2928 * current token is opening '(',
2929 * or ',' for __traits
2931 * current token is one after closing ')'
2934 Objects
*Parser::parseTemplateArgumentList()
2936 //printf("Parser::parseTemplateArgumentList()\n");
2937 Objects
*tiargs
= new Objects();
2938 TOK endtok
= TOKrparen
;
2939 assert(token
.value
== TOKlparen
|| token
.value
== TOKcomma
);
2942 // Get TemplateArgumentList
2943 while (token
.value
!= endtok
)
2945 // See if it is an Expression or a Type
2946 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
2947 { // Template argument is a type
2948 Type
*ta
= parseType();
2952 { // Template argument is an expression
2953 Expression
*ea
= parseAssignExp();
2956 if (token
.value
!= TOKcomma
)
2960 check(endtok
, "template argument list");
2964 /*****************************
2965 * Parse single template argument, to support the syntax:
2968 * current token is the arg
2971 Objects
*Parser::parseTemplateSingleArgument()
2973 //printf("parseTemplateSingleArgument()\n");
2974 Objects
*tiargs
= new Objects();
2976 switch (token
.value
)
2979 ta
= new TypeIdentifier(token
.loc
, token
.ident
);
2986 case TOKvoid
: ta
= Type::tvoid
; goto LabelX
;
2987 case TOKint8
: ta
= Type::tint8
; goto LabelX
;
2988 case TOKuns8
: ta
= Type::tuns8
; goto LabelX
;
2989 case TOKint16
: ta
= Type::tint16
; goto LabelX
;
2990 case TOKuns16
: ta
= Type::tuns16
; goto LabelX
;
2991 case TOKint32
: ta
= Type::tint32
; goto LabelX
;
2992 case TOKuns32
: ta
= Type::tuns32
; goto LabelX
;
2993 case TOKint64
: ta
= Type::tint64
; goto LabelX
;
2994 case TOKuns64
: ta
= Type::tuns64
; goto LabelX
;
2995 case TOKint128
: ta
= Type::tint128
; goto LabelX
;
2996 case TOKuns128
: ta
= Type::tuns128
; goto LabelX
;
2997 case TOKfloat32
: ta
= Type::tfloat32
; goto LabelX
;
2998 case TOKfloat64
: ta
= Type::tfloat64
; goto LabelX
;
2999 case TOKfloat80
: ta
= Type::tfloat80
; goto LabelX
;
3000 case TOKimaginary32
: ta
= Type::timaginary32
; goto LabelX
;
3001 case TOKimaginary64
: ta
= Type::timaginary64
; goto LabelX
;
3002 case TOKimaginary80
: ta
= Type::timaginary80
; goto LabelX
;
3003 case TOKcomplex32
: ta
= Type::tcomplex32
; goto LabelX
;
3004 case TOKcomplex64
: ta
= Type::tcomplex64
; goto LabelX
;
3005 case TOKcomplex80
: ta
= Type::tcomplex80
; goto LabelX
;
3006 case TOKbool
: ta
= Type::tbool
; goto LabelX
;
3007 case TOKchar
: ta
= Type::tchar
; goto LabelX
;
3008 case TOKwchar
: ta
= Type::twchar
; goto LabelX
;
3009 case TOKdchar
: ta
= Type::tdchar
; goto LabelX
;
3024 case TOKimaginary32v
:
3025 case TOKimaginary64v
:
3026 case TOKimaginary80v
:
3036 case TOKfilefullpath
:
3038 case TOKmodulestring
:
3042 { // Template argument is an expression
3043 Expression
*ea
= parsePrimaryExp();
3049 error("template argument expected following !");
3055 Dsymbols
*Parser::parseImport()
3057 Dsymbols
*decldefs
= new Dsymbols();
3058 Identifier
*aliasid
= NULL
;
3060 int isstatic
= token
.value
== TOKstatic
;
3064 //printf("Parser::parseImport()\n");
3069 if (token
.value
!= TOKidentifier
)
3071 error("identifier expected following import");
3075 Loc loc
= token
.loc
;
3076 Identifier
*id
= token
.ident
;
3077 Identifiers
*a
= NULL
;
3079 if (!aliasid
&& token
.value
== TOKassign
)
3084 while (token
.value
== TOKdot
)
3087 a
= new Identifiers();
3090 if (token
.value
!= TOKidentifier
)
3092 error("identifier expected following package");
3099 Import
*s
= new Import(loc
, a
, id
, aliasid
, isstatic
);
3103 * : alias=name, alias=name;
3106 if (token
.value
== TOKcolon
)
3111 if (token
.value
!= TOKidentifier
)
3113 error("identifier expected following :");
3116 Identifier
*alias
= token
.ident
;
3119 if (token
.value
== TOKassign
)
3122 if (token
.value
!= TOKidentifier
)
3124 error("identifier expected following %s=", alias
->toChars());
3135 s
->addAlias(name
, alias
);
3136 } while (token
.value
== TOKcomma
);
3137 break; // no comma-separated imports of this form
3141 } while (token
.value
== TOKcomma
);
3143 if (token
.value
== TOKsemicolon
)
3147 error("`;` expected");
3154 Type
*Parser::parseType(Identifier
**pident
, TemplateParameters
**ptpl
)
3156 /* Take care of the storage class prefixes that
3157 * serve as type attributes:
3165 * shared inout const type
3167 StorageClass stc
= 0;
3170 switch (token
.value
)
3173 if (peekNext() == TOKlparen
)
3174 break; // const as type constructor
3175 stc
|= STCconst
; // const as storage class
3180 if (peekNext() == TOKlparen
)
3182 stc
|= STCimmutable
;
3187 if (peekNext() == TOKlparen
)
3194 if (peekNext() == TOKlparen
)
3206 Loc typeLoc
= token
.loc
;
3209 t
= parseBasicType();
3212 t
= parseDeclarator(t
, &alt
, pident
, ptpl
);
3213 checkCstyleTypeSyntax(typeLoc
, t
, alt
, pident
? *pident
: NULL
);
3219 Type
*Parser::parseBasicType(bool dontLookDotIdents
)
3225 //printf("parseBasicType()\n");
3226 switch (token
.value
)
3228 case TOKvoid
: t
= Type::tvoid
; goto LabelX
;
3229 case TOKint8
: t
= Type::tint8
; goto LabelX
;
3230 case TOKuns8
: t
= Type::tuns8
; goto LabelX
;
3231 case TOKint16
: t
= Type::tint16
; goto LabelX
;
3232 case TOKuns16
: t
= Type::tuns16
; goto LabelX
;
3233 case TOKint32
: t
= Type::tint32
; goto LabelX
;
3234 case TOKuns32
: t
= Type::tuns32
; goto LabelX
;
3238 if (token
.value
== TOKint64
) // if `long long`
3240 error("use `long` for a 64 bit integer instead of `long long`");
3243 else if (token
.value
== TOKfloat64
) // if `long double`
3245 error("use `real` instead of `long double`");
3252 case TOKuns64
: t
= Type::tuns64
; goto LabelX
;
3253 case TOKint128
: t
= Type::tint128
; goto LabelX
;
3254 case TOKuns128
: t
= Type::tuns128
; goto LabelX
;
3255 case TOKfloat32
: t
= Type::tfloat32
; goto LabelX
;
3256 case TOKfloat64
: t
= Type::tfloat64
; goto LabelX
;
3257 case TOKfloat80
: t
= Type::tfloat80
; goto LabelX
;
3258 case TOKimaginary32
: t
= Type::timaginary32
; goto LabelX
;
3259 case TOKimaginary64
: t
= Type::timaginary64
; goto LabelX
;
3260 case TOKimaginary80
: t
= Type::timaginary80
; goto LabelX
;
3261 case TOKcomplex32
: t
= Type::tcomplex32
; goto LabelX
;
3262 case TOKcomplex64
: t
= Type::tcomplex64
; goto LabelX
;
3263 case TOKcomplex80
: t
= Type::tcomplex80
; goto LabelX
;
3264 case TOKbool
: t
= Type::tbool
; goto LabelX
;
3265 case TOKchar
: t
= Type::tchar
; goto LabelX
;
3266 case TOKwchar
: t
= Type::twchar
; goto LabelX
;
3267 case TOKdchar
: t
= Type::tdchar
; goto LabelX
;
3278 if (token
.value
== TOKnot
)
3280 // ident!(template_arguments)
3281 TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
3282 tempinst
->tiargs
= parseTemplateArguments();
3283 t
= parseBasicTypeStartingAt(new TypeInstance(loc
, tempinst
), dontLookDotIdents
);
3287 t
= parseBasicTypeStartingAt(new TypeIdentifier(loc
, id
), dontLookDotIdents
);
3292 // Leading . as in .foo
3293 t
= parseBasicTypeStartingAt(new TypeIdentifier(token
.loc
, Id::empty
), dontLookDotIdents
);
3297 // typeof(expression)
3298 t
= parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents
);
3306 if (TraitsExp
*te
= (TraitsExp
*) parsePrimaryExp())
3308 if (te
->ident
&& te
->args
)
3310 t
= new TypeTraits(token
.loc
, te
);
3314 t
= new TypeError();
3321 t
= parseType()->addSTC(STCconst
);
3329 t
= parseType()->addSTC(STCimmutable
);
3337 t
= parseType()->addSTC(STCshared
);
3345 t
= parseType()->addSTC(STCwild
);
3350 error("basic type expected, not %s", token
.toChars());
3357 Type
*Parser::parseBasicTypeStartingAt(TypeQualified
*tid
, bool dontLookDotIdents
)
3359 Type
*maybeArray
= NULL
;
3360 // See https://issues.dlang.org/show_bug.cgi?id=1215
3361 // A basic type can look like MyType (typical case), but also:
3362 // MyType.T -> A type
3363 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3364 // MyType[expr].T -> A type.
3365 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3366 // (iif MyType[expr].T is a Ttuple)
3369 switch (token
.value
)
3374 if (token
.value
!= TOKidentifier
)
3376 error("identifier expected following `.` instead of `%s`", token
.toChars());
3381 // This is actually a TypeTuple index, not an {a/s}array.
3382 // We need to have a while loop to unwind all index taking:
3383 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3385 Type
*t
= maybeArray
;
3388 if (t
->ty
== Tsarray
)
3390 // The index expression is an Expression.
3391 TypeSArray
*a
= (TypeSArray
*)t
;
3392 dimStack
.push(a
->dim
->syntaxCopy());
3393 t
= a
->next
->syntaxCopy();
3395 else if (t
->ty
== Taarray
)
3397 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3398 TypeAArray
*a
= (TypeAArray
*)t
;
3399 dimStack
.push(a
->index
->syntaxCopy());
3400 t
= a
->next
->syntaxCopy();
3407 assert(dimStack
.length
> 0);
3408 // We're good. Replay indices in the reverse order.
3409 tid
= (TypeQualified
*)t
;
3410 while (dimStack
.length
)
3412 tid
->addIndex(dimStack
.pop());
3416 Loc loc
= token
.loc
;
3417 Identifier
*id
= token
.ident
;
3419 if (token
.value
== TOKnot
)
3421 TemplateInstance
*tempinst
= new TemplateInstance(loc
, id
);
3422 tempinst
->tiargs
= parseTemplateArguments();
3423 tid
->addInst(tempinst
);
3431 if (dontLookDotIdents
) // workaround for Bugzilla 14911
3435 Type
*t
= maybeArray
? maybeArray
: (Type
*)tid
;
3436 if (token
.value
== TOKrbracket
)
3438 // It's a dynamic array, and we're done:
3439 // T[].U does not make sense.
3440 t
= new TypeDArray(t
);
3444 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
3446 // This can be one of two things:
3447 // 1 - an associative array declaration, T[type]
3448 // 2 - an associative array declaration, T[expr]
3449 // These can only be disambiguated later.
3450 Type
*index
= parseType(); // [ type ]
3451 maybeArray
= new TypeAArray(t
, index
);
3456 // This can be one of three things:
3457 // 1 - an static array declaration, T[expr]
3458 // 2 - a slice, T[expr .. expr]
3459 // 3 - a template parameter pack index expression, T[expr].U
3460 // 1 and 3 can only be disambiguated later.
3461 //printf("it's type[expression]\n");
3463 Expression
*e
= parseAssignExp(); // [ expression ]
3464 if (token
.value
== TOKslice
)
3466 // It's a slice, and we're done.
3468 Expression
*e2
= parseAssignExp(); // [ exp .. exp ]
3469 t
= new TypeSlice(t
, e
, e2
);
3476 maybeArray
= new TypeSArray(t
, e
);
3489 return maybeArray
? maybeArray
: (Type
*)tid
;
3492 /******************************************
3493 * Parse things that follow the initial type t.
3498 * t [expression .. expression]
3503 Type
*Parser::parseBasicType2(Type
*t
)
3505 //printf("parseBasicType2()\n");
3508 switch (token
.value
)
3511 t
= new TypePointer(t
);
3516 // Handle []. Make sure things like
3518 // is (array[1] of array[3] of int)
3520 if (token
.value
== TOKrbracket
)
3522 t
= new TypeDArray(t
); // []
3525 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
3527 // It's an associative array declaration
3528 //printf("it's an associative array\n");
3529 Type
*index
= parseType(); // [ type ]
3530 t
= new TypeAArray(t
, index
);
3535 //printf("it's type[expression]\n");
3537 Expression
*e
= parseAssignExp(); // [ expression ]
3538 if (token
.value
== TOKslice
)
3541 Expression
*e2
= parseAssignExp(); // [ exp .. exp ]
3542 t
= new TypeSlice(t
, e
, e2
);
3546 t
= new TypeSArray(t
,e
);
3556 // Handle delegate declaration:
3557 // t delegate(parameter list) nothrow pure
3558 // t function(parameter list) nothrow pure
3559 TOK save
= token
.value
;
3563 Parameters
*parameters
= parseParameters(&varargs
);
3565 StorageClass stc
= parsePostfix(STCundefined
, NULL
);
3566 TypeFunction
*tf
= new TypeFunction(ParameterList(parameters
, varargs
),
3568 if (stc
& (STCconst
| STCimmutable
| STCshared
| STCwild
| STCreturn
))
3570 if (save
== TOKfunction
)
3571 error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
3573 tf
= (TypeFunction
*)tf
->addSTC(stc
);
3576 if (save
== TOKdelegate
)
3577 t
= new TypeDelegate(tf
);
3579 t
= new TypePointer(tf
); // pointer to function
3592 Type
*Parser::parseDeclarator(Type
*t
, int *palt
, Identifier
**pident
,
3593 TemplateParameters
**tpl
, StorageClass storageClass
, int *pdisable
, Expressions
**pudas
)
3595 //printf("parseDeclarator(tpl = %p)\n", tpl);
3596 t
= parseBasicType2(t
);
3599 switch (token
.value
)
3603 *pident
= token
.ident
;
3605 error("unexpected identifer `%s` in declarator", token
.ident
->toChars());
3613 // like: T ((*fp))();
3614 if (peekNext() == TOKmul
||
3615 peekNext() == TOKlparen
)
3617 /* Parse things with parentheses around the identifier, like:
3619 * although the D style would be:
3624 ts
= parseDeclarator(t
, palt
, pident
);
3630 Token
*peekt
= &token
;
3631 /* Completely disallow C-style things like:
3633 * Improve error messages for the common bug of a missing return type
3634 * by looking to see if (a) looks like a parameter list.
3636 if (isParameters(&peekt
))
3638 error("function declaration without return type. (Note that constructors are always named `this`)");
3641 error("unexpected ( in declarator");
3650 // parse DeclaratorSuffixes
3653 switch (token
.value
)
3656 /* Support C style array syntax:
3658 * as opposed to D-style:
3663 // This is the old C-style post [] syntax.
3666 if (token
.value
== TOKrbracket
)
3668 // It's a dynamic array
3669 ta
= new TypeDArray(t
); // []
3673 else if (isDeclaration(&token
, 0, TOKrbracket
, NULL
))
3675 // It's an associative array
3676 //printf("it's an associative array\n");
3677 Type
*index
= parseType(); // [ type ]
3679 ta
= new TypeAArray(t
, index
);
3684 //printf("It's a static array\n");
3685 Expression
*e
= parseAssignExp(); // [ expression ]
3686 ta
= new TypeSArray(t
, e
);
3694 * ts -> ... -> ta -> t
3697 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
3707 Token
*tk
= peekPastParen(&token
);
3708 if (tk
->value
== TOKlparen
)
3710 /* Look ahead to see if this is (...)(...),
3711 * i.e. a function template declaration
3713 //printf("function template declaration\n");
3715 // Gather template parameter list
3716 *tpl
= parseTemplateParameterList();
3718 else if (tk
->value
== TOKassign
)
3721 * i.e. a variable template declaration
3723 //printf("variable template declaration\n");
3724 *tpl
= parseTemplateParameterList();
3730 Parameters
*parameters
= parseParameters(&varargs
);
3732 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
3734 StorageClass stc
= parsePostfix(storageClass
, pudas
);
3735 // merge prefix storage classes
3736 Type
*tf
= new TypeFunction(ParameterList(parameters
, varargs
),
3738 tf
= tf
->addSTC(stc
);
3740 *pdisable
= stc
& STCdisable
? 1 : 0;
3745 * ts -> ... -> tf -> t
3748 for (pt
= &ts
; *pt
!= t
; pt
= &((TypeNext
*)*pt
)->next
)
3761 void Parser::parseStorageClasses(StorageClass
&storage_class
, LINK
&link
,
3762 bool &setAlignment
, Expression
*&ealign
, Expressions
*&udas
)
3765 bool sawLinkage
= false; // seen a linkage declaration
3769 switch (token
.value
)
3772 if (peek(&token
)->value
== TOKlparen
)
3773 break; // const as type constructor
3774 stc
= STCconst
; // const as storage class
3778 if (peek(&token
)->value
== TOKlparen
)
3784 if (peek(&token
)->value
== TOKlparen
)
3790 if (peek(&token
)->value
== TOKlparen
)
3795 case TOKstatic
: stc
= STCstatic
; goto L1
;
3796 case TOKfinal
: stc
= STCfinal
; goto L1
;
3797 case TOKauto
: stc
= STCauto
; goto L1
;
3798 case TOKscope
: stc
= STCscope
; goto L1
;
3799 case TOKoverride
: stc
= STCoverride
; goto L1
;
3800 case TOKabstract
: stc
= STCabstract
; goto L1
;
3801 case TOKsynchronized
: stc
= STCsynchronized
; goto L1
;
3802 case TOKdeprecated
: stc
= STCdeprecated
; goto L1
;
3803 case TOKnothrow
: stc
= STCnothrow
; goto L1
;
3804 case TOKpure
: stc
= STCpure
; goto L1
;
3805 case TOKref
: stc
= STCref
; goto L1
;
3806 case TOKgshared
: stc
= STCgshared
; goto L1
;
3807 case TOKenum
: stc
= STCmanifest
; goto L1
;
3810 stc
= parseAttribute(&udas
);
3816 storage_class
= appendStorageClass(storage_class
, stc
);
3822 if (peek(&token
)->value
!= TOKlparen
)
3829 error("redundant linkage declaration");
3831 Identifiers
*idents
= NULL
;
3832 CPPMANGLE cppmangle
= CPPMANGLEdefault
;
3833 bool cppMangleOnly
= false;
3834 link
= parseLinkage(&idents
, &cppmangle
, &cppMangleOnly
);
3837 error("C++ name spaces not allowed here");
3840 if (cppmangle
!= CPPMANGLEdefault
)
3842 error("C++ mangle declaration not allowed here");
3850 setAlignment
= true;
3851 if (token
.value
== TOKlparen
)
3854 ealign
= parseExpression();
3866 /**********************************
3867 * Parse Declarations.
3869 * 1. declarations at global/class level
3870 * 2. declarations at statement level
3871 * Return array of Declaration *'s.
3874 Dsymbols
*Parser::parseDeclarations(bool autodecl
, PrefixAttributes
*pAttrs
, const utf8_t
*comment
)
3876 StorageClass storage_class
= STCundefined
;
3881 TOK tok
= TOKreserved
;
3882 LINK link
= linkage
;
3883 bool setAlignment
= false;
3884 Expression
*ealign
= NULL
;
3885 Loc loc
= token
.loc
;
3886 Expressions
*udas
= NULL
;
3889 //printf("parseDeclarations() %s\n", token.toChars());
3891 comment
= token
.blockComment
;
3895 ts
= NULL
; // infer type
3899 if (token
.value
== TOKalias
)
3905 * alias identifier this;
3907 if (token
.value
== TOKidentifier
&& peekNext() == TOKthis
)
3909 AliasThis
*s
= new AliasThis(loc
, token
.ident
);
3912 check(TOKsemicolon
);
3913 Dsymbols
*a
= new Dsymbols();
3915 addComment(s
, comment
);
3919 * alias identifier = type;
3920 * alias identifier(...) = type;
3922 if (token
.value
== TOKidentifier
&&
3923 skipParensIf(peek(&token
), &tk
) &&
3924 tk
->value
== TOKassign
)
3926 Dsymbols
*a
= new Dsymbols();
3929 ident
= token
.ident
;
3931 TemplateParameters
*tpl
= NULL
;
3932 if (token
.value
== TOKlparen
)
3933 tpl
= parseTemplateParameterList();
3936 bool hasParsedAttributes
= false;
3937 if (token
.value
== TOKat
)
3939 if (!hasParsedAttributes
)
3941 hasParsedAttributes
= true;
3942 storage_class
= STCundefined
;
3944 setAlignment
= false;
3947 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
);
3952 if (token
.value
== TOKfunction
||
3953 token
.value
== TOKdelegate
||
3954 (token
.value
== TOKlparen
&&
3955 skipAttributes(peekPastParen(&token
), &tk
) &&
3956 (tk
->value
== TOKgoesto
|| tk
->value
== TOKlcurly
)) ||
3957 token
.value
== TOKlcurly
||
3958 (token
.value
== TOKidentifier
&& peekNext() == TOKgoesto
))
3960 // function (parameters) { statements... }
3961 // delegate (parameters) { statements... }
3962 // (parameters) { statements... }
3963 // (parameters) => expression
3964 // { statements... }
3965 // identifier => expression
3967 Dsymbol
*s
= parseFunctionLiteral();
3971 if (storage_class
!= 0)
3972 error("Cannot put a storage-class in an alias declaration.");
3973 // shouldn't have set these variables
3974 assert(link
== linkage
&& !setAlignment
&& ealign
== NULL
);
3975 TemplateDeclaration
*tpl_
= (TemplateDeclaration
*) s
;
3976 assert(tpl_
!= NULL
&& tpl_
->members
->length
== 1);
3977 FuncLiteralDeclaration
*fd
= (FuncLiteralDeclaration
*) (*tpl_
->members
)[0];
3978 TypeFunction
*tf
= (TypeFunction
*) fd
->type
;
3979 assert(tf
->parameterList
.length() > 0);
3980 Dsymbols
*as
= new Dsymbols();
3981 (*tf
->parameterList
.parameters
)[0]->userAttribDecl
= new UserAttributeDeclaration(udas
, as
);
3983 v
= new AliasDeclaration(loc
, ident
, s
);
3987 // StorageClasses type
3988 if (!hasParsedAttributes
)
3990 hasParsedAttributes
= true;
3991 storage_class
= STCundefined
;
3993 setAlignment
= false;
3996 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
);
4000 error("user-defined attributes not allowed for %s declarations", Token::toChars(tok
));
4003 v
= new AliasDeclaration(loc
, ident
, t
);
4005 v
->storage_class
= storage_class
;
4010 Dsymbols
*a2
= new Dsymbols();
4012 TemplateDeclaration
*tempdecl
=
4013 new TemplateDeclaration(loc
, ident
, tpl
, NULL
, a2
);
4018 Dsymbols
*ax
= new Dsymbols();
4020 s
= new AlignDeclaration(v
->loc
, ealign
, ax
);
4022 if (link
!= linkage
)
4024 Dsymbols
*a2
= new Dsymbols();
4026 s
= new LinkDeclaration(link
, a2
);
4030 switch (token
.value
)
4034 addComment(s
, comment
);
4038 addComment(s
, comment
);
4039 if (token
.value
!= TOKidentifier
)
4041 error("identifier expected following comma, not %s", token
.toChars());
4044 if (peekNext() != TOKassign
&& peekNext() != TOKlparen
)
4046 error("= expected following identifier");
4052 error("semicolon expected to close %s declaration", Token::toChars(tok
));
4060 // alias StorageClasses type ident;
4063 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
);
4065 if (token
.value
== TOKstruct
||
4066 token
.value
== TOKunion
||
4067 token
.value
== TOKclass
||
4068 token
.value
== TOKinterface
)
4070 Dsymbol
*s
= parseAggregate();
4071 Dsymbols
*a
= new Dsymbols();
4076 s
= new StorageClassDeclaration(storage_class
, a
);
4082 s
= new AlignDeclaration(s
->loc
, ealign
, a
);
4086 if (link
!= linkage
)
4088 s
= new LinkDeclaration(link
, a
);
4094 s
= new UserAttributeDeclaration(udas
, a
);
4099 addComment(s
, comment
);
4103 /* Look for auto initializers:
4104 * storage_class identifier = initializer;
4105 * storage_class identifier(...) = initializer;
4107 if ((storage_class
|| udas
) &&
4108 token
.value
== TOKidentifier
&&
4109 skipParensIf(peek(&token
), &tk
) &&
4110 tk
->value
== TOKassign
)
4112 Dsymbols
*a
= parseAutoDeclarations(storage_class
, comment
);
4115 Dsymbol
*s
= new UserAttributeDeclaration(udas
, a
);
4122 /* Look for return type inference for template functions.
4124 if ((storage_class
|| udas
) && token
.value
== TOKidentifier
&& skipParens(peek(&token
), &tk
) &&
4125 skipAttributes(tk
, &tk
) &&
4126 (tk
->value
== TOKlparen
|| tk
->value
== TOKlcurly
|| tk
->value
== TOKin
|| tk
->value
== TOKout
||
4127 tk
->value
== TOKdo
|| (tk
->value
== TOKidentifier
&& tk
->ident
== Id::_body
)))
4133 ts
= parseBasicType();
4134 ts
= parseBasicType2(ts
);
4139 Dsymbols
*a
= new Dsymbols();
4143 storage_class
|= pAttrs
->storageClass
;
4144 //pAttrs->storageClass = STCundefined;
4149 TemplateParameters
*tpl
= NULL
;
4155 t
= parseDeclarator(ts
, &alt
, &ident
, &tpl
, storage_class
, &disable
, &udas
);
4159 else if (t
!= tfirst
)
4160 error("multiple declarations must have the same type, not %s and %s",
4161 tfirst
->toChars(), t
->toChars());
4162 bool isThis
= (t
->ty
== Tident
&& ((TypeIdentifier
*)t
)->ident
== Id::This
&& token
.value
== TOKassign
);
4164 checkCstyleTypeSyntax(loc
, t
, alt
, ident
);
4166 error("no identifier for declarator %s", t
->toChars());
4168 if (tok
== TOKalias
)
4171 Initializer
*init
= NULL
;
4173 /* Aliases can no longer have multiple declarators, storage classes,
4174 * linkages, or auto declarations.
4175 * These never made any sense, anyway.
4176 * The code below needs to be fixed to reject them.
4177 * The grammar has already been fixed to preclude them.
4181 error("user-defined attributes not allowed for %s declarations", Token::toChars(tok
));
4183 if (token
.value
== TOKassign
)
4186 init
= parseInitializer();
4191 error("cannot use syntax `alias this = %s`, use `alias %s this` instead",
4192 init
->toChars(), init
->toChars());
4194 error("alias cannot have initializer");
4196 v
= new AliasDeclaration(loc
, ident
, t
);
4198 v
->storage_class
= storage_class
;
4201 /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
4202 * on prefix and postfix.
4203 * @safe alias void function() FP1;
4204 * alias @safe void function() FP2; // FP2 is not @safe
4205 * alias void function() @safe FP3;
4207 pAttrs
->storageClass
&= (STCsafe
| STCsystem
| STCtrusted
);
4211 if (link
!= linkage
)
4213 Dsymbols
*ax
= new Dsymbols();
4215 s
= new LinkDeclaration(link
, ax
);
4218 switch (token
.value
)
4222 addComment(s
, comment
);
4227 addComment(s
, comment
);
4231 error("semicolon expected to close %s declaration", Token::toChars(tok
));
4235 else if (t
->ty
== Tfunction
)
4237 Expression
*constraint
= NULL
;
4239 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
4240 FuncDeclaration
*f
=
4241 new FuncDeclaration(loc
, Loc(), ident
, storage_class
| (disable
? STCdisable
: 0), t
);
4243 pAttrs
->storageClass
= STCundefined
;
4245 constraint
= parseConstraint();
4246 Dsymbol
*s
= parseContracts(f
);
4247 Identifier
*tplIdent
= s
->ident
;
4248 if (link
!= linkage
)
4250 Dsymbols
*ax
= new Dsymbols();
4252 s
= new LinkDeclaration(link
, ax
);
4256 Dsymbols
*ax
= new Dsymbols();
4258 s
= new UserAttributeDeclaration(udas
, ax
);
4261 /* A template parameter list means it's a function template
4265 // Wrap a template around the function declaration
4266 Dsymbols
*decldefs
= new Dsymbols();
4268 TemplateDeclaration
*tempdecl
=
4269 new TemplateDeclaration(loc
, tplIdent
, tpl
, constraint
, decldefs
);
4272 if (storage_class
& STCstatic
)
4274 assert(f
->storage_class
& STCstatic
);
4275 f
->storage_class
&= ~STCstatic
;
4277 Dsymbols
*ax
= new Dsymbols();
4279 s
= new StorageClassDeclaration(STCstatic
, ax
);
4283 addComment(s
, comment
);
4287 Initializer
*init
= NULL
;
4288 if (token
.value
== TOKassign
)
4291 init
= parseInitializer();
4294 VarDeclaration
*v
= new VarDeclaration(loc
, t
, ident
, init
);
4295 v
->storage_class
= storage_class
;
4297 pAttrs
->storageClass
= STCundefined
;
4303 Dsymbols
*a2
= new Dsymbols();
4305 TemplateDeclaration
*tempdecl
=
4306 new TemplateDeclaration(loc
, ident
, tpl
, NULL
, a2
, 0);
4309 if (link
!= linkage
)
4311 Dsymbols
*ax
= new Dsymbols();
4313 s
= new LinkDeclaration(link
, ax
);
4317 Dsymbols
*ax
= new Dsymbols();
4319 s
= new UserAttributeDeclaration(udas
, ax
);
4322 switch (token
.value
)
4326 addComment(s
, comment
);
4331 addComment(s
, comment
);
4335 error("semicolon expected, not `%s`", token
.toChars());
4344 Dsymbol
*Parser::parseFunctionLiteral()
4346 Loc loc
= token
.loc
;
4348 TemplateParameters
*tpl
= NULL
;
4349 Parameters
*parameters
= NULL
;
4350 VarArg varargs
= VARARGnone
;
4352 StorageClass stc
= 0;
4353 TOK save
= TOKreserved
;
4355 switch (token
.value
)
4361 if (token
.value
!= TOKlparen
&& token
.value
!= TOKlcurly
)
4363 // function type (parameters) { statements... }
4364 // delegate type (parameters) { statements... }
4365 tret
= parseBasicType();
4366 tret
= parseBasicType2(tret
); // function return type
4369 if (token
.value
== TOKlparen
)
4371 // function (parameters) { statements... }
4372 // delegate (parameters) { statements... }
4376 // function { statements... }
4377 // delegate { statements... }
4384 // (parameters) => expression
4385 // (parameters) { statements... }
4386 parameters
= parseParameters(&varargs
, &tpl
);
4387 stc
= parsePostfix(STCundefined
, NULL
);
4388 if (StorageClass modStc
= stc
& STC_TYPECTOR
)
4390 if (save
== TOKfunction
)
4393 stcToBuffer(&buf
, modStc
);
4394 error("function literal cannot be %s", buf
.peekChars());
4402 // { statements... }
4407 // identifier => expression
4408 parameters
= new Parameters();
4409 Identifier
*id
= Identifier::generateId("__T");
4410 Type
*t
= new TypeIdentifier(loc
, id
);
4411 parameters
->push(new Parameter(0, t
, token
.ident
, NULL
, NULL
));
4413 tpl
= new TemplateParameters();
4414 TemplateParameter
*tp
= new TemplateTypeParameter(loc
, id
, NULL
, NULL
);
4425 parameters
= new Parameters();
4426 TypeFunction
*tf
= new TypeFunction(ParameterList(parameters
, varargs
),
4427 tret
, linkage
, stc
);
4428 tf
= (TypeFunction
*)tf
->addSTC(stc
);
4429 FuncLiteralDeclaration
*fd
= new FuncLiteralDeclaration(loc
, Loc(), tf
, save
, NULL
);
4431 if (token
.value
== TOKgoesto
)
4434 Loc returnloc
= token
.loc
;
4435 Expression
*ae
= parseAssignExp();
4436 fd
->fbody
= new ReturnStatement(returnloc
, ae
);
4437 fd
->endloc
= token
.loc
;
4446 // Wrap a template around function fd
4447 Dsymbols
*decldefs
= new Dsymbols();
4449 return new TemplateDeclaration(fd
->loc
, fd
->ident
, tpl
, NULL
, decldefs
, false, true);
4455 /*****************************************
4456 * Parse auto declarations of the form:
4457 * storageClass ident = init, ident = init, ... ;
4458 * and return the array of them.
4459 * Starts with token on the first ident.
4460 * Ends with scanner past closing ';'
4463 Dsymbols
*Parser::parseAutoDeclarations(StorageClass storageClass
, const utf8_t
*comment
)
4465 //printf("parseAutoDeclarations\n");
4467 Dsymbols
*a
= new Dsymbols
;
4471 Loc loc
= token
.loc
;
4472 Identifier
*ident
= token
.ident
;
4473 nextToken(); // skip over ident
4475 TemplateParameters
*tpl
= NULL
;
4476 if (token
.value
== TOKlparen
)
4477 tpl
= parseTemplateParameterList();
4479 check(TOKassign
); // skip over '='
4480 Initializer
*init
= parseInitializer();
4481 VarDeclaration
*v
= new VarDeclaration(loc
, NULL
, ident
, init
);
4482 v
->storage_class
= storageClass
;
4487 Dsymbols
*a2
= new Dsymbols();
4489 TemplateDeclaration
*tempdecl
=
4490 new TemplateDeclaration(loc
, ident
, tpl
, NULL
, a2
, 0);
4494 switch (token
.value
)
4498 addComment(s
, comment
);
4503 if (!(token
.value
== TOKidentifier
&&
4504 skipParensIf(peek(&token
), &tk
) &&
4505 tk
->value
== TOKassign
))
4507 error("identifier expected following comma");
4510 addComment(s
, comment
);
4514 error("semicolon expected following auto declaration, not `%s`", token
.toChars());
4522 /*****************************************
4523 * Parse contracts following function declaration.
4526 FuncDeclaration
*Parser::parseContracts(FuncDeclaration
*f
)
4528 LINK linksave
= linkage
;
4530 bool literal
= f
->isFuncLiteralDeclaration() != NULL
;
4532 // The following is irrelevant, as it is overridden by sc->linkage in
4533 // TypeFunction::semantic
4534 linkage
= LINKd
; // nested functions have D linkage
4535 bool requireDo
= false;
4537 switch (token
.value
)
4541 error("missing body { ... } after in or out");
4542 f
->fbody
= parseStatement(PSsemi
);
4547 if (token
.ident
!= Id::_body
)
4553 f
->fbody
= parseStatement(PScurly
);
4559 // in { statements... }
4561 Loc loc
= token
.loc
;
4565 f
->frequires
= new Statements();
4567 if (token
.value
== TOKlparen
)
4570 Expression
*e
= parseAssignExp();
4571 Expression
*msg
= NULL
;
4572 if (token
.value
== TOKcomma
)
4575 if (token
.value
!= TOKrparen
)
4577 msg
= parseAssignExp();
4578 if (token
.value
== TOKcomma
)
4583 e
= new AssertExp(loc
, e
, msg
);
4584 f
->frequires
->push(new ExpStatement(loc
, e
));
4589 f
->frequires
->push(parseStatement(PScurly
| PSscope
));
4597 // out { statements... }
4598 // out (; expression)
4599 // out (identifier) { statements... }
4600 // out (identifier; expression)
4601 Loc loc
= token
.loc
;
4605 f
->fensures
= new Ensures();
4607 Identifier
*id
= NULL
;
4608 if (token
.value
!= TOKlcurly
)
4611 if (token
.value
!= TOKidentifier
&& token
.value
!= TOKsemicolon
)
4612 error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token
.toChars());
4613 if (token
.value
!= TOKsemicolon
)
4618 if (token
.value
== TOKsemicolon
)
4621 Expression
*e
= parseAssignExp();
4622 Expression
*msg
= NULL
;
4623 if (token
.value
== TOKcomma
)
4626 if (token
.value
!= TOKrparen
)
4628 msg
= parseAssignExp();
4629 if (token
.value
== TOKcomma
)
4634 e
= new AssertExp(loc
, e
, msg
);
4635 f
->fensures
->push(Ensure(id
, new ExpStatement(loc
, e
)));
4641 f
->fensures
->push(Ensure(id
, parseStatement(PScurly
| PSscope
)));
4649 // Bugzilla 15799: Semicolon becomes a part of function declaration
4650 // only when 'do' is not required
4661 const char *sbody
= requireDo
? "do " : "";
4662 error("missing %s{ ... } for function literal", sbody
);
4664 else if (!requireDo
) // allow these even with no body
4666 error("semicolon expected following function declaration");
4670 if (literal
&& !f
->fbody
)
4672 // Set empty function body for error recovery
4673 f
->fbody
= new CompoundStatement(Loc(), (Statement
*)NULL
);
4681 /*****************************************
4682 * Parse initializer for variable declaration.
4685 Initializer
*Parser::parseInitializer()
4687 StructInitializer
*is
;
4688 ArrayInitializer
*ia
;
4694 Loc loc
= token
.loc
;
4699 switch (token
.value
)
4702 /* Scan ahead to see if it is a struct initializer or
4703 * a function literal.
4704 * If it contains a ';', it is a function literal.
4705 * Treat { } as a struct initializer.
4708 for (t
= peek(&token
); 1; t
= peek(t
))
4734 is
= new StructInitializer(loc
);
4739 switch (token
.value
)
4743 error("comma expected separating field initializers");
4745 if (t
->value
== TOKcolon
)
4749 nextToken(); // skip over ':'
4754 value
= parseInitializer();
4755 is
->addInit(id
, value
);
4761 error("expression expected, not `,`");
4766 case TOKrcurly
: // allow trailing comma's
4771 error("found EOF instead of initializer");
4776 error("comma expected separating field initializers");
4777 value
= parseInitializer();
4778 is
->addInit(NULL
, value
);
4781 //error("found `%s` instead of field initializer", token.toChars());
4789 /* Scan ahead to see if it is an array initializer or
4791 * If it ends with a ';' ',' or '}', it is an array initializer.
4794 for (t
= peek(&token
); 1; t
= peek(t
))
4803 if (--brackets
== 0)
4805 if (t
->value
!= TOKsemicolon
&&
4806 t
->value
!= TOKcomma
&&
4807 t
->value
!= TOKrbracket
&&
4808 t
->value
!= TOKrcurly
)
4823 ia
= new ArrayInitializer(loc
);
4828 switch (token
.value
)
4832 { error("comma expected separating array initializers, not %s", token
.toChars());
4836 e
= parseAssignExp();
4839 if (token
.value
== TOKcolon
)
4842 value
= parseInitializer();
4845 { value
= new ExpInitializer(e
->loc
, e
);
4848 ia
->addInit(e
, value
);
4855 error("comma expected separating array initializers, not %s", token
.toChars());
4856 value
= parseInitializer();
4857 if (token
.value
== TOKcolon
)
4860 e
= initializerToExpression(value
);
4861 value
= parseInitializer();
4865 ia
->addInit(e
, value
);
4871 error("expression expected, not `,`");
4876 case TOKrbracket
: // allow trailing comma's
4881 error("found `%s` instead of array initializer", token
.toChars());
4890 if (t
->value
== TOKsemicolon
|| t
->value
== TOKcomma
)
4893 return new VoidInitializer(loc
);
4899 e
= parseAssignExp();
4900 ie
= new ExpInitializer(loc
, e
);
4905 /*****************************************
4906 * Parses default argument initializer expression that is an assign expression,
4907 * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
4910 Expression
*Parser::parseDefaultInitExp()
4912 if (token
.value
== TOKfile
||
4913 token
.value
== TOKfilefullpath
||
4914 token
.value
== TOKline
||
4915 token
.value
== TOKmodulestring
||
4916 token
.value
== TOKfuncstring
||
4917 token
.value
== TOKprettyfunc
)
4919 Token
*t
= peek(&token
);
4920 if (t
->value
== TOKcomma
|| t
->value
== TOKrparen
)
4922 Expression
*e
= NULL
;
4923 if (token
.value
== TOKfile
)
4924 e
= new FileInitExp(token
.loc
, TOKfile
);
4925 else if (token
.value
== TOKfilefullpath
)
4926 e
= new FileInitExp(token
.loc
, TOKfilefullpath
);
4927 else if (token
.value
== TOKline
)
4928 e
= new LineInitExp(token
.loc
);
4929 else if (token
.value
== TOKmodulestring
)
4930 e
= new ModuleInitExp(token
.loc
);
4931 else if (token
.value
== TOKfuncstring
)
4932 e
= new FuncInitExp(token
.loc
);
4933 else if (token
.value
== TOKprettyfunc
)
4934 e
= new PrettyFuncInitExp(token
.loc
);
4942 Expression
*e
= parseAssignExp();
4946 /*****************************************
4949 void Parser::checkDanglingElse(Loc elseloc
)
4951 if (token
.value
!= TOKelse
&&
4952 token
.value
!= TOKcatch
&&
4953 token
.value
!= TOKfinally
&&
4954 lookingForElse
.linnum
!= 0)
4956 warning(elseloc
, "else is dangling, add { } after condition at %s", lookingForElse
.toChars());
4960 void Parser::checkCstyleTypeSyntax(Loc loc
, Type
*t
, int alt
, Identifier
*ident
)
4965 const char *sp
= !ident
? "" : " ";
4966 const char *s
= !ident
? "" : ident
->toChars();
4967 if (alt
& 1) // contains C-style function pointer syntax
4968 error(loc
, "instead of C-style syntax, use D-style `%s%s%s`", t
->toChars(), sp
, s
);
4970 ::warning(loc
, "instead of C-style syntax, use D-style syntax `%s%s%s`", t
->toChars(), sp
, s
);
4974 /*****************************************
4975 * Parses `foreach` statements, `static foreach` statements and
4976 * `static foreach` declarations. The template parameter
4977 * `isStatic` is true, iff a `static foreach` should be parsed.
4978 * If `isStatic` is true, `isDecl` can be true to indicate that a
4979 * `static foreach` declaration should be parsed.
4981 Statement
*Parser::parseForeach(Loc loc
, bool *isRange
, bool isDecl
)
4983 TOK op
= token
.value
;
4988 Parameters
*parameters
= new Parameters();
4992 Identifier
*ai
= NULL
;
4995 StorageClass storageClass
= 0;
4996 StorageClass stc
= 0;
5000 storageClass
= appendStorageClass(storageClass
, stc
);
5003 switch (token
.value
)
5014 storageClass
= appendStorageClass(storageClass
, STCalias
);
5019 if (peekNext() != TOKlparen
)
5027 if (peekNext() != TOKlparen
)
5035 if (peekNext() != TOKlparen
)
5043 if (peekNext() != TOKlparen
)
5053 if (token
.value
== TOKidentifier
)
5055 Token
*t
= peek(&token
);
5056 if (t
->value
== TOKcomma
|| t
->value
== TOKsemicolon
)
5058 at
= NULL
; // infer argument type
5063 at
= parseType(&ai
);
5065 error("no identifier for declarator %s", at
->toChars());
5067 Parameter
*p
= new Parameter(storageClass
, at
, ai
, NULL
, NULL
);
5068 parameters
->push(p
);
5069 if (token
.value
== TOKcomma
)
5075 check(TOKsemicolon
);
5077 Expression
*aggr
= parseExpression();
5078 if (token
.value
== TOKslice
&& parameters
->length
== 1)
5080 Parameter
*p
= (*parameters
)[0];
5083 Expression
*upr
= parseExpression();
5086 Statement
*body
= (!isDecl
) ? parseStatement(0, NULL
, &endloc
) : NULL
;
5089 return new ForeachRangeStatement(loc
, op
, p
, aggr
, upr
, body
, endloc
);
5095 Statement
*body
= (!isDecl
) ? parseStatement(0, NULL
, &endloc
) : NULL
;
5098 return new ForeachStatement(loc
, op
, parameters
, aggr
, body
, endloc
);
5102 Dsymbol
*Parser::parseForeachStaticDecl(Loc loc
, Dsymbol
**pLastDecl
)
5106 bool isRange
= false;
5107 Statement
*s
= parseForeach(loc
, &isRange
, true);
5109 return new StaticForeachDeclaration(
5110 new StaticForeach(loc
, isRange
? NULL
: (ForeachStatement
*)s
,
5111 isRange
? (ForeachRangeStatement
*)s
: NULL
),
5112 parseBlock(pLastDecl
)
5116 Statement
*Parser::parseForeachStatic(Loc loc
)
5120 bool isRange
= false;
5121 Statement
*s
= parseForeach(loc
, &isRange
, false);
5123 return new StaticForeachStatement(loc
,
5124 new StaticForeach(loc
, isRange
? NULL
: (ForeachStatement
*)s
,
5125 isRange
? (ForeachRangeStatement
*)s
: NULL
)
5129 /*****************************************
5133 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
5136 Statement
*Parser::parseStatement(int flags
, const utf8_t
** endPtr
, Loc
*pEndloc
)
5138 Statement
*s
= NULL
;
5141 Statement
*elsebody
;
5143 Loc loc
= token
.loc
;
5145 //printf("parseStatement()\n");
5147 if (flags
& PScurly
&& token
.value
!= TOKlcurly
)
5148 error("statement expected to be { }, not %s", token
.toChars());
5150 switch (token
.value
)
5153 { /* A leading identifier can be a declaration, label, or expression.
5154 * The easiest case to check first is label:
5156 Token
*t
= peek(&token
);
5157 if (t
->value
== TOKcolon
)
5159 Token
*nt
= peek(t
);
5160 if (nt
->value
== TOKcolon
)
5166 error("use `.` for member lookup, not `::`");
5170 Identifier
*ident
= token
.ident
;
5173 if (token
.value
== TOKrcurly
)
5175 else if (token
.value
== TOKlcurly
)
5176 s
= parseStatement(PScurly
| PSscope
);
5178 s
= parseStatement(PSsemi_ok
);
5179 s
= new LabelStatement(loc
, ident
, s
);
5188 /* Bugzilla 15163: If tokens can be handled as
5189 * old C-style declaration or D expression, prefer the latter.
5191 if (isDeclaration(&token
, 3, TOKreserved
, NULL
))
5209 case TOKimaginary32v
:
5210 case TOKimaginary64v
:
5211 case TOKimaginary80v
:
5237 case TOKfilefullpath
:
5239 case TOKmodulestring
:
5244 Expression
*exp
= parseExpression();
5245 check(TOKsemicolon
, "statement");
5246 s
= new ExpStatement(loc
, exp
);
5251 { // Look ahead to see if it's static assert() or static if()
5253 Token
*t
= peek(&token
);
5254 if (t
->value
== TOKassert
)
5256 s
= new StaticAssertStatement(parseStaticAssert());
5259 if (t
->value
== TOKif
)
5261 cond
= parseStaticIfCondition();
5264 else if (t
->value
== TOKforeach
|| t
->value
== TOKforeach_reverse
)
5266 s
= parseForeachStatic(loc
);
5267 if (flags
& PSscope
)
5268 s
= new ScopeStatement(loc
, s
, token
.loc
);
5271 if (t
->value
== TOKimport
)
5273 Dsymbols
*imports
= parseImport();
5274 s
= new ImportStatement(loc
, imports
);
5275 if (flags
& PSscope
)
5276 s
= new ScopeStatement(loc
, s
, token
.loc
);
5283 if (peekNext() == TOKswitch
)
5291 case TOKwchar
: case TOKdchar
:
5292 case TOKbool
: case TOKchar
:
5293 case TOKint8
: case TOKuns8
:
5294 case TOKint16
: case TOKuns16
:
5295 case TOKint32
: case TOKuns32
:
5296 case TOKint64
: case TOKuns64
:
5297 case TOKint128
: case TOKuns128
:
5298 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
5299 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
5300 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
5302 // bug 7773: int.max is always a part of expression
5303 if (peekNext() == TOKdot
)
5305 if (peekNext() == TOKlparen
)
5330 Dsymbols
*a
= parseDeclarations(false, NULL
, NULL
);
5333 Statements
*as
= new Statements();
5334 as
->reserve(a
->length
);
5335 for (size_t i
= 0; i
< a
->length
; i
++)
5337 Dsymbol
*d
= (*a
)[i
];
5338 s
= new ExpStatement(loc
, d
);
5341 s
= new CompoundDeclarationStatement(loc
, as
);
5343 else if (a
->length
== 1)
5345 Dsymbol
*d
= (*a
)[0];
5346 s
= new ExpStatement(loc
, d
);
5349 s
= new ExpStatement(loc
, (Expression
*)NULL
);
5350 if (flags
& PSscope
)
5351 s
= new ScopeStatement(loc
, s
, token
.loc
);
5356 { /* Determine if this is a manifest constant declaration,
5357 * or a conventional enum.
5360 Token
*t
= peek(&token
);
5361 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
)
5363 else if (t
->value
!= TOKidentifier
)
5368 if (t
->value
== TOKlcurly
|| t
->value
== TOKcolon
||
5369 t
->value
== TOKsemicolon
)
5374 s
= new ExpStatement(loc
, d
);
5375 if (flags
& PSscope
)
5376 s
= new ScopeStatement(loc
, s
, token
.loc
);
5381 { Token
*t
= peek(&token
);
5382 if (t
->value
== TOKlparen
)
5384 Expression
*e
= parseAssignExp();
5385 check(TOKsemicolon
);
5386 if (e
->op
== TOKmixin
)
5388 CompileExp
*cpe
= (CompileExp
*)e
;
5389 s
= new CompileStatement(loc
, cpe
->e1
);
5393 s
= new ExpStatement(loc
, e
);
5397 Dsymbol
*d
= parseMixin();
5398 s
= new ExpStatement(loc
, d
);
5399 if (flags
& PSscope
)
5400 s
= new ScopeStatement(loc
, s
, token
.loc
);
5406 Loc lookingForElseSave
= lookingForElse
;
5407 lookingForElse
= Loc();
5410 //if (token.value == TOKsemicolon)
5411 //error("use `{ }` for an empty statement, not a `;`");
5412 Statements
*statements
= new Statements();
5413 while (token
.value
!= TOKrcurly
&& token
.value
!= TOKeof
)
5415 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
5417 if (endPtr
) *endPtr
= token
.ptr
;
5421 *pEndloc
= token
.loc
;
5422 pEndloc
= NULL
; // don't set it again
5424 s
= new CompoundStatement(loc
, statements
);
5425 if (flags
& (PSscope
| PScurlyscope
))
5426 s
= new ScopeStatement(loc
, s
, token
.loc
);
5427 check(TOKrcurly
, "compound statement");
5428 lookingForElse
= lookingForElseSave
;
5436 Expression
*condition
= parseExpression();
5439 Statement
*body
= parseStatement(PSscope
, NULL
, &endloc
);
5440 s
= new WhileStatement(loc
, condition
, body
, endloc
);
5445 if (!(flags
& PSsemi_ok
))
5448 deprecation("use `{ }` for an empty statement, not a `;`");
5450 error("use `{ }` for an empty statement, not a `;`");
5453 s
= new ExpStatement(loc
, (Expression
*)NULL
);
5458 Expression
*condition
;
5461 Loc lookingForElseSave
= lookingForElse
;
5462 lookingForElse
= Loc();
5463 body
= parseStatement(PSscope
);
5464 lookingForElse
= lookingForElseSave
;
5467 condition
= parseExpression();
5469 if (token
.value
== TOKsemicolon
)
5472 error("terminating `;` required after do-while statement");
5473 s
= new DoStatement(loc
, body
, condition
, token
.loc
);
5480 Expression
*condition
;
5481 Expression
*increment
;
5485 if (token
.value
== TOKsemicolon
)
5491 Loc lookingForElseSave
= lookingForElse
;
5492 lookingForElse
= Loc();
5493 init
= parseStatement(0);
5494 lookingForElse
= lookingForElseSave
;
5496 if (token
.value
== TOKsemicolon
)
5503 condition
= parseExpression();
5504 check(TOKsemicolon
, "for condition");
5506 if (token
.value
== TOKrparen
)
5511 { increment
= parseExpression();
5515 Statement
*body
= parseStatement(PSscope
, NULL
, &endloc
);
5516 s
= new ForStatement(loc
, init
, condition
, increment
, body
, endloc
);
5521 case TOKforeach_reverse
:
5523 s
= parseForeach(loc
, NULL
, false);
5529 Parameter
*param
= NULL
;
5530 Expression
*condition
;
5535 StorageClass storageClass
= 0;
5536 StorageClass stc
= 0;
5540 storageClass
= appendStorageClass(storageClass
, stc
);
5543 switch (token
.value
)
5552 if (peekNext() != TOKlparen
)
5559 if (peekNext() != TOKlparen
)
5566 if (peekNext() != TOKlparen
)
5573 if (peekNext() != TOKlparen
)
5583 if (storageClass
!= 0 &&
5584 token
.value
== TOKidentifier
&&
5585 peek(&token
)->value
== TOKassign
)
5587 Identifier
*ai
= token
.ident
;
5588 Type
*at
= NULL
; // infer parameter type
5591 param
= new Parameter(storageClass
, at
, ai
, NULL
, NULL
);
5593 else if (isDeclaration(&token
, 2, TOKassign
, NULL
))
5596 Type
*at
= parseType(&ai
);
5598 param
= new Parameter(storageClass
, at
, ai
, NULL
, NULL
);
5601 condition
= parseExpression();
5604 Loc lookingForElseSave
= lookingForElse
;
5605 lookingForElse
= loc
;
5606 ifbody
= parseStatement(PSscope
);
5607 lookingForElse
= lookingForElseSave
;
5609 if (token
.value
== TOKelse
)
5611 Loc elseloc
= token
.loc
;
5613 elsebody
= parseStatement(PSscope
);
5614 checkDanglingElse(elseloc
);
5618 if (condition
&& ifbody
)
5619 s
= new IfStatement(loc
, param
, condition
, ifbody
, elsebody
, token
.loc
);
5621 s
= NULL
; // don't propagate parsing errors
5626 if (peek(&token
)->value
!= TOKlparen
)
5627 goto Ldeclaration
; // scope used as storage class
5630 if (token
.value
!= TOKidentifier
)
5631 { error("scope identifier expected");
5635 { TOK t
= TOKon_scope_exit
;
5636 Identifier
*id
= token
.ident
;
5639 t
= TOKon_scope_exit
;
5640 else if (id
== Id::failure
)
5641 t
= TOKon_scope_failure
;
5642 else if (id
== Id::success
)
5643 t
= TOKon_scope_success
;
5645 error("valid scope identifiers are exit, failure, or success, not %s", id
->toChars());
5648 Statement
*st
= parseStatement(PSscope
);
5649 s
= new ScopeGuardStatement(loc
, t
, st
);
5655 if (token
.value
== TOKassign
)
5657 error("debug conditions can only be declared at module scope");
5662 cond
= parseDebugCondition();
5667 if (token
.value
== TOKassign
)
5669 error("version conditions can only be declared at module scope");
5674 cond
= parseVersionCondition();
5679 Loc lookingForElseSave
= lookingForElse
;
5680 lookingForElse
= loc
;
5681 ifbody
= parseStatement(0);
5682 lookingForElse
= lookingForElseSave
;
5685 if (token
.value
== TOKelse
)
5687 Loc elseloc
= token
.loc
;
5689 elsebody
= parseStatement(0);
5690 checkDanglingElse(elseloc
);
5692 s
= new ConditionalStatement(loc
, cond
, ifbody
, elsebody
);
5693 if (flags
& PSscope
)
5694 s
= new ScopeStatement(loc
, s
, token
.loc
);
5698 { Identifier
*ident
;
5699 Expressions
*args
= NULL
;
5704 if (token
.value
!= TOKidentifier
)
5705 { error("pragma(identifier expected");
5708 ident
= token
.ident
;
5710 if (token
.value
== TOKcomma
&& peekNext() != TOKrparen
)
5711 args
= parseArguments(); // pragma(identifier, args...);
5713 check(TOKrparen
); // pragma(identifier);
5714 if (token
.value
== TOKsemicolon
)
5719 body
= parseStatement(PSsemi
);
5720 s
= new PragmaStatement(loc
, ident
, args
, body
);
5732 Expression
*condition
= parseExpression();
5734 Statement
*body
= parseStatement(PSscope
);
5735 s
= new SwitchStatement(loc
, condition
, body
, isfinal
);
5741 Expressions cases
; // array of Expression's
5742 Expression
*last
= NULL
;
5747 exp
= parseAssignExp();
5749 if (token
.value
!= TOKcomma
)
5754 /* case exp: .. case last:
5756 if (token
.value
== TOKslice
)
5758 if (cases
.length
> 1)
5759 error("only one case allowed for start of case range");
5762 last
= parseAssignExp();
5766 if (flags
& PScurlyscope
)
5768 Statements
*statements
= new Statements();
5769 while (token
.value
!= TOKcase
&&
5770 token
.value
!= TOKdefault
&&
5771 token
.value
!= TOKeof
&&
5772 token
.value
!= TOKrcurly
)
5774 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
5776 s
= new CompoundStatement(loc
, statements
);
5779 s
= parseStatement(PSsemi
| PScurlyscope
);
5780 s
= new ScopeStatement(loc
, s
, token
.loc
);
5784 s
= new CaseRangeStatement(loc
, exp
, last
, s
);
5788 // Keep cases in order by building the case statements backwards
5789 for (size_t i
= cases
.length
; i
; i
--)
5792 s
= new CaseStatement(loc
, exp
, s
);
5803 if (flags
& PScurlyscope
)
5805 Statements
*statements
= new Statements();
5806 while (token
.value
!= TOKcase
&&
5807 token
.value
!= TOKdefault
&&
5808 token
.value
!= TOKeof
&&
5809 token
.value
!= TOKrcurly
)
5811 statements
->push(parseStatement(PSsemi
| PScurlyscope
));
5813 s
= new CompoundStatement(loc
, statements
);
5816 s
= parseStatement(PSsemi
| PScurlyscope
);
5817 s
= new ScopeStatement(loc
, s
, token
.loc
);
5818 s
= new DefaultStatement(loc
, s
);
5826 if (token
.value
== TOKsemicolon
)
5829 exp
= parseExpression();
5830 check(TOKsemicolon
, "return statement");
5831 s
= new ReturnStatement(loc
, exp
);
5836 { Identifier
*ident
;
5839 if (token
.value
== TOKidentifier
)
5840 { ident
= token
.ident
;
5845 check(TOKsemicolon
, "break statement");
5846 s
= new BreakStatement(loc
, ident
);
5851 { Identifier
*ident
;
5854 if (token
.value
== TOKidentifier
)
5855 { ident
= token
.ident
;
5860 check(TOKsemicolon
, "continue statement");
5861 s
= new ContinueStatement(loc
, ident
);
5866 { Identifier
*ident
;
5869 if (token
.value
== TOKdefault
)
5872 s
= new GotoDefaultStatement(loc
);
5874 else if (token
.value
== TOKcase
)
5876 Expression
*exp
= NULL
;
5879 if (token
.value
!= TOKsemicolon
)
5880 exp
= parseExpression();
5881 s
= new GotoCaseStatement(loc
, exp
);
5885 if (token
.value
!= TOKidentifier
)
5887 error("identifier expected following goto");
5892 ident
= token
.ident
;
5895 s
= new GotoStatement(loc
, ident
);
5897 check(TOKsemicolon
, "goto statement");
5901 case TOKsynchronized
:
5905 Token
*t
= peek(&token
);
5906 if (skipAttributes(t
, &t
) && t
->value
== TOKclass
)
5910 if (token
.value
== TOKlparen
)
5913 exp
= parseExpression();
5918 body
= parseStatement(PSscope
);
5919 s
= new SynchronizedStatement(loc
, exp
, body
);
5929 exp
= parseExpression();
5931 body
= parseStatement(PSscope
);
5932 s
= new WithStatement(loc
, exp
, body
, token
.loc
);
5938 Catches
*catches
= NULL
;
5939 Statement
*finalbody
= NULL
;
5942 Loc lookingForElseSave
= lookingForElse
;
5943 lookingForElse
= Loc();
5944 body
= parseStatement(PSscope
);
5945 lookingForElse
= lookingForElseSave
;
5946 while (token
.value
== TOKcatch
)
5952 Loc catchloc
= token
.loc
;
5955 if (token
.value
== TOKlcurly
|| token
.value
!= TOKlparen
)
5967 handler
= parseStatement(0);
5968 c
= new Catch(catchloc
, t
, id
, handler
);
5970 catches
= new Catches();
5974 if (token
.value
== TOKfinally
)
5977 finalbody
= parseStatement(PSscope
);
5981 if (!catches
&& !finalbody
)
5982 error("catch or finally expected following try");
5985 s
= new TryCatchStatement(loc
, body
, catches
);
5987 s
= new TryFinallyStatement(loc
, s
, finalbody
);
5996 exp
= parseExpression();
5997 check(TOKsemicolon
, "throw statement");
5998 s
= new ThrowStatement(loc
, exp
);
6004 // Parse the asm block into a sequence of AsmStatements,
6005 // each AsmStatement is one instruction.
6006 // Separate out labels.
6007 // Defer parsing of AsmStatements until semantic processing.
6012 StorageClass stc
= parsePostfix(STCundefined
, NULL
);
6013 if (stc
& (STCconst
| STCimmutable
| STCshared
| STCwild
))
6014 error("const/immutable/shared/inout attributes are not allowed on asm blocks");
6017 Token
*toklist
= NULL
;
6018 Token
**ptoklist
= &toklist
;
6019 Identifier
*label
= NULL
;
6020 Statements
*statements
= new Statements();
6021 size_t nestlevel
= 0;
6024 switch (token
.value
)
6029 // Look ahead to see if it is a label
6030 Token
*t
= peek(&token
);
6031 if (t
->value
== TOKcolon
)
6033 label
= token
.ident
;
6034 labelloc
= token
.loc
;
6053 if (toklist
|| label
)
6055 error("asm statements must end in `;`");
6061 error("mismatched number of curly brackets");
6064 if (toklist
|| label
)
6066 // Create AsmStatement from list of tokens we've saved
6067 s
= new AsmStatement(token
.loc
, toklist
);
6069 ptoklist
= &toklist
;
6071 { s
= new LabelStatement(labelloc
, label
, s
);
6074 statements
->push(s
);
6081 error("matching `}` expected, not end of file");
6087 *ptoklist
= Token::alloc();
6088 memcpy(*ptoklist
, &token
, sizeof(Token
));
6089 ptoklist
= &(*ptoklist
)->next
;
6097 s
= new CompoundAsmStatement(loc
, statements
, stc
);
6104 Dsymbols
*imports
= parseImport();
6105 s
= new ImportStatement(loc
, imports
);
6106 if (flags
& PSscope
)
6107 s
= new ScopeStatement(loc
, s
, token
.loc
);
6113 Dsymbol
*d
= parseTemplateDeclaration();
6114 s
= new ExpStatement(loc
, d
);
6119 error("found `%s` instead of statement", token
.toChars());
6123 while (token
.value
!= TOKrcurly
&&
6124 token
.value
!= TOKsemicolon
&&
6125 token
.value
!= TOKeof
)
6127 if (token
.value
== TOKsemicolon
)
6133 *pEndloc
= token
.loc
;
6137 void Parser::check(TOK value
)
6139 check(token
.loc
, value
);
6142 void Parser::check(Loc loc
, TOK value
)
6144 if (token
.value
!= value
)
6145 error(loc
, "found `%s` when expecting `%s`", token
.toChars(), Token::toChars(value
));
6149 void Parser::check(TOK value
, const char *string
)
6151 if (token
.value
!= value
)
6152 error("found `%s` when expecting `%s` following %s",
6153 token
.toChars(), Token::toChars(value
), string
);
6157 void Parser::checkParens(TOK value
, Expression
*e
)
6159 if (precedence
[e
->op
] == PREC_rel
&& !e
->parens
)
6160 error(e
->loc
, "%s must be parenthesized when next to operator %s", e
->toChars(), Token::toChars(value
));
6163 /************************************
6164 * Determine if the scanner is sitting on the start of a declaration.
6166 * needId 0 no identifier
6167 * 1 identifier optional
6168 * 2 must have identifier
6169 * 3 must have identifier, but don't recognize old C-style syntax.
6171 * if *pt is not NULL, it is set to the ending token, which would be endtok
6174 bool Parser::isDeclaration(Token
*t
, int needId
, TOK endtok
, Token
**pt
)
6176 //printf("isDeclaration(needId = %d)\n", needId);
6182 if ((t
->value
== TOKconst
||
6183 t
->value
== TOKimmutable
||
6184 t
->value
== TOKwild
||
6185 t
->value
== TOKshared
) &&
6186 peek(t
)->value
!= TOKlparen
)
6199 if (!isBasicType(&t
))
6203 if (!isDeclarator(&t
, &haveId
, &haveTpl
, endtok
, needId
!= 3))
6205 if ((needId
== 0 && !haveId
) ||
6207 (needId
== 2 && haveId
) ||
6208 (needId
== 3 && haveId
))
6218 //printf("\tis declaration, t = %s\n", t->toChars());
6222 //printf("\tis not declaration\n");
6226 bool Parser::isBasicType(Token
**pt
)
6228 // This code parallels parseBasicType()
6233 case TOKwchar
: case TOKdchar
:
6234 case TOKbool
: case TOKchar
:
6235 case TOKint8
: case TOKuns8
:
6236 case TOKint16
: case TOKuns16
:
6237 case TOKint32
: case TOKuns32
:
6238 case TOKint64
: case TOKuns64
:
6239 case TOKint128
: case TOKuns128
:
6240 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
6241 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
6242 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
6250 if (t
->value
== TOKnot
)
6260 if (t
->value
== TOKdot
)
6264 if (t
->value
!= TOKidentifier
)
6267 if (t
->value
!= TOKnot
)
6272 * !( args ), !identifier, etc.
6280 if (!skipParens(t
, &t
))
6283 case TOKwchar
: case TOKdchar
:
6284 case TOKbool
: case TOKchar
:
6285 case TOKint8
: case TOKuns8
:
6286 case TOKint16
: case TOKuns16
:
6287 case TOKint32
: case TOKuns32
:
6288 case TOKint64
: case TOKuns64
:
6289 case TOKint128
: case TOKuns128
:
6290 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
6291 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
6292 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
6303 case TOKimaginary32v
:
6304 case TOKimaginary64v
:
6305 case TOKimaginary80v
:
6315 case TOKfilefullpath
:
6317 case TOKmodulestring
:
6335 /* typeof(exp).identifier...
6338 if (!skipParens(t
, &t
))
6344 // __traits(getMember
6346 if (t
->value
!= TOKlparen
)
6350 if (t
->value
!= TOKidentifier
|| t
->ident
!= Id::getMember
)
6352 if (!skipParens(lp
, &lp
))
6354 // we are in a lookup for decl VS statement
6355 // so we expect a declarator following __trait if it's a type.
6356 // other usages wont be ambiguous (alias, template instance, type qual, etc.)
6357 if (lp
->value
!= TOKidentifier
)
6367 // const(type) or immutable(type) or shared(type) or wild(type)
6369 if (t
->value
!= TOKlparen
)
6372 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
6387 //printf("is not\n");
6391 bool Parser::isDeclarator(Token
**pt
, int *haveId
, int *haveTpl
, TOK endtok
, bool allowAltSyntax
)
6392 { // This code parallels parseDeclarator()
6396 //printf("Parser::isDeclarator() %s\n", t->toChars());
6397 if (t
->value
== TOKassign
)
6412 if (t
->value
== TOKrbracket
)
6416 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
6418 // It's an associative array declaration
6422 if (t
->value
== TOKdot
&& peek(t
)->value
== TOKidentifier
)
6431 // [ expression .. expression ]
6432 if (!isExpression(&t
))
6434 if (t
->value
== TOKslice
)
6437 if (!isExpression(&t
))
6439 if (t
->value
!= TOKrbracket
)
6445 if (t
->value
!= TOKrbracket
)
6450 if (t
->value
== TOKdot
&& peek(t
)->value
== TOKidentifier
)
6467 if (!allowAltSyntax
)
6468 return false; // Do not recognize C-style declarations.
6472 if (t
->value
== TOKrparen
)
6473 return false; // () is not a declarator
6475 /* Regard ( identifier ) as not a declarator
6476 * BUG: what about ( *identifier ) in
6478 * where f is a class instance with overloaded () ?
6479 * Should we just disallow C-style function pointer declarations?
6481 if (t
->value
== TOKidentifier
)
6482 { Token
*t2
= peek(t
);
6483 if (t2
->value
== TOKrparen
)
6488 if (!isDeclarator(&t
, haveId
, NULL
, TOKrparen
))
6497 if (!isParameters(&t
))
6499 skipAttributes(t
, &t
);
6514 if (t
->value
== TOKrbracket
)
6518 else if (isDeclaration(t
, 0, TOKrbracket
, &t
))
6519 { // It's an associative array declaration
6525 if (!isExpression(&t
))
6527 if (t
->value
!= TOKrbracket
)
6536 if (Token
*tk
= peekPastParen(t
))
6538 if (tk
->value
== TOKlparen
)
6540 if (!haveTpl
) return false;
6544 else if (tk
->value
== TOKassign
)
6546 if (!haveTpl
) return false;
6552 if (!isParameters(&t
))
6569 t
= peek(t
); // skip '@'
6570 t
= peek(t
); // skip identifier
6580 if (t
->ident
!= Id::_body
)
6584 // Valid tokens that follow a declaration
6595 // The !parens is to disallow unnecessary parentheses
6596 if (!parens
&& (endtok
== TOKreserved
|| endtok
== t
->value
))
6603 return haveTpl
? true : false;
6614 bool Parser::isParameters(Token
**pt
)
6615 { // This code parallels parseParameters()
6618 //printf("isParameters()\n");
6619 if (t
->value
!= TOKlparen
)
6623 for (;1; t
= peek(t
))
6650 if (t
->value
== TOKlparen
)
6653 if (!isDeclaration(t
, 0, TOKrparen
, &t
))
6655 t
= peek(t
); // skip past closing ')'
6661 { if (!isBasicType(&t
))
6665 if (t
->value
!= TOKdotdotdot
&&
6666 !isDeclarator(&t
, &tmp
, NULL
, TOKreserved
))
6668 if (t
->value
== TOKassign
)
6670 if (!isExpression(&t
))
6673 if (t
->value
== TOKdotdotdot
)
6679 if (t
->value
== TOKcomma
)
6687 if (t
->value
!= TOKrparen
)
6694 bool Parser::isExpression(Token
**pt
)
6696 // This is supposed to determine if something is an expression.
6697 // What it actually does is scan until a closing right bracket
6705 for (;; t
= peek(t
))
6723 if (brnest
|| panest
)
6737 if (--curlynest
>= 0)
6764 /*******************************************
6765 * Skip parens, brackets.
6769 * *pt is set to closing token, which is ')' on success
6772 * false some parsing error
6775 bool Parser::skipParens(Token
*t
, Token
**pt
)
6777 if (t
->value
!= TOKlparen
)
6809 *pt
= peek(t
); // skip found rparen
6816 bool Parser::skipParensIf(Token
*t
, Token
**pt
)
6818 if (t
->value
!= TOKlparen
)
6824 return skipParens(t
, pt
);
6827 /*******************************************
6830 * t is on a candidate attribute
6832 * *pt is set to first non-attribute token on success
6835 * false some parsing error
6838 bool Parser::skipAttributes(Token
*t
, Token
**pt
)
6853 case TOKsynchronized
:
6856 if (peek(t
)->value
== TOKlparen
)
6859 if (!skipParens(t
, &t
))
6861 // t is on the next of closing parenthesis
6874 if (t
->value
== TOKidentifier
)
6878 * @identifier!(arglist)
6879 * any of the above followed by (arglist)
6880 * @predefined_attribute
6882 if (t
->ident
== Id::property
||
6883 t
->ident
== Id::nogc
||
6884 t
->ident
== Id::safe
||
6885 t
->ident
== Id::trusted
||
6886 t
->ident
== Id::system
||
6887 t
->ident
== Id::disable
)
6890 if (t
->value
== TOKnot
)
6893 if (t
->value
== TOKlparen
)
6895 // @identifier!(arglist)
6896 if (!skipParens(t
, &t
))
6898 // t is on the next of closing parenthesis
6903 // Do low rent skipTemplateArgument
6904 if (t
->value
== TOKvector
)
6906 // identifier!__vector(type)
6908 if (!skipParens(t
, &t
))
6915 if (t
->value
== TOKlparen
)
6917 if (!skipParens(t
, &t
))
6919 // t is on the next of closing parenthesis
6924 if (t
->value
== TOKlparen
)
6926 // @( ArgumentList )
6927 if (!skipParens(t
, &t
))
6929 // t is on the next of closing parenthesis
6948 /********************************* Expression Parser ***************************/
6950 Expression
*Parser::parsePrimaryExp()
6955 Loc loc
= token
.loc
;
6957 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
6958 switch (token
.value
)
6962 Token
*t1
= peek(&token
);
6963 Token
*t2
= peek(t1
);
6964 if (t1
->value
== TOKmin
&& t2
->value
== TOKgt
)
6970 error("use `.` for member lookup, not `->`");
6974 if (peekNext() == TOKgoesto
)
6980 if (token
.value
== TOKnot
&& (save
= peekNext()) != TOKis
&& save
!= TOKin
)
6982 // identifier!(template-argument-list)
6983 TemplateInstance
*tempinst
;
6984 tempinst
= new TemplateInstance(loc
, id
);
6985 tempinst
->tiargs
= parseTemplateArguments();
6986 e
= new ScopeExp(loc
, tempinst
);
6989 e
= new IdentifierExp(loc
, id
);
6995 error("`$` is valid only inside [] of index or slice");
6996 e
= new DollarExp(loc
);
7001 // Signal global scope '.' operator with "" identifier
7002 e
= new IdentifierExp(loc
, Id::empty
);
7006 e
= new ThisExp(loc
);
7011 e
= new SuperExp(loc
);
7016 e
= new IntegerExp(loc
, (d_int32
)token
.int64value
, Type::tint32
);
7021 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tuns32
);
7026 e
= new IntegerExp(loc
, token
.int64value
, Type::tint64
);
7031 e
= new IntegerExp(loc
, token
.uns64value
, Type::tuns64
);
7036 e
= new RealExp(loc
, token
.floatvalue
, Type::tfloat32
);
7041 e
= new RealExp(loc
, token
.floatvalue
, Type::tfloat64
);
7046 e
= new RealExp(loc
, token
.floatvalue
, Type::tfloat80
);
7050 case TOKimaginary32v
:
7051 e
= new RealExp(loc
, token
.floatvalue
, Type::timaginary32
);
7055 case TOKimaginary64v
:
7056 e
= new RealExp(loc
, token
.floatvalue
, Type::timaginary64
);
7060 case TOKimaginary80v
:
7061 e
= new RealExp(loc
, token
.floatvalue
, Type::timaginary80
);
7066 e
= new NullExp(loc
);
7072 const char *s
= loc
.filename
? loc
.filename
: mod
->ident
->toChars();
7073 e
= new StringExp(loc
, const_cast<char *>(s
), strlen(s
), 0);
7078 case TOKfilefullpath
:
7080 assert(loc
.filename
); // __FILE_FULL_PATH__ does not work with an invalid location
7081 const char *s
= FileName::toAbsolute(loc
.filename
);
7082 e
= new StringExp(loc
, const_cast<char *>(s
), strlen(s
), 0);
7088 e
= new IntegerExp(loc
, loc
.linnum
, Type::tint32
);
7092 case TOKmodulestring
:
7094 const char *s
= md
? md
->toChars() : mod
->toChars();
7095 e
= new StringExp(loc
, const_cast<char *>(s
), strlen(s
), 0);
7101 e
= new FuncInitExp(loc
);
7106 e
= new PrettyFuncInitExp(loc
);
7111 e
= new IntegerExp(loc
, 1, Type::tbool
);
7116 e
= new IntegerExp(loc
, 0, Type::tbool
);
7121 e
= new IntegerExp(loc
, (d_uns8
)token
.uns64value
, Type::tchar
);
7126 e
= new IntegerExp(loc
, (d_uns16
)token
.uns64value
, Type::twchar
);
7131 e
= new IntegerExp(loc
, (d_uns32
)token
.uns64value
, Type::tdchar
);
7138 // cat adjacent strings
7139 utf8_t
*s
= token
.ustring
;
7140 size_t len
= token
.len
;
7141 unsigned char postfix
= token
.postfix
;
7144 const Token prev
= token
;
7146 if (token
.value
== TOKstring
||
7147 token
.value
== TOKxstring
)
7150 { if (token
.postfix
!= postfix
)
7151 error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix
, token
.postfix
);
7152 postfix
= token
.postfix
;
7155 deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
7156 prev
.toChars(), token
.toChars());
7159 size_t len2
= token
.len
;
7161 utf8_t
*s2
= (utf8_t
*)mem
.xmalloc((len
+ 1) * sizeof(utf8_t
));
7162 memcpy(s2
, s
, len1
* sizeof(utf8_t
));
7163 memcpy(s2
+ len1
, token
.ustring
, (len2
+ 1) * sizeof(utf8_t
));
7169 e
= new StringExp(loc
, s
, len
, postfix
);
7173 case TOKvoid
: t
= Type::tvoid
; goto LabelX
;
7174 case TOKint8
: t
= Type::tint8
; goto LabelX
;
7175 case TOKuns8
: t
= Type::tuns8
; goto LabelX
;
7176 case TOKint16
: t
= Type::tint16
; goto LabelX
;
7177 case TOKuns16
: t
= Type::tuns16
; goto LabelX
;
7178 case TOKint32
: t
= Type::tint32
; goto LabelX
;
7179 case TOKuns32
: t
= Type::tuns32
; goto LabelX
;
7180 case TOKint64
: t
= Type::tint64
; goto LabelX
;
7181 case TOKuns64
: t
= Type::tuns64
; goto LabelX
;
7182 case TOKint128
: t
= Type::tint128
; goto LabelX
;
7183 case TOKuns128
: t
= Type::tuns128
; goto LabelX
;
7184 case TOKfloat32
: t
= Type::tfloat32
; goto LabelX
;
7185 case TOKfloat64
: t
= Type::tfloat64
; goto LabelX
;
7186 case TOKfloat80
: t
= Type::tfloat80
; goto LabelX
;
7187 case TOKimaginary32
: t
= Type::timaginary32
; goto LabelX
;
7188 case TOKimaginary64
: t
= Type::timaginary64
; goto LabelX
;
7189 case TOKimaginary80
: t
= Type::timaginary80
; goto LabelX
;
7190 case TOKcomplex32
: t
= Type::tcomplex32
; goto LabelX
;
7191 case TOKcomplex64
: t
= Type::tcomplex64
; goto LabelX
;
7192 case TOKcomplex80
: t
= Type::tcomplex80
; goto LabelX
;
7193 case TOKbool
: t
= Type::tbool
; goto LabelX
;
7194 case TOKchar
: t
= Type::tchar
; goto LabelX
;
7195 case TOKwchar
: t
= Type::twchar
; goto LabelX
;
7196 case TOKdchar
: t
= Type::tdchar
; goto LabelX
;
7199 if (token
.value
== TOKlparen
)
7201 e
= new TypeExp(loc
, t
);
7202 e
= new CallExp(loc
, e
, parseArguments());
7205 check(TOKdot
, t
->toChars());
7206 if (token
.value
!= TOKidentifier
)
7207 { error("found `%s` when expecting identifier following `%s.`", token
.toChars(), t
->toChars());
7210 e
= typeDotIdExp(loc
, t
, token
.ident
);
7217 e
= new TypeExp(loc
, t
);
7224 e
= new TypeExp(loc
, t
);
7231 check(TOKlparen
, "typeid");
7233 if (isDeclaration(&token
, 0, TOKreserved
, NULL
))
7234 { // argument is a type
7238 { // argument is an expression
7239 o
= parseAssignExp();
7242 e
= new TypeidExp(loc
, o
);
7247 { /* __traits(identifier, args...)
7250 Objects
*args
= NULL
;
7254 if (token
.value
!= TOKidentifier
)
7255 { error("__traits(identifier, args...) expected");
7258 ident
= token
.ident
;
7260 if (token
.value
== TOKcomma
)
7261 args
= parseTemplateArgumentList(); // __traits(identifier, args...)
7263 check(TOKrparen
); // __traits(identifier)
7265 e
= new TraitsExp(loc
, ident
, args
);
7272 Identifier
*ident
= NULL
;
7274 TOK tok
= TOKreserved
;
7275 TOK tok2
= TOKreserved
;
7276 TemplateParameters
*tpl
= NULL
;
7279 if (token
.value
== TOKlparen
)
7282 targ
= parseType(&ident
);
7283 if (token
.value
== TOKcolon
|| token
.value
== TOKequal
)
7287 if (tok
== TOKequal
&&
7288 (token
.value
== TOKstruct
||
7289 token
.value
== TOKunion
||
7290 token
.value
== TOKclass
||
7291 token
.value
== TOKsuper
||
7292 token
.value
== TOKenum
||
7293 token
.value
== TOKinterface
||
7294 token
.value
== TOKmodule
||
7295 token
.value
== TOKpackage
||
7296 token
.value
== TOKargTypes
||
7297 token
.value
== TOKparameters
||
7298 (token
.value
== TOKconst
&& peek(&token
)->value
== TOKrparen
) ||
7299 (token
.value
== TOKimmutable
&& peek(&token
)->value
== TOKrparen
) ||
7300 (token
.value
== TOKshared
&& peek(&token
)->value
== TOKrparen
) ||
7301 (token
.value
== TOKwild
&& peek(&token
)->value
== TOKrparen
) ||
7302 token
.value
== TOKfunction
||
7303 token
.value
== TOKdelegate
||
7304 token
.value
== TOKreturn
||
7305 (token
.value
== TOKvector
&& peek(&token
)->value
== TOKrparen
)))
7312 tspec
= parseType();
7317 if (token
.value
== TOKcomma
)
7318 tpl
= parseTemplateParameterList(1);
7321 tpl
= new TemplateParameters();
7330 error("(type identifier : specialization) expected following is");
7333 e
= new IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
7338 { Expression
*msg
= NULL
;
7341 check(TOKlparen
, "assert");
7342 e
= parseAssignExp();
7343 if (token
.value
== TOKcomma
)
7346 if (token
.value
!= TOKrparen
)
7348 msg
= parseAssignExp();
7349 if (token
.value
== TOKcomma
)
7354 e
= new AssertExp(loc
, e
, msg
);
7361 check(TOKlparen
, "mixin");
7362 e
= parseAssignExp();
7364 e
= new CompileExp(loc
, e
);
7371 check(TOKlparen
, "import");
7372 e
= parseAssignExp();
7374 e
= new ImportExp(loc
, e
);
7379 e
= parseNewExp(NULL
);
7384 Token
*tk
= peekPastParen(&token
);
7385 if (skipAttributes(tk
, &tk
) &&
7386 (tk
->value
== TOKgoesto
|| tk
->value
== TOKlcurly
))
7388 // (arguments) => expression
7389 // (arguments) { statements... }
7395 e
= parseExpression();
7397 check(loc
, TOKrparen
);
7402 { /* Parse array literals and associative array literals:
7403 * [ value, value, value ... ]
7404 * [ key:value, key:value, key:value ... ]
7406 Expressions
*values
= new Expressions();
7407 Expressions
*keys
= NULL
;
7410 while (token
.value
!= TOKrbracket
&& token
.value
!= TOKeof
)
7412 e
= parseAssignExp();
7413 if (token
.value
== TOKcolon
&& (keys
|| values
->length
== 0))
7416 keys
= new Expressions();
7418 e
= parseAssignExp();
7421 { error("`key:value` expected for associative array literal");
7426 if (token
.value
== TOKrbracket
)
7430 check(loc
, TOKrbracket
);
7433 e
= new AssocArrayLiteralExp(loc
, keys
, values
);
7435 e
= new ArrayLiteralExp(loc
, NULL
, values
);
7444 Dsymbol
*s
= parseFunctionLiteral();
7445 e
= new FuncExp(loc
, s
);
7450 error("expression expected, not `%s`", token
.toChars());
7452 // Anything for e, as long as it's not NULL
7453 e
= new IntegerExp(loc
, 0, Type::tint32
);
7460 Expression
*Parser::parsePostExp(Expression
*e
)
7467 switch (token
.value
)
7471 if (token
.value
== TOKidentifier
)
7472 { Identifier
*id
= token
.ident
;
7475 if (token
.value
== TOKnot
&& peekNext() != TOKis
&& peekNext() != TOKin
)
7477 Objects
*tiargs
= parseTemplateArguments();
7478 e
= new DotTemplateInstanceExp(loc
, e
, id
, tiargs
);
7481 e
= new DotIdExp(loc
, e
, id
);
7484 else if (token
.value
== TOKnew
)
7490 error("identifier expected following `.`, not `%s`", token
.toChars());
7494 e
= new PostExp(TOKplusplus
, loc
, e
);
7498 e
= new PostExp(TOKminusminus
, loc
, e
);
7502 e
= new CallExp(loc
, e
, parseArguments());
7506 { // array dereferences:
7509 // array[lwr .. upr]
7512 Expressions
*arguments
= new Expressions();
7516 while (token
.value
!= TOKrbracket
&& token
.value
!= TOKeof
)
7518 index
= parseAssignExp();
7519 if (token
.value
== TOKslice
)
7521 // array[..., lwr..upr, ...]
7523 upr
= parseAssignExp();
7524 arguments
->push(new IntervalExp(loc
, index
, upr
));
7527 arguments
->push(index
);
7528 if (token
.value
== TOKrbracket
)
7534 e
= new ArrayExp(loc
, e
, arguments
);
7545 Expression
*Parser::parseUnaryExp()
7548 Loc loc
= token
.loc
;
7550 switch (token
.value
)
7554 e
= parseUnaryExp();
7555 e
= new AddrExp(loc
, e
);
7560 e
= parseUnaryExp();
7561 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7562 e
= new PreExp(TOKpreplusplus
, loc
, e
);
7567 e
= parseUnaryExp();
7568 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7569 e
= new PreExp(TOKpreminusminus
, loc
, e
);
7574 e
= parseUnaryExp();
7575 e
= new PtrExp(loc
, e
);
7580 e
= parseUnaryExp();
7581 e
= new NegExp(loc
, e
);
7586 e
= parseUnaryExp();
7587 e
= new UAddExp(loc
, e
);
7592 e
= parseUnaryExp();
7593 e
= new NotExp(loc
, e
);
7598 e
= parseUnaryExp();
7599 e
= new ComExp(loc
, e
);
7604 e
= parseUnaryExp();
7605 e
= new DeleteExp(loc
, e
, false);
7608 case TOKcast
: // cast(type) expression
7612 /* Look for cast(), cast(const), cast(immutable),
7613 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
7615 unsigned char m
= 0;
7618 switch (token
.value
)
7621 if (peekNext() == TOKlparen
)
7622 break; // const as type constructor
7623 m
|= MODconst
; // const as storage class
7628 if (peekNext() == TOKlparen
)
7635 if (peekNext() == TOKlparen
)
7642 if (peekNext() == TOKlparen
)
7653 if (token
.value
== TOKrparen
)
7656 e
= parseUnaryExp();
7657 e
= new CastExp(loc
, e
, m
);
7661 Type
*t
= parseType(); // cast( type )
7662 t
= t
->addMod(m
); // cast( const type )
7664 e
= parseUnaryExp();
7665 e
= new CastExp(loc
, e
, t
);
7673 case TOKimmutable
: // immutable(type)(arguments) / immutable(type).init
7675 StorageClass stc
= parseTypeCtor();
7676 Type
*t
= parseBasicType();
7678 e
= new TypeExp(loc
, t
);
7679 if (stc
== 0 && token
.value
== TOKdot
)
7682 if (token
.value
!= TOKidentifier
)
7684 error("identifier expected following (type).");
7687 e
= typeDotIdExp(loc
, t
, token
.ident
);
7689 e
= parsePostExp(e
);
7692 else if (token
.value
!= TOKlparen
)
7694 error("(arguments) expected following %s", t
->toChars());
7697 e
= new CallExp(loc
, e
, parseArguments());
7708 if (isDeclaration(tk
, 0, TOKrparen
, &tk
))
7710 tk
= peek(tk
); // skip over right parenthesis
7715 if (tk
->value
== TOKis
|| tk
->value
== TOKin
) // !is or !in
7737 case TOKimaginary32v
:
7738 case TOKimaginary64v
:
7739 case TOKimaginary80v
:
7753 case TOKfilefullpath
:
7755 case TOKmodulestring
:
7758 case TOKwchar
: case TOKdchar
:
7759 case TOKbool
: case TOKchar
:
7760 case TOKint8
: case TOKuns8
:
7761 case TOKint16
: case TOKuns16
:
7762 case TOKint32
: case TOKuns32
:
7763 case TOKint64
: case TOKuns64
:
7764 case TOKint128
: case TOKuns128
:
7765 case TOKfloat32
: case TOKfloat64
: case TOKfloat80
:
7766 case TOKimaginary32
: case TOKimaginary64
: case TOKimaginary80
:
7767 case TOKcomplex32
: case TOKcomplex64
: case TOKcomplex80
:
7777 // or .identifier!( ... )
7778 if (token
.value
== TOKdot
)
7780 if (peekNext() != TOKidentifier
&& peekNext() != TOKnew
)
7782 error("identifier or new keyword expected following (...).");
7785 e
= new TypeExp(loc
, t
);
7787 e
= parsePostExp(e
);
7791 e
= parseUnaryExp();
7792 e
= new CastExp(loc
, e
, t
);
7793 error("C style cast illegal, use %s", e
->toChars());
7802 e
= parsePrimaryExp();
7803 e
= parsePostExp(e
);
7807 e
= parsePrimaryExp();
7808 e
= parsePostExp(e
);
7813 // ^^ is right associative and has higher precedence than the unary operators
7814 while (token
.value
== TOKpow
)
7817 Expression
*e2
= parseUnaryExp();
7818 e
= new PowExp(loc
, e
, e2
);
7824 Expression
*Parser::parseMulExp()
7828 Loc loc
= token
.loc
;
7830 e
= parseUnaryExp();
7833 switch (token
.value
)
7835 case TOKmul
: nextToken(); e2
= parseUnaryExp(); e
= new MulExp(loc
,e
,e2
); continue;
7836 case TOKdiv
: nextToken(); e2
= parseUnaryExp(); e
= new DivExp(loc
,e
,e2
); continue;
7837 case TOKmod
: nextToken(); e2
= parseUnaryExp(); e
= new ModExp(loc
,e
,e2
); continue;
7847 Expression
*Parser::parseAddExp()
7851 Loc loc
= token
.loc
;
7856 switch (token
.value
)
7858 case TOKadd
: nextToken(); e2
= parseMulExp(); e
= new AddExp(loc
,e
,e2
); continue;
7859 case TOKmin
: nextToken(); e2
= parseMulExp(); e
= new MinExp(loc
,e
,e2
); continue;
7860 case TOKtilde
: nextToken(); e2
= parseMulExp(); e
= new CatExp(loc
,e
,e2
); continue;
7870 Expression
*Parser::parseShiftExp()
7874 Loc loc
= token
.loc
;
7879 switch (token
.value
)
7881 case TOKshl
: nextToken(); e2
= parseAddExp(); e
= new ShlExp(loc
,e
,e2
); continue;
7882 case TOKshr
: nextToken(); e2
= parseAddExp(); e
= new ShrExp(loc
,e
,e2
); continue;
7883 case TOKushr
: nextToken(); e2
= parseAddExp(); e
= new UshrExp(loc
,e
,e2
); continue;
7893 Expression
*Parser::parseCmpExp()
7898 Loc loc
= token
.loc
;
7900 e
= parseShiftExp();
7901 TOK op
= token
.value
;
7908 e2
= parseShiftExp();
7909 e
= new EqualExp(op
, loc
, e
, e2
);
7917 // Attempt to identify '!is'
7919 if (t
->value
== TOKin
)
7923 e2
= parseShiftExp();
7924 e
= new InExp(loc
, e
, e2
);
7925 e
= new NotExp(loc
, e
);
7928 if (t
->value
!= TOKis
)
7931 op
= TOKnotidentity
;
7936 e2
= parseShiftExp();
7937 e
= new IdentityExp(op
, loc
, e
, e2
);
7953 e2
= parseShiftExp();
7954 e
= new CmpExp(op
, loc
, e
, e2
);
7959 e2
= parseShiftExp();
7960 e
= new InExp(loc
, e
, e2
);
7969 Expression
*Parser::parseAndExp()
7971 Loc loc
= token
.loc
;
7973 Expression
*e
= parseCmpExp();
7974 while (token
.value
== TOKand
)
7976 checkParens(TOKand
, e
);
7978 Expression
*e2
= parseCmpExp();
7979 checkParens(TOKand
, e2
);
7980 e
= new AndExp(loc
,e
,e2
);
7986 Expression
*Parser::parseXorExp()
7988 Loc loc
= token
.loc
;
7990 Expression
*e
= parseAndExp();
7991 while (token
.value
== TOKxor
)
7993 checkParens(TOKxor
, e
);
7995 Expression
*e2
= parseAndExp();
7996 checkParens(TOKxor
, e2
);
7997 e
= new XorExp(loc
, e
, e2
);
8002 Expression
*Parser::parseOrExp()
8004 Loc loc
= token
.loc
;
8006 Expression
*e
= parseXorExp();
8007 while (token
.value
== TOKor
)
8009 checkParens(TOKor
, e
);
8011 Expression
*e2
= parseXorExp();
8012 checkParens(TOKor
, e2
);
8013 e
= new OrExp(loc
, e
, e2
);
8018 Expression
*Parser::parseAndAndExp()
8022 Loc loc
= token
.loc
;
8025 while (token
.value
== TOKandand
)
8029 e
= new LogicalExp(loc
, TOKandand
, e
, e2
);
8034 Expression
*Parser::parseOrOrExp()
8038 Loc loc
= token
.loc
;
8040 e
= parseAndAndExp();
8041 while (token
.value
== TOKoror
)
8044 e2
= parseAndAndExp();
8045 e
= new LogicalExp(loc
, TOKoror
, e
, e2
);
8050 Expression
*Parser::parseCondExp()
8055 Loc loc
= token
.loc
;
8058 if (token
.value
== TOKquestion
)
8061 e1
= parseExpression();
8063 e2
= parseCondExp();
8064 e
= new CondExp(loc
, e
, e1
, e2
);
8069 Expression
*Parser::parseAssignExp()
8079 switch (token
.value
)
8081 case TOKassign
: nextToken(); e2
= parseAssignExp(); e
= new AssignExp(loc
,e
,e2
); continue;
8082 case TOKaddass
: nextToken(); e2
= parseAssignExp(); e
= new AddAssignExp(loc
,e
,e2
); continue;
8083 case TOKminass
: nextToken(); e2
= parseAssignExp(); e
= new MinAssignExp(loc
,e
,e2
); continue;
8084 case TOKmulass
: nextToken(); e2
= parseAssignExp(); e
= new MulAssignExp(loc
,e
,e2
); continue;
8085 case TOKdivass
: nextToken(); e2
= parseAssignExp(); e
= new DivAssignExp(loc
,e
,e2
); continue;
8086 case TOKmodass
: nextToken(); e2
= parseAssignExp(); e
= new ModAssignExp(loc
,e
,e2
); continue;
8087 case TOKpowass
: nextToken(); e2
= parseAssignExp(); e
= new PowAssignExp(loc
,e
,e2
); continue;
8088 case TOKandass
: nextToken(); e2
= parseAssignExp(); e
= new AndAssignExp(loc
,e
,e2
); continue;
8089 case TOKorass
: nextToken(); e2
= parseAssignExp(); e
= new OrAssignExp(loc
,e
,e2
); continue;
8090 case TOKxorass
: nextToken(); e2
= parseAssignExp(); e
= new XorAssignExp(loc
,e
,e2
); continue;
8091 case TOKshlass
: nextToken(); e2
= parseAssignExp(); e
= new ShlAssignExp(loc
,e
,e2
); continue;
8092 case TOKshrass
: nextToken(); e2
= parseAssignExp(); e
= new ShrAssignExp(loc
,e
,e2
); continue;
8093 case TOKushrass
: nextToken(); e2
= parseAssignExp(); e
= new UshrAssignExp(loc
,e
,e2
); continue;
8094 case TOKcatass
: nextToken(); e2
= parseAssignExp(); e
= new CatAssignExp(loc
,e
,e2
); continue;
8103 Expression
*Parser::parseExpression()
8107 Loc loc
= token
.loc
;
8109 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
8110 e
= parseAssignExp();
8111 while (token
.value
== TOKcomma
)
8114 e2
= parseAssignExp();
8115 e
= new CommaExp(loc
, e
, e2
, false);
8122 /*************************
8123 * Collect argument list.
8124 * Assume current token is ',', '(' or '['.
8127 Expressions
*Parser::parseArguments()
8129 Expressions
*arguments
;
8133 arguments
= new Expressions();
8134 if (token
.value
== TOKlbracket
)
8135 endtok
= TOKrbracket
;
8141 while (token
.value
!= endtok
&& token
.value
!= TOKeof
)
8143 arg
= parseAssignExp();
8144 arguments
->push(arg
);
8145 if (token
.value
== endtok
)
8154 /*******************************************
8157 Expression
*Parser::parseNewExp(Expression
*thisexp
)
8160 Expressions
*newargs
;
8161 Expressions
*arguments
= NULL
;
8162 Loc loc
= token
.loc
;
8166 if (token
.value
== TOKlparen
)
8168 newargs
= parseArguments();
8171 // An anonymous nested class starts with "class"
8172 if (token
.value
== TOKclass
)
8175 if (token
.value
== TOKlparen
)
8176 arguments
= parseArguments();
8178 BaseClasses
*baseclasses
= NULL
;
8179 if (token
.value
!= TOKlcurly
)
8180 baseclasses
= parseBaseClasses();
8182 Identifier
*id
= NULL
;
8183 Dsymbols
*members
= NULL
;
8185 if (token
.value
!= TOKlcurly
)
8187 error("{ members } expected for anonymous class");
8192 members
= parseDeclDefs(0);
8193 if (token
.value
!= TOKrcurly
)
8194 error("class member expected");
8198 ClassDeclaration
*cd
= new ClassDeclaration(loc
, id
, baseclasses
, members
, false);
8199 Expression
*e
= new NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
8204 StorageClass stc
= parseTypeCtor();
8205 t
= parseBasicType(true);
8206 t
= parseBasicType2(t
);
8208 if (t
->ty
== Taarray
)
8210 TypeAArray
*taa
= (TypeAArray
*)t
;
8211 Type
*index
= taa
->index
;
8213 Expression
*edim
= typeToExpression(index
);
8216 error("need size of rightmost array, not type %s", index
->toChars());
8217 return new NullExp(loc
);
8219 t
= new TypeSArray(taa
->next
, edim
);
8221 else if (t
->ty
== Tsarray
)
8224 else if (token
.value
== TOKlparen
)
8226 arguments
= parseArguments();
8228 Expression
*e
= new NewExp(loc
, thisexp
, newargs
, t
, arguments
);
8232 /**********************************************
8235 void Parser::addComment(Dsymbol
*s
, const utf8_t
*blockComment
)
8237 s
->addComment(combineComments(blockComment
, token
.lineComment
));
8238 token
.lineComment
= NULL
;
8242 /**********************************
8243 * Set operator precedence for each operator.
8246 PREC precedence
[TOKMAX
];
8248 struct PrecedenceInitializer
8250 PrecedenceInitializer();
8253 static PrecedenceInitializer precedenceinitializer
;
8255 PrecedenceInitializer::PrecedenceInitializer()
8257 for (size_t i
= 0; i
< TOKMAX
; i
++)
8258 precedence
[i
] = PREC_zero
;
8260 precedence
[TOKtype
] = PREC_expr
;
8261 precedence
[TOKerror
] = PREC_expr
;
8263 precedence
[TOKtypeof
] = PREC_primary
;
8264 precedence
[TOKmixin
] = PREC_primary
;
8265 precedence
[TOKimport
] = PREC_primary
;
8267 precedence
[TOKdotvar
] = PREC_primary
;
8268 precedence
[TOKscope
] = PREC_primary
;
8269 precedence
[TOKidentifier
] = PREC_primary
;
8270 precedence
[TOKthis
] = PREC_primary
;
8271 precedence
[TOKsuper
] = PREC_primary
;
8272 precedence
[TOKint64
] = PREC_primary
;
8273 precedence
[TOKfloat64
] = PREC_primary
;
8274 precedence
[TOKcomplex80
] = PREC_primary
;
8275 precedence
[TOKnull
] = PREC_primary
;
8276 precedence
[TOKstring
] = PREC_primary
;
8277 precedence
[TOKarrayliteral
] = PREC_primary
;
8278 precedence
[TOKassocarrayliteral
] = PREC_primary
;
8279 precedence
[TOKclassreference
] = PREC_primary
;
8280 precedence
[TOKfile
] = PREC_primary
;
8281 precedence
[TOKfilefullpath
] = PREC_primary
;
8282 precedence
[TOKline
] = PREC_primary
;
8283 precedence
[TOKmodulestring
] = PREC_primary
;
8284 precedence
[TOKfuncstring
] = PREC_primary
;
8285 precedence
[TOKprettyfunc
] = PREC_primary
;
8286 precedence
[TOKtypeid
] = PREC_primary
;
8287 precedence
[TOKis
] = PREC_primary
;
8288 precedence
[TOKassert
] = PREC_primary
;
8289 precedence
[TOKhalt
] = PREC_primary
;
8290 precedence
[TOKtemplate
] = PREC_primary
;
8291 precedence
[TOKdsymbol
] = PREC_primary
;
8292 precedence
[TOKfunction
] = PREC_primary
;
8293 precedence
[TOKvar
] = PREC_primary
;
8294 precedence
[TOKsymoff
] = PREC_primary
;
8295 precedence
[TOKstructliteral
] = PREC_primary
;
8296 precedence
[TOKarraylength
] = PREC_primary
;
8297 precedence
[TOKdelegateptr
] = PREC_primary
;
8298 precedence
[TOKdelegatefuncptr
] = PREC_primary
;
8299 precedence
[TOKremove
] = PREC_primary
;
8300 precedence
[TOKtuple
] = PREC_primary
;
8301 precedence
[TOKtraits
] = PREC_primary
;
8302 precedence
[TOKdefault
] = PREC_primary
;
8303 precedence
[TOKoverloadset
] = PREC_primary
;
8304 precedence
[TOKvoid
] = PREC_primary
;
8305 precedence
[TOKvectorarray
] = PREC_primary
;
8308 precedence
[TOKdotti
] = PREC_primary
;
8309 precedence
[TOKdotid
] = PREC_primary
;
8310 precedence
[TOKdottd
] = PREC_primary
;
8311 precedence
[TOKdot
] = PREC_primary
;
8312 precedence
[TOKdottype
] = PREC_primary
;
8313 // precedence[TOKarrow] = PREC_primary;
8314 precedence
[TOKplusplus
] = PREC_primary
;
8315 precedence
[TOKminusminus
] = PREC_primary
;
8316 precedence
[TOKpreplusplus
] = PREC_primary
;
8317 precedence
[TOKpreminusminus
] = PREC_primary
;
8318 precedence
[TOKcall
] = PREC_primary
;
8319 precedence
[TOKslice
] = PREC_primary
;
8320 precedence
[TOKarray
] = PREC_primary
;
8321 precedence
[TOKindex
] = PREC_primary
;
8323 precedence
[TOKdelegate
] = PREC_unary
;
8324 precedence
[TOKaddress
] = PREC_unary
;
8325 precedence
[TOKstar
] = PREC_unary
;
8326 precedence
[TOKneg
] = PREC_unary
;
8327 precedence
[TOKuadd
] = PREC_unary
;
8328 precedence
[TOKnot
] = PREC_unary
;
8329 precedence
[TOKtilde
] = PREC_unary
;
8330 precedence
[TOKdelete
] = PREC_unary
;
8331 precedence
[TOKnew
] = PREC_unary
;
8332 precedence
[TOKnewanonclass
] = PREC_unary
;
8333 precedence
[TOKcast
] = PREC_unary
;
8335 precedence
[TOKvector
] = PREC_unary
;
8336 precedence
[TOKpow
] = PREC_pow
;
8338 precedence
[TOKmul
] = PREC_mul
;
8339 precedence
[TOKdiv
] = PREC_mul
;
8340 precedence
[TOKmod
] = PREC_mul
;
8342 precedence
[TOKadd
] = PREC_add
;
8343 precedence
[TOKmin
] = PREC_add
;
8344 precedence
[TOKcat
] = PREC_add
;
8346 precedence
[TOKshl
] = PREC_shift
;
8347 precedence
[TOKshr
] = PREC_shift
;
8348 precedence
[TOKushr
] = PREC_shift
;
8350 precedence
[TOKlt
] = PREC_rel
;
8351 precedence
[TOKle
] = PREC_rel
;
8352 precedence
[TOKgt
] = PREC_rel
;
8353 precedence
[TOKge
] = PREC_rel
;
8354 precedence
[TOKunord
] = PREC_rel
;
8355 precedence
[TOKlg
] = PREC_rel
;
8356 precedence
[TOKleg
] = PREC_rel
;
8357 precedence
[TOKule
] = PREC_rel
;
8358 precedence
[TOKul
] = PREC_rel
;
8359 precedence
[TOKuge
] = PREC_rel
;
8360 precedence
[TOKug
] = PREC_rel
;
8361 precedence
[TOKue
] = PREC_rel
;
8362 precedence
[TOKin
] = PREC_rel
;
8364 /* Note that we changed precedence, so that < and != have the same
8365 * precedence. This change is in the parser, too.
8367 precedence
[TOKequal
] = PREC_rel
;
8368 precedence
[TOKnotequal
] = PREC_rel
;
8369 precedence
[TOKidentity
] = PREC_rel
;
8370 precedence
[TOKnotidentity
] = PREC_rel
;
8372 precedence
[TOKand
] = PREC_and
;
8374 precedence
[TOKxor
] = PREC_xor
;
8376 precedence
[TOKor
] = PREC_or
;
8378 precedence
[TOKandand
] = PREC_andand
;
8380 precedence
[TOKoror
] = PREC_oror
;
8382 precedence
[TOKquestion
] = PREC_cond
;
8384 precedence
[TOKassign
] = PREC_assign
;
8385 precedence
[TOKconstruct
] = PREC_assign
;
8386 precedence
[TOKblit
] = PREC_assign
;
8387 precedence
[TOKaddass
] = PREC_assign
;
8388 precedence
[TOKminass
] = PREC_assign
;
8389 precedence
[TOKcatass
] = PREC_assign
;
8390 precedence
[TOKmulass
] = PREC_assign
;
8391 precedence
[TOKdivass
] = PREC_assign
;
8392 precedence
[TOKmodass
] = PREC_assign
;
8393 precedence
[TOKpowass
] = PREC_assign
;
8394 precedence
[TOKshlass
] = PREC_assign
;
8395 precedence
[TOKshrass
] = PREC_assign
;
8396 precedence
[TOKushrass
] = PREC_assign
;
8397 precedence
[TOKandass
] = PREC_assign
;
8398 precedence
[TOKorass
] = PREC_assign
;
8399 precedence
[TOKxorass
] = PREC_assign
;
8401 precedence
[TOKcomma
] = PREC_expr
;
8402 precedence
[TOKdeclaration
] = PREC_expr
;
8404 precedence
[TOKinterval
] = PREC_assign
;