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-2024 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
.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 using `in ref` for legacy compatibility
1231 error("attribute `scope` cannot be applied with `in`, use `-fpreview=in` instead");
1233 error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
1238 if ((added
& STC
.in_
) && (orig
& Redundant
))
1240 if (orig
& STC
.const_
)
1241 error("attribute `in` cannot be added after `const`: remove `const`");
1242 else if (compileEnv
.previewIn
)
1244 // Windows `printf` does not support `%1$s`
1245 const(char*) stc_str
= (orig
& STC
.scope_
) ?
"scope".ptr
: "ref".ptr
;
1246 error(token
.loc
, "attribute `in` cannot be added after `%s`: remove `%s`",
1249 else if (orig
& STC
.ref_
)
1251 // accept using `in ref` for legacy compatibility
1256 error("attribute `in` cannot be added after `scope`: remove `scope` and use `-fpreview=in`");
1258 error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
1263 checkConflictSTCGroup(STC
.const_ | STC
.immutable_ | STC
.manifest
);
1264 checkConflictSTCGroup(STC
.gshared | STC
.shared_
);
1265 checkConflictSTCGroup
!true(STC
.safeGroup
);
1270 /***********************************************
1271 * Parse attribute(s), lexer is on '@'.
1273 * Attributes can be builtin (e.g. `@safe`, `@nogc`, etc...),
1274 * or be user-defined (UDAs). In the former case, we return the storage
1275 * class via the return value, while in thelater case we return `0`
1279 * pudas = An array of UDAs to append to
1282 * If the attribute is builtin, the return value will be non-zero.
1283 * Otherwise, 0 is returned, and `pudas` will be appended to.
1285 private StorageClass
parseAttribute(ref AST
.Expressions
* udas
)
1288 if (token
.value
== TOK
.identifier
)
1290 // If we find a builtin attribute, we're done, return immediately.
1291 if (StorageClass
stc = isBuiltinAtAttribute(token
.ident
))
1294 // Allow identifier, template instantiation, or function call
1295 // for `@Argument` (single UDA) form.
1296 AST
.Expression exp
= parsePrimaryExp();
1297 if (token
.value
== TOK
.leftParenthesis
)
1299 const loc
= token
.loc
;
1300 AST
.Expressions
* args
= new AST
.Expressions();
1301 AST
.Identifiers
* names
= new AST
.Identifiers();
1302 parseNamedArguments(args
, names
);
1303 exp
= new AST
.CallExp(loc
, exp
, args
, names
);
1307 udas
= new AST
.Expressions();
1312 AST
.Expression
templateArgToExp(RootObject o
, const ref Loc loc
)
1316 case DYNCAST
.expression
:
1317 return cast(AST
.Expression
) o
;
1319 return new AST
.TypeExp(loc
, cast(AST
.Type
)o
);
1325 if (token
.value
== TOK
.leftParenthesis
)
1327 // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
1328 if (peekNext() == TOK
.rightParenthesis
)
1329 error("empty attribute list is not allowed");
1332 udas
= new AST
.Expressions();
1333 auto args
= parseTemplateArgumentList();
1334 foreach (arg
; *args
)
1335 udas
.push(templateArgToExp(arg
, token
.loc
));
1339 if (auto o
= parseTemplateSingleArgument())
1342 udas
= new AST
.Expressions();
1343 udas
.push(templateArgToExp(o
, token
.loc
));
1347 if (token
.isKeyword())
1348 error("`%s` is a keyword, not an `@` attribute", token
.toChars());
1350 error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token
.toChars());
1355 /***********************************************
1356 * Parse const/immutable/shared/inout/nothrow/pure postfix
1358 private StorageClass
parsePostfix(StorageClass storageClass
, AST
.Expressions
** pudas
)
1363 switch (token
.value
)
1369 case TOK
.immutable_
:
1370 stc = STC
.immutable_
;
1391 if (peekNext() == TOK
.scope_
)
1392 stc |
= STC
.returnScope
; // recognize `return scope`
1401 AST
.Expressions
* udas
= null;
1402 stc = parseAttribute(udas
);
1406 *pudas
= AST
.UserAttributeDeclaration
.concat(*pudas
, udas
);
1410 // void function() @uda fp;
1411 // () @uda { return 1; }
1412 error("user-defined attributes cannot appear as postfixes");
1420 if (skipAttributes(&token
, &tk
) && tk
.ptr
!= token
.ptr ||
1421 token
.value
== TOK
.static_ || token
.value
== TOK
.extern_
)
1423 error("`%s` token is not allowed in postfix position",
1424 Token
.toChars(token
.value
));
1428 return storageClass
;
1430 storageClass
= appendStorageClass(storageClass
, stc);
1435 private StorageClass
parseTypeCtor()
1437 StorageClass storageClass
= STC
.undefined_
;
1441 if (peekNext() == TOK
.leftParenthesis
)
1442 return storageClass
;
1445 switch (token
.value
)
1451 case TOK
.immutable_
:
1452 stc = STC
.immutable_
;
1464 return storageClass
;
1466 storageClass
= appendStorageClass(storageClass
, stc);
1471 /**************************************
1473 * Constraint is of the form:
1474 * if ( ConstraintExpression )
1476 private AST
.Expression
parseConstraint()
1478 AST
.Expression e
= null;
1479 if (token
.value
== TOK
.if_
)
1481 nextToken(); // skip over 'if'
1482 check(TOK
.leftParenthesis
);
1483 e
= parseExpression();
1484 check(TOK
.rightParenthesis
);
1489 /**************************************
1490 * Parse a TemplateDeclaration.
1492 private AST
.TemplateDeclaration
parseTemplateDeclaration(bool ismixin
= false)
1494 AST
.TemplateDeclaration tempdecl
;
1496 AST
.TemplateParameters
* tpl
;
1497 AST
.Dsymbols
* decldefs
;
1498 AST
.Expression constraint
= null;
1499 const loc
= token
.loc
;
1502 if (token
.value
!= TOK
.identifier
)
1504 error("identifier expected following `template`");
1509 tpl
= parseTemplateParameterList();
1513 constraint
= parseConstraint();
1515 if (token
.value
!= TOK
.leftCurly
)
1517 error("`{` expected after template parameter list, not `%s`", token
.toChars()); /* } */
1520 decldefs
= parseBlock(null);
1522 tempdecl
= new AST
.TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
, ismixin
);
1529 /******************************************
1530 * Parse template parameter list.
1532 * flag 0: parsing "( list )"
1533 * 1: parsing non-empty "list $(RPAREN)"
1535 private AST
.TemplateParameters
* parseTemplateParameterList(int flag
= 0)
1537 auto tpl
= new AST
.TemplateParameters();
1539 if (!flag
&& token
.value
!= TOK
.leftParenthesis
)
1541 error("parenthesized template parameter list expected following template identifier");
1546 // Get array of TemplateParameters
1547 if (flag || token
.value
!= TOK
.rightParenthesis
)
1549 while (token
.value
!= TOK
.rightParenthesis
)
1551 AST
.TemplateParameter tp
;
1553 Identifier tp_ident
= null;
1554 AST
.Type tp_spectype
= null;
1555 AST
.Type tp_valtype
= null;
1556 AST
.Type tp_defaulttype
= null;
1557 AST
.Expression tp_specvalue
= null;
1558 AST
.Expression tp_defaultvalue
= null;
1560 // Get TemplateParameter
1562 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1563 const tv
= peekNext();
1564 if (token
.value
== TOK
.alias_
)
1568 loc
= token
.loc
; // todo
1569 AST
.Type spectype
= null;
1570 if (isDeclaration(&token
, NeedDeclaratorId
.must
, TOK
.reserved
, null))
1572 spectype
= parseType(&tp_ident
);
1576 if (token
.value
!= TOK
.identifier
)
1578 error("identifier expected for template `alias` parameter");
1581 tp_ident
= token
.ident
;
1584 RootObject spec
= null;
1585 if (token
.value
== TOK
.colon
) // : Type
1588 if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.reserved
, null))
1591 spec
= parseCondExp();
1593 RootObject def
= null;
1594 if (token
.value
== TOK
.assign
) // = Type
1597 if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.reserved
, null))
1600 def
= parseCondExp();
1602 tp
= new AST
.TemplateAliasParameter(loc
, tp_ident
, spectype
, spec
, def
);
1604 else if (tv
== TOK
.colon || tv
== TOK
.assign || tv
== TOK
.comma || tv
== TOK
.rightParenthesis
)
1607 if (token
.value
!= TOK
.identifier
)
1609 error("identifier expected for template type parameter");
1613 tp_ident
= token
.ident
;
1615 if (token
.value
== TOK
.colon
) // : Type
1618 tp_spectype
= parseType();
1620 if (token
.value
== TOK
.assign
) // = Type
1623 tp_defaulttype
= parseType();
1625 tp
= new AST
.TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1627 else if (token
.value
== TOK
.identifier
&& tv
== TOK
.dotDotDot
)
1631 tp_ident
= token
.ident
;
1634 tp
= new AST
.TemplateTupleParameter(loc
, tp_ident
);
1636 else if (token
.value
== TOK
.this_
)
1640 if (token
.value
!= TOK
.identifier
)
1642 error("identifier expected for template `this` parameter");
1646 tp_ident
= token
.ident
;
1648 if (token
.value
== TOK
.colon
) // : Type
1651 tp_spectype
= parseType();
1653 if (token
.value
== TOK
.assign
) // = Type
1656 tp_defaulttype
= parseType();
1658 tp
= new AST
.TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1663 loc
= token
.loc
; // todo
1664 tp_valtype
= parseType(&tp_ident
);
1667 error("identifier expected for template value parameter");
1668 tp_ident
= Identifier
.idPool("error");
1670 if (token
.value
== TOK
.colon
) // : CondExpression
1673 tp_specvalue
= parseCondExp();
1675 if (token
.value
== TOK
.assign
) // = CondExpression
1678 tp_defaultvalue
= parseAssignExp();
1680 tp
= new AST
.TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1683 if (token
.value
!= TOK
.comma
)
1688 check(TOK
.rightParenthesis
);
1694 /******************************************
1695 * Parse template mixin.
1698 * mixin a.b.c!(args).Foo!(args);
1699 * mixin Foo!(args) identifier;
1700 * mixin typeof(expr).identifier!(args);
1702 private AST
.Dsymbol
parseMixin()
1704 AST
.TemplateMixin tm
;
1706 AST
.Objects
* tiargs
;
1708 //printf("parseMixin()\n");
1709 const locMixin
= token
.loc
;
1710 nextToken(); // skip 'mixin'
1712 auto loc
= token
.loc
;
1713 AST
.TypeQualified tqual
= null;
1714 if (token
.value
== TOK
.dot
)
1720 if (token
.value
== TOK
.typeof_
)
1722 tqual
= parseTypeof();
1725 if (token
.value
!= TOK
.identifier
)
1727 error("identifier expected, not `%s`", token
.toChars());
1738 if (token
.value
== TOK
.not)
1740 tiargs
= parseTemplateArguments();
1743 if (tiargs
&& token
.value
== TOK
.dot
)
1745 auto tempinst
= new AST
.TemplateInstance(loc
, id
, tiargs
);
1747 tqual
= new AST
.TypeInstance(loc
, tempinst
);
1749 tqual
.addInst(tempinst
);
1755 tqual
= new AST
.TypeIdentifier(loc
, id
);
1760 if (token
.value
!= TOK
.dot
)
1764 if (token
.value
!= TOK
.identifier
)
1766 error("identifier expected following `.` instead of `%s`", token
.toChars());
1775 if (token
.value
== TOK
.identifier
)
1781 tm
= new AST
.TemplateMixin(locMixin
, id
, tqual
, tiargs
);
1782 if (token
.value
!= TOK
.semicolon
)
1783 error("`;` expected after `mixin`");
1789 /******************************************
1790 * Parse template arguments.
1792 * current token is opening '!'
1794 * current token is one after closing '$(RPAREN)'
1796 private AST
.Objects
* parseTemplateArguments()
1798 AST
.Objects
* tiargs
;
1801 if (token
.value
== TOK
.leftParenthesis
)
1803 // ident!(template_arguments)
1804 tiargs
= parseTemplateArgumentList();
1808 // ident!template_argument
1809 RootObject o
= parseTemplateSingleArgument();
1812 error("template argument expected following `!`");
1816 tiargs
= new AST
.Objects();
1820 if (token
.value
== TOK
.not)
1822 TOK tok
= peekNext();
1823 if (tok
!= TOK
.is_
&& tok
!= TOK
.in_
)
1825 error("multiple ! arguments are not allowed");
1828 if (token
.value
== TOK
.leftParenthesis
)
1829 parseTemplateArgumentList();
1831 parseTemplateSingleArgument();
1832 if (token
.value
== TOK
.not && (tok
= peekNext()) != TOK
.is_
&& tok
!= TOK
.in_
)
1839 /******************************************
1840 * Parse template argument list.
1842 * current token is opening '$(LPAREN)',
1843 * or ',' for __traits
1845 * current token is one after closing '$(RPAREN)'
1847 private AST
.Objects
* parseTemplateArgumentList()
1849 //printf("Parser::parseTemplateArgumentList()\n");
1850 auto tiargs
= new AST
.Objects();
1851 TOK endtok
= TOK
.rightParenthesis
;
1852 assert(token
.value
== TOK
.leftParenthesis || token
.value
== TOK
.comma
);
1855 // Get TemplateArgumentList
1856 while (token
.value
!= endtok
)
1858 tiargs
.push(parseTypeOrAssignExp());
1859 if (token
.value
!= TOK
.comma
)
1863 check(endtok
, "template argument list");
1867 /***************************************
1868 * Parse a Type or an Expression
1870 * RootObject representing the AST
1872 RootObject
parseTypeOrAssignExp(TOK endtoken
= TOK
.reserved
)
1874 return isDeclaration(&token
, NeedDeclaratorId
.no
, endtoken
, null)
1875 ?
parseType() // argument is a type
1876 : parseAssignExp(); // argument is an expression
1879 /*****************************
1880 * Parse single template argument, to support the syntax:
1883 * current token is the arg
1884 * Returns: An AST.Type, AST.Expression, or `null` on error
1886 private RootObject
parseTemplateSingleArgument()
1888 //printf("parseTemplateSingleArgument()\n");
1890 switch (token
.value
)
1892 case TOK
.identifier
:
1893 ta
= new AST
.TypeIdentifier(token
.loc
, token
.ident
);
1901 ta
= AST
.Type
.tvoid
;
1905 ta
= AST
.Type
.tint8
;
1909 ta
= AST
.Type
.tuns8
;
1913 ta
= AST
.Type
.tint16
;
1917 ta
= AST
.Type
.tuns16
;
1921 ta
= AST
.Type
.tint32
;
1925 ta
= AST
.Type
.tuns32
;
1929 ta
= AST
.Type
.tint64
;
1933 ta
= AST
.Type
.tuns64
;
1937 ta
= AST
.Type
.tint128
;
1941 ta
= AST
.Type
.tuns128
;
1945 ta
= AST
.Type
.tfloat32
;
1949 ta
= AST
.Type
.tfloat64
;
1953 ta
= AST
.Type
.tfloat80
;
1956 case TOK
.imaginary32
:
1957 ta
= AST
.Type
.timaginary32
;
1960 case TOK
.imaginary64
:
1961 ta
= AST
.Type
.timaginary64
;
1964 case TOK
.imaginary80
:
1965 ta
= AST
.Type
.timaginary80
;
1969 ta
= AST
.Type
.tcomplex32
;
1973 ta
= AST
.Type
.tcomplex64
;
1977 ta
= AST
.Type
.tcomplex80
;
1981 ta
= AST
.Type
.tbool
;
1985 ta
= AST
.Type
.tchar
;
1989 ta
= AST
.Type
.twchar
;
1993 ta
= AST
.Type
.tdchar
;
1999 case TOK
.int32Literal
:
2000 case TOK
.uns32Literal
:
2001 case TOK
.int64Literal
:
2002 case TOK
.uns64Literal
:
2003 case TOK
.int128Literal
:
2004 case TOK
.uns128Literal
:
2005 case TOK
.float32Literal
:
2006 case TOK
.float64Literal
:
2007 case TOK
.float80Literal
:
2008 case TOK
.imaginary32Literal
:
2009 case TOK
.imaginary64Literal
:
2010 case TOK
.imaginary80Literal
:
2014 case TOK
.charLiteral
:
2015 case TOK
.wcharLiteral
:
2016 case TOK
.dcharLiteral
:
2018 case TOK
.interpolated
:
2019 case TOK
.hexadecimalString
:
2021 case TOK
.fileFullPath
:
2023 case TOK
.moduleString
:
2024 case TOK
.functionString
:
2025 case TOK
.prettyFunction
:
2028 // Template argument is an expression
2029 return parsePrimaryExp();
2036 /**********************************
2037 * Parse a static assertion.
2038 * Current token is 'static'.
2040 private AST
.StaticAssert
parseStaticAssert()
2042 const loc
= token
.loc
;
2044 AST
.Expressions
* msg
= null;
2046 //printf("parseStaticAssert()\n");
2049 check(TOK
.leftParenthesis
);
2050 exp
= parseAssignExp();
2051 if (token
.value
== TOK
.comma
)
2053 if (peekNext() == TOK
.rightParenthesis
)
2055 nextToken(); // consume `,`
2056 nextToken(); // consume `)`
2059 msg
= parseArguments();
2062 check(TOK
.rightParenthesis
);
2063 check(TOK
.semicolon
, "static assert");
2064 return new AST
.StaticAssert(loc
, exp
, msg
);
2067 /***********************************
2068 * Parse typeof(expression).
2069 * Current token is on the 'typeof'.
2071 private AST
.TypeQualified
parseTypeof()
2073 AST
.TypeQualified t
;
2074 const loc
= token
.loc
;
2077 check(TOK
.leftParenthesis
);
2078 if (token
.value
== TOK
.return_
) // typeof(return)
2081 t
= new AST
.TypeReturn(loc
);
2085 AST
.Expression exp
= parseExpression(); // typeof(expression)
2086 t
= new AST
.TypeTypeof(loc
, exp
);
2088 check(TOK
.rightParenthesis
);
2092 /***********************************
2093 * Parse __vector(type).
2094 * Current token is on the '__vector'.
2096 private AST
.Type
parseVector()
2099 check(TOK
.leftParenthesis
);
2100 AST
.Type tb
= parseType();
2101 check(TOK
.rightParenthesis
);
2102 return new AST
.TypeVector(tb
);
2105 /***********************************
2108 * extern (C++, namespaces)
2109 * extern (C++, "namespace", "namespaces", ...)
2110 * extern (C++, (StringExp))
2111 * The parser is on the 'extern' token.
2113 private ParsedLinkage
!(AST
) parseLinkage()
2115 ParsedLinkage
!(AST
) result
;
2117 assert(token
.value
== TOK
.leftParenthesis
);
2119 ParsedLinkage
!(AST
) returnLinkage(LINK link
)
2121 check(TOK
.rightParenthesis
);
2125 ParsedLinkage
!(AST
) invalidLinkage()
2127 error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Windows`, `System`");
2128 return returnLinkage(LINK
.d
);
2131 if (token
.value
!= TOK
.identifier
)
2132 return returnLinkage(LINK
.d
);
2134 Identifier id
= token
.ident
;
2136 if (id
== Id
.Windows
)
2137 return returnLinkage(LINK
.windows
);
2138 else if (id
== Id
.D
)
2139 return returnLinkage(LINK
.d
);
2140 else if (id
== Id
.System
)
2141 return returnLinkage(LINK
.system
);
2142 else if (id
== Id
.Objective
) // Looking for tokens "Objective-C"
2144 if (token
.value
!= TOK
.min
)
2145 return invalidLinkage();
2148 if (token
.ident
!= Id
.C
)
2149 return invalidLinkage();
2152 return returnLinkage(LINK
.objc
);
2154 else if (id
!= Id
.C
)
2155 return invalidLinkage();
2157 if (token
.value
!= TOK
.plusPlus
)
2158 return returnLinkage(LINK
.c
);
2161 if (token
.value
!= TOK
.comma
) // , namespaces or class or struct
2162 return returnLinkage(LINK
.cpp
);
2166 if (token
.value
== TOK
.rightParenthesis
)
2167 return returnLinkage(LINK
.cpp
); // extern(C++,)
2169 if (token
.value
== TOK
.class_ || token
.value
== TOK
.struct_
)
2171 result
.cppmangle
= token
.value
== TOK
.class_ ? CPPMANGLE
.asClass
: CPPMANGLE
.asStruct
;
2174 else if (token
.value
== TOK
.identifier
) // named scope namespace
2176 result
.idents
= new AST
.Identifiers();
2179 Identifier idn
= token
.ident
;
2180 result
.idents
.push(idn
);
2182 if (token
.value
== TOK
.dot
)
2185 if (token
.value
== TOK
.identifier
)
2187 error("identifier expected for C++ namespace");
2188 result
.idents
= null; // error occurred, invalidate list of elements.
2193 else // non-scoped StringExp namespace
2195 result
.identExps
= new AST
.Expressions();
2198 result
.identExps
.push(parseCondExp());
2199 if (token
.value
!= TOK
.comma
)
2202 // Allow trailing commas as done for argument lists, arrays, ...
2203 if (token
.value
== TOK
.rightParenthesis
)
2207 return returnLinkage(LINK
.cpp
);
2210 /***********************************
2211 * Parse ident1.ident2.ident3
2214 * entity = what qualified identifier is expected to resolve into.
2215 * Used only for better error message
2218 * array of identifiers with actual qualified one stored last
2220 private Identifier
[] parseQualifiedIdentifier(const(char)* entity
)
2222 Identifier
[] qualified
;
2227 if (token
.value
!= TOK
.identifier
)
2229 error(token
.loc
, "`%s` expected as dot-separated identifiers, got `%s`", entity
, token
.toChars());
2233 Identifier id
= token
.ident
;
2238 while (token
.value
== TOK
.dot
);
2243 private AST
.DebugSymbol
parseDebugSpecification()
2247 if (token
.value
== TOK
.identifier
)
2248 s
= new AST
.DebugSymbol(token
.loc
, token
.ident
);
2249 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2251 // @@@DEPRECATED_2.111@@@
2252 // Deprecated in 2.101, remove in 2.111
2253 deprecation("`debug = <integer>` is deprecated, use debug identifiers instead");
2255 s
= new AST
.DebugSymbol(token
.loc
, cast(uint)token
.unsvalue
);
2259 error("identifier or integer expected, not `%s`", token
.toChars());
2263 if (token
.value
!= TOK
.semicolon
)
2264 error("semicolon expected");
2269 /**************************************
2270 * Parse a debug conditional
2272 private AST
.Condition
parseDebugCondition()
2275 Identifier id
= null;
2276 Loc loc
= token
.loc
;
2278 if (token
.value
== TOK
.leftParenthesis
)
2282 if (token
.value
== TOK
.identifier
)
2284 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2286 // @@@DEPRECATED_2.111@@@
2287 // Deprecated in 2.101, remove in 2.111
2288 deprecation("`debug( <integer> )` is deprecated, use debug identifiers instead");
2290 level
= cast(uint)token
.unsvalue
;
2293 error("identifier or integer expected inside `debug(...)`, not `%s`", token
.toChars());
2296 check(TOK
.rightParenthesis
);
2298 return new AST
.DebugCondition(loc
, mod
, level
, id
);
2301 /**************************************
2302 * Parse a version specification
2304 private AST
.VersionSymbol
parseVersionSpecification()
2306 AST
.VersionSymbol s
;
2308 if (token
.value
== TOK
.identifier
)
2309 s
= new AST
.VersionSymbol(token
.loc
, token
.ident
);
2310 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2312 // @@@DEPRECATED_2.111@@@
2313 // Deprecated in 2.101, remove in 2.111
2314 deprecation("`version = <integer>` is deprecated, use version identifiers instead");
2315 s
= new AST
.VersionSymbol(token
.loc
, cast(uint)token
.unsvalue
);
2319 error("identifier or integer expected, not `%s`", token
.toChars());
2323 if (token
.value
!= TOK
.semicolon
)
2324 error("semicolon expected");
2329 /**************************************
2330 * Parse a version conditional
2332 private AST
.Condition
parseVersionCondition()
2335 Identifier id
= null;
2338 if (token
.value
== TOK
.leftParenthesis
)
2342 * version (unittest)
2344 * even though they are keywords
2347 if (token
.value
== TOK
.identifier
)
2349 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2351 // @@@DEPRECATED_2.111@@@
2352 // Deprecated in 2.101, remove in 2.111
2353 deprecation("`version( <integer> )` is deprecated, use version identifiers instead");
2355 level
= cast(uint)token
.unsvalue
;
2357 else if (token
.value
== TOK
.unittest_
)
2358 id
= Identifier
.idPool(Token
.toString(TOK
.unittest_
));
2359 else if (token
.value
== TOK
.assert_
)
2360 id
= Identifier
.idPool(Token
.toString(TOK
.assert_
));
2362 error("identifier or integer expected inside `version(...)`, not `%s`", token
.toChars());
2364 check(TOK
.rightParenthesis
);
2367 error("(condition) expected following `version`");
2368 return new AST
.VersionCondition(loc
, mod
, level
, id
);
2371 /***********************************************
2372 * static if (expression)
2376 * Current token is 'static'.
2378 private AST
.Condition
parseStaticIfCondition()
2381 AST
.Condition condition
;
2382 const loc
= token
.loc
;
2386 if (token
.value
== TOK
.leftParenthesis
)
2389 exp
= parseAssignExp();
2390 check(TOK
.rightParenthesis
);
2394 error("(expression) expected following `static if`");
2397 condition
= new AST
.StaticIfCondition(loc
, exp
);
2401 /*****************************************
2402 * Parse a constructor definition:
2403 * this(parameters) { body }
2405 * this(this) { body }
2406 * or constructor template:
2407 * this(templateparameters)(parameters) { body }
2408 * Current token is 'this'.
2410 private AST
.Dsymbol
parseCtor(PrefixAttributes
!AST
* pAttrs
)
2412 AST
.Expressions
* udas
= null;
2413 const loc
= token
.loc
;
2414 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2417 if (token
.value
== TOK
.leftParenthesis
&& peekNext() == TOK
.this_
&& peekNext2() == TOK
.rightParenthesis
)
2419 // this(this) { ... }
2422 check(TOK
.rightParenthesis
);
2424 stc = parsePostfix(stc, &udas
);
2425 if (stc & STC
.immutable_
)
2426 deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit.");
2427 if (stc & STC
.shared_
)
2428 deprecation("`shared` postblit is deprecated. Please use an unqualified postblit.");
2429 if (stc & STC
.const_
)
2430 deprecation("`const` postblit is deprecated. Please use an unqualified postblit.");
2431 if (stc & STC
.static_
)
2432 error(loc
, "postblit cannot be `static`");
2434 auto f
= new AST
.PostBlitDeclaration(loc
, Loc
.initial
, stc, Id
.postblit
);
2435 AST
.Dsymbol s
= parseContracts(f
);
2438 auto a
= new AST
.Dsymbols();
2440 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2445 /* Look ahead to see if:
2447 * which is a constructor template
2449 AST
.TemplateParameters
* tpl
= null;
2450 if (token
.value
== TOK
.leftParenthesis
&& peekPastParen(&token
).value
== TOK
.leftParenthesis
)
2452 tpl
= parseTemplateParameterList();
2455 /* Just a regular constructor
2457 auto parameterList
= parseParameterList(null);
2458 stc = parsePostfix(stc, &udas
);
2460 if (parameterList
.varargs
!= VarArg
.none || AST
.Parameter
.dim(parameterList
.parameters
) != 0)
2462 if (stc & STC
.static_
)
2463 error(loc
, "constructor cannot be static");
2465 else if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
)) // this()
2467 if (ss
== STC
.static_
)
2468 error(loc
, "use `static this()` to declare a static constructor");
2469 else if (ss
== (STC
.shared_ | STC
.static_
))
2470 error(loc
, "use `shared static this()` to declare a shared static constructor");
2473 AST
.Expression constraint
= tpl ?
parseConstraint() : null;
2475 AST
.Type tf
= new AST
.TypeFunction(parameterList
, null, linkage
, stc); // RetrunType -> auto
2476 tf
= tf
.addSTC(stc);
2478 auto f
= new AST
.CtorDeclaration(loc
, Loc
.initial
, stc, tf
);
2479 AST
.Dsymbol s
= parseContracts(f
, !!tpl
);
2482 auto a
= new AST
.Dsymbols();
2484 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2489 // Wrap a template around it
2490 auto decldefs
= new AST
.Dsymbols();
2492 s
= new AST
.TemplateDeclaration(loc
, f
.ident
, tpl
, constraint
, decldefs
);
2498 /*****************************************
2499 * Parse a destructor definition:
2501 * Current token is '~'.
2503 private AST
.Dsymbol
parseDtor(PrefixAttributes
!AST
* pAttrs
)
2505 AST
.Expressions
* udas
= null;
2506 const loc
= token
.loc
;
2507 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2511 check(TOK
.leftParenthesis
);
2512 check(TOK
.rightParenthesis
);
2514 stc = parsePostfix(stc, &udas
);
2515 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2517 if (ss
== STC
.static_
)
2518 error(loc
, "use `static ~this()` to declare a static destructor");
2519 else if (ss
== (STC
.shared_ | STC
.static_
))
2520 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
2523 auto f
= new AST
.DtorDeclaration(loc
, Loc
.initial
, stc, Id
.dtor
);
2524 AST
.Dsymbol s
= parseContracts(f
);
2527 auto a
= new AST
.Dsymbols();
2529 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2534 /*****************************************
2535 * Parse a static constructor definition:
2536 * static this() { body }
2537 * Current token is 'static'.
2539 private AST
.Dsymbol
parseStaticCtor(PrefixAttributes
!AST
* pAttrs
)
2541 //Expressions *udas = NULL;
2542 const loc
= token
.loc
;
2543 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2547 check(TOK
.leftParenthesis
);
2548 check(TOK
.rightParenthesis
);
2550 stc = parsePostfix(stc & ~STC
.TYPECTOR
, null) |
stc;
2551 if (stc & STC
.shared_
)
2552 error(loc
, "use `shared static this()` to declare a shared static constructor");
2553 else if (stc & STC
.static_
)
2554 appendStorageClass(stc, STC
.static_
); // complaint for the redundancy
2555 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2558 AST
.stcToBuffer(buf
, modStc
);
2559 error(loc
, "static constructor cannot be `%s`", buf
.peekChars());
2561 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2563 auto f
= new AST
.StaticCtorDeclaration(loc
, Loc
.initial
, stc);
2564 AST
.Dsymbol s
= parseContracts(f
);
2568 /*****************************************
2569 * Parse a static destructor definition:
2570 * static ~this() { body }
2571 * Current token is 'static'.
2573 private AST
.Dsymbol
parseStaticDtor(PrefixAttributes
!AST
* pAttrs
)
2575 AST
.Expressions
* udas
= null;
2576 const loc
= token
.loc
;
2577 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2582 check(TOK
.leftParenthesis
);
2583 check(TOK
.rightParenthesis
);
2585 stc = parsePostfix(stc & ~STC
.TYPECTOR
, &udas
) |
stc;
2586 if (stc & STC
.shared_
)
2587 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
2588 else if (stc & STC
.static_
)
2589 appendStorageClass(stc, STC
.static_
); // complaint for the redundancy
2590 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2593 AST
.stcToBuffer(buf
, modStc
);
2594 error(loc
, "static destructor cannot be `%s`", buf
.peekChars());
2596 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2598 auto f
= new AST
.StaticDtorDeclaration(loc
, Loc
.initial
, stc);
2599 AST
.Dsymbol s
= parseContracts(f
);
2602 auto a
= new AST
.Dsymbols();
2604 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2609 /*****************************************
2610 * Parse a shared static constructor definition:
2611 * shared static this() { body }
2612 * Current token is 'shared'.
2614 private AST
.Dsymbol
parseSharedStaticCtor(PrefixAttributes
!AST
* pAttrs
)
2616 //Expressions *udas = NULL;
2617 const loc
= token
.loc
;
2618 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2623 check(TOK
.leftParenthesis
);
2624 check(TOK
.rightParenthesis
);
2626 stc = parsePostfix(stc & ~STC
.TYPECTOR
, null) |
stc;
2627 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2628 appendStorageClass(stc, ss
); // complaint for the redundancy
2629 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2632 AST
.stcToBuffer(buf
, modStc
);
2633 error(loc
, "shared static constructor cannot be `%s`", buf
.peekChars());
2635 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2637 auto f
= new AST
.SharedStaticCtorDeclaration(loc
, Loc
.initial
, stc);
2638 AST
.Dsymbol s
= parseContracts(f
);
2642 /*****************************************
2643 * Parse a shared static destructor definition:
2644 * shared static ~this() { body }
2645 * Current token is 'shared'.
2647 private AST
.Dsymbol
parseSharedStaticDtor(PrefixAttributes
!AST
* pAttrs
)
2649 AST
.Expressions
* udas
= null;
2650 const loc
= token
.loc
;
2651 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2657 check(TOK
.leftParenthesis
);
2658 check(TOK
.rightParenthesis
);
2660 stc = parsePostfix(stc & ~STC
.TYPECTOR
, &udas
) |
stc;
2661 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2662 appendStorageClass(stc, ss
); // complaint for the redundancy
2663 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2666 AST
.stcToBuffer(buf
, modStc
);
2667 error(loc
, "shared static destructor cannot be `%s`", buf
.peekChars());
2669 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2671 auto f
= new AST
.SharedStaticDtorDeclaration(loc
, Loc
.initial
, stc);
2672 AST
.Dsymbol s
= parseContracts(f
);
2675 auto a
= new AST
.Dsymbols();
2677 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2682 /*****************************************
2683 * Parse an invariant definition:
2684 * invariant { statements... }
2685 * invariant() { statements... }
2686 * invariant (expression);
2687 * Current token is 'invariant'.
2689 private AST
.Dsymbol
parseInvariant(PrefixAttributes
!AST
* pAttrs
)
2691 const loc
= token
.loc
;
2692 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2695 if (token
.value
== TOK
.leftParenthesis
) // optional () or invariant (expression);
2698 if (token
.value
!= TOK
.rightParenthesis
) // invariant (expression);
2700 AST
.Expression e
= parseAssignExp(), msg
= null;
2701 if (token
.value
== TOK
.comma
)
2704 if (token
.value
!= TOK
.rightParenthesis
)
2706 msg
= parseAssignExp();
2707 if (token
.value
== TOK
.comma
)
2711 check(TOK
.rightParenthesis
);
2712 check(TOK
.semicolon
, "invariant");
2713 e
= new AST
.AssertExp(loc
, e
, msg
);
2714 auto fbody
= new AST
.ExpStatement(loc
, e
);
2715 auto f
= new AST
.InvariantDeclaration(loc
, token
.loc
, stc, null, fbody
);
2721 auto fbody
= parseStatement(ParseStatementFlags
.curly
);
2722 auto f
= new AST
.InvariantDeclaration(loc
, token
.loc
, stc, null, fbody
);
2726 /*****************************************
2727 * Parse a unittest definition:
2729 * Current token is 'unittest'.
2731 private AST
.Dsymbol
parseUnitTest(PrefixAttributes
!AST
* pAttrs
)
2733 const loc
= token
.loc
;
2734 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2738 const(char)* begPtr
= token
.ptr
+ 1; // skip left curly brace
2739 const(char)* endPtr
= null;
2740 AST
.Statement sbody
= parseStatement(ParseStatementFlags
.curly
, &endPtr
);
2742 /** Extract unittest body as a string. Must be done eagerly since memory
2743 will be released by the lexer before doc gen. */
2744 char* docline
= null;
2745 if (compileEnv
.ddocOutput
&& endPtr
> begPtr
)
2747 /* Remove trailing whitespaces */
2748 for (const(char)* p
= endPtr
- 1; begPtr
<= p
&& (*p
== ' ' ||
*p
== '\r' ||
*p
== '\n' ||
*p
== '\t'); --p
)
2753 size_t len
= endPtr
- begPtr
;
2756 docline
= cast(char*)mem
.xmalloc_noscan(len
+ 2);
2757 memcpy(docline
, begPtr
, len
);
2758 docline
[len
] = '\n'; // Terminate all lines by LF
2759 docline
[len
+ 1] = '\0';
2763 auto f
= new AST
.UnitTestDeclaration(loc
, token
.loc
, stc, docline
);
2768 /*****************************************
2769 * Parse a new definition:
2771 * Current token is 'new'.
2773 private AST
.Dsymbol
parseNew(PrefixAttributes
!AST
* pAttrs
)
2775 const loc
= token
.loc
;
2776 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2777 if (!(stc & STC
.disable
))
2779 error("`new` allocator must be annotated with `@disabled`");
2783 /* @@@DEPRECATED_2.108@@@
2784 * After deprecation period (2.108), remove all code in the version(all) block.
2788 auto parameterList
= parseParameterList(null); // parameterList ignored
2789 if (parameterList
.parameters
.length
> 0 || parameterList
.varargs
!= VarArg
.none
)
2790 deprecation("`new` allocator with non-empty parameter list is deprecated");
2791 auto f
= new AST
.NewDeclaration(loc
, stc);
2792 if (token
.value
!= TOK
.semicolon
)
2794 deprecation("`new` allocator with function definition is deprecated");
2795 parseContracts(f
); // body ignored
2806 check(TOK
.leftParenthesis
);
2807 check(TOK
.rightParenthesis
);
2808 check(TOK
.semicolon
);
2809 return new AST
.NewDeclaration(loc
, stc);
2813 /**********************************************
2814 * Parse parameter list.
2816 private AST
.ParameterList
parseParameterList(AST
.TemplateParameters
** tpl
)
2818 auto parameters
= new AST
.Parameters();
2819 VarArg varargs
= VarArg
.none
;
2820 StorageClass varargsStc
;
2822 // Attributes allowed for ...
2823 enum VarArgsStc
= STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.scope_ | STC
.return_ | STC
.returnScope
;
2825 check(TOK
.leftParenthesis
);
2828 Identifier ai
= null;
2830 StorageClass storageClass
= 0;
2833 AST
.Expressions
* udas
= null;
2834 for (; 1; nextToken())
2837 switch (token
.value
)
2839 case TOK
.rightParenthesis
:
2840 if (storageClass
!= 0 || udas
!is null)
2841 error("basic type expected, not `)`");
2845 varargs
= VarArg
.variadic
;
2846 varargsStc
= storageClass
;
2847 if (varargsStc
& ~VarArgsStc
)
2850 AST
.stcToBuffer(buf
, varargsStc
& ~VarArgsStc
);
2851 error("variadic parameter cannot have attributes `%s`", buf
.peekChars());
2852 varargsStc
&= VarArgsStc
;
2858 if (peekNext() == TOK
.leftParenthesis
)
2863 case TOK
.immutable_
:
2864 if (peekNext() == TOK
.leftParenthesis
)
2866 stc = STC
.immutable_
;
2870 if (peekNext() == TOK
.leftParenthesis
)
2876 if (peekNext() == TOK
.leftParenthesis
)
2882 AST
.Expressions
* exps
= null;
2883 StorageClass stc2
= parseAttribute(exps
);
2884 if (stc2
& atAttrGroup
)
2886 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2890 udas
= AST
.UserAttributeDeclaration
.concat(udas
, exps
);
2892 if (token
.value
== TOK
.dotDotDot
)
2893 error("variadic parameter cannot have user-defined attributes");
2897 // Don't call nextToken again.
2901 eSink
.message(scanloc
, "Usage of 'in' on parameter");
2903 if (compileEnv
.previewIn
)
2904 stc |
= STC
.constscoperef
;
2933 if (peekNext() == TOK
.scope_
)
2934 stc |
= STC
.returnScope
;
2937 storageClass
= appendStorageClass(storageClass
, stc);
2942 const stcx
= storageClass
& (STC
.in_ | STC
.ref_ | STC
.out_ | STC
.lazy_
);
2943 // if stcx is not a power of 2
2944 if (stcx
& (stcx
- 1) && !(stcx
== (STC
.in_ | STC
.ref_
)))
2945 error("incompatible parameter storage classes");
2946 //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
2947 //error("scope cannot be ref or out");
2949 const tv
= peekNext();
2951 if (tpl
&& token
.value
== TOK
.identifier
&&
2952 (tv
== TOK
.comma || tv
== TOK
.rightParenthesis || tv
== TOK
.dotDotDot
))
2954 Identifier id
= Identifier
.generateId("__T");
2956 at
= new AST
.TypeIdentifier(loc
, id
);
2958 *tpl
= new AST
.TemplateParameters();
2959 AST
.TemplateParameter tp
= new AST
.TemplateTypeParameter(loc
, id
, null, null);
2967 at
= parseType(&ai
, null, &loc
);
2970 if (token
.value
== TOK
.assign
) // = defaultArg
2973 ae
= parseAssignExp();
2975 auto param
= new AST
.Parameter(loc
, storageClass | STC
.parameter
, at
, ai
, ae
, null);
2978 auto a
= new AST
.Dsymbols();
2979 auto udad
= new AST
.UserAttributeDeclaration(udas
, a
);
2980 param
.userAttribDecl
= udad
;
2982 if (token
.value
== TOK
.at
)
2984 AST
.Expressions
* exps
= null;
2985 StorageClass stc2
= parseAttribute(exps
);
2986 if (stc2
& atAttrGroup
)
2988 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2992 error("user-defined attributes cannot appear as postfixes", token
.toChars());
2997 if (token
.value
== TOK
.dotDotDot
)
3002 if (storageClass
& (STC
.out_ | STC
.ref_
))
3003 error("variadic argument cannot be `out` or `ref`");
3004 varargs
= VarArg
.typesafe
;
3005 parameters
.push(param
);
3009 parameters
.push(param
);
3010 if (token
.value
== TOK
.comma
)
3024 check(TOK
.rightParenthesis
);
3025 return AST
.ParameterList(parameters
, varargs
, varargsStc
);
3028 /*************************************
3030 private AST
.EnumDeclaration
parseEnum()
3032 AST
.EnumDeclaration e
;
3035 auto loc
= token
.loc
;
3037 // printf("Parser::parseEnum()\n");
3040 if (token
.value
== TOK
.identifier
)
3047 if (token
.value
== TOK
.colon
)
3051 const typeLoc
= token
.loc
;
3052 memtype
= parseBasicType();
3053 memtype
= parseDeclarator(memtype
, alt
, null);
3054 checkCstyleTypeSyntax(typeLoc
, memtype
, alt
, null);
3057 e
= new AST
.EnumDeclaration(loc
, id
, memtype
);
3059 if (token
.value
== TOK
.semicolon
&& id
)
3061 else if (token
.value
== TOK
.leftCurly
)
3063 bool isAnonymousEnum
= !id
;
3065 //printf("enum definition\n");
3066 e
.members
= new AST
.Dsymbols();
3068 const(char)[] comment
= token
.blockComment
;
3069 while (token
.value
!= TOK
.rightCurly
)
3071 /* Can take the following forms...
3074 * 3. type ident = value
3075 * ... prefixed by valid attributes
3079 AST
.Type type
= null;
3080 Identifier ident
= null;
3082 AST
.Expressions
* udas
;
3084 AST
.Expression deprecationMessage
;
3085 enum attributeErrorMessage
= "`%s` is not a valid attribute for enum members";
3089 switch (token
.value
)
3092 if (StorageClass _stc
= parseAttribute(udas
))
3094 if (_stc
== STC
.disable
)
3099 AST
.stcToBuffer(buf
, _stc
);
3100 error(attributeErrorMessage
, buf
.peekChars());
3105 case TOK
.deprecated_
:
3106 stc |
= STC
.deprecated_
;
3107 if (!parseDeprecatedAttribute(deprecationMessage
))
3116 if (token
.value
== TOK
.identifier
)
3118 const tv
= peekNext();
3119 if (tv
== TOK
.assign || tv
== TOK
.comma || tv
== TOK
.rightCurly
)
3121 ident
= token
.ident
;
3127 if (isAnonymousEnum
)
3131 error("expected `,` or `=` after identifier, not `%s`", token
.toChars());
3136 if (isAnonymousEnum
)
3140 type
= parseType(&ident
, null);
3141 if (type
== AST
.Type
.terror
)
3148 error("no identifier for declarator `%s`", type
.toChars());
3153 const tv
= token
.value
;
3154 if (tv
!= TOK
.assign
&& tv
!= TOK
.comma
&& tv
!= TOK
.rightCurly
)
3156 error("expected `,` or `=` after identifier, not `%s`", token
.toChars());
3164 if (isBasicType(&t
))
3166 error("named enum cannot declare member with type", (*t
).toChars());
3170 check(TOK
.identifier
);
3172 // avoid extra error messages
3173 const tv
= token
.value
;
3174 if (tv
!= TOK
.assign
&& tv
!= TOK
.comma
&& tv
!= TOK
.rightCurly
&& tv
!= TOK
.endOfFile
)
3179 AST
.Expression value
;
3180 if (token
.value
== TOK
.assign
)
3183 value
= parseAssignExp();
3188 if (type
&& isAnonymousEnum
)
3189 error("initializer required after `%s` when type is specified", ident
.toChars());
3192 AST
.DeprecatedDeclaration
dd;
3193 if (deprecationMessage
)
3195 dd = new AST
.DeprecatedDeclaration(deprecationMessage
, null);
3196 stc |
= STC
.deprecated_
;
3199 auto em
= new AST
.EnumMember(loc
, ident
, value
, type
, stc, null, dd);
3204 auto uad
= new AST
.UserAttributeDeclaration(udas
, new AST
.Dsymbols());
3205 em
.userAttribDecl
= uad
;
3208 if (token
.value
!= TOK
.rightCurly
)
3210 addComment(em
, comment
);
3214 addComment(em
, comment
);
3215 comment
= token
.blockComment
;
3217 if (token
.value
== TOK
.endOfFile
)
3219 error("premature end of file");
3228 error("expected `{`, not `%s` for enum declaration", token
.toChars());
3230 //printf("-parseEnum() %s\n", e.toChars());
3234 /********************************
3235 * Parse struct, union, interface, class.
3237 private AST
.Dsymbol
parseAggregate()
3239 AST
.TemplateParameters
* tpl
= null;
3240 AST
.Expression constraint
;
3241 const loc
= token
.loc
;
3242 TOK tok
= token
.value
;
3244 //printf("Parser::parseAggregate()\n");
3247 if (token
.value
!= TOK
.identifier
)
3256 if (token
.value
== TOK
.leftParenthesis
)
3258 // struct/class template declaration.
3259 tpl
= parseTemplateParameterList();
3260 constraint
= parseConstraint();
3264 // Collect base class(es)
3265 AST
.BaseClasses
* baseclasses
= null;
3266 if (token
.value
== TOK
.colon
)
3268 if (tok
!= TOK
.interface_
&& tok
!= TOK
.class_
)
3269 error("base classes are not allowed for `%s`, did you mean `;`?", Token
.toChars(tok
));
3271 baseclasses
= parseBaseClasses();
3274 if (token
.value
== TOK
.if_
)
3277 error("template constraints appear both before and after BaseClassList, put them before");
3278 constraint
= parseConstraint();
3283 error("template constraints not allowed for anonymous `%s`", Token
.toChars(tok
));
3285 error("template constraints only allowed for templates");
3288 AST
.Dsymbols
* members
= null;
3289 if (token
.value
== TOK
.leftCurly
)
3291 //printf("aggregate definition\n");
3292 const lookingForElseSave
= lookingForElse
;
3293 lookingForElse
= Loc();
3295 members
= parseDeclDefs(0);
3296 lookingForElse
= lookingForElseSave
;
3297 if (token
.value
!= TOK
.rightCurly
)
3300 error(token
.loc
, "`}` expected following members in `%s` declaration",
3301 Token
.toChars(tok
));
3303 eSink
.errorSupplemental(loc
, "%s `%s` starts here",
3304 Token
.toChars(tok
), id
.toChars());
3306 eSink
.errorSupplemental(loc
, "%s starts here",
3307 Token
.toChars(tok
));
3311 else if (token
.value
== TOK
.semicolon
&& id
)
3313 if (baseclasses || constraint
)
3314 error("members expected");
3319 error(token
.loc
, "{ } expected following `%s` declaration", Token
.toChars(tok
));
3322 AST
.AggregateDeclaration a
;
3325 case TOK
.interface_
:
3327 error(loc
, "anonymous interfaces not allowed");
3328 a
= new AST
.InterfaceDeclaration(loc
, id
, baseclasses
);
3329 a
.members
= members
;
3334 error(loc
, "anonymous classes not allowed");
3335 bool inObject
= md
&& !md
.packages
&& md
.id
== Id
.object
;
3336 a
= new AST
.ClassDeclaration(loc
, id
, baseclasses
, members
, inObject
);
3342 bool inObject
= md
&& !md
.packages
&& md
.id
== Id
.object
;
3343 a
= new AST
.StructDeclaration(loc
, id
, inObject
);
3344 a
.members
= members
;
3348 /* Anonymous structs/unions are more like attributes.
3351 return new AST
.AnonDeclaration(loc
, false, members
);
3358 a
= new AST
.UnionDeclaration(loc
, id
);
3359 a
.members
= members
;
3363 /* Anonymous structs/unions are more like attributes.
3366 return new AST
.AnonDeclaration(loc
, true, members
);
3376 // Wrap a template around the aggregate declaration
3377 auto decldefs
= new AST
.Dsymbols();
3379 auto tempdecl
= new AST
.TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
);
3385 /*******************************************
3387 private AST
.BaseClasses
* parseBaseClasses()
3389 auto baseclasses
= new AST
.BaseClasses();
3391 for (; 1; nextToken())
3393 auto b
= new AST
.BaseClass(parseBasicType());
3394 baseclasses
.push(b
);
3395 if (token
.value
!= TOK
.comma
)
3401 AST
.Dsymbols
* parseImport()
3403 auto decldefs
= new AST
.Dsymbols();
3404 Identifier aliasid
= null;
3406 int isstatic
= token
.value
== TOK
.static_
;
3410 //printf("Parser::parseImport()\n");
3415 if (token
.value
!= TOK
.identifier
)
3417 error("identifier expected following `import`");
3421 const loc
= token
.loc
;
3422 Identifier id
= token
.ident
;
3425 if (!aliasid
&& token
.value
== TOK
.assign
)
3430 while (token
.value
== TOK
.dot
)
3434 if (token
.value
!= TOK
.identifier
)
3436 error("identifier expected following `package`");
3443 auto s
= new AST
.Import(loc
, a
, id
, aliasid
, isstatic
);
3447 * : alias=name, alias=name;
3450 if (token
.value
== TOK
.colon
)
3455 if (token
.value
!= TOK
.identifier
)
3457 error("identifier expected following `:`");
3460 Identifier _alias
= token
.ident
;
3463 if (token
.value
== TOK
.assign
)
3466 if (token
.value
!= TOK
.identifier
)
3468 error("identifier expected following `%s=`", _alias
.toChars());
3479 s
.addAlias(name
, _alias
);
3481 while (token
.value
== TOK
.comma
);
3482 break; // no comma-separated imports of this form
3486 while (token
.value
== TOK
.comma
);
3488 if (token
.value
== TOK
.semicolon
)
3492 error("`;` expected");
3499 /* Parse a type and optional identifier
3501 * pident = set to Identifier if there is one, null if not
3502 * ptpl = if !null, then set to TemplateParameterList
3503 * pdeclLoc = if !null, then set to location of the declarator
3505 AST
.Type
parseType(Identifier
* pident
= null, AST
.TemplateParameters
** ptpl
= null, Loc
* pdeclLoc
= null)
3507 /* Take care of the storage class prefixes that
3508 * serve as type attributes:
3516 * shared inout const type
3518 StorageClass
stc = 0;
3521 switch (token
.value
)
3524 if (peekNext() == TOK
.leftParenthesis
)
3525 break; // const as type constructor
3526 stc |
= STC
.const_
; // const as storage class
3530 case TOK
.immutable_
:
3531 if (peekNext() == TOK
.leftParenthesis
)
3533 stc |
= STC
.immutable_
;
3538 if (peekNext() == TOK
.leftParenthesis
)
3545 if (peekNext() == TOK
.leftParenthesis
)
3557 const typeLoc
= token
.loc
;
3560 t
= parseBasicType();
3563 *pdeclLoc
= token
.loc
;
3565 t
= parseDeclarator(t
, alt
, pident
, ptpl
);
3566 checkCstyleTypeSyntax(typeLoc
, t
, alt
, pident ?
*pident
: null);
3572 private AST
.Type
parseBasicType(bool dontLookDotIdents
= false)
3577 //printf("parseBasicType()\n");
3578 switch (token
.value
)
3593 t
= AST
.Type
.tint16
;
3597 t
= AST
.Type
.tuns16
;
3601 t
= AST
.Type
.tint32
;
3605 t
= AST
.Type
.tuns32
;
3609 t
= AST
.Type
.tint64
;
3611 if (token
.value
== TOK
.int64
) // if `long long`
3613 error("use `long` for a 64 bit integer instead of `long long`");
3616 else if (token
.value
== TOK
.float64
) // if `long double`
3618 error("use `real` instead of `long double`");
3619 t
= AST
.Type
.tfloat80
;
3625 t
= AST
.Type
.tuns64
;
3629 t
= AST
.Type
.tint128
;
3633 t
= AST
.Type
.tuns128
;
3637 t
= AST
.Type
.tfloat32
;
3641 t
= AST
.Type
.tfloat64
;
3645 t
= AST
.Type
.tfloat80
;
3648 case TOK
.imaginary32
:
3649 t
= AST
.Type
.timaginary32
;
3652 case TOK
.imaginary64
:
3653 t
= AST
.Type
.timaginary64
;
3656 case TOK
.imaginary80
:
3657 t
= AST
.Type
.timaginary80
;
3661 t
= AST
.Type
.tcomplex32
;
3665 t
= AST
.Type
.tcomplex64
;
3669 t
= AST
.Type
.tcomplex80
;
3681 t
= AST
.Type
.twchar
;
3685 t
= AST
.Type
.tdchar
;
3693 case TOK
.identifier
:
3697 if (token
.value
== TOK
.not)
3699 // ident!(template_arguments)
3700 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
3701 t
= parseBasicTypeStartingAt(new AST
.TypeInstance(loc
, tempinst
), dontLookDotIdents
);
3705 t
= parseBasicTypeStartingAt(new AST
.TypeIdentifier(loc
, id
), dontLookDotIdents
);
3710 // https://dlang.org/spec/expression.html#mixin_types
3713 if (token
.value
!= TOK
.leftParenthesis
)
3714 error(token
.loc
, "found `%s` when expecting `%s` following `mixin`", token
.toChars(), Token
.toChars(TOK
.leftParenthesis
));
3715 auto exps
= parseArguments();
3716 t
= new AST
.TypeMixin(loc
, exps
);
3720 // Leading . as in .foo
3721 t
= parseBasicTypeStartingAt(new AST
.TypeIdentifier(token
.loc
, Id
.empty
), dontLookDotIdents
);
3725 // typeof(expression)
3726 t
= parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents
);
3734 if (AST
.TraitsExp te
= cast(AST
.TraitsExp
) parsePrimaryExp())
3737 t
= new AST
.TypeTraits(token
.loc
, te
);
3740 t
= new AST
.TypeError
;
3746 check(TOK
.leftParenthesis
);
3747 t
= parseType().addSTC(STC
.const_
);
3748 check(TOK
.rightParenthesis
);
3751 case TOK
.immutable_
:
3754 check(TOK
.leftParenthesis
);
3755 t
= parseType().addSTC(STC
.immutable_
);
3756 check(TOK
.rightParenthesis
);
3762 check(TOK
.leftParenthesis
);
3763 t
= parseType().addSTC(STC
.shared_
);
3764 check(TOK
.rightParenthesis
);
3770 check(TOK
.leftParenthesis
);
3771 t
= parseType().addSTC(STC
.wild
);
3772 check(TOK
.rightParenthesis
);
3776 error("basic type expected, not `%s`", token
.toChars());
3777 if (token
.value
== TOK
.else_
)
3778 eSink
.errorSupplemental(token
.loc
, "There's no `static else`, use `else` instead.");
3779 t
= AST
.Type
.terror
;
3785 private AST
.Type
parseBasicTypeStartingAt(AST
.TypeQualified tid
, bool dontLookDotIdents
)
3787 AST
.Type maybeArray
= null;
3788 // See https://issues.dlang.org/show_bug.cgi?id=1215
3789 // A basic type can look like MyType (typical case), but also:
3790 // MyType.T -> A type
3791 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3792 // MyType[expr].T -> A type.
3793 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3794 // (iif MyType[expr].T is a Ttuple)
3797 switch (token
.value
)
3802 if (token
.value
!= TOK
.identifier
)
3804 error("identifier expected following `.` instead of `%s`", token
.toChars());
3809 // This is actually a TypeTuple index, not an {a/s}array.
3810 // We need to have a while loop to unwind all index taking:
3811 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3812 AST
.Objects dimStack
;
3813 AST
.Type t
= maybeArray
;
3816 if (t
.ty
== Tsarray
)
3818 // The index expression is an Expression.
3819 AST
.TypeSArray a
= cast(AST
.TypeSArray
)t
;
3820 dimStack
.push(a
.dim
.syntaxCopy());
3821 t
= a
.next
.syntaxCopy();
3823 else if (t
.ty
== Taarray
)
3825 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3826 AST
.TypeAArray a
= cast(AST
.TypeAArray
)t
;
3827 dimStack
.push(a
.index
.syntaxCopy());
3828 t
= a
.next
.syntaxCopy();
3835 assert(dimStack
.length
> 0);
3836 // We're good. Replay indices in the reverse order.
3837 tid
= cast(AST
.TypeQualified
)t
;
3838 while (dimStack
.length
)
3840 tid
.addIndex(dimStack
.pop());
3844 const loc
= token
.loc
;
3845 Identifier id
= token
.ident
;
3847 if (token
.value
== TOK
.not)
3849 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
3850 tid
.addInst(tempinst
);
3856 case TOK
.leftBracket
:
3858 if (dontLookDotIdents
) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911
3862 AST
.Type t
= maybeArray ? maybeArray
: cast(AST
.Type
)tid
;
3863 if (token
.value
== TOK
.rightBracket
)
3865 // It's a dynamic array, and we're done:
3866 // T[].U does not make sense.
3867 t
= new AST
.TypeDArray(t
);
3871 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
3873 // This can be one of two things:
3874 // 1 - an associative array declaration, T[type]
3875 // 2 - an associative array declaration, T[expr]
3876 // These can only be disambiguated later.
3877 AST
.Type index
= parseType(); // [ type ]
3878 maybeArray
= new AST
.TypeAArray(t
, index
);
3879 check(TOK
.rightBracket
);
3883 // This can be one of three things:
3884 // 1 - an static array declaration, T[expr]
3885 // 2 - a slice, T[expr .. expr]
3886 // 3 - a template parameter pack index expression, T[expr].U
3887 // 1 and 3 can only be disambiguated later.
3888 //printf("it's type[expression]\n");
3890 AST
.Expression e
= parseAssignExp(); // [ expression ]
3891 if (token
.value
== TOK
.slice
)
3893 // It's a slice, and we're done.
3895 AST
.Expression e2
= parseAssignExp(); // [ exp .. exp ]
3896 t
= new AST
.TypeSlice(t
, e
, e2
);
3898 check(TOK
.rightBracket
);
3903 maybeArray
= new AST
.TypeSArray(t
, e
);
3905 check(TOK
.rightBracket
);
3916 return maybeArray ? maybeArray
: cast(AST
.Type
)tid
;
3919 /******************************************
3920 * Parse suffixes to type t.
3923 * [AssignExpression]
3924 * [AssignExpression .. AssignExpression]
3926 * delegate Parameters MemberFunctionAttributes(opt)
3927 * function Parameters FunctionAttributes(opt)
3929 * t = the already parsed type
3931 * t with the suffixes added
3933 * https://dlang.org/spec/declaration.html#TypeSuffixes
3935 private AST
.Type
parseTypeSuffixes(AST
.Type t
)
3937 //printf("parseTypeSuffixes()\n");
3940 switch (token
.value
)
3943 t
= new AST
.TypePointer(t
);
3947 case TOK
.leftBracket
:
3948 // Handle []. Make sure things like
3950 // is (array[1] of array[3] of int)
3952 if (token
.value
== TOK
.rightBracket
)
3954 t
= new AST
.TypeDArray(t
); // []
3957 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
3959 // It's an associative array declaration
3960 //printf("it's an associative array\n");
3961 AST
.Type index
= parseType(); // [ type ]
3962 t
= new AST
.TypeAArray(t
, index
);
3963 check(TOK
.rightBracket
);
3967 //printf("it's type[expression]\n");
3969 AST
.Expression e
= parseAssignExp(); // [ expression ]
3973 check(TOK
.rightBracket
);
3976 if (token
.value
== TOK
.slice
)
3979 AST
.Expression e2
= parseAssignExp(); // [ exp .. exp ]
3980 t
= new AST
.TypeSlice(t
, e
, e2
);
3984 t
= new AST
.TypeSArray(t
, e
);
3987 check(TOK
.rightBracket
);
3994 // Handle delegate declaration:
3995 // t delegate(parameter list) nothrow pure
3996 // t function(parameter list) nothrow pure
3997 const save
= token
.value
;
4000 auto parameterList
= parseParameterList(null);
4002 StorageClass
stc = parsePostfix(STC
.undefined_
, null);
4003 auto tf
= new AST
.TypeFunction(parameterList
, t
, linkage
, stc);
4004 if (stc & (STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.wild | STC
.return_
))
4006 if (save
== TOK
.function_
)
4007 error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions");
4009 tf
= cast(AST
.TypeFunction
)tf
.addSTC(stc);
4011 t
= save
== TOK
.delegate_ ?
new AST
.TypeDelegate(tf
) : new AST
.TypePointer(tf
); // pointer to function
4022 /**********************
4025 * t = base type to start with
4026 * palt = OR in 1 for C-style function pointer declaration syntax,
4027 * 2 for C-style array declaration syntax, otherwise don't modify
4028 * pident = set to Identifier if there is one, null if not
4029 * tpl = if !null, then set to TemplateParameterList
4030 * storageClass = any storage classes seen so far
4031 * pdisable = set to true if @disable seen
4032 * pudas = any user defined attributes seen so far. Merged with any more found
4035 * Reference: https://dlang.org/spec/declaration.html#Declarator
4037 private AST
.Type
parseDeclarator(AST
.Type t
, ref int palt
, Identifier
* pident
,
4038 AST
.TemplateParameters
** tpl
= null, StorageClass storageClass
= 0,
4039 bool* pdisable
= null, AST
.Expressions
** pudas
= null)
4041 //printf("parseDeclarator(tpl = %p)\n", tpl);
4042 t
= parseTypeSuffixes(t
);
4044 switch (token
.value
)
4046 case TOK
.identifier
:
4048 *pident
= token
.ident
;
4050 error("unexpected identifier `%s` in declarator", token
.ident
.toChars());
4055 case TOK
.leftParenthesis
:
4058 // like: T ((*fp))();
4059 if (peekNext() == TOK
.mul ||
peekNext() == TOK
.leftParenthesis
)
4061 /* Parse things with parentheses around the identifier, like:
4063 * although the D style would be:
4068 ts
= parseDeclarator(t
, palt
, pident
);
4069 check(TOK
.rightParenthesis
);
4074 Token
* peekt
= &token
;
4075 /* Completely disallow C-style things like:
4077 * Improve error messages for the common bug of a missing return type
4078 * by looking to see if (a) looks like a parameter list.
4080 if (isParameters(&peekt
))
4082 error("function declaration without return type. (Note that constructors are always named `this`)");
4085 error("unexpected `(` in declarator");
4093 // parse DeclaratorSuffixes
4096 switch (token
.value
)
4098 static if (CARRAYDECL
)
4100 /* Support C style array syntax:
4102 * as opposed to D-style:
4105 case TOK
.leftBracket
:
4107 // This is the old C-style post [] syntax.
4110 if (token
.value
== TOK
.rightBracket
)
4112 // It's a dynamic array
4113 ta
= new AST
.TypeDArray(t
); // []
4117 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
4119 // It's an associative array
4120 //printf("it's an associative array\n");
4121 AST
.Type index
= parseType(); // [ type ]
4122 check(TOK
.rightBracket
);
4123 ta
= new AST
.TypeAArray(t
, index
);
4128 //printf("It's a static array\n");
4129 AST
.Expression e
= parseAssignExp(); // [ expression ]
4130 ta
= new AST
.TypeSArray(t
, e
);
4131 check(TOK
.rightBracket
);
4138 * ts -> ... -> ta -> t
4141 for (pt
= &ts
; *pt
!= t
; pt
= &(cast(AST
.TypeNext
)*pt
).next
)
4148 case TOK
.leftParenthesis
:
4152 Token
* tk
= peekPastParen(&token
);
4153 if (tk
.value
== TOK
.leftParenthesis
)
4155 /* Look ahead to see if this is (...)(...),
4156 * i.e. a function template declaration
4158 //printf("function template declaration\n");
4160 // Gather template parameter list
4161 *tpl
= parseTemplateParameterList();
4163 else if (tk
.value
== TOK
.assign
)
4166 * i.e. a variable template declaration
4168 //printf("variable template declaration\n");
4169 *tpl
= parseTemplateParameterList();
4174 auto parameterList
= parseParameterList(null);
4176 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
4178 // merge prefix storage classes
4179 StorageClass
stc = parsePostfix(storageClass
, pudas
);
4181 AST
.Type tf
= new AST
.TypeFunction(parameterList
, t
, linkage
, stc);
4182 tf
= tf
.addSTC(stc);
4184 *pdisable
= stc & STC
.disable ?
true : false;
4189 * ts -> ... -> tf -> t
4192 for (pt
= &ts
; *pt
!= t
; pt
= &(cast(AST
.TypeNext
)*pt
).next
)
4206 private void parseStorageClasses(ref StorageClass storage_class
, ref LINK link
,
4207 ref bool setAlignment
, ref AST
.Expression ealign
, ref AST
.Expressions
* udas
,
4211 bool sawLinkage
= false; // seen a linkage declaration
4213 linkloc
= Loc
.initial
;
4217 switch (token
.value
)
4220 if (peekNext() == TOK
.leftParenthesis
)
4221 break; // const as type constructor
4222 stc = STC
.const_
; // const as storage class
4225 case TOK
.immutable_
:
4226 if (peekNext() == TOK
.leftParenthesis
)
4228 stc = STC
.immutable_
;
4232 if (peekNext() == TOK
.leftParenthesis
)
4238 if (peekNext() == TOK
.leftParenthesis
)
4260 stc = STC
.override_
;
4264 stc = STC
.abstract_
;
4267 case TOK
.synchronized_
:
4268 stc = STC
.synchronized_
;
4271 case TOK
.deprecated_
:
4272 stc = STC
.deprecated_
;
4293 const tv
= peekNext();
4294 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
4296 if (tv
== TOK
.identifier
)
4298 const nextv
= peekNext2();
4299 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
4308 stc = parseAttribute(udas
);
4314 storage_class
= appendStorageClass(storage_class
, stc);
4320 if (peekNext() != TOK
.leftParenthesis
)
4327 error("redundant linkage declaration");
4329 linkloc
= token
.loc
;
4330 auto res
= parseLinkage();
4332 if (res
.idents || res
.identExps
)
4334 error("C++ name spaces not allowed here");
4336 if (res
.cppmangle
!= CPPMANGLE
.def
)
4338 error("C++ mangle declaration not allowed here");
4345 setAlignment
= true;
4346 if (token
.value
== TOK
.leftParenthesis
)
4349 ealign
= parseExpression();
4350 check(TOK
.rightParenthesis
);
4361 /**********************************
4362 * Parse Declarations.
4364 * 1. declarations at global/class level
4365 * 2. declarations at statement level
4367 * array of Declarations.
4369 private AST
.Dsymbols
* parseDeclarations(bool autodecl
, PrefixAttributes
!AST
* pAttrs
, const(char)* comment
)
4371 StorageClass storage_class
= STC
.undefined_
;
4372 LINK link
= linkage
;
4373 Loc linkloc
= this.linkLoc
;
4374 bool setAlignment
= false;
4375 AST
.Expression ealign
;
4376 AST
.Expressions
* udas
= null;
4378 //printf("parseDeclarations() %s\n", token.toChars());
4380 comment
= token
.blockComment
.ptr
;
4382 /* Look for AliasReassignment
4384 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.assign
)
4385 return parseAliasReassignment(comment
);
4387 /* Declarations that start with `alias`
4389 bool isAliasDeclaration
= false;
4390 auto aliasLoc
= token
.loc
;
4391 if (token
.value
== TOK
.alias_
)
4393 if (auto a
= parseAliasDeclarations(comment
))
4395 /* Handle these later:
4396 * alias StorageClasses type ident;
4398 isAliasDeclaration
= true;
4405 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4407 if (token
.value
== TOK
.enum_
)
4409 AST
.Dsymbol d
= parseEnum();
4410 auto a
= new AST
.Dsymbols();
4415 d
= new AST
.UserAttributeDeclaration(udas
, a
);
4416 a
= new AST
.Dsymbols();
4420 addComment(d
, comment
);
4423 if (token
.value
== TOK
.struct_ ||
4424 token
.value
== TOK
.union_ ||
4425 token
.value
== TOK
.class_ ||
4426 token
.value
== TOK
.interface_
)
4428 AST
.Dsymbol s
= parseAggregate();
4429 auto a
= new AST
.Dsymbols();
4434 s
= new AST
.StorageClassDeclaration(storage_class
, a
);
4435 a
= new AST
.Dsymbols();
4440 s
= new AST
.AlignDeclaration(s
.loc
, ealign
, a
);
4441 a
= new AST
.Dsymbols();
4444 if (link
!= linkage
)
4446 s
= new AST
.LinkDeclaration(linkloc
, link
, a
);
4447 a
= new AST
.Dsymbols();
4452 s
= new AST
.UserAttributeDeclaration(udas
, a
);
4453 a
= new AST
.Dsymbols();
4457 addComment(s
, comment
);
4461 /* Look for auto initializers:
4462 * storage_class identifier = initializer;
4463 * storage_class identifier(...) = initializer;
4465 if ((storage_class || udas
) && token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
4467 AST
.Dsymbols
* a
= parseAutoDeclarations(storage_class
, comment
);
4470 AST
.Dsymbol s
= new AST
.UserAttributeDeclaration(udas
, a
);
4471 a
= new AST
.Dsymbols();
4477 /* Look for return type inference for template functions.
4481 if ((storage_class || udas
) && token
.value
== TOK
.identifier
&& skipParens(peek(&token
), &tk
) &&
4482 skipAttributes(tk
, &tk
) &&
4483 (tk
.value
== TOK
.leftParenthesis || tk
.value
== TOK
.leftCurly || tk
.value
== TOK
.in_ || tk
.value
== TOK
.out_ || tk
.value
== TOK
.goesTo ||
4484 tk
.value
== TOK
.do_ || tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
))
4486 if (tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
)
4487 usageOfBodyKeyword();
4493 ts
= parseBasicType();
4494 ts
= parseTypeSuffixes(ts
);
4501 storage_class |
= pAttrs
.storageClass
;
4502 //pAttrs.storageClass = STC.undefined_;
4505 AST
.Type tfirst
= null;
4506 auto a
= new AST
.Dsymbols();
4510 AST
.TemplateParameters
* tpl
= null;
4514 const loc
= token
.loc
;
4516 auto t
= parseDeclarator(ts
, alt
, &ident
, &tpl
, storage_class
, &disable
, &udas
);
4520 else if (t
!= tfirst
)
4521 error(token
.loc
, "multiple declarations must have the same type, not `%s` and `%s`", tfirst
.toChars(), t
.toChars());
4523 if (token
.value
== TOK
.colon
&& !ident
&& t
.ty
!= Tfunction
)
4525 // Unnamed bit field
4526 ident
= Identifier
.generateAnonymousId("BitField");
4529 bool isThis
= (t
.ty
== Tident
&& (cast(AST
.TypeIdentifier
)t
).ident
== Id
.This
&& token
.value
== TOK
.assign
);
4531 checkCstyleTypeSyntax(loc
, t
, alt
, ident
);
4532 else if (!isThis
&& (t
!= AST
.Type
.terror
))
4533 noIdentifierForDeclarator(t
);
4535 if (isAliasDeclaration
)
4538 AST
.Initializer _init
= null;
4540 /* Aliases can no longer have multiple declarators, storage classes,
4541 * linkages, or auto declarations.
4542 * These never made any sense, anyway.
4543 * The code below needs to be fixed to reject them.
4544 * The grammar has already been fixed to preclude them.
4548 error("user-defined attributes not allowed for `alias` declarations");
4550 if (token
.value
== TOK
.assign
)
4553 _init
= parseInitializer();
4557 error("alias cannot have initializer");
4559 v
= new AST
.AliasDeclaration(aliasLoc
, ident
, t
);
4561 v
.storage_class
= storage_class
;
4564 /* AliasDeclaration distinguish @safe, @system, @trusted attributes
4565 * on prefix and postfix.
4566 * @safe alias void function() FP1;
4567 * alias @safe void function() FP2; // FP2 is not @safe
4568 * alias void function() @safe FP3;
4570 pAttrs
.storageClass
&= STC
.safeGroup
;
4574 if (link
!= linkage
)
4576 auto ax
= new AST
.Dsymbols();
4578 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4581 switch (token
.value
)
4585 addComment(s
, comment
);
4590 addComment(s
, comment
);
4594 error("semicolon expected to close `alias` declaration, not `%s`", token
.toChars());
4598 else if (t
.ty
== Tfunction
)
4600 /* @@@DEPRECATED_2.115@@@
4601 * change to error, deprecated in 2.105.1 */
4602 if (storage_class
& STC
.manifest
)
4603 deprecation("function cannot have enum storage class");
4605 AST
.Expression constraint
= null;
4606 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
4607 auto f
= new AST
.FuncDeclaration(loc
, Loc
.initial
, ident
, storage_class |
(disable ? STC
.disable
: 0), t
);
4609 pAttrs
.storageClass
= STC
.undefined_
;
4611 constraint
= parseConstraint();
4612 AST
.Dsymbol s
= parseContracts(f
, !!tpl
);
4613 auto tplIdent
= s
.ident
;
4615 if (link
!= linkage
)
4617 auto ax
= new AST
.Dsymbols();
4619 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4623 auto ax
= new AST
.Dsymbols();
4625 s
= new AST
.UserAttributeDeclaration(udas
, ax
);
4628 /* A template parameter list means it's a function template
4632 // @@@DEPRECATED_2.114@@@
4633 // Both deprecated in 2.104, change to error
4634 if (storage_class
& STC
.override_
)
4635 deprecation(loc
, "a function template is not virtual so cannot be marked `override`");
4636 else if (storage_class
& STC
.abstract_
)
4637 deprecation(loc
, "a function template is not virtual so cannot be marked `abstract`");
4639 // Wrap a template around the function declaration
4640 auto decldefs
= new AST
.Dsymbols();
4642 auto tempdecl
= new AST
.TemplateDeclaration(loc
, tplIdent
, tpl
, constraint
, decldefs
);
4645 StorageClass stc2
= STC
.undefined_
;
4646 if (storage_class
& STC
.static_
)
4648 assert(f
.storage_class
& STC
.static_
);
4649 f
.storage_class
&= ~STC
.static_
;
4650 stc2 |
= STC
.static_
;
4652 if (storage_class
& STC
.deprecated_
)
4654 assert(f
.storage_class
& STC
.deprecated_
);
4655 f
.storage_class
&= ~STC
.deprecated_
;
4656 stc2 |
= STC
.deprecated_
;
4658 if (stc2
!= STC
.undefined_
)
4660 auto ax
= new AST
.Dsymbols();
4662 s
= new AST
.StorageClassDeclaration(stc2
, ax
);
4666 addComment(s
, comment
);
4670 AST
.Expression width
;
4671 if (token
.value
== TOK
.colon
)
4674 width
= parseCondExp();
4677 AST
.Initializer _init
= null;
4678 if (token
.value
== TOK
.assign
)
4681 _init
= parseInitializer();
4688 error("initializer not allowed for bit-field declaration");
4690 error("storage class not allowed for bit-field declaration");
4691 s
= new AST
.BitFieldDeclaration(width
.loc
, t
, ident
, width
);
4695 auto v
= new AST
.VarDeclaration(loc
, t
, ident
, _init
);
4696 v
.storage_class
= storage_class
;
4698 pAttrs
.storageClass
= STC
.undefined_
;
4704 auto a2
= new AST
.Dsymbols();
4706 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
, 0);
4711 auto ax
= new AST
.Dsymbols();
4713 s
= new AST
.AlignDeclaration(s
.loc
, ealign
, ax
);
4715 if (link
!= linkage
)
4717 auto ax
= new AST
.Dsymbols();
4719 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4723 auto ax
= new AST
.Dsymbols();
4725 s
= new AST
.UserAttributeDeclaration(udas
, ax
);
4728 switch (token
.value
)
4732 addComment(s
, comment
);
4737 addComment(s
, comment
);
4741 if (loc
.linnum
!= token
.loc
.linnum
)
4743 error(token
.loc
, "semicolon needed to end declaration of `%s`, instead of `%s`", s
.toChars(), token
.toChars());
4744 eSink
.errorSupplemental(loc
, "`%s` declared here", s
.toChars());
4748 error(token
.loc
, "semicolon needed to end declaration of `%s` instead of `%s`", s
.toChars(), token
.toChars());
4758 /// Report an error that a declaration of type `t` is missing an identifier
4759 /// The parser is expected to sit on the next token after the type.
4760 private void noIdentifierForDeclarator(AST
.Type t
)
4762 error("no identifier for declarator `%s`", t
.toChars());
4763 // A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out`
4764 if (token
.isKeyword
)
4766 eSink
.errorSupplemental(token
.loc
, "`%s` is a keyword, perhaps append `_` to make it an identifier", token
.toChars());
4771 /********************************
4772 * Parse AliasReassignment:
4773 * identifier = type;
4774 * Parser is sitting on the identifier.
4775 * https://dlang.org/spec/declaration.html#alias-reassignment
4777 * comment = if not null, comment to attach to symbol
4781 private AST
.Dsymbols
* parseAliasReassignment(const(char)* comment
)
4783 const loc
= token
.loc
;
4784 auto ident
= token
.ident
;
4786 nextToken(); // advance past =
4787 auto t
= parseType();
4788 AST
.Dsymbol s
= new AST
.AliasAssign(loc
, ident
, t
, null);
4789 check(TOK
.semicolon
, "alias reassignment");
4790 addComment(s
, comment
);
4791 auto a
= new AST
.Dsymbols();
4796 /********************************
4797 * Parse declarations that start with `alias`
4798 * Parser is sitting on the `alias`.
4799 * https://dlang.org/spec/declaration.html#alias
4801 * comment = if not null, comment to attach to symbol
4805 private AST
.Dsymbols
* parseAliasDeclarations(const(char)* comment
)
4807 const loc
= token
.loc
;
4809 Loc linkloc
= this.linkLoc
;
4810 AST
.Expressions
* udas
;
4811 LINK link
= linkage
;
4812 StorageClass storage_class
= STC
.undefined_
;
4813 AST
.Expression ealign
;
4814 bool setAlignment
= false;
4817 * alias Identifier this;
4818 * https://dlang.org/spec/class.html#alias-this
4820 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.this_
)
4822 auto s
= new AST
.AliasThis(loc
, token
.ident
);
4825 check(TOK
.semicolon
, "`alias Identifier this`");
4826 auto a
= new AST
.Dsymbols();
4828 addComment(s
, comment
);
4832 * alias this = identifier;
4834 if (token
.value
== TOK
.this_
&& peekNext() == TOK
.assign
&& peekNext2() == TOK
.identifier
)
4838 auto s
= new AST
.AliasThis(loc
, token
.ident
);
4840 check(TOK
.semicolon
, "`alias this = Identifier`");
4841 auto a
= new AST
.Dsymbols();
4843 addComment(s
, comment
);
4847 * alias identifier = type;
4848 * alias identifier(...) = type;
4849 * https://dlang.org/spec/declaration.html#alias
4851 if (token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
4853 auto a
= new AST
.Dsymbols();
4856 auto ident
= token
.ident
;
4858 AST
.TemplateParameters
* tpl
= null;
4859 if (token
.value
== TOK
.leftParenthesis
)
4860 tpl
= parseTemplateParameterList();
4863 bool hasParsedAttributes
;
4864 void parseAttributes()
4866 if (hasParsedAttributes
) // only parse once
4868 hasParsedAttributes
= true;
4870 storage_class
= STC
.undefined_
;
4872 linkloc
= this.linkLoc
;
4873 setAlignment
= false;
4875 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4878 if (token
.value
== TOK
.at
)
4884 bool attributesAppended
;
4885 const StorageClass funcStc
= parseTypeCtor();
4887 // function literal?
4888 if (token
.value
== TOK
.function_ ||
4889 token
.value
== TOK
.delegate_ ||
4890 token
.value
== TOK
.leftParenthesis
&&
4891 skipAttributes(peekPastParen(&token
), &tk
) &&
4892 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
) ||
4893 token
.value
== TOK
.leftCurly ||
4894 token
.value
== TOK
.identifier
&& peekNext() == TOK
.goesTo ||
4895 token
.value
== TOK
.ref_
&& peekNext() == TOK
.leftParenthesis
&&
4896 skipAttributes(peekPastParen(peek(&token
)), &tk
) &&
4897 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
) ||
4898 token
.value
== TOK
.auto_
&&
4899 (peekNext() == TOK
.leftParenthesis ||
// for better error
4900 peekNext() == TOK
.ref_
&&
4901 peekNext2() == TOK
.leftParenthesis
)
4904 // function (parameters) { statements... }
4905 // delegate (parameters) { statements... }
4906 // (parameters) { statements... }
4907 // (parameters) => expression
4908 // { statements... }
4909 // identifier => expression
4910 // ref (parameters) { statements... }
4911 // ref (parameters) => expression
4912 // auto ref (parameters) { statements... }
4913 // auto ref (parameters) => expression
4915 s
= parseFunctionLiteral();
4919 if (storage_class
!= 0)
4920 error("cannot put a storage-class in an `alias` declaration.");
4921 // parseAttributes shouldn't have set these variables
4922 assert(link
== linkage
&& !setAlignment
&& ealign
is null);
4923 auto tpl_
= cast(AST
.TemplateDeclaration
) s
;
4924 if (tpl_
is null || tpl_
.members
.length
!= 1)
4926 error("user-defined attributes are not allowed on `alias` declarations");
4930 auto fd
= cast(AST
.FuncLiteralDeclaration
) (*tpl_
.members
)[0];
4931 auto tf
= cast(AST
.TypeFunction
) fd
.type
;
4932 assert(tf
.parameterList
.parameters
.length
> 0);
4933 auto as
= new AST
.Dsymbols();
4934 (*tf
.parameterList
.parameters
)[0].userAttribDecl
= new AST
.UserAttributeDeclaration(udas
, as
);
4938 v
= new AST
.AliasDeclaration(loc
, ident
, s
);
4945 error("user-defined attributes not allowed for `alias` declarations");
4947 auto t
= parseBasicType();
4948 t
= parseTypeSuffixes(t
);
4949 if (token
.value
== TOK
.identifier
)
4951 error("unexpected identifier `%s` after `%s`",
4952 token
.ident
.toChars(), t
.toChars());
4955 else if (token
.value
== TOK
.leftParenthesis
)
4958 // StorageClasses Type ( Parameters ) MemberFunctionAttributes
4959 auto parameterList
= parseParameterList(null);
4961 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4963 error("user-defined attributes not allowed for `alias` declarations");
4965 attributesAppended
= true;
4966 // Note: method types can have a TypeCtor attribute
4967 storage_class
= appendStorageClass(storage_class
, funcStc
);
4968 t
= new AST
.TypeFunction(parameterList
, t
, link
, storage_class
);
4971 // Disallow meaningless storage classes on type aliases
4974 // Don't raise errors for STC that are part of a function/delegate type, e.g.
4975 // `alias F = ref pure nothrow @nogc @safe int function();`
4976 const remStc
= t
.isTypeFunction ?
4977 storage_class
& ~(STC
.FUNCATTR | STC
.TYPECTOR
) : {
4978 auto tp
= t
.isTypePointer
;
4979 const isFuncType
= (tp
&& tp
.next
.isTypeFunction
) || t
.isTypeDelegate
;
4980 return isFuncType ?
(storage_class
& ~STC
.FUNCATTR
) : storage_class
;
4986 AST
.stcToBuffer(buf
, remStc
);
4987 // @@@DEPRECATED_2.103@@@
4988 // Deprecated in 2020-07, can be made an error in 2.103
4989 eSink
.deprecation(token
.loc
, "storage class `%s` has no effect in type aliases", buf
.peekChars());
4993 v
= new AST
.AliasDeclaration(loc
, ident
, t
);
4995 if (!attributesAppended
)
4996 storage_class
= appendStorageClass(storage_class
, funcStc
);
4997 v
.storage_class
= storage_class
;
5002 auto a2
= new AST
.Dsymbols();
5004 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
);
5007 if (link
!= linkage
)
5009 auto a2
= new AST
.Dsymbols();
5011 s
= new AST
.LinkDeclaration(linkloc
, link
, a2
);
5015 switch (token
.value
)
5019 addComment(s
, comment
);
5024 addComment(s
, comment
);
5025 if (token
.value
!= TOK
.identifier
)
5027 error("identifier expected following comma, not `%s`", token
.toChars());
5030 if (peekNext() != TOK
.assign
&& peekNext() != TOK
.leftParenthesis
)
5032 error("`=` expected following identifier");
5039 error("semicolon expected to close `alias` declaration, not `%s`", token
.toChars());
5047 // alias StorageClasses type ident;
5051 private AST
.Dsymbol
parseFunctionLiteral()
5053 const loc
= token
.loc
;
5054 AST
.TemplateParameters
* tpl
= null;
5055 AST
.ParameterList parameterList
;
5056 AST
.Type tret
= null;
5057 StorageClass
stc = 0;
5058 TOK save
= TOK
.reserved
;
5060 switch (token
.value
)
5066 if (token
.value
== TOK
.auto_
)
5069 if (token
.value
== TOK
.ref_
)
5071 // function auto ref (parameters) { statements... }
5072 // delegate auto ref (parameters) { statements... }
5073 stc = STC
.auto_ | STC
.ref_
;
5077 error("`auto` can only be used as part of `auto ref` for function literal return values");
5079 else if (token
.value
== TOK
.ref_
)
5081 // function ref (parameters) { statements... }
5082 // delegate ref (parameters) { statements... }
5086 if (token
.value
!= TOK
.leftParenthesis
&& token
.value
!= TOK
.leftCurly
&&
5087 token
.value
!= TOK
.goesTo
)
5089 // function type (parameters) { statements... }
5090 // delegate type (parameters) { statements... }
5091 tret
= parseBasicType();
5092 tret
= parseTypeSuffixes(tret
); // function return type
5095 if (token
.value
== TOK
.leftParenthesis
)
5097 // function (parameters) { statements... }
5098 // delegate (parameters) { statements... }
5102 // function { statements... }
5103 // delegate { statements... }
5106 goto case TOK
.leftParenthesis
;
5111 if (token
.value
== TOK
.ref_
)
5113 // auto ref (parameters) => expression
5114 // auto ref (parameters) { statements... }
5115 stc = STC
.auto_ | STC
.ref_
;
5119 error("`auto` can only be used as part of `auto ref` for function literal return values");
5120 goto case TOK
.leftParenthesis
;
5124 // ref (parameters) => expression
5125 // ref (parameters) { statements... }
5128 goto case TOK
.leftParenthesis
;
5130 case TOK
.leftParenthesis
:
5132 // (parameters) => expression
5133 // (parameters) { statements... }
5134 parameterList
= parseParameterList(&tpl
);
5135 stc = parsePostfix(stc, null);
5136 if (StorageClass modStc
= stc & STC
.TYPECTOR
)
5138 if (save
== TOK
.function_
)
5141 AST
.stcToBuffer(buf
, modStc
);
5142 error("function literal cannot be `%s`", buf
.peekChars());
5145 save
= TOK
.delegate_
;
5150 // { statements... }
5153 case TOK
.identifier
:
5155 // identifier => expression
5156 parameterList
.parameters
= new AST
.Parameters();
5157 Identifier id
= Identifier
.generateId("__T");
5158 AST
.Type t
= new AST
.TypeIdentifier(loc
, id
);
5159 parameterList
.parameters
.push(new AST
.Parameter(loc
, STC
.parameter
, t
, token
.ident
, null, null));
5161 tpl
= new AST
.TemplateParameters();
5162 AST
.TemplateParameter tp
= new AST
.TemplateTypeParameter(loc
, id
, null, null);
5172 auto tf
= new AST
.TypeFunction(parameterList
, tret
, linkage
, stc);
5173 tf
= cast(AST
.TypeFunction
)tf
.addSTC(stc);
5174 auto fd
= new AST
.FuncLiteralDeclaration(loc
, Loc
.initial
, tf
, save
, null, null, stc & STC
.auto_
);
5176 if (token
.value
== TOK
.goesTo
)
5179 if (token
.value
== TOK
.leftCurly
)
5181 deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
5182 deprecationSupplemental("Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
5184 const returnloc
= token
.loc
;
5185 AST
.Expression ae
= parseAssignExp();
5186 fd
.fbody
= new AST
.ReturnStatement(returnloc
, ae
);
5187 fd
.endloc
= token
.loc
;
5196 // Wrap a template around function fd
5197 auto decldefs
= new AST
.Dsymbols();
5199 return new AST
.TemplateDeclaration(fd
.loc
, fd
.ident
, tpl
, null, decldefs
, false, true);
5204 /*****************************************
5205 * Parse contracts following function declaration.
5207 private AST
.FuncDeclaration
parseContracts(AST
.FuncDeclaration f
, bool isTemplateFunction
= false)
5209 LINK linksave
= linkage
;
5211 bool literal
= f
.isFuncLiteralDeclaration() !is null;
5213 // The following is irrelevant, as it is overridden by sc.linkage in
5214 // TypeFunction::semantic
5215 linkage
= LINK
.d
; // nested functions have D linkage
5216 bool requireDo
= false;
5218 switch (token
.value
)
5222 error("missing `do { ... }` after `in` or `out`");
5223 const returnloc
= token
.loc
;
5225 f
.fbody
= new AST
.ReturnStatement(returnloc
, parseExpression());
5226 f
.endloc
= token
.loc
;
5227 check(TOK
.semicolon
);
5232 error("missing `do { ... }` after `in` or `out`");
5233 f
.fbody
= parseStatement(0);
5237 case TOK
.identifier
:
5238 if (token
.ident
== Id
._body
)
5240 usageOfBodyKeyword();
5247 f
.fbody
= parseStatement(ParseStatementFlags
.curly
);
5253 // Do we want this for function declarations, so we can do:
5254 // int x, y, foo(), z;
5261 // in { statements... }
5263 auto loc
= token
.loc
;
5267 f
.frequires
= new AST
.Statements
;
5269 if (token
.value
== TOK
.leftParenthesis
)
5272 AST
.Expression e
= parseAssignExp(), msg
= null;
5273 if (token
.value
== TOK
.comma
)
5276 if (token
.value
!= TOK
.rightParenthesis
)
5278 msg
= parseAssignExp();
5279 if (token
.value
== TOK
.comma
)
5283 check(TOK
.rightParenthesis
);
5284 e
= new AST
.AssertExp(loc
, e
, msg
);
5285 f
.frequires
.push(new AST
.ExpStatement(loc
, e
));
5290 auto ret = parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
);
5292 f
.frequires
.push(ret);
5298 // out { statements... }
5299 // out (; expression)
5300 // out (identifier) { statements... }
5301 // out (identifier; expression)
5302 auto loc
= token
.loc
;
5306 f
.fensures
= new AST
.Ensures
;
5308 Identifier id
= null;
5309 if (token
.value
!= TOK
.leftCurly
)
5311 check(TOK
.leftParenthesis
);
5312 if (token
.value
!= TOK
.identifier
&& token
.value
!= TOK
.semicolon
)
5313 error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token
.toChars());
5314 if (token
.value
!= TOK
.semicolon
)
5319 if (token
.value
== TOK
.semicolon
)
5322 AST
.Expression e
= parseAssignExp(), msg
= null;
5323 if (token
.value
== TOK
.comma
)
5326 if (token
.value
!= TOK
.rightParenthesis
)
5328 msg
= parseAssignExp();
5329 if (token
.value
== TOK
.comma
)
5333 check(TOK
.rightParenthesis
);
5334 e
= new AST
.AssertExp(loc
, e
, msg
);
5335 f
.fensures
.push(AST
.Ensure(id
, new AST
.ExpStatement(loc
, e
)));
5339 check(TOK
.rightParenthesis
);
5341 f
.fensures
.push(AST
.Ensure(id
, parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
)));
5348 // https://issues.dlang.org/show_bug.cgi?id=15799
5349 // Semicolon becomes a part of function declaration
5350 // only when 'do' is not required
5360 const(char)* sbody
= requireDo ?
"do " : "";
5361 error("missing `%s{ ... }` for function literal", sbody
);
5363 else if (!requireDo
) // allow contracts even with no body
5365 TOK t
= token
.value
;
5366 if (t
== TOK
.const_ || t
== TOK
.immutable_ || t
== TOK
.inout_ || t
== TOK
.return_ ||
5367 t
== TOK
.shared_ || t
== TOK
.nothrow_ || t
== TOK
.pure_
)
5368 error("'%s' cannot be placed after a template constraint", token
.toChars
);
5369 else if (t
== TOK
.at
)
5370 error("attributes cannot be placed after a template constraint");
5371 else if (t
== TOK
.if_
)
5373 if (isTemplateFunction
)
5374 error("template constraint must follow parameter lists and attributes");
5376 error("cannot use function constraints for non-template functions. Use `static if` instead");
5379 error("semicolon expected following function declaration, not `%s`", token
.toChars());
5383 if (literal
&& !f
.fbody
)
5385 // Set empty function body for error recovery
5386 f
.fbody
= new AST
.CompoundStatement(Loc
.initial
, cast(AST
.Statement
)null);
5394 /*****************************************
5396 private void checkDanglingElse(Loc elseloc
)
5398 if (token
.value
!= TOK
.else_
&& token
.value
!= TOK
.catch_
&& token
.value
!= TOK
.finally_
&& lookingForElse
.linnum
!= 0)
5400 eSink
.warning(elseloc
, "else is dangling, add { } after condition at %s", lookingForElse
.toChars());
5404 /* *************************
5405 * Issue errors if C-style syntax
5407 * alt = !=0 for C-style syntax
5409 private void checkCstyleTypeSyntax(Loc loc
, AST
.Type t
, int alt
, Identifier ident
)
5414 const(char)* sp
= !ident ?
"" : " ";
5415 const(char)* s
= !ident ?
"" : ident
.toChars();
5416 error(loc
, "instead of C-style syntax, use D-style `%s%s%s`", t
.toChars(), sp
, s
);
5419 /*****************************
5420 * Ad-hoc error message for missing or extra parens that close a condition.
5422 * start = "if", "while", etc. Must be 0 terminated.
5423 * param = if the condition is a declaration, this will be non-null
5424 * condition = if param is null, then this is the conditional Expression. If condition is null,
5425 * then an error in the condition was already reported.
5427 private void closeCondition(string start
, AST
.Parameter param
, AST
.Expression condition
)
5430 if (token
.value
!= TOK
.rightParenthesis
&& condition
)
5432 format
= "missing closing `)` after `%s (%s`";
5435 check(TOK
.rightParenthesis
);
5436 if (token
.value
== TOK
.rightParenthesis
)
5438 if (condition
) // if not an error in condition
5439 format
= "extra `)` after `%s (%s)`";
5443 error(token
.loc
, format
.ptr
, start
.ptr
, param ?
"declaration".ptr
: condition
.toChars());
5446 /*****************************************
5447 * Parses `foreach` statements, `static foreach` statements and
5448 * `static foreach` declarations.
5450 * Foreach = one of Statement, StaticForeachStatement, StaticForeachDeclaration
5451 * loc = location of foreach
5452 * pLastDecl = non-null for StaticForeachDeclaration
5454 * the Foreach generated
5456 private Foreach
parseForeach(alias Foreach
)(Loc loc
, AST
.Dsymbol
* pLastDecl
)
5458 static if (is(Foreach
== AST
.StaticForeachStatement
) ||
is(Foreach
== AST
.StaticForeachDeclaration
))
5463 TOK op
= token
.value
;
5466 check(TOK
.leftParenthesis
);
5468 auto parameters
= new AST
.Parameters();
5472 Identifier ai
= null;
5476 StorageClass storageClass
= 0;
5477 StorageClass
stc = 0;
5481 storageClass
= appendStorageClass(storageClass
, stc);
5484 switch (token
.value
)
5495 error("cannot declare `out` loop variable, use `ref` instead");
5500 error("cannot declare `auto` loop variable, omit `auto` to still get type inference");
5509 storageClass
= appendStorageClass(storageClass
, STC
.alias_
);
5514 if (peekNext() != TOK
.leftParenthesis
)
5521 case TOK
.immutable_
:
5522 if (peekNext() != TOK
.leftParenthesis
)
5524 stc = STC
.immutable_
;
5530 if (peekNext() != TOK
.leftParenthesis
)
5538 if (peekNext() != TOK
.leftParenthesis
)
5548 if (token
.value
== TOK
.identifier
)
5550 const tv
= peekNext();
5551 if (tv
== TOK
.comma || tv
== TOK
.semicolon || tv
== TOK
.rightParenthesis
)
5553 lastai
= token
.ident
;
5555 at
= null; // infer argument type
5561 at
= parseType(&ai
);
5563 noIdentifierForDeclarator(at
);
5565 auto p
= new AST
.Parameter(aloc
, storageClass
, at
, ai
, null, null);
5567 if (token
.value
== TOK
.comma
)
5574 if (token
.value
!= TOK
.semicolon
)
5576 error("missing `; expression` before `)` of `foreach`");
5578 if (lastai
&& parameters
.length
>= 2)
5580 eSink
.errorSupplemental(loc
, "perhaps the `;` goes before `%s`", lastai
.toChars());
5586 AST
.Expression aggr
= parseExpression();
5587 if (token
.value
== TOK
.slice
&& parameters
.length
== 1)
5589 AST
.Parameter p
= (*parameters
)[0];
5591 AST
.Expression upr
= parseExpression();
5592 check(TOK
.rightParenthesis
);
5594 static if (is(Foreach
== AST
.Statement
) ||
is(Foreach
== AST
.StaticForeachStatement
))
5596 AST
.Statement _body
= parseStatement(0, null, &endloc
);
5600 AST
.Statement _body
= null;
5602 auto rangefe
= new AST
.ForeachRangeStatement(loc
, op
, p
, aggr
, upr
, _body
, endloc
);
5603 static if (is(Foreach
== AST
.Statement
))
5607 else static if(is(Foreach
== AST
.StaticForeachDeclaration
))
5609 return new AST
.StaticForeachDeclaration(new AST
.StaticForeach(loc
, null, rangefe
), parseBlock(pLastDecl
));
5611 else static if (is(Foreach
== AST
.StaticForeachStatement
))
5613 return new AST
.StaticForeachStatement(loc
, new AST
.StaticForeach(loc
, null, rangefe
));
5618 check(TOK
.rightParenthesis
);
5620 static if (is(Foreach
== AST
.Statement
) ||
is(Foreach
== AST
.StaticForeachStatement
))
5622 AST
.Statement _body
= parseStatement(0, null, &endloc
);
5626 AST
.Statement _body
= null;
5628 auto aggrfe
= new AST
.ForeachStatement(loc
, op
, parameters
, aggr
, _body
, endloc
);
5629 static if (is(Foreach
== AST
.Statement
))
5633 else static if(is(Foreach
== AST
.StaticForeachDeclaration
))
5635 return new AST
.StaticForeachDeclaration(new AST
.StaticForeach(loc
, aggrfe
, null), parseBlock(pLastDecl
));
5637 else static if (is(Foreach
== AST
.StaticForeachStatement
))
5639 return new AST
.StaticForeachStatement(loc
, new AST
.StaticForeach(loc
, aggrfe
, null));
5646 * Parse an assignment condition for if or while statements.
5649 * The variable that is declared inside the condition
5651 AST
.Parameter
parseAssignCondition()
5653 AST
.Parameter param
= null;
5654 StorageClass storageClass
= 0;
5655 StorageClass
stc = 0;
5659 switch (token
.value
)
5661 // parse ref for better error
5675 if (peekNext() != TOK
.leftParenthesis
)
5682 case TOK
.immutable_
:
5683 if (peekNext() != TOK
.leftParenthesis
)
5685 stc = STC
.immutable_
;
5691 if (peekNext() != TOK
.leftParenthesis
)
5699 if (peekNext() != TOK
.leftParenthesis
)
5709 storageClass
= appendStorageClass(storageClass
, stc);
5712 auto n
= peek(&token
);
5713 if (storageClass
!= 0 && token
.value
== TOK
.identifier
&& n
.value
== TOK
.assign
)
5715 Identifier ai
= token
.ident
;
5716 AST
.Type at
= null; // infer parameter type
5717 const aloc
= token
.loc
;
5720 param
= new AST
.Parameter(aloc
, storageClass
, at
, ai
, null, null);
5722 else if (isDeclaration(&token
, NeedDeclaratorId
.must
, TOK
.assign
, null))
5725 const aloc
= token
.loc
;
5726 AST
.Type at
= parseType(&ai
);
5728 param
= new AST
.Parameter(aloc
, storageClass
, at
, ai
, null, null);
5730 else if (storageClass
!= 0)
5731 error("found `%s` while expecting `=` or identifier", n
.toChars());
5736 /*****************************************
5740 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
5742 AST
.Statement
parseStatement(int flags
, const(char)** endPtr
= null, Loc
* pEndloc
= null)
5746 AST
.Statement ifbody
;
5747 AST
.Statement elsebody
;
5749 const loc
= token
.loc
;
5751 //printf("parseStatement()\n");
5752 if (flags
& ParseStatementFlags
.curly
&& token
.value
!= TOK
.leftCurly
)
5753 error("statement expected to be `{ }`, not `%s`", token
.toChars());
5755 switch (token
.value
)
5757 case TOK
.identifier
:
5759 /* A leading identifier can be a declaration, label, or expression.
5760 * The easiest case to check first is label:
5762 if (peekNext() == TOK
.colonColon
)
5767 error("use `.` for member lookup, not `::`");
5771 if (peekNext() == TOK
.colon
)
5774 Identifier ident
= token
.ident
;
5777 if (token
.value
== TOK
.rightCurly
)
5779 else if (token
.value
== TOK
.leftCurly
)
5780 s
= parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
);
5781 else if (flags
& ParseStatementFlags
.curlyScope
)
5782 s
= parseStatement(ParseStatementFlags
.semiOk | ParseStatementFlags
.curlyScope
);
5784 s
= parseStatement(ParseStatementFlags
.semiOk
);
5785 s
= new AST
.LabelStatement(loc
, ident
, s
);
5794 /* https://issues.dlang.org/show_bug.cgi?id=15163
5795 * If tokens can be handled as
5796 * old C-style declaration or D expression, prefer the latter.
5798 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
5805 case TOK
.int32Literal
:
5806 case TOK
.uns32Literal
:
5807 case TOK
.int64Literal
:
5808 case TOK
.uns64Literal
:
5809 case TOK
.int128Literal
:
5810 case TOK
.uns128Literal
:
5811 case TOK
.float32Literal
:
5812 case TOK
.float64Literal
:
5813 case TOK
.float80Literal
:
5814 case TOK
.imaginary32Literal
:
5815 case TOK
.imaginary64Literal
:
5816 case TOK
.imaginary80Literal
:
5817 case TOK
.charLiteral
:
5818 case TOK
.wcharLiteral
:
5819 case TOK
.dcharLiteral
:
5824 case TOK
.interpolated
:
5825 case TOK
.hexadecimalString
:
5826 case TOK
.leftParenthesis
:
5834 case TOK
.minusMinus
:
5841 case TOK
.leftBracket
:
5843 case TOK
.fileFullPath
:
5845 case TOK
.moduleString
:
5846 case TOK
.functionString
:
5847 case TOK
.prettyFunction
:
5850 AST
.Expression exp
= parseExpression();
5851 /* https://issues.dlang.org/show_bug.cgi?id=15103
5852 * Improve declaration / initialization syntax error message
5853 * Error: found 'foo' when expecting ';' following expression
5854 * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
5856 if (token
.value
== TOK
.identifier
&& exp
.op
== EXP
.identifier
)
5858 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());
5864 * https://issues.dlang.org/show_bug.cgi?id=22529
5865 * Avoid empty declaration error in case of missing semicolon
5866 * followed by another token and another semicolon. E.g.:
5871 * When the missing `;` error is emitted, token is sitting on return.
5872 * If we simply use `check` to emit the error, the token is advanced
5873 * to `;` and the empty statement error would follow. To avoid that,
5874 * we check if the next token is a semicolon and simply output the error,
5875 * otherwise we fall back on the old path (advancing the token).
5877 if (token
.value
!= TOK
.semicolon
&& peek(&token
).value
== TOK
.semicolon
)
5878 error("found `%s` when expecting `;` following expression", token
.toChars());
5881 if (token
.value
!= TOK
.semicolon
)
5883 error("found `%s` when expecting `;` following expression", token
.toChars());
5884 eSink
.errorSupplemental(exp
.loc
, "expression: `%s`", exp
.toChars());
5889 s
= new AST
.ExpStatement(loc
, exp
);
5894 // Look ahead to see if it's static assert() or static if()
5895 const tv
= peekNext();
5896 if (tv
== TOK
.assert_
)
5898 s
= new AST
.StaticAssertStatement(parseStaticAssert());
5903 cond
= parseStaticIfCondition();
5906 if (tv
== TOK
.foreach_ || tv
== TOK
.foreach_reverse_
)
5908 s
= parseForeach
!(AST
.StaticForeachStatement
)(loc
, null);
5909 if (flags
& ParseStatementFlags
.scope_
)
5910 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5913 if (tv
== TOK
.import_
)
5915 AST
.Dsymbols
* imports
= parseImport();
5916 s
= new AST
.ImportStatement(loc
, imports
);
5917 if (flags
& ParseStatementFlags
.scope_
)
5918 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5924 if (peekNext() == TOK
.switch_
)
5949 case TOK
.imaginary32
:
5950 case TOK
.imaginary64
:
5951 case TOK
.imaginary80
:
5956 // bug 7773: int.max is always a part of expression
5957 if (peekNext() == TOK
.dot
)
5959 if (peekNext() == TOK
.leftParenthesis
)
5969 case TOK
.immutable_
:
5972 case TOK
.deprecated_
:
5981 case TOK
.interface_
:
5984 AST
.Dsymbols
* a
= parseDeclarations(false, null, null);
5987 auto as
= new AST
.Statements();
5988 as
.reserve(a
.length
);
5989 foreach (i
; 0 .. a
.length
)
5991 AST
.Dsymbol d
= (*a
)[i
];
5992 s
= new AST
.ExpStatement(loc
, d
);
5995 s
= new AST
.CompoundDeclarationStatement(loc
, as
);
5997 else if (a
.length
== 1)
5999 AST
.Dsymbol d
= (*a
)[0];
6000 s
= new AST
.ExpStatement(loc
, d
);
6003 s
= new AST
.ExpStatement(loc
, cast(AST
.Expression
)null);
6004 if (flags
& ParseStatementFlags
.scope_
)
6005 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6010 /* Determine if this is a manifest constant declaration,
6011 * or a conventional enum.
6014 const tv
= peekNext();
6015 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
6017 else if (tv
!= TOK
.identifier
)
6021 const nextv
= peekNext2();
6022 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
6027 s
= new AST
.ExpStatement(loc
, d
);
6028 if (flags
& ParseStatementFlags
.scope_
)
6029 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6034 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
6036 const tv
= peekNext();
6037 if (tv
== TOK
.leftParenthesis
)
6040 AST
.Expression e
= parseAssignExp();
6041 check(TOK
.semicolon
, "mixin");
6042 if (e
.op
== EXP
.mixin_
)
6044 AST
.MixinExp cpe
= cast(AST
.MixinExp
)e
;
6045 s
= new AST
.MixinStatement(loc
, cpe
.exps
);
6049 s
= new AST
.ExpStatement(loc
, e
);
6053 else if (tv
== TOK
.template_
)
6057 AST
.Dsymbol d
= parseTemplateDeclaration(true);
6058 s
= new AST
.ExpStatement(loc
, d
);
6061 AST
.Dsymbol d
= parseMixin();
6062 s
= new AST
.ExpStatement(loc
, d
);
6063 if (flags
& ParseStatementFlags
.scope_
)
6064 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6069 const lcLoc
= token
.loc
;
6070 const lookingForElseSave
= lookingForElse
;
6071 lookingForElse
= Loc
.initial
;
6074 //if (token.value == TOK.semicolon)
6075 // error("use `{ }` for an empty statement, not `;`");
6076 auto statements
= new AST
.Statements();
6077 while (token
.value
!= TOK
.rightCurly
&& token
.value
!= TOK
.endOfFile
)
6079 statements
.push(parseStatement(ParseStatementFlags
.curlyScope | ParseStatementFlags
.semiOk
));
6082 *endPtr
= token
.ptr
;
6086 *pEndloc
= token
.loc
;
6087 pEndloc
= null; // don't set it again
6089 s
= new AST
.CompoundStatement(loc
, statements
);
6090 if (flags
& (ParseStatementFlags
.scope_ | ParseStatementFlags
.curlyScope
))
6091 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6092 if (token
.value
!= TOK
.rightCurly
)
6094 error(token
.loc
, "matching `}` expected following compound statement, not `%s`",
6096 eSink
.errorSupplemental(lcLoc
, "unmatched `{`");
6100 lookingForElse
= lookingForElseSave
;
6106 check(TOK
.leftParenthesis
);
6107 auto param
= parseAssignCondition();
6108 auto condition
= parseExpression();
6109 closeCondition("while", param
, condition
);
6112 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6113 s
= new AST
.WhileStatement(loc
, condition
, _body
, endloc
, param
);
6117 if (!(flags
& ParseStatementFlags
.semiOk
))
6119 error("use `{ }` for an empty statement, not `;`");
6122 s
= new AST
.ExpStatement(loc
, cast(AST
.Expression
)null);
6127 AST
.Statement _body
;
6130 const lookingForElseSave
= lookingForElse
;
6131 lookingForElse
= Loc
.initial
;
6132 _body
= parseStatement(ParseStatementFlags
.scope_
);
6133 lookingForElse
= lookingForElseSave
;
6135 check(TOK
.leftParenthesis
);
6136 auto condition
= parseExpression();
6137 closeCondition("do .. while", null, condition
);
6138 if (token
.value
== TOK
.semicolon
)
6141 error("terminating `;` required after do-while statement");
6142 s
= new AST
.DoStatement(loc
, _body
, condition
, token
.loc
);
6147 AST
.Statement _init
;
6148 AST
.Expression condition
;
6149 AST
.Expression increment
;
6152 check(TOK
.leftParenthesis
);
6153 if (token
.value
== TOK
.semicolon
)
6160 const lookingForElseSave
= lookingForElse
;
6161 lookingForElse
= Loc
.initial
;
6162 _init
= parseStatement(0);
6163 lookingForElse
= lookingForElseSave
;
6165 if (token
.value
== TOK
.semicolon
)
6172 condition
= parseExpression();
6173 check(TOK
.semicolon
, "`for` condition");
6175 if (token
.value
== TOK
.rightParenthesis
)
6182 increment
= parseExpression();
6183 check(TOK
.rightParenthesis
);
6186 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6187 s
= new AST
.ForStatement(loc
, _init
, condition
, increment
, _body
, endloc
);
6191 case TOK
.foreach_reverse_
:
6193 s
= parseForeach
!(AST
.Statement
)(loc
, null);
6199 check(TOK
.leftParenthesis
);
6200 auto param
= parseAssignCondition();
6201 auto condition
= parseExpression();
6202 closeCondition("if", param
, condition
);
6205 const lookingForElseSave
= lookingForElse
;
6206 lookingForElse
= loc
;
6207 ifbody
= parseStatement(ParseStatementFlags
.scope_
);
6208 lookingForElse
= lookingForElseSave
;
6210 if (token
.value
== TOK
.else_
)
6212 const elseloc
= token
.loc
;
6214 elsebody
= parseStatement(ParseStatementFlags
.scope_
);
6215 checkDanglingElse(elseloc
);
6219 if (condition
&& ifbody
)
6220 s
= new AST
.IfStatement(loc
, param
, condition
, ifbody
, elsebody
, token
.loc
);
6222 s
= null; // don't propagate parsing errors
6227 error("found `else` without a corresponding `if`, `version` or `debug` statement");
6231 if (peekNext() != TOK
.leftParenthesis
)
6232 goto Ldeclaration
; // scope used as storage class
6234 check(TOK
.leftParenthesis
);
6235 if (token
.value
!= TOK
.identifier
)
6237 error("scope identifier expected");
6242 TOK t
= TOK
.onScopeExit
;
6243 Identifier id
= token
.ident
;
6245 t
= TOK
.onScopeExit
;
6246 else if (id
== Id
.failure
)
6247 t
= TOK
.onScopeFailure
;
6248 else if (id
== Id
.success
)
6249 t
= TOK
.onScopeSuccess
;
6251 error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id
.toChars());
6253 check(TOK
.rightParenthesis
);
6254 AST
.Statement st
= parseStatement(ParseStatementFlags
.scope_
);
6255 s
= new AST
.ScopeGuardStatement(loc
, t
, st
);
6261 if (token
.value
== TOK
.assign
)
6263 if (auto ds = parseDebugSpecification())
6266 eSink
.error(ds.loc
, "%s `%s` declaration must be at module level", ds.kind
, ds.toPrettyChars
);
6268 eSink
.error(ds.loc
, "%s `%s` level declaration must be at module level", ds.kind
, ds.toPrettyChars
);
6272 cond
= parseDebugCondition();
6277 if (token
.value
== TOK
.assign
)
6279 if (auto vs
= parseVersionSpecification())
6282 eSink
.error(vs
.loc
, "%s `%s` declaration must be at module level", vs
.kind
, vs
.toPrettyChars
);
6284 eSink
.error(vs
.loc
, "%s `%s` level declaration must be at module level", vs
.kind
, vs
.toPrettyChars
);
6288 cond
= parseVersionCondition();
6293 const lookingForElseSave
= lookingForElse
;
6294 lookingForElse
= loc
;
6295 ifbody
= parseStatement(0);
6296 lookingForElse
= lookingForElseSave
;
6299 if (token
.value
== TOK
.else_
)
6301 const elseloc
= token
.loc
;
6303 elsebody
= parseStatement(0);
6304 checkDanglingElse(elseloc
);
6306 s
= new AST
.ConditionalStatement(loc
, cond
, ifbody
, elsebody
);
6307 if (flags
& ParseStatementFlags
.scope_
)
6308 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6314 AST
.Expressions
* args
= null;
6315 AST
.Statement _body
;
6318 check(TOK
.leftParenthesis
);
6319 if (token
.value
!= TOK
.identifier
)
6321 error("`pragma(identifier)` expected");
6324 ident
= token
.ident
;
6326 if (token
.value
== TOK
.comma
&& peekNext() != TOK
.rightParenthesis
)
6327 args
= parseArguments(); // pragma(identifier, args...);
6329 check(TOK
.rightParenthesis
); // pragma(identifier);
6330 if (token
.value
== TOK
.semicolon
)
6336 _body
= parseStatement(0);
6337 s
= new AST
.PragmaStatement(loc
, ident
, args
, _body
);
6347 check(TOK
.leftParenthesis
);
6348 auto param
= parseAssignCondition();
6349 AST
.Expression condition
= parseExpression();
6350 closeCondition("switch", null, condition
);
6351 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
);
6352 s
= new AST
.SwitchStatement(loc
, param
, condition
, _body
, isfinal
, token
.loc
);
6358 AST
.Expressions cases
; // array of Expression's
6359 AST
.Expression last
= null;
6364 exp
= parseAssignExp();
6366 if (token
.value
!= TOK
.comma
)
6368 nextToken(); //comma
6370 while (token
.value
!= TOK
.colon
&& token
.value
!= TOK
.endOfFile
);
6373 /* case exp: .. case last:
6375 if (token
.value
== TOK
.slice
)
6377 if (cases
.length
> 1)
6378 error("only one `case` allowed for start of case range");
6381 last
= parseAssignExp();
6385 if (flags
& ParseStatementFlags
.curlyScope
)
6387 auto statements
= new AST
.Statements();
6388 while (token
.value
!= TOK
.case_
&& token
.value
!= TOK
.default_
&& token
.value
!= TOK
.endOfFile
&& token
.value
!= TOK
.rightCurly
)
6390 auto cur
= parseStatement(ParseStatementFlags
.curlyScope
);
6391 statements
.push(cur
);
6393 // https://issues.dlang.org/show_bug.cgi?id=21739
6394 // Stop at the last break s.t. the following non-case statements are
6395 // not merged into the current case. This can happen for
6396 // case 1: ... break;
6397 // debug { case 2: ... }
6398 if (cur
&& cur
.isBreakStatement())
6401 s
= new AST
.CompoundStatement(loc
, statements
);
6405 s
= parseStatement(0);
6407 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6411 s
= new AST
.CaseRangeStatement(loc
, exp
, last
, s
);
6415 // Keep cases in order by building the case statements backwards
6416 for (size_t i
= cases
.length
; i
; i
--)
6419 s
= new AST
.CaseStatement(loc
, exp
, s
);
6429 if (flags
& ParseStatementFlags
.curlyScope
)
6431 auto statements
= new AST
.Statements();
6432 while (token
.value
!= TOK
.case_
&& token
.value
!= TOK
.default_
&& token
.value
!= TOK
.endOfFile
&& token
.value
!= TOK
.rightCurly
)
6434 statements
.push(parseStatement(ParseStatementFlags
.curlyScope
));
6436 s
= new AST
.CompoundStatement(loc
, statements
);
6439 s
= parseStatement(0);
6440 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6441 s
= new AST
.DefaultStatement(loc
, s
);
6448 exp
= token
.value
== TOK
.semicolon ?
null : parseExpression();
6449 check(TOK
.semicolon
, "`return` statement");
6450 s
= new AST
.ReturnStatement(loc
, exp
);
6458 if (token
.value
== TOK
.identifier
)
6460 ident
= token
.ident
;
6463 check(TOK
.semicolon
, "`break` statement");
6464 s
= new AST
.BreakStatement(loc
, ident
);
6472 if (token
.value
== TOK
.identifier
)
6474 ident
= token
.ident
;
6477 check(TOK
.semicolon
, "`continue` statement");
6478 s
= new AST
.ContinueStatement(loc
, ident
);
6485 if (token
.value
== TOK
.default_
)
6488 s
= new AST
.GotoDefaultStatement(loc
);
6490 else if (token
.value
== TOK
.case_
)
6492 AST
.Expression exp
= null;
6494 if (token
.value
!= TOK
.semicolon
)
6495 exp
= parseExpression();
6496 s
= new AST
.GotoCaseStatement(loc
, exp
);
6500 if (token
.value
!= TOK
.identifier
)
6502 error("identifier expected following `goto`");
6507 ident
= token
.ident
;
6510 s
= new AST
.GotoStatement(loc
, ident
);
6512 check(TOK
.semicolon
, "`goto` statement");
6515 case TOK
.synchronized_
:
6518 AST
.Statement _body
;
6520 Token
* t
= peek(&token
);
6521 if (skipAttributes(t
, &t
) && t
.value
== TOK
.class_
)
6525 if (token
.value
== TOK
.leftParenthesis
)
6528 exp
= parseExpression();
6529 closeCondition("synchronized", null, exp
);
6533 _body
= parseStatement(ParseStatementFlags
.scope_
);
6534 s
= new AST
.SynchronizedStatement(loc
, exp
, _body
);
6540 AST
.Statement _body
;
6544 check(TOK
.leftParenthesis
);
6545 exp
= parseExpression();
6546 closeCondition("with", null, exp
);
6547 _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6548 s
= new AST
.WithStatement(loc
, exp
, _body
, endloc
);
6553 AST
.Statement _body
;
6554 AST
.Catches
* catches
= null;
6555 AST
.Statement finalbody
= null;
6558 const lookingForElseSave
= lookingForElse
;
6559 lookingForElse
= Loc
.initial
;
6560 _body
= parseStatement(ParseStatementFlags
.scope_
);
6561 lookingForElse
= lookingForElseSave
;
6562 while (token
.value
== TOK
.catch_
)
6564 AST
.Statement handler
;
6568 const catchloc
= token
.loc
;
6571 if (token
.value
!= TOK
.leftParenthesis
)
6573 deprecation("`catch` statement without an exception specification is deprecated");
6574 deprecationSupplemental("use `catch(Throwable)` for old behavior");
6580 check(TOK
.leftParenthesis
);
6583 check(TOK
.rightParenthesis
);
6585 handler
= parseStatement(0);
6586 c
= new AST
.Catch(catchloc
, t
, id
, handler
);
6588 catches
= new AST
.Catches();
6592 if (token
.value
== TOK
.finally_
)
6595 finalbody
= parseStatement(ParseStatementFlags
.scope_
);
6599 if (!catches
&& !finalbody
)
6600 error("`catch` or `finally` expected following `try`");
6604 s
= new AST
.TryCatchStatement(loc
, _body
, catches
);
6606 s
= new AST
.TryFinallyStatement(loc
, s
, finalbody
);
6614 exp
= parseExpression();
6615 check(TOK
.semicolon
, "`throw` statement");
6616 s
= new AST
.ThrowStatement(loc
, exp
);
6621 s
= parseAsm(false);
6626 /* https://issues.dlang.org/show_bug.cgi?id=16088
6628 * At this point it can either be an
6629 * https://dlang.org/spec/grammar.html#ImportExpression
6631 * https://dlang.org/spec/grammar.html#ImportDeclaration.
6632 * See if the next token after `import` is a `(`; if so,
6633 * then it is an import expression.
6635 if (peekNext() == TOK
.leftParenthesis
)
6637 AST
.Expression e
= parseExpression();
6638 check(TOK
.semicolon
, "`import` Expression");
6639 s
= new AST
.ExpStatement(loc
, e
);
6643 AST
.Dsymbols
* imports
= parseImport();
6644 s
= new AST
.ImportStatement(loc
, imports
);
6645 if (flags
& ParseStatementFlags
.scope_
)
6646 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6652 AST
.Dsymbol d
= parseTemplateDeclaration();
6653 s
= new AST
.ExpStatement(loc
, d
);
6657 error("found `%s` instead of statement", token
.toChars());
6661 while (token
.value
!= TOK
.rightCurly
&& token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
6663 if (token
.value
== TOK
.semicolon
)
6665 s
= new AST
.ErrorStatement
;
6674 private AST
.ExpInitializer
parseExpInitializer(Loc loc
)
6676 auto ae
= parseAssignExp();
6677 return new AST
.ExpInitializer(loc
, ae
);
6680 private AST
.Initializer
parseStructInitializer(Loc loc
)
6682 /* Scan ahead to discern between a struct initializer and
6683 * parameterless function literal.
6685 * We'll scan the topmost curly bracket level for statement-related
6686 * tokens, thereby ruling out a struct initializer. (A struct
6687 * initializer which itself contains function literals may have
6688 * statements at nested curly bracket levels.)
6690 * It's important that this function literal check not be
6691 * pendantic, otherwise a function having the slightest syntax
6692 * error would emit confusing errors when we proceed to parse it
6693 * as a struct initializer.
6695 * The following two ambiguous cases will be treated as a struct
6696 * initializer (best we can do without type info):
6698 * {{statements...}} - i.e. it could be struct initializer
6699 * with one function literal, or function literal having an
6700 * extra level of curly brackets
6701 * If a function literal is intended in these cases (unlikely),
6702 * source can use a more explicit function literal syntax
6703 * (e.g. prefix with "()" for empty parameter list).
6707 for (auto t
= peek(&token
); 1; t
= peek(t
))
6711 case TOK
.leftParenthesis
:
6714 case TOK
.rightParenthesis
:
6717 // https://issues.dlang.org/show_bug.cgi?id=21163
6718 // lambda params can have the `scope` storage class, e.g
6719 // `S s = { (scope Type Id){} }`
6721 if (!parens
) goto case;
6723 /* Look for a semicolon or keyword of statements which don't
6724 * require a semicolon (typically containing BlockStatement).
6725 * Tokens like "else", "catch", etc. are omitted where the
6726 * leading token of the statement is sufficient.
6733 case TOK
.interface_
:
6738 case TOK
.synchronized_
:
6745 return parseExpInitializer(loc
);
6752 case TOK
.rightCurly
:
6766 auto _is
= new AST
.StructInitializer(loc
);
6767 bool commaExpected
= false;
6771 switch (token
.value
)
6773 case TOK
.identifier
:
6777 error("comma expected separating field initializers");
6778 const t
= peek(&token
);
6780 if (t
.value
== TOK
.colon
)
6784 nextToken(); // skip over ':'
6786 auto value
= parseInitializer();
6787 _is
.addInit(id
, value
);
6788 commaExpected
= true;
6793 error("expression expected, not `,`");
6795 commaExpected
= false;
6798 case TOK
.rightCurly
: // allow trailing comma's
6803 error("found end of file instead of initializer");
6808 error("comma expected separating field initializers");
6809 auto value
= parseInitializer();
6810 _is
.addInit(null, value
);
6811 commaExpected
= true;
6820 /*****************************************
6821 * Parse initializer for variable declaration.
6823 private AST
.Initializer
parseInitializer()
6825 const loc
= token
.loc
;
6827 switch (token
.value
)
6830 return parseStructInitializer(loc
);
6832 case TOK
.leftBracket
:
6833 /* Scan ahead to see if it is an array initializer or
6835 * If it ends with a ';' ',' or ']', it is an array initializer.
6838 for (auto t
= peek(&token
); 1; t
= peek(t
))
6842 case TOK
.leftBracket
:
6846 case TOK
.rightBracket
:
6847 if (--brackets
== 0)
6850 if (t
.value
!= TOK
.semicolon
&& t
.value
!= TOK
.comma
&& t
.value
!= TOK
.rightBracket
&& t
.value
!= TOK
.rightCurly
)
6851 return parseExpInitializer(loc
);
6865 auto ia
= new AST
.ArrayInitializer(loc
);
6866 bool commaExpected
= false;
6871 switch (token
.value
)
6876 error("comma expected separating array initializers, not `%s`", token
.toChars());
6880 auto e
= parseAssignExp();
6884 AST
.Initializer value
;
6885 if (token
.value
== TOK
.colon
)
6888 value
= parseInitializer();
6892 value
= new AST
.ExpInitializer(e
.loc
, e
);
6895 ia
.addInit(e
, value
);
6896 commaExpected
= true;
6900 case TOK
.leftBracket
:
6902 error("comma expected separating array initializers, not `%s`", token
.toChars());
6903 auto value
= parseInitializer();
6906 if (token
.value
== TOK
.colon
)
6909 if (auto ei
= value
.isExpInitializer())
6912 value
= parseInitializer();
6915 error("initializer expression expected following colon, not `%s`", token
.toChars());
6917 ia
.addInit(e
, value
);
6918 commaExpected
= true;
6923 error("expression expected, not `,`");
6925 commaExpected
= false;
6928 case TOK
.rightBracket
: // allow trailing comma's
6933 error("found `%s` instead of array initializer", token
.toChars());
6941 const tv
= peekNext();
6942 if (tv
== TOK
.semicolon || tv
== TOK
.comma
)
6945 return new AST
.VoidInitializer(loc
);
6947 return parseExpInitializer(loc
);
6950 return parseExpInitializer(loc
);
6954 /********************
6955 * Parse inline assembler block.
6956 * Enters with token on the `asm`.
6957 * https://dlang.org/spec/iasm.html
6960 * asm FunctionAttributes(opt) { AsmInstructionListopt }
6961 * AsmInstructionList:
6963 * AsmInstruction ; AsmInstruction
6966 * endOfLine = true if EOL means end of asm statement
6968 * inline assembler block as a Statement
6970 AST
.Statement
parseAsm(bool endOfLine
)
6972 // Parse the asm block into a sequence of AsmStatements,
6973 // each AsmStatement is one instruction.
6974 // Separate out labels.
6975 // Defer parsing of AsmStatements until semantic processing.
6977 const loc
= token
.loc
;
6981 StorageClass
stc = parsePostfix(STC
.undefined_
, null); // optional FunctionAttributes
6982 if (stc & (STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.wild
))
6983 error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
6985 check(TOK
.leftCurly
);
6986 Token
* toklist
= null;
6987 Token
** ptoklist
= &toklist
;
6988 Identifier label
= null;
6989 auto statements
= new AST
.Statements();
6990 size_t nestlevel
= 0;
6995 switch (token
.value
)
6997 case TOK
.identifier
:
7000 // Look ahead to see if it is a label
7001 if (peekNext() == TOK
.colon
)
7004 label
= token
.ident
;
7005 labelloc
= token
.loc
;
7017 case TOK
.rightCurly
:
7023 if (toklist || label
)
7025 error("`asm` statements must end in `;`");
7035 error("mismatched number of curly brackets");
7037 if (toklist || label
)
7039 // Create AsmStatement from list of tokens we've saved
7040 AST
.AsmStatement as
= new AST
.AsmStatement(token
.loc
, toklist
);
7041 as
.caseSensitive
= !endOfLine
;
7042 AST
.Statement s
= as
;
7044 ptoklist
= &toklist
;
7047 s
= new AST
.LabelStatement(labelloc
, label
, s
);
7057 error("matching `}` expected, not end of file");
7060 case TOK
.colonColon
: // treat as two separate : tokens for iasmgcc
7061 *ptoklist
= allocateToken();
7062 memcpy(*ptoklist
, &token
, Token
.sizeof
);
7063 (*ptoklist
).value
= TOK
.colon
;
7064 ptoklist
= &(*ptoklist
).next
;
7066 *ptoklist
= allocateToken();
7067 memcpy(*ptoklist
, &token
, Token
.sizeof
);
7068 (*ptoklist
).value
= TOK
.colon
;
7069 ptoklist
= &(*ptoklist
).next
;
7076 *ptoklist
= allocateToken();
7077 memcpy(*ptoklist
, &token
, Token
.sizeof
);
7078 ptoklist
= &(*ptoklist
).next
;
7086 if (token
.value
== TOK
.endOfLine
)
7088 auto s
= new AST
.CompoundAsmStatement(loc
, statements
, stc);
7092 /**********************************
7093 * Issue error if the current token is not `value`,
7094 * advance to next token.
7096 * loc = location for error message
7097 * value = token value to compare with
7099 void check(Loc loc
, TOK value
)
7101 if (token
.value
!= value
)
7102 error(loc
, "found `%s` when expecting `%s`", token
.toChars(), Token
.toChars(value
));
7106 /**********************************
7107 * Issue error if the current token is not `value`,
7108 * advance to next token.
7110 * value = token value to compare with
7112 void check(TOK value
)
7114 check(token
.loc
, value
);
7117 /**********************************
7118 * Issue error if the current token is not `value`,
7119 * advance to next token.
7121 * value = token value to compare with
7122 * string = for error message
7124 void check(TOK value
, const(char)* string
)
7126 if (token
.value
!= value
)
7127 error(token
.loc
, "found `%s` when expecting `%s` following %s", token
.toChars(), Token
.toChars(value
), string
);
7131 private void checkParens(TOK value
, AST
.Expression e
)
7133 if (precedence
[e
.op
] == PREC
.rel
)
7134 error(e
.loc
, "`%s` must be surrounded by parentheses when next to operator `%s`", e
.toChars(), Token
.toChars(value
));
7138 enum NeedDeclaratorId
7140 no
, // Declarator part must have no identifier
7141 opt
, // Declarator part identifier is optional
7142 must
, // Declarator part must have identifier
7143 mustIfDstyle
, // Declarator part must have identifier, but don't recognize old C-style syntax
7146 /************************************
7147 * Determine if the scanner is sitting on the start of a declaration.
7149 * t = current token of the scanner
7150 * needId = flag with additional requirements for a declaration
7151 * endtok = ending token
7152 * pt = will be set ending token (if not null)
7154 * true if the token `t` is a declaration, false otherwise
7156 private bool isDeclaration(Token
* t
, NeedDeclaratorId needId
, TOK endtok
, Token
** pt
)
7158 //printf("isDeclaration(needId = %d)\n", needId);
7164 if ((t
.value
== TOK
.const_ || t
.value
== TOK
.immutable_ || t
.value
== TOK
.inout_ || t
.value
== TOK
.shared_
) && peek(t
).value
!= TOK
.leftParenthesis
)
7177 if (!isBasicType(&t
))
7181 if (!isDeclarator(&t
, &haveId
, &haveTpl
, endtok
, needId
!= NeedDeclaratorId
.mustIfDstyle
))
7183 if ((needId
== NeedDeclaratorId
.no
&& !haveId
) ||
7184 (needId
== NeedDeclaratorId
.opt
) ||
7185 (needId
== NeedDeclaratorId
.must
&& haveId
) ||
7186 (needId
== NeedDeclaratorId
.mustIfDstyle
&& haveId
))
7195 //printf("\tis declaration, t = %s\n", t.toChars());
7199 //printf("\tis not declaration\n");
7203 // pt = test token. If found, pt is set to the token after BasicType
7204 private bool isBasicType(Token
** pt
)
7206 // This code parallels parseBasicType()
7227 case TOK
.imaginary32
:
7228 case TOK
.imaginary64
:
7229 case TOK
.imaginary80
:
7237 case TOK
.identifier
:
7240 if (t
.value
== TOK
.not)
7250 if (t
.value
== TOK
.dot
)
7254 if (t
.value
!= TOK
.identifier
)
7257 if (t
.value
!= TOK
.not)
7262 * !( args ), !identifier, etc.
7267 case TOK
.identifier
:
7270 case TOK
.leftParenthesis
:
7271 if (!skipParens(t
, &t
))
7292 case TOK
.imaginary32
:
7293 case TOK
.imaginary64
:
7294 case TOK
.imaginary80
:
7299 case TOK
.int32Literal
:
7300 case TOK
.uns32Literal
:
7301 case TOK
.int64Literal
:
7302 case TOK
.uns64Literal
:
7303 case TOK
.int128Literal
:
7304 case TOK
.uns128Literal
:
7305 case TOK
.float32Literal
:
7306 case TOK
.float64Literal
:
7307 case TOK
.float80Literal
:
7308 case TOK
.imaginary32Literal
:
7309 case TOK
.imaginary64Literal
:
7310 case TOK
.imaginary80Literal
:
7314 case TOK
.charLiteral
:
7315 case TOK
.wcharLiteral
:
7316 case TOK
.dcharLiteral
:
7318 case TOK
.interpolated
:
7319 case TOK
.hexadecimalString
:
7321 case TOK
.fileFullPath
:
7323 case TOK
.moduleString
:
7324 case TOK
.functionString
:
7325 case TOK
.prettyFunction
:
7342 /* typeof(exp).identifier...
7345 if (!skipParens(t
, &t
))
7350 // __traits(getMember
7352 if (t
.value
!= TOK
.leftParenthesis
)
7356 if (t
.value
!= TOK
.identifier || t
.ident
!= Id
.getMember
)
7358 if (!skipParens(lp
, &lp
))
7360 // we are in a lookup for decl VS statement
7361 // so we expect a declarator following __trait if it's a type.
7362 // other usages wont be ambiguous (alias, template instance, type qual, etc.)
7363 if (lp
.value
!= TOK
.identifier
)
7369 case TOK
.immutable_
:
7372 // const(type) or immutable(type) or shared(type) or wild(type)
7374 if (t
.value
!= TOK
.leftParenthesis
)
7377 if (!isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &t
))
7392 //printf("is not\n");
7396 private bool isDeclarator(Token
** pt
, int* haveId
, int* haveTpl
, TOK endtok
, bool allowAltSyntax
= true)
7398 // This code parallels parseDeclarator()
7402 //printf("Parser::isDeclarator() %s\n", t.toChars());
7403 if (t
.value
== TOK
.assign
)
7416 case TOK
.leftBracket
:
7418 if (t
.value
== TOK
.rightBracket
)
7422 else if (isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightBracket
, &t
))
7424 // It's an associative array declaration
7428 if (t
.value
== TOK
.dot
&& peek(t
).value
== TOK
.identifier
)
7437 // [ expression .. expression ]
7438 if (!isExpression(&t
))
7440 if (t
.value
== TOK
.slice
)
7443 if (!isExpression(&t
))
7445 if (t
.value
!= TOK
.rightBracket
)
7451 if (t
.value
!= TOK
.rightBracket
)
7455 if (t
.value
== TOK
.dot
&& peek(t
).value
== TOK
.identifier
)
7464 case TOK
.identifier
:
7471 case TOK
.leftParenthesis
:
7472 if (!allowAltSyntax
)
7473 return false; // Do not recognize C-style declarations.
7476 if (t
.value
== TOK
.rightParenthesis
)
7477 return false; // () is not a declarator
7479 /* Regard ( identifier ) as not a declarator
7480 * BUG: what about ( *identifier ) in
7482 * where f is a class instance with overloaded () ?
7483 * Should we just disallow C-style function pointer declarations?
7485 if (t
.value
== TOK
.identifier
)
7487 Token
* t2
= peek(t
);
7488 if (t2
.value
== TOK
.rightParenthesis
)
7492 if (!isDeclarator(&t
, haveId
, null, TOK
.rightParenthesis
))
7501 if (!isParameters(&t
))
7503 skipAttributes(t
, &t
);
7516 static if (CARRAYDECL
)
7518 case TOK
.leftBracket
:
7521 if (t
.value
== TOK
.rightBracket
)
7525 else if (isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightBracket
, &t
))
7527 // It's an associative array declaration
7533 if (!isExpression(&t
))
7535 if (t
.value
!= TOK
.rightBracket
)
7542 case TOK
.leftParenthesis
:
7544 if (Token
* tk
= peekPastParen(t
))
7546 if (tk
.value
== TOK
.leftParenthesis
)
7553 else if (tk
.value
== TOK
.assign
)
7562 if (!isParameters(&t
))
7569 case TOK
.immutable_
:
7580 t
= peek(t
); // skip '@'
7581 t
= peek(t
); // skip identifier
7591 // Valid tokens that follow the start of a declaration
7592 case TOK
.rightParenthesis
:
7593 case TOK
.rightBracket
:
7602 // The !parens is to disallow unnecessary parentheses
7603 if (!parens
&& (endtok
== TOK
.reserved || endtok
== t
.value
))
7610 // To recognize the shortened function declaration syntax
7613 1. https://issues.dlang.org/show_bug.cgi?id=24088
7615 2. We need to make sure the would-be
7616 declarator has an identifier otherwise function literals
7617 are handled incorrectly. Some special treatment is required
7618 here, it turns out that a lot of code in the compiler relies
7619 on this mess (in the parser), i.e. having isDeclarator be more
7620 precise the parsing of other things go kaboom, so we do it in a
7627 case TOK
.identifier
:
7628 if (t
.ident
== Id
._body
)
7630 usageOfBodyKeyword();
7636 return haveTpl ?
true : false;
7638 // Used for mixin type parsing
7640 if (endtok
== TOK
.endOfFile
)
7651 private bool isParameters(Token
** pt
)
7653 // This code parallels parseParameterList()
7656 //printf("isParameters()\n");
7657 if (t
.value
!= TOK
.leftParenthesis
)
7661 for (; 1; t
= peek(t
))
7666 case TOK
.rightParenthesis
:
7671 if (skipAttributes(t
, &pastAttr
))
7693 case TOK
.immutable_
:
7697 if (t
.value
== TOK
.leftParenthesis
)
7700 if (!isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &t
))
7702 t
= peek(t
); // skip past closing ')'
7709 if (!isBasicType(&t
))
7713 if (t
.value
!= TOK
.dotDotDot
&& !isDeclarator(&t
, &tmp
, null, TOK
.reserved
))
7715 if (t
.value
== TOK
.assign
)
7718 if (!isExpression(&t
))
7721 if (t
.value
== TOK
.dotDotDot
)
7727 if (t
.value
== TOK
.comma
)
7735 if (t
.value
!= TOK
.rightParenthesis
)
7742 private bool isExpression(Token
** pt
)
7744 // This is supposed to determine if something is an expression.
7745 // What it actually does is scan until a closing right bracket
7753 for (;; t
= peek(t
))
7757 case TOK
.leftBracket
:
7761 case TOK
.rightBracket
:
7766 case TOK
.leftParenthesis
:
7771 if (brnest || panest
)
7775 case TOK
.rightParenthesis
:
7784 case TOK
.rightCurly
:
7785 if (--curlynest
>= 0)
7812 /*******************************************
7815 * t = on opening $(LPAREN)
7816 * pt = *pt is set to token past '$(RPAREN)' on true
7819 * false some parsing error
7821 bool skipParens(Token
* t
, Token
** pt
)
7823 if (t
.value
!= TOK
.leftParenthesis
)
7832 case TOK
.leftParenthesis
:
7836 case TOK
.rightParenthesis
:
7854 *pt
= peek(t
); // skip found rparen
7861 private bool skipParensIf(Token
* t
, Token
** pt
)
7863 if (t
.value
!= TOK
.leftParenthesis
)
7869 return skipParens(t
, pt
);
7872 //returns true if the next value (after optional matching parens) is expected
7873 private bool hasOptionalParensThen(Token
* t
, TOK expected
)
7876 if (!skipParensIf(t
, &tk
))
7878 return tk
.value
== expected
;
7881 /*******************************************
7884 * t is on a candidate attribute
7886 * *pt is set to first non-attribute token on success
7889 * false some parsing error
7891 private bool skipAttributes(Token
* t
, Token
** pt
)
7898 case TOK
.immutable_
:
7906 case TOK
.synchronized_
:
7909 case TOK
.deprecated_
:
7910 if (peek(t
).value
== TOK
.leftParenthesis
)
7913 if (!skipParens(t
, &t
))
7915 // t is on the next of closing parenthesis
7929 if (t
.value
== TOK
.identifier
)
7933 * @identifier!(arglist)
7934 * any of the above followed by (arglist)
7935 * @predefined_attribute
7937 if (isBuiltinAtAttribute(t
.ident
))
7940 if (t
.value
== TOK
.not)
7943 if (t
.value
== TOK
.leftParenthesis
)
7945 // @identifier!(arglist)
7946 if (!skipParens(t
, &t
))
7948 // t is on the next of closing parenthesis
7953 // Do low rent skipTemplateArgument
7954 if (t
.value
== TOK
.vector
)
7956 // identifier!__vector(type)
7958 if (!skipParens(t
, &t
))
7965 if (t
.value
== TOK
.leftParenthesis
)
7967 if (!skipParens(t
, &t
))
7969 // t is on the next of closing parenthesis
7974 if (t
.value
== TOK
.leftParenthesis
)
7976 // @( ArgumentList )
7977 if (!skipParens(t
, &t
))
7979 // t is on the next of closing parenthesis
7998 AST
.Expression
parseExpression()
8000 auto loc
= token
.loc
;
8002 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
8003 auto e
= parseAssignExp();
8004 while (token
.value
== TOK
.comma
)
8007 auto e2
= parseAssignExp();
8008 e
= new AST
.CommaExp(loc
, e
, e2
, false);
8014 /********************************* Expression Parser ***************************/
8016 AST
.Expression
parsePrimaryExp()
8021 const loc
= token
.loc
;
8023 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
8024 switch (token
.value
)
8026 case TOK
.identifier
:
8028 if (peekNext() == TOK
.arrow
)
8030 // skip `identifier ->`
8033 error("use `.` for member lookup, not `->`");
8037 if (peekNext() == TOK
.goesTo
)
8043 if (token
.value
== TOK
.not && (save
= peekNext()) != TOK
.is_
&& save
!= TOK
.in_
)
8045 // identifier!(template-argument-list)
8046 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
8047 e
= new AST
.ScopeExp(loc
, tempinst
);
8050 e
= new AST
.IdentifierExp(loc
, id
);
8055 error("`$` is valid only inside [] of index or slice");
8056 e
= new AST
.DollarExp(loc
);
8061 // Signal global scope '.' operator with "" identifier
8062 e
= new AST
.IdentifierExp(loc
, Id
.empty
);
8066 e
= new AST
.ThisExp(loc
);
8071 e
= new AST
.SuperExp(loc
);
8075 case TOK
.int32Literal
:
8076 e
= new AST
.IntegerExp(loc
, token
.intvalue
, AST
.Type
.tint32
);
8080 case TOK
.uns32Literal
:
8081 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tuns32
);
8085 case TOK
.int64Literal
:
8086 e
= new AST
.IntegerExp(loc
, token
.intvalue
, AST
.Type
.tint64
);
8090 case TOK
.uns64Literal
:
8091 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tuns64
);
8095 case TOK
.float32Literal
:
8096 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat32
);
8100 case TOK
.float64Literal
:
8101 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat64
);
8105 case TOK
.float80Literal
:
8106 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat80
);
8110 case TOK
.imaginary32Literal
:
8111 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary32
);
8115 case TOK
.imaginary64Literal
:
8116 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary64
);
8120 case TOK
.imaginary80Literal
:
8121 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary80
);
8126 e
= new AST
.NullExp(loc
);
8131 e
= new AST
.FileInitExp(loc
, EXP
.file
);
8134 case TOK
.fileFullPath
:
8135 e
= new AST
.FileInitExp(loc
, EXP
.fileFullPath
);
8140 e
= new AST
.LineInitExp(loc
);
8144 case TOK
.moduleString
:
8145 e
= new AST
.ModuleInitExp(loc
);
8148 case TOK
.functionString
:
8149 e
= new AST
.FuncInitExp(loc
);
8153 case TOK
.prettyFunction
:
8154 e
= new AST
.PrettyFuncInitExp(loc
);
8159 e
= new AST
.IntegerExp(loc
, 1, AST
.Type
.tbool
);
8164 e
= new AST
.IntegerExp(loc
, 0, AST
.Type
.tbool
);
8168 case TOK
.charLiteral
:
8169 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tchar
);
8173 case TOK
.wcharLiteral
:
8174 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.twchar
);
8178 case TOK
.dcharLiteral
:
8179 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tdchar
);
8183 case TOK
.interpolated
:
8184 e
= new AST
.InterpExp(loc
, token
.interpolatedSet
, token
.postfix
);
8189 case TOK
.hexadecimalString
:
8190 const bool hexString
= token
.value
== TOK
.hexadecimalString
;
8192 // cat adjacent strings
8193 auto s
= token
.ustring
;
8194 auto len
= token
.len
;
8195 auto postfix
= token
.postfix
;
8200 if (token
.value
== TOK
.string_ || token
.value
== TOK
.hexadecimalString
)
8204 if (token
.postfix
!= postfix
)
8205 error(token
.loc
, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix
, token
.postfix
);
8206 postfix
= token
.postfix
;
8209 error("implicit string concatenation is error-prone and disallowed in D");
8210 eSink
.errorSupplemental(token
.loc
, "Use the explicit syntax instead " ~
8211 "(concatenating literals is `@nogc`): %s ~ %s",
8212 prev
.toChars(), token
.toChars());
8215 const len2
= token
.len
;
8217 auto s2
= cast(char*)mem
.xmalloc_noscan(len
* char.sizeof
);
8218 memcpy(s2
, s
, len1
* char.sizeof
);
8219 memcpy(s2
+ len1
, token
.ustring
, len2
* char.sizeof
);
8225 e
= new AST
.StringExp(loc
, s
[0 .. len
], len
, 1, postfix
);
8226 e
.isStringExp().hexString
= hexString
;
8242 t
= AST
.Type
.tint16
;
8246 t
= AST
.Type
.tuns16
;
8250 t
= AST
.Type
.tint32
;
8254 t
= AST
.Type
.tuns32
;
8258 t
= AST
.Type
.tint64
;
8262 t
= AST
.Type
.tuns64
;
8266 t
= AST
.Type
.tint128
;
8270 t
= AST
.Type
.tuns128
;
8274 t
= AST
.Type
.tfloat32
;
8278 t
= AST
.Type
.tfloat64
;
8282 t
= AST
.Type
.tfloat80
;
8285 case TOK
.imaginary32
:
8286 t
= AST
.Type
.timaginary32
;
8289 case TOK
.imaginary64
:
8290 t
= AST
.Type
.timaginary64
;
8293 case TOK
.imaginary80
:
8294 t
= AST
.Type
.timaginary80
;
8298 t
= AST
.Type
.tcomplex32
;
8302 t
= AST
.Type
.tcomplex64
;
8306 t
= AST
.Type
.tcomplex80
;
8318 t
= AST
.Type
.twchar
;
8322 t
= AST
.Type
.tdchar
;
8325 const next
= peekNext();
8326 if (next
!= TOK
.leftParenthesis
&& next
!= TOK
.dot
)
8328 // defer error for better diagnostics
8329 e
= new AST
.TypeExp(loc
, parseType
);
8333 if (token
.value
== TOK
.leftParenthesis
)
8335 e
= new AST
.TypeExp(loc
, t
);
8336 e
= new AST
.CallExp(loc
, e
, parseArguments());
8340 if (token
.value
!= TOK
.identifier
)
8342 error(token
.loc
, "found `%s` when expecting identifier following `%s`.", token
.toChars(), t
.toChars());
8345 e
= new AST
.DotIdExp(loc
, new AST
.TypeExp(loc
, t
), token
.ident
);
8352 e
= new AST
.TypeExp(loc
, t
);
8358 e
= new AST
.TypeExp(loc
, t
);
8364 check(TOK
.leftParenthesis
, "`typeid`");
8365 RootObject o
= parseTypeOrAssignExp();
8366 check(TOK
.rightParenthesis
);
8367 e
= new AST
.TypeidExp(loc
, o
);
8372 /* __traits(identifier, args...)
8375 AST
.Objects
* args
= null;
8378 check(TOK
.leftParenthesis
);
8379 if (token
.value
!= TOK
.identifier
)
8381 error("`__traits(identifier, args...)` expected");
8384 ident
= token
.ident
;
8386 if (token
.value
== TOK
.comma
)
8387 args
= parseTemplateArgumentList(); // __traits(identifier, args...)
8389 check(TOK
.rightParenthesis
); // __traits(identifier)
8391 e
= new AST
.TraitsExp(loc
, ident
, args
);
8397 Identifier ident
= null;
8398 AST
.Type tspec
= null;
8399 TOK tok
= TOK
.reserved
;
8400 TOK tok2
= TOK
.reserved
;
8401 AST
.TemplateParameters
* tpl
= null;
8404 if (token
.value
!= TOK
.leftParenthesis
)
8406 error("expected `(` following `is`, not `%s`", token
.toChars());
8412 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.leftParenthesis
)
8414 error(loc
, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token
.toChars());
8416 Token
* tempTok
= peekPastParen(&token
);
8417 memcpy(&token
, tempTok
, Token
.sizeof
);
8420 targ
= parseType(&ident
);
8421 if (token
.value
== TOK
.colon || token
.value
== TOK
.equal
)
8425 if (tok
== TOK
.equal
&& (token
.value
== TOK
.struct_ || token
.value
== TOK
.union_
8426 || token
.value
== TOK
.class_ || token
.value
== TOK
.super_ || token
.value
== TOK
.enum_
8427 || token
.value
== TOK
.interface_ || token
.value
== TOK
.package_ || token
.value
== TOK
.module_
8428 || token
.value
== TOK
.argumentTypes || token
.value
== TOK
.parameters
8429 || token
.value
== TOK
.const_
&& peekNext() == TOK
.rightParenthesis
8430 || token
.value
== TOK
.immutable_
&& peekNext() == TOK
.rightParenthesis
8431 || token
.value
== TOK
.shared_
&& peekNext() == TOK
.rightParenthesis
8432 || token
.value
== TOK
.inout_
&& peekNext() == TOK
.rightParenthesis || token
.value
== TOK
.function_
8433 || token
.value
== TOK
.delegate_ || token
.value
== TOK
.return_
8434 ||
(token
.value
== TOK
.vector
&& peekNext() == TOK
.rightParenthesis
)))
8441 tspec
= parseType();
8446 if (token
.value
== TOK
.comma
)
8447 tpl
= parseTemplateParameterList(1);
8450 tpl
= new AST
.TemplateParameters();
8451 check(TOK
.rightParenthesis
);
8455 check(TOK
.rightParenthesis
);
8457 e
= new AST
.IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
8462 // https://dlang.org/spec/expression.html#assert_expressions
8463 AST
.Expression msg
= null;
8466 check(TOK
.leftParenthesis
, "`assert`");
8467 e
= parseAssignExp();
8468 if (token
.value
== TOK
.comma
)
8471 if (token
.value
!= TOK
.rightParenthesis
)
8473 msg
= parseAssignExp();
8474 if (token
.value
== TOK
.comma
)
8478 check(TOK
.rightParenthesis
);
8479 e
= new AST
.AssertExp(loc
, e
, msg
);
8484 // https://dlang.org/spec/expression.html#mixin_expressions
8486 if (token
.value
!= TOK
.leftParenthesis
)
8487 error(token
.loc
, "found `%s` when expecting `%s` following `mixin`", token
.toChars(), Token
.toChars(TOK
.leftParenthesis
));
8488 auto exps
= parseArguments();
8489 e
= new AST
.MixinExp(loc
, exps
);
8495 check(TOK
.leftParenthesis
, "`import`");
8496 e
= parseAssignExp();
8497 check(TOK
.rightParenthesis
);
8498 e
= new AST
.ImportExp(loc
, e
);
8502 e
= parseNewExp(null);
8507 if (peekNext() == TOK
.ref_
&& peekNext2() == TOK
.leftParenthesis
)
8509 Token
* tk
= peekPastParen(peek(peek(&token
)));
8510 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8512 // auto ref (arguments) => expression
8513 // auto ref (arguments) { statements... }
8518 error("found `%s` when expecting `ref` and function literal following `auto`", token
.toChars());
8523 if (peekNext() == TOK
.leftParenthesis
)
8525 Token
* tk
= peekPastParen(peek(&token
));
8526 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8528 // ref (arguments) => expression
8529 // ref (arguments) { statements... }
8534 error("found `%s` when expecting function literal following `ref`", token
.toChars());
8537 case TOK
.leftParenthesis
:
8539 Token
* tk
= peekPastParen(&token
);
8540 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8542 // (arguments) => expression
8543 // (arguments) { statements... }
8549 e
= parseExpression();
8550 check(loc
, TOK
.rightParenthesis
);
8553 case TOK
.leftBracket
:
8555 /* Parse array literals and associative array literals:
8556 * [ value, value, value ... ]
8557 * [ key:value, key:value, key:value ... ]
8559 auto values
= new AST
.Expressions();
8560 AST
.Expressions
* keys
= null;
8563 while (token
.value
!= TOK
.rightBracket
&& token
.value
!= TOK
.endOfFile
)
8565 e
= parseAssignExp();
8566 if (token
.value
== TOK
.colon
&& (keys || values
.length
== 0))
8570 keys
= new AST
.Expressions();
8572 e
= parseAssignExp();
8576 error("`key:value` expected for associative array literal");
8580 if (token
.value
== TOK
.rightBracket
)
8584 check(loc
, TOK
.rightBracket
);
8587 e
= new AST
.AssocArrayLiteralExp(loc
, keys
, values
);
8589 e
= new AST
.ArrayLiteralExp(loc
, null, values
);
8597 AST
.Dsymbol s
= parseFunctionLiteral();
8598 e
= new AST
.FuncExp(loc
, s
);
8603 error("expression expected, not `%s`", token
.toChars());
8605 // Anything for e, as long as it's not NULL
8606 e
= new AST
.IntegerExp(loc
, 0, AST
.Type
.tint32
);
8613 private AST
.Expression
parseUnaryExp()
8616 const loc
= token
.loc
;
8618 switch (token
.value
)
8622 e
= parseUnaryExp();
8623 e
= new AST
.AddrExp(loc
, e
);
8628 e
= parseUnaryExp();
8629 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8630 e
= new AST
.PreExp(EXP
.prePlusPlus
, loc
, e
);
8633 case TOK
.minusMinus
:
8635 e
= parseUnaryExp();
8636 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8637 e
= new AST
.PreExp(EXP
.preMinusMinus
, loc
, e
);
8642 e
= parseUnaryExp();
8643 e
= new AST
.PtrExp(loc
, e
);
8648 e
= parseUnaryExp();
8649 e
= new AST
.NegExp(loc
, e
);
8654 e
= parseUnaryExp();
8655 e
= new AST
.UAddExp(loc
, e
);
8660 e
= parseUnaryExp();
8661 e
= new AST
.NotExp(loc
, e
);
8666 e
= parseUnaryExp();
8667 e
= new AST
.ComExp(loc
, e
);
8671 // @@@DEPRECATED_2.109@@@
8672 // Use of `delete` keyword has been an error since 2.099.
8673 // Remove from the parser after 2.109.
8675 e
= parseUnaryExp();
8676 e
= new AST
.DeleteExp(loc
, e
, false);
8679 case TOK
.cast_
: // cast(type) expression
8682 check(TOK
.leftParenthesis
);
8683 /* Look for cast(), cast(const), cast(immutable),
8684 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
8689 switch (token
.value
)
8692 if (peekNext() == TOK
.leftParenthesis
)
8693 break; // const as type constructor
8694 m |
= MODFlags
.const_
; // const as storage class
8698 case TOK
.immutable_
:
8699 if (peekNext() == TOK
.leftParenthesis
)
8701 m |
= MODFlags
.immutable_
;
8706 if (peekNext() == TOK
.leftParenthesis
)
8708 m |
= MODFlags
.shared_
;
8713 if (peekNext() == TOK
.leftParenthesis
)
8724 if (token
.value
== TOK
.rightParenthesis
)
8727 e
= parseUnaryExp();
8728 e
= new AST
.CastExp(loc
, e
, m
);
8732 AST
.Type t
= parseType(); // cast( type )
8733 t
= t
.addMod(m
); // cast( const type )
8734 check(TOK
.rightParenthesis
);
8735 e
= parseUnaryExp();
8736 e
= new AST
.CastExp(loc
, e
, t
);
8743 case TOK
.immutable_
: // immutable(type)(arguments) / immutable(type).init
8745 StorageClass
stc = parseTypeCtor();
8747 AST
.Type t
= parseBasicType();
8750 if (stc == 0 && token
.value
== TOK
.dot
)
8753 if (token
.value
!= TOK
.identifier
)
8755 error("identifier expected following `%s.`, not `%s`",
8756 t
.toChars(), token
.toChars());
8757 return AST
.ErrorExp
.get();
8759 e
= new AST
.DotIdExp(loc
, new AST
.TypeExp(loc
, t
), token
.ident
);
8761 e
= parsePostExp(e
);
8765 e
= new AST
.TypeExp(loc
, t
);
8766 if (token
.value
!= TOK
.leftParenthesis
)
8768 error("`(arguments)` expected following `%s`, not `%s`",
8769 t
.toChars(), token
.toChars());
8772 e
= new AST
.CallExp(loc
, e
, parseArguments());
8776 case TOK
.leftParenthesis
:
8778 auto tk
= peek(&token
);
8779 static if (CCASTSYNTAX
)
8782 if (isDeclaration(tk
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &tk
))
8784 tk
= peek(tk
); // skip over right parenthesis
8789 if (tk
.value
== TOK
.is_ || tk
.value
== TOK
.in_
) // !is or !in
8795 case TOK
.minusMinus
:
8798 case TOK
.leftParenthesis
:
8799 case TOK
.identifier
:
8802 case TOK
.int32Literal
:
8803 case TOK
.uns32Literal
:
8804 case TOK
.int64Literal
:
8805 case TOK
.uns64Literal
:
8806 case TOK
.int128Literal
:
8807 case TOK
.uns128Literal
:
8808 case TOK
.float32Literal
:
8809 case TOK
.float64Literal
:
8810 case TOK
.float80Literal
:
8811 case TOK
.imaginary32Literal
:
8812 case TOK
.imaginary64Literal
:
8813 case TOK
.imaginary80Literal
:
8817 case TOK
.charLiteral
:
8818 case TOK
.wcharLiteral
:
8819 case TOK
.dcharLiteral
:
8821 case TOK
.interpolated
:
8828 case TOK
.fileFullPath
:
8830 case TOK
.moduleString
:
8831 case TOK
.functionString
:
8832 case TOK
.prettyFunction
:
8850 case TOK
.imaginary32
:
8851 case TOK
.imaginary64
:
8852 case TOK
.imaginary80
:
8860 // Note: `t` may be an expression that looks like a type
8861 auto t
= parseType();
8862 check(TOK
.rightParenthesis
);
8865 // or .identifier!( ... )
8866 if (token
.value
== TOK
.dot
)
8868 if (peekNext() != TOK
.identifier
&& peekNext() != TOK
.new_
)
8870 error("identifier or new keyword expected following `(...)`.");
8872 return AST
.ErrorExp
.get();
8874 auto te
= new AST
.TypeExp(loc
, t
);
8876 e
= parsePostExp(te
);
8878 else if (token
.value
== TOK
.leftParenthesis ||
8879 token
.value
== TOK
.plusPlus || token
.value
== TOK
.minusMinus
)
8884 auto te
= new AST
.TypeExp(loc
, t
);
8886 e
= parsePostExp(te
);
8890 e
= parseUnaryExp();
8891 e
= new AST
.CastExp(loc
, e
, t
);
8892 error(loc
, "C style cast illegal, use `%s`", e
.toChars());
8901 e
= parsePrimaryExp();
8902 e
= parsePostExp(e
);
8908 // Deviation from the DIP:
8909 // Parse AssignExpression instead of Expression to avoid conflicts for comma
8910 // separated lists, e.g. function arguments
8911 AST
.Expression exp
= parseAssignExp();
8912 e
= new AST
.ThrowExp(loc
, exp
);
8917 e
= parsePrimaryExp();
8918 e
= parsePostExp(e
);
8923 // ^^ is right associative and has higher precedence than the unary operators
8924 while (token
.value
== TOK
.pow
)
8927 AST
.Expression e2
= parseUnaryExp();
8928 e
= new AST
.PowExp(loc
, e
, e2
);
8934 private AST
.Expression
parsePostExp(AST
.Expression e
)
8938 const loc
= token
.loc
;
8939 switch (token
.value
)
8943 if (token
.value
== TOK
.identifier
)
8945 Identifier id
= token
.ident
;
8948 if (token
.value
== TOK
.not && peekNext() != TOK
.is_
&& peekNext() != TOK
.in_
)
8950 AST
.Objects
* tiargs
= parseTemplateArguments();
8951 e
= new AST
.DotTemplateInstanceExp(loc
, e
, id
, tiargs
);
8954 e
= new AST
.DotIdExp(loc
, e
, id
);
8957 if (token
.value
== TOK
.new_
)
8962 error("identifier or `new` expected following `.`, not `%s`", token
.toChars());
8966 e
= new AST
.PostExp(EXP
.plusPlus
, loc
, e
);
8969 case TOK
.minusMinus
:
8970 e
= new AST
.PostExp(EXP
.minusMinus
, loc
, e
);
8973 case TOK
.leftParenthesis
:
8974 AST
.Expressions
* args
= new AST
.Expressions();
8975 AST
.Identifiers
* names
= new AST
.Identifiers();
8976 parseNamedArguments(args
, names
);
8977 e
= new AST
.CallExp(loc
, e
, args
, names
);
8980 case TOK
.leftBracket
:
8982 // array dereferences:
8985 // array[lwr .. upr]
8986 AST
.Expression index
;
8988 auto arguments
= new AST
.Expressions();
8992 while (token
.value
!= TOK
.rightBracket
&& token
.value
!= TOK
.endOfFile
)
8994 index
= parseAssignExp();
8995 if (token
.value
== TOK
.slice
)
8997 // array[..., lwr..upr, ...]
8999 upr
= parseAssignExp();
9000 arguments
.push(new AST
.IntervalExp(loc
, index
, upr
));
9003 arguments
.push(index
);
9004 if (token
.value
== TOK
.rightBracket
)
9008 check(TOK
.rightBracket
);
9010 e
= new AST
.ArrayExp(loc
, e
, arguments
);
9020 private AST
.Expression
parseMulExp()
9022 const loc
= token
.loc
;
9023 auto e
= parseUnaryExp();
9027 switch (token
.value
)
9031 auto e2
= parseUnaryExp();
9032 e
= new AST
.MulExp(loc
, e
, e2
);
9037 auto e2
= parseUnaryExp();
9038 e
= new AST
.DivExp(loc
, e
, e2
);
9043 auto e2
= parseUnaryExp();
9044 e
= new AST
.ModExp(loc
, e
, e2
);
9055 private AST
.Expression
parseAddExp()
9057 const loc
= token
.loc
;
9058 auto e
= parseMulExp();
9062 switch (token
.value
)
9066 auto e2
= parseMulExp();
9067 e
= new AST
.AddExp(loc
, e
, e2
);
9072 auto e2
= parseMulExp();
9073 e
= new AST
.MinExp(loc
, e
, e2
);
9078 auto e2
= parseMulExp();
9079 e
= new AST
.CatExp(loc
, e
, e2
);
9090 private AST
.Expression
parseShiftExp()
9092 const loc
= token
.loc
;
9093 auto e
= parseAddExp();
9097 switch (token
.value
)
9101 auto e2
= parseAddExp();
9102 e
= new AST
.ShlExp(loc
, e
, e2
);
9105 case TOK
.rightShift
:
9107 auto e2
= parseAddExp();
9108 e
= new AST
.ShrExp(loc
, e
, e2
);
9111 case TOK
.unsignedRightShift
:
9113 auto e2
= parseAddExp();
9114 e
= new AST
.UshrExp(loc
, e
, e2
);
9125 private AST
.Expression
parseCmpExp()
9127 const loc
= token
.loc
;
9129 auto e
= parseShiftExp();
9130 EXP op
= EXP
.reserved
;
9132 switch (token
.value
)
9134 case TOK
.equal
: op
= EXP
.equal
; goto Lequal
;
9135 case TOK
.notEqual
: op
= EXP
.notEqual
; goto Lequal
;
9138 auto e2
= parseShiftExp();
9139 e
= new AST
.EqualExp(op
, loc
, e
, e2
);
9144 // Attempt to identify '!is'
9145 const tv
= peekNext();
9150 auto e2
= parseShiftExp();
9151 e
= new AST
.InExp(loc
, e
, e2
);
9152 e
= new AST
.NotExp(loc
, e
);
9158 op
= EXP
.notIdentity
;
9161 case TOK
.is_
: op
= EXP
.identity
; goto Lidentity
;
9164 auto e2
= parseShiftExp();
9165 e
= new AST
.IdentityExp(op
, loc
, e
, e2
);
9168 case TOK
.lessThan
: op
= EXP
.lessThan
; goto Lcmp
;
9169 case TOK
.lessOrEqual
: op
= EXP
.lessOrEqual
; goto Lcmp
;
9170 case TOK
.greaterThan
: op
= EXP
.greaterThan
; goto Lcmp
;
9171 case TOK
.greaterOrEqual
: op
= EXP
.greaterOrEqual
; goto Lcmp
;
9174 auto e2
= parseShiftExp();
9175 e
= new AST
.CmpExp(op
, loc
, e
, e2
);
9180 auto e2
= parseShiftExp();
9181 e
= new AST
.InExp(loc
, e
, e2
);
9190 private AST
.Expression
parseAndExp()
9192 Loc loc
= token
.loc
;
9193 bool parens
= token
.value
== TOK
.leftParenthesis
;
9194 auto e
= parseCmpExp();
9195 while (token
.value
== TOK
.and)
9198 checkParens(TOK
.and, e
);
9199 parens
= nextToken() == TOK
.leftParenthesis
;
9200 auto e2
= parseCmpExp();
9202 checkParens(TOK
.and, e2
);
9203 e
= new AST
.AndExp(loc
, e
, e2
);
9204 parens
= true; // don't call checkParens() for And
9210 private AST
.Expression
parseXorExp()
9212 Loc loc
= token
.loc
;
9214 bool parens
= token
.value
== TOK
.leftParenthesis
;
9215 auto e
= parseAndExp();
9216 while (token
.value
== TOK
.xor)
9219 checkParens(TOK
.xor, e
);
9220 parens
= nextToken() == TOK
.leftParenthesis
;
9221 auto e2
= parseAndExp();
9223 checkParens(TOK
.xor, e2
);
9224 e
= new AST
.XorExp(loc
, e
, e2
);
9231 private AST
.Expression
parseOrExp()
9233 Loc loc
= token
.loc
;
9235 bool parens
= token
.value
== TOK
.leftParenthesis
;
9236 auto e
= parseXorExp();
9237 while (token
.value
== TOK
.or)
9240 checkParens(TOK
.or, e
);
9241 parens
= nextToken() == TOK
.leftParenthesis
;
9242 auto e2
= parseXorExp();
9244 checkParens(TOK
.or, e2
);
9245 e
= new AST
.OrExp(loc
, e
, e2
);
9252 private AST
.Expression
parseAndAndExp()
9254 const loc
= token
.loc
;
9256 auto e
= parseOrExp();
9257 while (token
.value
== TOK
.andAnd
)
9260 auto e2
= parseOrExp();
9261 e
= new AST
.LogicalExp(loc
, EXP
.andAnd
, e
, e2
);
9266 private AST
.Expression
parseOrOrExp()
9268 const loc
= token
.loc
;
9270 auto e
= parseAndAndExp();
9271 while (token
.value
== TOK
.orOr
)
9274 auto e2
= parseAndAndExp();
9275 e
= new AST
.LogicalExp(loc
, EXP
.orOr
, e
, e2
);
9280 private AST
.Expression
parseCondExp()
9282 const loc
= token
.loc
;
9284 auto e
= parseOrOrExp();
9285 if (token
.value
== TOK
.question
)
9288 auto e1
= parseExpression();
9290 auto e2
= parseCondExp();
9291 e
= new AST
.CondExp(loc
, e
, e1
, e2
);
9296 AST
.Expression
parseAssignExp()
9298 bool parens
= token
.value
== TOK
.leftParenthesis
;
9304 // require parens for e.g. `t ? a = 1 : b = 2`
9305 void checkRequiredParens()
9307 if (e
.op
== EXP
.question
&& !parens
)
9308 eSink
.error(e
.loc
, "`%s` must be surrounded by parentheses when next to operator `%s`",
9309 e
.toChars(), Token
.toChars(token
.value
));
9312 const loc
= token
.loc
;
9313 switch (token
.value
)
9316 checkRequiredParens();
9318 auto e2
= parseAssignExp();
9319 e
= new AST
.AssignExp(loc
, e
, e2
);
9323 checkRequiredParens();
9325 auto e2
= parseAssignExp();
9326 e
= new AST
.AddAssignExp(loc
, e
, e2
);
9330 checkRequiredParens();
9332 auto e2
= parseAssignExp();
9333 e
= new AST
.MinAssignExp(loc
, e
, e2
);
9337 checkRequiredParens();
9339 auto e2
= parseAssignExp();
9340 e
= new AST
.MulAssignExp(loc
, e
, e2
);
9344 checkRequiredParens();
9346 auto e2
= parseAssignExp();
9347 e
= new AST
.DivAssignExp(loc
, e
, e2
);
9351 checkRequiredParens();
9353 auto e2
= parseAssignExp();
9354 e
= new AST
.ModAssignExp(loc
, e
, e2
);
9358 checkRequiredParens();
9360 auto e2
= parseAssignExp();
9361 e
= new AST
.PowAssignExp(loc
, e
, e2
);
9365 checkRequiredParens();
9367 auto e2
= parseAssignExp();
9368 e
= new AST
.AndAssignExp(loc
, e
, e2
);
9372 checkRequiredParens();
9374 auto e2
= parseAssignExp();
9375 e
= new AST
.OrAssignExp(loc
, e
, e2
);
9379 checkRequiredParens();
9381 auto e2
= parseAssignExp();
9382 e
= new AST
.XorAssignExp(loc
, e
, e2
);
9385 case TOK
.leftShiftAssign
:
9386 checkRequiredParens();
9388 auto e2
= parseAssignExp();
9389 e
= new AST
.ShlAssignExp(loc
, e
, e2
);
9392 case TOK
.rightShiftAssign
:
9393 checkRequiredParens();
9395 auto e2
= parseAssignExp();
9396 e
= new AST
.ShrAssignExp(loc
, e
, e2
);
9399 case TOK
.unsignedRightShiftAssign
:
9400 checkRequiredParens();
9402 auto e2
= parseAssignExp();
9403 e
= new AST
.UshrAssignExp(loc
, e
, e2
);
9406 case TOK
.concatenateAssign
:
9407 checkRequiredParens();
9409 auto e2
= parseAssignExp();
9410 e
= new AST
.CatAssignExp(loc
, e
, e2
);
9420 /*************************
9421 * Collect argument list.
9422 * Assume current token is ',', '$(LPAREN)' or '['.
9424 private AST
.Expressions
* parseArguments()
9427 AST
.Expressions
* arguments
= new AST
.Expressions();
9428 parseNamedArguments(arguments
, null);
9432 /*************************
9433 * Collect argument list.
9434 * Assume current token is ',', '$(LPAREN)' or '['.
9436 private void parseNamedArguments(AST
.Expressions
* arguments
, AST
.Identifiers
* names
)
9440 const endtok
= token
.value
== TOK
.leftBracket ? TOK
.rightBracket
: TOK
.rightParenthesis
;
9444 while (token
.value
!= endtok
&& token
.value
!= TOK
.endOfFile
)
9446 if (peekNext() == TOK
.colon
)
9448 // Named argument `name: exp`
9449 auto loc
= token
.loc
;
9450 auto ident
= token
.ident
;
9451 check(TOK
.identifier
);
9456 error(loc
, "named arguments not allowed here");
9464 auto arg
= parseAssignExp();
9465 arguments
.push(arg
);
9467 if (token
.value
!= TOK
.comma
)
9470 nextToken(); //comma
9475 /*******************************************
9477 private AST
.Expression
parseNewExp(AST
.Expression thisexp
)
9479 const loc
= token
.loc
;
9482 AST
.Expressions
* arguments
= null;
9483 AST
.Identifiers
* names
= null;
9485 // An anonymous nested class starts with "class"
9486 if (token
.value
== TOK
.class_
)
9489 if (token
.value
== TOK
.leftParenthesis
)
9491 arguments
= new AST
.Expressions();
9492 names
= new AST
.Identifiers();
9493 parseNamedArguments(arguments
, names
);
9496 AST
.BaseClasses
* baseclasses
= null;
9497 if (token
.value
!= TOK
.leftCurly
)
9498 baseclasses
= parseBaseClasses();
9500 Identifier id
= null;
9501 AST
.Dsymbols
* members
= null;
9503 if (token
.value
!= TOK
.leftCurly
)
9505 error("`{ members }` expected for anonymous class");
9510 members
= parseDeclDefs(0);
9511 if (token
.value
!= TOK
.rightCurly
)
9512 error("class member expected");
9516 auto cd
= new AST
.ClassDeclaration(loc
, id
, baseclasses
, members
, false);
9517 auto e
= new AST
.NewAnonClassExp(loc
, thisexp
, cd
, arguments
);
9521 const stc = parseTypeCtor();
9522 auto t
= parseBasicType(true);
9523 t
= parseTypeSuffixes(t
);
9525 if (t
.ty
== Taarray
)
9527 AST
.TypeAArray taa
= cast(AST
.TypeAArray
)t
;
9528 AST
.Type index
= taa
.index
;
9529 // `new Type[expr]` is a static array
9530 auto edim
= AST
.typeToExpression(index
);
9532 t
= new AST
.TypeSArray(taa
.next
, edim
);
9534 else if (token
.value
== TOK
.leftParenthesis
&& t
.ty
!= Tsarray
)
9536 arguments
= new AST
.Expressions();
9537 names
= new AST
.Identifiers();
9538 parseNamedArguments(arguments
, names
);
9541 auto e
= new AST
.NewExp(loc
, thisexp
, t
, arguments
, names
);
9545 /**********************************************
9547 private void addComment(AST
.Dsymbol s
, const(char)* blockComment
)
9550 this.addComment(s
, blockComment
.toDString());
9553 private void addComment(AST
.Dsymbol s
, const(char)[] blockComment
)
9557 s
.addComment(combineComments(blockComment
, token
.lineComment
, true));
9558 token
.lineComment
= null;
9562 /**********************************************
9563 * Recognize builtin @ attributes
9565 * ident = identifier
9567 * storage class for attribute, 0 if not
9569 static StorageClass
isBuiltinAtAttribute(Identifier ident
)
9571 return (ident
== Id
.property
) ? STC
.property
:
9572 (ident
== Id
.nogc
) ? STC
.nogc
:
9573 (ident
== Id
.safe
) ? STC
.safe
:
9574 (ident
== Id
.trusted
) ? STC
.trusted
:
9575 (ident
== Id
.system
) ? STC
.system
:
9576 (ident
== Id
.live
) ? STC
.live
:
9577 (ident
== Id
.future
) ? STC
.future
:
9578 (ident
== Id
.disable
) ? STC
.disable
:
9582 enum StorageClass atAttrGroup
=
9589 /*STC.future |*/ // probably should be included
9592 void usageOfBodyKeyword()
9594 version (none
) // disable obsolete warning
9596 eSink
.warning(token
.loc
, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
9622 /**********************************
9623 * Set operator precedence for each operator.
9627 immutable PREC
[EXP
.max
+ 1] precedence
=
9629 EXP
.type
: PREC
.expr
,
9630 EXP
.error
: PREC
.expr
,
9631 EXP
.objcClassReference
: PREC
.expr
, // Objective-C class reference, same as EXP.type
9633 EXP
.mixin_
: PREC
.primary
,
9635 EXP
.import_
: PREC
.primary
,
9636 EXP
.dotVariable
: PREC
.primary
,
9637 EXP
.scope_
: PREC
.primary
,
9638 EXP
.identifier
: PREC
.primary
,
9639 EXP
.this_
: PREC
.primary
,
9640 EXP
.super_
: PREC
.primary
,
9641 EXP
.int64
: PREC
.primary
,
9642 EXP
.float64
: PREC
.primary
,
9643 EXP
.complex80
: PREC
.primary
,
9644 EXP
.null_
: PREC
.primary
,
9645 EXP
.string_
: PREC
.primary
,
9646 EXP
.arrayLiteral
: PREC
.primary
,
9647 EXP
.assocArrayLiteral
: PREC
.primary
,
9648 EXP
.classReference
: PREC
.primary
,
9649 EXP
.file
: PREC
.primary
,
9650 EXP
.fileFullPath
: PREC
.primary
,
9651 EXP
.line
: PREC
.primary
,
9652 EXP
.moduleString
: PREC
.primary
,
9653 EXP
.functionString
: PREC
.primary
,
9654 EXP
.prettyFunction
: PREC
.primary
,
9655 EXP
.typeid_
: PREC
.primary
,
9656 EXP
.is_
: PREC
.primary
,
9657 EXP
.assert_
: PREC
.primary
,
9658 EXP
.halt
: PREC
.primary
,
9659 EXP
.template_
: PREC
.primary
,
9660 EXP
.dSymbol
: PREC
.primary
,
9661 EXP
.function_
: PREC
.primary
,
9662 EXP
.variable
: PREC
.primary
,
9663 EXP
.symbolOffset
: PREC
.primary
,
9664 EXP
.structLiteral
: PREC
.primary
,
9665 EXP
.compoundLiteral
: PREC
.primary
,
9666 EXP
.arrayLength
: PREC
.primary
,
9667 EXP
.delegatePointer
: PREC
.primary
,
9668 EXP
.delegateFunctionPointer
: PREC
.primary
,
9669 EXP
.remove
: PREC
.primary
,
9670 EXP
.tuple
: PREC
.primary
,
9671 EXP
.traits
: PREC
.primary
,
9672 EXP
.overloadSet
: PREC
.primary
,
9673 EXP
.void_
: PREC
.primary
,
9674 EXP
.vectorArray
: PREC
.primary
,
9675 EXP
._Generic
: PREC
.primary
,
9678 EXP
.dotTemplateInstance
: PREC
.primary
,
9679 EXP
.dotIdentifier
: PREC
.primary
,
9680 EXP
.dotTemplateDeclaration
: PREC
.primary
,
9681 EXP
.dot
: PREC
.primary
,
9682 EXP
.dotType
: PREC
.primary
,
9683 EXP
.plusPlus
: PREC
.primary
,
9684 EXP
.minusMinus
: PREC
.primary
,
9685 EXP
.prePlusPlus
: PREC
.primary
,
9686 EXP
.preMinusMinus
: PREC
.primary
,
9687 EXP
.call : PREC
.primary
,
9688 EXP
.slice
: PREC
.primary
,
9689 EXP
.array
: PREC
.primary
,
9690 EXP
.index
: PREC
.primary
,
9692 EXP
.delegate_
: PREC
.unary
,
9693 EXP
.address
: PREC
.unary
,
9694 EXP
.star
: PREC
.unary
,
9695 EXP
.negate
: PREC
.unary
,
9696 EXP
.uadd
: PREC
.unary
,
9697 EXP
.not : PREC
.unary
,
9698 EXP
.tilde
: PREC
.unary
,
9699 EXP
.delete_
: PREC
.unary
,
9700 EXP
.new_
: PREC
.unary
,
9701 EXP
.newAnonymousClass
: PREC
.unary
,
9702 EXP
.cast_
: PREC
.unary
,
9703 EXP
.throw_
: PREC
.unary
,
9705 EXP
.vector
: PREC
.unary
,
9714 EXP
.concatenate
: PREC
.add,
9716 EXP
.leftShift
: PREC
.shift
,
9717 EXP
.rightShift
: PREC
.shift
,
9718 EXP
.unsignedRightShift
: PREC
.shift
,
9720 EXP
.lessThan
: PREC
.rel
,
9721 EXP
.lessOrEqual
: PREC
.rel
,
9722 EXP
.greaterThan
: PREC
.rel
,
9723 EXP
.greaterOrEqual
: PREC
.rel
,
9726 /* Note that we changed precedence, so that < and != have the same
9727 * precedence. This change is in the parser, too.
9729 EXP
.equal
: PREC
.rel
,
9730 EXP
.notEqual
: PREC
.rel
,
9731 EXP
.identity
: PREC
.rel
,
9732 EXP
.notIdentity
: PREC
.rel
,
9738 EXP
.andAnd
: PREC
.andand
,
9739 EXP
.orOr
: PREC
.oror
,
9741 EXP
.question
: PREC
.cond
,
9743 EXP
.assign
: PREC
.assign
,
9744 EXP
.construct
: PREC
.assign
,
9745 EXP
.blit
: PREC
.assign
,
9746 EXP
.addAssign
: PREC
.assign
,
9747 EXP
.minAssign
: PREC
.assign
,
9748 EXP
.concatenateAssign
: PREC
.assign
,
9749 EXP
.concatenateElemAssign
: PREC
.assign
,
9750 EXP
.concatenateDcharAssign
: PREC
.assign
,
9751 EXP
.mulAssign
: PREC
.assign
,
9752 EXP
.divAssign
: PREC
.assign
,
9753 EXP
.modAssign
: PREC
.assign
,
9754 EXP
.powAssign
: PREC
.assign
,
9755 EXP
.leftShiftAssign
: PREC
.assign
,
9756 EXP
.rightShiftAssign
: PREC
.assign
,
9757 EXP
.unsignedRightShiftAssign
: PREC
.assign
,
9758 EXP
.andAssign
: PREC
.assign
,
9759 EXP
.orAssign
: PREC
.assign
,
9760 EXP
.xorAssign
: PREC
.assign
,
9762 EXP
.comma
: PREC
.expr
,
9763 EXP
.declaration
: PREC
.expr
,
9765 EXP
.interval
: PREC
.assign
,
9768 enum ParseStatementFlags
: int
9770 scope_
= 2, // start a new scope
9771 curly
= 4, // { } statement is required
9772 curlyScope
= 8, // { } starts a new scope
9773 semiOk
= 0x10, // empty ';' are really ok
9776 struct PrefixAttributes(AST
)
9778 StorageClass storageClass
;
9779 AST
.Expression depmsg
;
9781 AST
.Visibility visibility
;
9783 AST
.Expression ealign
;
9784 AST
.Expressions
* udas
;
9785 const(char)* comment
;
9788 /// The result of the `ParseLinkage` function
9789 struct ParsedLinkage(AST
)
9791 /// What linkage was specified
9793 /// If `extern(C++, class|struct)`, contains the `class|struct`
9794 CPPMANGLE cppmangle
;
9795 /// If `extern(C++, some.identifier)`, will be the identifiers
9796 AST
.Identifiers
* idents
;
9797 /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
9798 AST
.Expressions
* identExps
;
9802 /*********************************** Private *************************************/
9804 /***********************
9805 * How multiple declarations are parsed.
9813 private enum CDECLSYNTAX
= 0;
9816 * Support C cast syntax:
9817 * (type)(expression)
9819 private enum CCASTSYNTAX
= 1;
9822 * Support postfix C array declarations, such as
9825 private enum CARRAYDECL
= 1;
9827 /*****************************
9828 * Destructively extract storage class from pAttrs.
9830 private StorageClass
getStorageClass(AST
)(PrefixAttributes
!(AST
)* pAttrs
)
9832 StorageClass
stc = STC
.undefined_
;
9835 stc = pAttrs
.storageClass
;
9836 pAttrs
.storageClass
= STC
.undefined_
;