2 * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
4 * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar)
6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d)
10 * Documentation: https://dlang.org/phobos/dmd_parse.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parse.d
16 import core
.stdc
.stdio
;
17 import core
.stdc
.string
;
22 import dmd
.identifier
;
25 import dmd
.root
.filename
;
26 import dmd
.common
.outbuffer
;
28 import dmd
.root
.rootobject
;
29 import dmd
.root
.string
;
32 alias CompileEnv
= dmd
.lexer
.CompileEnv
;
34 /***********************************************************
36 class Parser(AST
, Lexer
= dmd
.lexer
.Lexer
) : Lexer
38 AST
.ModuleDeclaration
* md
;
46 Loc endloc
; // set to location of last right curly
47 int inBrackets
; // inside [] of array index or slice
48 Loc lookingForElse
; // location of lonely if looking for an else
49 bool doUnittests
; // parse unittest blocks
52 bool transitionIn
= false; /// `-transition=in` is active, `in` parameters are listed
54 /*********************
55 * Use this constructor for string mixins.
57 * loc = location in source file of mixin
59 extern (D
) this(const ref Loc loc
, AST
.Module _module
, const(char)[] input
, bool doDocComment
,
60 ErrorSink errorSink
, const CompileEnv
* compileEnv
, const bool doUnittests
) scope
62 //printf("Parser::Parser()1 %d\n", doUnittests);
63 this(_module
, input
, doDocComment
, errorSink
, compileEnv
, doUnittests
);
67 /**************************************************
68 * Main Parser constructor.
70 extern (D
) this(AST
.Module _module
, const(char)[] input
, bool doDocComment
, ErrorSink errorSink
,
71 const CompileEnv
* compileEnv
, const bool doUnittests
) scope
73 super(_module ? _module
.srcfile
.toChars() : null, input
.ptr
, 0, input
.length
, doDocComment
, false,
77 //printf("Parser::Parser()2 %d\n", doUnittests);
79 this.linkage
= LINK
.d
;
80 this.doUnittests
= doUnittests
;
84 + Parse a module, i.e. the optional `module x.y.z` declaration and all declarations
85 + found in the current file.
87 + Returns: the list of declarations or an empty list in case of malformed declarations,
88 + the module declaration will be stored as `this.md` if found
90 AST
.Dsymbols
* parseModule()
92 if (!parseModuleDeclaration())
95 return parseModuleContent();
99 + Parse the optional module declaration
101 + Returns: false if a malformed module declaration was found
103 final bool parseModuleDeclaration()
105 const comment
= token
.blockComment
;
106 bool isdeprecated
= false;
107 AST
.Expression msg
= null;
109 // Parse optional module attributes
110 parseModuleAttributes(msg
, isdeprecated
);
112 // ModuleDeclaration leads off
113 if (token
.value
== TOK
.module_
)
115 const loc
= token
.loc
;
118 /* parse ModuleFullyQualifiedName
119 * https://dlang.org/spec/module.html#ModuleFullyQualifiedName
122 if (token
.value
!= TOK
.identifier
)
124 error("identifier expected following `module`");
129 Identifier id
= token
.ident
;
131 while (nextToken() == TOK
.dot
)
135 if (token
.value
!= TOK
.identifier
)
137 error("identifier expected following `package`");
143 md
= new AST
.ModuleDeclaration(loc
, a
, id
, msg
, isdeprecated
);
145 if (token
.value
!= TOK
.semicolon
)
146 error("`;` expected following module declaration instead of `%s`", token
.toChars());
148 addComment(mod
, comment
);
154 + Parse the content of a module, i.e. all declarations found until the end of file.
156 + Returns: the list of declarations or an empty list in case of malformed declarations
158 final AST
.Dsymbols
* parseModuleContent()
160 AST
.Dsymbol lastDecl
= mod
;
161 AST
.Dsymbols
* decldefs
= parseDeclDefs(0, &lastDecl
);
163 if (token
.value
== TOK
.rightCurly
)
165 error("unmatched closing brace");
166 return errorReturn();
169 if (token
.value
!= TOK
.endOfFile
)
171 error("unrecognized declaration");
172 return errorReturn();
178 + Skips to the end of the current declaration - denoted by either `;` or EOF
180 + Returns: An empty list of Dsymbols
182 private AST
.Dsymbols
* errorReturn()
184 while (token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
187 return new AST
.Dsymbols();
190 /**********************************
191 * Parse the ModuleAttributes preceding a module declaration.
193 * ModuleAttributes(opt) module ModuleFullyQualifiedName ;
194 * https://dlang.org/spec/module.html#ModuleAttributes
196 * msg = set to the AssignExpression from DeprecatedAttribute https://dlang.org/spec/module.html#DeprecatedAttribute
197 * isdeprecated = set to true if a DeprecatedAttribute is seen
200 void parseModuleAttributes(out AST
.Expression msg
, out bool isdeprecated
)
203 if (!(skipAttributes(&token
, &tk
) && tk
.value
== TOK
.module_
))
204 return; // no module attributes
206 AST
.Expressions
* udas
= null;
207 while (token
.value
!= TOK
.module_
)
211 case TOK
.deprecated_
:
213 // deprecated (...) module ...
215 error("there is only one deprecation attribute allowed for module declaration");
218 if (token
.value
== TOK
.leftParenthesis
)
220 check(TOK
.leftParenthesis
);
221 msg
= parseAssignExp();
222 check(TOK
.rightParenthesis
);
228 AST
.Expressions
* exps
= null;
229 const stc = parseAttribute(exps
);
230 if (stc & atAttrGroup
)
232 error("`@%s` attribute for module declaration is not supported", token
.toChars());
236 udas
= AST
.UserAttributeDeclaration
.concat(udas
, exps
);
244 error("`module` expected instead of `%s`", token
.toChars());
253 auto a
= new AST
.Dsymbols();
254 auto udad
= new AST
.UserAttributeDeclaration(udas
, a
);
255 mod
.userAttribDecl
= udad
;
262 * Parses a `deprecated` declaration
265 * msg = Deprecated message, if any.
266 * Used to support overriding a deprecated storage class with
267 * a deprecated declaration with a message, but to error
268 * if both declaration have a message.
271 * Whether the deprecated declaration has a message
273 private bool parseDeprecatedAttribute(ref AST
.Expression msg
)
275 if (peekNext() != TOK
.leftParenthesis
)
279 check(TOK
.leftParenthesis
);
280 AST
.Expression e
= parseAssignExp();
281 check(TOK
.rightParenthesis
);
284 error(token
.loc
, "conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg
.toChars(), e
.toChars());
290 /************************************
291 * Parse declarations and definitions
293 * once = !=0 means parse exactly one decl or def
294 * pLastDecl = set to last decl or def parsed
295 * pAttrs = keep track of attributes
297 * array of declared symbols
299 AST
.Dsymbols
* parseDeclDefs(int once
, AST
.Dsymbol
* pLastDecl
= null, PrefixAttributes
!AST
* pAttrs
= null)
301 AST
.Dsymbol lastDecl
= null; // used to link unittest to its previous declaration
303 pLastDecl
= &lastDecl
;
305 const linksave
= linkage
; // save global state
307 //printf("Parser::parseDeclDefs()\n");
308 auto decldefs
= new AST
.Dsymbols();
312 AST
.Dsymbol s
= null;
313 AST
.Dsymbols
* a
= null;
315 PrefixAttributes
!AST attrs
;
316 if (!once ||
!pAttrs
)
319 pAttrs
.comment
= token
.blockComment
.ptr
;
321 AST
.Visibility
.Kind prot
;
323 AST
.Condition condition
;
334 /* Determine if this is a manifest constant declaration,
335 * or a conventional enum.
337 const tv
= peekNext();
338 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
340 else if (tv
!= TOK
.identifier
)
344 const nextv
= peekNext2();
345 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
358 s
= cast(AST
.Dsymbol
)parseTemplateDeclaration();
363 const loc
= token
.loc
;
366 case TOK
.leftParenthesis
:
369 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
373 auto exps
= parseArguments();
374 check(TOK
.semicolon
);
375 s
= new AST
.MixinDeclaration(loc
, exps
);
381 s
= cast(AST
.Dsymbol
)parseTemplateDeclaration(true);
407 case TOK
.imaginary32
:
408 case TOK
.imaginary64
:
409 case TOK
.imaginary80
:
426 a
= parseDeclarations(false, pAttrs
, pAttrs
.comment
);
428 *pLastDecl
= (*a
)[a
.length
- 1];
432 if (peekNext() == TOK
.dot
)
434 s
= parseCtor(pAttrs
);
438 s
= parseDtor(pAttrs
);
442 const tv
= peekNext();
443 if (tv
== TOK
.leftParenthesis || tv
== TOK
.leftCurly
)
445 // invariant { statements... }
446 // invariant() { statements... }
447 // invariant (expression);
448 s
= parseInvariant(pAttrs
);
451 error("invariant body expected, not `%s`", token
.toChars());
456 * Ignore unittests in non-root modules.
458 * This mainly means that unittests *inside templates* are only
459 * ever instantiated if the module lexically declaring the
460 * template is one of the root modules.
462 * E.g., compiling some project with `-unittest` does NOT
463 * compile and later run any unittests in instantiations of
464 * templates declared in other libraries.
466 * Declaring unittests *inside* templates is considered an anti-
467 * pattern. In almost all cases, the unittests don't depend on
468 * the template parameters, but instantiate the template with
469 * fixed arguments (e.g., Nullable!T unittests instantiating
470 * Nullable!int), so compiling and running identical tests for
471 * each template instantiation is hardly desirable.
472 * But adding a unittest right below some function being tested
473 * is arguably good for locality, so unittests end up inside
475 * To make sure a template's unittests are run, it should be
476 * instantiated in the same module, e.g., some module-level
479 * Another reason for ignoring unittests in templates from non-
480 * root modules is for template codegen culling via
481 * TemplateInstance.needsCodegen(). If the compiler decides not
482 * to emit some Nullable!bool because there's an existing
483 * instantiation in some non-root module, it has no idea whether
484 * that module was compiled with -unittest too, and so whether
485 * Nullable!int (instantiated in some unittest inside the
486 * Nullable template) can be culled too. By ignoring unittests
487 * in non-root modules, the compiler won't consider any
488 * template instantiations in these unittests as candidates for
489 * further codegen culling.
491 // The isRoot check is here because it can change after parsing begins (see dmodule.d)
492 if (doUnittests
&& mod
.isRoot())
494 linkage
= LINK
.d
; // unittests have D linkage
495 s
= parseUnitTest(pAttrs
);
497 (*pLastDecl
).ddocUnittest
= cast(AST
.UnitTestDeclaration
)s
;
501 // Skip over unittest block by counting { }
521 error(loc
, "closing `}` of unittest not found before end of file");
529 // Workaround 14894. Add an empty unittest declaration to keep
530 // the number of symbols in this scope independent of -unittest.
531 s
= new AST
.UnitTestDeclaration(loc
, token
.loc
, STC
.undefined_
, null);
536 s
= parseNew(pAttrs
);
541 error("declaration expected, not `%s`", token
.toChars());
547 error("declaration expected, not `%s`", token
.toChars());
552 const next
= peekNext();
553 if (next
== TOK
.this_
)
554 s
= parseStaticCtor(pAttrs
);
555 else if (next
== TOK
.tilde
)
556 s
= parseStaticDtor(pAttrs
);
557 else if (next
== TOK
.assert_
)
558 s
= parseStaticAssert();
559 else if (next
== TOK
.if_
)
561 const Loc loc
= token
.loc
;
562 condition
= parseStaticIfCondition();
564 if (token
.value
== TOK
.colon
)
565 athen
= parseBlock(pLastDecl
);
568 const lookingForElseSave
= lookingForElse
;
569 lookingForElse
= token
.loc
;
570 athen
= parseBlock(pLastDecl
);
571 lookingForElse
= lookingForElseSave
;
573 AST
.Dsymbols
* aelse
= null;
574 if (token
.value
== TOK
.else_
)
576 const elseloc
= token
.loc
;
578 aelse
= parseBlock(pLastDecl
);
579 checkDanglingElse(elseloc
);
581 s
= new AST
.StaticIfDeclaration(loc
, condition
, athen
, aelse
);
583 else if (next
== TOK
.import_
)
588 else if (next
== TOK
.foreach_ || next
== TOK
.foreach_reverse_
)
590 s
= parseForeach
!(AST
.StaticForeachDeclaration
)(token
.loc
, pLastDecl
);
600 if (peekNext() == TOK
.leftParenthesis
)
606 if (peekNext() == TOK
.leftParenthesis
)
608 stc = STC
.immutable_
;
613 const next
= peekNext();
614 if (next
== TOK
.leftParenthesis
)
616 if (next
== TOK
.static_
)
618 TOK next2
= peekNext2();
619 if (next2
== TOK
.this_
)
621 s
= parseSharedStaticCtor(pAttrs
);
624 if (next2
== TOK
.tilde
)
626 s
= parseSharedStaticDtor(pAttrs
);
634 if (peekNext() == TOK
.leftParenthesis
)
659 case TOK
.synchronized_
:
660 stc = STC
.synchronized_
;
681 AST
.Expressions
* exps
= null;
682 stc = parseAttribute(exps
);
684 goto Lstc
; // it's a predefined attribute
685 // no redundant/conflicting check for UDAs
686 pAttrs
.udas
= AST
.UserAttributeDeclaration
.concat(pAttrs
.udas
, exps
);
690 pAttrs
.storageClass
= appendStorageClass(pAttrs
.storageClass
, stc);
696 /* Look for auto initializers:
697 * storage_class identifier = initializer;
698 * storage_class identifier(...) = initializer;
700 if (token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
702 a
= parseAutoDeclarations(getStorageClass
!AST(pAttrs
), pAttrs
.comment
);
704 *pLastDecl
= (*a
)[a
.length
- 1];
707 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
713 /* Look for return type inference for template functions.
716 if (token
.value
== TOK
.identifier
&& skipParens(peek(&token
), &tk
) && skipAttributes(tk
, &tk
) &&
717 (tk
.value
== TOK
.leftParenthesis || tk
.value
== TOK
.leftCurly || tk
.value
== TOK
.in_ ||
718 tk
.value
== TOK
.out_ || tk
.value
== TOK
.do_ || tk
.value
== TOK
.goesTo ||
719 tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
))
721 if (tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
)
722 usageOfBodyKeyword();
724 a
= parseDeclarations(true, pAttrs
, pAttrs
.comment
);
726 *pLastDecl
= (*a
)[a
.length
- 1];
729 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
735 a
= parseBlock(pLastDecl
, pAttrs
);
736 auto stc2
= getStorageClass
!AST(pAttrs
);
737 if (stc2
!= STC
.undefined_
)
739 s
= new AST
.StorageClassDeclaration(scdLoc
, stc2
, a
);
745 a
= new AST
.Dsymbols();
748 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
753 case TOK
.deprecated_
:
755 stc |
= STC
.deprecated_
;
756 if (!parseDeprecatedAttribute(pAttrs
.depmsg
))
759 a
= parseBlock(pLastDecl
, pAttrs
);
760 s
= new AST
.DeprecatedDeclaration(pAttrs
.depmsg
, a
);
761 pAttrs
.depmsg
= null;
764 case TOK
.leftBracket
:
766 if (peekNext() == TOK
.rightBracket
)
767 error("empty attribute list is not allowed");
768 error("use `@(attributes)` instead of `[attributes]`");
769 AST
.Expressions
* exps
= parseArguments();
770 // no redundant/conflicting check for UDAs
772 pAttrs
.udas
= AST
.UserAttributeDeclaration
.concat(pAttrs
.udas
, exps
);
773 a
= parseBlock(pLastDecl
, pAttrs
);
776 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
783 if (peekNext() != TOK
.leftParenthesis
)
789 const linkLoc
= token
.loc
;
790 auto res
= parseLinkage();
791 if (pAttrs
.link
!= LINK
.default_
)
793 if (pAttrs
.link
!= res
.link
)
795 error(token
.loc
, "conflicting linkage `extern (%s)` and `extern (%s)`", AST
.linkageToChars(pAttrs
.link
), AST
.linkageToChars(res
.link
));
797 else if (res
.idents || res
.identExps || res
.cppmangle
!= CPPMANGLE
.def
)
800 // extern(C++, foo) extern(C++, bar) void foo();
801 // to be equivalent with:
802 // extern(C++, foo.bar) void foo();
804 // extern(C++, "ns") extern(C++, class) struct test {}
805 // extern(C++, class) extern(C++, "ns") struct test {}
808 error("redundant linkage `extern (%s)`", AST
.linkageToChars(pAttrs
.link
));
810 pAttrs
.link
= res
.link
;
811 this.linkage
= res
.link
;
812 this.linkLoc
= linkLoc
;
813 a
= parseBlock(pLastDecl
, pAttrs
);
816 assert(res
.link
== LINK
.cpp
);
817 assert(res
.idents
.length
);
818 for (size_t i
= res
.idents
.length
; i
;)
820 Identifier id
= (*res
.idents
)[--i
];
823 a
= new AST
.Dsymbols();
826 s
= new AST
.Nspace(linkLoc
, id
, null, a
);
828 pAttrs
.link
= LINK
.default_
;
830 else if (res
.identExps
)
832 assert(res
.link
== LINK
.cpp
);
833 assert(res
.identExps
.length
);
834 for (size_t i
= res
.identExps
.length
; i
;)
836 AST
.Expression exp
= (*res
.identExps
)[--i
];
839 a
= new AST
.Dsymbols();
842 s
= new AST
.CPPNamespaceDeclaration(linkLoc
, exp
, a
);
844 pAttrs
.link
= LINK
.default_
;
846 else if (res
.cppmangle
!= CPPMANGLE
.def
)
848 assert(res
.link
== LINK
.cpp
);
849 s
= new AST
.CPPMangleDeclaration(linkLoc
, res
.cppmangle
, a
);
851 else if (pAttrs
.link
!= LINK
.default_
)
853 s
= new AST
.LinkDeclaration(linkLoc
, pAttrs
.link
, a
);
854 pAttrs
.link
= LINK
.default_
;
860 prot
= AST
.Visibility
.Kind
.private_
;
864 prot
= AST
.Visibility
.Kind
.package_
;
868 prot
= AST
.Visibility
.Kind
.protected_
;
872 prot
= AST
.Visibility
.Kind
.public_
;
876 prot
= AST
.Visibility
.Kind
.export_
;
880 if (pAttrs
.visibility
.kind
!= AST
.Visibility
.Kind
.undefined
)
882 if (pAttrs
.visibility
.kind
!= prot
)
883 error(token
.loc
, "conflicting visibility attribute `%s` and `%s`", AST
.visibilityToChars(pAttrs
.visibility
.kind
), AST
.visibilityToChars(prot
));
885 error("redundant visibility attribute `%s`", AST
.visibilityToChars(prot
));
887 pAttrs
.visibility
.kind
= prot
;
888 const attrloc
= token
.loc
;
892 // optional qualified package identifier to bind
894 Identifier
[] pkg_prot_idents
;
895 if (pAttrs
.visibility
.kind
== AST
.Visibility
.Kind
.package_
&& token
.value
== TOK
.leftParenthesis
)
897 pkg_prot_idents
= parseQualifiedIdentifier("protection package");
899 check(TOK
.rightParenthesis
);
902 while (token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
909 a
= parseBlock(pLastDecl
, pAttrs
);
910 if (pAttrs
.visibility
.kind
!= AST
.Visibility
.Kind
.undefined
)
912 if (pAttrs
.visibility
.kind
== AST
.Visibility
.Kind
.package_
&& pkg_prot_idents
)
913 s
= new AST
.VisibilityDeclaration(attrloc
, pkg_prot_idents
, a
);
915 s
= new AST
.VisibilityDeclaration(attrloc
, pAttrs
.visibility
, a
);
917 pAttrs
.visibility
= AST
.Visibility(AST
.Visibility
.Kind
.undefined
);
923 const attrLoc
= token
.loc
;
927 AST
.Expression e
= null; // default
928 if (token
.value
== TOK
.leftParenthesis
)
931 e
= parseAssignExp();
932 check(TOK
.rightParenthesis
);
935 if (pAttrs
.setAlignment
)
938 error("redundant alignment attribute `align(%s)`", e
.toChars());
940 error("redundant alignment attribute `align`");
943 pAttrs
.setAlignment
= true;
945 a
= parseBlock(pLastDecl
, pAttrs
);
946 if (pAttrs
.setAlignment
)
948 s
= new AST
.AlignDeclaration(attrLoc
, pAttrs
.ealign
, a
);
949 pAttrs
.setAlignment
= false;
950 pAttrs
.ealign
= null;
956 AST
.Expressions
* args
= null;
957 const loc
= token
.loc
;
960 check(TOK
.leftParenthesis
);
961 if (token
.value
!= TOK
.identifier
)
963 error("`pragma(identifier)` expected");
966 Identifier ident
= token
.ident
;
968 if (token
.value
== TOK
.comma
&& peekNext() != TOK
.rightParenthesis
)
969 args
= parseArguments(); // pragma(identifier, args...)
971 check(TOK
.rightParenthesis
); // pragma(identifier)
973 AST
.Dsymbols
* a2
= null;
974 if (token
.value
== TOK
.semicolon
)
976 /* https://issues.dlang.org/show_bug.cgi?id=2354
977 * Accept single semicolon as an empty
978 * DeclarationBlock following attribute.
980 * Attribute DeclarationBlock
987 a2
= parseBlock(pLastDecl
);
988 s
= new AST
.PragmaDeclaration(loc
, ident
, args
, a2
);
992 startloc
= token
.loc
;
994 if (token
.value
== TOK
.assign
)
996 s
= parseDebugSpecification();
999 condition
= parseDebugCondition();
1003 startloc
= token
.loc
;
1005 if (token
.value
== TOK
.assign
)
1007 s
= parseVersionSpecification();
1010 condition
= parseVersionCondition();
1015 AST
.Dsymbols
* athen
;
1016 if (token
.value
== TOK
.colon
)
1017 athen
= parseBlock(pLastDecl
);
1020 const lookingForElseSave
= lookingForElse
;
1021 lookingForElse
= token
.loc
;
1022 athen
= parseBlock(pLastDecl
);
1023 lookingForElse
= lookingForElseSave
;
1025 AST
.Dsymbols
* aelse
= null;
1026 if (token
.value
== TOK
.else_
)
1028 const elseloc
= token
.loc
;
1030 aelse
= parseBlock(pLastDecl
);
1031 checkDanglingElse(elseloc
);
1033 s
= new AST
.ConditionalDeclaration(startloc
, condition
, athen
, aelse
);
1037 // empty declaration
1038 //error("empty declaration");
1043 error("declaration expected, not `%s`", token
.toChars());
1045 while (token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
1054 if (!s
.isAttribDeclaration())
1057 addComment(s
, pAttrs
.comment
);
1059 else if (a
&& a
.length
)
1071 /*****************************************
1072 * Parse auto declarations of the form:
1073 * storageClass ident = init, ident = init, ... ;
1074 * and return the array of them.
1075 * Starts with token on the first ident.
1076 * Ends with scanner past closing ';'
1078 private AST
.Dsymbols
* parseAutoDeclarations(StorageClass storageClass
, const(char)* comment
)
1080 //printf("parseAutoDeclarations\n");
1081 auto a
= new AST
.Dsymbols();
1085 const loc
= token
.loc
;
1086 Identifier ident
= token
.ident
;
1087 nextToken(); // skip over ident
1089 AST
.TemplateParameters
* tpl
= null;
1090 if (token
.value
== TOK
.leftParenthesis
)
1091 tpl
= parseTemplateParameterList();
1093 check(TOK
.assign
); // skip over '='
1094 AST
.Initializer _init
= parseInitializer();
1095 auto v
= new AST
.VarDeclaration(loc
, null, ident
, _init
, storageClass
);
1100 auto a2
= new AST
.Dsymbols();
1102 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
, 0);
1106 switch (token
.value
)
1110 addComment(s
, comment
);
1115 if (!(token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
)))
1117 error("identifier expected following comma");
1120 addComment(s
, comment
);
1124 error("semicolon expected following auto declaration, not `%s`", token
.toChars());
1132 /********************************************
1133 * Parse declarations after an align, visibility, or extern decl.
1135 private AST
.Dsymbols
* parseBlock(AST
.Dsymbol
* pLastDecl
, PrefixAttributes
!AST
* pAttrs
= null)
1137 AST
.Dsymbols
* a
= null;
1139 //printf("parseBlock()\n");
1140 switch (token
.value
)
1143 error("declaration expected following attribute, not `;`");
1148 error("declaration expected following attribute, not end of file");
1153 const lcLoc
= token
.loc
;
1154 const lookingForElseSave
= lookingForElse
;
1155 lookingForElse
= Loc();
1158 a
= parseDeclDefs(0, pLastDecl
);
1159 if (token
.value
!= TOK
.rightCurly
)
1161 /* left curly brace */
1162 error("matching `}` expected, not `%s`", token
.toChars());
1163 eSink
.errorSupplemental(lcLoc
, "unmatched `{`");
1167 lookingForElse
= lookingForElseSave
;
1172 a
= parseDeclDefs(0, pLastDecl
); // grab declarations up to closing curly bracket
1176 a
= parseDeclDefs(1, pLastDecl
, pAttrs
);
1183 * Provide an error message if `added` contains storage classes which are
1184 * redundant with those in `orig`; otherwise, return the combination.
1187 * orig = The already applied storage class.
1188 * added = The new storage class to add to `orig`.
1191 * The combination of both storage classes (`orig | added`).
1193 private StorageClass
appendStorageClass(StorageClass orig
, StorageClass added
)
1195 void checkConflictSTCGroup(bool at
= false)(StorageClass group
)
1197 if (added
& group
&& orig
& group
& ((orig
& group
) - 1))
1199 at ?
"conflicting attribute `@%s`"
1200 : "conflicting attribute `%s`",
1207 AST
.stcToBuffer(buf
, added
);
1208 error("redundant attribute `%s`", buf
.peekChars());
1209 return orig | added
;
1212 const Redundant
= (STC
.const_ | STC
.scope_ | STC
.ref_
);
1215 if ((orig
& STC
.in_
) && (added
& Redundant
))
1217 if (added
& STC
.const_
)
1218 error("attribute `const` is redundant with previously-applied `in`");
1219 else if (compileEnv
.previewIn
)
1221 error("attribute `%s` is redundant with previously-applied `in`",
1222 (orig
& STC
.scope_
) ?
"scope".ptr
: "ref".ptr
);
1224 else if (added
& STC
.ref_
)
1226 // accept for legacy compatibility
1227 //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
1230 error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
1234 if ((added
& STC
.in_
) && (orig
& Redundant
))
1236 if (orig
& STC
.const_
)
1237 error("attribute `in` cannot be added after `const`: remove `const`");
1238 else if (compileEnv
.previewIn
)
1240 // Windows `printf` does not support `%1$s`
1241 const(char*) stc_str
= (orig
& STC
.scope_
) ?
"scope".ptr
: "ref".ptr
;
1242 error(token
.loc
, "attribute `in` cannot be added after `%s`: remove `%s`",
1245 else if (orig
& STC
.ref_
)
1247 // accept for legacy compatibility
1248 //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
1251 error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
1255 checkConflictSTCGroup(STC
.const_ | STC
.immutable_ | STC
.manifest
);
1256 checkConflictSTCGroup(STC
.gshared | STC
.shared_
);
1257 checkConflictSTCGroup
!true(STC
.safeGroup
);
1262 /***********************************************
1263 * Parse attribute(s), lexer is on '@'.
1265 * Attributes can be builtin (e.g. `@safe`, `@nogc`, etc...),
1266 * or be user-defined (UDAs). In the former case, we return the storage
1267 * class via the return value, while in thelater case we return `0`
1271 * pudas = An array of UDAs to append to
1274 * If the attribute is builtin, the return value will be non-zero.
1275 * Otherwise, 0 is returned, and `pudas` will be appended to.
1277 private StorageClass
parseAttribute(ref AST
.Expressions
* udas
)
1280 if (token
.value
== TOK
.identifier
)
1282 // If we find a builtin attribute, we're done, return immediately.
1283 if (StorageClass
stc = isBuiltinAtAttribute(token
.ident
))
1286 // Allow identifier, template instantiation, or function call
1287 // for `@Argument` (single UDA) form.
1288 AST
.Expression exp
= parsePrimaryExp();
1289 if (token
.value
== TOK
.leftParenthesis
)
1291 const loc
= token
.loc
;
1292 AST
.Expressions
* args
= new AST
.Expressions();
1293 AST
.Identifiers
* names
= new AST
.Identifiers();
1294 parseNamedArguments(args
, names
);
1295 exp
= new AST
.CallExp(loc
, exp
, args
, names
);
1299 udas
= new AST
.Expressions();
1304 AST
.Expression
templateArgToExp(RootObject o
, const ref Loc loc
)
1308 case DYNCAST
.expression
:
1309 return cast(AST
.Expression
) o
;
1311 return new AST
.TypeExp(loc
, cast(AST
.Type
)o
);
1317 if (token
.value
== TOK
.leftParenthesis
)
1319 // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
1320 if (peekNext() == TOK
.rightParenthesis
)
1321 error("empty attribute list is not allowed");
1324 udas
= new AST
.Expressions();
1325 auto args
= parseTemplateArgumentList();
1326 foreach (arg
; *args
)
1327 udas
.push(templateArgToExp(arg
, token
.loc
));
1331 if (auto o
= parseTemplateSingleArgument())
1334 udas
= new AST
.Expressions();
1335 udas
.push(templateArgToExp(o
, token
.loc
));
1339 if (token
.isKeyword())
1340 error("`%s` is a keyword, not an `@` attribute", token
.toChars());
1342 error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token
.toChars());
1347 /***********************************************
1348 * Parse const/immutable/shared/inout/nothrow/pure postfix
1350 private StorageClass
parsePostfix(StorageClass storageClass
, AST
.Expressions
** pudas
)
1355 switch (token
.value
)
1361 case TOK
.immutable_
:
1362 stc = STC
.immutable_
;
1383 if (peekNext() == TOK
.scope_
)
1384 stc |
= STC
.returnScope
; // recognize `return scope`
1393 AST
.Expressions
* udas
= null;
1394 stc = parseAttribute(udas
);
1398 *pudas
= AST
.UserAttributeDeclaration
.concat(*pudas
, udas
);
1402 // void function() @uda fp;
1403 // () @uda { return 1; }
1404 error("user-defined attributes cannot appear as postfixes");
1412 if (skipAttributes(&token
, &tk
) && tk
.ptr
!= token
.ptr ||
1413 token
.value
== TOK
.static_ || token
.value
== TOK
.extern_
)
1415 error("`%s` token is not allowed in postfix position",
1416 Token
.toChars(token
.value
));
1420 return storageClass
;
1422 storageClass
= appendStorageClass(storageClass
, stc);
1427 private StorageClass
parseTypeCtor()
1429 StorageClass storageClass
= STC
.undefined_
;
1433 if (peekNext() == TOK
.leftParenthesis
)
1434 return storageClass
;
1437 switch (token
.value
)
1443 case TOK
.immutable_
:
1444 stc = STC
.immutable_
;
1456 return storageClass
;
1458 storageClass
= appendStorageClass(storageClass
, stc);
1463 /**************************************
1465 * Constraint is of the form:
1466 * if ( ConstraintExpression )
1468 private AST
.Expression
parseConstraint()
1470 AST
.Expression e
= null;
1471 if (token
.value
== TOK
.if_
)
1473 nextToken(); // skip over 'if'
1474 check(TOK
.leftParenthesis
);
1475 e
= parseExpression();
1476 check(TOK
.rightParenthesis
);
1481 /**************************************
1482 * Parse a TemplateDeclaration.
1484 private AST
.TemplateDeclaration
parseTemplateDeclaration(bool ismixin
= false)
1486 AST
.TemplateDeclaration tempdecl
;
1488 AST
.TemplateParameters
* tpl
;
1489 AST
.Dsymbols
* decldefs
;
1490 AST
.Expression constraint
= null;
1491 const loc
= token
.loc
;
1494 if (token
.value
!= TOK
.identifier
)
1496 error("identifier expected following `template`");
1501 tpl
= parseTemplateParameterList();
1505 constraint
= parseConstraint();
1507 if (token
.value
!= TOK
.leftCurly
)
1509 error("`{` expected after template parameter list, not `%s`", token
.toChars()); /* } */
1512 decldefs
= parseBlock(null);
1514 tempdecl
= new AST
.TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
, ismixin
);
1521 /******************************************
1522 * Parse template parameter list.
1524 * flag 0: parsing "( list )"
1525 * 1: parsing non-empty "list $(RPAREN)"
1527 private AST
.TemplateParameters
* parseTemplateParameterList(int flag
= 0)
1529 auto tpl
= new AST
.TemplateParameters();
1531 if (!flag
&& token
.value
!= TOK
.leftParenthesis
)
1533 error("parenthesized template parameter list expected following template identifier");
1538 // Get array of TemplateParameters
1539 if (flag || token
.value
!= TOK
.rightParenthesis
)
1541 while (token
.value
!= TOK
.rightParenthesis
)
1543 AST
.TemplateParameter tp
;
1545 Identifier tp_ident
= null;
1546 AST
.Type tp_spectype
= null;
1547 AST
.Type tp_valtype
= null;
1548 AST
.Type tp_defaulttype
= null;
1549 AST
.Expression tp_specvalue
= null;
1550 AST
.Expression tp_defaultvalue
= null;
1552 // Get TemplateParameter
1554 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1555 const tv
= peekNext();
1556 if (token
.value
== TOK
.alias_
)
1560 loc
= token
.loc
; // todo
1561 AST
.Type spectype
= null;
1562 if (isDeclaration(&token
, NeedDeclaratorId
.must
, TOK
.reserved
, null))
1564 spectype
= parseType(&tp_ident
);
1568 if (token
.value
!= TOK
.identifier
)
1570 error("identifier expected for template `alias` parameter");
1573 tp_ident
= token
.ident
;
1576 RootObject spec
= null;
1577 if (token
.value
== TOK
.colon
) // : Type
1580 if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.reserved
, null))
1583 spec
= parseCondExp();
1585 RootObject def
= null;
1586 if (token
.value
== TOK
.assign
) // = Type
1589 if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.reserved
, null))
1592 def
= parseCondExp();
1594 tp
= new AST
.TemplateAliasParameter(loc
, tp_ident
, spectype
, spec
, def
);
1596 else if (tv
== TOK
.colon || tv
== TOK
.assign || tv
== TOK
.comma || tv
== TOK
.rightParenthesis
)
1599 if (token
.value
!= TOK
.identifier
)
1601 error("identifier expected for template type parameter");
1605 tp_ident
= token
.ident
;
1607 if (token
.value
== TOK
.colon
) // : Type
1610 tp_spectype
= parseType();
1612 if (token
.value
== TOK
.assign
) // = Type
1615 tp_defaulttype
= parseType();
1617 tp
= new AST
.TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1619 else if (token
.value
== TOK
.identifier
&& tv
== TOK
.dotDotDot
)
1623 tp_ident
= token
.ident
;
1626 tp
= new AST
.TemplateTupleParameter(loc
, tp_ident
);
1628 else if (token
.value
== TOK
.this_
)
1632 if (token
.value
!= TOK
.identifier
)
1634 error("identifier expected for template `this` parameter");
1638 tp_ident
= token
.ident
;
1640 if (token
.value
== TOK
.colon
) // : Type
1643 tp_spectype
= parseType();
1645 if (token
.value
== TOK
.assign
) // = Type
1648 tp_defaulttype
= parseType();
1650 tp
= new AST
.TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1655 loc
= token
.loc
; // todo
1656 tp_valtype
= parseType(&tp_ident
);
1659 error("identifier expected for template value parameter");
1660 tp_ident
= Identifier
.idPool("error");
1662 if (token
.value
== TOK
.colon
) // : CondExpression
1665 tp_specvalue
= parseCondExp();
1667 if (token
.value
== TOK
.assign
) // = CondExpression
1670 tp_defaultvalue
= parseDefaultInitExp();
1672 tp
= new AST
.TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1675 if (token
.value
!= TOK
.comma
)
1680 check(TOK
.rightParenthesis
);
1686 /******************************************
1687 * Parse template mixin.
1690 * mixin a.b.c!(args).Foo!(args);
1691 * mixin Foo!(args) identifier;
1692 * mixin typeof(expr).identifier!(args);
1694 private AST
.Dsymbol
parseMixin()
1696 AST
.TemplateMixin tm
;
1698 AST
.Objects
* tiargs
;
1700 //printf("parseMixin()\n");
1701 const locMixin
= token
.loc
;
1702 nextToken(); // skip 'mixin'
1704 auto loc
= token
.loc
;
1705 AST
.TypeQualified tqual
= null;
1706 if (token
.value
== TOK
.dot
)
1712 if (token
.value
== TOK
.typeof_
)
1714 tqual
= parseTypeof();
1717 if (token
.value
!= TOK
.identifier
)
1719 error("identifier expected, not `%s`", token
.toChars());
1730 if (token
.value
== TOK
.not)
1732 tiargs
= parseTemplateArguments();
1735 if (tiargs
&& token
.value
== TOK
.dot
)
1737 auto tempinst
= new AST
.TemplateInstance(loc
, id
, tiargs
);
1739 tqual
= new AST
.TypeInstance(loc
, tempinst
);
1741 tqual
.addInst(tempinst
);
1747 tqual
= new AST
.TypeIdentifier(loc
, id
);
1752 if (token
.value
!= TOK
.dot
)
1756 if (token
.value
!= TOK
.identifier
)
1758 error("identifier expected following `.` instead of `%s`", token
.toChars());
1767 if (token
.value
== TOK
.identifier
)
1773 tm
= new AST
.TemplateMixin(locMixin
, id
, tqual
, tiargs
);
1774 if (token
.value
!= TOK
.semicolon
)
1775 error("`;` expected after `mixin`");
1781 /******************************************
1782 * Parse template arguments.
1784 * current token is opening '!'
1786 * current token is one after closing '$(RPAREN)'
1788 private AST
.Objects
* parseTemplateArguments()
1790 AST
.Objects
* tiargs
;
1793 if (token
.value
== TOK
.leftParenthesis
)
1795 // ident!(template_arguments)
1796 tiargs
= parseTemplateArgumentList();
1800 // ident!template_argument
1801 RootObject o
= parseTemplateSingleArgument();
1804 error("template argument expected following `!`");
1808 tiargs
= new AST
.Objects();
1812 if (token
.value
== TOK
.not)
1814 TOK tok
= peekNext();
1815 if (tok
!= TOK
.is_
&& tok
!= TOK
.in_
)
1817 error("multiple ! arguments are not allowed");
1820 if (token
.value
== TOK
.leftParenthesis
)
1821 parseTemplateArgumentList();
1823 parseTemplateSingleArgument();
1824 if (token
.value
== TOK
.not && (tok
= peekNext()) != TOK
.is_
&& tok
!= TOK
.in_
)
1831 /******************************************
1832 * Parse template argument list.
1834 * current token is opening '$(LPAREN)',
1835 * or ',' for __traits
1837 * current token is one after closing '$(RPAREN)'
1839 private AST
.Objects
* parseTemplateArgumentList()
1841 //printf("Parser::parseTemplateArgumentList()\n");
1842 auto tiargs
= new AST
.Objects();
1843 TOK endtok
= TOK
.rightParenthesis
;
1844 assert(token
.value
== TOK
.leftParenthesis || token
.value
== TOK
.comma
);
1847 // Get TemplateArgumentList
1848 while (token
.value
!= endtok
)
1850 tiargs
.push(parseTypeOrAssignExp());
1851 if (token
.value
!= TOK
.comma
)
1855 check(endtok
, "template argument list");
1859 /***************************************
1860 * Parse a Type or an Expression
1862 * RootObject representing the AST
1864 RootObject
parseTypeOrAssignExp(TOK endtoken
= TOK
.reserved
)
1866 return isDeclaration(&token
, NeedDeclaratorId
.no
, endtoken
, null)
1867 ?
parseType() // argument is a type
1868 : parseAssignExp(); // argument is an expression
1871 /*****************************
1872 * Parse single template argument, to support the syntax:
1875 * current token is the arg
1876 * Returns: An AST.Type, AST.Expression, or `null` on error
1878 private RootObject
parseTemplateSingleArgument()
1880 //printf("parseTemplateSingleArgument()\n");
1882 switch (token
.value
)
1884 case TOK
.identifier
:
1885 ta
= new AST
.TypeIdentifier(token
.loc
, token
.ident
);
1893 ta
= AST
.Type
.tvoid
;
1897 ta
= AST
.Type
.tint8
;
1901 ta
= AST
.Type
.tuns8
;
1905 ta
= AST
.Type
.tint16
;
1909 ta
= AST
.Type
.tuns16
;
1913 ta
= AST
.Type
.tint32
;
1917 ta
= AST
.Type
.tuns32
;
1921 ta
= AST
.Type
.tint64
;
1925 ta
= AST
.Type
.tuns64
;
1929 ta
= AST
.Type
.tint128
;
1933 ta
= AST
.Type
.tuns128
;
1937 ta
= AST
.Type
.tfloat32
;
1941 ta
= AST
.Type
.tfloat64
;
1945 ta
= AST
.Type
.tfloat80
;
1948 case TOK
.imaginary32
:
1949 ta
= AST
.Type
.timaginary32
;
1952 case TOK
.imaginary64
:
1953 ta
= AST
.Type
.timaginary64
;
1956 case TOK
.imaginary80
:
1957 ta
= AST
.Type
.timaginary80
;
1961 ta
= AST
.Type
.tcomplex32
;
1965 ta
= AST
.Type
.tcomplex64
;
1969 ta
= AST
.Type
.tcomplex80
;
1973 ta
= AST
.Type
.tbool
;
1977 ta
= AST
.Type
.tchar
;
1981 ta
= AST
.Type
.twchar
;
1985 ta
= AST
.Type
.tdchar
;
1991 case TOK
.int32Literal
:
1992 case TOK
.uns32Literal
:
1993 case TOK
.int64Literal
:
1994 case TOK
.uns64Literal
:
1995 case TOK
.int128Literal
:
1996 case TOK
.uns128Literal
:
1997 case TOK
.float32Literal
:
1998 case TOK
.float64Literal
:
1999 case TOK
.float80Literal
:
2000 case TOK
.imaginary32Literal
:
2001 case TOK
.imaginary64Literal
:
2002 case TOK
.imaginary80Literal
:
2006 case TOK
.charLiteral
:
2007 case TOK
.wcharLiteral
:
2008 case TOK
.dcharLiteral
:
2010 case TOK
.hexadecimalString
:
2012 case TOK
.fileFullPath
:
2014 case TOK
.moduleString
:
2015 case TOK
.functionString
:
2016 case TOK
.prettyFunction
:
2019 // Template argument is an expression
2020 return parsePrimaryExp();
2027 /**********************************
2028 * Parse a static assertion.
2029 * Current token is 'static'.
2031 private AST
.StaticAssert
parseStaticAssert()
2033 const loc
= token
.loc
;
2035 AST
.Expressions
* msg
= null;
2037 //printf("parseStaticAssert()\n");
2040 check(TOK
.leftParenthesis
);
2041 exp
= parseAssignExp();
2042 if (token
.value
== TOK
.comma
)
2044 if (peekNext() == TOK
.rightParenthesis
)
2046 nextToken(); // consume `,`
2047 nextToken(); // consume `)`
2050 msg
= parseArguments();
2053 check(TOK
.rightParenthesis
);
2054 check(TOK
.semicolon
, "static assert");
2055 return new AST
.StaticAssert(loc
, exp
, msg
);
2058 /***********************************
2059 * Parse typeof(expression).
2060 * Current token is on the 'typeof'.
2062 private AST
.TypeQualified
parseTypeof()
2064 AST
.TypeQualified t
;
2065 const loc
= token
.loc
;
2068 check(TOK
.leftParenthesis
);
2069 if (token
.value
== TOK
.return_
) // typeof(return)
2072 t
= new AST
.TypeReturn(loc
);
2076 AST
.Expression exp
= parseExpression(); // typeof(expression)
2077 t
= new AST
.TypeTypeof(loc
, exp
);
2079 check(TOK
.rightParenthesis
);
2083 /***********************************
2084 * Parse __vector(type).
2085 * Current token is on the '__vector'.
2087 private AST
.Type
parseVector()
2090 check(TOK
.leftParenthesis
);
2091 AST
.Type tb
= parseType();
2092 check(TOK
.rightParenthesis
);
2093 return new AST
.TypeVector(tb
);
2096 /***********************************
2099 * extern (C++, namespaces)
2100 * extern (C++, "namespace", "namespaces", ...)
2101 * extern (C++, (StringExp))
2102 * The parser is on the 'extern' token.
2104 private ParsedLinkage
!(AST
) parseLinkage()
2106 ParsedLinkage
!(AST
) result
;
2108 assert(token
.value
== TOK
.leftParenthesis
);
2110 ParsedLinkage
!(AST
) returnLinkage(LINK link
)
2112 check(TOK
.rightParenthesis
);
2116 ParsedLinkage
!(AST
) invalidLinkage()
2118 error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Windows`, `System`");
2119 return returnLinkage(LINK
.d
);
2122 if (token
.value
!= TOK
.identifier
)
2123 return returnLinkage(LINK
.d
);
2125 Identifier id
= token
.ident
;
2127 if (id
== Id
.Windows
)
2128 return returnLinkage(LINK
.windows
);
2129 else if (id
== Id
.D
)
2130 return returnLinkage(LINK
.d
);
2131 else if (id
== Id
.System
)
2132 return returnLinkage(LINK
.system
);
2133 else if (id
== Id
.Objective
) // Looking for tokens "Objective-C"
2135 if (token
.value
!= TOK
.min
)
2136 return invalidLinkage();
2139 if (token
.ident
!= Id
.C
)
2140 return invalidLinkage();
2143 return returnLinkage(LINK
.objc
);
2145 else if (id
!= Id
.C
)
2146 return invalidLinkage();
2148 if (token
.value
!= TOK
.plusPlus
)
2149 return returnLinkage(LINK
.c
);
2152 if (token
.value
!= TOK
.comma
) // , namespaces or class or struct
2153 return returnLinkage(LINK
.cpp
);
2157 if (token
.value
== TOK
.rightParenthesis
)
2158 return returnLinkage(LINK
.cpp
); // extern(C++,)
2160 if (token
.value
== TOK
.class_ || token
.value
== TOK
.struct_
)
2162 result
.cppmangle
= token
.value
== TOK
.class_ ? CPPMANGLE
.asClass
: CPPMANGLE
.asStruct
;
2165 else if (token
.value
== TOK
.identifier
) // named scope namespace
2167 result
.idents
= new AST
.Identifiers();
2170 Identifier idn
= token
.ident
;
2171 result
.idents
.push(idn
);
2173 if (token
.value
== TOK
.dot
)
2176 if (token
.value
== TOK
.identifier
)
2178 error("identifier expected for C++ namespace");
2179 result
.idents
= null; // error occurred, invalidate list of elements.
2184 else // non-scoped StringExp namespace
2186 result
.identExps
= new AST
.Expressions();
2189 result
.identExps
.push(parseCondExp());
2190 if (token
.value
!= TOK
.comma
)
2193 // Allow trailing commas as done for argument lists, arrays, ...
2194 if (token
.value
== TOK
.rightParenthesis
)
2198 return returnLinkage(LINK
.cpp
);
2201 /***********************************
2202 * Parse ident1.ident2.ident3
2205 * entity = what qualified identifier is expected to resolve into.
2206 * Used only for better error message
2209 * array of identifiers with actual qualified one stored last
2211 private Identifier
[] parseQualifiedIdentifier(const(char)* entity
)
2213 Identifier
[] qualified
;
2218 if (token
.value
!= TOK
.identifier
)
2220 error(token
.loc
, "`%s` expected as dot-separated identifiers, got `%s`", entity
, token
.toChars());
2224 Identifier id
= token
.ident
;
2229 while (token
.value
== TOK
.dot
);
2234 private AST
.DebugSymbol
parseDebugSpecification()
2238 if (token
.value
== TOK
.identifier
)
2239 s
= new AST
.DebugSymbol(token
.loc
, token
.ident
);
2240 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2242 // @@@DEPRECATED_2.111@@@
2243 // Deprecated in 2.101, remove in 2.111
2244 deprecation("`debug = <integer>` is deprecated, use debug identifiers instead");
2246 s
= new AST
.DebugSymbol(token
.loc
, cast(uint)token
.unsvalue
);
2250 error("identifier or integer expected, not `%s`", token
.toChars());
2254 if (token
.value
!= TOK
.semicolon
)
2255 error("semicolon expected");
2260 /**************************************
2261 * Parse a debug conditional
2263 private AST
.Condition
parseDebugCondition()
2266 Identifier id
= null;
2267 Loc loc
= token
.loc
;
2269 if (token
.value
== TOK
.leftParenthesis
)
2273 if (token
.value
== TOK
.identifier
)
2275 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2277 // @@@DEPRECATED_2.111@@@
2278 // Deprecated in 2.101, remove in 2.111
2279 deprecation("`debug( <integer> )` is deprecated, use debug identifiers instead");
2281 level
= cast(uint)token
.unsvalue
;
2284 error("identifier or integer expected inside `debug(...)`, not `%s`", token
.toChars());
2287 check(TOK
.rightParenthesis
);
2289 return new AST
.DebugCondition(loc
, mod
, level
, id
);
2292 /**************************************
2293 * Parse a version specification
2295 private AST
.VersionSymbol
parseVersionSpecification()
2297 AST
.VersionSymbol s
;
2299 if (token
.value
== TOK
.identifier
)
2300 s
= new AST
.VersionSymbol(token
.loc
, token
.ident
);
2301 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2303 // @@@DEPRECATED_2.111@@@
2304 // Deprecated in 2.101, remove in 2.111
2305 deprecation("`version = <integer>` is deprecated, use version identifiers instead");
2306 s
= new AST
.VersionSymbol(token
.loc
, cast(uint)token
.unsvalue
);
2310 error("identifier or integer expected, not `%s`", token
.toChars());
2314 if (token
.value
!= TOK
.semicolon
)
2315 error("semicolon expected");
2320 /**************************************
2321 * Parse a version conditional
2323 private AST
.Condition
parseVersionCondition()
2326 Identifier id
= null;
2329 if (token
.value
== TOK
.leftParenthesis
)
2333 * version (unittest)
2335 * even though they are keywords
2338 if (token
.value
== TOK
.identifier
)
2340 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2342 // @@@DEPRECATED_2.111@@@
2343 // Deprecated in 2.101, remove in 2.111
2344 deprecation("`version( <integer> )` is deprecated, use version identifiers instead");
2346 level
= cast(uint)token
.unsvalue
;
2348 else if (token
.value
== TOK
.unittest_
)
2349 id
= Identifier
.idPool(Token
.toString(TOK
.unittest_
));
2350 else if (token
.value
== TOK
.assert_
)
2351 id
= Identifier
.idPool(Token
.toString(TOK
.assert_
));
2353 error("identifier or integer expected inside `version(...)`, not `%s`", token
.toChars());
2355 check(TOK
.rightParenthesis
);
2358 error("(condition) expected following `version`");
2359 return new AST
.VersionCondition(loc
, mod
, level
, id
);
2362 /***********************************************
2363 * static if (expression)
2367 * Current token is 'static'.
2369 private AST
.Condition
parseStaticIfCondition()
2372 AST
.Condition condition
;
2373 const loc
= token
.loc
;
2377 if (token
.value
== TOK
.leftParenthesis
)
2380 exp
= parseAssignExp();
2381 check(TOK
.rightParenthesis
);
2385 error("(expression) expected following `static if`");
2388 condition
= new AST
.StaticIfCondition(loc
, exp
);
2392 /*****************************************
2393 * Parse a constructor definition:
2394 * this(parameters) { body }
2396 * this(this) { body }
2397 * or constructor template:
2398 * this(templateparameters)(parameters) { body }
2399 * Current token is 'this'.
2401 private AST
.Dsymbol
parseCtor(PrefixAttributes
!AST
* pAttrs
)
2403 AST
.Expressions
* udas
= null;
2404 const loc
= token
.loc
;
2405 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2408 if (token
.value
== TOK
.leftParenthesis
&& peekNext() == TOK
.this_
&& peekNext2() == TOK
.rightParenthesis
)
2410 // this(this) { ... }
2413 check(TOK
.rightParenthesis
);
2415 stc = parsePostfix(stc, &udas
);
2416 if (stc & STC
.immutable_
)
2417 deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit.");
2418 if (stc & STC
.shared_
)
2419 deprecation("`shared` postblit is deprecated. Please use an unqualified postblit.");
2420 if (stc & STC
.const_
)
2421 deprecation("`const` postblit is deprecated. Please use an unqualified postblit.");
2422 if (stc & STC
.static_
)
2423 error(loc
, "postblit cannot be `static`");
2425 auto f
= new AST
.PostBlitDeclaration(loc
, Loc
.initial
, stc, Id
.postblit
);
2426 AST
.Dsymbol s
= parseContracts(f
);
2429 auto a
= new AST
.Dsymbols();
2431 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2436 /* Look ahead to see if:
2438 * which is a constructor template
2440 AST
.TemplateParameters
* tpl
= null;
2441 if (token
.value
== TOK
.leftParenthesis
&& peekPastParen(&token
).value
== TOK
.leftParenthesis
)
2443 tpl
= parseTemplateParameterList();
2446 /* Just a regular constructor
2448 auto parameterList
= parseParameterList(null);
2449 stc = parsePostfix(stc, &udas
);
2451 if (parameterList
.varargs
!= VarArg
.none || AST
.Parameter
.dim(parameterList
.parameters
) != 0)
2453 if (stc & STC
.static_
)
2454 error(loc
, "constructor cannot be static");
2456 else if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
)) // this()
2458 if (ss
== STC
.static_
)
2459 error(loc
, "use `static this()` to declare a static constructor");
2460 else if (ss
== (STC
.shared_ | STC
.static_
))
2461 error(loc
, "use `shared static this()` to declare a shared static constructor");
2464 AST
.Expression constraint
= tpl ?
parseConstraint() : null;
2466 AST
.Type tf
= new AST
.TypeFunction(parameterList
, null, linkage
, stc); // RetrunType -> auto
2467 tf
= tf
.addSTC(stc);
2469 auto f
= new AST
.CtorDeclaration(loc
, Loc
.initial
, stc, tf
);
2470 AST
.Dsymbol s
= parseContracts(f
, !!tpl
);
2473 auto a
= new AST
.Dsymbols();
2475 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2480 // Wrap a template around it
2481 auto decldefs
= new AST
.Dsymbols();
2483 s
= new AST
.TemplateDeclaration(loc
, f
.ident
, tpl
, constraint
, decldefs
);
2489 /*****************************************
2490 * Parse a destructor definition:
2492 * Current token is '~'.
2494 private AST
.Dsymbol
parseDtor(PrefixAttributes
!AST
* pAttrs
)
2496 AST
.Expressions
* udas
= null;
2497 const loc
= token
.loc
;
2498 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2502 check(TOK
.leftParenthesis
);
2503 check(TOK
.rightParenthesis
);
2505 stc = parsePostfix(stc, &udas
);
2506 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2508 if (ss
== STC
.static_
)
2509 error(loc
, "use `static ~this()` to declare a static destructor");
2510 else if (ss
== (STC
.shared_ | STC
.static_
))
2511 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
2514 auto f
= new AST
.DtorDeclaration(loc
, Loc
.initial
, stc, Id
.dtor
);
2515 AST
.Dsymbol s
= parseContracts(f
);
2518 auto a
= new AST
.Dsymbols();
2520 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2525 /*****************************************
2526 * Parse a static constructor definition:
2527 * static this() { body }
2528 * Current token is 'static'.
2530 private AST
.Dsymbol
parseStaticCtor(PrefixAttributes
!AST
* pAttrs
)
2532 //Expressions *udas = NULL;
2533 const loc
= token
.loc
;
2534 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2538 check(TOK
.leftParenthesis
);
2539 check(TOK
.rightParenthesis
);
2541 stc = parsePostfix(stc & ~STC
.TYPECTOR
, null) |
stc;
2542 if (stc & STC
.shared_
)
2543 error(loc
, "use `shared static this()` to declare a shared static constructor");
2544 else if (stc & STC
.static_
)
2545 appendStorageClass(stc, STC
.static_
); // complaint for the redundancy
2546 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2549 AST
.stcToBuffer(buf
, modStc
);
2550 error(loc
, "static constructor cannot be `%s`", buf
.peekChars());
2552 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2554 auto f
= new AST
.StaticCtorDeclaration(loc
, Loc
.initial
, stc);
2555 AST
.Dsymbol s
= parseContracts(f
);
2559 /*****************************************
2560 * Parse a static destructor definition:
2561 * static ~this() { body }
2562 * Current token is 'static'.
2564 private AST
.Dsymbol
parseStaticDtor(PrefixAttributes
!AST
* pAttrs
)
2566 AST
.Expressions
* udas
= null;
2567 const loc
= token
.loc
;
2568 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2573 check(TOK
.leftParenthesis
);
2574 check(TOK
.rightParenthesis
);
2576 stc = parsePostfix(stc & ~STC
.TYPECTOR
, &udas
) |
stc;
2577 if (stc & STC
.shared_
)
2578 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
2579 else if (stc & STC
.static_
)
2580 appendStorageClass(stc, STC
.static_
); // complaint for the redundancy
2581 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2584 AST
.stcToBuffer(buf
, modStc
);
2585 error(loc
, "static destructor cannot be `%s`", buf
.peekChars());
2587 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2589 auto f
= new AST
.StaticDtorDeclaration(loc
, Loc
.initial
, stc);
2590 AST
.Dsymbol s
= parseContracts(f
);
2593 auto a
= new AST
.Dsymbols();
2595 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2600 /*****************************************
2601 * Parse a shared static constructor definition:
2602 * shared static this() { body }
2603 * Current token is 'shared'.
2605 private AST
.Dsymbol
parseSharedStaticCtor(PrefixAttributes
!AST
* pAttrs
)
2607 //Expressions *udas = NULL;
2608 const loc
= token
.loc
;
2609 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2614 check(TOK
.leftParenthesis
);
2615 check(TOK
.rightParenthesis
);
2617 stc = parsePostfix(stc & ~STC
.TYPECTOR
, null) |
stc;
2618 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2619 appendStorageClass(stc, ss
); // complaint for the redundancy
2620 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2623 AST
.stcToBuffer(buf
, modStc
);
2624 error(loc
, "shared static constructor cannot be `%s`", buf
.peekChars());
2626 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2628 auto f
= new AST
.SharedStaticCtorDeclaration(loc
, Loc
.initial
, stc);
2629 AST
.Dsymbol s
= parseContracts(f
);
2633 /*****************************************
2634 * Parse a shared static destructor definition:
2635 * shared static ~this() { body }
2636 * Current token is 'shared'.
2638 private AST
.Dsymbol
parseSharedStaticDtor(PrefixAttributes
!AST
* pAttrs
)
2640 AST
.Expressions
* udas
= null;
2641 const loc
= token
.loc
;
2642 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2648 check(TOK
.leftParenthesis
);
2649 check(TOK
.rightParenthesis
);
2651 stc = parsePostfix(stc & ~STC
.TYPECTOR
, &udas
) |
stc;
2652 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2653 appendStorageClass(stc, ss
); // complaint for the redundancy
2654 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2657 AST
.stcToBuffer(buf
, modStc
);
2658 error(loc
, "shared static destructor cannot be `%s`", buf
.peekChars());
2660 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2662 auto f
= new AST
.SharedStaticDtorDeclaration(loc
, Loc
.initial
, stc);
2663 AST
.Dsymbol s
= parseContracts(f
);
2666 auto a
= new AST
.Dsymbols();
2668 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2673 /*****************************************
2674 * Parse an invariant definition:
2675 * invariant { statements... }
2676 * invariant() { statements... }
2677 * invariant (expression);
2678 * Current token is 'invariant'.
2680 private AST
.Dsymbol
parseInvariant(PrefixAttributes
!AST
* pAttrs
)
2682 const loc
= token
.loc
;
2683 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2686 if (token
.value
== TOK
.leftParenthesis
) // optional () or invariant (expression);
2689 if (token
.value
!= TOK
.rightParenthesis
) // invariant (expression);
2691 AST
.Expression e
= parseAssignExp(), msg
= null;
2692 if (token
.value
== TOK
.comma
)
2695 if (token
.value
!= TOK
.rightParenthesis
)
2697 msg
= parseAssignExp();
2698 if (token
.value
== TOK
.comma
)
2702 check(TOK
.rightParenthesis
);
2703 check(TOK
.semicolon
, "invariant");
2704 e
= new AST
.AssertExp(loc
, e
, msg
);
2705 auto fbody
= new AST
.ExpStatement(loc
, e
);
2706 auto f
= new AST
.InvariantDeclaration(loc
, token
.loc
, stc, null, fbody
);
2712 auto fbody
= parseStatement(ParseStatementFlags
.curly
);
2713 auto f
= new AST
.InvariantDeclaration(loc
, token
.loc
, stc, null, fbody
);
2717 /*****************************************
2718 * Parse a unittest definition:
2720 * Current token is 'unittest'.
2722 private AST
.Dsymbol
parseUnitTest(PrefixAttributes
!AST
* pAttrs
)
2724 const loc
= token
.loc
;
2725 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2729 const(char)* begPtr
= token
.ptr
+ 1; // skip left curly brace
2730 const(char)* endPtr
= null;
2731 AST
.Statement sbody
= parseStatement(ParseStatementFlags
.curly
, &endPtr
);
2733 /** Extract unittest body as a string. Must be done eagerly since memory
2734 will be released by the lexer before doc gen. */
2735 char* docline
= null;
2736 if (compileEnv
.ddocOutput
&& endPtr
> begPtr
)
2738 /* Remove trailing whitespaces */
2739 for (const(char)* p
= endPtr
- 1; begPtr
<= p
&& (*p
== ' ' ||
*p
== '\r' ||
*p
== '\n' ||
*p
== '\t'); --p
)
2744 size_t len
= endPtr
- begPtr
;
2747 docline
= cast(char*)mem
.xmalloc_noscan(len
+ 2);
2748 memcpy(docline
, begPtr
, len
);
2749 docline
[len
] = '\n'; // Terminate all lines by LF
2750 docline
[len
+ 1] = '\0';
2754 auto f
= new AST
.UnitTestDeclaration(loc
, token
.loc
, stc, docline
);
2759 /*****************************************
2760 * Parse a new definition:
2762 * Current token is 'new'.
2764 private AST
.Dsymbol
parseNew(PrefixAttributes
!AST
* pAttrs
)
2766 const loc
= token
.loc
;
2767 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2768 if (!(stc & STC
.disable
))
2770 error("`new` allocator must be annotated with `@disabled`");
2774 /* @@@DEPRECATED_2.108@@@
2775 * After deprecation period (2.108), remove all code in the version(all) block.
2779 auto parameterList
= parseParameterList(null); // parameterList ignored
2780 if (parameterList
.parameters
.length
> 0 || parameterList
.varargs
!= VarArg
.none
)
2781 deprecation("`new` allocator with non-empty parameter list is deprecated");
2782 auto f
= new AST
.NewDeclaration(loc
, stc);
2783 if (token
.value
!= TOK
.semicolon
)
2785 deprecation("`new` allocator with function definition is deprecated");
2786 parseContracts(f
); // body ignored
2797 check(TOK
.leftParenthesis
);
2798 check(TOK
.rightParenthesis
);
2799 check(TOK
.semicolon
);
2800 return new AST
.NewDeclaration(loc
, stc);
2804 /**********************************************
2805 * Parse parameter list.
2807 private AST
.ParameterList
parseParameterList(AST
.TemplateParameters
** tpl
)
2809 auto parameters
= new AST
.Parameters();
2810 VarArg varargs
= VarArg
.none
;
2811 StorageClass varargsStc
;
2813 // Attributes allowed for ...
2814 enum VarArgsStc
= STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.scope_ | STC
.return_ | STC
.returnScope
;
2816 check(TOK
.leftParenthesis
);
2819 Identifier ai
= null;
2821 StorageClass storageClass
= 0;
2824 AST
.Expressions
* udas
= null;
2825 for (; 1; nextToken())
2828 switch (token
.value
)
2830 case TOK
.rightParenthesis
:
2831 if (storageClass
!= 0 || udas
!is null)
2832 error("basic type expected, not `)`");
2836 varargs
= VarArg
.variadic
;
2837 varargsStc
= storageClass
;
2838 if (varargsStc
& ~VarArgsStc
)
2841 AST
.stcToBuffer(buf
, varargsStc
& ~VarArgsStc
);
2842 error("variadic parameter cannot have attributes `%s`", buf
.peekChars());
2843 varargsStc
&= VarArgsStc
;
2849 if (peekNext() == TOK
.leftParenthesis
)
2854 case TOK
.immutable_
:
2855 if (peekNext() == TOK
.leftParenthesis
)
2857 stc = STC
.immutable_
;
2861 if (peekNext() == TOK
.leftParenthesis
)
2867 if (peekNext() == TOK
.leftParenthesis
)
2873 AST
.Expressions
* exps
= null;
2874 StorageClass stc2
= parseAttribute(exps
);
2875 if (stc2
& atAttrGroup
)
2877 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2881 udas
= AST
.UserAttributeDeclaration
.concat(udas
, exps
);
2883 if (token
.value
== TOK
.dotDotDot
)
2884 error("variadic parameter cannot have user-defined attributes");
2888 // Don't call nextToken again.
2892 eSink
.message(scanloc
, "Usage of 'in' on parameter");
2922 if (peekNext() == TOK
.scope_
)
2923 stc |
= STC
.returnScope
;
2926 storageClass
= appendStorageClass(storageClass
, stc);
2931 stc = storageClass
& (STC
.IOR | STC
.lazy_
);
2932 // if stc is not a power of 2
2933 if (stc & (stc - 1) && !(stc == (STC
.in_ | STC
.ref_
)))
2934 error("incompatible parameter storage classes");
2935 //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
2936 //error("scope cannot be ref or out");
2938 const tv
= peekNext();
2940 if (tpl
&& token
.value
== TOK
.identifier
&&
2941 (tv
== TOK
.comma || tv
== TOK
.rightParenthesis || tv
== TOK
.dotDotDot
))
2943 Identifier id
= Identifier
.generateId("__T");
2945 at
= new AST
.TypeIdentifier(loc
, id
);
2947 *tpl
= new AST
.TemplateParameters();
2948 AST
.TemplateParameter tp
= new AST
.TemplateTypeParameter(loc
, id
, null, null);
2956 at
= parseType(&ai
, null, &loc
);
2959 if (token
.value
== TOK
.assign
) // = defaultArg
2962 ae
= parseDefaultInitExp();
2964 auto param
= new AST
.Parameter(loc
, storageClass | STC
.parameter
, at
, ai
, ae
, null);
2967 auto a
= new AST
.Dsymbols();
2968 auto udad
= new AST
.UserAttributeDeclaration(udas
, a
);
2969 param
.userAttribDecl
= udad
;
2971 if (token
.value
== TOK
.at
)
2973 AST
.Expressions
* exps
= null;
2974 StorageClass stc2
= parseAttribute(exps
);
2975 if (stc2
& atAttrGroup
)
2977 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2981 error("user-defined attributes cannot appear as postfixes", token
.toChars());
2986 if (token
.value
== TOK
.dotDotDot
)
2991 if (storageClass
& (STC
.out_ | STC
.ref_
))
2992 error("variadic argument cannot be `out` or `ref`");
2993 varargs
= VarArg
.typesafe
;
2994 parameters
.push(param
);
2998 parameters
.push(param
);
2999 if (token
.value
== TOK
.comma
)
3013 check(TOK
.rightParenthesis
);
3014 return AST
.ParameterList(parameters
, varargs
, varargsStc
);
3017 /*************************************
3019 private AST
.EnumDeclaration
parseEnum()
3021 AST
.EnumDeclaration e
;
3024 auto loc
= token
.loc
;
3026 // printf("Parser::parseEnum()\n");
3029 if (token
.value
== TOK
.identifier
)
3036 if (token
.value
== TOK
.colon
)
3040 const typeLoc
= token
.loc
;
3041 memtype
= parseBasicType();
3042 memtype
= parseDeclarator(memtype
, alt
, null);
3043 checkCstyleTypeSyntax(typeLoc
, memtype
, alt
, null);
3046 e
= new AST
.EnumDeclaration(loc
, id
, memtype
);
3048 if (token
.value
== TOK
.semicolon
&& id
)
3050 else if (token
.value
== TOK
.leftCurly
)
3052 bool isAnonymousEnum
= !id
;
3054 //printf("enum definition\n");
3055 e
.members
= new AST
.Dsymbols();
3057 const(char)[] comment
= token
.blockComment
;
3058 while (token
.value
!= TOK
.rightCurly
)
3060 /* Can take the following forms...
3063 * 3. type ident = value
3064 * ... prefixed by valid attributes
3068 AST
.Type type
= null;
3069 Identifier ident
= null;
3071 AST
.Expressions
* udas
;
3073 AST
.Expression deprecationMessage
;
3074 enum attributeErrorMessage
= "`%s` is not a valid attribute for enum members";
3078 switch (token
.value
)
3081 if (StorageClass _stc
= parseAttribute(udas
))
3083 if (_stc
== STC
.disable
)
3088 AST
.stcToBuffer(buf
, _stc
);
3089 error(attributeErrorMessage
, buf
.peekChars());
3094 case TOK
.deprecated_
:
3095 stc |
= STC
.deprecated_
;
3096 if (!parseDeprecatedAttribute(deprecationMessage
))
3105 if (token
.value
== TOK
.identifier
)
3107 const tv
= peekNext();
3108 if (tv
== TOK
.assign || tv
== TOK
.comma || tv
== TOK
.rightCurly
)
3110 ident
= token
.ident
;
3116 if (isAnonymousEnum
)
3120 error("expected `,` or `=` after identifier, not `%s`", token
.toChars());
3125 if (isAnonymousEnum
)
3129 type
= parseType(&ident
, null);
3130 if (type
== AST
.Type
.terror
)
3137 error("no identifier for declarator `%s`", type
.toChars());
3142 const tv
= token
.value
;
3143 if (tv
!= TOK
.assign
&& tv
!= TOK
.comma
&& tv
!= TOK
.rightCurly
)
3145 error("expected `,` or `=` after identifier, not `%s`", token
.toChars());
3153 if (isBasicType(&t
))
3155 error("named enum cannot declare member with type", (*t
).toChars());
3159 check(TOK
.identifier
);
3161 // avoid extra error messages
3162 const tv
= token
.value
;
3163 if (tv
!= TOK
.assign
&& tv
!= TOK
.comma
&& tv
!= TOK
.rightCurly
&& tv
!= TOK
.endOfFile
)
3168 AST
.Expression value
;
3169 if (token
.value
== TOK
.assign
)
3172 value
= parseAssignExp();
3177 if (type
&& isAnonymousEnum
)
3178 error("initializer required after `%s` when type is specified", ident
.toChars());
3181 AST
.DeprecatedDeclaration
dd;
3182 if (deprecationMessage
)
3184 dd = new AST
.DeprecatedDeclaration(deprecationMessage
, null);
3185 stc |
= STC
.deprecated_
;
3188 auto em
= new AST
.EnumMember(loc
, ident
, value
, type
, stc, null, dd);
3193 auto uad
= new AST
.UserAttributeDeclaration(udas
, new AST
.Dsymbols());
3194 em
.userAttribDecl
= uad
;
3197 if (token
.value
!= TOK
.rightCurly
)
3199 addComment(em
, comment
);
3203 addComment(em
, comment
);
3204 comment
= token
.blockComment
;
3206 if (token
.value
== TOK
.endOfFile
)
3208 error("premature end of file");
3217 error("expected `{`, not `%s` for enum declaration", token
.toChars());
3219 //printf("-parseEnum() %s\n", e.toChars());
3223 /********************************
3224 * Parse struct, union, interface, class.
3226 private AST
.Dsymbol
parseAggregate()
3228 AST
.TemplateParameters
* tpl
= null;
3229 AST
.Expression constraint
;
3230 const loc
= token
.loc
;
3231 TOK tok
= token
.value
;
3233 //printf("Parser::parseAggregate()\n");
3236 if (token
.value
!= TOK
.identifier
)
3245 if (token
.value
== TOK
.leftParenthesis
)
3247 // struct/class template declaration.
3248 tpl
= parseTemplateParameterList();
3249 constraint
= parseConstraint();
3253 // Collect base class(es)
3254 AST
.BaseClasses
* baseclasses
= null;
3255 if (token
.value
== TOK
.colon
)
3257 if (tok
!= TOK
.interface_
&& tok
!= TOK
.class_
)
3258 error("base classes are not allowed for `%s`, did you mean `;`?", Token
.toChars(tok
));
3260 baseclasses
= parseBaseClasses();
3263 if (token
.value
== TOK
.if_
)
3266 error("template constraints appear both before and after BaseClassList, put them before");
3267 constraint
= parseConstraint();
3272 error("template constraints not allowed for anonymous `%s`", Token
.toChars(tok
));
3274 error("template constraints only allowed for templates");
3277 AST
.Dsymbols
* members
= null;
3278 if (token
.value
== TOK
.leftCurly
)
3280 //printf("aggregate definition\n");
3281 const lookingForElseSave
= lookingForElse
;
3282 lookingForElse
= Loc();
3284 members
= parseDeclDefs(0);
3285 lookingForElse
= lookingForElseSave
;
3286 if (token
.value
!= TOK
.rightCurly
)
3289 error(token
.loc
, "`}` expected following members in `%s` declaration",
3290 Token
.toChars(tok
));
3292 eSink
.errorSupplemental(loc
, "%s `%s` starts here",
3293 Token
.toChars(tok
), id
.toChars());
3295 eSink
.errorSupplemental(loc
, "%s starts here",
3296 Token
.toChars(tok
));
3300 else if (token
.value
== TOK
.semicolon
&& id
)
3302 if (baseclasses || constraint
)
3303 error("members expected");
3308 error(token
.loc
, "{ } expected following `%s` declaration", Token
.toChars(tok
));
3311 AST
.AggregateDeclaration a
;
3314 case TOK
.interface_
:
3316 error(loc
, "anonymous interfaces not allowed");
3317 a
= new AST
.InterfaceDeclaration(loc
, id
, baseclasses
);
3318 a
.members
= members
;
3323 error(loc
, "anonymous classes not allowed");
3324 bool inObject
= md
&& !md
.packages
&& md
.id
== Id
.object
;
3325 a
= new AST
.ClassDeclaration(loc
, id
, baseclasses
, members
, inObject
);
3331 bool inObject
= md
&& !md
.packages
&& md
.id
== Id
.object
;
3332 a
= new AST
.StructDeclaration(loc
, id
, inObject
);
3333 a
.members
= members
;
3337 /* Anonymous structs/unions are more like attributes.
3340 return new AST
.AnonDeclaration(loc
, false, members
);
3347 a
= new AST
.UnionDeclaration(loc
, id
);
3348 a
.members
= members
;
3352 /* Anonymous structs/unions are more like attributes.
3355 return new AST
.AnonDeclaration(loc
, true, members
);
3365 // Wrap a template around the aggregate declaration
3366 auto decldefs
= new AST
.Dsymbols();
3368 auto tempdecl
= new AST
.TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
);
3374 /*******************************************
3376 private AST
.BaseClasses
* parseBaseClasses()
3378 auto baseclasses
= new AST
.BaseClasses();
3380 for (; 1; nextToken())
3382 auto b
= new AST
.BaseClass(parseBasicType());
3383 baseclasses
.push(b
);
3384 if (token
.value
!= TOK
.comma
)
3390 AST
.Dsymbols
* parseImport()
3392 auto decldefs
= new AST
.Dsymbols();
3393 Identifier aliasid
= null;
3395 int isstatic
= token
.value
== TOK
.static_
;
3399 //printf("Parser::parseImport()\n");
3404 if (token
.value
!= TOK
.identifier
)
3406 error("identifier expected following `import`");
3410 const loc
= token
.loc
;
3411 Identifier id
= token
.ident
;
3414 if (!aliasid
&& token
.value
== TOK
.assign
)
3419 while (token
.value
== TOK
.dot
)
3423 if (token
.value
!= TOK
.identifier
)
3425 error("identifier expected following `package`");
3432 auto s
= new AST
.Import(loc
, a
, id
, aliasid
, isstatic
);
3436 * : alias=name, alias=name;
3439 if (token
.value
== TOK
.colon
)
3444 if (token
.value
!= TOK
.identifier
)
3446 error("identifier expected following `:`");
3449 Identifier _alias
= token
.ident
;
3452 if (token
.value
== TOK
.assign
)
3455 if (token
.value
!= TOK
.identifier
)
3457 error("identifier expected following `%s=`", _alias
.toChars());
3468 s
.addAlias(name
, _alias
);
3470 while (token
.value
== TOK
.comma
);
3471 break; // no comma-separated imports of this form
3475 while (token
.value
== TOK
.comma
);
3477 if (token
.value
== TOK
.semicolon
)
3481 error("`;` expected");
3488 /* Parse a type and optional identifier
3490 * pident = set to Identifier if there is one, null if not
3491 * ptpl = if !null, then set to TemplateParameterList
3492 * pdeclLoc = if !null, then set to location of the declarator
3494 AST
.Type
parseType(Identifier
* pident
= null, AST
.TemplateParameters
** ptpl
= null, Loc
* pdeclLoc
= null)
3496 /* Take care of the storage class prefixes that
3497 * serve as type attributes:
3505 * shared inout const type
3507 StorageClass
stc = 0;
3510 switch (token
.value
)
3513 if (peekNext() == TOK
.leftParenthesis
)
3514 break; // const as type constructor
3515 stc |
= STC
.const_
; // const as storage class
3519 case TOK
.immutable_
:
3520 if (peekNext() == TOK
.leftParenthesis
)
3522 stc |
= STC
.immutable_
;
3527 if (peekNext() == TOK
.leftParenthesis
)
3534 if (peekNext() == TOK
.leftParenthesis
)
3546 const typeLoc
= token
.loc
;
3549 t
= parseBasicType();
3552 *pdeclLoc
= token
.loc
;
3554 t
= parseDeclarator(t
, alt
, pident
, ptpl
);
3555 checkCstyleTypeSyntax(typeLoc
, t
, alt
, pident ?
*pident
: null);
3561 private AST
.Type
parseBasicType(bool dontLookDotIdents
= false)
3566 //printf("parseBasicType()\n");
3567 switch (token
.value
)
3582 t
= AST
.Type
.tint16
;
3586 t
= AST
.Type
.tuns16
;
3590 t
= AST
.Type
.tint32
;
3594 t
= AST
.Type
.tuns32
;
3598 t
= AST
.Type
.tint64
;
3600 if (token
.value
== TOK
.int64
) // if `long long`
3602 error("use `long` for a 64 bit integer instead of `long long`");
3605 else if (token
.value
== TOK
.float64
) // if `long double`
3607 error("use `real` instead of `long double`");
3608 t
= AST
.Type
.tfloat80
;
3614 t
= AST
.Type
.tuns64
;
3618 t
= AST
.Type
.tint128
;
3622 t
= AST
.Type
.tuns128
;
3626 t
= AST
.Type
.tfloat32
;
3630 t
= AST
.Type
.tfloat64
;
3634 t
= AST
.Type
.tfloat80
;
3637 case TOK
.imaginary32
:
3638 t
= AST
.Type
.timaginary32
;
3641 case TOK
.imaginary64
:
3642 t
= AST
.Type
.timaginary64
;
3645 case TOK
.imaginary80
:
3646 t
= AST
.Type
.timaginary80
;
3650 t
= AST
.Type
.tcomplex32
;
3654 t
= AST
.Type
.tcomplex64
;
3658 t
= AST
.Type
.tcomplex80
;
3670 t
= AST
.Type
.twchar
;
3674 t
= AST
.Type
.tdchar
;
3682 case TOK
.identifier
:
3686 if (token
.value
== TOK
.not)
3688 // ident!(template_arguments)
3689 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
3690 t
= parseBasicTypeStartingAt(new AST
.TypeInstance(loc
, tempinst
), dontLookDotIdents
);
3694 t
= parseBasicTypeStartingAt(new AST
.TypeIdentifier(loc
, id
), dontLookDotIdents
);
3699 // https://dlang.org/spec/expression.html#mixin_types
3702 if (token
.value
!= TOK
.leftParenthesis
)
3703 error(token
.loc
, "found `%s` when expecting `%s` following `mixin`", token
.toChars(), Token
.toChars(TOK
.leftParenthesis
));
3704 auto exps
= parseArguments();
3705 t
= new AST
.TypeMixin(loc
, exps
);
3709 // Leading . as in .foo
3710 t
= parseBasicTypeStartingAt(new AST
.TypeIdentifier(token
.loc
, Id
.empty
), dontLookDotIdents
);
3714 // typeof(expression)
3715 t
= parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents
);
3723 if (AST
.TraitsExp te
= cast(AST
.TraitsExp
) parsePrimaryExp())
3726 t
= new AST
.TypeTraits(token
.loc
, te
);
3729 t
= new AST
.TypeError
;
3735 check(TOK
.leftParenthesis
);
3736 t
= parseType().addSTC(STC
.const_
);
3737 check(TOK
.rightParenthesis
);
3740 case TOK
.immutable_
:
3743 check(TOK
.leftParenthesis
);
3744 t
= parseType().addSTC(STC
.immutable_
);
3745 check(TOK
.rightParenthesis
);
3751 check(TOK
.leftParenthesis
);
3752 t
= parseType().addSTC(STC
.shared_
);
3753 check(TOK
.rightParenthesis
);
3759 check(TOK
.leftParenthesis
);
3760 t
= parseType().addSTC(STC
.wild
);
3761 check(TOK
.rightParenthesis
);
3765 error("basic type expected, not `%s`", token
.toChars());
3766 if (token
.value
== TOK
.else_
)
3767 eSink
.errorSupplemental(token
.loc
, "There's no `static else`, use `else` instead.");
3768 t
= AST
.Type
.terror
;
3774 private AST
.Type
parseBasicTypeStartingAt(AST
.TypeQualified tid
, bool dontLookDotIdents
)
3776 AST
.Type maybeArray
= null;
3777 // See https://issues.dlang.org/show_bug.cgi?id=1215
3778 // A basic type can look like MyType (typical case), but also:
3779 // MyType.T -> A type
3780 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3781 // MyType[expr].T -> A type.
3782 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3783 // (iif MyType[expr].T is a Ttuple)
3786 switch (token
.value
)
3791 if (token
.value
!= TOK
.identifier
)
3793 error("identifier expected following `.` instead of `%s`", token
.toChars());
3798 // This is actually a TypeTuple index, not an {a/s}array.
3799 // We need to have a while loop to unwind all index taking:
3800 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3801 AST
.Objects dimStack
;
3802 AST
.Type t
= maybeArray
;
3805 if (t
.ty
== Tsarray
)
3807 // The index expression is an Expression.
3808 AST
.TypeSArray a
= cast(AST
.TypeSArray
)t
;
3809 dimStack
.push(a
.dim
.syntaxCopy());
3810 t
= a
.next
.syntaxCopy();
3812 else if (t
.ty
== Taarray
)
3814 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3815 AST
.TypeAArray a
= cast(AST
.TypeAArray
)t
;
3816 dimStack
.push(a
.index
.syntaxCopy());
3817 t
= a
.next
.syntaxCopy();
3824 assert(dimStack
.length
> 0);
3825 // We're good. Replay indices in the reverse order.
3826 tid
= cast(AST
.TypeQualified
)t
;
3827 while (dimStack
.length
)
3829 tid
.addIndex(dimStack
.pop());
3833 const loc
= token
.loc
;
3834 Identifier id
= token
.ident
;
3836 if (token
.value
== TOK
.not)
3838 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
3839 tid
.addInst(tempinst
);
3845 case TOK
.leftBracket
:
3847 if (dontLookDotIdents
) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911
3851 AST
.Type t
= maybeArray ? maybeArray
: cast(AST
.Type
)tid
;
3852 if (token
.value
== TOK
.rightBracket
)
3854 // It's a dynamic array, and we're done:
3855 // T[].U does not make sense.
3856 t
= new AST
.TypeDArray(t
);
3860 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
3862 // This can be one of two things:
3863 // 1 - an associative array declaration, T[type]
3864 // 2 - an associative array declaration, T[expr]
3865 // These can only be disambiguated later.
3866 AST
.Type index
= parseType(); // [ type ]
3867 maybeArray
= new AST
.TypeAArray(t
, index
);
3868 check(TOK
.rightBracket
);
3872 // This can be one of three things:
3873 // 1 - an static array declaration, T[expr]
3874 // 2 - a slice, T[expr .. expr]
3875 // 3 - a template parameter pack index expression, T[expr].U
3876 // 1 and 3 can only be disambiguated later.
3877 //printf("it's type[expression]\n");
3879 AST
.Expression e
= parseAssignExp(); // [ expression ]
3880 if (token
.value
== TOK
.slice
)
3882 // It's a slice, and we're done.
3884 AST
.Expression e2
= parseAssignExp(); // [ exp .. exp ]
3885 t
= new AST
.TypeSlice(t
, e
, e2
);
3887 check(TOK
.rightBracket
);
3892 maybeArray
= new AST
.TypeSArray(t
, e
);
3894 check(TOK
.rightBracket
);
3905 return maybeArray ? maybeArray
: cast(AST
.Type
)tid
;
3908 /******************************************
3909 * Parse suffixes to type t.
3912 * [AssignExpression]
3913 * [AssignExpression .. AssignExpression]
3915 * delegate Parameters MemberFunctionAttributes(opt)
3916 * function Parameters FunctionAttributes(opt)
3918 * t = the already parsed type
3920 * t with the suffixes added
3922 * https://dlang.org/spec/declaration.html#TypeSuffixes
3924 private AST
.Type
parseTypeSuffixes(AST
.Type t
)
3926 //printf("parseTypeSuffixes()\n");
3929 switch (token
.value
)
3932 t
= new AST
.TypePointer(t
);
3936 case TOK
.leftBracket
:
3937 // Handle []. Make sure things like
3939 // is (array[1] of array[3] of int)
3941 if (token
.value
== TOK
.rightBracket
)
3943 t
= new AST
.TypeDArray(t
); // []
3946 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
3948 // It's an associative array declaration
3949 //printf("it's an associative array\n");
3950 AST
.Type index
= parseType(); // [ type ]
3951 t
= new AST
.TypeAArray(t
, index
);
3952 check(TOK
.rightBracket
);
3956 //printf("it's type[expression]\n");
3958 AST
.Expression e
= parseAssignExp(); // [ expression ]
3962 check(TOK
.rightBracket
);
3965 if (token
.value
== TOK
.slice
)
3968 AST
.Expression e2
= parseAssignExp(); // [ exp .. exp ]
3969 t
= new AST
.TypeSlice(t
, e
, e2
);
3973 t
= new AST
.TypeSArray(t
, e
);
3976 check(TOK
.rightBracket
);
3983 // Handle delegate declaration:
3984 // t delegate(parameter list) nothrow pure
3985 // t function(parameter list) nothrow pure
3986 const save
= token
.value
;
3989 auto parameterList
= parseParameterList(null);
3991 StorageClass
stc = parsePostfix(STC
.undefined_
, null);
3992 auto tf
= new AST
.TypeFunction(parameterList
, t
, linkage
, stc);
3993 if (stc & (STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.wild | STC
.return_
))
3995 if (save
== TOK
.function_
)
3996 error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions");
3998 tf
= cast(AST
.TypeFunction
)tf
.addSTC(stc);
4000 t
= save
== TOK
.delegate_ ?
new AST
.TypeDelegate(tf
) : new AST
.TypePointer(tf
); // pointer to function
4011 /**********************
4014 * t = base type to start with
4015 * palt = OR in 1 for C-style function pointer declaration syntax,
4016 * 2 for C-style array declaration syntax, otherwise don't modify
4017 * pident = set to Identifier if there is one, null if not
4018 * tpl = if !null, then set to TemplateParameterList
4019 * storageClass = any storage classes seen so far
4020 * pdisable = set to true if @disable seen
4021 * pudas = any user defined attributes seen so far. Merged with any more found
4024 * Reference: https://dlang.org/spec/declaration.html#Declarator
4026 private AST
.Type
parseDeclarator(AST
.Type t
, ref int palt
, Identifier
* pident
,
4027 AST
.TemplateParameters
** tpl
= null, StorageClass storageClass
= 0,
4028 bool* pdisable
= null, AST
.Expressions
** pudas
= null)
4030 //printf("parseDeclarator(tpl = %p)\n", tpl);
4031 t
= parseTypeSuffixes(t
);
4033 switch (token
.value
)
4035 case TOK
.identifier
:
4037 *pident
= token
.ident
;
4039 error("unexpected identifier `%s` in declarator", token
.ident
.toChars());
4044 case TOK
.leftParenthesis
:
4047 // like: T ((*fp))();
4048 if (peekNext() == TOK
.mul ||
peekNext() == TOK
.leftParenthesis
)
4050 /* Parse things with parentheses around the identifier, like:
4052 * although the D style would be:
4057 ts
= parseDeclarator(t
, palt
, pident
);
4058 check(TOK
.rightParenthesis
);
4063 Token
* peekt
= &token
;
4064 /* Completely disallow C-style things like:
4066 * Improve error messages for the common bug of a missing return type
4067 * by looking to see if (a) looks like a parameter list.
4069 if (isParameters(&peekt
))
4071 error("function declaration without return type. (Note that constructors are always named `this`)");
4074 error("unexpected `(` in declarator");
4082 // parse DeclaratorSuffixes
4085 switch (token
.value
)
4087 static if (CARRAYDECL
)
4089 /* Support C style array syntax:
4091 * as opposed to D-style:
4094 case TOK
.leftBracket
:
4096 // This is the old C-style post [] syntax.
4099 if (token
.value
== TOK
.rightBracket
)
4101 // It's a dynamic array
4102 ta
= new AST
.TypeDArray(t
); // []
4106 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
4108 // It's an associative array
4109 //printf("it's an associative array\n");
4110 AST
.Type index
= parseType(); // [ type ]
4111 check(TOK
.rightBracket
);
4112 ta
= new AST
.TypeAArray(t
, index
);
4117 //printf("It's a static array\n");
4118 AST
.Expression e
= parseAssignExp(); // [ expression ]
4119 ta
= new AST
.TypeSArray(t
, e
);
4120 check(TOK
.rightBracket
);
4127 * ts -> ... -> ta -> t
4130 for (pt
= &ts
; *pt
!= t
; pt
= &(cast(AST
.TypeNext
)*pt
).next
)
4137 case TOK
.leftParenthesis
:
4141 Token
* tk
= peekPastParen(&token
);
4142 if (tk
.value
== TOK
.leftParenthesis
)
4144 /* Look ahead to see if this is (...)(...),
4145 * i.e. a function template declaration
4147 //printf("function template declaration\n");
4149 // Gather template parameter list
4150 *tpl
= parseTemplateParameterList();
4152 else if (tk
.value
== TOK
.assign
)
4155 * i.e. a variable template declaration
4157 //printf("variable template declaration\n");
4158 *tpl
= parseTemplateParameterList();
4163 auto parameterList
= parseParameterList(null);
4165 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
4167 // merge prefix storage classes
4168 StorageClass
stc = parsePostfix(storageClass
, pudas
);
4170 AST
.Type tf
= new AST
.TypeFunction(parameterList
, t
, linkage
, stc);
4171 tf
= tf
.addSTC(stc);
4173 *pdisable
= stc & STC
.disable ?
true : false;
4178 * ts -> ... -> tf -> t
4181 for (pt
= &ts
; *pt
!= t
; pt
= &(cast(AST
.TypeNext
)*pt
).next
)
4195 private void parseStorageClasses(ref StorageClass storage_class
, ref LINK link
,
4196 ref bool setAlignment
, ref AST
.Expression ealign
, ref AST
.Expressions
* udas
,
4200 bool sawLinkage
= false; // seen a linkage declaration
4202 linkloc
= Loc
.initial
;
4206 switch (token
.value
)
4209 if (peekNext() == TOK
.leftParenthesis
)
4210 break; // const as type constructor
4211 stc = STC
.const_
; // const as storage class
4214 case TOK
.immutable_
:
4215 if (peekNext() == TOK
.leftParenthesis
)
4217 stc = STC
.immutable_
;
4221 if (peekNext() == TOK
.leftParenthesis
)
4227 if (peekNext() == TOK
.leftParenthesis
)
4249 stc = STC
.override_
;
4253 stc = STC
.abstract_
;
4256 case TOK
.synchronized_
:
4257 stc = STC
.synchronized_
;
4260 case TOK
.deprecated_
:
4261 stc = STC
.deprecated_
;
4282 const tv
= peekNext();
4283 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
4285 if (tv
== TOK
.identifier
)
4287 const nextv
= peekNext2();
4288 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
4297 stc = parseAttribute(udas
);
4303 storage_class
= appendStorageClass(storage_class
, stc);
4309 if (peekNext() != TOK
.leftParenthesis
)
4316 error("redundant linkage declaration");
4318 linkloc
= token
.loc
;
4319 auto res
= parseLinkage();
4321 if (res
.idents || res
.identExps
)
4323 error("C++ name spaces not allowed here");
4325 if (res
.cppmangle
!= CPPMANGLE
.def
)
4327 error("C++ mangle declaration not allowed here");
4334 setAlignment
= true;
4335 if (token
.value
== TOK
.leftParenthesis
)
4338 ealign
= parseExpression();
4339 check(TOK
.rightParenthesis
);
4350 /**********************************
4351 * Parse Declarations.
4353 * 1. declarations at global/class level
4354 * 2. declarations at statement level
4356 * array of Declarations.
4358 private AST
.Dsymbols
* parseDeclarations(bool autodecl
, PrefixAttributes
!AST
* pAttrs
, const(char)* comment
)
4360 StorageClass storage_class
= STC
.undefined_
;
4361 LINK link
= linkage
;
4362 Loc linkloc
= this.linkLoc
;
4363 bool setAlignment
= false;
4364 AST
.Expression ealign
;
4365 AST
.Expressions
* udas
= null;
4367 //printf("parseDeclarations() %s\n", token.toChars());
4369 comment
= token
.blockComment
.ptr
;
4371 /* Look for AliasReassignment
4373 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.assign
)
4374 return parseAliasReassignment(comment
);
4376 /* Declarations that start with `alias`
4378 bool isAliasDeclaration
= false;
4379 auto aliasLoc
= token
.loc
;
4380 if (token
.value
== TOK
.alias_
)
4382 if (auto a
= parseAliasDeclarations(comment
))
4384 /* Handle these later:
4385 * alias StorageClasses type ident;
4387 isAliasDeclaration
= true;
4394 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4396 if (token
.value
== TOK
.enum_
)
4398 AST
.Dsymbol d
= parseEnum();
4399 auto a
= new AST
.Dsymbols();
4404 d
= new AST
.UserAttributeDeclaration(udas
, a
);
4405 a
= new AST
.Dsymbols();
4409 addComment(d
, comment
);
4412 if (token
.value
== TOK
.struct_ ||
4413 token
.value
== TOK
.union_ ||
4414 token
.value
== TOK
.class_ ||
4415 token
.value
== TOK
.interface_
)
4417 AST
.Dsymbol s
= parseAggregate();
4418 auto a
= new AST
.Dsymbols();
4423 s
= new AST
.StorageClassDeclaration(storage_class
, a
);
4424 a
= new AST
.Dsymbols();
4429 s
= new AST
.AlignDeclaration(s
.loc
, ealign
, a
);
4430 a
= new AST
.Dsymbols();
4433 if (link
!= linkage
)
4435 s
= new AST
.LinkDeclaration(linkloc
, link
, a
);
4436 a
= new AST
.Dsymbols();
4441 s
= new AST
.UserAttributeDeclaration(udas
, a
);
4442 a
= new AST
.Dsymbols();
4446 addComment(s
, comment
);
4450 /* Look for auto initializers:
4451 * storage_class identifier = initializer;
4452 * storage_class identifier(...) = initializer;
4454 if ((storage_class || udas
) && token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
4456 AST
.Dsymbols
* a
= parseAutoDeclarations(storage_class
, comment
);
4459 AST
.Dsymbol s
= new AST
.UserAttributeDeclaration(udas
, a
);
4460 a
= new AST
.Dsymbols();
4466 /* Look for return type inference for template functions.
4470 if ((storage_class || udas
) && token
.value
== TOK
.identifier
&& skipParens(peek(&token
), &tk
) &&
4471 skipAttributes(tk
, &tk
) &&
4472 (tk
.value
== TOK
.leftParenthesis || tk
.value
== TOK
.leftCurly || tk
.value
== TOK
.in_ || tk
.value
== TOK
.out_ || tk
.value
== TOK
.goesTo ||
4473 tk
.value
== TOK
.do_ || tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
))
4475 if (tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
)
4476 usageOfBodyKeyword();
4482 ts
= parseBasicType();
4483 ts
= parseTypeSuffixes(ts
);
4490 storage_class |
= pAttrs
.storageClass
;
4491 //pAttrs.storageClass = STC.undefined_;
4494 AST
.Type tfirst
= null;
4495 auto a
= new AST
.Dsymbols();
4499 AST
.TemplateParameters
* tpl
= null;
4503 const loc
= token
.loc
;
4505 auto t
= parseDeclarator(ts
, alt
, &ident
, &tpl
, storage_class
, &disable
, &udas
);
4509 else if (t
!= tfirst
)
4510 error(token
.loc
, "multiple declarations must have the same type, not `%s` and `%s`", tfirst
.toChars(), t
.toChars());
4512 if (token
.value
== TOK
.colon
&& !ident
&& t
.ty
!= Tfunction
)
4514 // Unnamed bit field
4515 ident
= Identifier
.generateAnonymousId("BitField");
4518 bool isThis
= (t
.ty
== Tident
&& (cast(AST
.TypeIdentifier
)t
).ident
== Id
.This
&& token
.value
== TOK
.assign
);
4520 checkCstyleTypeSyntax(loc
, t
, alt
, ident
);
4521 else if (!isThis
&& (t
!= AST
.Type
.terror
))
4522 noIdentifierForDeclarator(t
);
4524 if (isAliasDeclaration
)
4527 AST
.Initializer _init
= null;
4529 /* Aliases can no longer have multiple declarators, storage classes,
4530 * linkages, or auto declarations.
4531 * These never made any sense, anyway.
4532 * The code below needs to be fixed to reject them.
4533 * The grammar has already been fixed to preclude them.
4537 error("user-defined attributes not allowed for `alias` declarations");
4539 if (token
.value
== TOK
.assign
)
4542 _init
= parseInitializer();
4546 error("alias cannot have initializer");
4548 v
= new AST
.AliasDeclaration(aliasLoc
, ident
, t
);
4550 v
.storage_class
= storage_class
;
4553 /* AliasDeclaration distinguish @safe, @system, @trusted attributes
4554 * on prefix and postfix.
4555 * @safe alias void function() FP1;
4556 * alias @safe void function() FP2; // FP2 is not @safe
4557 * alias void function() @safe FP3;
4559 pAttrs
.storageClass
&= STC
.safeGroup
;
4563 if (link
!= linkage
)
4565 auto ax
= new AST
.Dsymbols();
4567 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4570 switch (token
.value
)
4574 addComment(s
, comment
);
4579 addComment(s
, comment
);
4583 error("semicolon expected to close `alias` declaration, not `%s`", token
.toChars());
4587 else if (t
.ty
== Tfunction
)
4589 /* @@@DEPRECATED_2.115@@@
4590 * change to error, deprecated in 2.105.1 */
4591 if (storage_class
& STC
.manifest
)
4592 deprecation("function cannot have enum storage class");
4594 AST
.Expression constraint
= null;
4595 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
4596 auto f
= new AST
.FuncDeclaration(loc
, Loc
.initial
, ident
, storage_class |
(disable ? STC
.disable
: 0), t
);
4598 pAttrs
.storageClass
= STC
.undefined_
;
4600 constraint
= parseConstraint();
4601 AST
.Dsymbol s
= parseContracts(f
, !!tpl
);
4602 auto tplIdent
= s
.ident
;
4604 if (link
!= linkage
)
4606 auto ax
= new AST
.Dsymbols();
4608 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4612 auto ax
= new AST
.Dsymbols();
4614 s
= new AST
.UserAttributeDeclaration(udas
, ax
);
4617 /* A template parameter list means it's a function template
4621 // @@@DEPRECATED_2.114@@@
4622 // Both deprecated in 2.104, change to error
4623 if (storage_class
& STC
.override_
)
4624 deprecation(loc
, "a function template is not virtual so cannot be marked `override`");
4625 else if (storage_class
& STC
.abstract_
)
4626 deprecation(loc
, "a function template is not virtual so cannot be marked `abstract`");
4628 // Wrap a template around the function declaration
4629 auto decldefs
= new AST
.Dsymbols();
4631 auto tempdecl
= new AST
.TemplateDeclaration(loc
, tplIdent
, tpl
, constraint
, decldefs
);
4634 StorageClass stc2
= STC
.undefined_
;
4635 if (storage_class
& STC
.static_
)
4637 assert(f
.storage_class
& STC
.static_
);
4638 f
.storage_class
&= ~STC
.static_
;
4639 stc2 |
= STC
.static_
;
4641 if (storage_class
& STC
.deprecated_
)
4643 assert(f
.storage_class
& STC
.deprecated_
);
4644 f
.storage_class
&= ~STC
.deprecated_
;
4645 stc2 |
= STC
.deprecated_
;
4647 if (stc2
!= STC
.undefined_
)
4649 auto ax
= new AST
.Dsymbols();
4651 s
= new AST
.StorageClassDeclaration(stc2
, ax
);
4655 addComment(s
, comment
);
4659 AST
.Expression width
;
4660 if (token
.value
== TOK
.colon
)
4663 width
= parseCondExp();
4666 AST
.Initializer _init
= null;
4667 if (token
.value
== TOK
.assign
)
4670 _init
= parseInitializer();
4677 error("initializer not allowed for bit-field declaration");
4679 error("storage class not allowed for bit-field declaration");
4680 s
= new AST
.BitFieldDeclaration(width
.loc
, t
, ident
, width
);
4684 auto v
= new AST
.VarDeclaration(loc
, t
, ident
, _init
);
4685 v
.storage_class
= storage_class
;
4687 pAttrs
.storageClass
= STC
.undefined_
;
4693 auto a2
= new AST
.Dsymbols();
4695 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
, 0);
4700 auto ax
= new AST
.Dsymbols();
4702 s
= new AST
.AlignDeclaration(s
.loc
, ealign
, ax
);
4704 if (link
!= linkage
)
4706 auto ax
= new AST
.Dsymbols();
4708 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4712 auto ax
= new AST
.Dsymbols();
4714 s
= new AST
.UserAttributeDeclaration(udas
, ax
);
4717 switch (token
.value
)
4721 addComment(s
, comment
);
4726 addComment(s
, comment
);
4730 if (loc
.linnum
!= token
.loc
.linnum
)
4732 error(token
.loc
, "semicolon needed to end declaration of `%s`, instead of `%s`", s
.toChars(), token
.toChars());
4733 eSink
.errorSupplemental(loc
, "`%s` declared here", s
.toChars());
4737 error(token
.loc
, "semicolon needed to end declaration of `%s` instead of `%s`", s
.toChars(), token
.toChars());
4747 /// Report an error that a declaration of type `t` is missing an identifier
4748 /// The parser is expected to sit on the next token after the type.
4749 private void noIdentifierForDeclarator(AST
.Type t
)
4751 error("no identifier for declarator `%s`", t
.toChars());
4752 // A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out`
4753 if (token
.isKeyword
)
4755 eSink
.errorSupplemental(token
.loc
, "`%s` is a keyword, perhaps append `_` to make it an identifier", token
.toChars());
4760 /********************************
4761 * Parse AliasReassignment:
4762 * identifier = type;
4763 * Parser is sitting on the identifier.
4764 * https://dlang.org/spec/declaration.html#alias-reassignment
4766 * comment = if not null, comment to attach to symbol
4770 private AST
.Dsymbols
* parseAliasReassignment(const(char)* comment
)
4772 const loc
= token
.loc
;
4773 auto ident
= token
.ident
;
4775 nextToken(); // advance past =
4776 auto t
= parseType();
4777 AST
.Dsymbol s
= new AST
.AliasAssign(loc
, ident
, t
, null);
4778 check(TOK
.semicolon
, "alias reassignment");
4779 addComment(s
, comment
);
4780 auto a
= new AST
.Dsymbols();
4785 /********************************
4786 * Parse declarations that start with `alias`
4787 * Parser is sitting on the `alias`.
4788 * https://dlang.org/spec/declaration.html#alias
4790 * comment = if not null, comment to attach to symbol
4794 private AST
.Dsymbols
* parseAliasDeclarations(const(char)* comment
)
4796 const loc
= token
.loc
;
4798 Loc linkloc
= this.linkLoc
;
4799 AST
.Expressions
* udas
;
4800 LINK link
= linkage
;
4801 StorageClass storage_class
= STC
.undefined_
;
4802 AST
.Expression ealign
;
4803 bool setAlignment
= false;
4806 * alias Identifier this;
4807 * https://dlang.org/spec/class.html#alias-this
4809 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.this_
)
4811 auto s
= new AST
.AliasThis(loc
, token
.ident
);
4814 check(TOK
.semicolon
, "`alias Identifier this`");
4815 auto a
= new AST
.Dsymbols();
4817 addComment(s
, comment
);
4821 * alias this = identifier;
4823 if (token
.value
== TOK
.this_
&& peekNext() == TOK
.assign
&& peekNext2() == TOK
.identifier
)
4827 auto s
= new AST
.AliasThis(loc
, token
.ident
);
4829 check(TOK
.semicolon
, "`alias this = Identifier`");
4830 auto a
= new AST
.Dsymbols();
4832 addComment(s
, comment
);
4836 * alias identifier = type;
4837 * alias identifier(...) = type;
4838 * https://dlang.org/spec/declaration.html#alias
4840 if (token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
4842 auto a
= new AST
.Dsymbols();
4845 auto ident
= token
.ident
;
4847 AST
.TemplateParameters
* tpl
= null;
4848 if (token
.value
== TOK
.leftParenthesis
)
4849 tpl
= parseTemplateParameterList();
4852 bool hasParsedAttributes
;
4853 void parseAttributes()
4855 if (hasParsedAttributes
) // only parse once
4857 hasParsedAttributes
= true;
4859 storage_class
= STC
.undefined_
;
4861 linkloc
= this.linkLoc
;
4862 setAlignment
= false;
4864 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4867 if (token
.value
== TOK
.at
)
4873 // try to parse function type:
4874 // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
4875 bool attributesAppended
;
4876 const StorageClass funcStc
= parseTypeCtor();
4877 Token
* tlu
= &token
;
4879 if (token
.value
!= TOK
.function_
&&
4880 token
.value
!= TOK
.delegate_
&&
4881 isBasicType(&tlu
) && tlu
&&
4882 tlu
.value
== TOK
.leftParenthesis
)
4884 AST
.Type tret
= parseBasicType();
4885 auto parameterList
= parseParameterList(null);
4889 error("user-defined attributes not allowed for `alias` declarations");
4891 attributesAppended
= true;
4892 storage_class
= appendStorageClass(storage_class
, funcStc
);
4893 AST
.Type tf
= new AST
.TypeFunction(parameterList
, tret
, link
, storage_class
);
4894 v
= new AST
.AliasDeclaration(loc
, ident
, tf
);
4896 else if (token
.value
== TOK
.function_ ||
4897 token
.value
== TOK
.delegate_ ||
4898 token
.value
== TOK
.leftParenthesis
&&
4899 skipAttributes(peekPastParen(&token
), &tk
) &&
4900 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
) ||
4901 token
.value
== TOK
.leftCurly ||
4902 token
.value
== TOK
.identifier
&& peekNext() == TOK
.goesTo ||
4903 token
.value
== TOK
.ref_
&& peekNext() == TOK
.leftParenthesis
&&
4904 skipAttributes(peekPastParen(peek(&token
)), &tk
) &&
4905 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
) ||
4906 token
.value
== TOK
.auto_
&& peekNext() == TOK
.ref_
&&
4907 peekNext2() == TOK
.leftParenthesis
&&
4908 skipAttributes(peekPastParen(peek(peek(&token
))), &tk
) &&
4909 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
)
4912 // function (parameters) { statements... }
4913 // delegate (parameters) { statements... }
4914 // (parameters) { statements... }
4915 // (parameters) => expression
4916 // { statements... }
4917 // identifier => expression
4918 // ref (parameters) { statements... }
4919 // ref (parameters) => expression
4920 // auto ref (parameters) { statements... }
4921 // auto ref (parameters) => expression
4923 s
= parseFunctionLiteral();
4927 if (storage_class
!= 0)
4928 error("cannot put a storage-class in an `alias` declaration.");
4929 // parseAttributes shouldn't have set these variables
4930 assert(link
== linkage
&& !setAlignment
&& ealign
is null);
4931 auto tpl_
= cast(AST
.TemplateDeclaration
) s
;
4932 if (tpl_
is null || tpl_
.members
.length
!= 1)
4934 error("user-defined attributes are not allowed on `alias` declarations");
4938 auto fd
= cast(AST
.FuncLiteralDeclaration
) (*tpl_
.members
)[0];
4939 auto tf
= cast(AST
.TypeFunction
) fd
.type
;
4940 assert(tf
.parameterList
.parameters
.length
> 0);
4941 auto as
= new AST
.Dsymbols();
4942 (*tf
.parameterList
.parameters
)[0].userAttribDecl
= new AST
.UserAttributeDeclaration(udas
, as
);
4946 v
= new AST
.AliasDeclaration(loc
, ident
, s
);
4953 error("user-defined attributes not allowed for `alias` declarations");
4955 auto t
= parseType();
4957 // Disallow meaningless storage classes on type aliases
4960 // Don't raise errors for STC that are part of a function/delegate type, e.g.
4961 // `alias F = ref pure nothrow @nogc @safe int function();`
4962 auto tp
= t
.isTypePointer
;
4963 const isFuncType
= (tp
&& tp
.next
.isTypeFunction
) || t
.isTypeDelegate
;
4964 const remStc
= isFuncType ?
(storage_class
& ~STC
.FUNCATTR
) : storage_class
;
4969 AST
.stcToBuffer(buf
, remStc
);
4970 // @@@DEPRECATED_2.103@@@
4971 // Deprecated in 2020-07, can be made an error in 2.103
4972 eSink
.deprecation(token
.loc
, "storage class `%s` has no effect in type aliases", buf
.peekChars());
4976 v
= new AST
.AliasDeclaration(loc
, ident
, t
);
4978 if (!attributesAppended
)
4979 storage_class
= appendStorageClass(storage_class
, funcStc
);
4980 v
.storage_class
= storage_class
;
4985 auto a2
= new AST
.Dsymbols();
4987 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
);
4990 if (link
!= linkage
)
4992 auto a2
= new AST
.Dsymbols();
4994 s
= new AST
.LinkDeclaration(linkloc
, link
, a2
);
4998 switch (token
.value
)
5002 addComment(s
, comment
);
5007 addComment(s
, comment
);
5008 if (token
.value
!= TOK
.identifier
)
5010 error("identifier expected following comma, not `%s`", token
.toChars());
5013 if (peekNext() != TOK
.assign
&& peekNext() != TOK
.leftParenthesis
)
5015 error("`=` expected following identifier");
5022 error("semicolon expected to close `alias` declaration, not `%s`", token
.toChars());
5030 // alias StorageClasses type ident;
5034 private AST
.Dsymbol
parseFunctionLiteral()
5036 const loc
= token
.loc
;
5037 AST
.TemplateParameters
* tpl
= null;
5038 AST
.ParameterList parameterList
;
5039 AST
.Type tret
= null;
5040 StorageClass
stc = 0;
5041 TOK save
= TOK
.reserved
;
5043 switch (token
.value
)
5049 if (token
.value
== TOK
.auto_
)
5052 if (token
.value
== TOK
.ref_
)
5054 // function auto ref (parameters) { statements... }
5055 // delegate auto ref (parameters) { statements... }
5056 stc = STC
.auto_ | STC
.ref_
;
5060 error("`auto` can only be used as part of `auto ref` for function literal return values");
5062 else if (token
.value
== TOK
.ref_
)
5064 // function ref (parameters) { statements... }
5065 // delegate ref (parameters) { statements... }
5069 if (token
.value
!= TOK
.leftParenthesis
&& token
.value
!= TOK
.leftCurly
&&
5070 token
.value
!= TOK
.goesTo
)
5072 // function type (parameters) { statements... }
5073 // delegate type (parameters) { statements... }
5074 tret
= parseBasicType();
5075 tret
= parseTypeSuffixes(tret
); // function return type
5078 if (token
.value
== TOK
.leftParenthesis
)
5080 // function (parameters) { statements... }
5081 // delegate (parameters) { statements... }
5085 // function { statements... }
5086 // delegate { statements... }
5089 goto case TOK
.leftParenthesis
;
5094 if (token
.value
== TOK
.ref_
)
5096 // auto ref (parameters) => expression
5097 // auto ref (parameters) { statements... }
5098 stc = STC
.auto_ | STC
.ref_
;
5102 error("`auto` can only be used as part of `auto ref` for function literal return values");
5103 goto case TOK
.leftParenthesis
;
5107 // ref (parameters) => expression
5108 // ref (parameters) { statements... }
5111 goto case TOK
.leftParenthesis
;
5113 case TOK
.leftParenthesis
:
5115 // (parameters) => expression
5116 // (parameters) { statements... }
5117 parameterList
= parseParameterList(&tpl
);
5118 stc = parsePostfix(stc, null);
5119 if (StorageClass modStc
= stc & STC
.TYPECTOR
)
5121 if (save
== TOK
.function_
)
5124 AST
.stcToBuffer(buf
, modStc
);
5125 error("function literal cannot be `%s`", buf
.peekChars());
5128 save
= TOK
.delegate_
;
5133 // { statements... }
5136 case TOK
.identifier
:
5138 // identifier => expression
5139 parameterList
.parameters
= new AST
.Parameters();
5140 Identifier id
= Identifier
.generateId("__T");
5141 AST
.Type t
= new AST
.TypeIdentifier(loc
, id
);
5142 parameterList
.parameters
.push(new AST
.Parameter(loc
, STC
.parameter
, t
, token
.ident
, null, null));
5144 tpl
= new AST
.TemplateParameters();
5145 AST
.TemplateParameter tp
= new AST
.TemplateTypeParameter(loc
, id
, null, null);
5155 auto tf
= new AST
.TypeFunction(parameterList
, tret
, linkage
, stc);
5156 tf
= cast(AST
.TypeFunction
)tf
.addSTC(stc);
5157 auto fd
= new AST
.FuncLiteralDeclaration(loc
, Loc
.initial
, tf
, save
, null, null, stc & STC
.auto_
);
5159 if (token
.value
== TOK
.goesTo
)
5162 if (token
.value
== TOK
.leftCurly
)
5164 deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
5165 deprecationSupplemental("Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
5167 const returnloc
= token
.loc
;
5168 AST
.Expression ae
= parseAssignExp();
5169 fd
.fbody
= new AST
.ReturnStatement(returnloc
, ae
);
5170 fd
.endloc
= token
.loc
;
5179 // Wrap a template around function fd
5180 auto decldefs
= new AST
.Dsymbols();
5182 return new AST
.TemplateDeclaration(fd
.loc
, fd
.ident
, tpl
, null, decldefs
, false, true);
5187 /*****************************************
5188 * Parse contracts following function declaration.
5190 private AST
.FuncDeclaration
parseContracts(AST
.FuncDeclaration f
, bool isTemplateFunction
= false)
5192 LINK linksave
= linkage
;
5194 bool literal
= f
.isFuncLiteralDeclaration() !is null;
5196 // The following is irrelevant, as it is overridden by sc.linkage in
5197 // TypeFunction::semantic
5198 linkage
= LINK
.d
; // nested functions have D linkage
5199 bool requireDo
= false;
5201 switch (token
.value
)
5205 error("missing `do { ... }` after `in` or `out`");
5206 if (!compileEnv
.shortenedMethods
)
5207 error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
5208 const returnloc
= token
.loc
;
5210 f
.fbody
= new AST
.ReturnStatement(returnloc
, parseExpression());
5211 f
.endloc
= token
.loc
;
5212 check(TOK
.semicolon
);
5217 error("missing `do { ... }` after `in` or `out`");
5218 f
.fbody
= parseStatement(0);
5222 case TOK
.identifier
:
5223 if (token
.ident
== Id
._body
)
5225 usageOfBodyKeyword();
5232 f
.fbody
= parseStatement(ParseStatementFlags
.curly
);
5238 // Do we want this for function declarations, so we can do:
5239 // int x, y, foo(), z;
5246 // in { statements... }
5248 auto loc
= token
.loc
;
5252 f
.frequires
= new AST
.Statements
;
5254 if (token
.value
== TOK
.leftParenthesis
)
5257 AST
.Expression e
= parseAssignExp(), msg
= null;
5258 if (token
.value
== TOK
.comma
)
5261 if (token
.value
!= TOK
.rightParenthesis
)
5263 msg
= parseAssignExp();
5264 if (token
.value
== TOK
.comma
)
5268 check(TOK
.rightParenthesis
);
5269 e
= new AST
.AssertExp(loc
, e
, msg
);
5270 f
.frequires
.push(new AST
.ExpStatement(loc
, e
));
5275 auto ret = parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
);
5277 f
.frequires
.push(ret);
5283 // out { statements... }
5284 // out (; expression)
5285 // out (identifier) { statements... }
5286 // out (identifier; expression)
5287 auto loc
= token
.loc
;
5291 f
.fensures
= new AST
.Ensures
;
5293 Identifier id
= null;
5294 if (token
.value
!= TOK
.leftCurly
)
5296 check(TOK
.leftParenthesis
);
5297 if (token
.value
!= TOK
.identifier
&& token
.value
!= TOK
.semicolon
)
5298 error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token
.toChars());
5299 if (token
.value
!= TOK
.semicolon
)
5304 if (token
.value
== TOK
.semicolon
)
5307 AST
.Expression e
= parseAssignExp(), msg
= null;
5308 if (token
.value
== TOK
.comma
)
5311 if (token
.value
!= TOK
.rightParenthesis
)
5313 msg
= parseAssignExp();
5314 if (token
.value
== TOK
.comma
)
5318 check(TOK
.rightParenthesis
);
5319 e
= new AST
.AssertExp(loc
, e
, msg
);
5320 f
.fensures
.push(AST
.Ensure(id
, new AST
.ExpStatement(loc
, e
)));
5324 check(TOK
.rightParenthesis
);
5326 f
.fensures
.push(AST
.Ensure(id
, parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
)));
5333 // https://issues.dlang.org/show_bug.cgi?id=15799
5334 // Semicolon becomes a part of function declaration
5335 // only when 'do' is not required
5345 const(char)* sbody
= requireDo ?
"do " : "";
5346 error("missing `%s{ ... }` for function literal", sbody
);
5348 else if (!requireDo
) // allow contracts even with no body
5350 TOK t
= token
.value
;
5351 if (t
== TOK
.const_ || t
== TOK
.immutable_ || t
== TOK
.inout_ || t
== TOK
.return_ ||
5352 t
== TOK
.shared_ || t
== TOK
.nothrow_ || t
== TOK
.pure_
)
5353 error("'%s' cannot be placed after a template constraint", token
.toChars
);
5354 else if (t
== TOK
.at
)
5355 error("attributes cannot be placed after a template constraint");
5356 else if (t
== TOK
.if_
)
5358 if (isTemplateFunction
)
5359 error("template constraint must follow parameter lists and attributes");
5361 error("cannot use function constraints for non-template functions. Use `static if` instead");
5364 error("semicolon expected following function declaration, not `%s`", token
.toChars());
5368 if (literal
&& !f
.fbody
)
5370 // Set empty function body for error recovery
5371 f
.fbody
= new AST
.CompoundStatement(Loc
.initial
, cast(AST
.Statement
)null);
5379 /*****************************************
5381 private void checkDanglingElse(Loc elseloc
)
5383 if (token
.value
!= TOK
.else_
&& token
.value
!= TOK
.catch_
&& token
.value
!= TOK
.finally_
&& lookingForElse
.linnum
!= 0)
5385 eSink
.warning(elseloc
, "else is dangling, add { } after condition at %s", lookingForElse
.toChars());
5389 /* *************************
5390 * Issue errors if C-style syntax
5392 * alt = !=0 for C-style syntax
5394 private void checkCstyleTypeSyntax(Loc loc
, AST
.Type t
, int alt
, Identifier ident
)
5399 const(char)* sp
= !ident ?
"" : " ";
5400 const(char)* s
= !ident ?
"" : ident
.toChars();
5401 error(loc
, "instead of C-style syntax, use D-style `%s%s%s`", t
.toChars(), sp
, s
);
5404 /*****************************
5405 * Ad-hoc error message for missing or extra parens that close a condition.
5407 * start = "if", "while", etc. Must be 0 terminated.
5408 * param = if the condition is a declaration, this will be non-null
5409 * condition = if param is null, then this is the conditional Expression. If condition is null,
5410 * then an error in the condition was already reported.
5412 private void closeCondition(string start
, AST
.Parameter param
, AST
.Expression condition
)
5415 if (token
.value
!= TOK
.rightParenthesis
&& condition
)
5417 format
= "missing closing `)` after `%s (%s`";
5420 check(TOK
.rightParenthesis
);
5421 if (token
.value
== TOK
.rightParenthesis
)
5423 if (condition
) // if not an error in condition
5424 format
= "extra `)` after `%s (%s)`";
5428 error(token
.loc
, format
.ptr
, start
.ptr
, param ?
"declaration".ptr
: condition
.toChars());
5431 /*****************************************
5432 * Parses `foreach` statements, `static foreach` statements and
5433 * `static foreach` declarations.
5435 * Foreach = one of Statement, StaticForeachStatement, StaticForeachDeclaration
5436 * loc = location of foreach
5437 * pLastDecl = non-null for StaticForeachDeclaration
5439 * the Foreach generated
5441 private Foreach
parseForeach(alias Foreach
)(Loc loc
, AST
.Dsymbol
* pLastDecl
)
5443 static if (is(Foreach
== AST
.StaticForeachStatement
) ||
is(Foreach
== AST
.StaticForeachDeclaration
))
5448 TOK op
= token
.value
;
5451 check(TOK
.leftParenthesis
);
5453 auto parameters
= new AST
.Parameters();
5457 Identifier ai
= null;
5461 StorageClass storageClass
= 0;
5462 StorageClass
stc = 0;
5466 storageClass
= appendStorageClass(storageClass
, stc);
5469 switch (token
.value
)
5480 error("cannot declare `out` loop variable, use `ref` instead");
5485 error("cannot declare `auto` loop variable, omit `auto` to still get type inference");
5494 storageClass
= appendStorageClass(storageClass
, STC
.alias_
);
5499 if (peekNext() != TOK
.leftParenthesis
)
5506 case TOK
.immutable_
:
5507 if (peekNext() != TOK
.leftParenthesis
)
5509 stc = STC
.immutable_
;
5515 if (peekNext() != TOK
.leftParenthesis
)
5523 if (peekNext() != TOK
.leftParenthesis
)
5533 if (token
.value
== TOK
.identifier
)
5535 const tv
= peekNext();
5536 if (tv
== TOK
.comma || tv
== TOK
.semicolon || tv
== TOK
.rightParenthesis
)
5538 lastai
= token
.ident
;
5540 at
= null; // infer argument type
5546 at
= parseType(&ai
);
5548 noIdentifierForDeclarator(at
);
5550 auto p
= new AST
.Parameter(aloc
, storageClass
, at
, ai
, null, null);
5552 if (token
.value
== TOK
.comma
)
5559 if (token
.value
!= TOK
.semicolon
)
5561 error("missing `; expression` before `)` of `foreach`");
5563 if (lastai
&& parameters
.length
>= 2)
5565 eSink
.errorSupplemental(loc
, "perhaps the `;` goes before `%s`", lastai
.toChars());
5571 AST
.Expression aggr
= parseExpression();
5572 if (token
.value
== TOK
.slice
&& parameters
.length
== 1)
5574 AST
.Parameter p
= (*parameters
)[0];
5576 AST
.Expression upr
= parseExpression();
5577 check(TOK
.rightParenthesis
);
5579 static if (is(Foreach
== AST
.Statement
) ||
is(Foreach
== AST
.StaticForeachStatement
))
5581 AST
.Statement _body
= parseStatement(0, null, &endloc
);
5585 AST
.Statement _body
= null;
5587 auto rangefe
= new AST
.ForeachRangeStatement(loc
, op
, p
, aggr
, upr
, _body
, endloc
);
5588 static if (is(Foreach
== AST
.Statement
))
5592 else static if(is(Foreach
== AST
.StaticForeachDeclaration
))
5594 return new AST
.StaticForeachDeclaration(new AST
.StaticForeach(loc
, null, rangefe
), parseBlock(pLastDecl
));
5596 else static if (is(Foreach
== AST
.StaticForeachStatement
))
5598 return new AST
.StaticForeachStatement(loc
, new AST
.StaticForeach(loc
, null, rangefe
));
5603 check(TOK
.rightParenthesis
);
5605 static if (is(Foreach
== AST
.Statement
) ||
is(Foreach
== AST
.StaticForeachStatement
))
5607 AST
.Statement _body
= parseStatement(0, null, &endloc
);
5611 AST
.Statement _body
= null;
5613 auto aggrfe
= new AST
.ForeachStatement(loc
, op
, parameters
, aggr
, _body
, endloc
);
5614 static if (is(Foreach
== AST
.Statement
))
5618 else static if(is(Foreach
== AST
.StaticForeachDeclaration
))
5620 return new AST
.StaticForeachDeclaration(new AST
.StaticForeach(loc
, aggrfe
, null), parseBlock(pLastDecl
));
5622 else static if (is(Foreach
== AST
.StaticForeachStatement
))
5624 return new AST
.StaticForeachStatement(loc
, new AST
.StaticForeach(loc
, aggrfe
, null));
5631 * Parse an assignment condition for if or while statements.
5634 * The variable that is declared inside the condition
5636 AST
.Parameter
parseAssignCondition()
5638 AST
.Parameter param
= null;
5639 StorageClass storageClass
= 0;
5640 StorageClass
stc = 0;
5644 switch (token
.value
)
5646 // parse ref for better error
5660 if (peekNext() != TOK
.leftParenthesis
)
5667 case TOK
.immutable_
:
5668 if (peekNext() != TOK
.leftParenthesis
)
5670 stc = STC
.immutable_
;
5676 if (peekNext() != TOK
.leftParenthesis
)
5684 if (peekNext() != TOK
.leftParenthesis
)
5694 storageClass
= appendStorageClass(storageClass
, stc);
5697 auto n
= peek(&token
);
5698 if (storageClass
!= 0 && token
.value
== TOK
.identifier
&& n
.value
== TOK
.assign
)
5700 Identifier ai
= token
.ident
;
5701 AST
.Type at
= null; // infer parameter type
5702 const aloc
= token
.loc
;
5705 param
= new AST
.Parameter(aloc
, storageClass
, at
, ai
, null, null);
5707 else if (isDeclaration(&token
, NeedDeclaratorId
.must
, TOK
.assign
, null))
5710 const aloc
= token
.loc
;
5711 AST
.Type at
= parseType(&ai
);
5713 param
= new AST
.Parameter(aloc
, storageClass
, at
, ai
, null, null);
5715 else if (storageClass
!= 0)
5716 error("found `%s` while expecting `=` or identifier", n
.toChars());
5721 /*****************************************
5725 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
5727 AST
.Statement
parseStatement(int flags
, const(char)** endPtr
= null, Loc
* pEndloc
= null)
5731 AST
.Statement ifbody
;
5732 AST
.Statement elsebody
;
5734 const loc
= token
.loc
;
5736 //printf("parseStatement()\n");
5737 if (flags
& ParseStatementFlags
.curly
&& token
.value
!= TOK
.leftCurly
)
5738 error("statement expected to be `{ }`, not `%s`", token
.toChars());
5740 switch (token
.value
)
5742 case TOK
.identifier
:
5744 /* A leading identifier can be a declaration, label, or expression.
5745 * The easiest case to check first is label:
5747 if (peekNext() == TOK
.colonColon
)
5752 error("use `.` for member lookup, not `::`");
5756 if (peekNext() == TOK
.colon
)
5759 Identifier ident
= token
.ident
;
5762 if (token
.value
== TOK
.rightCurly
)
5764 else if (token
.value
== TOK
.leftCurly
)
5765 s
= parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
);
5766 else if (flags
& ParseStatementFlags
.curlyScope
)
5767 s
= parseStatement(ParseStatementFlags
.semiOk | ParseStatementFlags
.curlyScope
);
5769 s
= parseStatement(ParseStatementFlags
.semiOk
);
5770 s
= new AST
.LabelStatement(loc
, ident
, s
);
5779 /* https://issues.dlang.org/show_bug.cgi?id=15163
5780 * If tokens can be handled as
5781 * old C-style declaration or D expression, prefer the latter.
5783 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
5790 case TOK
.int32Literal
:
5791 case TOK
.uns32Literal
:
5792 case TOK
.int64Literal
:
5793 case TOK
.uns64Literal
:
5794 case TOK
.int128Literal
:
5795 case TOK
.uns128Literal
:
5796 case TOK
.float32Literal
:
5797 case TOK
.float64Literal
:
5798 case TOK
.float80Literal
:
5799 case TOK
.imaginary32Literal
:
5800 case TOK
.imaginary64Literal
:
5801 case TOK
.imaginary80Literal
:
5802 case TOK
.charLiteral
:
5803 case TOK
.wcharLiteral
:
5804 case TOK
.dcharLiteral
:
5809 case TOK
.hexadecimalString
:
5810 case TOK
.leftParenthesis
:
5818 case TOK
.minusMinus
:
5825 case TOK
.leftBracket
:
5827 case TOK
.fileFullPath
:
5829 case TOK
.moduleString
:
5830 case TOK
.functionString
:
5831 case TOK
.prettyFunction
:
5834 AST
.Expression exp
= parseExpression();
5835 /* https://issues.dlang.org/show_bug.cgi?id=15103
5836 * Improve declaration / initialization syntax error message
5837 * Error: found 'foo' when expecting ';' following expression
5838 * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
5840 if (token
.value
== TOK
.identifier
&& exp
.op
== EXP
.identifier
)
5842 error(token
.loc
, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token
).toChars(), exp
.toChars(), token
.toChars(), peek(peek(&token
)).toChars());
5848 * https://issues.dlang.org/show_bug.cgi?id=22529
5849 * Avoid empty declaration error in case of missing semicolon
5850 * followed by another token and another semicolon. E.g.:
5855 * When the missing `;` error is emitted, token is sitting on return.
5856 * If we simply use `check` to emit the error, the token is advanced
5857 * to `;` and the empty statement error would follow. To avoid that,
5858 * we check if the next token is a semicolon and simply output the error,
5859 * otherwise we fall back on the old path (advancing the token).
5861 if (token
.value
!= TOK
.semicolon
&& peek(&token
).value
== TOK
.semicolon
)
5862 error("found `%s` when expecting `;` following expression", token
.toChars());
5865 if (token
.value
!= TOK
.semicolon
)
5867 error("found `%s` when expecting `;` following expression", token
.toChars());
5868 eSink
.errorSupplemental(exp
.loc
, "expression: `%s`", exp
.toChars());
5873 s
= new AST
.ExpStatement(loc
, exp
);
5878 // Look ahead to see if it's static assert() or static if()
5879 const tv
= peekNext();
5880 if (tv
== TOK
.assert_
)
5882 s
= new AST
.StaticAssertStatement(parseStaticAssert());
5887 cond
= parseStaticIfCondition();
5890 if (tv
== TOK
.foreach_ || tv
== TOK
.foreach_reverse_
)
5892 s
= parseForeach
!(AST
.StaticForeachStatement
)(loc
, null);
5893 if (flags
& ParseStatementFlags
.scope_
)
5894 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5897 if (tv
== TOK
.import_
)
5899 AST
.Dsymbols
* imports
= parseImport();
5900 s
= new AST
.ImportStatement(loc
, imports
);
5901 if (flags
& ParseStatementFlags
.scope_
)
5902 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5908 if (peekNext() == TOK
.switch_
)
5933 case TOK
.imaginary32
:
5934 case TOK
.imaginary64
:
5935 case TOK
.imaginary80
:
5940 // bug 7773: int.max is always a part of expression
5941 if (peekNext() == TOK
.dot
)
5943 if (peekNext() == TOK
.leftParenthesis
)
5953 case TOK
.immutable_
:
5956 case TOK
.deprecated_
:
5965 case TOK
.interface_
:
5968 AST
.Dsymbols
* a
= parseDeclarations(false, null, null);
5971 auto as
= new AST
.Statements();
5972 as
.reserve(a
.length
);
5973 foreach (i
; 0 .. a
.length
)
5975 AST
.Dsymbol d
= (*a
)[i
];
5976 s
= new AST
.ExpStatement(loc
, d
);
5979 s
= new AST
.CompoundDeclarationStatement(loc
, as
);
5981 else if (a
.length
== 1)
5983 AST
.Dsymbol d
= (*a
)[0];
5984 s
= new AST
.ExpStatement(loc
, d
);
5987 s
= new AST
.ExpStatement(loc
, cast(AST
.Expression
)null);
5988 if (flags
& ParseStatementFlags
.scope_
)
5989 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5994 /* Determine if this is a manifest constant declaration,
5995 * or a conventional enum.
5998 const tv
= peekNext();
5999 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
6001 else if (tv
!= TOK
.identifier
)
6005 const nextv
= peekNext2();
6006 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
6011 s
= new AST
.ExpStatement(loc
, d
);
6012 if (flags
& ParseStatementFlags
.scope_
)
6013 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6018 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
6020 const tv
= peekNext();
6021 if (tv
== TOK
.leftParenthesis
)
6024 AST
.Expression e
= parseAssignExp();
6025 check(TOK
.semicolon
, "mixin");
6026 if (e
.op
== EXP
.mixin_
)
6028 AST
.MixinExp cpe
= cast(AST
.MixinExp
)e
;
6029 s
= new AST
.MixinStatement(loc
, cpe
.exps
);
6033 s
= new AST
.ExpStatement(loc
, e
);
6037 else if (tv
== TOK
.template_
)
6041 AST
.Dsymbol d
= parseTemplateDeclaration(true);
6042 s
= new AST
.ExpStatement(loc
, d
);
6045 AST
.Dsymbol d
= parseMixin();
6046 s
= new AST
.ExpStatement(loc
, d
);
6047 if (flags
& ParseStatementFlags
.scope_
)
6048 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6053 const lcLoc
= token
.loc
;
6054 const lookingForElseSave
= lookingForElse
;
6055 lookingForElse
= Loc
.initial
;
6058 //if (token.value == TOK.semicolon)
6059 // error("use `{ }` for an empty statement, not `;`");
6060 auto statements
= new AST
.Statements();
6061 while (token
.value
!= TOK
.rightCurly
&& token
.value
!= TOK
.endOfFile
)
6063 statements
.push(parseStatement(ParseStatementFlags
.curlyScope | ParseStatementFlags
.semiOk
));
6066 *endPtr
= token
.ptr
;
6070 *pEndloc
= token
.loc
;
6071 pEndloc
= null; // don't set it again
6073 s
= new AST
.CompoundStatement(loc
, statements
);
6074 if (flags
& (ParseStatementFlags
.scope_ | ParseStatementFlags
.curlyScope
))
6075 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6076 if (token
.value
!= TOK
.rightCurly
)
6078 error(token
.loc
, "matching `}` expected following compound statement, not `%s`",
6080 eSink
.errorSupplemental(lcLoc
, "unmatched `{`");
6084 lookingForElse
= lookingForElseSave
;
6090 check(TOK
.leftParenthesis
);
6091 auto param
= parseAssignCondition();
6092 auto condition
= parseExpression();
6093 closeCondition("while", param
, condition
);
6096 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6097 s
= new AST
.WhileStatement(loc
, condition
, _body
, endloc
, param
);
6101 if (!(flags
& ParseStatementFlags
.semiOk
))
6103 error("use `{ }` for an empty statement, not `;`");
6106 s
= new AST
.ExpStatement(loc
, cast(AST
.Expression
)null);
6111 AST
.Statement _body
;
6114 const lookingForElseSave
= lookingForElse
;
6115 lookingForElse
= Loc
.initial
;
6116 _body
= parseStatement(ParseStatementFlags
.scope_
);
6117 lookingForElse
= lookingForElseSave
;
6119 check(TOK
.leftParenthesis
);
6120 auto condition
= parseExpression();
6121 closeCondition("do .. while", null, condition
);
6122 if (token
.value
== TOK
.semicolon
)
6125 error("terminating `;` required after do-while statement");
6126 s
= new AST
.DoStatement(loc
, _body
, condition
, token
.loc
);
6131 AST
.Statement _init
;
6132 AST
.Expression condition
;
6133 AST
.Expression increment
;
6136 check(TOK
.leftParenthesis
);
6137 if (token
.value
== TOK
.semicolon
)
6144 const lookingForElseSave
= lookingForElse
;
6145 lookingForElse
= Loc
.initial
;
6146 _init
= parseStatement(0);
6147 lookingForElse
= lookingForElseSave
;
6149 if (token
.value
== TOK
.semicolon
)
6156 condition
= parseExpression();
6157 check(TOK
.semicolon
, "`for` condition");
6159 if (token
.value
== TOK
.rightParenthesis
)
6166 increment
= parseExpression();
6167 check(TOK
.rightParenthesis
);
6170 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6171 s
= new AST
.ForStatement(loc
, _init
, condition
, increment
, _body
, endloc
);
6175 case TOK
.foreach_reverse_
:
6177 s
= parseForeach
!(AST
.Statement
)(loc
, null);
6183 check(TOK
.leftParenthesis
);
6184 auto param
= parseAssignCondition();
6185 auto condition
= parseExpression();
6186 closeCondition("if", param
, condition
);
6189 const lookingForElseSave
= lookingForElse
;
6190 lookingForElse
= loc
;
6191 ifbody
= parseStatement(ParseStatementFlags
.scope_
);
6192 lookingForElse
= lookingForElseSave
;
6194 if (token
.value
== TOK
.else_
)
6196 const elseloc
= token
.loc
;
6198 elsebody
= parseStatement(ParseStatementFlags
.scope_
);
6199 checkDanglingElse(elseloc
);
6203 if (condition
&& ifbody
)
6204 s
= new AST
.IfStatement(loc
, param
, condition
, ifbody
, elsebody
, token
.loc
);
6206 s
= null; // don't propagate parsing errors
6211 error("found `else` without a corresponding `if`, `version` or `debug` statement");
6215 if (peekNext() != TOK
.leftParenthesis
)
6216 goto Ldeclaration
; // scope used as storage class
6218 check(TOK
.leftParenthesis
);
6219 if (token
.value
!= TOK
.identifier
)
6221 error("scope identifier expected");
6226 TOK t
= TOK
.onScopeExit
;
6227 Identifier id
= token
.ident
;
6229 t
= TOK
.onScopeExit
;
6230 else if (id
== Id
.failure
)
6231 t
= TOK
.onScopeFailure
;
6232 else if (id
== Id
.success
)
6233 t
= TOK
.onScopeSuccess
;
6235 error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id
.toChars());
6237 check(TOK
.rightParenthesis
);
6238 AST
.Statement st
= parseStatement(ParseStatementFlags
.scope_
);
6239 s
= new AST
.ScopeGuardStatement(loc
, t
, st
);
6245 if (token
.value
== TOK
.assign
)
6247 if (auto ds = parseDebugSpecification())
6250 eSink
.error(ds.loc
, "%s `%s` declaration must be at module level", ds.kind
, ds.toPrettyChars
);
6252 eSink
.error(ds.loc
, "%s `%s` level declaration must be at module level", ds.kind
, ds.toPrettyChars
);
6256 cond
= parseDebugCondition();
6261 if (token
.value
== TOK
.assign
)
6263 if (auto vs
= parseVersionSpecification())
6266 eSink
.error(vs
.loc
, "%s `%s` declaration must be at module level", vs
.kind
, vs
.toPrettyChars
);
6268 eSink
.error(vs
.loc
, "%s `%s` level declaration must be at module level", vs
.kind
, vs
.toPrettyChars
);
6272 cond
= parseVersionCondition();
6277 const lookingForElseSave
= lookingForElse
;
6278 lookingForElse
= loc
;
6279 ifbody
= parseStatement(0);
6280 lookingForElse
= lookingForElseSave
;
6283 if (token
.value
== TOK
.else_
)
6285 const elseloc
= token
.loc
;
6287 elsebody
= parseStatement(0);
6288 checkDanglingElse(elseloc
);
6290 s
= new AST
.ConditionalStatement(loc
, cond
, ifbody
, elsebody
);
6291 if (flags
& ParseStatementFlags
.scope_
)
6292 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6298 AST
.Expressions
* args
= null;
6299 AST
.Statement _body
;
6302 check(TOK
.leftParenthesis
);
6303 if (token
.value
!= TOK
.identifier
)
6305 error("`pragma(identifier)` expected");
6308 ident
= token
.ident
;
6310 if (token
.value
== TOK
.comma
&& peekNext() != TOK
.rightParenthesis
)
6311 args
= parseArguments(); // pragma(identifier, args...);
6313 check(TOK
.rightParenthesis
); // pragma(identifier);
6314 if (token
.value
== TOK
.semicolon
)
6320 _body
= parseStatement(0);
6321 s
= new AST
.PragmaStatement(loc
, ident
, args
, _body
);
6331 check(TOK
.leftParenthesis
);
6332 auto param
= parseAssignCondition();
6333 AST
.Expression condition
= parseExpression();
6334 closeCondition("switch", null, condition
);
6335 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
);
6336 s
= new AST
.SwitchStatement(loc
, param
, condition
, _body
, isfinal
, token
.loc
);
6342 AST
.Expressions cases
; // array of Expression's
6343 AST
.Expression last
= null;
6348 exp
= parseAssignExp();
6350 if (token
.value
!= TOK
.comma
)
6352 nextToken(); //comma
6354 while (token
.value
!= TOK
.colon
&& token
.value
!= TOK
.endOfFile
);
6357 /* case exp: .. case last:
6359 if (token
.value
== TOK
.slice
)
6361 if (cases
.length
> 1)
6362 error("only one `case` allowed for start of case range");
6365 last
= parseAssignExp();
6369 if (flags
& ParseStatementFlags
.curlyScope
)
6371 auto statements
= new AST
.Statements();
6372 while (token
.value
!= TOK
.case_
&& token
.value
!= TOK
.default_
&& token
.value
!= TOK
.endOfFile
&& token
.value
!= TOK
.rightCurly
)
6374 auto cur
= parseStatement(ParseStatementFlags
.curlyScope
);
6375 statements
.push(cur
);
6377 // https://issues.dlang.org/show_bug.cgi?id=21739
6378 // Stop at the last break s.t. the following non-case statements are
6379 // not merged into the current case. This can happen for
6380 // case 1: ... break;
6381 // debug { case 2: ... }
6382 if (cur
&& cur
.isBreakStatement())
6385 s
= new AST
.CompoundStatement(loc
, statements
);
6389 s
= parseStatement(0);
6391 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6395 s
= new AST
.CaseRangeStatement(loc
, exp
, last
, s
);
6399 // Keep cases in order by building the case statements backwards
6400 for (size_t i
= cases
.length
; i
; i
--)
6403 s
= new AST
.CaseStatement(loc
, exp
, s
);
6413 if (flags
& ParseStatementFlags
.curlyScope
)
6415 auto statements
= new AST
.Statements();
6416 while (token
.value
!= TOK
.case_
&& token
.value
!= TOK
.default_
&& token
.value
!= TOK
.endOfFile
&& token
.value
!= TOK
.rightCurly
)
6418 statements
.push(parseStatement(ParseStatementFlags
.curlyScope
));
6420 s
= new AST
.CompoundStatement(loc
, statements
);
6423 s
= parseStatement(0);
6424 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6425 s
= new AST
.DefaultStatement(loc
, s
);
6432 exp
= token
.value
== TOK
.semicolon ?
null : parseExpression();
6433 check(TOK
.semicolon
, "`return` statement");
6434 s
= new AST
.ReturnStatement(loc
, exp
);
6442 if (token
.value
== TOK
.identifier
)
6444 ident
= token
.ident
;
6447 check(TOK
.semicolon
, "`break` statement");
6448 s
= new AST
.BreakStatement(loc
, ident
);
6456 if (token
.value
== TOK
.identifier
)
6458 ident
= token
.ident
;
6461 check(TOK
.semicolon
, "`continue` statement");
6462 s
= new AST
.ContinueStatement(loc
, ident
);
6469 if (token
.value
== TOK
.default_
)
6472 s
= new AST
.GotoDefaultStatement(loc
);
6474 else if (token
.value
== TOK
.case_
)
6476 AST
.Expression exp
= null;
6478 if (token
.value
!= TOK
.semicolon
)
6479 exp
= parseExpression();
6480 s
= new AST
.GotoCaseStatement(loc
, exp
);
6484 if (token
.value
!= TOK
.identifier
)
6486 error("identifier expected following `goto`");
6491 ident
= token
.ident
;
6494 s
= new AST
.GotoStatement(loc
, ident
);
6496 check(TOK
.semicolon
, "`goto` statement");
6499 case TOK
.synchronized_
:
6502 AST
.Statement _body
;
6504 Token
* t
= peek(&token
);
6505 if (skipAttributes(t
, &t
) && t
.value
== TOK
.class_
)
6509 if (token
.value
== TOK
.leftParenthesis
)
6512 exp
= parseExpression();
6513 closeCondition("synchronized", null, exp
);
6517 _body
= parseStatement(ParseStatementFlags
.scope_
);
6518 s
= new AST
.SynchronizedStatement(loc
, exp
, _body
);
6524 AST
.Statement _body
;
6528 check(TOK
.leftParenthesis
);
6529 exp
= parseExpression();
6530 closeCondition("with", null, exp
);
6531 _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6532 s
= new AST
.WithStatement(loc
, exp
, _body
, endloc
);
6537 AST
.Statement _body
;
6538 AST
.Catches
* catches
= null;
6539 AST
.Statement finalbody
= null;
6542 const lookingForElseSave
= lookingForElse
;
6543 lookingForElse
= Loc
.initial
;
6544 _body
= parseStatement(ParseStatementFlags
.scope_
);
6545 lookingForElse
= lookingForElseSave
;
6546 while (token
.value
== TOK
.catch_
)
6548 AST
.Statement handler
;
6552 const catchloc
= token
.loc
;
6555 if (token
.value
!= TOK
.leftParenthesis
)
6557 deprecation("`catch` statement without an exception specification is deprecated");
6558 deprecationSupplemental("use `catch(Throwable)` for old behavior");
6564 check(TOK
.leftParenthesis
);
6567 check(TOK
.rightParenthesis
);
6569 handler
= parseStatement(0);
6570 c
= new AST
.Catch(catchloc
, t
, id
, handler
);
6572 catches
= new AST
.Catches();
6576 if (token
.value
== TOK
.finally_
)
6579 finalbody
= parseStatement(ParseStatementFlags
.scope_
);
6583 if (!catches
&& !finalbody
)
6584 error("`catch` or `finally` expected following `try`");
6588 s
= new AST
.TryCatchStatement(loc
, _body
, catches
);
6590 s
= new AST
.TryFinallyStatement(loc
, s
, finalbody
);
6598 exp
= parseExpression();
6599 check(TOK
.semicolon
, "`throw` statement");
6600 s
= new AST
.ThrowStatement(loc
, exp
);
6605 s
= parseAsm(false);
6610 /* https://issues.dlang.org/show_bug.cgi?id=16088
6612 * At this point it can either be an
6613 * https://dlang.org/spec/grammar.html#ImportExpression
6615 * https://dlang.org/spec/grammar.html#ImportDeclaration.
6616 * See if the next token after `import` is a `(`; if so,
6617 * then it is an import expression.
6619 if (peekNext() == TOK
.leftParenthesis
)
6621 AST
.Expression e
= parseExpression();
6622 check(TOK
.semicolon
, "`import` Expression");
6623 s
= new AST
.ExpStatement(loc
, e
);
6627 AST
.Dsymbols
* imports
= parseImport();
6628 s
= new AST
.ImportStatement(loc
, imports
);
6629 if (flags
& ParseStatementFlags
.scope_
)
6630 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6636 AST
.Dsymbol d
= parseTemplateDeclaration();
6637 s
= new AST
.ExpStatement(loc
, d
);
6641 error("found `%s` instead of statement", token
.toChars());
6645 while (token
.value
!= TOK
.rightCurly
&& token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
6647 if (token
.value
== TOK
.semicolon
)
6649 s
= new AST
.ErrorStatement
;
6658 private AST
.ExpInitializer
parseExpInitializer(Loc loc
)
6660 auto ae
= parseAssignExp();
6661 return new AST
.ExpInitializer(loc
, ae
);
6664 private AST
.Initializer
parseStructInitializer(Loc loc
)
6666 /* Scan ahead to discern between a struct initializer and
6667 * parameterless function literal.
6669 * We'll scan the topmost curly bracket level for statement-related
6670 * tokens, thereby ruling out a struct initializer. (A struct
6671 * initializer which itself contains function literals may have
6672 * statements at nested curly bracket levels.)
6674 * It's important that this function literal check not be
6675 * pendantic, otherwise a function having the slightest syntax
6676 * error would emit confusing errors when we proceed to parse it
6677 * as a struct initializer.
6679 * The following two ambiguous cases will be treated as a struct
6680 * initializer (best we can do without type info):
6682 * {{statements...}} - i.e. it could be struct initializer
6683 * with one function literal, or function literal having an
6684 * extra level of curly brackets
6685 * If a function literal is intended in these cases (unlikely),
6686 * source can use a more explicit function literal syntax
6687 * (e.g. prefix with "()" for empty parameter list).
6691 for (auto t
= peek(&token
); 1; t
= peek(t
))
6695 case TOK
.leftParenthesis
:
6698 case TOK
.rightParenthesis
:
6701 // https://issues.dlang.org/show_bug.cgi?id=21163
6702 // lambda params can have the `scope` storage class, e.g
6703 // `S s = { (scope Type Id){} }`
6705 if (!parens
) goto case;
6707 /* Look for a semicolon or keyword of statements which don't
6708 * require a semicolon (typically containing BlockStatement).
6709 * Tokens like "else", "catch", etc. are omitted where the
6710 * leading token of the statement is sufficient.
6717 case TOK
.interface_
:
6722 case TOK
.synchronized_
:
6729 return parseExpInitializer(loc
);
6736 case TOK
.rightCurly
:
6750 auto _is
= new AST
.StructInitializer(loc
);
6751 bool commaExpected
= false;
6755 switch (token
.value
)
6757 case TOK
.identifier
:
6761 error("comma expected separating field initializers");
6762 const t
= peek(&token
);
6764 if (t
.value
== TOK
.colon
)
6768 nextToken(); // skip over ':'
6770 auto value
= parseInitializer();
6771 _is
.addInit(id
, value
);
6772 commaExpected
= true;
6777 error("expression expected, not `,`");
6779 commaExpected
= false;
6782 case TOK
.rightCurly
: // allow trailing comma's
6787 error("found end of file instead of initializer");
6792 error("comma expected separating field initializers");
6793 auto value
= parseInitializer();
6794 _is
.addInit(null, value
);
6795 commaExpected
= true;
6804 /*****************************************
6805 * Parse initializer for variable declaration.
6807 private AST
.Initializer
parseInitializer()
6809 const loc
= token
.loc
;
6811 switch (token
.value
)
6814 return parseStructInitializer(loc
);
6816 case TOK
.leftBracket
:
6817 /* Scan ahead to see if it is an array initializer or
6819 * If it ends with a ';' ',' or ']', it is an array initializer.
6822 for (auto t
= peek(&token
); 1; t
= peek(t
))
6826 case TOK
.leftBracket
:
6830 case TOK
.rightBracket
:
6831 if (--brackets
== 0)
6834 if (t
.value
!= TOK
.semicolon
&& t
.value
!= TOK
.comma
&& t
.value
!= TOK
.rightBracket
&& t
.value
!= TOK
.rightCurly
)
6835 return parseExpInitializer(loc
);
6849 auto ia
= new AST
.ArrayInitializer(loc
);
6850 bool commaExpected
= false;
6855 switch (token
.value
)
6860 error("comma expected separating array initializers, not `%s`", token
.toChars());
6864 auto e
= parseAssignExp();
6868 AST
.Initializer value
;
6869 if (token
.value
== TOK
.colon
)
6872 value
= parseInitializer();
6876 value
= new AST
.ExpInitializer(e
.loc
, e
);
6879 ia
.addInit(e
, value
);
6880 commaExpected
= true;
6884 case TOK
.leftBracket
:
6886 error("comma expected separating array initializers, not `%s`", token
.toChars());
6887 auto value
= parseInitializer();
6890 if (token
.value
== TOK
.colon
)
6893 if (auto ei
= value
.isExpInitializer())
6896 value
= parseInitializer();
6899 error("initializer expression expected following colon, not `%s`", token
.toChars());
6901 ia
.addInit(e
, value
);
6902 commaExpected
= true;
6907 error("expression expected, not `,`");
6909 commaExpected
= false;
6912 case TOK
.rightBracket
: // allow trailing comma's
6917 error("found `%s` instead of array initializer", token
.toChars());
6925 const tv
= peekNext();
6926 if (tv
== TOK
.semicolon || tv
== TOK
.comma
)
6929 return new AST
.VoidInitializer(loc
);
6931 return parseExpInitializer(loc
);
6934 return parseExpInitializer(loc
);
6938 /*****************************************
6939 * Parses default argument initializer expression that is an assign expression,
6940 * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
6942 private AST
.Expression
parseDefaultInitExp()
6944 AST
.Expression e
= null;
6945 const tv
= peekNext();
6946 if (tv
== TOK
.comma || tv
== TOK
.rightParenthesis
)
6948 switch (token
.value
)
6950 case TOK
.file
: e
= new AST
.FileInitExp(token
.loc
, EXP
.file
); break;
6951 case TOK
.fileFullPath
: e
= new AST
.FileInitExp(token
.loc
, EXP
.fileFullPath
); break;
6952 case TOK
.line
: e
= new AST
.LineInitExp(token
.loc
); break;
6953 case TOK
.moduleString
: e
= new AST
.ModuleInitExp(token
.loc
); break;
6954 case TOK
.functionString
: e
= new AST
.FuncInitExp(token
.loc
); break;
6955 case TOK
.prettyFunction
: e
= new AST
.PrettyFuncInitExp(token
.loc
); break;
6962 return parseAssignExp();
6965 /********************
6966 * Parse inline assembler block.
6967 * Enters with token on the `asm`.
6968 * https://dlang.org/spec/iasm.html
6971 * asm FunctionAttributes(opt) { AsmInstructionListopt }
6972 * AsmInstructionList:
6974 * AsmInstruction ; AsmInstruction
6977 * endOfLine = true if EOL means end of asm statement
6979 * inline assembler block as a Statement
6981 AST
.Statement
parseAsm(bool endOfLine
)
6983 // Parse the asm block into a sequence of AsmStatements,
6984 // each AsmStatement is one instruction.
6985 // Separate out labels.
6986 // Defer parsing of AsmStatements until semantic processing.
6988 const loc
= token
.loc
;
6992 StorageClass
stc = parsePostfix(STC
.undefined_
, null); // optional FunctionAttributes
6993 if (stc & (STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.wild
))
6994 error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
6996 check(TOK
.leftCurly
);
6997 Token
* toklist
= null;
6998 Token
** ptoklist
= &toklist
;
6999 Identifier label
= null;
7000 auto statements
= new AST
.Statements();
7001 size_t nestlevel
= 0;
7006 switch (token
.value
)
7008 case TOK
.identifier
:
7011 // Look ahead to see if it is a label
7012 if (peekNext() == TOK
.colon
)
7015 label
= token
.ident
;
7016 labelloc
= token
.loc
;
7028 case TOK
.rightCurly
:
7034 if (toklist || label
)
7036 error("`asm` statements must end in `;`");
7046 error("mismatched number of curly brackets");
7048 if (toklist || label
)
7050 // Create AsmStatement from list of tokens we've saved
7051 AST
.AsmStatement as
= new AST
.AsmStatement(token
.loc
, toklist
);
7052 as
.caseSensitive
= !endOfLine
;
7053 AST
.Statement s
= as
;
7055 ptoklist
= &toklist
;
7058 s
= new AST
.LabelStatement(labelloc
, label
, s
);
7068 error("matching `}` expected, not end of file");
7071 case TOK
.colonColon
: // treat as two separate : tokens for iasmgcc
7072 *ptoklist
= allocateToken();
7073 memcpy(*ptoklist
, &token
, Token
.sizeof
);
7074 (*ptoklist
).value
= TOK
.colon
;
7075 ptoklist
= &(*ptoklist
).next
;
7077 *ptoklist
= allocateToken();
7078 memcpy(*ptoklist
, &token
, Token
.sizeof
);
7079 (*ptoklist
).value
= TOK
.colon
;
7080 ptoklist
= &(*ptoklist
).next
;
7087 *ptoklist
= allocateToken();
7088 memcpy(*ptoklist
, &token
, Token
.sizeof
);
7089 ptoklist
= &(*ptoklist
).next
;
7097 if (token
.value
== TOK
.endOfLine
)
7099 auto s
= new AST
.CompoundAsmStatement(loc
, statements
, stc);
7103 /**********************************
7104 * Issue error if the current token is not `value`,
7105 * advance to next token.
7107 * loc = location for error message
7108 * value = token value to compare with
7110 void check(Loc loc
, TOK value
)
7112 if (token
.value
!= value
)
7113 error(loc
, "found `%s` when expecting `%s`", token
.toChars(), Token
.toChars(value
));
7117 /**********************************
7118 * Issue error if the current token is not `value`,
7119 * advance to next token.
7121 * value = token value to compare with
7123 void check(TOK value
)
7125 check(token
.loc
, value
);
7128 /**********************************
7129 * Issue error if the current token is not `value`,
7130 * advance to next token.
7132 * value = token value to compare with
7133 * string = for error message
7135 void check(TOK value
, const(char)* string
)
7137 if (token
.value
!= value
)
7138 error(token
.loc
, "found `%s` when expecting `%s` following %s", token
.toChars(), Token
.toChars(value
), string
);
7142 private void checkParens(TOK value
, AST
.Expression e
)
7144 if (precedence
[e
.op
] == PREC
.rel
)
7145 error(e
.loc
, "`%s` must be surrounded by parentheses when next to operator `%s`", e
.toChars(), Token
.toChars(value
));
7149 enum NeedDeclaratorId
7151 no
, // Declarator part must have no identifier
7152 opt
, // Declarator part identifier is optional
7153 must
, // Declarator part must have identifier
7154 mustIfDstyle
, // Declarator part must have identifier, but don't recognize old C-style syntax
7157 /************************************
7158 * Determine if the scanner is sitting on the start of a declaration.
7160 * t = current token of the scanner
7161 * needId = flag with additional requirements for a declaration
7162 * endtok = ending token
7163 * pt = will be set ending token (if not null)
7165 * true if the token `t` is a declaration, false otherwise
7167 private bool isDeclaration(Token
* t
, NeedDeclaratorId needId
, TOK endtok
, Token
** pt
)
7169 //printf("isDeclaration(needId = %d)\n", needId);
7175 if ((t
.value
== TOK
.const_ || t
.value
== TOK
.immutable_ || t
.value
== TOK
.inout_ || t
.value
== TOK
.shared_
) && peek(t
).value
!= TOK
.leftParenthesis
)
7188 if (!isBasicType(&t
))
7192 if (!isDeclarator(&t
, &haveId
, &haveTpl
, endtok
, needId
!= NeedDeclaratorId
.mustIfDstyle
))
7194 if ((needId
== NeedDeclaratorId
.no
&& !haveId
) ||
7195 (needId
== NeedDeclaratorId
.opt
) ||
7196 (needId
== NeedDeclaratorId
.must
&& haveId
) ||
7197 (needId
== NeedDeclaratorId
.mustIfDstyle
&& haveId
))
7206 //printf("\tis declaration, t = %s\n", t.toChars());
7210 //printf("\tis not declaration\n");
7214 private bool isBasicType(Token
** pt
)
7216 // This code parallels parseBasicType()
7237 case TOK
.imaginary32
:
7238 case TOK
.imaginary64
:
7239 case TOK
.imaginary80
:
7247 case TOK
.identifier
:
7250 if (t
.value
== TOK
.not)
7260 if (t
.value
== TOK
.dot
)
7264 if (t
.value
!= TOK
.identifier
)
7267 if (t
.value
!= TOK
.not)
7272 * !( args ), !identifier, etc.
7277 case TOK
.identifier
:
7280 case TOK
.leftParenthesis
:
7281 if (!skipParens(t
, &t
))
7302 case TOK
.imaginary32
:
7303 case TOK
.imaginary64
:
7304 case TOK
.imaginary80
:
7309 case TOK
.int32Literal
:
7310 case TOK
.uns32Literal
:
7311 case TOK
.int64Literal
:
7312 case TOK
.uns64Literal
:
7313 case TOK
.int128Literal
:
7314 case TOK
.uns128Literal
:
7315 case TOK
.float32Literal
:
7316 case TOK
.float64Literal
:
7317 case TOK
.float80Literal
:
7318 case TOK
.imaginary32Literal
:
7319 case TOK
.imaginary64Literal
:
7320 case TOK
.imaginary80Literal
:
7324 case TOK
.charLiteral
:
7325 case TOK
.wcharLiteral
:
7326 case TOK
.dcharLiteral
:
7328 case TOK
.hexadecimalString
:
7330 case TOK
.fileFullPath
:
7332 case TOK
.moduleString
:
7333 case TOK
.functionString
:
7334 case TOK
.prettyFunction
:
7351 /* typeof(exp).identifier...
7354 if (!skipParens(t
, &t
))
7359 // __traits(getMember
7361 if (t
.value
!= TOK
.leftParenthesis
)
7365 if (t
.value
!= TOK
.identifier || t
.ident
!= Id
.getMember
)
7367 if (!skipParens(lp
, &lp
))
7369 // we are in a lookup for decl VS statement
7370 // so we expect a declarator following __trait if it's a type.
7371 // other usages wont be ambiguous (alias, template instance, type qual, etc.)
7372 if (lp
.value
!= TOK
.identifier
)
7378 case TOK
.immutable_
:
7381 // const(type) or immutable(type) or shared(type) or wild(type)
7383 if (t
.value
!= TOK
.leftParenthesis
)
7386 if (!isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &t
))
7401 //printf("is not\n");
7405 private bool isDeclarator(Token
** pt
, int* haveId
, int* haveTpl
, TOK endtok
, bool allowAltSyntax
= true)
7407 // This code parallels parseDeclarator()
7411 //printf("Parser::isDeclarator() %s\n", t.toChars());
7412 if (t
.value
== TOK
.assign
)
7425 case TOK
.leftBracket
:
7427 if (t
.value
== TOK
.rightBracket
)
7431 else if (isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightBracket
, &t
))
7433 // It's an associative array declaration
7437 if (t
.value
== TOK
.dot
&& peek(t
).value
== TOK
.identifier
)
7446 // [ expression .. expression ]
7447 if (!isExpression(&t
))
7449 if (t
.value
== TOK
.slice
)
7452 if (!isExpression(&t
))
7454 if (t
.value
!= TOK
.rightBracket
)
7460 if (t
.value
!= TOK
.rightBracket
)
7464 if (t
.value
== TOK
.dot
&& peek(t
).value
== TOK
.identifier
)
7473 case TOK
.identifier
:
7480 case TOK
.leftParenthesis
:
7481 if (!allowAltSyntax
)
7482 return false; // Do not recognize C-style declarations.
7485 if (t
.value
== TOK
.rightParenthesis
)
7486 return false; // () is not a declarator
7488 /* Regard ( identifier ) as not a declarator
7489 * BUG: what about ( *identifier ) in
7491 * where f is a class instance with overloaded () ?
7492 * Should we just disallow C-style function pointer declarations?
7494 if (t
.value
== TOK
.identifier
)
7496 Token
* t2
= peek(t
);
7497 if (t2
.value
== TOK
.rightParenthesis
)
7501 if (!isDeclarator(&t
, haveId
, null, TOK
.rightParenthesis
))
7510 if (!isParameters(&t
))
7512 skipAttributes(t
, &t
);
7525 static if (CARRAYDECL
)
7527 case TOK
.leftBracket
:
7530 if (t
.value
== TOK
.rightBracket
)
7534 else if (isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightBracket
, &t
))
7536 // It's an associative array declaration
7542 if (!isExpression(&t
))
7544 if (t
.value
!= TOK
.rightBracket
)
7551 case TOK
.leftParenthesis
:
7553 if (Token
* tk
= peekPastParen(t
))
7555 if (tk
.value
== TOK
.leftParenthesis
)
7562 else if (tk
.value
== TOK
.assign
)
7571 if (!isParameters(&t
))
7578 case TOK
.immutable_
:
7589 t
= peek(t
); // skip '@'
7590 t
= peek(t
); // skip identifier
7600 // Valid tokens that follow the start of a declaration
7601 case TOK
.rightParenthesis
:
7602 case TOK
.rightBracket
:
7611 // The !parens is to disallow unnecessary parentheses
7612 if (!parens
&& (endtok
== TOK
.reserved || endtok
== t
.value
))
7619 // To recognize the shortened function declaration syntax
7622 1. https://issues.dlang.org/show_bug.cgi?id=24088
7624 2. We need to make sure the would-be
7625 declarator has an identifier otherwise function literals
7626 are handled incorrectly. Some special treatment is required
7627 here, it turns out that a lot of code in the compiler relies
7628 on this mess (in the parser), i.e. having isDeclarator be more
7629 precise the parsing of other things go kaboom, so we do it in a
7636 case TOK
.identifier
:
7637 if (t
.ident
== Id
._body
)
7639 usageOfBodyKeyword();
7645 return haveTpl ?
true : false;
7647 // Used for mixin type parsing
7649 if (endtok
== TOK
.endOfFile
)
7660 private bool isParameters(Token
** pt
)
7662 // This code parallels parseParameterList()
7665 //printf("isParameters()\n");
7666 if (t
.value
!= TOK
.leftParenthesis
)
7670 for (; 1; t
= peek(t
))
7675 case TOK
.rightParenthesis
:
7680 if (skipAttributes(t
, &pastAttr
))
7702 case TOK
.immutable_
:
7706 if (t
.value
== TOK
.leftParenthesis
)
7709 if (!isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &t
))
7711 t
= peek(t
); // skip past closing ')'
7718 if (!isBasicType(&t
))
7722 if (t
.value
!= TOK
.dotDotDot
&& !isDeclarator(&t
, &tmp
, null, TOK
.reserved
))
7724 if (t
.value
== TOK
.assign
)
7727 if (!isExpression(&t
))
7730 if (t
.value
== TOK
.dotDotDot
)
7736 if (t
.value
== TOK
.comma
)
7744 if (t
.value
!= TOK
.rightParenthesis
)
7751 private bool isExpression(Token
** pt
)
7753 // This is supposed to determine if something is an expression.
7754 // What it actually does is scan until a closing right bracket
7762 for (;; t
= peek(t
))
7766 case TOK
.leftBracket
:
7770 case TOK
.rightBracket
:
7775 case TOK
.leftParenthesis
:
7780 if (brnest || panest
)
7784 case TOK
.rightParenthesis
:
7793 case TOK
.rightCurly
:
7794 if (--curlynest
>= 0)
7821 /*******************************************
7824 * t = on opening $(LPAREN)
7825 * pt = *pt is set to token past '$(RPAREN)' on true
7828 * false some parsing error
7830 bool skipParens(Token
* t
, Token
** pt
)
7832 if (t
.value
!= TOK
.leftParenthesis
)
7841 case TOK
.leftParenthesis
:
7845 case TOK
.rightParenthesis
:
7863 *pt
= peek(t
); // skip found rparen
7870 private bool skipParensIf(Token
* t
, Token
** pt
)
7872 if (t
.value
!= TOK
.leftParenthesis
)
7878 return skipParens(t
, pt
);
7881 //returns true if the next value (after optional matching parens) is expected
7882 private bool hasOptionalParensThen(Token
* t
, TOK expected
)
7885 if (!skipParensIf(t
, &tk
))
7887 return tk
.value
== expected
;
7890 /*******************************************
7893 * t is on a candidate attribute
7895 * *pt is set to first non-attribute token on success
7898 * false some parsing error
7900 private bool skipAttributes(Token
* t
, Token
** pt
)
7907 case TOK
.immutable_
:
7915 case TOK
.synchronized_
:
7918 case TOK
.deprecated_
:
7919 if (peek(t
).value
== TOK
.leftParenthesis
)
7922 if (!skipParens(t
, &t
))
7924 // t is on the next of closing parenthesis
7938 if (t
.value
== TOK
.identifier
)
7942 * @identifier!(arglist)
7943 * any of the above followed by (arglist)
7944 * @predefined_attribute
7946 if (isBuiltinAtAttribute(t
.ident
))
7949 if (t
.value
== TOK
.not)
7952 if (t
.value
== TOK
.leftParenthesis
)
7954 // @identifier!(arglist)
7955 if (!skipParens(t
, &t
))
7957 // t is on the next of closing parenthesis
7962 // Do low rent skipTemplateArgument
7963 if (t
.value
== TOK
.vector
)
7965 // identifier!__vector(type)
7967 if (!skipParens(t
, &t
))
7974 if (t
.value
== TOK
.leftParenthesis
)
7976 if (!skipParens(t
, &t
))
7978 // t is on the next of closing parenthesis
7983 if (t
.value
== TOK
.leftParenthesis
)
7985 // @( ArgumentList )
7986 if (!skipParens(t
, &t
))
7988 // t is on the next of closing parenthesis
8007 AST
.Expression
parseExpression()
8009 auto loc
= token
.loc
;
8011 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
8012 auto e
= parseAssignExp();
8013 while (token
.value
== TOK
.comma
)
8016 auto e2
= parseAssignExp();
8017 e
= new AST
.CommaExp(loc
, e
, e2
, false);
8023 /********************************* Expression Parser ***************************/
8025 AST
.Expression
parsePrimaryExp()
8030 const loc
= token
.loc
;
8032 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
8033 switch (token
.value
)
8035 case TOK
.identifier
:
8037 if (peekNext() == TOK
.arrow
)
8039 // skip `identifier ->`
8042 error("use `.` for member lookup, not `->`");
8046 if (peekNext() == TOK
.goesTo
)
8052 if (token
.value
== TOK
.not && (save
= peekNext()) != TOK
.is_
&& save
!= TOK
.in_
)
8054 // identifier!(template-argument-list)
8055 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
8056 e
= new AST
.ScopeExp(loc
, tempinst
);
8059 e
= new AST
.IdentifierExp(loc
, id
);
8064 error("`$` is valid only inside [] of index or slice");
8065 e
= new AST
.DollarExp(loc
);
8070 // Signal global scope '.' operator with "" identifier
8071 e
= new AST
.IdentifierExp(loc
, Id
.empty
);
8075 e
= new AST
.ThisExp(loc
);
8080 e
= new AST
.SuperExp(loc
);
8084 case TOK
.int32Literal
:
8085 e
= new AST
.IntegerExp(loc
, token
.intvalue
, AST
.Type
.tint32
);
8089 case TOK
.uns32Literal
:
8090 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tuns32
);
8094 case TOK
.int64Literal
:
8095 e
= new AST
.IntegerExp(loc
, token
.intvalue
, AST
.Type
.tint64
);
8099 case TOK
.uns64Literal
:
8100 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tuns64
);
8104 case TOK
.float32Literal
:
8105 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat32
);
8109 case TOK
.float64Literal
:
8110 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat64
);
8114 case TOK
.float80Literal
:
8115 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat80
);
8119 case TOK
.imaginary32Literal
:
8120 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary32
);
8124 case TOK
.imaginary64Literal
:
8125 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary64
);
8129 case TOK
.imaginary80Literal
:
8130 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary80
);
8135 e
= new AST
.NullExp(loc
);
8141 const(char)* s
= loc
.filename ? loc
.filename
: mod
.ident
.toChars();
8142 e
= new AST
.StringExp(loc
, s
.toDString());
8146 case TOK
.fileFullPath
:
8148 assert(loc
.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
8149 const s
= FileName
.toAbsolute(loc
.filename
);
8150 e
= new AST
.StringExp(loc
, s
.toDString());
8156 e
= new AST
.IntegerExp(loc
, loc
.linnum
, AST
.Type
.tint32
);
8160 case TOK
.moduleString
:
8162 const(char)* s
= md ? md
.toChars() : mod
.toChars();
8163 e
= new AST
.StringExp(loc
, s
.toDString());
8167 case TOK
.functionString
:
8168 e
= new AST
.FuncInitExp(loc
);
8172 case TOK
.prettyFunction
:
8173 e
= new AST
.PrettyFuncInitExp(loc
);
8178 e
= new AST
.IntegerExp(loc
, 1, AST
.Type
.tbool
);
8183 e
= new AST
.IntegerExp(loc
, 0, AST
.Type
.tbool
);
8187 case TOK
.charLiteral
:
8188 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tchar
);
8192 case TOK
.wcharLiteral
:
8193 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.twchar
);
8197 case TOK
.dcharLiteral
:
8198 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tdchar
);
8203 case TOK
.hexadecimalString
:
8204 const bool hexString
= token
.value
== TOK
.hexadecimalString
;
8206 // cat adjacent strings
8207 auto s
= token
.ustring
;
8208 auto len
= token
.len
;
8209 auto postfix
= token
.postfix
;
8214 if (token
.value
== TOK
.string_ || token
.value
== TOK
.hexadecimalString
)
8218 if (token
.postfix
!= postfix
)
8219 error(token
.loc
, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix
, token
.postfix
);
8220 postfix
= token
.postfix
;
8223 error("implicit string concatenation is error-prone and disallowed in D");
8224 eSink
.errorSupplemental(token
.loc
, "Use the explicit syntax instead " ~
8225 "(concatenating literals is `@nogc`): %s ~ %s",
8226 prev
.toChars(), token
.toChars());
8229 const len2
= token
.len
;
8231 auto s2
= cast(char*)mem
.xmalloc_noscan(len
* char.sizeof
);
8232 memcpy(s2
, s
, len1
* char.sizeof
);
8233 memcpy(s2
+ len1
, token
.ustring
, len2
* char.sizeof
);
8239 e
= new AST
.StringExp(loc
, s
[0 .. len
], len
, 1, postfix
);
8240 e
.isStringExp().hexString
= hexString
;
8256 t
= AST
.Type
.tint16
;
8260 t
= AST
.Type
.tuns16
;
8264 t
= AST
.Type
.tint32
;
8268 t
= AST
.Type
.tuns32
;
8272 t
= AST
.Type
.tint64
;
8276 t
= AST
.Type
.tuns64
;
8280 t
= AST
.Type
.tint128
;
8284 t
= AST
.Type
.tuns128
;
8288 t
= AST
.Type
.tfloat32
;
8292 t
= AST
.Type
.tfloat64
;
8296 t
= AST
.Type
.tfloat80
;
8299 case TOK
.imaginary32
:
8300 t
= AST
.Type
.timaginary32
;
8303 case TOK
.imaginary64
:
8304 t
= AST
.Type
.timaginary64
;
8307 case TOK
.imaginary80
:
8308 t
= AST
.Type
.timaginary80
;
8312 t
= AST
.Type
.tcomplex32
;
8316 t
= AST
.Type
.tcomplex64
;
8320 t
= AST
.Type
.tcomplex80
;
8332 t
= AST
.Type
.twchar
;
8336 t
= AST
.Type
.tdchar
;
8339 const next
= peekNext();
8340 if (next
!= TOK
.leftParenthesis
&& next
!= TOK
.dot
)
8342 // defer error for better diagnostics
8343 e
= new AST
.TypeExp(loc
, parseType
);
8347 if (token
.value
== TOK
.leftParenthesis
)
8349 e
= new AST
.TypeExp(loc
, t
);
8350 e
= new AST
.CallExp(loc
, e
, parseArguments());
8354 if (token
.value
!= TOK
.identifier
)
8356 error(token
.loc
, "found `%s` when expecting identifier following `%s`.", token
.toChars(), t
.toChars());
8359 e
= new AST
.DotIdExp(loc
, new AST
.TypeExp(loc
, t
), token
.ident
);
8366 e
= new AST
.TypeExp(loc
, t
);
8372 e
= new AST
.TypeExp(loc
, t
);
8378 check(TOK
.leftParenthesis
, "`typeid`");
8379 RootObject o
= parseTypeOrAssignExp();
8380 check(TOK
.rightParenthesis
);
8381 e
= new AST
.TypeidExp(loc
, o
);
8386 /* __traits(identifier, args...)
8389 AST
.Objects
* args
= null;
8392 check(TOK
.leftParenthesis
);
8393 if (token
.value
!= TOK
.identifier
)
8395 error("`__traits(identifier, args...)` expected");
8398 ident
= token
.ident
;
8400 if (token
.value
== TOK
.comma
)
8401 args
= parseTemplateArgumentList(); // __traits(identifier, args...)
8403 check(TOK
.rightParenthesis
); // __traits(identifier)
8405 e
= new AST
.TraitsExp(loc
, ident
, args
);
8411 Identifier ident
= null;
8412 AST
.Type tspec
= null;
8413 TOK tok
= TOK
.reserved
;
8414 TOK tok2
= TOK
.reserved
;
8415 AST
.TemplateParameters
* tpl
= null;
8418 if (token
.value
== TOK
.leftParenthesis
)
8421 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.leftParenthesis
)
8423 error(loc
, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token
.toChars());
8425 Token
* tempTok
= peekPastParen(&token
);
8426 memcpy(&token
, tempTok
, Token
.sizeof
);
8429 targ
= parseType(&ident
);
8430 if (token
.value
== TOK
.colon || token
.value
== TOK
.equal
)
8434 if (tok
== TOK
.equal
&& (token
.value
== TOK
.struct_ || token
.value
== TOK
.union_
8435 || token
.value
== TOK
.class_ || token
.value
== TOK
.super_ || token
.value
== TOK
.enum_
8436 || token
.value
== TOK
.interface_ || token
.value
== TOK
.package_ || token
.value
== TOK
.module_
8437 || token
.value
== TOK
.argumentTypes || token
.value
== TOK
.parameters
8438 || token
.value
== TOK
.const_
&& peekNext() == TOK
.rightParenthesis
8439 || token
.value
== TOK
.immutable_
&& peekNext() == TOK
.rightParenthesis
8440 || token
.value
== TOK
.shared_
&& peekNext() == TOK
.rightParenthesis
8441 || token
.value
== TOK
.inout_
&& peekNext() == TOK
.rightParenthesis || token
.value
== TOK
.function_
8442 || token
.value
== TOK
.delegate_ || token
.value
== TOK
.return_
8443 ||
(token
.value
== TOK
.vector
&& peekNext() == TOK
.rightParenthesis
)))
8450 tspec
= parseType();
8455 if (token
.value
== TOK
.comma
)
8456 tpl
= parseTemplateParameterList(1);
8459 tpl
= new AST
.TemplateParameters();
8460 check(TOK
.rightParenthesis
);
8464 check(TOK
.rightParenthesis
);
8468 error("`type identifier : specialization` expected following `is`");
8471 e
= new AST
.IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
8476 // https://dlang.org/spec/expression.html#assert_expressions
8477 AST
.Expression msg
= null;
8480 check(TOK
.leftParenthesis
, "`assert`");
8481 e
= parseAssignExp();
8482 if (token
.value
== TOK
.comma
)
8485 if (token
.value
!= TOK
.rightParenthesis
)
8487 msg
= parseAssignExp();
8488 if (token
.value
== TOK
.comma
)
8492 check(TOK
.rightParenthesis
);
8493 e
= new AST
.AssertExp(loc
, e
, msg
);
8498 // https://dlang.org/spec/expression.html#mixin_expressions
8500 if (token
.value
!= TOK
.leftParenthesis
)
8501 error(token
.loc
, "found `%s` when expecting `%s` following `mixin`", token
.toChars(), Token
.toChars(TOK
.leftParenthesis
));
8502 auto exps
= parseArguments();
8503 e
= new AST
.MixinExp(loc
, exps
);
8509 check(TOK
.leftParenthesis
, "`import`");
8510 e
= parseAssignExp();
8511 check(TOK
.rightParenthesis
);
8512 e
= new AST
.ImportExp(loc
, e
);
8516 e
= parseNewExp(null);
8521 if (peekNext() == TOK
.ref_
&& peekNext2() == TOK
.leftParenthesis
)
8523 Token
* tk
= peekPastParen(peek(peek(&token
)));
8524 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8526 // auto ref (arguments) => expression
8527 // auto ref (arguments) { statements... }
8532 error("found `%s` when expecting `ref` and function literal following `auto`", token
.toChars());
8537 if (peekNext() == TOK
.leftParenthesis
)
8539 Token
* tk
= peekPastParen(peek(&token
));
8540 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8542 // ref (arguments) => expression
8543 // ref (arguments) { statements... }
8548 error("found `%s` when expecting function literal following `ref`", token
.toChars());
8551 case TOK
.leftParenthesis
:
8553 Token
* tk
= peekPastParen(&token
);
8554 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8556 // (arguments) => expression
8557 // (arguments) { statements... }
8563 e
= parseExpression();
8564 check(loc
, TOK
.rightParenthesis
);
8567 case TOK
.leftBracket
:
8569 /* Parse array literals and associative array literals:
8570 * [ value, value, value ... ]
8571 * [ key:value, key:value, key:value ... ]
8573 auto values
= new AST
.Expressions();
8574 AST
.Expressions
* keys
= null;
8577 while (token
.value
!= TOK
.rightBracket
&& token
.value
!= TOK
.endOfFile
)
8579 e
= parseAssignExp();
8580 if (token
.value
== TOK
.colon
&& (keys || values
.length
== 0))
8584 keys
= new AST
.Expressions();
8586 e
= parseAssignExp();
8590 error("`key:value` expected for associative array literal");
8594 if (token
.value
== TOK
.rightBracket
)
8598 check(loc
, TOK
.rightBracket
);
8601 e
= new AST
.AssocArrayLiteralExp(loc
, keys
, values
);
8603 e
= new AST
.ArrayLiteralExp(loc
, null, values
);
8611 AST
.Dsymbol s
= parseFunctionLiteral();
8612 e
= new AST
.FuncExp(loc
, s
);
8617 error("expression expected, not `%s`", token
.toChars());
8619 // Anything for e, as long as it's not NULL
8620 e
= new AST
.IntegerExp(loc
, 0, AST
.Type
.tint32
);
8627 private AST
.Expression
parseUnaryExp()
8630 const loc
= token
.loc
;
8632 switch (token
.value
)
8636 e
= parseUnaryExp();
8637 e
= new AST
.AddrExp(loc
, e
);
8642 e
= parseUnaryExp();
8643 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8644 e
= new AST
.PreExp(EXP
.prePlusPlus
, loc
, e
);
8647 case TOK
.minusMinus
:
8649 e
= parseUnaryExp();
8650 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8651 e
= new AST
.PreExp(EXP
.preMinusMinus
, loc
, e
);
8656 e
= parseUnaryExp();
8657 e
= new AST
.PtrExp(loc
, e
);
8662 e
= parseUnaryExp();
8663 e
= new AST
.NegExp(loc
, e
);
8668 e
= parseUnaryExp();
8669 e
= new AST
.UAddExp(loc
, e
);
8674 e
= parseUnaryExp();
8675 e
= new AST
.NotExp(loc
, e
);
8680 e
= parseUnaryExp();
8681 e
= new AST
.ComExp(loc
, e
);
8685 // @@@DEPRECATED_2.109@@@
8686 // Use of `delete` keyword has been an error since 2.099.
8687 // Remove from the parser after 2.109.
8689 e
= parseUnaryExp();
8690 e
= new AST
.DeleteExp(loc
, e
, false);
8693 case TOK
.cast_
: // cast(type) expression
8696 check(TOK
.leftParenthesis
);
8697 /* Look for cast(), cast(const), cast(immutable),
8698 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
8703 switch (token
.value
)
8706 if (peekNext() == TOK
.leftParenthesis
)
8707 break; // const as type constructor
8708 m |
= MODFlags
.const_
; // const as storage class
8712 case TOK
.immutable_
:
8713 if (peekNext() == TOK
.leftParenthesis
)
8715 m |
= MODFlags
.immutable_
;
8720 if (peekNext() == TOK
.leftParenthesis
)
8722 m |
= MODFlags
.shared_
;
8727 if (peekNext() == TOK
.leftParenthesis
)
8738 if (token
.value
== TOK
.rightParenthesis
)
8741 e
= parseUnaryExp();
8742 e
= new AST
.CastExp(loc
, e
, m
);
8746 AST
.Type t
= parseType(); // cast( type )
8747 t
= t
.addMod(m
); // cast( const type )
8748 check(TOK
.rightParenthesis
);
8749 e
= parseUnaryExp();
8750 e
= new AST
.CastExp(loc
, e
, t
);
8757 case TOK
.immutable_
: // immutable(type)(arguments) / immutable(type).init
8759 StorageClass
stc = parseTypeCtor();
8761 AST
.Type t
= parseBasicType();
8764 if (stc == 0 && token
.value
== TOK
.dot
)
8767 if (token
.value
!= TOK
.identifier
)
8769 error("identifier expected following `%s.`, not `%s`",
8770 t
.toChars(), token
.toChars());
8771 return AST
.ErrorExp
.get();
8773 e
= new AST
.DotIdExp(loc
, new AST
.TypeExp(loc
, t
), token
.ident
);
8775 e
= parsePostExp(e
);
8779 e
= new AST
.TypeExp(loc
, t
);
8780 if (token
.value
!= TOK
.leftParenthesis
)
8782 error("`(arguments)` expected following `%s`, not `%s`",
8783 t
.toChars(), token
.toChars());
8786 e
= new AST
.CallExp(loc
, e
, parseArguments());
8790 case TOK
.leftParenthesis
:
8792 auto tk
= peek(&token
);
8793 static if (CCASTSYNTAX
)
8796 if (isDeclaration(tk
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &tk
))
8798 tk
= peek(tk
); // skip over right parenthesis
8803 if (tk
.value
== TOK
.is_ || tk
.value
== TOK
.in_
) // !is or !in
8809 case TOK
.minusMinus
:
8812 case TOK
.leftParenthesis
:
8813 case TOK
.identifier
:
8816 case TOK
.int32Literal
:
8817 case TOK
.uns32Literal
:
8818 case TOK
.int64Literal
:
8819 case TOK
.uns64Literal
:
8820 case TOK
.int128Literal
:
8821 case TOK
.uns128Literal
:
8822 case TOK
.float32Literal
:
8823 case TOK
.float64Literal
:
8824 case TOK
.float80Literal
:
8825 case TOK
.imaginary32Literal
:
8826 case TOK
.imaginary64Literal
:
8827 case TOK
.imaginary80Literal
:
8831 case TOK
.charLiteral
:
8832 case TOK
.wcharLiteral
:
8833 case TOK
.dcharLiteral
:
8841 case TOK
.fileFullPath
:
8843 case TOK
.moduleString
:
8844 case TOK
.functionString
:
8845 case TOK
.prettyFunction
:
8863 case TOK
.imaginary32
:
8864 case TOK
.imaginary64
:
8865 case TOK
.imaginary80
:
8873 // Note: `t` may be an expression that looks like a type
8874 auto t
= parseType();
8875 check(TOK
.rightParenthesis
);
8878 // or .identifier!( ... )
8879 if (token
.value
== TOK
.dot
)
8881 if (peekNext() != TOK
.identifier
&& peekNext() != TOK
.new_
)
8883 error("identifier or new keyword expected following `(...)`.");
8885 return AST
.ErrorExp
.get();
8887 auto te
= new AST
.TypeExp(loc
, t
);
8889 e
= parsePostExp(te
);
8891 else if (token
.value
== TOK
.leftParenthesis ||
8892 token
.value
== TOK
.plusPlus || token
.value
== TOK
.minusMinus
)
8897 auto te
= new AST
.TypeExp(loc
, t
);
8899 e
= parsePostExp(te
);
8903 e
= parseUnaryExp();
8904 e
= new AST
.CastExp(loc
, e
, t
);
8905 error(loc
, "C style cast illegal, use `%s`", e
.toChars());
8914 e
= parsePrimaryExp();
8915 e
= parsePostExp(e
);
8921 // Deviation from the DIP:
8922 // Parse AssignExpression instead of Expression to avoid conflicts for comma
8923 // separated lists, e.g. function arguments
8924 AST
.Expression exp
= parseAssignExp();
8925 e
= new AST
.ThrowExp(loc
, exp
);
8930 e
= parsePrimaryExp();
8931 e
= parsePostExp(e
);
8936 // ^^ is right associative and has higher precedence than the unary operators
8937 while (token
.value
== TOK
.pow
)
8940 AST
.Expression e2
= parseUnaryExp();
8941 e
= new AST
.PowExp(loc
, e
, e2
);
8947 private AST
.Expression
parsePostExp(AST
.Expression e
)
8951 const loc
= token
.loc
;
8952 switch (token
.value
)
8956 if (token
.value
== TOK
.identifier
)
8958 Identifier id
= token
.ident
;
8961 if (token
.value
== TOK
.not && peekNext() != TOK
.is_
&& peekNext() != TOK
.in_
)
8963 AST
.Objects
* tiargs
= parseTemplateArguments();
8964 e
= new AST
.DotTemplateInstanceExp(loc
, e
, id
, tiargs
);
8967 e
= new AST
.DotIdExp(loc
, e
, id
);
8970 if (token
.value
== TOK
.new_
)
8975 error("identifier or `new` expected following `.`, not `%s`", token
.toChars());
8979 e
= new AST
.PostExp(EXP
.plusPlus
, loc
, e
);
8982 case TOK
.minusMinus
:
8983 e
= new AST
.PostExp(EXP
.minusMinus
, loc
, e
);
8986 case TOK
.leftParenthesis
:
8987 AST
.Expressions
* args
= new AST
.Expressions();
8988 AST
.Identifiers
* names
= new AST
.Identifiers();
8989 parseNamedArguments(args
, names
);
8990 e
= new AST
.CallExp(loc
, e
, args
, names
);
8993 case TOK
.leftBracket
:
8995 // array dereferences:
8998 // array[lwr .. upr]
8999 AST
.Expression index
;
9001 auto arguments
= new AST
.Expressions();
9005 while (token
.value
!= TOK
.rightBracket
&& token
.value
!= TOK
.endOfFile
)
9007 index
= parseAssignExp();
9008 if (token
.value
== TOK
.slice
)
9010 // array[..., lwr..upr, ...]
9012 upr
= parseAssignExp();
9013 arguments
.push(new AST
.IntervalExp(loc
, index
, upr
));
9016 arguments
.push(index
);
9017 if (token
.value
== TOK
.rightBracket
)
9021 check(TOK
.rightBracket
);
9023 e
= new AST
.ArrayExp(loc
, e
, arguments
);
9033 private AST
.Expression
parseMulExp()
9035 const loc
= token
.loc
;
9036 auto e
= parseUnaryExp();
9040 switch (token
.value
)
9044 auto e2
= parseUnaryExp();
9045 e
= new AST
.MulExp(loc
, e
, e2
);
9050 auto e2
= parseUnaryExp();
9051 e
= new AST
.DivExp(loc
, e
, e2
);
9056 auto e2
= parseUnaryExp();
9057 e
= new AST
.ModExp(loc
, e
, e2
);
9068 private AST
.Expression
parseAddExp()
9070 const loc
= token
.loc
;
9071 auto e
= parseMulExp();
9075 switch (token
.value
)
9079 auto e2
= parseMulExp();
9080 e
= new AST
.AddExp(loc
, e
, e2
);
9085 auto e2
= parseMulExp();
9086 e
= new AST
.MinExp(loc
, e
, e2
);
9091 auto e2
= parseMulExp();
9092 e
= new AST
.CatExp(loc
, e
, e2
);
9103 private AST
.Expression
parseShiftExp()
9105 const loc
= token
.loc
;
9106 auto e
= parseAddExp();
9110 switch (token
.value
)
9114 auto e2
= parseAddExp();
9115 e
= new AST
.ShlExp(loc
, e
, e2
);
9118 case TOK
.rightShift
:
9120 auto e2
= parseAddExp();
9121 e
= new AST
.ShrExp(loc
, e
, e2
);
9124 case TOK
.unsignedRightShift
:
9126 auto e2
= parseAddExp();
9127 e
= new AST
.UshrExp(loc
, e
, e2
);
9138 private AST
.Expression
parseCmpExp()
9140 const loc
= token
.loc
;
9142 auto e
= parseShiftExp();
9143 EXP op
= EXP
.reserved
;
9145 switch (token
.value
)
9147 case TOK
.equal
: op
= EXP
.equal
; goto Lequal
;
9148 case TOK
.notEqual
: op
= EXP
.notEqual
; goto Lequal
;
9151 auto e2
= parseShiftExp();
9152 e
= new AST
.EqualExp(op
, loc
, e
, e2
);
9157 // Attempt to identify '!is'
9158 const tv
= peekNext();
9163 auto e2
= parseShiftExp();
9164 e
= new AST
.InExp(loc
, e
, e2
);
9165 e
= new AST
.NotExp(loc
, e
);
9171 op
= EXP
.notIdentity
;
9174 case TOK
.is_
: op
= EXP
.identity
; goto Lidentity
;
9177 auto e2
= parseShiftExp();
9178 e
= new AST
.IdentityExp(op
, loc
, e
, e2
);
9181 case TOK
.lessThan
: op
= EXP
.lessThan
; goto Lcmp
;
9182 case TOK
.lessOrEqual
: op
= EXP
.lessOrEqual
; goto Lcmp
;
9183 case TOK
.greaterThan
: op
= EXP
.greaterThan
; goto Lcmp
;
9184 case TOK
.greaterOrEqual
: op
= EXP
.greaterOrEqual
; goto Lcmp
;
9187 auto e2
= parseShiftExp();
9188 e
= new AST
.CmpExp(op
, loc
, e
, e2
);
9193 auto e2
= parseShiftExp();
9194 e
= new AST
.InExp(loc
, e
, e2
);
9203 private AST
.Expression
parseAndExp()
9205 Loc loc
= token
.loc
;
9206 bool parens
= token
.value
== TOK
.leftParenthesis
;
9207 auto e
= parseCmpExp();
9208 while (token
.value
== TOK
.and)
9211 checkParens(TOK
.and, e
);
9212 parens
= nextToken() == TOK
.leftParenthesis
;
9213 auto e2
= parseCmpExp();
9215 checkParens(TOK
.and, e2
);
9216 e
= new AST
.AndExp(loc
, e
, e2
);
9217 parens
= true; // don't call checkParens() for And
9223 private AST
.Expression
parseXorExp()
9225 Loc loc
= token
.loc
;
9227 bool parens
= token
.value
== TOK
.leftParenthesis
;
9228 auto e
= parseAndExp();
9229 while (token
.value
== TOK
.xor)
9232 checkParens(TOK
.xor, e
);
9233 parens
= nextToken() == TOK
.leftParenthesis
;
9234 auto e2
= parseAndExp();
9236 checkParens(TOK
.xor, e2
);
9237 e
= new AST
.XorExp(loc
, e
, e2
);
9244 private AST
.Expression
parseOrExp()
9246 Loc loc
= token
.loc
;
9248 bool parens
= token
.value
== TOK
.leftParenthesis
;
9249 auto e
= parseXorExp();
9250 while (token
.value
== TOK
.or)
9253 checkParens(TOK
.or, e
);
9254 parens
= nextToken() == TOK
.leftParenthesis
;
9255 auto e2
= parseXorExp();
9257 checkParens(TOK
.or, e2
);
9258 e
= new AST
.OrExp(loc
, e
, e2
);
9265 private AST
.Expression
parseAndAndExp()
9267 const loc
= token
.loc
;
9269 auto e
= parseOrExp();
9270 while (token
.value
== TOK
.andAnd
)
9273 auto e2
= parseOrExp();
9274 e
= new AST
.LogicalExp(loc
, EXP
.andAnd
, e
, e2
);
9279 private AST
.Expression
parseOrOrExp()
9281 const loc
= token
.loc
;
9283 auto e
= parseAndAndExp();
9284 while (token
.value
== TOK
.orOr
)
9287 auto e2
= parseAndAndExp();
9288 e
= new AST
.LogicalExp(loc
, EXP
.orOr
, e
, e2
);
9293 private AST
.Expression
parseCondExp()
9295 const loc
= token
.loc
;
9297 auto e
= parseOrOrExp();
9298 if (token
.value
== TOK
.question
)
9301 auto e1
= parseExpression();
9303 auto e2
= parseCondExp();
9304 e
= new AST
.CondExp(loc
, e
, e1
, e2
);
9309 AST
.Expression
parseAssignExp()
9311 bool parens
= token
.value
== TOK
.leftParenthesis
;
9317 // require parens for e.g. `t ? a = 1 : b = 2`
9318 void checkRequiredParens()
9320 if (e
.op
== EXP
.question
&& !parens
)
9321 eSink
.error(e
.loc
, "`%s` must be surrounded by parentheses when next to operator `%s`",
9322 e
.toChars(), Token
.toChars(token
.value
));
9325 const loc
= token
.loc
;
9326 switch (token
.value
)
9329 checkRequiredParens();
9331 auto e2
= parseAssignExp();
9332 e
= new AST
.AssignExp(loc
, e
, e2
);
9336 checkRequiredParens();
9338 auto e2
= parseAssignExp();
9339 e
= new AST
.AddAssignExp(loc
, e
, e2
);
9343 checkRequiredParens();
9345 auto e2
= parseAssignExp();
9346 e
= new AST
.MinAssignExp(loc
, e
, e2
);
9350 checkRequiredParens();
9352 auto e2
= parseAssignExp();
9353 e
= new AST
.MulAssignExp(loc
, e
, e2
);
9357 checkRequiredParens();
9359 auto e2
= parseAssignExp();
9360 e
= new AST
.DivAssignExp(loc
, e
, e2
);
9364 checkRequiredParens();
9366 auto e2
= parseAssignExp();
9367 e
= new AST
.ModAssignExp(loc
, e
, e2
);
9371 checkRequiredParens();
9373 auto e2
= parseAssignExp();
9374 e
= new AST
.PowAssignExp(loc
, e
, e2
);
9378 checkRequiredParens();
9380 auto e2
= parseAssignExp();
9381 e
= new AST
.AndAssignExp(loc
, e
, e2
);
9385 checkRequiredParens();
9387 auto e2
= parseAssignExp();
9388 e
= new AST
.OrAssignExp(loc
, e
, e2
);
9392 checkRequiredParens();
9394 auto e2
= parseAssignExp();
9395 e
= new AST
.XorAssignExp(loc
, e
, e2
);
9398 case TOK
.leftShiftAssign
:
9399 checkRequiredParens();
9401 auto e2
= parseAssignExp();
9402 e
= new AST
.ShlAssignExp(loc
, e
, e2
);
9405 case TOK
.rightShiftAssign
:
9406 checkRequiredParens();
9408 auto e2
= parseAssignExp();
9409 e
= new AST
.ShrAssignExp(loc
, e
, e2
);
9412 case TOK
.unsignedRightShiftAssign
:
9413 checkRequiredParens();
9415 auto e2
= parseAssignExp();
9416 e
= new AST
.UshrAssignExp(loc
, e
, e2
);
9419 case TOK
.concatenateAssign
:
9420 checkRequiredParens();
9422 auto e2
= parseAssignExp();
9423 e
= new AST
.CatAssignExp(loc
, e
, e2
);
9433 /*************************
9434 * Collect argument list.
9435 * Assume current token is ',', '$(LPAREN)' or '['.
9437 private AST
.Expressions
* parseArguments()
9440 AST
.Expressions
* arguments
= new AST
.Expressions();
9441 parseNamedArguments(arguments
, null);
9445 /*************************
9446 * Collect argument list.
9447 * Assume current token is ',', '$(LPAREN)' or '['.
9449 private void parseNamedArguments(AST
.Expressions
* arguments
, AST
.Identifiers
* names
)
9453 const endtok
= token
.value
== TOK
.leftBracket ? TOK
.rightBracket
: TOK
.rightParenthesis
;
9457 while (token
.value
!= endtok
&& token
.value
!= TOK
.endOfFile
)
9459 if (peekNext() == TOK
.colon
)
9461 // Named argument `name: exp`
9462 auto loc
= token
.loc
;
9463 auto ident
= token
.ident
;
9464 check(TOK
.identifier
);
9469 error(loc
, "named arguments not allowed here");
9477 auto arg
= parseAssignExp();
9478 arguments
.push(arg
);
9480 if (token
.value
!= TOK
.comma
)
9483 nextToken(); //comma
9488 /*******************************************
9490 private AST
.Expression
parseNewExp(AST
.Expression thisexp
)
9492 const loc
= token
.loc
;
9495 AST
.Expressions
* arguments
= null;
9496 AST
.Identifiers
* names
= null;
9498 // An anonymous nested class starts with "class"
9499 if (token
.value
== TOK
.class_
)
9502 if (token
.value
== TOK
.leftParenthesis
)
9504 arguments
= new AST
.Expressions();
9505 names
= new AST
.Identifiers();
9506 parseNamedArguments(arguments
, names
);
9509 AST
.BaseClasses
* baseclasses
= null;
9510 if (token
.value
!= TOK
.leftCurly
)
9511 baseclasses
= parseBaseClasses();
9513 Identifier id
= null;
9514 AST
.Dsymbols
* members
= null;
9516 if (token
.value
!= TOK
.leftCurly
)
9518 error("`{ members }` expected for anonymous class");
9523 members
= parseDeclDefs(0);
9524 if (token
.value
!= TOK
.rightCurly
)
9525 error("class member expected");
9529 auto cd
= new AST
.ClassDeclaration(loc
, id
, baseclasses
, members
, false);
9530 auto e
= new AST
.NewAnonClassExp(loc
, thisexp
, cd
, arguments
);
9534 const stc = parseTypeCtor();
9535 auto t
= parseBasicType(true);
9536 t
= parseTypeSuffixes(t
);
9538 if (t
.ty
== Taarray
)
9540 AST
.TypeAArray taa
= cast(AST
.TypeAArray
)t
;
9541 AST
.Type index
= taa
.index
;
9542 // `new Type[expr]` is a static array
9543 auto edim
= AST
.typeToExpression(index
);
9545 t
= new AST
.TypeSArray(taa
.next
, edim
);
9547 else if (token
.value
== TOK
.leftParenthesis
&& t
.ty
!= Tsarray
)
9549 arguments
= new AST
.Expressions();
9550 names
= new AST
.Identifiers();
9551 parseNamedArguments(arguments
, names
);
9554 auto e
= new AST
.NewExp(loc
, thisexp
, t
, arguments
, names
);
9558 /**********************************************
9560 private void addComment(AST
.Dsymbol s
, const(char)* blockComment
)
9563 this.addComment(s
, blockComment
.toDString());
9566 private void addComment(AST
.Dsymbol s
, const(char)[] blockComment
)
9570 s
.addComment(combineComments(blockComment
, token
.lineComment
, true));
9571 token
.lineComment
= null;
9575 /**********************************************
9576 * Recognize builtin @ attributes
9578 * ident = identifier
9580 * storage class for attribute, 0 if not
9582 static StorageClass
isBuiltinAtAttribute(Identifier ident
)
9584 return (ident
== Id
.property
) ? STC
.property
:
9585 (ident
== Id
.nogc
) ? STC
.nogc
:
9586 (ident
== Id
.safe
) ? STC
.safe
:
9587 (ident
== Id
.trusted
) ? STC
.trusted
:
9588 (ident
== Id
.system
) ? STC
.system
:
9589 (ident
== Id
.live
) ? STC
.live
:
9590 (ident
== Id
.future
) ? STC
.future
:
9591 (ident
== Id
.disable
) ? STC
.disable
:
9595 enum StorageClass atAttrGroup
=
9602 /*STC.future |*/ // probably should be included
9605 void usageOfBodyKeyword()
9607 version (none
) // disable obsolete warning
9609 eSink
.warning(token
.loc
, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
9635 /**********************************
9636 * Set operator precedence for each operator.
9640 immutable PREC
[EXP
.max
+ 1] precedence
=
9642 EXP
.type
: PREC
.expr
,
9643 EXP
.error
: PREC
.expr
,
9644 EXP
.objcClassReference
: PREC
.expr
, // Objective-C class reference, same as EXP.type
9646 EXP
.mixin_
: PREC
.primary
,
9648 EXP
.import_
: PREC
.primary
,
9649 EXP
.dotVariable
: PREC
.primary
,
9650 EXP
.scope_
: PREC
.primary
,
9651 EXP
.identifier
: PREC
.primary
,
9652 EXP
.this_
: PREC
.primary
,
9653 EXP
.super_
: PREC
.primary
,
9654 EXP
.int64
: PREC
.primary
,
9655 EXP
.float64
: PREC
.primary
,
9656 EXP
.complex80
: PREC
.primary
,
9657 EXP
.null_
: PREC
.primary
,
9658 EXP
.string_
: PREC
.primary
,
9659 EXP
.arrayLiteral
: PREC
.primary
,
9660 EXP
.assocArrayLiteral
: PREC
.primary
,
9661 EXP
.classReference
: PREC
.primary
,
9662 EXP
.file
: PREC
.primary
,
9663 EXP
.fileFullPath
: PREC
.primary
,
9664 EXP
.line
: PREC
.primary
,
9665 EXP
.moduleString
: PREC
.primary
,
9666 EXP
.functionString
: PREC
.primary
,
9667 EXP
.prettyFunction
: PREC
.primary
,
9668 EXP
.typeid_
: PREC
.primary
,
9669 EXP
.is_
: PREC
.primary
,
9670 EXP
.assert_
: PREC
.primary
,
9671 EXP
.halt
: PREC
.primary
,
9672 EXP
.template_
: PREC
.primary
,
9673 EXP
.dSymbol
: PREC
.primary
,
9674 EXP
.function_
: PREC
.primary
,
9675 EXP
.variable
: PREC
.primary
,
9676 EXP
.symbolOffset
: PREC
.primary
,
9677 EXP
.structLiteral
: PREC
.primary
,
9678 EXP
.compoundLiteral
: PREC
.primary
,
9679 EXP
.arrayLength
: PREC
.primary
,
9680 EXP
.delegatePointer
: PREC
.primary
,
9681 EXP
.delegateFunctionPointer
: PREC
.primary
,
9682 EXP
.remove
: PREC
.primary
,
9683 EXP
.tuple
: PREC
.primary
,
9684 EXP
.traits
: PREC
.primary
,
9685 EXP
.overloadSet
: PREC
.primary
,
9686 EXP
.void_
: PREC
.primary
,
9687 EXP
.vectorArray
: PREC
.primary
,
9688 EXP
._Generic
: PREC
.primary
,
9691 EXP
.dotTemplateInstance
: PREC
.primary
,
9692 EXP
.dotIdentifier
: PREC
.primary
,
9693 EXP
.dotTemplateDeclaration
: PREC
.primary
,
9694 EXP
.dot
: PREC
.primary
,
9695 EXP
.dotType
: PREC
.primary
,
9696 EXP
.plusPlus
: PREC
.primary
,
9697 EXP
.minusMinus
: PREC
.primary
,
9698 EXP
.prePlusPlus
: PREC
.primary
,
9699 EXP
.preMinusMinus
: PREC
.primary
,
9700 EXP
.call : PREC
.primary
,
9701 EXP
.slice
: PREC
.primary
,
9702 EXP
.array
: PREC
.primary
,
9703 EXP
.index
: PREC
.primary
,
9705 EXP
.delegate_
: PREC
.unary
,
9706 EXP
.address
: PREC
.unary
,
9707 EXP
.star
: PREC
.unary
,
9708 EXP
.negate
: PREC
.unary
,
9709 EXP
.uadd
: PREC
.unary
,
9710 EXP
.not : PREC
.unary
,
9711 EXP
.tilde
: PREC
.unary
,
9712 EXP
.delete_
: PREC
.unary
,
9713 EXP
.new_
: PREC
.unary
,
9714 EXP
.newAnonymousClass
: PREC
.unary
,
9715 EXP
.cast_
: PREC
.unary
,
9716 EXP
.throw_
: PREC
.unary
,
9718 EXP
.vector
: PREC
.unary
,
9727 EXP
.concatenate
: PREC
.add,
9729 EXP
.leftShift
: PREC
.shift
,
9730 EXP
.rightShift
: PREC
.shift
,
9731 EXP
.unsignedRightShift
: PREC
.shift
,
9733 EXP
.lessThan
: PREC
.rel
,
9734 EXP
.lessOrEqual
: PREC
.rel
,
9735 EXP
.greaterThan
: PREC
.rel
,
9736 EXP
.greaterOrEqual
: PREC
.rel
,
9739 /* Note that we changed precedence, so that < and != have the same
9740 * precedence. This change is in the parser, too.
9742 EXP
.equal
: PREC
.rel
,
9743 EXP
.notEqual
: PREC
.rel
,
9744 EXP
.identity
: PREC
.rel
,
9745 EXP
.notIdentity
: PREC
.rel
,
9751 EXP
.andAnd
: PREC
.andand
,
9752 EXP
.orOr
: PREC
.oror
,
9754 EXP
.question
: PREC
.cond
,
9756 EXP
.assign
: PREC
.assign
,
9757 EXP
.construct
: PREC
.assign
,
9758 EXP
.blit
: PREC
.assign
,
9759 EXP
.addAssign
: PREC
.assign
,
9760 EXP
.minAssign
: PREC
.assign
,
9761 EXP
.concatenateAssign
: PREC
.assign
,
9762 EXP
.concatenateElemAssign
: PREC
.assign
,
9763 EXP
.concatenateDcharAssign
: PREC
.assign
,
9764 EXP
.mulAssign
: PREC
.assign
,
9765 EXP
.divAssign
: PREC
.assign
,
9766 EXP
.modAssign
: PREC
.assign
,
9767 EXP
.powAssign
: PREC
.assign
,
9768 EXP
.leftShiftAssign
: PREC
.assign
,
9769 EXP
.rightShiftAssign
: PREC
.assign
,
9770 EXP
.unsignedRightShiftAssign
: PREC
.assign
,
9771 EXP
.andAssign
: PREC
.assign
,
9772 EXP
.orAssign
: PREC
.assign
,
9773 EXP
.xorAssign
: PREC
.assign
,
9775 EXP
.comma
: PREC
.expr
,
9776 EXP
.declaration
: PREC
.expr
,
9778 EXP
.interval
: PREC
.assign
,
9781 enum ParseStatementFlags
: int
9783 scope_
= 2, // start a new scope
9784 curly
= 4, // { } statement is required
9785 curlyScope
= 8, // { } starts a new scope
9786 semiOk
= 0x10, // empty ';' are really ok
9789 struct PrefixAttributes(AST
)
9791 StorageClass storageClass
;
9792 AST
.Expression depmsg
;
9794 AST
.Visibility visibility
;
9796 AST
.Expression ealign
;
9797 AST
.Expressions
* udas
;
9798 const(char)* comment
;
9801 /// The result of the `ParseLinkage` function
9802 struct ParsedLinkage(AST
)
9804 /// What linkage was specified
9806 /// If `extern(C++, class|struct)`, contains the `class|struct`
9807 CPPMANGLE cppmangle
;
9808 /// If `extern(C++, some.identifier)`, will be the identifiers
9809 AST
.Identifiers
* idents
;
9810 /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
9811 AST
.Expressions
* identExps
;
9815 /*********************************** Private *************************************/
9817 /***********************
9818 * How multiple declarations are parsed.
9826 private enum CDECLSYNTAX
= 0;
9829 * Support C cast syntax:
9830 * (type)(expression)
9832 private enum CCASTSYNTAX
= 1;
9835 * Support postfix C array declarations, such as
9838 private enum CARRAYDECL
= 1;
9840 /*****************************
9841 * Destructively extract storage class from pAttrs.
9843 private StorageClass
getStorageClass(AST
)(PrefixAttributes
!(AST
)* pAttrs
)
9845 StorageClass
stc = STC
.undefined_
;
9848 stc = pAttrs
.storageClass
;
9849 pAttrs
.storageClass
= STC
.undefined_
;