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-2021 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 http://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
;
21 import dmd
.identifier
;
24 import dmd
.root
.filename
;
25 import dmd
.common
.outbuffer
;
27 import dmd
.root
.rootobject
;
28 import dmd
.root
.string
;
31 // How multiple declarations are parsed.
38 private enum CDECLSYNTAX
= 0;
40 // Support C cast syntax:
42 private enum CCASTSYNTAX
= 1;
44 // Support postfix C array declarations, such as
46 private enum CARRAYDECL
= 1;
48 /**********************************
49 * Set operator precedence for each operator.
53 immutable PREC
[EXP
.max
+ 1] precedence
=
56 EXP
.error
: PREC
.expr
,
57 EXP
.objcClassReference
: PREC
.expr
, // Objective-C class reference, same as EXP.type
59 EXP
.typeof_
: PREC
.primary
,
60 EXP
.mixin_
: PREC
.primary
,
62 EXP
.import_
: PREC
.primary
,
63 EXP
.dotVariable
: PREC
.primary
,
64 EXP
.scope_
: PREC
.primary
,
65 EXP
.identifier
: PREC
.primary
,
66 EXP
.this_
: PREC
.primary
,
67 EXP
.super_
: PREC
.primary
,
68 EXP
.int64
: PREC
.primary
,
69 EXP
.float64
: PREC
.primary
,
70 EXP
.complex80
: PREC
.primary
,
71 EXP
.null_
: PREC
.primary
,
72 EXP
.string_
: PREC
.primary
,
73 EXP
.arrayLiteral
: PREC
.primary
,
74 EXP
.assocArrayLiteral
: PREC
.primary
,
75 EXP
.classReference
: PREC
.primary
,
76 EXP
.file
: PREC
.primary
,
77 EXP
.fileFullPath
: PREC
.primary
,
78 EXP
.line
: PREC
.primary
,
79 EXP
.moduleString
: PREC
.primary
,
80 EXP
.functionString
: PREC
.primary
,
81 EXP
.prettyFunction
: PREC
.primary
,
82 EXP
.typeid_
: PREC
.primary
,
83 EXP
.is_
: PREC
.primary
,
84 EXP
.assert_
: PREC
.primary
,
85 EXP
.halt
: PREC
.primary
,
86 EXP
.template_
: PREC
.primary
,
87 EXP
.dSymbol
: PREC
.primary
,
88 EXP
.function_
: PREC
.primary
,
89 EXP
.variable
: PREC
.primary
,
90 EXP
.symbolOffset
: PREC
.primary
,
91 EXP
.structLiteral
: PREC
.primary
,
92 EXP
.compoundLiteral
: PREC
.primary
,
93 EXP
.arrayLength
: PREC
.primary
,
94 EXP
.delegatePointer
: PREC
.primary
,
95 EXP
.delegateFunctionPointer
: PREC
.primary
,
96 EXP
.remove
: PREC
.primary
,
97 EXP
.tuple
: PREC
.primary
,
98 EXP
.traits
: PREC
.primary
,
99 EXP
.default_
: PREC
.primary
,
100 EXP
.overloadSet
: PREC
.primary
,
101 EXP
.void_
: PREC
.primary
,
102 EXP
.vectorArray
: PREC
.primary
,
103 EXP
._Generic
: PREC
.primary
,
106 EXP
.dotTemplateInstance
: PREC
.primary
,
107 EXP
.dotIdentifier
: PREC
.primary
,
108 EXP
.dotTemplateDeclaration
: PREC
.primary
,
109 EXP
.dot
: PREC
.primary
,
110 EXP
.dotType
: PREC
.primary
,
111 EXP
.plusPlus
: PREC
.primary
,
112 EXP
.minusMinus
: PREC
.primary
,
113 EXP
.prePlusPlus
: PREC
.primary
,
114 EXP
.preMinusMinus
: PREC
.primary
,
115 EXP
.call : PREC
.primary
,
116 EXP
.slice
: PREC
.primary
,
117 EXP
.array
: PREC
.primary
,
118 EXP
.index
: PREC
.primary
,
120 EXP
.delegate_
: PREC
.unary
,
121 EXP
.address
: PREC
.unary
,
122 EXP
.star
: PREC
.unary
,
123 EXP
.negate
: PREC
.unary
,
124 EXP
.uadd
: PREC
.unary
,
125 EXP
.not : PREC
.unary
,
126 EXP
.tilde
: PREC
.unary
,
127 EXP
.delete_
: PREC
.unary
,
128 EXP
.new_
: PREC
.unary
,
129 EXP
.newAnonymousClass
: PREC
.unary
,
130 EXP
.cast_
: PREC
.unary
,
132 EXP
.vector
: PREC
.unary
,
141 EXP
.concatenate
: PREC
.add,
143 EXP
.leftShift
: PREC
.shift
,
144 EXP
.rightShift
: PREC
.shift
,
145 EXP
.unsignedRightShift
: PREC
.shift
,
147 EXP
.lessThan
: PREC
.rel
,
148 EXP
.lessOrEqual
: PREC
.rel
,
149 EXP
.greaterThan
: PREC
.rel
,
150 EXP
.greaterOrEqual
: PREC
.rel
,
153 /* Note that we changed precedence, so that < and != have the same
154 * precedence. This change is in the parser, too.
156 EXP
.equal
: PREC
.rel
,
157 EXP
.notEqual
: PREC
.rel
,
158 EXP
.identity
: PREC
.rel
,
159 EXP
.notIdentity
: PREC
.rel
,
165 EXP
.andAnd
: PREC
.andand
,
166 EXP
.orOr
: PREC
.oror
,
168 EXP
.question
: PREC
.cond
,
170 EXP
.assign
: PREC
.assign
,
171 EXP
.construct
: PREC
.assign
,
172 EXP
.blit
: PREC
.assign
,
173 EXP
.addAssign
: PREC
.assign
,
174 EXP
.minAssign
: PREC
.assign
,
175 EXP
.concatenateAssign
: PREC
.assign
,
176 EXP
.concatenateElemAssign
: PREC
.assign
,
177 EXP
.concatenateDcharAssign
: PREC
.assign
,
178 EXP
.mulAssign
: PREC
.assign
,
179 EXP
.divAssign
: PREC
.assign
,
180 EXP
.modAssign
: PREC
.assign
,
181 EXP
.powAssign
: PREC
.assign
,
182 EXP
.leftShiftAssign
: PREC
.assign
,
183 EXP
.rightShiftAssign
: PREC
.assign
,
184 EXP
.unsignedRightShiftAssign
: PREC
.assign
,
185 EXP
.andAssign
: PREC
.assign
,
186 EXP
.orAssign
: PREC
.assign
,
187 EXP
.xorAssign
: PREC
.assign
,
189 EXP
.comma
: PREC
.expr
,
190 EXP
.declaration
: PREC
.expr
,
192 EXP
.interval
: PREC
.assign
,
195 enum ParseStatementFlags
: int
197 semi
= 1, // empty ';' statements are allowed, but deprecated
198 scope_
= 2, // start a new scope
199 curly
= 4, // { } statement is required
200 curlyScope
= 8, // { } starts a new scope
201 semiOk
= 0x10, // empty ';' are really ok
204 struct PrefixAttributes(AST
)
206 StorageClass storageClass
;
207 AST
.Expression depmsg
;
209 AST
.Visibility visibility
;
211 AST
.Expression ealign
;
212 AST
.Expressions
* udas
;
213 const(char)* comment
;
216 /// The result of the `ParseLinkage` function
217 struct ParsedLinkage(AST
)
219 /// What linkage was specified
221 /// If `extern(C++, class|struct)`, contains the `class|struct`
223 /// If `extern(C++, some.identifier)`, will be the identifiers
224 AST
.Identifiers
* idents
;
225 /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
226 AST
.Expressions
* identExps
;
229 /*****************************
230 * Destructively extract storage class from pAttrs.
232 private StorageClass
getStorageClass(AST
)(PrefixAttributes
!(AST
)* pAttrs
)
234 StorageClass
stc = STC
.undefined_
;
237 stc = pAttrs
.storageClass
;
238 pAttrs
.storageClass
= STC
.undefined_
;
243 /**************************************
244 * dump mixin expansion to file for better debugging
246 private bool writeMixin(const(char)[] s
, ref Loc loc
)
248 if (!global
.params
.mixinOut
)
251 OutBuffer
* ob
= global
.params
.mixinOut
;
253 ob
.writestring("// expansion at ");
254 ob
.writestring(loc
.toChars());
257 global
.params
.mixinLines
++;
259 loc
= Loc(global
.params
.mixinFile
, global
.params
.mixinLines
+ 1, loc
.charnum
);
261 // write by line to create consistent line endings
263 for (size_t i
= 0; i
< s
.length
; ++i
)
265 // detect LF and CRLF
267 if (c
== '\n' ||
(c
== '\r' && i
+1 < s
.length
&& s
[i
+1] == '\n'))
269 ob
.writestring(s
[lastpos
.. i
]);
271 global
.params
.mixinLines
++;
278 if(lastpos
< s
.length
)
279 ob
.writestring(s
[lastpos
.. $]);
281 if (s
.length
== 0 || s
[$-1] != '\n')
283 ob
.writenl(); // ensure empty line after expansion
284 global
.params
.mixinLines
++;
287 global
.params
.mixinLines
++;
292 /***********************************************************
294 class Parser(AST
) : Lexer
296 AST
.ModuleDeclaration
* md
;
304 Loc endloc
; // set to location of last right curly
305 int inBrackets
; // inside [] of array index or slice
306 Loc lookingForElse
; // location of lonely if looking for an else
309 /*********************
310 * Use this constructor for string mixins.
312 * loc location in source file of mixin
314 extern (D
) this(const ref Loc loc
, AST
.Module _module
, const(char)[] input
, bool doDocComment
)
316 super(_module ? _module
.srcfile
.toChars() : null, input
.ptr
, 0, input
.length
, doDocComment
, false);
318 //printf("Parser::Parser()\n");
321 if (!writeMixin(input
, scanloc
) && loc
.filename
)
323 /* Create a pseudo-filename for the mixin string, as it may not even exist
324 * in the source file.
326 char* filename
= cast(char*)mem
.xmalloc(strlen(loc
.filename
) + 7 + (loc
.linnum
).sizeof
* 3 + 1);
327 sprintf(filename
, "%s-mixin-%d", loc
.filename
, cast(int)loc
.linnum
);
328 scanloc
.filename
= filename
;
333 //nextToken(); // start up the scanner
336 extern (D
) this(AST
.Module _module
, const(char)[] input
, bool doDocComment
)
338 super(_module ? _module
.srcfile
.toChars() : null, input
.ptr
, 0, input
.length
, doDocComment
, false);
340 //printf("Parser::Parser()\n");
343 //nextToken(); // start up the scanner
346 AST
.Dsymbols
* parseModule()
348 const comment
= token
.blockComment
;
349 bool isdeprecated
= false;
350 AST
.Expression msg
= null;
351 AST
.Expressions
* udas
= null;
352 AST
.Dsymbols
* decldefs
;
353 AST
.Dsymbol lastDecl
= mod
; // for attaching ddoc unittests to module decl
356 if (skipAttributes(&token
, &tk
) && tk
.value
== TOK
.module_
)
358 while (token
.value
!= TOK
.module_
)
362 case TOK
.deprecated_
:
364 // deprecated (...) module ...
366 error("there is only one deprecation attribute allowed for module declaration");
369 if (token
.value
== TOK
.leftParenthesis
)
371 check(TOK
.leftParenthesis
);
372 msg
= parseAssignExp();
373 check(TOK
.rightParenthesis
);
379 AST
.Expressions
* exps
= null;
380 const stc = parseAttribute(exps
);
381 if (stc & atAttrGroup
)
383 error("`@%s` attribute for module declaration is not supported", token
.toChars());
387 udas
= AST
.UserAttributeDeclaration
.concat(udas
, exps
);
395 error("`module` expected instead of `%s`", token
.toChars());
405 auto a
= new AST
.Dsymbols();
406 auto udad
= new AST
.UserAttributeDeclaration(udas
, a
);
407 mod
.userAttribDecl
= udad
;
410 // ModuleDeclation leads off
411 if (token
.value
== TOK
.module_
)
413 const loc
= token
.loc
;
416 if (token
.value
!= TOK
.identifier
)
418 error("identifier expected following `module`");
423 Identifier id
= token
.ident
;
425 while (nextToken() == TOK
.dot
)
429 if (token
.value
!= TOK
.identifier
)
431 error("identifier expected following `package`");
437 md
= new AST
.ModuleDeclaration(loc
, a
, id
, msg
, isdeprecated
);
439 if (token
.value
!= TOK
.semicolon
)
440 error("`;` expected following module declaration instead of `%s`", token
.toChars());
442 addComment(mod
, comment
);
445 decldefs
= parseDeclDefs(0, &lastDecl
);
446 if (token
.value
!= TOK
.endOfFile
)
448 error(token
.loc
, "unrecognized declaration");
454 while (token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
457 return new AST
.Dsymbols();
463 * Parses a `deprecated` declaration
466 * msg = Deprecated message, if any.
467 * Used to support overriding a deprecated storage class with
468 * a deprecated declaration with a message, but to error
469 * if both declaration have a message.
472 * Whether the deprecated declaration has a message
474 private bool parseDeprecatedAttribute(ref AST
.Expression msg
)
476 if (peekNext() != TOK
.leftParenthesis
)
480 check(TOK
.leftParenthesis
);
481 AST
.Expression e
= parseAssignExp();
482 check(TOK
.rightParenthesis
);
485 error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg
.toChars(), e
.toChars());
491 AST
.Dsymbols
* parseDeclDefs(int once
, AST
.Dsymbol
* pLastDecl
= null, PrefixAttributes
!AST
* pAttrs
= null)
493 AST
.Dsymbol lastDecl
= null; // used to link unittest to its previous declaration
495 pLastDecl
= &lastDecl
;
497 const linksave
= linkage
; // save global state
499 //printf("Parser::parseDeclDefs()\n");
500 auto decldefs
= new AST
.Dsymbols();
504 AST
.Dsymbol s
= null;
505 AST
.Dsymbols
* a
= null;
507 PrefixAttributes
!AST attrs
;
508 if (!once ||
!pAttrs
)
511 pAttrs
.comment
= token
.blockComment
.ptr
;
513 AST
.Visibility
.Kind prot
;
515 AST
.Condition condition
;
525 /* Determine if this is a manifest constant declaration,
526 * or a conventional enum.
528 const tv
= peekNext();
529 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
531 else if (tv
!= TOK
.identifier
)
535 const nextv
= peekNext2();
536 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
549 s
= cast(AST
.Dsymbol
)parseTemplateDeclaration();
554 const loc
= token
.loc
;
557 case TOK
.leftParenthesis
:
560 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
564 auto exps
= parseArguments();
565 check(TOK
.semicolon
);
566 s
= new AST
.CompileDeclaration(loc
, exps
);
572 s
= cast(AST
.Dsymbol
)parseTemplateDeclaration(true);
598 case TOK
.imaginary32
:
599 case TOK
.imaginary64
:
600 case TOK
.imaginary80
:
617 a
= parseDeclarations(false, pAttrs
, pAttrs
.comment
);
619 *pLastDecl
= (*a
)[a
.dim
- 1];
623 if (peekNext() == TOK
.dot
)
625 s
= parseCtor(pAttrs
);
629 s
= parseDtor(pAttrs
);
633 const tv
= peekNext();
634 if (tv
== TOK
.leftParenthesis || tv
== TOK
.leftCurly
)
636 // invariant { statements... }
637 // invariant() { statements... }
638 // invariant (expression);
639 s
= parseInvariant(pAttrs
);
642 error("invariant body expected, not `%s`", token
.toChars());
646 if (global
.params
.useUnitTests || global
.params
.doDocComments || global
.params
.doHdrGeneration
)
648 s
= parseUnitTest(pAttrs
);
650 (*pLastDecl
).ddocUnittest
= cast(AST
.UnitTestDeclaration
)s
;
654 // Skip over unittest block by counting { }
674 error(loc
, "closing `}` of unittest not found before end of file");
682 // Workaround 14894. Add an empty unittest declaration to keep
683 // the number of symbols in this scope independent of -unittest.
684 s
= new AST
.UnitTestDeclaration(loc
, token
.loc
, STC
.undefined_
, null);
689 s
= parseNew(pAttrs
);
694 error("declaration expected, not `%s`", token
.toChars());
700 error("declaration expected, not `%s`", token
.toChars());
705 const next
= peekNext();
706 if (next
== TOK
.this_
)
707 s
= parseStaticCtor(pAttrs
);
708 else if (next
== TOK
.tilde
)
709 s
= parseStaticDtor(pAttrs
);
710 else if (next
== TOK
.assert_
)
711 s
= parseStaticAssert();
712 else if (next
== TOK
.if_
)
714 const Loc loc
= token
.loc
;
715 condition
= parseStaticIfCondition();
717 if (token
.value
== TOK
.colon
)
718 athen
= parseBlock(pLastDecl
);
721 const lookingForElseSave
= lookingForElse
;
722 lookingForElse
= token
.loc
;
723 athen
= parseBlock(pLastDecl
);
724 lookingForElse
= lookingForElseSave
;
726 AST
.Dsymbols
* aelse
= null;
727 if (token
.value
== TOK
.else_
)
729 const elseloc
= token
.loc
;
731 aelse
= parseBlock(pLastDecl
);
732 checkDanglingElse(elseloc
);
734 s
= new AST
.StaticIfDeclaration(loc
, condition
, athen
, aelse
);
736 else if (next
== TOK
.import_
)
741 else if (next
== TOK
.foreach_ || next
== TOK
.foreach_reverse_
)
743 s
= parseForeach
!(AST
.StaticForeachDeclaration
)(token
.loc
, pLastDecl
);
753 if (peekNext() == TOK
.leftParenthesis
)
759 if (peekNext() == TOK
.leftParenthesis
)
761 stc = STC
.immutable_
;
766 const next
= peekNext();
767 if (next
== TOK
.leftParenthesis
)
769 if (next
== TOK
.static_
)
771 TOK next2
= peekNext2();
772 if (next2
== TOK
.this_
)
774 s
= parseSharedStaticCtor(pAttrs
);
777 if (next2
== TOK
.tilde
)
779 s
= parseSharedStaticDtor(pAttrs
);
787 if (peekNext() == TOK
.leftParenthesis
)
812 case TOK
.synchronized_
:
813 stc = STC
.synchronized_
;
834 AST
.Expressions
* exps
= null;
835 stc = parseAttribute(exps
);
837 goto Lstc
; // it's a predefined attribute
838 // no redundant/conflicting check for UDAs
839 pAttrs
.udas
= AST
.UserAttributeDeclaration
.concat(pAttrs
.udas
, exps
);
843 pAttrs
.storageClass
= appendStorageClass(pAttrs
.storageClass
, stc);
848 /* Look for auto initializers:
849 * storage_class identifier = initializer;
850 * storage_class identifier(...) = initializer;
852 if (token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
854 a
= parseAutoDeclarations(getStorageClass
!AST(pAttrs
), pAttrs
.comment
);
856 *pLastDecl
= (*a
)[a
.dim
- 1];
859 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
865 /* Look for return type inference for template functions.
868 if (token
.value
== TOK
.identifier
&& skipParens(peek(&token
), &tk
) && skipAttributes(tk
, &tk
) &&
869 (tk
.value
== TOK
.leftParenthesis || tk
.value
== TOK
.leftCurly || tk
.value
== TOK
.in_ ||
870 tk
.value
== TOK
.out_ || tk
.value
== TOK
.do_ || tk
.value
== TOK
.goesTo ||
871 tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
))
874 // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
875 // Deprecated in 2.097 - Can be removed from 2.117
876 // The deprecation period is longer than usual as `body`
877 // was quite widely used.
878 if (tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
)
879 deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
881 a
= parseDeclarations(true, pAttrs
, pAttrs
.comment
);
883 *pLastDecl
= (*a
)[a
.dim
- 1];
886 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
892 a
= parseBlock(pLastDecl
, pAttrs
);
893 auto stc2
= getStorageClass
!AST(pAttrs
);
894 if (stc2
!= STC
.undefined_
)
896 s
= new AST
.StorageClassDeclaration(stc2
, a
);
902 a
= new AST
.Dsymbols();
905 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
910 case TOK
.deprecated_
:
912 stc |
= STC
.deprecated_
;
913 if (!parseDeprecatedAttribute(pAttrs
.depmsg
))
916 a
= parseBlock(pLastDecl
, pAttrs
);
917 s
= new AST
.DeprecatedDeclaration(pAttrs
.depmsg
, a
);
918 pAttrs
.depmsg
= null;
921 case TOK
.leftBracket
:
923 if (peekNext() == TOK
.rightBracket
)
924 error("empty attribute list is not allowed");
925 error("use `@(attributes)` instead of `[attributes]`");
926 AST
.Expressions
* exps
= parseArguments();
927 // no redundant/conflicting check for UDAs
929 pAttrs
.udas
= AST
.UserAttributeDeclaration
.concat(pAttrs
.udas
, exps
);
930 a
= parseBlock(pLastDecl
, pAttrs
);
933 s
= new AST
.UserAttributeDeclaration(pAttrs
.udas
, a
);
940 if (peekNext() != TOK
.leftParenthesis
)
946 const linkLoc
= token
.loc
;
947 auto res
= parseLinkage();
948 if (pAttrs
.link
!= LINK
.default_
)
950 if (pAttrs
.link
!= res
.link
)
952 error("conflicting linkage `extern (%s)` and `extern (%s)`", AST
.linkageToChars(pAttrs
.link
), AST
.linkageToChars(res
.link
));
954 else if (res
.idents || res
.identExps || res
.cppmangle
!= CPPMANGLE
.def
)
957 // extern(C++, foo) extern(C++, bar) void foo();
958 // to be equivalent with:
959 // extern(C++, foo.bar) void foo();
961 // extern(C++, "ns") extern(C++, class) struct test {}
962 // extern(C++, class) extern(C++, "ns") struct test {}
965 error("redundant linkage `extern (%s)`", AST
.linkageToChars(pAttrs
.link
));
967 pAttrs
.link
= res
.link
;
968 this.linkage
= res
.link
;
969 this.linkLoc
= linkLoc
;
970 a
= parseBlock(pLastDecl
, pAttrs
);
973 assert(res
.link
== LINK
.cpp
);
974 assert(res
.idents
.dim
);
975 for (size_t i
= res
.idents
.dim
; i
;)
977 Identifier id
= (*res
.idents
)[--i
];
980 a
= new AST
.Dsymbols();
983 s
= new AST
.Nspace(linkLoc
, id
, null, a
);
985 pAttrs
.link
= LINK
.default_
;
987 else if (res
.identExps
)
989 assert(res
.link
== LINK
.cpp
);
990 assert(res
.identExps
.dim
);
991 for (size_t i
= res
.identExps
.dim
; i
;)
993 AST
.Expression exp
= (*res
.identExps
)[--i
];
996 a
= new AST
.Dsymbols();
999 s
= new AST
.CPPNamespaceDeclaration(linkLoc
, exp
, a
);
1001 pAttrs
.link
= LINK
.default_
;
1003 else if (res
.cppmangle
!= CPPMANGLE
.def
)
1005 assert(res
.link
== LINK
.cpp
);
1006 s
= new AST
.CPPMangleDeclaration(linkLoc
, res
.cppmangle
, a
);
1008 else if (pAttrs
.link
!= LINK
.default_
)
1010 s
= new AST
.LinkDeclaration(linkLoc
, pAttrs
.link
, a
);
1011 pAttrs
.link
= LINK
.default_
;
1017 prot
= AST
.Visibility
.Kind
.private_
;
1021 prot
= AST
.Visibility
.Kind
.package_
;
1024 case TOK
.protected_
:
1025 prot
= AST
.Visibility
.Kind
.protected_
;
1029 prot
= AST
.Visibility
.Kind
.public_
;
1033 prot
= AST
.Visibility
.Kind
.export_
;
1037 if (pAttrs
.visibility
.kind
!= AST
.Visibility
.Kind
.undefined
)
1039 if (pAttrs
.visibility
.kind
!= prot
)
1040 error("conflicting visibility attribute `%s` and `%s`", AST
.visibilityToChars(pAttrs
.visibility
.kind
), AST
.visibilityToChars(prot
));
1042 error("redundant visibility attribute `%s`", AST
.visibilityToChars(prot
));
1044 pAttrs
.visibility
.kind
= prot
;
1048 // optional qualified package identifier to bind
1050 Identifier
[] pkg_prot_idents
;
1051 if (pAttrs
.visibility
.kind
== AST
.Visibility
.Kind
.package_
&& token
.value
== TOK
.leftParenthesis
)
1053 pkg_prot_idents
= parseQualifiedIdentifier("protection package");
1054 if (pkg_prot_idents
)
1055 check(TOK
.rightParenthesis
);
1058 while (token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
1065 const attrloc
= token
.loc
;
1066 a
= parseBlock(pLastDecl
, pAttrs
);
1067 if (pAttrs
.visibility
.kind
!= AST
.Visibility
.Kind
.undefined
)
1069 if (pAttrs
.visibility
.kind
== AST
.Visibility
.Kind
.package_
&& pkg_prot_idents
)
1070 s
= new AST
.VisibilityDeclaration(attrloc
, pkg_prot_idents
, a
);
1072 s
= new AST
.VisibilityDeclaration(attrloc
, pAttrs
.visibility
, a
);
1074 pAttrs
.visibility
= AST
.Visibility(AST
.Visibility
.Kind
.undefined
);
1080 const attrLoc
= token
.loc
;
1084 AST
.Expression e
= null; // default
1085 if (token
.value
== TOK
.leftParenthesis
)
1088 e
= parseAssignExp();
1089 check(TOK
.rightParenthesis
);
1092 if (pAttrs
.setAlignment
)
1095 error("redundant alignment attribute `align(%s)`", e
.toChars());
1097 error("redundant alignment attribute `align`");
1100 pAttrs
.setAlignment
= true;
1102 a
= parseBlock(pLastDecl
, pAttrs
);
1103 if (pAttrs
.setAlignment
)
1105 s
= new AST
.AlignDeclaration(attrLoc
, pAttrs
.ealign
, a
);
1106 pAttrs
.setAlignment
= false;
1107 pAttrs
.ealign
= null;
1113 AST
.Expressions
* args
= null;
1114 const loc
= token
.loc
;
1117 check(TOK
.leftParenthesis
);
1118 if (token
.value
!= TOK
.identifier
)
1120 error("`pragma(identifier)` expected");
1123 Identifier ident
= token
.ident
;
1125 if (token
.value
== TOK
.comma
&& peekNext() != TOK
.rightParenthesis
)
1126 args
= parseArguments(); // pragma(identifier, args...)
1128 check(TOK
.rightParenthesis
); // pragma(identifier)
1130 AST
.Dsymbols
* a2
= null;
1131 if (token
.value
== TOK
.semicolon
)
1133 /* https://issues.dlang.org/show_bug.cgi?id=2354
1134 * Accept single semicolon as an empty
1135 * DeclarationBlock following attribute.
1137 * Attribute DeclarationBlock
1144 a2
= parseBlock(pLastDecl
);
1145 s
= new AST
.PragmaDeclaration(loc
, ident
, args
, a2
);
1149 startloc
= token
.loc
;
1151 if (token
.value
== TOK
.assign
)
1154 if (token
.value
== TOK
.identifier
)
1155 s
= new AST
.DebugSymbol(token
.loc
, token
.ident
);
1156 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
1157 s
= new AST
.DebugSymbol(token
.loc
, cast(uint)token
.unsvalue
);
1160 error("identifier or integer expected, not `%s`", token
.toChars());
1164 if (token
.value
!= TOK
.semicolon
)
1165 error("semicolon expected");
1170 condition
= parseDebugCondition();
1174 startloc
= token
.loc
;
1176 if (token
.value
== TOK
.assign
)
1179 if (token
.value
== TOK
.identifier
)
1180 s
= new AST
.VersionSymbol(token
.loc
, token
.ident
);
1181 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
1182 s
= new AST
.VersionSymbol(token
.loc
, cast(uint)token
.unsvalue
);
1185 error("identifier or integer expected, not `%s`", token
.toChars());
1189 if (token
.value
!= TOK
.semicolon
)
1190 error("semicolon expected");
1194 condition
= parseVersionCondition();
1199 AST
.Dsymbols
* athen
;
1200 if (token
.value
== TOK
.colon
)
1201 athen
= parseBlock(pLastDecl
);
1204 const lookingForElseSave
= lookingForElse
;
1205 lookingForElse
= token
.loc
;
1206 athen
= parseBlock(pLastDecl
);
1207 lookingForElse
= lookingForElseSave
;
1209 AST
.Dsymbols
* aelse
= null;
1210 if (token
.value
== TOK
.else_
)
1212 const elseloc
= token
.loc
;
1214 aelse
= parseBlock(pLastDecl
);
1215 checkDanglingElse(elseloc
);
1217 s
= new AST
.ConditionalDeclaration(startloc
, condition
, athen
, aelse
);
1221 // empty declaration
1222 //error("empty declaration");
1227 error("declaration expected, not `%s`", token
.toChars());
1229 while (token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
1238 if (!s
.isAttribDeclaration())
1241 addComment(s
, pAttrs
.comment
);
1243 else if (a
&& a
.dim
)
1255 /*****************************************
1256 * Parse auto declarations of the form:
1257 * storageClass ident = init, ident = init, ... ;
1258 * and return the array of them.
1259 * Starts with token on the first ident.
1260 * Ends with scanner past closing ';'
1262 private AST
.Dsymbols
* parseAutoDeclarations(StorageClass storageClass
, const(char)* comment
)
1264 //printf("parseAutoDeclarations\n");
1265 auto a
= new AST
.Dsymbols();
1269 const loc
= token
.loc
;
1270 Identifier ident
= token
.ident
;
1271 nextToken(); // skip over ident
1273 AST
.TemplateParameters
* tpl
= null;
1274 if (token
.value
== TOK
.leftParenthesis
)
1275 tpl
= parseTemplateParameterList();
1277 check(TOK
.assign
); // skip over '='
1278 AST
.Initializer _init
= parseInitializer();
1279 auto v
= new AST
.VarDeclaration(loc
, null, ident
, _init
, storageClass
);
1284 auto a2
= new AST
.Dsymbols();
1286 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
, 0);
1290 switch (token
.value
)
1294 addComment(s
, comment
);
1299 if (!(token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
)))
1301 error("identifier expected following comma");
1304 addComment(s
, comment
);
1308 error("semicolon expected following auto declaration, not `%s`", token
.toChars());
1316 /********************************************
1317 * Parse declarations after an align, visibility, or extern decl.
1319 private AST
.Dsymbols
* parseBlock(AST
.Dsymbol
* pLastDecl
, PrefixAttributes
!AST
* pAttrs
= null)
1321 AST
.Dsymbols
* a
= null;
1323 //printf("parseBlock()\n");
1324 switch (token
.value
)
1327 error("declaration expected following attribute, not `;`");
1332 error("declaration expected following attribute, not end of file");
1337 const lookingForElseSave
= lookingForElse
;
1338 lookingForElse
= Loc();
1341 a
= parseDeclDefs(0, pLastDecl
);
1342 if (token
.value
!= TOK
.rightCurly
)
1345 error("matching `}` expected, not `%s`", token
.toChars());
1349 lookingForElse
= lookingForElseSave
;
1354 a
= parseDeclDefs(0, pLastDecl
); // grab declarations up to closing curly bracket
1358 a
= parseDeclDefs(1, pLastDecl
, pAttrs
);
1365 * Provide an error message if `added` contains storage classes which are
1366 * redundant with those in `orig`; otherwise, return the combination.
1369 * orig = The already applied storage class.
1370 * added = The new storage class to add to `orig`.
1373 * The combination of both storage classes (`orig | added`).
1375 private StorageClass
appendStorageClass(StorageClass orig
, StorageClass added
)
1380 AST
.stcToBuffer(&buf
, added
);
1381 error("redundant attribute `%s`", buf
.peekChars());
1382 return orig | added
;
1385 const Redundant
= (STC
.const_ | STC
.scope_ |
1386 (global
.params
.previewIn ? STC
.ref_
: 0));
1389 if ((orig
& STC
.in_
) && (added
& Redundant
))
1391 if (added
& STC
.const_
)
1392 error("attribute `const` is redundant with previously-applied `in`");
1393 else if (global
.params
.previewIn
)
1395 error("attribute `%s` is redundant with previously-applied `in`",
1396 (orig
& STC
.scope_
) ?
"scope".ptr
: "ref".ptr
);
1399 error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
1403 if ((added
& STC
.in_
) && (orig
& Redundant
))
1405 if (orig
& STC
.const_
)
1406 error("attribute `in` cannot be added after `const`: remove `const`");
1407 else if (global
.params
.previewIn
)
1409 // Windows `printf` does not support `%1$s`
1410 const(char*) stc_str
= (orig
& STC
.scope_
) ?
"scope".ptr
: "ref".ptr
;
1411 error("attribute `in` cannot be added after `%s`: remove `%s`",
1415 error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
1419 if (added
& (STC
.const_ | STC
.immutable_ | STC
.manifest
))
1421 StorageClass u
= orig
& (STC
.const_ | STC
.immutable_ | STC
.manifest
);
1423 error("conflicting attribute `%s`", Token
.toChars(token
.value
));
1425 if (added
& (STC
.gshared | STC
.shared_ | STC
.tls
))
1427 StorageClass u
= orig
& (STC
.gshared | STC
.shared_ | STC
.tls
);
1429 error("conflicting attribute `%s`", Token
.toChars(token
.value
));
1431 if (added
& STC
.safeGroup
)
1433 StorageClass u
= orig
& STC
.safeGroup
;
1435 error("conflicting attribute `@%s`", token
.toChars());
1441 /***********************************************
1442 * Parse attribute(s), lexer is on '@'.
1444 * Attributes can be builtin (e.g. `@safe`, `@nogc`, etc...),
1445 * or be user-defined (UDAs). In the former case, we return the storage
1446 * class via the return value, while in thelater case we return `0`
1450 * pudas = An array of UDAs to append to
1453 * If the attribute is builtin, the return value will be non-zero.
1454 * Otherwise, 0 is returned, and `pudas` will be appended to.
1456 private StorageClass
parseAttribute(ref AST
.Expressions
* udas
)
1459 if (token
.value
== TOK
.identifier
)
1461 // If we find a builtin attribute, we're done, return immediately.
1462 if (StorageClass
stc = isBuiltinAtAttribute(token
.ident
))
1465 // Allow identifier, template instantiation, or function call
1466 // for `@Argument` (single UDA) form.
1467 AST
.Expression exp
= parsePrimaryExp();
1468 if (token
.value
== TOK
.leftParenthesis
)
1470 const loc
= token
.loc
;
1471 exp
= new AST
.CallExp(loc
, exp
, parseArguments());
1475 udas
= new AST
.Expressions();
1480 if (token
.value
== TOK
.leftParenthesis
)
1482 // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
1483 if (peekNext() == TOK
.rightParenthesis
)
1484 error("empty attribute list is not allowed");
1485 udas
= AST
.UserAttributeDeclaration
.concat(udas
, parseArguments());
1489 if (token
.isKeyword())
1490 error("`%s` is a keyword, not an `@` attribute", token
.toChars());
1492 error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token
.toChars());
1497 /***********************************************
1498 * Parse const/immutable/shared/inout/nothrow/pure postfix
1500 private StorageClass
parsePostfix(StorageClass storageClass
, AST
.Expressions
** pudas
)
1505 switch (token
.value
)
1511 case TOK
.immutable_
:
1512 stc = STC
.immutable_
;
1541 AST
.Expressions
* udas
= null;
1542 stc = parseAttribute(udas
);
1546 *pudas
= AST
.UserAttributeDeclaration
.concat(*pudas
, udas
);
1550 // void function() @uda fp;
1551 // () @uda { return 1; }
1552 error("user-defined attributes cannot appear as postfixes");
1559 return storageClass
;
1561 storageClass
= appendStorageClass(storageClass
, stc);
1566 private StorageClass
parseTypeCtor()
1568 StorageClass storageClass
= STC
.undefined_
;
1572 if (peekNext() == TOK
.leftParenthesis
)
1573 return storageClass
;
1576 switch (token
.value
)
1582 case TOK
.immutable_
:
1583 stc = STC
.immutable_
;
1595 return storageClass
;
1597 storageClass
= appendStorageClass(storageClass
, stc);
1602 /**************************************
1604 * Constraint is of the form:
1605 * if ( ConstraintExpression )
1607 private AST
.Expression
parseConstraint()
1609 AST
.Expression e
= null;
1610 if (token
.value
== TOK
.if_
)
1612 nextToken(); // skip over 'if'
1613 check(TOK
.leftParenthesis
);
1614 e
= parseExpression();
1615 check(TOK
.rightParenthesis
);
1620 /**************************************
1621 * Parse a TemplateDeclaration.
1623 private AST
.TemplateDeclaration
parseTemplateDeclaration(bool ismixin
= false)
1625 AST
.TemplateDeclaration tempdecl
;
1627 AST
.TemplateParameters
* tpl
;
1628 AST
.Dsymbols
* decldefs
;
1629 AST
.Expression constraint
= null;
1630 const loc
= token
.loc
;
1633 if (token
.value
!= TOK
.identifier
)
1635 error("identifier expected following `template`");
1640 tpl
= parseTemplateParameterList();
1644 constraint
= parseConstraint();
1646 if (token
.value
!= TOK
.leftCurly
)
1648 error("members of template declaration expected");
1651 decldefs
= parseBlock(null);
1653 tempdecl
= new AST
.TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
, ismixin
);
1660 /******************************************
1661 * Parse template parameter list.
1663 * flag 0: parsing "( list )"
1664 * 1: parsing non-empty "list $(RPAREN)"
1666 private AST
.TemplateParameters
* parseTemplateParameterList(int flag
= 0)
1668 auto tpl
= new AST
.TemplateParameters();
1670 if (!flag
&& token
.value
!= TOK
.leftParenthesis
)
1672 error("parenthesized template parameter list expected following template identifier");
1677 // Get array of TemplateParameters
1678 if (flag || token
.value
!= TOK
.rightParenthesis
)
1680 while (token
.value
!= TOK
.rightParenthesis
)
1682 AST
.TemplateParameter tp
;
1684 Identifier tp_ident
= null;
1685 AST
.Type tp_spectype
= null;
1686 AST
.Type tp_valtype
= null;
1687 AST
.Type tp_defaulttype
= null;
1688 AST
.Expression tp_specvalue
= null;
1689 AST
.Expression tp_defaultvalue
= null;
1691 // Get TemplateParameter
1693 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1694 const tv
= peekNext();
1695 if (token
.value
== TOK
.alias_
)
1699 loc
= token
.loc
; // todo
1700 AST
.Type spectype
= null;
1701 if (isDeclaration(&token
, NeedDeclaratorId
.must
, TOK
.reserved
, null))
1703 spectype
= parseType(&tp_ident
);
1707 if (token
.value
!= TOK
.identifier
)
1709 error("identifier expected for template `alias` parameter");
1712 tp_ident
= token
.ident
;
1715 RootObject spec
= null;
1716 if (token
.value
== TOK
.colon
) // : Type
1719 if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.reserved
, null))
1722 spec
= parseCondExp();
1724 RootObject def
= null;
1725 if (token
.value
== TOK
.assign
) // = Type
1728 if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.reserved
, null))
1731 def
= parseCondExp();
1733 tp
= new AST
.TemplateAliasParameter(loc
, tp_ident
, spectype
, spec
, def
);
1735 else if (tv
== TOK
.colon || tv
== TOK
.assign || tv
== TOK
.comma || tv
== TOK
.rightParenthesis
)
1738 if (token
.value
!= TOK
.identifier
)
1740 error("identifier expected for template type parameter");
1744 tp_ident
= token
.ident
;
1746 if (token
.value
== TOK
.colon
) // : Type
1749 tp_spectype
= parseType();
1751 if (token
.value
== TOK
.assign
) // = Type
1754 tp_defaulttype
= parseType();
1756 tp
= new AST
.TemplateTypeParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1758 else if (token
.value
== TOK
.identifier
&& tv
== TOK
.dotDotDot
)
1762 tp_ident
= token
.ident
;
1765 tp
= new AST
.TemplateTupleParameter(loc
, tp_ident
);
1767 else if (token
.value
== TOK
.this_
)
1771 if (token
.value
!= TOK
.identifier
)
1773 error("identifier expected for template `this` parameter");
1777 tp_ident
= token
.ident
;
1779 if (token
.value
== TOK
.colon
) // : Type
1782 tp_spectype
= parseType();
1784 if (token
.value
== TOK
.assign
) // = Type
1787 tp_defaulttype
= parseType();
1789 tp
= new AST
.TemplateThisParameter(loc
, tp_ident
, tp_spectype
, tp_defaulttype
);
1794 loc
= token
.loc
; // todo
1795 tp_valtype
= parseType(&tp_ident
);
1798 error("identifier expected for template value parameter");
1799 tp_ident
= Identifier
.idPool("error");
1801 if (token
.value
== TOK
.colon
) // : CondExpression
1804 tp_specvalue
= parseCondExp();
1806 if (token
.value
== TOK
.assign
) // = CondExpression
1809 tp_defaultvalue
= parseDefaultInitExp();
1811 tp
= new AST
.TemplateValueParameter(loc
, tp_ident
, tp_valtype
, tp_specvalue
, tp_defaultvalue
);
1814 if (token
.value
!= TOK
.comma
)
1819 check(TOK
.rightParenthesis
);
1825 /******************************************
1826 * Parse template mixin.
1829 * mixin a.b.c!(args).Foo!(args);
1830 * mixin Foo!(args) identifier;
1831 * mixin typeof(expr).identifier!(args);
1833 private AST
.Dsymbol
parseMixin()
1835 AST
.TemplateMixin tm
;
1837 AST
.Objects
* tiargs
;
1839 //printf("parseMixin()\n");
1840 const locMixin
= token
.loc
;
1841 nextToken(); // skip 'mixin'
1843 auto loc
= token
.loc
;
1844 AST
.TypeQualified tqual
= null;
1845 if (token
.value
== TOK
.dot
)
1851 if (token
.value
== TOK
.typeof_
)
1853 tqual
= parseTypeof();
1856 if (token
.value
!= TOK
.identifier
)
1858 error("identifier expected, not `%s`", token
.toChars());
1869 if (token
.value
== TOK
.not)
1871 tiargs
= parseTemplateArguments();
1874 if (tiargs
&& token
.value
== TOK
.dot
)
1876 auto tempinst
= new AST
.TemplateInstance(loc
, id
, tiargs
);
1878 tqual
= new AST
.TypeInstance(loc
, tempinst
);
1880 tqual
.addInst(tempinst
);
1886 tqual
= new AST
.TypeIdentifier(loc
, id
);
1891 if (token
.value
!= TOK
.dot
)
1895 if (token
.value
!= TOK
.identifier
)
1897 error("identifier expected following `.` instead of `%s`", token
.toChars());
1906 if (token
.value
== TOK
.identifier
)
1912 tm
= new AST
.TemplateMixin(locMixin
, id
, tqual
, tiargs
);
1913 if (token
.value
!= TOK
.semicolon
)
1914 error("`;` expected after `mixin`");
1920 /******************************************
1921 * Parse template arguments.
1923 * current token is opening '!'
1925 * current token is one after closing '$(RPAREN)'
1927 private AST
.Objects
* parseTemplateArguments()
1929 AST
.Objects
* tiargs
;
1932 if (token
.value
== TOK
.leftParenthesis
)
1934 // ident!(template_arguments)
1935 tiargs
= parseTemplateArgumentList();
1939 // ident!template_argument
1940 tiargs
= parseTemplateSingleArgument();
1942 if (token
.value
== TOK
.not)
1944 TOK tok
= peekNext();
1945 if (tok
!= TOK
.is_
&& tok
!= TOK
.in_
)
1947 error("multiple ! arguments are not allowed");
1950 if (token
.value
== TOK
.leftParenthesis
)
1951 parseTemplateArgumentList();
1953 parseTemplateSingleArgument();
1954 if (token
.value
== TOK
.not && (tok
= peekNext()) != TOK
.is_
&& tok
!= TOK
.in_
)
1961 /******************************************
1962 * Parse template argument list.
1964 * current token is opening '$(LPAREN)',
1965 * or ',' for __traits
1967 * current token is one after closing '$(RPAREN)'
1969 private AST
.Objects
* parseTemplateArgumentList()
1971 //printf("Parser::parseTemplateArgumentList()\n");
1972 auto tiargs
= new AST
.Objects();
1973 TOK endtok
= TOK
.rightParenthesis
;
1974 assert(token
.value
== TOK
.leftParenthesis || token
.value
== TOK
.comma
);
1977 // Get TemplateArgumentList
1978 while (token
.value
!= endtok
)
1980 tiargs
.push(parseTypeOrAssignExp());
1981 if (token
.value
!= TOK
.comma
)
1985 check(endtok
, "template argument list");
1989 /***************************************
1990 * Parse a Type or an Expression
1992 * RootObject representing the AST
1994 RootObject
parseTypeOrAssignExp(TOK endtoken
= TOK
.reserved
)
1996 return isDeclaration(&token
, NeedDeclaratorId
.no
, endtoken
, null)
1997 ?
parseType() // argument is a type
1998 : parseAssignExp(); // argument is an expression
2001 /*****************************
2002 * Parse single template argument, to support the syntax:
2005 * current token is the arg
2007 private AST
.Objects
* parseTemplateSingleArgument()
2009 //printf("parseTemplateSingleArgument()\n");
2010 auto tiargs
= new AST
.Objects();
2012 switch (token
.value
)
2014 case TOK
.identifier
:
2015 ta
= new AST
.TypeIdentifier(token
.loc
, token
.ident
);
2023 ta
= AST
.Type
.tvoid
;
2027 ta
= AST
.Type
.tint8
;
2031 ta
= AST
.Type
.tuns8
;
2035 ta
= AST
.Type
.tint16
;
2039 ta
= AST
.Type
.tuns16
;
2043 ta
= AST
.Type
.tint32
;
2047 ta
= AST
.Type
.tuns32
;
2051 ta
= AST
.Type
.tint64
;
2055 ta
= AST
.Type
.tuns64
;
2059 ta
= AST
.Type
.tint128
;
2063 ta
= AST
.Type
.tuns128
;
2067 ta
= AST
.Type
.tfloat32
;
2071 ta
= AST
.Type
.tfloat64
;
2075 ta
= AST
.Type
.tfloat80
;
2078 case TOK
.imaginary32
:
2079 ta
= AST
.Type
.timaginary32
;
2082 case TOK
.imaginary64
:
2083 ta
= AST
.Type
.timaginary64
;
2086 case TOK
.imaginary80
:
2087 ta
= AST
.Type
.timaginary80
;
2091 ta
= AST
.Type
.tcomplex32
;
2095 ta
= AST
.Type
.tcomplex64
;
2099 ta
= AST
.Type
.tcomplex80
;
2103 ta
= AST
.Type
.tbool
;
2107 ta
= AST
.Type
.tchar
;
2111 ta
= AST
.Type
.twchar
;
2115 ta
= AST
.Type
.tdchar
;
2122 case TOK
.int32Literal
:
2123 case TOK
.uns32Literal
:
2124 case TOK
.int64Literal
:
2125 case TOK
.uns64Literal
:
2126 case TOK
.int128Literal
:
2127 case TOK
.uns128Literal
:
2128 case TOK
.float32Literal
:
2129 case TOK
.float64Literal
:
2130 case TOK
.float80Literal
:
2131 case TOK
.imaginary32Literal
:
2132 case TOK
.imaginary64Literal
:
2133 case TOK
.imaginary80Literal
:
2137 case TOK
.charLiteral
:
2138 case TOK
.wcharLiteral
:
2139 case TOK
.dcharLiteral
:
2141 case TOK
.hexadecimalString
:
2143 case TOK
.fileFullPath
:
2145 case TOK
.moduleString
:
2146 case TOK
.functionString
:
2147 case TOK
.prettyFunction
:
2150 // Template argument is an expression
2151 AST
.Expression ea
= parsePrimaryExp();
2156 error("template argument expected following `!`");
2162 /**********************************
2163 * Parse a static assertion.
2164 * Current token is 'static'.
2166 private AST
.StaticAssert
parseStaticAssert()
2168 const loc
= token
.loc
;
2170 AST
.Expression msg
= null;
2172 //printf("parseStaticAssert()\n");
2175 check(TOK
.leftParenthesis
);
2176 exp
= parseAssignExp();
2177 if (token
.value
== TOK
.comma
)
2180 if (token
.value
!= TOK
.rightParenthesis
)
2182 msg
= parseAssignExp();
2183 if (token
.value
== TOK
.comma
)
2187 check(TOK
.rightParenthesis
);
2188 check(TOK
.semicolon
);
2189 return new AST
.StaticAssert(loc
, exp
, msg
);
2192 /***********************************
2193 * Parse typeof(expression).
2194 * Current token is on the 'typeof'.
2196 private AST
.TypeQualified
parseTypeof()
2198 AST
.TypeQualified t
;
2199 const loc
= token
.loc
;
2202 check(TOK
.leftParenthesis
);
2203 if (token
.value
== TOK
.return_
) // typeof(return)
2206 t
= new AST
.TypeReturn(loc
);
2210 AST
.Expression exp
= parseExpression(); // typeof(expression)
2211 t
= new AST
.TypeTypeof(loc
, exp
);
2213 check(TOK
.rightParenthesis
);
2217 /***********************************
2218 * Parse __vector(type).
2219 * Current token is on the '__vector'.
2221 private AST
.Type
parseVector()
2224 check(TOK
.leftParenthesis
);
2225 AST
.Type tb
= parseType();
2226 check(TOK
.rightParenthesis
);
2227 return new AST
.TypeVector(tb
);
2230 /***********************************
2233 * extern (C++, namespaces)
2234 * extern (C++, "namespace", "namespaces", ...)
2235 * extern (C++, (StringExp))
2236 * The parser is on the 'extern' token.
2238 private ParsedLinkage
!(AST
) parseLinkage()
2240 ParsedLinkage
!(AST
) result
;
2242 assert(token
.value
== TOK
.leftParenthesis
);
2244 ParsedLinkage
!(AST
) returnLinkage(LINK link
)
2246 check(TOK
.rightParenthesis
);
2250 ParsedLinkage
!(AST
) invalidLinkage()
2252 error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Windows`, `System`");
2253 return returnLinkage(LINK
.d
);
2256 if (token
.value
!= TOK
.identifier
)
2257 return returnLinkage(LINK
.d
);
2259 Identifier id
= token
.ident
;
2261 if (id
== Id
.Windows
)
2262 return returnLinkage(LINK
.windows
);
2263 else if (id
== Id
.D
)
2264 return returnLinkage(LINK
.d
);
2265 else if (id
== Id
.System
)
2266 return returnLinkage(LINK
.system
);
2267 else if (id
== Id
.Objective
) // Looking for tokens "Objective-C"
2269 if (token
.value
!= TOK
.min
)
2270 return invalidLinkage();
2273 if (token
.ident
!= Id
.C
)
2274 return invalidLinkage();
2277 return returnLinkage(LINK
.objc
);
2279 else if (id
!= Id
.C
)
2280 return invalidLinkage();
2282 if (token
.value
!= TOK
.plusPlus
)
2283 return returnLinkage(LINK
.c
);
2286 if (token
.value
!= TOK
.comma
) // , namespaces or class or struct
2287 return returnLinkage(LINK
.cpp
);
2291 if (token
.value
== TOK
.rightParenthesis
)
2292 return returnLinkage(LINK
.cpp
); // extern(C++,)
2294 if (token
.value
== TOK
.class_ || token
.value
== TOK
.struct_
)
2296 result
.cppmangle
= token
.value
== TOK
.class_ ? CPPMANGLE
.asClass
: CPPMANGLE
.asStruct
;
2299 else if (token
.value
== TOK
.identifier
) // named scope namespace
2301 result
.idents
= new AST
.Identifiers();
2304 Identifier idn
= token
.ident
;
2305 result
.idents
.push(idn
);
2307 if (token
.value
== TOK
.dot
)
2310 if (token
.value
== TOK
.identifier
)
2312 error("identifier expected for C++ namespace");
2313 result
.idents
= null; // error occurred, invalidate list of elements.
2318 else // non-scoped StringExp namespace
2320 result
.identExps
= new AST
.Expressions();
2323 result
.identExps
.push(parseCondExp());
2324 if (token
.value
!= TOK
.comma
)
2327 // Allow trailing commas as done for argument lists, arrays, ...
2328 if (token
.value
== TOK
.rightParenthesis
)
2332 return returnLinkage(LINK
.cpp
);
2335 /***********************************
2336 * Parse ident1.ident2.ident3
2339 * entity = what qualified identifier is expected to resolve into.
2340 * Used only for better error message
2343 * array of identifiers with actual qualified one stored last
2345 private Identifier
[] parseQualifiedIdentifier(const(char)* entity
)
2347 Identifier
[] qualified
;
2352 if (token
.value
!= TOK
.identifier
)
2354 error("`%s` expected as dot-separated identifiers, got `%s`", entity
, token
.toChars());
2358 Identifier id
= token
.ident
;
2363 while (token
.value
== TOK
.dot
);
2368 /**************************************
2369 * Parse a debug conditional
2371 private AST
.Condition
parseDebugCondition()
2374 Identifier id
= null;
2375 Loc loc
= token
.loc
;
2377 if (token
.value
== TOK
.leftParenthesis
)
2381 if (token
.value
== TOK
.identifier
)
2383 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2384 level
= cast(uint)token
.unsvalue
;
2386 error("identifier or integer expected inside `debug(...)`, not `%s`", token
.toChars());
2389 check(TOK
.rightParenthesis
);
2391 return new AST
.DebugCondition(loc
, mod
, level
, id
);
2394 /**************************************
2395 * Parse a version conditional
2397 private AST
.Condition
parseVersionCondition()
2400 Identifier id
= null;
2403 if (token
.value
== TOK
.leftParenthesis
)
2407 * version (unittest)
2409 * even though they are keywords
2412 if (token
.value
== TOK
.identifier
)
2414 else if (token
.value
== TOK
.int32Literal || token
.value
== TOK
.int64Literal
)
2415 level
= cast(uint)token
.unsvalue
;
2416 else if (token
.value
== TOK
.unittest_
)
2417 id
= Identifier
.idPool(Token
.toString(TOK
.unittest_
));
2418 else if (token
.value
== TOK
.assert_
)
2419 id
= Identifier
.idPool(Token
.toString(TOK
.assert_
));
2421 error("identifier or integer expected inside `version(...)`, not `%s`", token
.toChars());
2423 check(TOK
.rightParenthesis
);
2426 error("(condition) expected following `version`");
2427 return new AST
.VersionCondition(loc
, mod
, level
, id
);
2430 /***********************************************
2431 * static if (expression)
2435 * Current token is 'static'.
2437 private AST
.Condition
parseStaticIfCondition()
2440 AST
.Condition condition
;
2441 const loc
= token
.loc
;
2445 if (token
.value
== TOK
.leftParenthesis
)
2448 exp
= parseAssignExp();
2449 check(TOK
.rightParenthesis
);
2453 error("(expression) expected following `static if`");
2456 condition
= new AST
.StaticIfCondition(loc
, exp
);
2460 /*****************************************
2461 * Parse a constructor definition:
2462 * this(parameters) { body }
2464 * this(this) { body }
2465 * or constructor template:
2466 * this(templateparameters)(parameters) { body }
2467 * Current token is 'this'.
2469 private AST
.Dsymbol
parseCtor(PrefixAttributes
!AST
* pAttrs
)
2471 AST
.Expressions
* udas
= null;
2472 const loc
= token
.loc
;
2473 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2476 if (token
.value
== TOK
.leftParenthesis
&& peekNext() == TOK
.this_
&& peekNext2() == TOK
.rightParenthesis
)
2478 // this(this) { ... }
2481 check(TOK
.rightParenthesis
);
2483 stc = parsePostfix(stc, &udas
);
2484 if (stc & STC
.immutable_
)
2485 deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit.");
2486 if (stc & STC
.shared_
)
2487 deprecation("`shared` postblit is deprecated. Please use an unqualified postblit.");
2488 if (stc & STC
.const_
)
2489 deprecation("`const` postblit is deprecated. Please use an unqualified postblit.");
2490 if (stc & STC
.static_
)
2491 error(loc
, "postblit cannot be `static`");
2493 auto f
= new AST
.PostBlitDeclaration(loc
, Loc
.initial
, stc, Id
.postblit
);
2494 AST
.Dsymbol s
= parseContracts(f
);
2497 auto a
= new AST
.Dsymbols();
2499 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2504 /* Look ahead to see if:
2506 * which is a constructor template
2508 AST
.TemplateParameters
* tpl
= null;
2509 if (token
.value
== TOK
.leftParenthesis
&& peekPastParen(&token
).value
== TOK
.leftParenthesis
)
2511 tpl
= parseTemplateParameterList();
2514 /* Just a regular constructor
2516 auto parameterList
= parseParameterList(null);
2517 stc = parsePostfix(stc, &udas
);
2519 if (parameterList
.varargs
!= VarArg
.none || AST
.Parameter
.dim(parameterList
.parameters
) != 0)
2521 if (stc & STC
.static_
)
2522 error(loc
, "constructor cannot be static");
2524 else if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
)) // this()
2526 if (ss
== STC
.static_
)
2527 error(loc
, "use `static this()` to declare a static constructor");
2528 else if (ss
== (STC
.shared_ | STC
.static_
))
2529 error(loc
, "use `shared static this()` to declare a shared static constructor");
2532 AST
.Expression constraint
= tpl ?
parseConstraint() : null;
2534 AST
.Type tf
= new AST
.TypeFunction(parameterList
, null, linkage
, stc); // RetrunType -> auto
2535 tf
= tf
.addSTC(stc);
2537 auto f
= new AST
.CtorDeclaration(loc
, Loc
.initial
, stc, tf
);
2538 AST
.Dsymbol s
= parseContracts(f
);
2541 auto a
= new AST
.Dsymbols();
2543 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2548 // Wrap a template around it
2549 auto decldefs
= new AST
.Dsymbols();
2551 s
= new AST
.TemplateDeclaration(loc
, f
.ident
, tpl
, constraint
, decldefs
);
2557 /*****************************************
2558 * Parse a destructor definition:
2560 * Current token is '~'.
2562 private AST
.Dsymbol
parseDtor(PrefixAttributes
!AST
* pAttrs
)
2564 AST
.Expressions
* udas
= null;
2565 const loc
= token
.loc
;
2566 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2570 check(TOK
.leftParenthesis
);
2571 check(TOK
.rightParenthesis
);
2573 stc = parsePostfix(stc, &udas
);
2574 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2576 if (ss
== STC
.static_
)
2577 error(loc
, "use `static ~this()` to declare a static destructor");
2578 else if (ss
== (STC
.shared_ | STC
.static_
))
2579 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
2582 auto f
= new AST
.DtorDeclaration(loc
, Loc
.initial
, stc, Id
.dtor
);
2583 AST
.Dsymbol s
= parseContracts(f
);
2586 auto a
= new AST
.Dsymbols();
2588 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2593 /*****************************************
2594 * Parse a static constructor definition:
2595 * static this() { body }
2596 * Current token is 'static'.
2598 private AST
.Dsymbol
parseStaticCtor(PrefixAttributes
!AST
* pAttrs
)
2600 //Expressions *udas = NULL;
2601 const loc
= token
.loc
;
2602 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2606 check(TOK
.leftParenthesis
);
2607 check(TOK
.rightParenthesis
);
2609 stc = parsePostfix(stc & ~STC
.TYPECTOR
, null) |
stc;
2610 if (stc & STC
.shared_
)
2611 error(loc
, "use `shared static this()` to declare a shared static constructor");
2612 else if (stc & STC
.static_
)
2613 appendStorageClass(stc, STC
.static_
); // complaint for the redundancy
2614 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2617 AST
.stcToBuffer(&buf
, modStc
);
2618 error(loc
, "static constructor cannot be `%s`", buf
.peekChars());
2620 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2622 auto f
= new AST
.StaticCtorDeclaration(loc
, Loc
.initial
, stc);
2623 AST
.Dsymbol s
= parseContracts(f
);
2627 /*****************************************
2628 * Parse a static destructor definition:
2629 * static ~this() { body }
2630 * Current token is 'static'.
2632 private AST
.Dsymbol
parseStaticDtor(PrefixAttributes
!AST
* pAttrs
)
2634 AST
.Expressions
* udas
= null;
2635 const loc
= token
.loc
;
2636 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2641 check(TOK
.leftParenthesis
);
2642 check(TOK
.rightParenthesis
);
2644 stc = parsePostfix(stc & ~STC
.TYPECTOR
, &udas
) |
stc;
2645 if (stc & STC
.shared_
)
2646 error(loc
, "use `shared static ~this()` to declare a shared static destructor");
2647 else if (stc & STC
.static_
)
2648 appendStorageClass(stc, STC
.static_
); // complaint for the redundancy
2649 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2652 AST
.stcToBuffer(&buf
, modStc
);
2653 error(loc
, "static destructor cannot be `%s`", buf
.peekChars());
2655 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2657 auto f
= new AST
.StaticDtorDeclaration(loc
, Loc
.initial
, stc);
2658 AST
.Dsymbol s
= parseContracts(f
);
2661 auto a
= new AST
.Dsymbols();
2663 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2668 /*****************************************
2669 * Parse a shared static constructor definition:
2670 * shared static this() { body }
2671 * Current token is 'shared'.
2673 private AST
.Dsymbol
parseSharedStaticCtor(PrefixAttributes
!AST
* pAttrs
)
2675 //Expressions *udas = NULL;
2676 const loc
= token
.loc
;
2677 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2682 check(TOK
.leftParenthesis
);
2683 check(TOK
.rightParenthesis
);
2685 stc = parsePostfix(stc & ~STC
.TYPECTOR
, null) |
stc;
2686 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2687 appendStorageClass(stc, ss
); // complaint for the redundancy
2688 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2691 AST
.stcToBuffer(&buf
, modStc
);
2692 error(loc
, "shared static constructor cannot be `%s`", buf
.peekChars());
2694 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2696 auto f
= new AST
.SharedStaticCtorDeclaration(loc
, Loc
.initial
, stc);
2697 AST
.Dsymbol s
= parseContracts(f
);
2701 /*****************************************
2702 * Parse a shared static destructor definition:
2703 * shared static ~this() { body }
2704 * Current token is 'shared'.
2706 private AST
.Dsymbol
parseSharedStaticDtor(PrefixAttributes
!AST
* pAttrs
)
2708 AST
.Expressions
* udas
= null;
2709 const loc
= token
.loc
;
2710 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2716 check(TOK
.leftParenthesis
);
2717 check(TOK
.rightParenthesis
);
2719 stc = parsePostfix(stc & ~STC
.TYPECTOR
, &udas
) |
stc;
2720 if (StorageClass ss
= stc & (STC
.shared_ | STC
.static_
))
2721 appendStorageClass(stc, ss
); // complaint for the redundancy
2722 else if (StorageClass modStc
= stc & STC
.TYPECTOR
)
2725 AST
.stcToBuffer(&buf
, modStc
);
2726 error(loc
, "shared static destructor cannot be `%s`", buf
.peekChars());
2728 stc &= ~(STC
.static_ | STC
.TYPECTOR
);
2730 auto f
= new AST
.SharedStaticDtorDeclaration(loc
, Loc
.initial
, stc);
2731 AST
.Dsymbol s
= parseContracts(f
);
2734 auto a
= new AST
.Dsymbols();
2736 s
= new AST
.UserAttributeDeclaration(udas
, a
);
2741 /*****************************************
2742 * Parse an invariant definition:
2743 * invariant { statements... }
2744 * invariant() { statements... }
2745 * invariant (expression);
2746 * Current token is 'invariant'.
2748 private AST
.Dsymbol
parseInvariant(PrefixAttributes
!AST
* pAttrs
)
2750 const loc
= token
.loc
;
2751 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2754 if (token
.value
== TOK
.leftParenthesis
) // optional () or invariant (expression);
2757 if (token
.value
!= TOK
.rightParenthesis
) // invariant (expression);
2759 AST
.Expression e
= parseAssignExp(), msg
= null;
2760 if (token
.value
== TOK
.comma
)
2763 if (token
.value
!= TOK
.rightParenthesis
)
2765 msg
= parseAssignExp();
2766 if (token
.value
== TOK
.comma
)
2770 check(TOK
.rightParenthesis
);
2771 check(TOK
.semicolon
);
2772 e
= new AST
.AssertExp(loc
, e
, msg
);
2773 auto fbody
= new AST
.ExpStatement(loc
, e
);
2774 auto f
= new AST
.InvariantDeclaration(loc
, token
.loc
, stc, null, fbody
);
2780 auto fbody
= parseStatement(ParseStatementFlags
.curly
);
2781 auto f
= new AST
.InvariantDeclaration(loc
, token
.loc
, stc, null, fbody
);
2785 /*****************************************
2786 * Parse a unittest definition:
2788 * Current token is 'unittest'.
2790 private AST
.Dsymbol
parseUnitTest(PrefixAttributes
!AST
* pAttrs
)
2792 const loc
= token
.loc
;
2793 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2797 const(char)* begPtr
= token
.ptr
+ 1; // skip '{'
2798 const(char)* endPtr
= null;
2799 AST
.Statement sbody
= parseStatement(ParseStatementFlags
.curly
, &endPtr
);
2801 /** Extract unittest body as a string. Must be done eagerly since memory
2802 will be released by the lexer before doc gen. */
2803 char* docline
= null;
2804 if (global
.params
.doDocComments
&& endPtr
> begPtr
)
2806 /* Remove trailing whitespaces */
2807 for (const(char)* p
= endPtr
- 1; begPtr
<= p
&& (*p
== ' ' ||
*p
== '\r' ||
*p
== '\n' ||
*p
== '\t'); --p
)
2812 size_t len
= endPtr
- begPtr
;
2815 docline
= cast(char*)mem
.xmalloc_noscan(len
+ 2);
2816 memcpy(docline
, begPtr
, len
);
2817 docline
[len
] = '\n'; // Terminate all lines by LF
2818 docline
[len
+ 1] = '\0';
2822 auto f
= new AST
.UnitTestDeclaration(loc
, token
.loc
, stc, docline
);
2827 /*****************************************
2828 * Parse a new definition:
2830 * Current token is 'new'.
2832 private AST
.Dsymbol
parseNew(PrefixAttributes
!AST
* pAttrs
)
2834 const loc
= token
.loc
;
2835 StorageClass
stc = getStorageClass
!AST(pAttrs
);
2836 if (!(stc & STC
.disable
))
2838 error("`new` allocator must be annotated with `@disabled`");
2842 /* @@@DEPRECATED_2.098@@@
2843 * After deprecation period (2.108), remove all code in the version(all) block.
2847 auto parameterList
= parseParameterList(null); // parameterList ignored
2848 if (parameterList
.parameters
.length
> 0 || parameterList
.varargs
!= VarArg
.none
)
2849 deprecation("`new` allocator with non-empty parameter list is deprecated");
2850 auto f
= new AST
.NewDeclaration(loc
, stc);
2851 if (token
.value
!= TOK
.semicolon
)
2853 deprecation("`new` allocator with function definition is deprecated");
2854 parseContracts(f
); // body ignored
2865 check(TOK
.leftParenthesis
);
2866 check(TOK
.rightParenthesis
);
2867 check(TOK
.semicolon
);
2868 return new AST
.NewDeclaration(loc
, stc);
2872 /**********************************************
2873 * Parse parameter list.
2875 private AST
.ParameterList
parseParameterList(AST
.TemplateParameters
** tpl
)
2877 auto parameters
= new AST
.Parameters();
2878 VarArg varargs
= VarArg
.none
;
2880 StorageClass varargsStc
;
2882 // Attributes allowed for ...
2883 enum VarArgsStc
= STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.scope_ | STC
.return_
;
2885 check(TOK
.leftParenthesis
);
2888 Identifier ai
= null;
2890 StorageClass storageClass
= 0;
2893 AST
.Expressions
* udas
= null;
2894 for (; 1; nextToken())
2897 switch (token
.value
)
2899 case TOK
.rightParenthesis
:
2900 if (storageClass
!= 0 || udas
!is null)
2901 error("basic type expected, not `)`");
2905 varargs
= VarArg
.variadic
;
2906 varargsStc
= storageClass
;
2907 if (varargsStc
& ~VarArgsStc
)
2910 AST
.stcToBuffer(&buf
, varargsStc
& ~VarArgsStc
);
2911 error("variadic parameter cannot have attributes `%s`", buf
.peekChars());
2912 varargsStc
&= VarArgsStc
;
2918 if (peekNext() == TOK
.leftParenthesis
)
2923 case TOK
.immutable_
:
2924 if (peekNext() == TOK
.leftParenthesis
)
2926 stc = STC
.immutable_
;
2930 if (peekNext() == TOK
.leftParenthesis
)
2936 if (peekNext() == TOK
.leftParenthesis
)
2942 AST
.Expressions
* exps
= null;
2943 StorageClass stc2
= parseAttribute(exps
);
2944 if (stc2
& atAttrGroup
)
2946 error("`@%s` attribute for function parameter is not supported", token
.toChars());
2950 udas
= AST
.UserAttributeDeclaration
.concat(udas
, exps
);
2952 if (token
.value
== TOK
.dotDotDot
)
2953 error("variadic parameter cannot have user-defined attributes");
2957 // Don't call nextToken again.
2960 if (global
.params
.vin
)
2961 message(scanloc
, "Usage of 'in' on parameter");
2993 storageClass
= appendStorageClass(storageClass
, stc);
3003 storageClass
= STC
.auto_
;
3007 storageClass
= STC
.alias_
;
3012 if (token
.value
== TOK
.identifier
)
3018 at
= null; // no type
3019 ae
= null; // no default argument
3020 if (token
.value
== TOK
.assign
) // = defaultArg
3023 ae
= parseDefaultInitExp();
3029 error("default argument expected for `alias %s`", ai ? ai
.toChars() : "");
3035 stc = storageClass
& (STC
.IOR | STC
.lazy_
);
3036 // if stc is not a power of 2
3037 if (stc & (stc - 1) && !(stc == (STC
.in_ | STC
.ref_
)))
3038 error("incompatible parameter storage classes");
3039 //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
3040 //error("scope cannot be ref or out");
3042 if (tpl
&& token
.value
== TOK
.identifier
)
3044 const tv
= peekNext();
3045 if (tv
== TOK
.comma || tv
== TOK
.rightParenthesis || tv
== TOK
.dotDotDot
)
3047 Identifier id
= Identifier
.generateId("__T");
3048 const loc
= token
.loc
;
3049 at
= new AST
.TypeIdentifier(loc
, id
);
3051 *tpl
= new AST
.TemplateParameters();
3052 AST
.TemplateParameter tp
= new AST
.TemplateTypeParameter(loc
, id
, null, null);
3063 at
= parseType(&ai
);
3066 if (token
.value
== TOK
.assign
) // = defaultArg
3069 ae
= parseDefaultInitExp();
3075 error("default argument expected for `%s`", ai ? ai
.toChars() : at
.toChars());
3077 auto param
= new AST
.Parameter(storageClass | STC
.parameter
, at
, ai
, ae
, null);
3080 auto a
= new AST
.Dsymbols();
3081 auto udad
= new AST
.UserAttributeDeclaration(udas
, a
);
3082 param
.userAttribDecl
= udad
;
3084 if (token
.value
== TOK
.at
)
3086 AST
.Expressions
* exps
= null;
3087 StorageClass stc2
= parseAttribute(exps
);
3088 if (stc2
& atAttrGroup
)
3090 error("`@%s` attribute for function parameter is not supported", token
.toChars());
3094 error("user-defined attributes cannot appear as postfixes", token
.toChars());
3099 if (token
.value
== TOK
.dotDotDot
)
3104 if (storageClass
& (STC
.out_ | STC
.ref_
))
3105 error("variadic argument cannot be `out` or `ref`");
3106 varargs
= VarArg
.typesafe
;
3107 parameters
.push(param
);
3111 parameters
.push(param
);
3112 if (token
.value
== TOK
.comma
)
3126 check(TOK
.rightParenthesis
);
3127 return AST
.ParameterList(parameters
, varargs
, varargsStc
);
3130 /*************************************
3132 private AST
.EnumDeclaration
parseEnum()
3134 AST
.EnumDeclaration e
;
3137 auto loc
= token
.loc
;
3139 // printf("Parser::parseEnum()\n");
3142 if (token
.value
== TOK
.identifier
)
3149 if (token
.value
== TOK
.colon
)
3153 const typeLoc
= token
.loc
;
3154 memtype
= parseBasicType();
3155 memtype
= parseDeclarator(memtype
, alt
, null);
3156 checkCstyleTypeSyntax(typeLoc
, memtype
, alt
, null);
3159 e
= new AST
.EnumDeclaration(loc
, id
, memtype
);
3160 if (token
.value
== TOK
.semicolon
&& id
)
3162 else if (token
.value
== TOK
.leftCurly
)
3164 bool isAnonymousEnum
= !id
;
3167 //printf("enum definition\n");
3168 e
.members
= new AST
.Dsymbols();
3170 const(char)[] comment
= token
.blockComment
;
3171 while (token
.value
!= TOK
.rightCurly
)
3173 /* Can take the following forms...
3176 * 3. type ident = value
3177 * ... prefixed by valid attributes
3181 AST
.Type type
= null;
3182 Identifier ident
= null;
3184 AST
.Expressions
* udas
;
3186 AST
.Expression deprecationMessage
;
3187 enum attributeErrorMessage
= "`%s` is not a valid attribute for enum members";
3188 while(token
.value
!= TOK
.rightCurly
3189 && token
.value
!= TOK
.comma
3190 && token
.value
!= TOK
.assign
)
3195 if (StorageClass _stc
= parseAttribute(udas
))
3197 if (_stc
== STC
.disable
)
3202 AST
.stcToBuffer(&buf
, _stc
);
3203 error(attributeErrorMessage
, buf
.peekChars());
3205 prevTOK
= token
.value
;
3209 case TOK
.deprecated_
:
3210 stc |
= STC
.deprecated_
;
3211 if (!parseDeprecatedAttribute(deprecationMessage
))
3213 prevTOK
= token
.value
;
3217 case TOK
.identifier
:
3218 const tv
= peekNext();
3219 if (tv
== TOK
.assign || tv
== TOK
.comma || tv
== TOK
.rightCurly
)
3221 ident
= token
.ident
;
3223 prevTOK
= token
.value
;
3232 if (isAnonymousEnum
)
3234 type
= parseType(&ident
, null);
3235 if (type
== AST
.Type
.terror
)
3238 prevTOK
= token
.value
;
3243 prevTOK
= TOK
.identifier
;
3248 error(attributeErrorMessage
, token
.toChars());
3249 prevTOK
= token
.value
;
3254 if (token
.value
== TOK
.comma
)
3256 prevTOK
= token
.value
;
3260 if (type
&& type
!= AST
.Type
.terror
)
3263 error("no identifier for declarator `%s`", type
.toChars());
3264 if (!isAnonymousEnum
)
3265 error("type only allowed if anonymous enum and no enum type");
3267 AST
.Expression value
;
3268 if (token
.value
== TOK
.assign
)
3270 if (prevTOK
== TOK
.identifier
)
3273 value
= parseAssignExp();
3277 error("assignment must be preceded by an identifier");
3284 if (type
&& type
!= AST
.Type
.terror
&& isAnonymousEnum
)
3285 error("if type, there must be an initializer");
3288 AST
.DeprecatedDeclaration
dd;
3289 if (deprecationMessage
)
3291 dd = new AST
.DeprecatedDeclaration(deprecationMessage
, null);
3292 stc |
= STC
.deprecated_
;
3295 auto em
= new AST
.EnumMember(loc
, ident
, value
, type
, stc, null, dd);
3300 auto s
= new AST
.Dsymbols();
3302 auto uad
= new AST
.UserAttributeDeclaration(udas
, s
);
3303 em
.userAttribDecl
= uad
;
3306 if (token
.value
== TOK
.rightCurly
)
3311 addComment(em
, comment
);
3315 addComment(em
, comment
);
3316 comment
= token
.blockComment
;
3318 if (token
.value
== TOK
.endOfFile
)
3320 error("premature end of file");
3327 error("enum declaration is invalid");
3329 //printf("-parseEnum() %s\n", e.toChars());
3333 /********************************
3334 * Parse struct, union, interface, class.
3336 private AST
.Dsymbol
parseAggregate()
3338 AST
.TemplateParameters
* tpl
= null;
3339 AST
.Expression constraint
;
3340 const loc
= token
.loc
;
3341 TOK tok
= token
.value
;
3343 //printf("Parser::parseAggregate()\n");
3346 if (token
.value
!= TOK
.identifier
)
3355 if (token
.value
== TOK
.leftParenthesis
)
3357 // struct/class template declaration.
3358 tpl
= parseTemplateParameterList();
3359 constraint
= parseConstraint();
3363 // Collect base class(es)
3364 AST
.BaseClasses
* baseclasses
= null;
3365 if (token
.value
== TOK
.colon
)
3367 if (tok
!= TOK
.interface_
&& tok
!= TOK
.class_
)
3368 error("base classes are not allowed for `%s`, did you mean `;`?", Token
.toChars(tok
));
3370 baseclasses
= parseBaseClasses();
3373 if (token
.value
== TOK
.if_
)
3376 error("template constraints appear both before and after BaseClassList, put them before");
3377 constraint
= parseConstraint();
3382 error("template constraints not allowed for anonymous `%s`", Token
.toChars(tok
));
3384 error("template constraints only allowed for templates");
3387 AST
.Dsymbols
* members
= null;
3388 if (token
.value
== TOK
.leftCurly
)
3390 //printf("aggregate definition\n");
3391 const lookingForElseSave
= lookingForElse
;
3392 lookingForElse
= Loc();
3394 members
= parseDeclDefs(0);
3395 lookingForElse
= lookingForElseSave
;
3396 if (token
.value
!= TOK
.rightCurly
)
3399 error("`}` expected following members in `%s` declaration at %s",
3400 Token
.toChars(tok
), loc
.toChars());
3404 else if (token
.value
== TOK
.semicolon
&& id
)
3406 if (baseclasses || constraint
)
3407 error("members expected");
3412 error("{ } expected following `%s` declaration", Token
.toChars(tok
));
3415 AST
.AggregateDeclaration a
;
3418 case TOK
.interface_
:
3420 error(loc
, "anonymous interfaces not allowed");
3421 a
= new AST
.InterfaceDeclaration(loc
, id
, baseclasses
);
3422 a
.members
= members
;
3427 error(loc
, "anonymous classes not allowed");
3428 bool inObject
= md
&& !md
.packages
&& md
.id
== Id
.object
;
3429 a
= new AST
.ClassDeclaration(loc
, id
, baseclasses
, members
, inObject
);
3435 bool inObject
= md
&& !md
.packages
&& md
.id
== Id
.object
;
3436 a
= new AST
.StructDeclaration(loc
, id
, inObject
);
3437 a
.members
= members
;
3441 /* Anonymous structs/unions are more like attributes.
3444 return new AST
.AnonDeclaration(loc
, false, members
);
3451 a
= new AST
.UnionDeclaration(loc
, id
);
3452 a
.members
= members
;
3456 /* Anonymous structs/unions are more like attributes.
3459 return new AST
.AnonDeclaration(loc
, true, members
);
3469 // Wrap a template around the aggregate declaration
3470 auto decldefs
= new AST
.Dsymbols();
3472 auto tempdecl
= new AST
.TemplateDeclaration(loc
, id
, tpl
, constraint
, decldefs
);
3478 /*******************************************
3480 private AST
.BaseClasses
* parseBaseClasses()
3482 auto baseclasses
= new AST
.BaseClasses();
3484 for (; 1; nextToken())
3486 auto b
= new AST
.BaseClass(parseBasicType());
3487 baseclasses
.push(b
);
3488 if (token
.value
!= TOK
.comma
)
3494 private AST
.Dsymbols
* parseImport()
3496 auto decldefs
= new AST
.Dsymbols();
3497 Identifier aliasid
= null;
3499 int isstatic
= token
.value
== TOK
.static_
;
3503 //printf("Parser::parseImport()\n");
3508 if (token
.value
!= TOK
.identifier
)
3510 error("identifier expected following `import`");
3514 const loc
= token
.loc
;
3515 Identifier id
= token
.ident
;
3518 if (!aliasid
&& token
.value
== TOK
.assign
)
3523 while (token
.value
== TOK
.dot
)
3527 if (token
.value
!= TOK
.identifier
)
3529 error("identifier expected following `package`");
3536 auto s
= new AST
.Import(loc
, a
, id
, aliasid
, isstatic
);
3540 * : alias=name, alias=name;
3543 if (token
.value
== TOK
.colon
)
3548 if (token
.value
!= TOK
.identifier
)
3550 error("identifier expected following `:`");
3553 Identifier _alias
= token
.ident
;
3556 if (token
.value
== TOK
.assign
)
3559 if (token
.value
!= TOK
.identifier
)
3561 error("identifier expected following `%s=`", _alias
.toChars());
3572 s
.addAlias(name
, _alias
);
3574 while (token
.value
== TOK
.comma
);
3575 break; // no comma-separated imports of this form
3579 while (token
.value
== TOK
.comma
);
3581 if (token
.value
== TOK
.semicolon
)
3585 error("`;` expected");
3592 AST
.Type
parseType(Identifier
* pident
= null, AST
.TemplateParameters
** ptpl
= null)
3594 /* Take care of the storage class prefixes that
3595 * serve as type attributes:
3603 * shared inout const type
3605 StorageClass
stc = 0;
3608 switch (token
.value
)
3611 if (peekNext() == TOK
.leftParenthesis
)
3612 break; // const as type constructor
3613 stc |
= STC
.const_
; // const as storage class
3617 case TOK
.immutable_
:
3618 if (peekNext() == TOK
.leftParenthesis
)
3620 stc |
= STC
.immutable_
;
3625 if (peekNext() == TOK
.leftParenthesis
)
3632 if (peekNext() == TOK
.leftParenthesis
)
3644 const typeLoc
= token
.loc
;
3647 t
= parseBasicType();
3650 t
= parseDeclarator(t
, alt
, pident
, ptpl
);
3651 checkCstyleTypeSyntax(typeLoc
, t
, alt
, pident ?
*pident
: null);
3657 private AST
.Type
parseBasicType(bool dontLookDotIdents
= false)
3662 //printf("parseBasicType()\n");
3663 switch (token
.value
)
3678 t
= AST
.Type
.tint16
;
3682 t
= AST
.Type
.tuns16
;
3686 t
= AST
.Type
.tint32
;
3690 t
= AST
.Type
.tuns32
;
3694 t
= AST
.Type
.tint64
;
3696 if (token
.value
== TOK
.int64
) // if `long long`
3698 error("use `long` for a 64 bit integer instead of `long long`");
3701 else if (token
.value
== TOK
.float64
) // if `long double`
3703 error("use `real` instead of `long double`");
3704 t
= AST
.Type
.tfloat80
;
3710 t
= AST
.Type
.tuns64
;
3714 t
= AST
.Type
.tint128
;
3718 t
= AST
.Type
.tuns128
;
3722 t
= AST
.Type
.tfloat32
;
3726 t
= AST
.Type
.tfloat64
;
3730 t
= AST
.Type
.tfloat80
;
3733 case TOK
.imaginary32
:
3734 t
= AST
.Type
.timaginary32
;
3737 case TOK
.imaginary64
:
3738 t
= AST
.Type
.timaginary64
;
3741 case TOK
.imaginary80
:
3742 t
= AST
.Type
.timaginary80
;
3746 t
= AST
.Type
.tcomplex32
;
3750 t
= AST
.Type
.tcomplex64
;
3754 t
= AST
.Type
.tcomplex80
;
3766 t
= AST
.Type
.twchar
;
3770 t
= AST
.Type
.tdchar
;
3778 case TOK
.identifier
:
3782 if (token
.value
== TOK
.not)
3784 // ident!(template_arguments)
3785 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
3786 t
= parseBasicTypeStartingAt(new AST
.TypeInstance(loc
, tempinst
), dontLookDotIdents
);
3790 t
= parseBasicTypeStartingAt(new AST
.TypeIdentifier(loc
, id
), dontLookDotIdents
);
3795 // https://dlang.org/spec/expression.html#mixin_types
3798 if (token
.value
!= TOK
.leftParenthesis
)
3799 error("found `%s` when expecting `%s` following `mixin`", token
.toChars(), Token
.toChars(TOK
.leftParenthesis
));
3800 auto exps
= parseArguments();
3801 t
= new AST
.TypeMixin(loc
, exps
);
3805 // Leading . as in .foo
3806 t
= parseBasicTypeStartingAt(new AST
.TypeIdentifier(token
.loc
, Id
.empty
), dontLookDotIdents
);
3810 // typeof(expression)
3811 t
= parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents
);
3819 if (AST
.TraitsExp te
= cast(AST
.TraitsExp
) parsePrimaryExp())
3820 if (te
.ident
&& te
.args
)
3822 t
= new AST
.TypeTraits(token
.loc
, te
);
3825 t
= new AST
.TypeError
;
3831 check(TOK
.leftParenthesis
);
3832 t
= parseType().addSTC(STC
.const_
);
3833 check(TOK
.rightParenthesis
);
3836 case TOK
.immutable_
:
3839 check(TOK
.leftParenthesis
);
3840 t
= parseType().addSTC(STC
.immutable_
);
3841 check(TOK
.rightParenthesis
);
3847 check(TOK
.leftParenthesis
);
3848 t
= parseType().addSTC(STC
.shared_
);
3849 check(TOK
.rightParenthesis
);
3855 check(TOK
.leftParenthesis
);
3856 t
= parseType().addSTC(STC
.wild
);
3857 check(TOK
.rightParenthesis
);
3861 error("basic type expected, not `%s`", token
.toChars());
3862 if (token
.value
== TOK
.else_
)
3863 errorSupplemental(token
.loc
, "There's no `static else`, use `else` instead.");
3864 t
= AST
.Type
.terror
;
3870 private AST
.Type
parseBasicTypeStartingAt(AST
.TypeQualified tid
, bool dontLookDotIdents
)
3872 AST
.Type maybeArray
= null;
3873 // See https://issues.dlang.org/show_bug.cgi?id=1215
3874 // A basic type can look like MyType (typical case), but also:
3875 // MyType.T -> A type
3876 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3877 // MyType[expr].T -> A type.
3878 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3879 // (iif MyType[expr].T is a Ttuple)
3882 switch (token
.value
)
3887 if (token
.value
!= TOK
.identifier
)
3889 error("identifier expected following `.` instead of `%s`", token
.toChars());
3894 // This is actually a TypeTuple index, not an {a/s}array.
3895 // We need to have a while loop to unwind all index taking:
3896 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3897 AST
.Objects dimStack
;
3898 AST
.Type t
= maybeArray
;
3901 if (t
.ty
== Tsarray
)
3903 // The index expression is an Expression.
3904 AST
.TypeSArray a
= cast(AST
.TypeSArray
)t
;
3905 dimStack
.push(a
.dim
.syntaxCopy());
3906 t
= a
.next
.syntaxCopy();
3908 else if (t
.ty
== Taarray
)
3910 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3911 AST
.TypeAArray a
= cast(AST
.TypeAArray
)t
;
3912 dimStack
.push(a
.index
.syntaxCopy());
3913 t
= a
.next
.syntaxCopy();
3920 assert(dimStack
.dim
> 0);
3921 // We're good. Replay indices in the reverse order.
3922 tid
= cast(AST
.TypeQualified
)t
;
3923 while (dimStack
.dim
)
3925 tid
.addIndex(dimStack
.pop());
3929 const loc
= token
.loc
;
3930 Identifier id
= token
.ident
;
3932 if (token
.value
== TOK
.not)
3934 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
3935 tid
.addInst(tempinst
);
3941 case TOK
.leftBracket
:
3943 if (dontLookDotIdents
) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911
3947 AST
.Type t
= maybeArray ? maybeArray
: cast(AST
.Type
)tid
;
3948 if (token
.value
== TOK
.rightBracket
)
3950 // It's a dynamic array, and we're done:
3951 // T[].U does not make sense.
3952 t
= new AST
.TypeDArray(t
);
3956 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
3958 // This can be one of two things:
3959 // 1 - an associative array declaration, T[type]
3960 // 2 - an associative array declaration, T[expr]
3961 // These can only be disambiguated later.
3962 AST
.Type index
= parseType(); // [ type ]
3963 maybeArray
= new AST
.TypeAArray(t
, index
);
3964 check(TOK
.rightBracket
);
3968 // This can be one of three things:
3969 // 1 - an static array declaration, T[expr]
3970 // 2 - a slice, T[expr .. expr]
3971 // 3 - a template parameter pack index expression, T[expr].U
3972 // 1 and 3 can only be disambiguated later.
3973 //printf("it's type[expression]\n");
3975 AST
.Expression e
= parseAssignExp(); // [ expression ]
3976 if (token
.value
== TOK
.slice
)
3978 // It's a slice, and we're done.
3980 AST
.Expression e2
= parseAssignExp(); // [ exp .. exp ]
3981 t
= new AST
.TypeSlice(t
, e
, e2
);
3983 check(TOK
.rightBracket
);
3988 maybeArray
= new AST
.TypeSArray(t
, e
);
3990 check(TOK
.rightBracket
);
4001 return maybeArray ? maybeArray
: cast(AST
.Type
)tid
;
4004 /******************************************
4005 * Parse suffixes to type t.
4008 * [AssignExpression]
4009 * [AssignExpression .. AssignExpression]
4011 * delegate Parameters MemberFunctionAttributes(opt)
4012 * function Parameters FunctionAttributes(opt)
4014 * t = the already parsed type
4016 * t with the suffixes added
4018 * https://dlang.org/spec/declaration.html#TypeSuffixes
4020 private AST
.Type
parseTypeSuffixes(AST
.Type t
)
4022 //printf("parseTypeSuffixes()\n");
4025 switch (token
.value
)
4028 t
= new AST
.TypePointer(t
);
4032 case TOK
.leftBracket
:
4033 // Handle []. Make sure things like
4035 // is (array[1] of array[3] of int)
4037 if (token
.value
== TOK
.rightBracket
)
4039 t
= new AST
.TypeDArray(t
); // []
4042 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
4044 // It's an associative array declaration
4045 //printf("it's an associative array\n");
4046 AST
.Type index
= parseType(); // [ type ]
4047 t
= new AST
.TypeAArray(t
, index
);
4048 check(TOK
.rightBracket
);
4052 //printf("it's type[expression]\n");
4054 AST
.Expression e
= parseAssignExp(); // [ expression ]
4058 check(TOK
.rightBracket
);
4061 if (token
.value
== TOK
.slice
)
4064 AST
.Expression e2
= parseAssignExp(); // [ exp .. exp ]
4065 t
= new AST
.TypeSlice(t
, e
, e2
);
4069 t
= new AST
.TypeSArray(t
, e
);
4072 check(TOK
.rightBracket
);
4079 // Handle delegate declaration:
4080 // t delegate(parameter list) nothrow pure
4081 // t function(parameter list) nothrow pure
4082 const save
= token
.value
;
4085 auto parameterList
= parseParameterList(null);
4087 StorageClass
stc = parsePostfix(STC
.undefined_
, null);
4088 auto tf
= new AST
.TypeFunction(parameterList
, t
, linkage
, stc);
4089 if (stc & (STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.wild | STC
.return_
))
4091 if (save
== TOK
.function_
)
4092 error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions");
4094 tf
= cast(AST
.TypeFunction
)tf
.addSTC(stc);
4096 t
= save
== TOK
.delegate_ ?
new AST
.TypeDelegate(tf
) : new AST
.TypePointer(tf
); // pointer to function
4107 /**********************
4110 * t = base type to start with
4111 * palt = OR in 1 for C-style function pointer declaration syntax,
4112 * 2 for C-style array declaration syntax, otherwise don't modify
4113 * pident = set to Identifier if there is one, null if not
4114 * tpl = if !null, then set to TemplateParameterList
4115 * storageClass = any storage classes seen so far
4116 * pdisable = set to true if @disable seen
4117 * pudas = any user defined attributes seen so far. Merged with any more found
4120 * Reference: https://dlang.org/spec/declaration.html#Declarator
4122 private AST
.Type
parseDeclarator(AST
.Type t
, ref int palt
, Identifier
* pident
,
4123 AST
.TemplateParameters
** tpl
= null, StorageClass storageClass
= 0,
4124 bool* pdisable
= null, AST
.Expressions
** pudas
= null)
4126 //printf("parseDeclarator(tpl = %p)\n", tpl);
4127 t
= parseTypeSuffixes(t
);
4129 switch (token
.value
)
4131 case TOK
.identifier
:
4133 *pident
= token
.ident
;
4135 error("unexpected identifier `%s` in declarator", token
.ident
.toChars());
4140 case TOK
.leftParenthesis
:
4143 // like: T ((*fp))();
4144 if (peekNext() == TOK
.mul ||
peekNext() == TOK
.leftParenthesis
)
4146 /* Parse things with parentheses around the identifier, like:
4148 * although the D style would be:
4153 ts
= parseDeclarator(t
, palt
, pident
);
4154 check(TOK
.rightParenthesis
);
4159 Token
* peekt
= &token
;
4160 /* Completely disallow C-style things like:
4162 * Improve error messages for the common bug of a missing return type
4163 * by looking to see if (a) looks like a parameter list.
4165 if (isParameters(&peekt
))
4167 error("function declaration without return type. (Note that constructors are always named `this`)");
4170 error("unexpected `(` in declarator");
4178 // parse DeclaratorSuffixes
4181 switch (token
.value
)
4183 static if (CARRAYDECL
)
4185 /* Support C style array syntax:
4187 * as opposed to D-style:
4190 case TOK
.leftBracket
:
4192 // This is the old C-style post [] syntax.
4195 if (token
.value
== TOK
.rightBracket
)
4197 // It's a dynamic array
4198 ta
= new AST
.TypeDArray(t
); // []
4202 else if (isDeclaration(&token
, NeedDeclaratorId
.no
, TOK
.rightBracket
, null))
4204 // It's an associative array
4205 //printf("it's an associative array\n");
4206 AST
.Type index
= parseType(); // [ type ]
4207 check(TOK
.rightBracket
);
4208 ta
= new AST
.TypeAArray(t
, index
);
4213 //printf("It's a static array\n");
4214 AST
.Expression e
= parseAssignExp(); // [ expression ]
4215 ta
= new AST
.TypeSArray(t
, e
);
4216 check(TOK
.rightBracket
);
4223 * ts -> ... -> ta -> t
4226 for (pt
= &ts
; *pt
!= t
; pt
= &(cast(AST
.TypeNext
)*pt
).next
)
4233 case TOK
.leftParenthesis
:
4237 Token
* tk
= peekPastParen(&token
);
4238 if (tk
.value
== TOK
.leftParenthesis
)
4240 /* Look ahead to see if this is (...)(...),
4241 * i.e. a function template declaration
4243 //printf("function template declaration\n");
4245 // Gather template parameter list
4246 *tpl
= parseTemplateParameterList();
4248 else if (tk
.value
== TOK
.assign
)
4251 * i.e. a variable template declaration
4253 //printf("variable template declaration\n");
4254 *tpl
= parseTemplateParameterList();
4259 auto parameterList
= parseParameterList(null);
4261 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
4263 // merge prefix storage classes
4264 StorageClass
stc = parsePostfix(storageClass
, pudas
);
4266 AST
.Type tf
= new AST
.TypeFunction(parameterList
, t
, linkage
, stc);
4267 tf
= tf
.addSTC(stc);
4269 *pdisable
= stc & STC
.disable ?
true : false;
4274 * ts -> ... -> tf -> t
4277 for (pt
= &ts
; *pt
!= t
; pt
= &(cast(AST
.TypeNext
)*pt
).next
)
4291 private void parseStorageClasses(ref StorageClass storage_class
, ref LINK link
,
4292 ref bool setAlignment
, ref AST
.Expression ealign
, ref AST
.Expressions
* udas
,
4296 bool sawLinkage
= false; // seen a linkage declaration
4298 linkloc
= Loc
.initial
;
4302 switch (token
.value
)
4305 if (peekNext() == TOK
.leftParenthesis
)
4306 break; // const as type constructor
4307 stc = STC
.const_
; // const as storage class
4310 case TOK
.immutable_
:
4311 if (peekNext() == TOK
.leftParenthesis
)
4313 stc = STC
.immutable_
;
4317 if (peekNext() == TOK
.leftParenthesis
)
4323 if (peekNext() == TOK
.leftParenthesis
)
4345 stc = STC
.override_
;
4349 stc = STC
.abstract_
;
4352 case TOK
.synchronized_
:
4353 stc = STC
.synchronized_
;
4356 case TOK
.deprecated_
:
4357 stc = STC
.deprecated_
;
4378 const tv
= peekNext();
4379 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
4381 if (tv
== TOK
.identifier
)
4383 const nextv
= peekNext2();
4384 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
4393 stc = parseAttribute(udas
);
4399 storage_class
= appendStorageClass(storage_class
, stc);
4405 if (peekNext() != TOK
.leftParenthesis
)
4412 error("redundant linkage declaration");
4414 linkloc
= token
.loc
;
4415 auto res
= parseLinkage();
4417 if (res
.idents || res
.identExps
)
4419 error("C++ name spaces not allowed here");
4421 if (res
.cppmangle
!= CPPMANGLE
.def
)
4423 error("C++ mangle declaration not allowed here");
4430 setAlignment
= true;
4431 if (token
.value
== TOK
.leftParenthesis
)
4434 ealign
= parseExpression();
4435 check(TOK
.rightParenthesis
);
4446 /**********************************
4447 * Parse Declarations.
4449 * 1. declarations at global/class level
4450 * 2. declarations at statement level
4451 * Return array of Declaration *'s.
4453 private AST
.Dsymbols
* parseDeclarations(bool autodecl
, PrefixAttributes
!AST
* pAttrs
, const(char)* comment
)
4455 StorageClass storage_class
= STC
.undefined_
;
4456 TOK tok
= TOK
.reserved
;
4457 LINK link
= linkage
;
4458 Loc linkloc
= this.linkLoc
;
4459 bool setAlignment
= false;
4460 AST
.Expression ealign
;
4461 AST
.Expressions
* udas
= null;
4463 //printf("parseDeclarations() %s\n", token.toChars());
4465 comment
= token
.blockComment
.ptr
;
4467 /* Look for AliasAssignment:
4468 * identifier = type;
4470 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.assign
)
4472 const loc
= token
.loc
;
4473 auto ident
= token
.ident
;
4475 nextToken(); // advance past =
4476 auto t
= parseType();
4477 AST
.Dsymbol s
= new AST
.AliasAssign(loc
, ident
, t
, null);
4478 check(TOK
.semicolon
);
4479 addComment(s
, comment
);
4480 auto a
= new AST
.Dsymbols();
4485 if (token
.value
== TOK
.alias_
)
4487 const loc
= token
.loc
;
4492 * alias identifier this;
4494 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.this_
)
4496 auto s
= new AST
.AliasThis(loc
, token
.ident
);
4499 check(TOK
.semicolon
);
4500 auto a
= new AST
.Dsymbols();
4502 addComment(s
, comment
);
4508 * alias this = identifier;
4510 if (token
.value
== TOK
.this_
&& peekNext() == TOK
.assign
&& peekNext2() == TOK
.identifier
)
4514 auto s
= new AliasThis(loc
, token
.ident
);
4516 check(TOK
.semicolon
);
4517 auto a
= new Dsymbols();
4519 addComment(s
, comment
);
4524 * alias identifier = type;
4525 * alias identifier(...) = type;
4527 if (token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
4529 auto a
= new AST
.Dsymbols();
4532 auto ident
= token
.ident
;
4534 AST
.TemplateParameters
* tpl
= null;
4535 if (token
.value
== TOK
.leftParenthesis
)
4536 tpl
= parseTemplateParameterList();
4539 bool hasParsedAttributes
;
4540 void parseAttributes()
4542 if (hasParsedAttributes
) // only parse once
4544 hasParsedAttributes
= true;
4546 storage_class
= STC
.undefined_
;
4548 linkloc
= this.linkLoc
;
4549 setAlignment
= false;
4551 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4554 if (token
.value
== TOK
.at
)
4560 // try to parse function type:
4561 // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
4562 bool attributesAppended
;
4563 const StorageClass funcStc
= parseTypeCtor();
4564 Token
* tlu
= &token
;
4566 if (token
.value
!= TOK
.function_
&&
4567 token
.value
!= TOK
.delegate_
&&
4568 isBasicType(&tlu
) && tlu
&&
4569 tlu
.value
== TOK
.leftParenthesis
)
4571 AST
.Type tret
= parseBasicType();
4572 auto parameterList
= parseParameterList(null);
4576 error("user-defined attributes not allowed for `alias` declarations");
4578 attributesAppended
= true;
4579 storage_class
= appendStorageClass(storage_class
, funcStc
);
4580 AST
.Type tf
= new AST
.TypeFunction(parameterList
, tret
, link
, storage_class
);
4581 v
= new AST
.AliasDeclaration(loc
, ident
, tf
);
4583 else if (token
.value
== TOK
.function_ ||
4584 token
.value
== TOK
.delegate_ ||
4585 token
.value
== TOK
.leftParenthesis
&&
4586 skipAttributes(peekPastParen(&token
), &tk
) &&
4587 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
) ||
4588 token
.value
== TOK
.leftCurly ||
4589 token
.value
== TOK
.identifier
&& peekNext() == TOK
.goesTo ||
4590 token
.value
== TOK
.ref_
&& peekNext() == TOK
.leftParenthesis
&&
4591 skipAttributes(peekPastParen(peek(&token
)), &tk
) &&
4592 (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
)
4595 // function (parameters) { statements... }
4596 // delegate (parameters) { statements... }
4597 // (parameters) { statements... }
4598 // (parameters) => expression
4599 // { statements... }
4600 // identifier => expression
4601 // ref (parameters) { statements... }
4602 // ref (parameters) => expression
4604 s
= parseFunctionLiteral();
4608 if (storage_class
!= 0)
4609 error("Cannot put a storage-class in an alias declaration.");
4610 // parseAttributes shouldn't have set these variables
4611 assert(link
== linkage
&& !setAlignment
&& ealign
is null);
4612 auto tpl_
= cast(AST
.TemplateDeclaration
) s
;
4613 assert(tpl_
!is null && tpl_
.members
.dim
== 1);
4614 auto fd
= cast(AST
.FuncLiteralDeclaration
) (*tpl_
.members
)[0];
4615 auto tf
= cast(AST
.TypeFunction
) fd
.type
;
4616 assert(tf
.parameterList
.parameters
.dim
> 0);
4617 auto as
= new AST
.Dsymbols();
4618 (*tf
.parameterList
.parameters
)[0].userAttribDecl
= new AST
.UserAttributeDeclaration(udas
, as
);
4621 v
= new AST
.AliasDeclaration(loc
, ident
, s
);
4628 error("user-defined attributes not allowed for `%s` declarations", Token
.toChars(tok
));
4630 auto t
= parseType();
4632 // Disallow meaningless storage classes on type aliases
4635 // Don't raise errors for STC that are part of a function/delegate type, e.g.
4636 // `alias F = ref pure nothrow @nogc @safe int function();`
4637 auto tp
= t
.isTypePointer
;
4638 const isFuncType
= (tp
&& tp
.next
.isTypeFunction
) || t
.isTypeDelegate
;
4639 const remStc
= isFuncType ?
(storage_class
& ~STC
.FUNCATTR
) : storage_class
;
4644 AST
.stcToBuffer(&buf
, remStc
);
4645 // @@@DEPRECATED_2.093@@@
4646 // Deprecated in 2020-07, can be made an error in 2.103
4647 deprecation("storage class `%s` has no effect in type aliases", buf
.peekChars());
4651 v
= new AST
.AliasDeclaration(loc
, ident
, t
);
4653 if (!attributesAppended
)
4654 storage_class
= appendStorageClass(storage_class
, funcStc
);
4655 v
.storage_class
= storage_class
;
4660 auto a2
= new AST
.Dsymbols();
4662 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
);
4665 if (link
!= linkage
)
4667 auto a2
= new AST
.Dsymbols();
4669 s
= new AST
.LinkDeclaration(linkloc
, link
, a2
);
4673 switch (token
.value
)
4677 addComment(s
, comment
);
4682 addComment(s
, comment
);
4683 if (token
.value
!= TOK
.identifier
)
4685 error("identifier expected following comma, not `%s`", token
.toChars());
4688 if (peekNext() != TOK
.assign
&& peekNext() != TOK
.leftParenthesis
)
4690 error("`=` expected following identifier");
4697 error("semicolon expected to close `%s` declaration", Token
.toChars(tok
));
4705 // alias StorageClasses type ident;
4712 parseStorageClasses(storage_class
, link
, setAlignment
, ealign
, udas
, linkloc
);
4714 if (token
.value
== TOK
.enum_
)
4716 AST
.Dsymbol d
= parseEnum();
4717 auto a
= new AST
.Dsymbols();
4722 d
= new AST
.UserAttributeDeclaration(udas
, a
);
4723 a
= new AST
.Dsymbols();
4727 addComment(d
, comment
);
4730 if (token
.value
== TOK
.struct_ ||
4731 token
.value
== TOK
.union_ ||
4732 token
.value
== TOK
.class_ ||
4733 token
.value
== TOK
.interface_
)
4735 AST
.Dsymbol s
= parseAggregate();
4736 auto a
= new AST
.Dsymbols();
4741 s
= new AST
.StorageClassDeclaration(storage_class
, a
);
4742 a
= new AST
.Dsymbols();
4747 s
= new AST
.AlignDeclaration(s
.loc
, ealign
, a
);
4748 a
= new AST
.Dsymbols();
4751 if (link
!= linkage
)
4753 s
= new AST
.LinkDeclaration(linkloc
, link
, a
);
4754 a
= new AST
.Dsymbols();
4759 s
= new AST
.UserAttributeDeclaration(udas
, a
);
4760 a
= new AST
.Dsymbols();
4764 addComment(s
, comment
);
4768 /* Look for auto initializers:
4769 * storage_class identifier = initializer;
4770 * storage_class identifier(...) = initializer;
4772 if ((storage_class || udas
) && token
.value
== TOK
.identifier
&& hasOptionalParensThen(peek(&token
), TOK
.assign
))
4774 AST
.Dsymbols
* a
= parseAutoDeclarations(storage_class
, comment
);
4777 AST
.Dsymbol s
= new AST
.UserAttributeDeclaration(udas
, a
);
4778 a
= new AST
.Dsymbols();
4784 /* Look for return type inference for template functions.
4788 if ((storage_class || udas
) && token
.value
== TOK
.identifier
&& skipParens(peek(&token
), &tk
) &&
4789 skipAttributes(tk
, &tk
) &&
4790 (tk
.value
== TOK
.leftParenthesis || tk
.value
== TOK
.leftCurly || tk
.value
== TOK
.in_ || tk
.value
== TOK
.out_ || tk
.value
== TOK
.goesTo ||
4791 tk
.value
== TOK
.do_ || tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
))
4794 // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
4795 // Deprecated in 2.097 - Can be removed from 2.117
4796 // The deprecation period is longer than usual as `body`
4797 // was quite widely used.
4798 if (tk
.value
== TOK
.identifier
&& tk
.ident
== Id
._body
)
4799 deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
4805 ts
= parseBasicType();
4806 ts
= parseTypeSuffixes(ts
);
4813 storage_class |
= pAttrs
.storageClass
;
4814 //pAttrs.storageClass = STC.undefined_;
4817 AST
.Type tfirst
= null;
4818 auto a
= new AST
.Dsymbols();
4822 AST
.TemplateParameters
* tpl
= null;
4826 const loc
= token
.loc
;
4829 auto t
= parseDeclarator(ts
, alt
, &ident
, &tpl
, storage_class
, &disable
, &udas
);
4833 else if (t
!= tfirst
)
4834 error("multiple declarations must have the same type, not `%s` and `%s`", tfirst
.toChars(), t
.toChars());
4836 bool isThis
= (t
.ty
== Tident
&& (cast(AST
.TypeIdentifier
)t
).ident
== Id
.This
&& token
.value
== TOK
.assign
);
4838 checkCstyleTypeSyntax(loc
, t
, alt
, ident
);
4839 else if (!isThis
&& (t
!= AST
.Type
.terror
))
4840 error("no identifier for declarator `%s`", t
.toChars());
4842 if (tok
== TOK
.alias_
)
4845 AST
.Initializer _init
= null;
4847 /* Aliases can no longer have multiple declarators, storage classes,
4848 * linkages, or auto declarations.
4849 * These never made any sense, anyway.
4850 * The code below needs to be fixed to reject them.
4851 * The grammar has already been fixed to preclude them.
4855 error("user-defined attributes not allowed for `%s` declarations", Token
.toChars(tok
));
4857 if (token
.value
== TOK
.assign
)
4860 _init
= parseInitializer();
4865 error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init
.toChars(), _init
.toChars());
4867 error("alias cannot have initializer");
4869 v
= new AST
.AliasDeclaration(loc
, ident
, t
);
4871 v
.storage_class
= storage_class
;
4874 /* AliasDeclaration distinguish @safe, @system, @trusted attributes
4875 * on prefix and postfix.
4876 * @safe alias void function() FP1;
4877 * alias @safe void function() FP2; // FP2 is not @safe
4878 * alias void function() @safe FP3;
4880 pAttrs
.storageClass
&= STC
.safeGroup
;
4884 if (link
!= linkage
)
4886 auto ax
= new AST
.Dsymbols();
4888 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4891 switch (token
.value
)
4895 addComment(s
, comment
);
4900 addComment(s
, comment
);
4904 error("semicolon expected to close `%s` declaration", Token
.toChars(tok
));
4908 else if (t
.ty
== Tfunction
)
4910 AST
.Expression constraint
= null;
4911 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
4912 auto f
= new AST
.FuncDeclaration(loc
, Loc
.initial
, ident
, storage_class |
(disable ? STC
.disable
: 0), t
);
4914 pAttrs
.storageClass
= STC
.undefined_
;
4916 constraint
= parseConstraint();
4917 AST
.Dsymbol s
= parseContracts(f
);
4918 auto tplIdent
= s
.ident
;
4920 if (link
!= linkage
)
4922 auto ax
= new AST
.Dsymbols();
4924 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
4928 auto ax
= new AST
.Dsymbols();
4930 s
= new AST
.UserAttributeDeclaration(udas
, ax
);
4933 /* A template parameter list means it's a function template
4937 // Wrap a template around the function declaration
4938 auto decldefs
= new AST
.Dsymbols();
4940 auto tempdecl
= new AST
.TemplateDeclaration(loc
, tplIdent
, tpl
, constraint
, decldefs
);
4943 StorageClass stc2
= STC
.undefined_
;
4944 if (storage_class
& STC
.static_
)
4946 assert(f
.storage_class
& STC
.static_
);
4947 f
.storage_class
&= ~STC
.static_
;
4948 stc2 |
= STC
.static_
;
4950 if (storage_class
& STC
.deprecated_
)
4952 assert(f
.storage_class
& STC
.deprecated_
);
4953 f
.storage_class
&= ~STC
.deprecated_
;
4954 stc2 |
= STC
.deprecated_
;
4956 if (stc2
!= STC
.undefined_
)
4958 auto ax
= new AST
.Dsymbols();
4960 s
= new AST
.StorageClassDeclaration(stc2
, ax
);
4964 addComment(s
, comment
);
4968 AST
.Initializer _init
= null;
4969 if (token
.value
== TOK
.assign
)
4972 _init
= parseInitializer();
4975 auto v
= new AST
.VarDeclaration(loc
, t
, ident
, _init
);
4976 v
.storage_class
= storage_class
;
4978 pAttrs
.storageClass
= STC
.undefined_
;
4984 auto a2
= new AST
.Dsymbols();
4986 auto tempdecl
= new AST
.TemplateDeclaration(loc
, ident
, tpl
, null, a2
, 0);
4991 auto ax
= new AST
.Dsymbols();
4993 s
= new AST
.AlignDeclaration(v
.loc
, ealign
, ax
);
4995 if (link
!= linkage
)
4997 auto ax
= new AST
.Dsymbols();
4999 s
= new AST
.LinkDeclaration(linkloc
, link
, ax
);
5003 auto ax
= new AST
.Dsymbols();
5005 s
= new AST
.UserAttributeDeclaration(udas
, ax
);
5008 switch (token
.value
)
5012 addComment(s
, comment
);
5017 addComment(s
, comment
);
5021 error("semicolon expected, not `%s`", token
.toChars());
5030 private AST
.Dsymbol
parseFunctionLiteral()
5032 const loc
= token
.loc
;
5033 AST
.TemplateParameters
* tpl
= null;
5034 AST
.ParameterList parameterList
;
5035 AST
.Type tret
= null;
5036 StorageClass
stc = 0;
5037 TOK save
= TOK
.reserved
;
5039 switch (token
.value
)
5045 if (token
.value
== TOK
.ref_
)
5047 // function ref (parameters) { statements... }
5048 // delegate ref (parameters) { statements... }
5052 if (token
.value
!= TOK
.leftParenthesis
&& token
.value
!= TOK
.leftCurly
)
5054 // function type (parameters) { statements... }
5055 // delegate type (parameters) { statements... }
5056 tret
= parseBasicType();
5057 tret
= parseTypeSuffixes(tret
); // function return type
5060 if (token
.value
== TOK
.leftParenthesis
)
5062 // function (parameters) { statements... }
5063 // delegate (parameters) { statements... }
5067 // function { statements... }
5068 // delegate { statements... }
5071 goto case TOK
.leftParenthesis
;
5075 // ref (parameters) => expression
5076 // ref (parameters) { statements... }
5079 goto case TOK
.leftParenthesis
;
5081 case TOK
.leftParenthesis
:
5083 // (parameters) => expression
5084 // (parameters) { statements... }
5085 parameterList
= parseParameterList(&tpl
);
5086 stc = parsePostfix(stc, null);
5087 if (StorageClass modStc
= stc & STC
.TYPECTOR
)
5089 if (save
== TOK
.function_
)
5092 AST
.stcToBuffer(&buf
, modStc
);
5093 error("function literal cannot be `%s`", buf
.peekChars());
5096 save
= TOK
.delegate_
;
5101 // { statements... }
5104 case TOK
.identifier
:
5106 // identifier => expression
5107 parameterList
.parameters
= new AST
.Parameters();
5108 Identifier id
= Identifier
.generateId("__T");
5109 AST
.Type t
= new AST
.TypeIdentifier(loc
, id
);
5110 parameterList
.parameters
.push(new AST
.Parameter(STC
.parameter
, t
, token
.ident
, null, null));
5112 tpl
= new AST
.TemplateParameters();
5113 AST
.TemplateParameter tp
= new AST
.TemplateTypeParameter(loc
, id
, null, null);
5123 auto tf
= new AST
.TypeFunction(parameterList
, tret
, linkage
, stc);
5124 tf
= cast(AST
.TypeFunction
)tf
.addSTC(stc);
5125 auto fd
= new AST
.FuncLiteralDeclaration(loc
, Loc
.initial
, tf
, save
, null);
5127 if (token
.value
== TOK
.goesTo
)
5130 if (token
.value
== TOK
.leftCurly
)
5132 deprecation("Using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
5133 deprecationSupplemental(token
.loc
, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
5135 const returnloc
= token
.loc
;
5136 AST
.Expression ae
= parseAssignExp();
5137 fd
.fbody
= new AST
.ReturnStatement(returnloc
, ae
);
5138 fd
.endloc
= token
.loc
;
5147 // Wrap a template around function fd
5148 auto decldefs
= new AST
.Dsymbols();
5150 return new AST
.TemplateDeclaration(fd
.loc
, fd
.ident
, tpl
, null, decldefs
, false, true);
5155 /*****************************************
5156 * Parse contracts following function declaration.
5158 private AST
.FuncDeclaration
parseContracts(AST
.FuncDeclaration f
)
5160 LINK linksave
= linkage
;
5162 bool literal
= f
.isFuncLiteralDeclaration() !is null;
5164 // The following is irrelevant, as it is overridden by sc.linkage in
5165 // TypeFunction::semantic
5166 linkage
= LINK
.d
; // nested functions have D linkage
5167 bool requireDo
= false;
5169 switch (token
.value
)
5173 error("missing `do { ... }` after `in` or `out`");
5174 if (!global
.params
.shortenedMethods
)
5175 error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
5176 const returnloc
= token
.loc
;
5178 f
.fbody
= new AST
.ReturnStatement(returnloc
, parseExpression());
5179 f
.endloc
= token
.loc
;
5180 check(TOK
.semicolon
);
5185 error("missing `do { ... }` after `in` or `out`");
5186 f
.fbody
= parseStatement(ParseStatementFlags
.semi
);
5190 case TOK
.identifier
:
5191 if (token
.ident
== Id
._body
)
5194 // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
5195 // Deprecated in 2.097 - Can be removed from 2.117
5196 // The deprecation period is longer than usual as `body`
5197 // was quite widely used.
5198 deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
5205 f
.fbody
= parseStatement(ParseStatementFlags
.curly
);
5211 // Do we want this for function declarations, so we can do:
5212 // int x, y, foo(), z;
5219 // in { statements... }
5221 auto loc
= token
.loc
;
5225 f
.frequires
= new AST
.Statements
;
5227 if (token
.value
== TOK
.leftParenthesis
)
5230 AST
.Expression e
= parseAssignExp(), msg
= null;
5231 if (token
.value
== TOK
.comma
)
5234 if (token
.value
!= TOK
.rightParenthesis
)
5236 msg
= parseAssignExp();
5237 if (token
.value
== TOK
.comma
)
5241 check(TOK
.rightParenthesis
);
5242 e
= new AST
.AssertExp(loc
, e
, msg
);
5243 f
.frequires
.push(new AST
.ExpStatement(loc
, e
));
5248 f
.frequires
.push(parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
));
5254 // out { statements... }
5255 // out (; expression)
5256 // out (identifier) { statements... }
5257 // out (identifier; expression)
5258 auto loc
= token
.loc
;
5262 f
.fensures
= new AST
.Ensures
;
5264 Identifier id
= null;
5265 if (token
.value
!= TOK
.leftCurly
)
5267 check(TOK
.leftParenthesis
);
5268 if (token
.value
!= TOK
.identifier
&& token
.value
!= TOK
.semicolon
)
5269 error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token
.toChars());
5270 if (token
.value
!= TOK
.semicolon
)
5275 if (token
.value
== TOK
.semicolon
)
5278 AST
.Expression e
= parseAssignExp(), msg
= null;
5279 if (token
.value
== TOK
.comma
)
5282 if (token
.value
!= TOK
.rightParenthesis
)
5284 msg
= parseAssignExp();
5285 if (token
.value
== TOK
.comma
)
5289 check(TOK
.rightParenthesis
);
5290 e
= new AST
.AssertExp(loc
, e
, msg
);
5291 f
.fensures
.push(AST
.Ensure(id
, new AST
.ExpStatement(loc
, e
)));
5295 check(TOK
.rightParenthesis
);
5297 f
.fensures
.push(AST
.Ensure(id
, parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
)));
5304 // https://issues.dlang.org/show_bug.cgi?id=15799
5305 // Semicolon becomes a part of function declaration
5306 // only when 'do' is not required
5316 const(char)* sbody
= requireDo ?
"do " : "";
5317 error("missing `%s{ ... }` for function literal", sbody
);
5319 else if (!requireDo
) // allow contracts even with no body
5321 TOK t
= token
.value
;
5322 if (t
== TOK
.const_ || t
== TOK
.immutable_ || t
== TOK
.inout_ || t
== TOK
.return_ ||
5323 t
== TOK
.shared_ || t
== TOK
.nothrow_ || t
== TOK
.pure_
)
5324 error("'%s' cannot be placed after a template constraint", token
.toChars
);
5325 else if (t
== TOK
.at
)
5326 error("attributes cannot be placed after a template constraint");
5327 else if (t
== TOK
.if_
)
5328 error("cannot use function constraints for non-template functions. Use `static if` instead");
5330 error("semicolon expected following function declaration");
5334 if (literal
&& !f
.fbody
)
5336 // Set empty function body for error recovery
5337 f
.fbody
= new AST
.CompoundStatement(Loc
.initial
, cast(AST
.Statement
)null);
5345 /*****************************************
5347 private void checkDanglingElse(Loc elseloc
)
5349 if (token
.value
!= TOK
.else_
&& token
.value
!= TOK
.catch_
&& token
.value
!= TOK
.finally_
&& lookingForElse
.linnum
!= 0)
5351 warning(elseloc
, "else is dangling, add { } after condition at %s", lookingForElse
.toChars());
5355 /* *************************
5356 * Issue errors if C-style syntax
5358 * alt = !=0 for C-style syntax
5360 private void checkCstyleTypeSyntax(Loc loc
, AST
.Type t
, int alt
, Identifier ident
)
5365 const(char)* sp
= !ident ?
"" : " ";
5366 const(char)* s
= !ident ?
"" : ident
.toChars();
5367 error(loc
, "instead of C-style syntax, use D-style `%s%s%s`", t
.toChars(), sp
, s
);
5370 /*****************************************
5371 * Parses `foreach` statements, `static foreach` statements and
5372 * `static foreach` declarations.
5374 * Foreach = one of Statement, StaticForeachStatement, StaticForeachDeclaration
5375 * loc = location of foreach
5376 * pLastDecl = non-null for StaticForeachDeclaration
5378 * the Foreach generated
5380 private Foreach
parseForeach(alias Foreach
)(Loc loc
, AST
.Dsymbol
* pLastDecl
)
5382 static if (is(Foreach
== AST
.StaticForeachStatement
) ||
is(Foreach
== AST
.StaticForeachDeclaration
))
5387 TOK op
= token
.value
;
5390 check(TOK
.leftParenthesis
);
5392 auto parameters
= new AST
.Parameters();
5395 Identifier ai
= null;
5398 StorageClass storageClass
= 0;
5399 StorageClass
stc = 0;
5403 storageClass
= appendStorageClass(storageClass
, stc);
5406 switch (token
.value
)
5417 error("cannot declare `out` loop variable, use `ref` instead");
5426 storageClass
= appendStorageClass(storageClass
, STC
.alias_
);
5431 if (peekNext() != TOK
.leftParenthesis
)
5438 case TOK
.immutable_
:
5439 if (peekNext() != TOK
.leftParenthesis
)
5441 stc = STC
.immutable_
;
5447 if (peekNext() != TOK
.leftParenthesis
)
5455 if (peekNext() != TOK
.leftParenthesis
)
5465 if (token
.value
== TOK
.identifier
)
5467 const tv
= peekNext();
5468 if (tv
== TOK
.comma || tv
== TOK
.semicolon
)
5471 at
= null; // infer argument type
5476 at
= parseType(&ai
);
5478 error("no identifier for declarator `%s`", at
.toChars());
5480 auto p
= new AST
.Parameter(storageClass
, at
, ai
, null, null);
5482 if (token
.value
== TOK
.comma
)
5489 check(TOK
.semicolon
);
5491 AST
.Expression aggr
= parseExpression();
5492 if (token
.value
== TOK
.slice
&& parameters
.dim
== 1)
5494 AST
.Parameter p
= (*parameters
)[0];
5496 AST
.Expression upr
= parseExpression();
5497 check(TOK
.rightParenthesis
);
5499 static if (is(Foreach
== AST
.Statement
) ||
is(Foreach
== AST
.StaticForeachStatement
))
5501 AST
.Statement _body
= parseStatement(0, null, &endloc
);
5505 AST
.Statement _body
= null;
5507 auto rangefe
= new AST
.ForeachRangeStatement(loc
, op
, p
, aggr
, upr
, _body
, endloc
);
5508 static if (is(Foreach
== AST
.Statement
))
5512 else static if(is(Foreach
== AST
.StaticForeachDeclaration
))
5514 return new AST
.StaticForeachDeclaration(new AST
.StaticForeach(loc
, null, rangefe
), parseBlock(pLastDecl
));
5516 else static if (is(Foreach
== AST
.StaticForeachStatement
))
5518 return new AST
.StaticForeachStatement(loc
, new AST
.StaticForeach(loc
, null, rangefe
));
5523 check(TOK
.rightParenthesis
);
5525 static if (is(Foreach
== AST
.Statement
) ||
is(Foreach
== AST
.StaticForeachStatement
))
5527 AST
.Statement _body
= parseStatement(0, null, &endloc
);
5531 AST
.Statement _body
= null;
5533 auto aggrfe
= new AST
.ForeachStatement(loc
, op
, parameters
, aggr
, _body
, endloc
);
5534 static if (is(Foreach
== AST
.Statement
))
5538 else static if(is(Foreach
== AST
.StaticForeachDeclaration
))
5540 return new AST
.StaticForeachDeclaration(new AST
.StaticForeach(loc
, aggrfe
, null), parseBlock(pLastDecl
));
5542 else static if (is(Foreach
== AST
.StaticForeachStatement
))
5544 return new AST
.StaticForeachStatement(loc
, new AST
.StaticForeach(loc
, aggrfe
, null));
5551 * Parse an assignment condition for if or while statements.
5554 * The variable that is declared inside the condition
5556 AST
.Parameter
parseAssignCondition()
5558 AST
.Parameter param
= null;
5559 StorageClass storageClass
= 0;
5560 StorageClass
stc = 0;
5564 storageClass
= appendStorageClass(storageClass
, stc);
5567 switch (token
.value
)
5582 if (peekNext() != TOK
.leftParenthesis
)
5589 case TOK
.immutable_
:
5590 if (peekNext() != TOK
.leftParenthesis
)
5592 stc = STC
.immutable_
;
5598 if (peekNext() != TOK
.leftParenthesis
)
5606 if (peekNext() != TOK
.leftParenthesis
)
5616 auto n
= peek(&token
);
5617 if (storageClass
!= 0 && token
.value
== TOK
.identifier
&& n
.value
== TOK
.assign
)
5619 Identifier ai
= token
.ident
;
5620 AST
.Type at
= null; // infer parameter type
5623 param
= new AST
.Parameter(storageClass
, at
, ai
, null, null);
5625 else if (isDeclaration(&token
, NeedDeclaratorId
.must
, TOK
.assign
, null))
5628 AST
.Type at
= parseType(&ai
);
5630 param
= new AST
.Parameter(storageClass
, at
, ai
, null, null);
5632 else if (storageClass
!= 0)
5633 error("found `%s` while expecting `=` or identifier", n
.toChars());
5638 /*****************************************
5642 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
5644 AST
.Statement
parseStatement(int flags
, const(char)** endPtr
= null, Loc
* pEndloc
= null)
5648 AST
.Statement ifbody
;
5649 AST
.Statement elsebody
;
5651 const loc
= token
.loc
;
5653 //printf("parseStatement()\n");
5654 if (flags
& ParseStatementFlags
.curly
&& token
.value
!= TOK
.leftCurly
)
5655 error("statement expected to be `{ }`, not `%s`", token
.toChars());
5657 switch (token
.value
)
5659 case TOK
.identifier
:
5661 /* A leading identifier can be a declaration, label, or expression.
5662 * The easiest case to check first is label:
5664 if (peekNext() == TOK
.colonColon
)
5669 error("use `.` for member lookup, not `::`");
5673 if (peekNext() == TOK
.colon
)
5676 Identifier ident
= token
.ident
;
5679 if (token
.value
== TOK
.rightCurly
)
5681 else if (token
.value
== TOK
.leftCurly
)
5682 s
= parseStatement(ParseStatementFlags
.curly | ParseStatementFlags
.scope_
);
5684 s
= parseStatement(ParseStatementFlags
.semiOk
);
5685 s
= new AST
.LabelStatement(loc
, ident
, s
);
5694 /* https://issues.dlang.org/show_bug.cgi?id=15163
5695 * If tokens can be handled as
5696 * old C-style declaration or D expression, prefer the latter.
5698 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
5705 case TOK
.int32Literal
:
5706 case TOK
.uns32Literal
:
5707 case TOK
.int64Literal
:
5708 case TOK
.uns64Literal
:
5709 case TOK
.int128Literal
:
5710 case TOK
.uns128Literal
:
5711 case TOK
.float32Literal
:
5712 case TOK
.float64Literal
:
5713 case TOK
.float80Literal
:
5714 case TOK
.imaginary32Literal
:
5715 case TOK
.imaginary64Literal
:
5716 case TOK
.imaginary80Literal
:
5717 case TOK
.charLiteral
:
5718 case TOK
.wcharLiteral
:
5719 case TOK
.dcharLiteral
:
5724 case TOK
.hexadecimalString
:
5725 case TOK
.leftParenthesis
:
5733 case TOK
.minusMinus
:
5740 case TOK
.leftBracket
:
5742 case TOK
.fileFullPath
:
5744 case TOK
.moduleString
:
5745 case TOK
.functionString
:
5746 case TOK
.prettyFunction
:
5749 AST
.Expression exp
= parseExpression();
5750 /* https://issues.dlang.org/show_bug.cgi?id=15103
5751 * Improve declaration / initialization syntax error message
5752 * Error: found 'foo' when expecting ';' following statement
5753 * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
5755 if (token
.value
== TOK
.identifier
&& exp
.op
== EXP
.identifier
)
5757 error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token
).toChars(), exp
.toChars(), token
.toChars(), peek(peek(&token
)).toChars());
5761 check(TOK
.semicolon
, "statement");
5762 s
= new AST
.ExpStatement(loc
, exp
);
5767 // Look ahead to see if it's static assert() or static if()
5768 const tv
= peekNext();
5769 if (tv
== TOK
.assert_
)
5771 s
= new AST
.StaticAssertStatement(parseStaticAssert());
5776 cond
= parseStaticIfCondition();
5779 if (tv
== TOK
.foreach_ || tv
== TOK
.foreach_reverse_
)
5781 s
= parseForeach
!(AST
.StaticForeachStatement
)(loc
, null);
5782 if (flags
& ParseStatementFlags
.scope_
)
5783 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5786 if (tv
== TOK
.import_
)
5788 AST
.Dsymbols
* imports
= parseImport();
5789 s
= new AST
.ImportStatement(loc
, imports
);
5790 if (flags
& ParseStatementFlags
.scope_
)
5791 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5797 if (peekNext() == TOK
.switch_
)
5822 case TOK
.imaginary32
:
5823 case TOK
.imaginary64
:
5824 case TOK
.imaginary80
:
5829 // bug 7773: int.max is always a part of expression
5830 if (peekNext() == TOK
.dot
)
5832 if (peekNext() == TOK
.leftParenthesis
)
5842 case TOK
.immutable_
:
5845 case TOK
.deprecated_
:
5854 case TOK
.interface_
:
5857 AST
.Dsymbols
* a
= parseDeclarations(false, null, null);
5860 auto as
= new AST
.Statements();
5862 foreach (i
; 0 .. a
.dim
)
5864 AST
.Dsymbol d
= (*a
)[i
];
5865 s
= new AST
.ExpStatement(loc
, d
);
5868 s
= new AST
.CompoundDeclarationStatement(loc
, as
);
5870 else if (a
.dim
== 1)
5872 AST
.Dsymbol d
= (*a
)[0];
5873 s
= new AST
.ExpStatement(loc
, d
);
5876 s
= new AST
.ExpStatement(loc
, cast(AST
.Expression
)null);
5877 if (flags
& ParseStatementFlags
.scope_
)
5878 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5883 /* Determine if this is a manifest constant declaration,
5884 * or a conventional enum.
5887 const tv
= peekNext();
5888 if (tv
== TOK
.leftCurly || tv
== TOK
.colon
)
5890 else if (tv
!= TOK
.identifier
)
5894 const nextv
= peekNext2();
5895 if (nextv
== TOK
.leftCurly || nextv
== TOK
.colon || nextv
== TOK
.semicolon
)
5900 s
= new AST
.ExpStatement(loc
, d
);
5901 if (flags
& ParseStatementFlags
.scope_
)
5902 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5907 if (isDeclaration(&token
, NeedDeclaratorId
.mustIfDstyle
, TOK
.reserved
, null))
5909 if (peekNext() == TOK
.leftParenthesis
)
5912 AST
.Expression e
= parseAssignExp();
5913 check(TOK
.semicolon
);
5914 if (e
.op
== EXP
.mixin_
)
5916 AST
.MixinExp cpe
= cast(AST
.MixinExp
)e
;
5917 s
= new AST
.CompileStatement(loc
, cpe
.exps
);
5921 s
= new AST
.ExpStatement(loc
, e
);
5925 AST
.Dsymbol d
= parseMixin();
5926 s
= new AST
.ExpStatement(loc
, d
);
5927 if (flags
& ParseStatementFlags
.scope_
)
5928 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5933 const lookingForElseSave
= lookingForElse
;
5934 lookingForElse
= Loc
.initial
;
5937 //if (token.value == TOK.semicolon)
5938 // error("use `{ }` for an empty statement, not `;`");
5939 auto statements
= new AST
.Statements();
5940 while (token
.value
!= TOK
.rightCurly
&& token
.value
!= TOK
.endOfFile
)
5942 statements
.push(parseStatement(ParseStatementFlags
.semi | ParseStatementFlags
.curlyScope
));
5945 *endPtr
= token
.ptr
;
5949 *pEndloc
= token
.loc
;
5950 pEndloc
= null; // don't set it again
5952 s
= new AST
.CompoundStatement(loc
, statements
);
5953 if (flags
& (ParseStatementFlags
.scope_ | ParseStatementFlags
.curlyScope
))
5954 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
5955 check(TOK
.rightCurly
, "compound statement");
5956 lookingForElse
= lookingForElseSave
;
5961 AST
.Parameter param
= null;
5963 check(TOK
.leftParenthesis
);
5964 param
= parseAssignCondition();
5965 AST
.Expression condition
= parseExpression();
5966 check(TOK
.rightParenthesis
);
5968 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
5969 s
= new AST
.WhileStatement(loc
, condition
, _body
, endloc
, param
);
5973 if (!(flags
& ParseStatementFlags
.semiOk
))
5975 if (flags
& ParseStatementFlags
.semi
)
5976 deprecation("use `{ }` for an empty statement, not `;`");
5978 error("use `{ }` for an empty statement, not `;`");
5981 s
= new AST
.ExpStatement(loc
, cast(AST
.Expression
)null);
5986 AST
.Statement _body
;
5987 AST
.Expression condition
;
5990 const lookingForElseSave
= lookingForElse
;
5991 lookingForElse
= Loc
.initial
;
5992 _body
= parseStatement(ParseStatementFlags
.scope_
);
5993 lookingForElse
= lookingForElseSave
;
5995 check(TOK
.leftParenthesis
);
5996 condition
= parseExpression();
5997 check(TOK
.rightParenthesis
);
5998 if (token
.value
== TOK
.semicolon
)
6001 error("terminating `;` required after do-while statement");
6002 s
= new AST
.DoStatement(loc
, _body
, condition
, token
.loc
);
6007 AST
.Statement _init
;
6008 AST
.Expression condition
;
6009 AST
.Expression increment
;
6012 check(TOK
.leftParenthesis
);
6013 if (token
.value
== TOK
.semicolon
)
6020 const lookingForElseSave
= lookingForElse
;
6021 lookingForElse
= Loc
.initial
;
6022 _init
= parseStatement(0);
6023 lookingForElse
= lookingForElseSave
;
6025 if (token
.value
== TOK
.semicolon
)
6032 condition
= parseExpression();
6033 check(TOK
.semicolon
, "`for` condition");
6035 if (token
.value
== TOK
.rightParenthesis
)
6042 increment
= parseExpression();
6043 check(TOK
.rightParenthesis
);
6046 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6047 s
= new AST
.ForStatement(loc
, _init
, condition
, increment
, _body
, endloc
);
6051 case TOK
.foreach_reverse_
:
6053 s
= parseForeach
!(AST
.Statement
)(loc
, null);
6058 AST
.Parameter param
= null;
6059 AST
.Expression condition
;
6062 check(TOK
.leftParenthesis
);
6063 param
= parseAssignCondition();
6064 condition
= parseExpression();
6065 check(TOK
.rightParenthesis
);
6067 const lookingForElseSave
= lookingForElse
;
6068 lookingForElse
= loc
;
6069 ifbody
= parseStatement(ParseStatementFlags
.scope_
);
6070 lookingForElse
= lookingForElseSave
;
6072 if (token
.value
== TOK
.else_
)
6074 const elseloc
= token
.loc
;
6076 elsebody
= parseStatement(ParseStatementFlags
.scope_
);
6077 checkDanglingElse(elseloc
);
6081 if (condition
&& ifbody
)
6082 s
= new AST
.IfStatement(loc
, param
, condition
, ifbody
, elsebody
, token
.loc
);
6084 s
= null; // don't propagate parsing errors
6089 error("found `else` without a corresponding `if`, `version` or `debug` statement");
6093 if (peekNext() != TOK
.leftParenthesis
)
6094 goto Ldeclaration
; // scope used as storage class
6096 check(TOK
.leftParenthesis
);
6097 if (token
.value
!= TOK
.identifier
)
6099 error("scope identifier expected");
6104 TOK t
= TOK
.onScopeExit
;
6105 Identifier id
= token
.ident
;
6107 t
= TOK
.onScopeExit
;
6108 else if (id
== Id
.failure
)
6109 t
= TOK
.onScopeFailure
;
6110 else if (id
== Id
.success
)
6111 t
= TOK
.onScopeSuccess
;
6113 error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id
.toChars());
6115 check(TOK
.rightParenthesis
);
6116 AST
.Statement st
= parseStatement(ParseStatementFlags
.scope_
);
6117 s
= new AST
.ScopeGuardStatement(loc
, t
, st
);
6123 if (token
.value
== TOK
.assign
)
6125 error("debug conditions can only be declared at module scope");
6130 cond
= parseDebugCondition();
6135 if (token
.value
== TOK
.assign
)
6137 error("version conditions can only be declared at module scope");
6142 cond
= parseVersionCondition();
6147 const lookingForElseSave
= lookingForElse
;
6148 lookingForElse
= loc
;
6149 ifbody
= parseStatement(0);
6150 lookingForElse
= lookingForElseSave
;
6153 if (token
.value
== TOK
.else_
)
6155 const elseloc
= token
.loc
;
6157 elsebody
= parseStatement(0);
6158 checkDanglingElse(elseloc
);
6160 s
= new AST
.ConditionalStatement(loc
, cond
, ifbody
, elsebody
);
6161 if (flags
& ParseStatementFlags
.scope_
)
6162 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6168 AST
.Expressions
* args
= null;
6169 AST
.Statement _body
;
6172 check(TOK
.leftParenthesis
);
6173 if (token
.value
!= TOK
.identifier
)
6175 error("`pragma(identifier)` expected");
6178 ident
= token
.ident
;
6180 if (token
.value
== TOK
.comma
&& peekNext() != TOK
.rightParenthesis
)
6181 args
= parseArguments(); // pragma(identifier, args...);
6183 check(TOK
.rightParenthesis
); // pragma(identifier);
6184 if (token
.value
== TOK
.semicolon
)
6190 _body
= parseStatement(ParseStatementFlags
.semi
);
6191 s
= new AST
.PragmaStatement(loc
, ident
, args
, _body
);
6201 check(TOK
.leftParenthesis
);
6202 AST
.Expression condition
= parseExpression();
6203 check(TOK
.rightParenthesis
);
6204 AST
.Statement _body
= parseStatement(ParseStatementFlags
.scope_
);
6205 s
= new AST
.SwitchStatement(loc
, condition
, _body
, isfinal
);
6211 AST
.Expressions cases
; // array of Expression's
6212 AST
.Expression last
= null;
6217 exp
= parseAssignExp();
6219 if (token
.value
!= TOK
.comma
)
6221 nextToken(); //comma
6223 while (token
.value
!= TOK
.colon
&& token
.value
!= TOK
.endOfFile
);
6226 /* case exp: .. case last:
6228 if (token
.value
== TOK
.slice
)
6231 error("only one `case` allowed for start of case range");
6234 last
= parseAssignExp();
6238 if (flags
& ParseStatementFlags
.curlyScope
)
6240 auto statements
= new AST
.Statements();
6241 while (token
.value
!= TOK
.case_
&& token
.value
!= TOK
.default_
&& token
.value
!= TOK
.endOfFile
&& token
.value
!= TOK
.rightCurly
)
6243 auto cur
= parseStatement(ParseStatementFlags
.semi | ParseStatementFlags
.curlyScope
);
6244 statements
.push(cur
);
6246 // https://issues.dlang.org/show_bug.cgi?id=21739
6247 // Stop at the last break s.t. the following non-case statements are
6248 // not merged into the current case. This can happen for
6249 // case 1: ... break;
6250 // debug { case 2: ... }
6251 if (cur
&& cur
.isBreakStatement())
6254 s
= new AST
.CompoundStatement(loc
, statements
);
6258 s
= parseStatement(ParseStatementFlags
.semi
);
6260 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6264 s
= new AST
.CaseRangeStatement(loc
, exp
, last
, s
);
6268 // Keep cases in order by building the case statements backwards
6269 for (size_t i
= cases
.dim
; i
; i
--)
6272 s
= new AST
.CaseStatement(loc
, exp
, s
);
6282 if (flags
& ParseStatementFlags
.curlyScope
)
6284 auto statements
= new AST
.Statements();
6285 while (token
.value
!= TOK
.case_
&& token
.value
!= TOK
.default_
&& token
.value
!= TOK
.endOfFile
&& token
.value
!= TOK
.rightCurly
)
6287 statements
.push(parseStatement(ParseStatementFlags
.semi | ParseStatementFlags
.curlyScope
));
6289 s
= new AST
.CompoundStatement(loc
, statements
);
6292 s
= parseStatement(ParseStatementFlags
.semi
);
6293 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6294 s
= new AST
.DefaultStatement(loc
, s
);
6301 exp
= token
.value
== TOK
.semicolon ?
null : parseExpression();
6302 check(TOK
.semicolon
, "`return` statement");
6303 s
= new AST
.ReturnStatement(loc
, exp
);
6311 if (token
.value
== TOK
.identifier
)
6313 ident
= token
.ident
;
6316 check(TOK
.semicolon
, "`break` statement");
6317 s
= new AST
.BreakStatement(loc
, ident
);
6325 if (token
.value
== TOK
.identifier
)
6327 ident
= token
.ident
;
6330 check(TOK
.semicolon
, "`continue` statement");
6331 s
= new AST
.ContinueStatement(loc
, ident
);
6338 if (token
.value
== TOK
.default_
)
6341 s
= new AST
.GotoDefaultStatement(loc
);
6343 else if (token
.value
== TOK
.case_
)
6345 AST
.Expression exp
= null;
6347 if (token
.value
!= TOK
.semicolon
)
6348 exp
= parseExpression();
6349 s
= new AST
.GotoCaseStatement(loc
, exp
);
6353 if (token
.value
!= TOK
.identifier
)
6355 error("identifier expected following `goto`");
6360 ident
= token
.ident
;
6363 s
= new AST
.GotoStatement(loc
, ident
);
6365 check(TOK
.semicolon
, "`goto` statement");
6368 case TOK
.synchronized_
:
6371 AST
.Statement _body
;
6373 Token
* t
= peek(&token
);
6374 if (skipAttributes(t
, &t
) && t
.value
== TOK
.class_
)
6378 if (token
.value
== TOK
.leftParenthesis
)
6381 exp
= parseExpression();
6382 check(TOK
.rightParenthesis
);
6386 _body
= parseStatement(ParseStatementFlags
.scope_
);
6387 s
= new AST
.SynchronizedStatement(loc
, exp
, _body
);
6393 AST
.Statement _body
;
6397 check(TOK
.leftParenthesis
);
6398 exp
= parseExpression();
6399 check(TOK
.rightParenthesis
);
6400 _body
= parseStatement(ParseStatementFlags
.scope_
, null, &endloc
);
6401 s
= new AST
.WithStatement(loc
, exp
, _body
, endloc
);
6406 AST
.Statement _body
;
6407 AST
.Catches
* catches
= null;
6408 AST
.Statement finalbody
= null;
6411 const lookingForElseSave
= lookingForElse
;
6412 lookingForElse
= Loc
.initial
;
6413 _body
= parseStatement(ParseStatementFlags
.scope_
);
6414 lookingForElse
= lookingForElseSave
;
6415 while (token
.value
== TOK
.catch_
)
6417 AST
.Statement handler
;
6421 const catchloc
= token
.loc
;
6424 if (token
.value
!= TOK
.leftParenthesis
)
6426 deprecation("`catch` statement without an exception specification is deprecated");
6427 deprecationSupplemental(token
.loc
, "use `catch(Throwable)` for old behavior");
6433 check(TOK
.leftParenthesis
);
6436 check(TOK
.rightParenthesis
);
6438 handler
= parseStatement(0);
6439 c
= new AST
.Catch(catchloc
, t
, id
, handler
);
6441 catches
= new AST
.Catches();
6445 if (token
.value
== TOK
.finally_
)
6448 finalbody
= parseStatement(ParseStatementFlags
.scope_
);
6452 if (!catches
&& !finalbody
)
6453 error("`catch` or `finally` expected following `try`");
6457 s
= new AST
.TryCatchStatement(loc
, _body
, catches
);
6459 s
= new AST
.TryFinallyStatement(loc
, s
, finalbody
);
6467 exp
= parseExpression();
6468 check(TOK
.semicolon
, "`throw` statement");
6469 s
= new AST
.ThrowStatement(loc
, exp
);
6479 /* https://issues.dlang.org/show_bug.cgi?id=16088
6481 * At this point it can either be an
6482 * https://dlang.org/spec/grammar.html#ImportExpression
6484 * https://dlang.org/spec/grammar.html#ImportDeclaration.
6485 * See if the next token after `import` is a `(`; if so,
6486 * then it is an import expression.
6488 if (peekNext() == TOK
.leftParenthesis
)
6490 AST
.Expression e
= parseExpression();
6491 check(TOK
.semicolon
);
6492 s
= new AST
.ExpStatement(loc
, e
);
6496 AST
.Dsymbols
* imports
= parseImport();
6497 s
= new AST
.ImportStatement(loc
, imports
);
6498 if (flags
& ParseStatementFlags
.scope_
)
6499 s
= new AST
.ScopeStatement(loc
, s
, token
.loc
);
6505 AST
.Dsymbol d
= parseTemplateDeclaration();
6506 s
= new AST
.ExpStatement(loc
, d
);
6510 error("found `%s` instead of statement", token
.toChars());
6514 while (token
.value
!= TOK
.rightCurly
&& token
.value
!= TOK
.semicolon
&& token
.value
!= TOK
.endOfFile
)
6516 if (token
.value
== TOK
.semicolon
)
6527 private AST
.ExpInitializer
parseExpInitializer(Loc loc
)
6529 auto ae
= parseAssignExp();
6530 return new AST
.ExpInitializer(loc
, ae
);
6533 private AST
.Initializer
parseStructInitializer(Loc loc
)
6535 /* Scan ahead to discern between a struct initializer and
6536 * parameterless function literal.
6538 * We'll scan the topmost curly bracket level for statement-related
6539 * tokens, thereby ruling out a struct initializer. (A struct
6540 * initializer which itself contains function literals may have
6541 * statements at nested curly bracket levels.)
6543 * It's important that this function literal check not be
6544 * pendantic, otherwise a function having the slightest syntax
6545 * error would emit confusing errors when we proceed to parse it
6546 * as a struct initializer.
6548 * The following two ambiguous cases will be treated as a struct
6549 * initializer (best we can do without type info):
6551 * {{statements...}} - i.e. it could be struct initializer
6552 * with one function literal, or function literal having an
6553 * extra level of curly brackets
6554 * If a function literal is intended in these cases (unlikely),
6555 * source can use a more explicit function literal syntax
6556 * (e.g. prefix with "()" for empty parameter list).
6560 for (auto t
= peek(&token
); 1; t
= peek(t
))
6564 case TOK
.leftParenthesis
:
6567 case TOK
.rightParenthesis
:
6570 // https://issues.dlang.org/show_bug.cgi?id=21163
6571 // lambda params can have the `scope` storage class, e.g
6572 // `S s = { (scope Type Id){} }`
6574 if (!parens
) goto case;
6576 /* Look for a semicolon or keyword of statements which don't
6577 * require a semicolon (typically containing BlockStatement).
6578 * Tokens like "else", "catch", etc. are omitted where the
6579 * leading token of the statement is sufficient.
6586 case TOK
.interface_
:
6591 case TOK
.synchronized_
:
6598 return parseExpInitializer(loc
);
6605 case TOK
.rightCurly
:
6619 auto _is
= new AST
.StructInitializer(loc
);
6620 bool commaExpected
= false;
6624 switch (token
.value
)
6626 case TOK
.identifier
:
6630 error("comma expected separating field initializers");
6631 const t
= peek(&token
);
6633 if (t
.value
== TOK
.colon
)
6637 nextToken(); // skip over ':'
6639 auto value
= parseInitializer();
6640 _is
.addInit(id
, value
);
6641 commaExpected
= true;
6646 error("expression expected, not `,`");
6648 commaExpected
= false;
6651 case TOK
.rightCurly
: // allow trailing comma's
6656 error("found end of file instead of initializer");
6661 error("comma expected separating field initializers");
6662 auto value
= parseInitializer();
6663 _is
.addInit(null, value
);
6664 commaExpected
= true;
6673 /*****************************************
6674 * Parse initializer for variable declaration.
6676 private AST
.Initializer
parseInitializer()
6678 const loc
= token
.loc
;
6680 switch (token
.value
)
6683 return parseStructInitializer(loc
);
6685 case TOK
.leftBracket
:
6686 /* Scan ahead to see if it is an array initializer or
6688 * If it ends with a ';' ',' or '}', it is an array initializer.
6691 for (auto t
= peek(&token
); 1; t
= peek(t
))
6695 case TOK
.leftBracket
:
6699 case TOK
.rightBracket
:
6700 if (--brackets
== 0)
6703 if (t
.value
!= TOK
.semicolon
&& t
.value
!= TOK
.comma
&& t
.value
!= TOK
.rightBracket
&& t
.value
!= TOK
.rightCurly
)
6704 return parseExpInitializer(loc
);
6718 auto ia
= new AST
.ArrayInitializer(loc
);
6719 bool commaExpected
= false;
6724 switch (token
.value
)
6729 error("comma expected separating array initializers, not `%s`", token
.toChars());
6733 auto e
= parseAssignExp();
6737 AST
.Initializer value
;
6738 if (token
.value
== TOK
.colon
)
6741 value
= parseInitializer();
6745 value
= new AST
.ExpInitializer(e
.loc
, e
);
6748 ia
.addInit(e
, value
);
6749 commaExpected
= true;
6753 case TOK
.leftBracket
:
6755 error("comma expected separating array initializers, not `%s`", token
.toChars());
6756 auto value
= parseInitializer();
6759 if (token
.value
== TOK
.colon
)
6762 if (auto ei
= value
.isExpInitializer())
6765 value
= parseInitializer();
6768 error("initializer expression expected following colon, not `%s`", token
.toChars());
6770 ia
.addInit(e
, value
);
6771 commaExpected
= true;
6776 error("expression expected, not `,`");
6778 commaExpected
= false;
6781 case TOK
.rightBracket
: // allow trailing comma's
6786 error("found `%s` instead of array initializer", token
.toChars());
6794 const tv
= peekNext();
6795 if (tv
== TOK
.semicolon || tv
== TOK
.comma
)
6798 return new AST
.VoidInitializer(loc
);
6800 return parseExpInitializer(loc
);
6803 return parseExpInitializer(loc
);
6807 /*****************************************
6808 * Parses default argument initializer expression that is an assign expression,
6809 * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
6811 private AST
.Expression
parseDefaultInitExp()
6813 AST
.Expression e
= null;
6814 const tv
= peekNext();
6815 if (tv
== TOK
.comma || tv
== TOK
.rightParenthesis
)
6817 switch (token
.value
)
6819 case TOK
.file
: e
= new AST
.FileInitExp(token
.loc
, EXP
.file
); break;
6820 case TOK
.fileFullPath
: e
= new AST
.FileInitExp(token
.loc
, EXP
.fileFullPath
); break;
6821 case TOK
.line
: e
= new AST
.LineInitExp(token
.loc
); break;
6822 case TOK
.moduleString
: e
= new AST
.ModuleInitExp(token
.loc
); break;
6823 case TOK
.functionString
: e
= new AST
.FuncInitExp(token
.loc
); break;
6824 case TOK
.prettyFunction
: e
= new AST
.PrettyFuncInitExp(token
.loc
); break;
6831 return parseAssignExp();
6834 /********************
6835 * Parse inline assembler block.
6837 * inline assembler block as a Statement
6839 AST
.Statement
parseAsm()
6841 // Parse the asm block into a sequence of AsmStatements,
6842 // each AsmStatement is one instruction.
6843 // Separate out labels.
6844 // Defer parsing of AsmStatements until semantic processing.
6846 const loc
= token
.loc
;
6850 StorageClass
stc = parsePostfix(STC
.undefined_
, null);
6851 if (stc & (STC
.const_ | STC
.immutable_ | STC
.shared_ | STC
.wild
))
6852 error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
6854 check(TOK
.leftCurly
);
6855 Token
* toklist
= null;
6856 Token
** ptoklist
= &toklist
;
6857 Identifier label
= null;
6858 auto statements
= new AST
.Statements();
6859 size_t nestlevel
= 0;
6862 switch (token
.value
)
6864 case TOK
.identifier
:
6867 // Look ahead to see if it is a label
6868 if (peekNext() == TOK
.colon
)
6871 label
= token
.ident
;
6872 labelloc
= token
.loc
;
6884 case TOK
.rightCurly
:
6890 if (toklist || label
)
6892 error("`asm` statements must end in `;`");
6898 error("mismatched number of curly brackets");
6900 if (toklist || label
)
6902 // Create AsmStatement from list of tokens we've saved
6903 AST
.Statement s
= new AST
.AsmStatement(token
.loc
, toklist
);
6905 ptoklist
= &toklist
;
6908 s
= new AST
.LabelStatement(labelloc
, label
, s
);
6918 error("matching `}` expected, not end of file");
6921 case TOK
.colonColon
: // treat as two separate : tokens for iasmgcc
6922 *ptoklist
= allocateToken();
6923 memcpy(*ptoklist
, &token
, Token
.sizeof
);
6924 (*ptoklist
).value
= TOK
.colon
;
6925 ptoklist
= &(*ptoklist
).next
;
6927 *ptoklist
= allocateToken();
6928 memcpy(*ptoklist
, &token
, Token
.sizeof
);
6929 (*ptoklist
).value
= TOK
.colon
;
6930 ptoklist
= &(*ptoklist
).next
;
6937 *ptoklist
= allocateToken();
6938 memcpy(*ptoklist
, &token
, Token
.sizeof
);
6939 ptoklist
= &(*ptoklist
).next
;
6947 auto s
= new AST
.CompoundAsmStatement(loc
, statements
, stc);
6951 /**********************************
6952 * Issue error if the current token is not `value`,
6953 * advance to next token.
6955 * loc = location for error message
6956 * value = token value to compare with
6958 void check(Loc loc
, TOK value
)
6960 if (token
.value
!= value
)
6961 error(loc
, "found `%s` when expecting `%s`", token
.toChars(), Token
.toChars(value
));
6965 /**********************************
6966 * Issue error if the current token is not `value`,
6967 * advance to next token.
6969 * value = token value to compare with
6971 void check(TOK value
)
6973 check(token
.loc
, value
);
6976 /**********************************
6977 * Issue error if the current token is not `value`,
6978 * advance to next token.
6980 * value = token value to compare with
6981 * string = for error message
6983 void check(TOK value
, const(char)* string
)
6985 if (token
.value
!= value
)
6986 error("found `%s` when expecting `%s` following %s", token
.toChars(), Token
.toChars(value
), string
);
6990 private void checkParens(TOK value
, AST
.Expression e
)
6992 if (precedence
[e
.op
] == PREC
.rel
&& !e
.parens
)
6993 error(e
.loc
, "`%s` must be surrounded by parentheses when next to operator `%s`", e
.toChars(), Token
.toChars(value
));
6997 enum NeedDeclaratorId
6999 no
, // Declarator part must have no identifier
7000 opt
, // Declarator part identifier is optional
7001 must
, // Declarator part must have identifier
7002 mustIfDstyle
, // Declarator part must have identifier, but don't recognize old C-style syntax
7005 /************************************
7006 * Determine if the scanner is sitting on the start of a declaration.
7008 * t = current token of the scanner
7009 * needId = flag with additional requirements for a declaration
7010 * endtok = ending token
7011 * pt = will be set ending token (if not null)
7013 * true if the token `t` is a declaration, false otherwise
7015 private bool isDeclaration(Token
* t
, NeedDeclaratorId needId
, TOK endtok
, Token
** pt
)
7017 //printf("isDeclaration(needId = %d)\n", needId);
7023 if ((t
.value
== TOK
.const_ || t
.value
== TOK
.immutable_ || t
.value
== TOK
.inout_ || t
.value
== TOK
.shared_
) && peek(t
).value
!= TOK
.leftParenthesis
)
7036 if (!isBasicType(&t
))
7040 if (!isDeclarator(&t
, &haveId
, &haveTpl
, endtok
, needId
!= NeedDeclaratorId
.mustIfDstyle
))
7042 if ((needId
== NeedDeclaratorId
.no
&& !haveId
) ||
7043 (needId
== NeedDeclaratorId
.opt
) ||
7044 (needId
== NeedDeclaratorId
.must
&& haveId
) ||
7045 (needId
== NeedDeclaratorId
.mustIfDstyle
&& haveId
))
7054 //printf("\tis declaration, t = %s\n", t.toChars());
7058 //printf("\tis not declaration\n");
7062 private bool isBasicType(Token
** pt
)
7064 // This code parallels parseBasicType()
7085 case TOK
.imaginary32
:
7086 case TOK
.imaginary64
:
7087 case TOK
.imaginary80
:
7095 case TOK
.identifier
:
7098 if (t
.value
== TOK
.not)
7108 if (t
.value
== TOK
.dot
)
7112 if (t
.value
!= TOK
.identifier
)
7115 if (t
.value
!= TOK
.not)
7120 * !( args ), !identifier, etc.
7125 case TOK
.identifier
:
7128 case TOK
.leftParenthesis
:
7129 if (!skipParens(t
, &t
))
7150 case TOK
.imaginary32
:
7151 case TOK
.imaginary64
:
7152 case TOK
.imaginary80
:
7157 case TOK
.int32Literal
:
7158 case TOK
.uns32Literal
:
7159 case TOK
.int64Literal
:
7160 case TOK
.uns64Literal
:
7161 case TOK
.int128Literal
:
7162 case TOK
.uns128Literal
:
7163 case TOK
.float32Literal
:
7164 case TOK
.float64Literal
:
7165 case TOK
.float80Literal
:
7166 case TOK
.imaginary32Literal
:
7167 case TOK
.imaginary64Literal
:
7168 case TOK
.imaginary80Literal
:
7172 case TOK
.charLiteral
:
7173 case TOK
.wcharLiteral
:
7174 case TOK
.dcharLiteral
:
7176 case TOK
.hexadecimalString
:
7178 case TOK
.fileFullPath
:
7180 case TOK
.moduleString
:
7181 case TOK
.functionString
:
7182 case TOK
.prettyFunction
:
7199 /* typeof(exp).identifier...
7202 if (!skipParens(t
, &t
))
7207 // __traits(getMember
7209 if (t
.value
!= TOK
.leftParenthesis
)
7213 if (t
.value
!= TOK
.identifier || t
.ident
!= Id
.getMember
)
7215 if (!skipParens(lp
, &lp
))
7217 // we are in a lookup for decl VS statement
7218 // so we expect a declarator following __trait if it's a type.
7219 // other usages wont be ambiguous (alias, template instance, type qual, etc.)
7220 if (lp
.value
!= TOK
.identifier
)
7226 case TOK
.immutable_
:
7229 // const(type) or immutable(type) or shared(type) or wild(type)
7231 if (t
.value
!= TOK
.leftParenthesis
)
7234 if (!isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &t
))
7249 //printf("is not\n");
7253 private bool isDeclarator(Token
** pt
, int* haveId
, int* haveTpl
, TOK endtok
, bool allowAltSyntax
= true)
7255 // This code parallels parseDeclarator()
7259 //printf("Parser::isDeclarator() %s\n", t.toChars());
7260 if (t
.value
== TOK
.assign
)
7273 case TOK
.leftBracket
:
7275 if (t
.value
== TOK
.rightBracket
)
7279 else if (isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightBracket
, &t
))
7281 // It's an associative array declaration
7285 if (t
.value
== TOK
.dot
&& peek(t
).value
== TOK
.identifier
)
7294 // [ expression .. expression ]
7295 if (!isExpression(&t
))
7297 if (t
.value
== TOK
.slice
)
7300 if (!isExpression(&t
))
7302 if (t
.value
!= TOK
.rightBracket
)
7308 if (t
.value
!= TOK
.rightBracket
)
7312 if (t
.value
== TOK
.dot
&& peek(t
).value
== TOK
.identifier
)
7321 case TOK
.identifier
:
7328 case TOK
.leftParenthesis
:
7329 if (!allowAltSyntax
)
7330 return false; // Do not recognize C-style declarations.
7333 if (t
.value
== TOK
.rightParenthesis
)
7334 return false; // () is not a declarator
7336 /* Regard ( identifier ) as not a declarator
7337 * BUG: what about ( *identifier ) in
7339 * where f is a class instance with overloaded () ?
7340 * Should we just disallow C-style function pointer declarations?
7342 if (t
.value
== TOK
.identifier
)
7344 Token
* t2
= peek(t
);
7345 if (t2
.value
== TOK
.rightParenthesis
)
7349 if (!isDeclarator(&t
, haveId
, null, TOK
.rightParenthesis
))
7358 if (!isParameters(&t
))
7360 skipAttributes(t
, &t
);
7373 static if (CARRAYDECL
)
7375 case TOK
.leftBracket
:
7378 if (t
.value
== TOK
.rightBracket
)
7382 else if (isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightBracket
, &t
))
7384 // It's an associative array declaration
7390 if (!isExpression(&t
))
7392 if (t
.value
!= TOK
.rightBracket
)
7399 case TOK
.leftParenthesis
:
7401 if (Token
* tk
= peekPastParen(t
))
7403 if (tk
.value
== TOK
.leftParenthesis
)
7410 else if (tk
.value
== TOK
.assign
)
7419 if (!isParameters(&t
))
7426 case TOK
.immutable_
:
7437 t
= peek(t
); // skip '@'
7438 t
= peek(t
); // skip identifier
7448 // Valid tokens that follow a declaration
7449 case TOK
.rightParenthesis
:
7450 case TOK
.rightBracket
:
7459 // The !parens is to disallow unnecessary parentheses
7460 if (!parens
&& (endtok
== TOK
.reserved || endtok
== t
.value
))
7467 case TOK
.identifier
:
7468 if (t
.ident
== Id
._body
)
7471 // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
7472 // Deprecated in 2.097 - Can be removed from 2.117
7473 // The deprecation period is longer than usual as `body`
7474 // was quite widely used.
7475 deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
7481 return haveTpl ?
true : false;
7483 // Used for mixin type parsing
7485 if (endtok
== TOK
.endOfFile
)
7496 private bool isParameters(Token
** pt
)
7498 // This code parallels parseParameterList()
7501 //printf("isParameters()\n");
7502 if (t
.value
!= TOK
.leftParenthesis
)
7506 for (; 1; t
= peek(t
))
7511 case TOK
.rightParenthesis
:
7516 if (skipAttributes(t
, &pastAttr
))
7538 case TOK
.immutable_
:
7542 if (t
.value
== TOK
.leftParenthesis
)
7545 if (!isDeclaration(t
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &t
))
7547 t
= peek(t
); // skip past closing ')'
7559 if (t
.value
== TOK
.identifier
)
7561 if (t
.value
== TOK
.assign
)
7564 if (!isExpression(&t
))
7572 if (!isBasicType(&t
))
7576 if (t
.value
!= TOK
.dotDotDot
&& !isDeclarator(&t
, &tmp
, null, TOK
.reserved
))
7578 if (t
.value
== TOK
.assign
)
7581 if (!isExpression(&t
))
7584 if (t
.value
== TOK
.dotDotDot
)
7590 if (t
.value
== TOK
.comma
)
7598 if (t
.value
!= TOK
.rightParenthesis
)
7605 private bool isExpression(Token
** pt
)
7607 // This is supposed to determine if something is an expression.
7608 // What it actually does is scan until a closing right bracket
7616 for (;; t
= peek(t
))
7620 case TOK
.leftBracket
:
7624 case TOK
.rightBracket
:
7629 case TOK
.leftParenthesis
:
7634 if (brnest || panest
)
7638 case TOK
.rightParenthesis
:
7647 case TOK
.rightCurly
:
7648 if (--curlynest
>= 0)
7675 /*******************************************
7678 * t = on opening $(LPAREN)
7679 * pt = *pt is set to token past '$(RPAREN)' on true
7682 * false some parsing error
7684 bool skipParens(Token
* t
, Token
** pt
)
7686 if (t
.value
!= TOK
.leftParenthesis
)
7695 case TOK
.leftParenthesis
:
7699 case TOK
.rightParenthesis
:
7717 *pt
= peek(t
); // skip found rparen
7724 private bool skipParensIf(Token
* t
, Token
** pt
)
7726 if (t
.value
!= TOK
.leftParenthesis
)
7732 return skipParens(t
, pt
);
7735 //returns true if the next value (after optional matching parens) is expected
7736 private bool hasOptionalParensThen(Token
* t
, TOK expected
)
7739 if (!skipParensIf(t
, &tk
))
7741 return tk
.value
== expected
;
7744 /*******************************************
7747 * t is on a candidate attribute
7749 * *pt is set to first non-attribute token on success
7752 * false some parsing error
7754 private bool skipAttributes(Token
* t
, Token
** pt
)
7761 case TOK
.immutable_
:
7769 case TOK
.synchronized_
:
7772 case TOK
.deprecated_
:
7773 if (peek(t
).value
== TOK
.leftParenthesis
)
7776 if (!skipParens(t
, &t
))
7778 // t is on the next of closing parenthesis
7792 if (t
.value
== TOK
.identifier
)
7796 * @identifier!(arglist)
7797 * any of the above followed by (arglist)
7798 * @predefined_attribute
7800 if (isBuiltinAtAttribute(t
.ident
))
7803 if (t
.value
== TOK
.not)
7806 if (t
.value
== TOK
.leftParenthesis
)
7808 // @identifier!(arglist)
7809 if (!skipParens(t
, &t
))
7811 // t is on the next of closing parenthesis
7816 // Do low rent skipTemplateArgument
7817 if (t
.value
== TOK
.vector
)
7819 // identifier!__vector(type)
7821 if (!skipParens(t
, &t
))
7828 if (t
.value
== TOK
.leftParenthesis
)
7830 if (!skipParens(t
, &t
))
7832 // t is on the next of closing parenthesis
7837 if (t
.value
== TOK
.leftParenthesis
)
7839 // @( ArgumentList )
7840 if (!skipParens(t
, &t
))
7842 // t is on the next of closing parenthesis
7861 AST
.Expression
parseExpression()
7863 auto loc
= token
.loc
;
7865 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
7866 auto e
= parseAssignExp();
7867 while (token
.value
== TOK
.comma
)
7870 auto e2
= parseAssignExp();
7871 e
= new AST
.CommaExp(loc
, e
, e2
, false);
7877 /********************************* Expression Parser ***************************/
7879 AST
.Expression
parsePrimaryExp()
7884 const loc
= token
.loc
;
7886 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
7887 switch (token
.value
)
7889 case TOK
.identifier
:
7891 if (peekNext() == TOK
.arrow
)
7893 // skip `identifier ->`
7896 error("use `.` for member lookup, not `->`");
7900 if (peekNext() == TOK
.goesTo
)
7906 if (token
.value
== TOK
.not && (save
= peekNext()) != TOK
.is_
&& save
!= TOK
.in_
)
7908 // identifier!(template-argument-list)
7909 auto tempinst
= new AST
.TemplateInstance(loc
, id
, parseTemplateArguments());
7910 e
= new AST
.ScopeExp(loc
, tempinst
);
7913 e
= new AST
.IdentifierExp(loc
, id
);
7918 error("`$` is valid only inside [] of index or slice");
7919 e
= new AST
.DollarExp(loc
);
7924 // Signal global scope '.' operator with "" identifier
7925 e
= new AST
.IdentifierExp(loc
, Id
.empty
);
7929 e
= new AST
.ThisExp(loc
);
7934 e
= new AST
.SuperExp(loc
);
7938 case TOK
.int32Literal
:
7939 e
= new AST
.IntegerExp(loc
, token
.intvalue
, AST
.Type
.tint32
);
7943 case TOK
.uns32Literal
:
7944 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tuns32
);
7948 case TOK
.int64Literal
:
7949 e
= new AST
.IntegerExp(loc
, token
.intvalue
, AST
.Type
.tint64
);
7953 case TOK
.uns64Literal
:
7954 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tuns64
);
7958 case TOK
.float32Literal
:
7959 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat32
);
7963 case TOK
.float64Literal
:
7964 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat64
);
7968 case TOK
.float80Literal
:
7969 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.tfloat80
);
7973 case TOK
.imaginary32Literal
:
7974 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary32
);
7978 case TOK
.imaginary64Literal
:
7979 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary64
);
7983 case TOK
.imaginary80Literal
:
7984 e
= new AST
.RealExp(loc
, token
.floatvalue
, AST
.Type
.timaginary80
);
7989 e
= new AST
.NullExp(loc
);
7995 const(char)* s
= loc
.filename ? loc
.filename
: mod
.ident
.toChars();
7996 e
= new AST
.StringExp(loc
, s
.toDString());
8000 case TOK
.fileFullPath
:
8002 assert(loc
.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
8003 const s
= FileName
.toAbsolute(loc
.filename
);
8004 e
= new AST
.StringExp(loc
, s
.toDString());
8010 e
= new AST
.IntegerExp(loc
, loc
.linnum
, AST
.Type
.tint32
);
8014 case TOK
.moduleString
:
8016 const(char)* s
= md ? md
.toChars() : mod
.toChars();
8017 e
= new AST
.StringExp(loc
, s
.toDString());
8021 case TOK
.functionString
:
8022 e
= new AST
.FuncInitExp(loc
);
8026 case TOK
.prettyFunction
:
8027 e
= new AST
.PrettyFuncInitExp(loc
);
8032 e
= new AST
.IntegerExp(loc
, 1, AST
.Type
.tbool
);
8037 e
= new AST
.IntegerExp(loc
, 0, AST
.Type
.tbool
);
8041 case TOK
.charLiteral
:
8042 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tchar
);
8046 case TOK
.wcharLiteral
:
8047 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.twchar
);
8051 case TOK
.dcharLiteral
:
8052 e
= new AST
.IntegerExp(loc
, token
.unsvalue
, AST
.Type
.tdchar
);
8057 case TOK
.hexadecimalString
:
8059 // cat adjacent strings
8060 auto s
= token
.ustring
;
8061 auto len
= token
.len
;
8062 auto postfix
= token
.postfix
;
8067 if (token
.value
== TOK
.string_ || token
.value
== TOK
.hexadecimalString
)
8071 if (token
.postfix
!= postfix
)
8072 error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix
, token
.postfix
);
8073 postfix
= token
.postfix
;
8076 error("Implicit string concatenation is error-prone and disallowed in D");
8077 errorSupplemental(token
.loc
, "Use the explicit syntax instead " ~
8078 "(concatenating literals is `@nogc`): %s ~ %s",
8079 prev
.toChars(), token
.toChars());
8082 const len2
= token
.len
;
8084 auto s2
= cast(char*)mem
.xmalloc_noscan(len
* char.sizeof
);
8085 memcpy(s2
, s
, len1
* char.sizeof
);
8086 memcpy(s2
+ len1
, token
.ustring
, len2
* char.sizeof
);
8092 e
= new AST
.StringExp(loc
, s
[0 .. len
], len
, 1, postfix
);
8108 t
= AST
.Type
.tint16
;
8112 t
= AST
.Type
.tuns16
;
8116 t
= AST
.Type
.tint32
;
8120 t
= AST
.Type
.tuns32
;
8124 t
= AST
.Type
.tint64
;
8128 t
= AST
.Type
.tuns64
;
8132 t
= AST
.Type
.tint128
;
8136 t
= AST
.Type
.tuns128
;
8140 t
= AST
.Type
.tfloat32
;
8144 t
= AST
.Type
.tfloat64
;
8148 t
= AST
.Type
.tfloat80
;
8151 case TOK
.imaginary32
:
8152 t
= AST
.Type
.timaginary32
;
8155 case TOK
.imaginary64
:
8156 t
= AST
.Type
.timaginary64
;
8159 case TOK
.imaginary80
:
8160 t
= AST
.Type
.timaginary80
;
8164 t
= AST
.Type
.tcomplex32
;
8168 t
= AST
.Type
.tcomplex64
;
8172 t
= AST
.Type
.tcomplex80
;
8184 t
= AST
.Type
.twchar
;
8188 t
= AST
.Type
.tdchar
;
8192 if (token
.value
== TOK
.leftParenthesis
)
8194 e
= new AST
.TypeExp(loc
, t
);
8195 e
= new AST
.CallExp(loc
, e
, parseArguments());
8198 check(TOK
.dot
, t
.toChars());
8199 if (token
.value
!= TOK
.identifier
)
8201 error("found `%s` when expecting identifier following `%s`.", token
.toChars(), t
.toChars());
8204 e
= new AST
.DotIdExp(loc
, new AST
.TypeExp(loc
, t
), token
.ident
);
8211 e
= new AST
.TypeExp(loc
, t
);
8217 e
= new AST
.TypeExp(loc
, t
);
8223 check(TOK
.leftParenthesis
, "`typeid`");
8224 RootObject o
= parseTypeOrAssignExp();
8225 check(TOK
.rightParenthesis
);
8226 e
= new AST
.TypeidExp(loc
, o
);
8231 /* __traits(identifier, args...)
8234 AST
.Objects
* args
= null;
8237 check(TOK
.leftParenthesis
);
8238 if (token
.value
!= TOK
.identifier
)
8240 error("`__traits(identifier, args...)` expected");
8243 ident
= token
.ident
;
8245 if (token
.value
== TOK
.comma
)
8246 args
= parseTemplateArgumentList(); // __traits(identifier, args...)
8248 check(TOK
.rightParenthesis
); // __traits(identifier)
8250 e
= new AST
.TraitsExp(loc
, ident
, args
);
8256 Identifier ident
= null;
8257 AST
.Type tspec
= null;
8258 TOK tok
= TOK
.reserved
;
8259 TOK tok2
= TOK
.reserved
;
8260 AST
.TemplateParameters
* tpl
= null;
8263 if (token
.value
== TOK
.leftParenthesis
)
8266 if (token
.value
== TOK
.identifier
&& peekNext() == TOK
.leftParenthesis
)
8268 error(loc
, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token
.toChars());
8270 Token
* tempTok
= peekPastParen(&token
);
8271 memcpy(&token
, tempTok
, Token
.sizeof
);
8274 targ
= parseType(&ident
);
8275 if (token
.value
== TOK
.colon || token
.value
== TOK
.equal
)
8279 if (tok
== TOK
.equal
&& (token
.value
== TOK
.struct_ || token
.value
== TOK
.union_
8280 || token
.value
== TOK
.class_ || token
.value
== TOK
.super_ || token
.value
== TOK
.enum_
8281 || token
.value
== TOK
.interface_ || token
.value
== TOK
.package_ || token
.value
== TOK
.module_
8282 || token
.value
== TOK
.argumentTypes || token
.value
== TOK
.parameters
8283 || token
.value
== TOK
.const_
&& peekNext() == TOK
.rightParenthesis
8284 || token
.value
== TOK
.immutable_
&& peekNext() == TOK
.rightParenthesis
8285 || token
.value
== TOK
.shared_
&& peekNext() == TOK
.rightParenthesis
8286 || token
.value
== TOK
.inout_
&& peekNext() == TOK
.rightParenthesis || token
.value
== TOK
.function_
8287 || token
.value
== TOK
.delegate_ || token
.value
== TOK
.return_
8288 ||
(token
.value
== TOK
.vector
&& peekNext() == TOK
.rightParenthesis
)))
8295 tspec
= parseType();
8300 if (token
.value
== TOK
.comma
)
8301 tpl
= parseTemplateParameterList(1);
8304 tpl
= new AST
.TemplateParameters();
8305 check(TOK
.rightParenthesis
);
8309 check(TOK
.rightParenthesis
);
8313 error("`type identifier : specialization` expected following `is`");
8316 e
= new AST
.IsExp(loc
, targ
, ident
, tok
, tspec
, tok2
, tpl
);
8321 // https://dlang.org/spec/expression.html#assert_expressions
8322 AST
.Expression msg
= null;
8325 check(TOK
.leftParenthesis
, "`assert`");
8326 e
= parseAssignExp();
8327 if (token
.value
== TOK
.comma
)
8330 if (token
.value
!= TOK
.rightParenthesis
)
8332 msg
= parseAssignExp();
8333 if (token
.value
== TOK
.comma
)
8337 check(TOK
.rightParenthesis
);
8338 e
= new AST
.AssertExp(loc
, e
, msg
);
8343 // https://dlang.org/spec/expression.html#mixin_expressions
8345 if (token
.value
!= TOK
.leftParenthesis
)
8346 error("found `%s` when expecting `%s` following `mixin`", token
.toChars(), Token
.toChars(TOK
.leftParenthesis
));
8347 auto exps
= parseArguments();
8348 e
= new AST
.MixinExp(loc
, exps
);
8354 check(TOK
.leftParenthesis
, "`import`");
8355 e
= parseAssignExp();
8356 check(TOK
.rightParenthesis
);
8357 e
= new AST
.ImportExp(loc
, e
);
8361 e
= parseNewExp(null);
8366 if (peekNext() == TOK
.leftParenthesis
)
8368 Token
* tk
= peekPastParen(peek(&token
));
8369 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8371 // ref (arguments) => expression
8372 // ref (arguments) { statements... }
8377 error("found `%s` when expecting function literal following `ref`", token
.toChars());
8380 case TOK
.leftParenthesis
:
8382 Token
* tk
= peekPastParen(&token
);
8383 if (skipAttributes(tk
, &tk
) && (tk
.value
== TOK
.goesTo || tk
.value
== TOK
.leftCurly
))
8385 // (arguments) => expression
8386 // (arguments) { statements... }
8392 e
= parseExpression();
8394 check(loc
, TOK
.rightParenthesis
);
8397 case TOK
.leftBracket
:
8399 /* Parse array literals and associative array literals:
8400 * [ value, value, value ... ]
8401 * [ key:value, key:value, key:value ... ]
8403 auto values
= new AST
.Expressions();
8404 AST
.Expressions
* keys
= null;
8407 while (token
.value
!= TOK
.rightBracket
&& token
.value
!= TOK
.endOfFile
)
8409 e
= parseAssignExp();
8410 if (token
.value
== TOK
.colon
&& (keys || values
.dim
== 0))
8414 keys
= new AST
.Expressions();
8416 e
= parseAssignExp();
8420 error("`key:value` expected for associative array literal");
8424 if (token
.value
== TOK
.rightBracket
)
8428 check(loc
, TOK
.rightBracket
);
8431 e
= new AST
.AssocArrayLiteralExp(loc
, keys
, values
);
8433 e
= new AST
.ArrayLiteralExp(loc
, null, values
);
8441 AST
.Dsymbol s
= parseFunctionLiteral();
8442 e
= new AST
.FuncExp(loc
, s
);
8446 error("expression expected, not `%s`", token
.toChars());
8448 // Anything for e, as long as it's not NULL
8449 e
= new AST
.IntegerExp(loc
, 0, AST
.Type
.tint32
);
8456 private AST
.Expression
parseUnaryExp()
8459 const loc
= token
.loc
;
8461 switch (token
.value
)
8465 e
= parseUnaryExp();
8466 e
= new AST
.AddrExp(loc
, e
);
8471 e
= parseUnaryExp();
8472 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8473 e
= new AST
.PreExp(EXP
.prePlusPlus
, loc
, e
);
8476 case TOK
.minusMinus
:
8478 e
= parseUnaryExp();
8479 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8480 e
= new AST
.PreExp(EXP
.preMinusMinus
, loc
, e
);
8485 e
= parseUnaryExp();
8486 e
= new AST
.PtrExp(loc
, e
);
8491 e
= parseUnaryExp();
8492 e
= new AST
.NegExp(loc
, e
);
8497 e
= parseUnaryExp();
8498 e
= new AST
.UAddExp(loc
, e
);
8503 e
= parseUnaryExp();
8504 e
= new AST
.NotExp(loc
, e
);
8509 e
= parseUnaryExp();
8510 e
= new AST
.ComExp(loc
, e
);
8515 e
= parseUnaryExp();
8516 e
= new AST
.DeleteExp(loc
, e
, false);
8519 case TOK
.cast_
: // cast(type) expression
8522 check(TOK
.leftParenthesis
);
8523 /* Look for cast(), cast(const), cast(immutable),
8524 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
8529 switch (token
.value
)
8532 if (peekNext() == TOK
.leftParenthesis
)
8533 break; // const as type constructor
8534 m |
= MODFlags
.const_
; // const as storage class
8538 case TOK
.immutable_
:
8539 if (peekNext() == TOK
.leftParenthesis
)
8541 m |
= MODFlags
.immutable_
;
8546 if (peekNext() == TOK
.leftParenthesis
)
8548 m |
= MODFlags
.shared_
;
8553 if (peekNext() == TOK
.leftParenthesis
)
8564 if (token
.value
== TOK
.rightParenthesis
)
8567 e
= parseUnaryExp();
8568 e
= new AST
.CastExp(loc
, e
, m
);
8572 AST
.Type t
= parseType(); // cast( type )
8573 t
= t
.addMod(m
); // cast( const type )
8574 check(TOK
.rightParenthesis
);
8575 e
= parseUnaryExp();
8576 e
= new AST
.CastExp(loc
, e
, t
);
8583 case TOK
.immutable_
: // immutable(type)(arguments) / immutable(type).init
8585 StorageClass
stc = parseTypeCtor();
8587 AST
.Type t
= parseBasicType();
8590 if (stc == 0 && token
.value
== TOK
.dot
)
8593 if (token
.value
!= TOK
.identifier
)
8595 error("identifier expected following `(type)`.");
8598 e
= new AST
.DotIdExp(loc
, new AST
.TypeExp(loc
, t
), token
.ident
);
8600 e
= parsePostExp(e
);
8604 e
= new AST
.TypeExp(loc
, t
);
8605 if (token
.value
!= TOK
.leftParenthesis
)
8607 error("`(arguments)` expected following `%s`", t
.toChars());
8610 e
= new AST
.CallExp(loc
, e
, parseArguments());
8614 case TOK
.leftParenthesis
:
8616 auto tk
= peek(&token
);
8617 static if (CCASTSYNTAX
)
8620 if (isDeclaration(tk
, NeedDeclaratorId
.no
, TOK
.rightParenthesis
, &tk
))
8622 tk
= peek(tk
); // skip over right parenthesis
8627 if (tk
.value
== TOK
.is_ || tk
.value
== TOK
.in_
) // !is or !in
8633 case TOK
.minusMinus
:
8636 case TOK
.leftParenthesis
:
8637 case TOK
.identifier
:
8640 case TOK
.int32Literal
:
8641 case TOK
.uns32Literal
:
8642 case TOK
.int64Literal
:
8643 case TOK
.uns64Literal
:
8644 case TOK
.int128Literal
:
8645 case TOK
.uns128Literal
:
8646 case TOK
.float32Literal
:
8647 case TOK
.float64Literal
:
8648 case TOK
.float80Literal
:
8649 case TOK
.imaginary32Literal
:
8650 case TOK
.imaginary64Literal
:
8651 case TOK
.imaginary80Literal
:
8655 case TOK
.charLiteral
:
8656 case TOK
.wcharLiteral
:
8657 case TOK
.dcharLiteral
:
8673 case TOK
.fileFullPath
:
8675 case TOK
.moduleString
:
8676 case TOK
.functionString
:
8677 case TOK
.prettyFunction
:
8695 case TOK
.imaginary32
:
8696 case TOK
.imaginary64
:
8697 case TOK
.imaginary80
:
8705 auto t
= parseType();
8706 check(TOK
.rightParenthesis
);
8709 // or .identifier!( ... )
8710 if (token
.value
== TOK
.dot
)
8712 if (peekNext() != TOK
.identifier
&& peekNext() != TOK
.new_
)
8714 error("identifier or new keyword expected following `(...)`.");
8717 e
= new AST
.TypeExp(loc
, t
);
8719 e
= parsePostExp(e
);
8723 e
= parseUnaryExp();
8724 e
= new AST
.CastExp(loc
, e
, t
);
8725 error("C style cast illegal, use `%s`", e
.toChars());
8734 e
= parsePrimaryExp();
8735 e
= parsePostExp(e
);
8739 e
= parsePrimaryExp();
8740 e
= parsePostExp(e
);
8745 // ^^ is right associative and has higher precedence than the unary operators
8746 while (token
.value
== TOK
.pow
)
8749 AST
.Expression e2
= parseUnaryExp();
8750 e
= new AST
.PowExp(loc
, e
, e2
);
8756 private AST
.Expression
parsePostExp(AST
.Expression e
)
8760 const loc
= token
.loc
;
8761 switch (token
.value
)
8765 if (token
.value
== TOK
.identifier
)
8767 Identifier id
= token
.ident
;
8770 if (token
.value
== TOK
.not && peekNext() != TOK
.is_
&& peekNext() != TOK
.in_
)
8772 AST
.Objects
* tiargs
= parseTemplateArguments();
8773 e
= new AST
.DotTemplateInstanceExp(loc
, e
, id
, tiargs
);
8776 e
= new AST
.DotIdExp(loc
, e
, id
);
8779 if (token
.value
== TOK
.new_
)
8784 error("identifier or `new` expected following `.`, not `%s`", token
.toChars());
8788 e
= new AST
.PostExp(EXP
.plusPlus
, loc
, e
);
8791 case TOK
.minusMinus
:
8792 e
= new AST
.PostExp(EXP
.minusMinus
, loc
, e
);
8795 case TOK
.leftParenthesis
:
8796 e
= new AST
.CallExp(loc
, e
, parseArguments());
8799 case TOK
.leftBracket
:
8801 // array dereferences:
8804 // array[lwr .. upr]
8805 AST
.Expression index
;
8807 auto arguments
= new AST
.Expressions();
8811 while (token
.value
!= TOK
.rightBracket
&& token
.value
!= TOK
.endOfFile
)
8813 index
= parseAssignExp();
8814 if (token
.value
== TOK
.slice
)
8816 // array[..., lwr..upr, ...]
8818 upr
= parseAssignExp();
8819 arguments
.push(new AST
.IntervalExp(loc
, index
, upr
));
8822 arguments
.push(index
);
8823 if (token
.value
== TOK
.rightBracket
)
8827 check(TOK
.rightBracket
);
8829 e
= new AST
.ArrayExp(loc
, e
, arguments
);
8839 private AST
.Expression
parseMulExp()
8841 const loc
= token
.loc
;
8842 auto e
= parseUnaryExp();
8846 switch (token
.value
)
8850 auto e2
= parseUnaryExp();
8851 e
= new AST
.MulExp(loc
, e
, e2
);
8856 auto e2
= parseUnaryExp();
8857 e
= new AST
.DivExp(loc
, e
, e2
);
8862 auto e2
= parseUnaryExp();
8863 e
= new AST
.ModExp(loc
, e
, e2
);
8874 private AST
.Expression
parseAddExp()
8876 const loc
= token
.loc
;
8877 auto e
= parseMulExp();
8881 switch (token
.value
)
8885 auto e2
= parseMulExp();
8886 e
= new AST
.AddExp(loc
, e
, e2
);
8891 auto e2
= parseMulExp();
8892 e
= new AST
.MinExp(loc
, e
, e2
);
8897 auto e2
= parseMulExp();
8898 e
= new AST
.CatExp(loc
, e
, e2
);
8909 private AST
.Expression
parseShiftExp()
8911 const loc
= token
.loc
;
8912 auto e
= parseAddExp();
8916 switch (token
.value
)
8920 auto e2
= parseAddExp();
8921 e
= new AST
.ShlExp(loc
, e
, e2
);
8924 case TOK
.rightShift
:
8926 auto e2
= parseAddExp();
8927 e
= new AST
.ShrExp(loc
, e
, e2
);
8930 case TOK
.unsignedRightShift
:
8932 auto e2
= parseAddExp();
8933 e
= new AST
.UshrExp(loc
, e
, e2
);
8944 private AST
.Expression
parseCmpExp()
8946 const loc
= token
.loc
;
8948 auto e
= parseShiftExp();
8949 EXP op
= EXP
.reserved
;
8951 switch (token
.value
)
8953 case TOK
.equal
: op
= EXP
.equal
; goto Lequal
;
8954 case TOK
.notEqual
: op
= EXP
.notEqual
; goto Lequal
;
8957 auto e2
= parseShiftExp();
8958 e
= new AST
.EqualExp(op
, loc
, e
, e2
);
8963 // Attempt to identify '!is'
8964 const tv
= peekNext();
8969 auto e2
= parseShiftExp();
8970 e
= new AST
.InExp(loc
, e
, e2
);
8971 e
= new AST
.NotExp(loc
, e
);
8977 op
= EXP
.notIdentity
;
8980 case TOK
.is_
: op
= EXP
.identity
; goto Lidentity
;
8983 auto e2
= parseShiftExp();
8984 e
= new AST
.IdentityExp(op
, loc
, e
, e2
);
8987 case TOK
.lessThan
: op
= EXP
.lessThan
; goto Lcmp
;
8988 case TOK
.lessOrEqual
: op
= EXP
.lessOrEqual
; goto Lcmp
;
8989 case TOK
.greaterThan
: op
= EXP
.greaterThan
; goto Lcmp
;
8990 case TOK
.greaterOrEqual
: op
= EXP
.greaterOrEqual
; goto Lcmp
;
8993 auto e2
= parseShiftExp();
8994 e
= new AST
.CmpExp(op
, loc
, e
, e2
);
8999 auto e2
= parseShiftExp();
9000 e
= new AST
.InExp(loc
, e
, e2
);
9009 private AST
.Expression
parseAndExp()
9011 Loc loc
= token
.loc
;
9012 auto e
= parseCmpExp();
9013 while (token
.value
== TOK
.and)
9015 checkParens(TOK
.and, e
);
9017 auto e2
= parseCmpExp();
9018 checkParens(TOK
.and, e2
);
9019 e
= new AST
.AndExp(loc
, e
, e2
);
9025 private AST
.Expression
parseXorExp()
9027 const loc
= token
.loc
;
9029 auto e
= parseAndExp();
9030 while (token
.value
== TOK
.xor)
9032 checkParens(TOK
.xor, e
);
9034 auto e2
= parseAndExp();
9035 checkParens(TOK
.xor, e2
);
9036 e
= new AST
.XorExp(loc
, e
, e2
);
9041 private AST
.Expression
parseOrExp()
9043 const loc
= token
.loc
;
9045 auto e
= parseXorExp();
9046 while (token
.value
== TOK
.or)
9048 checkParens(TOK
.or, e
);
9050 auto e2
= parseXorExp();
9051 checkParens(TOK
.or, e2
);
9052 e
= new AST
.OrExp(loc
, e
, e2
);
9057 private AST
.Expression
parseAndAndExp()
9059 const loc
= token
.loc
;
9061 auto e
= parseOrExp();
9062 while (token
.value
== TOK
.andAnd
)
9065 auto e2
= parseOrExp();
9066 e
= new AST
.LogicalExp(loc
, EXP
.andAnd
, e
, e2
);
9071 private AST
.Expression
parseOrOrExp()
9073 const loc
= token
.loc
;
9075 auto e
= parseAndAndExp();
9076 while (token
.value
== TOK
.orOr
)
9079 auto e2
= parseAndAndExp();
9080 e
= new AST
.LogicalExp(loc
, EXP
.orOr
, e
, e2
);
9085 private AST
.Expression
parseCondExp()
9087 const loc
= token
.loc
;
9089 auto e
= parseOrOrExp();
9090 if (token
.value
== TOK
.question
)
9093 auto e1
= parseExpression();
9095 auto e2
= parseCondExp();
9096 e
= new AST
.CondExp(loc
, e
, e1
, e2
);
9101 AST
.Expression
parseAssignExp()
9108 // require parens for e.g. `t ? a = 1 : b = 2`
9109 void checkRequiredParens()
9111 if (e
.op
== EXP
.question
&& !e
.parens
)
9112 dmd
.errors
.error(e
.loc
, "`%s` must be surrounded by parentheses when next to operator `%s`",
9113 e
.toChars(), Token
.toChars(token
.value
));
9116 const loc
= token
.loc
;
9117 switch (token
.value
)
9120 checkRequiredParens();
9122 auto e2
= parseAssignExp();
9123 e
= new AST
.AssignExp(loc
, e
, e2
);
9127 checkRequiredParens();
9129 auto e2
= parseAssignExp();
9130 e
= new AST
.AddAssignExp(loc
, e
, e2
);
9134 checkRequiredParens();
9136 auto e2
= parseAssignExp();
9137 e
= new AST
.MinAssignExp(loc
, e
, e2
);
9141 checkRequiredParens();
9143 auto e2
= parseAssignExp();
9144 e
= new AST
.MulAssignExp(loc
, e
, e2
);
9148 checkRequiredParens();
9150 auto e2
= parseAssignExp();
9151 e
= new AST
.DivAssignExp(loc
, e
, e2
);
9155 checkRequiredParens();
9157 auto e2
= parseAssignExp();
9158 e
= new AST
.ModAssignExp(loc
, e
, e2
);
9162 checkRequiredParens();
9164 auto e2
= parseAssignExp();
9165 e
= new AST
.PowAssignExp(loc
, e
, e2
);
9169 checkRequiredParens();
9171 auto e2
= parseAssignExp();
9172 e
= new AST
.AndAssignExp(loc
, e
, e2
);
9176 checkRequiredParens();
9178 auto e2
= parseAssignExp();
9179 e
= new AST
.OrAssignExp(loc
, e
, e2
);
9183 checkRequiredParens();
9185 auto e2
= parseAssignExp();
9186 e
= new AST
.XorAssignExp(loc
, e
, e2
);
9189 case TOK
.leftShiftAssign
:
9190 checkRequiredParens();
9192 auto e2
= parseAssignExp();
9193 e
= new AST
.ShlAssignExp(loc
, e
, e2
);
9196 case TOK
.rightShiftAssign
:
9197 checkRequiredParens();
9199 auto e2
= parseAssignExp();
9200 e
= new AST
.ShrAssignExp(loc
, e
, e2
);
9203 case TOK
.unsignedRightShiftAssign
:
9204 checkRequiredParens();
9206 auto e2
= parseAssignExp();
9207 e
= new AST
.UshrAssignExp(loc
, e
, e2
);
9210 case TOK
.concatenateAssign
:
9211 checkRequiredParens();
9213 auto e2
= parseAssignExp();
9214 e
= new AST
.CatAssignExp(loc
, e
, e2
);
9224 /*************************
9225 * Collect argument list.
9226 * Assume current token is ',', '$(LPAREN)' or '['.
9228 private AST
.Expressions
* parseArguments()
9231 AST
.Expressions
* arguments
;
9233 arguments
= new AST
.Expressions();
9234 const endtok
= token
.value
== TOK
.leftBracket ? TOK
.rightBracket
: TOK
.rightParenthesis
;
9238 while (token
.value
!= endtok
&& token
.value
!= TOK
.endOfFile
)
9240 auto arg
= parseAssignExp();
9241 arguments
.push(arg
);
9242 if (token
.value
!= TOK
.comma
)
9245 nextToken(); //comma
9253 /*******************************************
9255 private AST
.Expression
parseNewExp(AST
.Expression thisexp
)
9257 const loc
= token
.loc
;
9260 AST
.Expressions
* newargs
= null;
9261 AST
.Expressions
* arguments
= null;
9262 if (token
.value
== TOK
.leftParenthesis
)
9264 newargs
= parseArguments();
9267 // An anonymous nested class starts with "class"
9268 if (token
.value
== TOK
.class_
)
9271 if (token
.value
== TOK
.leftParenthesis
)
9272 arguments
= parseArguments();
9274 AST
.BaseClasses
* baseclasses
= null;
9275 if (token
.value
!= TOK
.leftCurly
)
9276 baseclasses
= parseBaseClasses();
9278 Identifier id
= null;
9279 AST
.Dsymbols
* members
= null;
9281 if (token
.value
!= TOK
.leftCurly
)
9283 error("`{ members }` expected for anonymous class");
9288 members
= parseDeclDefs(0);
9289 if (token
.value
!= TOK
.rightCurly
)
9290 error("class member expected");
9294 auto cd
= new AST
.ClassDeclaration(loc
, id
, baseclasses
, members
, false);
9295 auto e
= new AST
.NewAnonClassExp(loc
, thisexp
, newargs
, cd
, arguments
);
9299 const stc = parseTypeCtor();
9300 auto t
= parseBasicType(true);
9301 t
= parseTypeSuffixes(t
);
9303 if (t
.ty
== Taarray
)
9305 AST
.TypeAArray taa
= cast(AST
.TypeAArray
)t
;
9306 AST
.Type index
= taa
.index
;
9307 auto edim
= AST
.typeToExpression(index
);
9310 error("cannot create a `%s` with `new`", t
.toChars
);
9311 return new AST
.NullExp(loc
);
9313 t
= new AST
.TypeSArray(taa
.next
, edim
);
9315 else if (token
.value
== TOK
.leftParenthesis
&& t
.ty
!= Tsarray
)
9317 arguments
= parseArguments();
9320 auto e
= new AST
.NewExp(loc
, thisexp
, newargs
, t
, arguments
);
9324 /**********************************************
9326 private void addComment(AST
.Dsymbol s
, const(char)* blockComment
)
9329 this.addComment(s
, blockComment
.toDString());
9332 private void addComment(AST
.Dsymbol s
, const(char)[] blockComment
)
9336 s
.addComment(combineComments(blockComment
, token
.lineComment
, true));
9337 token
.lineComment
= null;
9341 /**********************************************
9342 * Recognize builtin @ attributes
9344 * ident = identifier
9346 * storage class for attribute, 0 if not
9348 static StorageClass
isBuiltinAtAttribute(Identifier ident
)
9350 return (ident
== Id
.property
) ? STC
.property
:
9351 (ident
== Id
.nogc
) ? STC
.nogc
:
9352 (ident
== Id
.safe
) ? STC
.safe
:
9353 (ident
== Id
.trusted
) ? STC
.trusted
:
9354 (ident
== Id
.system
) ? STC
.system
:
9355 (ident
== Id
.live
) ? STC
.live
:
9356 (ident
== Id
.future
) ? STC
.future
:
9357 (ident
== Id
.disable
) ? STC
.disable
:
9361 enum StorageClass atAttrGroup
=
9368 /*STC.future |*/ // probably should be included