parse.d revision 1.1 1 1.1 mrg /**
2 1.1 mrg * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
3 1.1 mrg *
4 1.1 mrg * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar)
5 1.1 mrg *
6 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d)
10 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_parse.html
11 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parse.d
12 1.1 mrg */
13 1.1 mrg
14 1.1 mrg module dmd.parse;
15 1.1 mrg
16 1.1 mrg import core.stdc.stdio;
17 1.1 mrg import core.stdc.string;
18 1.1 mrg import dmd.astenums;
19 1.1 mrg import dmd.globals;
20 1.1 mrg import dmd.id;
21 1.1 mrg import dmd.identifier;
22 1.1 mrg import dmd.lexer;
23 1.1 mrg import dmd.errors;
24 1.1 mrg import dmd.root.filename;
25 1.1 mrg import dmd.common.outbuffer;
26 1.1 mrg import dmd.root.rmem;
27 1.1 mrg import dmd.root.rootobject;
28 1.1 mrg import dmd.root.string;
29 1.1 mrg import dmd.tokens;
30 1.1 mrg
31 1.1 mrg /***********************************************************
32 1.1 mrg */
33 1.1 mrg class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
34 1.1 mrg {
35 1.1 mrg AST.ModuleDeclaration* md;
36 1.1 mrg
37 1.1 mrg protected
38 1.1 mrg {
39 1.1 mrg AST.Module mod;
40 1.1 mrg LINK linkage;
41 1.1 mrg Loc linkLoc;
42 1.1 mrg CPPMANGLE cppmangle;
43 1.1 mrg Loc endloc; // set to location of last right curly
44 1.1 mrg int inBrackets; // inside [] of array index or slice
45 1.1 mrg Loc lookingForElse; // location of lonely if looking for an else
46 1.1 mrg }
47 1.1 mrg
48 1.1 mrg /*********************
49 1.1 mrg * Use this constructor for string mixins.
50 1.1 mrg * Input:
51 1.1 mrg * loc location in source file of mixin
52 1.1 mrg */
53 1.1 mrg extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment)
54 1.1 mrg {
55 1.1 mrg super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false);
56 1.1 mrg
57 1.1 mrg //printf("Parser::Parser()\n");
58 1.1 mrg scanloc = loc;
59 1.1 mrg
60 1.1 mrg if (!writeMixin(input, scanloc) && loc.filename)
61 1.1 mrg {
62 1.1 mrg /* Create a pseudo-filename for the mixin string, as it may not even exist
63 1.1 mrg * in the source file.
64 1.1 mrg */
65 1.1 mrg char* filename = cast(char*)mem.xmalloc(strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1);
66 1.1 mrg sprintf(filename, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
67 1.1 mrg scanloc.filename = filename;
68 1.1 mrg }
69 1.1 mrg
70 1.1 mrg mod = _module;
71 1.1 mrg linkage = LINK.d;
72 1.1 mrg //nextToken(); // start up the scanner
73 1.1 mrg }
74 1.1 mrg
75 1.1 mrg extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment)
76 1.1 mrg {
77 1.1 mrg super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false);
78 1.1 mrg
79 1.1 mrg //printf("Parser::Parser()\n");
80 1.1 mrg mod = _module;
81 1.1 mrg linkage = LINK.d;
82 1.1 mrg //nextToken(); // start up the scanner
83 1.1 mrg }
84 1.1 mrg
85 1.1 mrg /++
86 1.1 mrg + Parse a module, i.e. the optional `module x.y.z` declaration and all declarations
87 1.1 mrg + found in the current file.
88 1.1 mrg +
89 1.1 mrg + Returns: the list of declarations or an empty list in case of malformed declarations,
90 1.1 mrg + the module declaration will be stored as `this.md` if found
91 1.1 mrg +/
92 1.1 mrg AST.Dsymbols* parseModule()
93 1.1 mrg {
94 1.1 mrg if (!parseModuleDeclaration())
95 1.1 mrg return errorReturn();
96 1.1 mrg
97 1.1 mrg return parseModuleContent();
98 1.1 mrg }
99 1.1 mrg
100 1.1 mrg /++
101 1.1 mrg + Parse the optional module declaration
102 1.1 mrg +
103 1.1 mrg + Returns: false if a malformed module declaration was found
104 1.1 mrg +/
105 1.1 mrg final bool parseModuleDeclaration()
106 1.1 mrg {
107 1.1 mrg const comment = token.blockComment;
108 1.1 mrg bool isdeprecated = false;
109 1.1 mrg AST.Expression msg = null;
110 1.1 mrg
111 1.1 mrg // Parse optional module attributes
112 1.1 mrg parseModuleAttributes(msg, isdeprecated);
113 1.1 mrg
114 1.1 mrg // ModuleDeclaration leads off
115 1.1 mrg if (token.value == TOK.module_)
116 1.1 mrg {
117 1.1 mrg const loc = token.loc;
118 1.1 mrg nextToken();
119 1.1 mrg
120 1.1 mrg /* parse ModuleFullyQualifiedName
121 1.1 mrg * https://dlang.org/spec/module.html#ModuleFullyQualifiedName
122 1.1 mrg */
123 1.1 mrg
124 1.1 mrg if (token.value != TOK.identifier)
125 1.1 mrg {
126 1.1 mrg error("identifier expected following `module`");
127 1.1 mrg return false;
128 1.1 mrg }
129 1.1 mrg
130 1.1 mrg Identifier[] a;
131 1.1 mrg Identifier id = token.ident;
132 1.1 mrg
133 1.1 mrg while (nextToken() == TOK.dot)
134 1.1 mrg {
135 1.1 mrg a ~= id;
136 1.1 mrg nextToken();
137 1.1 mrg if (token.value != TOK.identifier)
138 1.1 mrg {
139 1.1 mrg error("identifier expected following `package`");
140 1.1 mrg return false;
141 1.1 mrg }
142 1.1 mrg id = token.ident;
143 1.1 mrg }
144 1.1 mrg
145 1.1 mrg md = new AST.ModuleDeclaration(loc, a, id, msg, isdeprecated);
146 1.1 mrg
147 1.1 mrg if (token.value != TOK.semicolon)
148 1.1 mrg error("`;` expected following module declaration instead of `%s`", token.toChars());
149 1.1 mrg nextToken();
150 1.1 mrg addComment(mod, comment);
151 1.1 mrg }
152 1.1 mrg return true;
153 1.1 mrg }
154 1.1 mrg
155 1.1 mrg /++
156 1.1 mrg + Parse the content of a module, i.e. all declarations found until the end of file.
157 1.1 mrg +
158 1.1 mrg + Returns: the list of declarations or an empty list in case of malformed declarations
159 1.1 mrg +/
160 1.1 mrg final AST.Dsymbols* parseModuleContent()
161 1.1 mrg {
162 1.1 mrg AST.Dsymbol lastDecl = mod;
163 1.1 mrg AST.Dsymbols* decldefs = parseDeclDefs(0, &lastDecl);
164 1.1 mrg
165 1.1 mrg if (token.value == TOK.rightCurly)
166 1.1 mrg {
167 1.1 mrg error(token.loc, "unmatched closing brace");
168 1.1 mrg return errorReturn();
169 1.1 mrg }
170 1.1 mrg
171 1.1 mrg if (token.value != TOK.endOfFile)
172 1.1 mrg {
173 1.1 mrg error(token.loc, "unrecognized declaration");
174 1.1 mrg return errorReturn();
175 1.1 mrg }
176 1.1 mrg return decldefs;
177 1.1 mrg }
178 1.1 mrg
179 1.1 mrg /++
180 1.1 mrg + Skips to the end of the current declaration - denoted by either `;` or EOF
181 1.1 mrg +
182 1.1 mrg + Returns: An empty list of Dsymbols
183 1.1 mrg +/
184 1.1 mrg private AST.Dsymbols* errorReturn()
185 1.1 mrg {
186 1.1 mrg while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
187 1.1 mrg nextToken();
188 1.1 mrg nextToken();
189 1.1 mrg return new AST.Dsymbols();
190 1.1 mrg }
191 1.1 mrg
192 1.1 mrg /**********************************
193 1.1 mrg * Parse the ModuleAttributes preceding a module declaration.
194 1.1 mrg * ModuleDeclaration:
195 1.1 mrg * ModuleAttributes(opt) module ModuleFullyQualifiedName ;
196 1.1 mrg * https://dlang.org/spec/module.html#ModuleAttributes
197 1.1 mrg * Params:
198 1.1 mrg * msg = set to the AssignExpression from DeprecatedAttribute https://dlang.org/spec/module.html#DeprecatedAttribute
199 1.1 mrg * isdeprecated = set to true if a DeprecatedAttribute is seen
200 1.1 mrg */
201 1.1 mrg private
202 1.1 mrg void parseModuleAttributes(out AST.Expression msg, out bool isdeprecated)
203 1.1 mrg {
204 1.1 mrg Token* tk;
205 1.1 mrg if (!(skipAttributes(&token, &tk) && tk.value == TOK.module_))
206 1.1 mrg return; // no module attributes
207 1.1 mrg
208 1.1 mrg AST.Expressions* udas = null;
209 1.1 mrg while (token.value != TOK.module_)
210 1.1 mrg {
211 1.1 mrg switch (token.value)
212 1.1 mrg {
213 1.1 mrg case TOK.deprecated_:
214 1.1 mrg {
215 1.1 mrg // deprecated (...) module ...
216 1.1 mrg if (isdeprecated)
217 1.1 mrg error("there is only one deprecation attribute allowed for module declaration");
218 1.1 mrg isdeprecated = true;
219 1.1 mrg nextToken();
220 1.1 mrg if (token.value == TOK.leftParenthesis)
221 1.1 mrg {
222 1.1 mrg check(TOK.leftParenthesis);
223 1.1 mrg msg = parseAssignExp();
224 1.1 mrg check(TOK.rightParenthesis);
225 1.1 mrg }
226 1.1 mrg break;
227 1.1 mrg }
228 1.1 mrg case TOK.at:
229 1.1 mrg {
230 1.1 mrg AST.Expressions* exps = null;
231 1.1 mrg const stc = parseAttribute(exps);
232 1.1 mrg if (stc & atAttrGroup)
233 1.1 mrg {
234 1.1 mrg error("`@%s` attribute for module declaration is not supported", token.toChars());
235 1.1 mrg }
236 1.1 mrg else
237 1.1 mrg {
238 1.1 mrg udas = AST.UserAttributeDeclaration.concat(udas, exps);
239 1.1 mrg }
240 1.1 mrg if (stc)
241 1.1 mrg nextToken();
242 1.1 mrg break;
243 1.1 mrg }
244 1.1 mrg default:
245 1.1 mrg {
246 1.1 mrg error("`module` expected instead of `%s`", token.toChars());
247 1.1 mrg nextToken();
248 1.1 mrg break;
249 1.1 mrg }
250 1.1 mrg }
251 1.1 mrg }
252 1.1 mrg
253 1.1 mrg if (udas)
254 1.1 mrg {
255 1.1 mrg auto a = new AST.Dsymbols();
256 1.1 mrg auto udad = new AST.UserAttributeDeclaration(udas, a);
257 1.1 mrg mod.userAttribDecl = udad;
258 1.1 mrg }
259 1.1 mrg }
260 1.1 mrg
261 1.1 mrg final:
262 1.1 mrg
263 1.1 mrg /**
264 1.1 mrg * Parses a `deprecated` declaration
265 1.1 mrg *
266 1.1 mrg * Params:
267 1.1 mrg * msg = Deprecated message, if any.
268 1.1 mrg * Used to support overriding a deprecated storage class with
269 1.1 mrg * a deprecated declaration with a message, but to error
270 1.1 mrg * if both declaration have a message.
271 1.1 mrg *
272 1.1 mrg * Returns:
273 1.1 mrg * Whether the deprecated declaration has a message
274 1.1 mrg */
275 1.1 mrg private bool parseDeprecatedAttribute(ref AST.Expression msg)
276 1.1 mrg {
277 1.1 mrg if (peekNext() != TOK.leftParenthesis)
278 1.1 mrg return false;
279 1.1 mrg
280 1.1 mrg nextToken();
281 1.1 mrg check(TOK.leftParenthesis);
282 1.1 mrg AST.Expression e = parseAssignExp();
283 1.1 mrg check(TOK.rightParenthesis);
284 1.1 mrg if (msg)
285 1.1 mrg {
286 1.1 mrg error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars());
287 1.1 mrg }
288 1.1 mrg msg = e;
289 1.1 mrg return true;
290 1.1 mrg }
291 1.1 mrg
292 1.1 mrg AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null)
293 1.1 mrg {
294 1.1 mrg AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration
295 1.1 mrg if (!pLastDecl)
296 1.1 mrg pLastDecl = &lastDecl;
297 1.1 mrg
298 1.1 mrg const linksave = linkage; // save global state
299 1.1 mrg
300 1.1 mrg //printf("Parser::parseDeclDefs()\n");
301 1.1 mrg auto decldefs = new AST.Dsymbols();
302 1.1 mrg do
303 1.1 mrg {
304 1.1 mrg // parse result
305 1.1 mrg AST.Dsymbol s = null;
306 1.1 mrg AST.Dsymbols* a = null;
307 1.1 mrg
308 1.1 mrg PrefixAttributes!AST attrs;
309 1.1 mrg if (!once || !pAttrs)
310 1.1 mrg {
311 1.1 mrg pAttrs = &attrs;
312 1.1 mrg pAttrs.comment = token.blockComment.ptr;
313 1.1 mrg }
314 1.1 mrg AST.Visibility.Kind prot;
315 1.1 mrg StorageClass stc;
316 1.1 mrg AST.Condition condition;
317 1.1 mrg
318 1.1 mrg linkage = linksave;
319 1.1 mrg
320 1.1 mrg Loc startloc;
321 1.1 mrg
322 1.1 mrg switch (token.value)
323 1.1 mrg {
324 1.1 mrg case TOK.enum_:
325 1.1 mrg {
326 1.1 mrg /* Determine if this is a manifest constant declaration,
327 1.1 mrg * or a conventional enum.
328 1.1 mrg */
329 1.1 mrg const tv = peekNext();
330 1.1 mrg if (tv == TOK.leftCurly || tv == TOK.colon)
331 1.1 mrg s = parseEnum();
332 1.1 mrg else if (tv != TOK.identifier)
333 1.1 mrg goto Ldeclaration;
334 1.1 mrg else
335 1.1 mrg {
336 1.1 mrg const nextv = peekNext2();
337 1.1 mrg if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
338 1.1 mrg s = parseEnum();
339 1.1 mrg else
340 1.1 mrg goto Ldeclaration;
341 1.1 mrg }
342 1.1 mrg break;
343 1.1 mrg }
344 1.1 mrg case TOK.import_:
345 1.1 mrg a = parseImport();
346 1.1 mrg // keep pLastDecl
347 1.1 mrg break;
348 1.1 mrg
349 1.1 mrg case TOK.template_:
350 1.1 mrg s = cast(AST.Dsymbol)parseTemplateDeclaration();
351 1.1 mrg break;
352 1.1 mrg
353 1.1 mrg case TOK.mixin_:
354 1.1 mrg {
355 1.1 mrg const loc = token.loc;
356 1.1 mrg switch (peekNext())
357 1.1 mrg {
358 1.1 mrg case TOK.leftParenthesis:
359 1.1 mrg {
360 1.1 mrg // MixinType
361 1.1 mrg if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
362 1.1 mrg goto Ldeclaration;
363 1.1 mrg // mixin(string)
364 1.1 mrg nextToken();
365 1.1 mrg auto exps = parseArguments();
366 1.1 mrg check(TOK.semicolon);
367 1.1 mrg s = new AST.CompileDeclaration(loc, exps);
368 1.1 mrg break;
369 1.1 mrg }
370 1.1 mrg case TOK.template_:
371 1.1 mrg // mixin template
372 1.1 mrg nextToken();
373 1.1 mrg s = cast(AST.Dsymbol)parseTemplateDeclaration(true);
374 1.1 mrg break;
375 1.1 mrg
376 1.1 mrg default:
377 1.1 mrg s = parseMixin();
378 1.1 mrg break;
379 1.1 mrg }
380 1.1 mrg break;
381 1.1 mrg }
382 1.1 mrg case TOK.wchar_:
383 1.1 mrg case TOK.dchar_:
384 1.1 mrg case TOK.bool_:
385 1.1 mrg case TOK.char_:
386 1.1 mrg case TOK.int8:
387 1.1 mrg case TOK.uns8:
388 1.1 mrg case TOK.int16:
389 1.1 mrg case TOK.uns16:
390 1.1 mrg case TOK.int32:
391 1.1 mrg case TOK.uns32:
392 1.1 mrg case TOK.int64:
393 1.1 mrg case TOK.uns64:
394 1.1 mrg case TOK.int128:
395 1.1 mrg case TOK.uns128:
396 1.1 mrg case TOK.float32:
397 1.1 mrg case TOK.float64:
398 1.1 mrg case TOK.float80:
399 1.1 mrg case TOK.imaginary32:
400 1.1 mrg case TOK.imaginary64:
401 1.1 mrg case TOK.imaginary80:
402 1.1 mrg case TOK.complex32:
403 1.1 mrg case TOK.complex64:
404 1.1 mrg case TOK.complex80:
405 1.1 mrg case TOK.void_:
406 1.1 mrg case TOK.alias_:
407 1.1 mrg case TOK.identifier:
408 1.1 mrg case TOK.super_:
409 1.1 mrg case TOK.typeof_:
410 1.1 mrg case TOK.dot:
411 1.1 mrg case TOK.vector:
412 1.1 mrg case TOK.struct_:
413 1.1 mrg case TOK.union_:
414 1.1 mrg case TOK.class_:
415 1.1 mrg case TOK.interface_:
416 1.1 mrg case TOK.traits:
417 1.1 mrg Ldeclaration:
418 1.1 mrg a = parseDeclarations(false, pAttrs, pAttrs.comment);
419 1.1 mrg if (a && a.dim)
420 1.1 mrg *pLastDecl = (*a)[a.dim - 1];
421 1.1 mrg break;
422 1.1 mrg
423 1.1 mrg case TOK.this_:
424 1.1 mrg if (peekNext() == TOK.dot)
425 1.1 mrg goto Ldeclaration;
426 1.1 mrg s = parseCtor(pAttrs);
427 1.1 mrg break;
428 1.1 mrg
429 1.1 mrg case TOK.tilde:
430 1.1 mrg s = parseDtor(pAttrs);
431 1.1 mrg break;
432 1.1 mrg
433 1.1 mrg case TOK.invariant_:
434 1.1 mrg const tv = peekNext();
435 1.1 mrg if (tv == TOK.leftParenthesis || tv == TOK.leftCurly)
436 1.1 mrg {
437 1.1 mrg // invariant { statements... }
438 1.1 mrg // invariant() { statements... }
439 1.1 mrg // invariant (expression);
440 1.1 mrg s = parseInvariant(pAttrs);
441 1.1 mrg break;
442 1.1 mrg }
443 1.1 mrg error("invariant body expected, not `%s`", token.toChars());
444 1.1 mrg goto Lerror;
445 1.1 mrg
446 1.1 mrg case TOK.unittest_:
447 1.1 mrg /**
448 1.1 mrg * Ignore unittests in non-root modules.
449 1.1 mrg *
450 1.1 mrg * This mainly means that unittests *inside templates* are only
451 1.1 mrg * ever instantiated if the module lexically declaring the
452 1.1 mrg * template is one of the root modules.
453 1.1 mrg *
454 1.1 mrg * E.g., compiling some project with `-unittest` does NOT
455 1.1 mrg * compile and later run any unittests in instantiations of
456 1.1 mrg * templates declared in other libraries.
457 1.1 mrg *
458 1.1 mrg * Declaring unittests *inside* templates is considered an anti-
459 1.1 mrg * pattern. In almost all cases, the unittests don't depend on
460 1.1 mrg * the template parameters, but instantiate the template with
461 1.1 mrg * fixed arguments (e.g., Nullable!T unittests instantiating
462 1.1 mrg * Nullable!int), so compiling and running identical tests for
463 1.1 mrg * each template instantiation is hardly desirable.
464 1.1 mrg * But adding a unittest right below some function being tested
465 1.1 mrg * is arguably good for locality, so unittests end up inside
466 1.1 mrg * templates.
467 1.1 mrg * To make sure a template's unittests are run, it should be
468 1.1 mrg * instantiated in the same module, e.g., some module-level
469 1.1 mrg * unittest.
470 1.1 mrg *
471 1.1 mrg * Another reason for ignoring unittests in templates from non-
472 1.1 mrg * root modules is for template codegen culling via
473 1.1 mrg * TemplateInstance.needsCodegen(). If the compiler decides not
474 1.1 mrg * to emit some Nullable!bool because there's an existing
475 1.1 mrg * instantiation in some non-root module, it has no idea whether
476 1.1 mrg * that module was compiled with -unittest too, and so whether
477 1.1 mrg * Nullable!int (instantiated in some unittest inside the
478 1.1 mrg * Nullable template) can be culled too. By ignoring unittests
479 1.1 mrg * in non-root modules, the compiler won't consider any
480 1.1 mrg * template instantiations in these unittests as candidates for
481 1.1 mrg * further codegen culling.
482 1.1 mrg */
483 1.1 mrg if (mod.isRoot() && (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration))
484 1.1 mrg {
485 1.1 mrg s = parseUnitTest(pAttrs);
486 1.1 mrg if (*pLastDecl)
487 1.1 mrg (*pLastDecl).ddocUnittest = cast(AST.UnitTestDeclaration)s;
488 1.1 mrg }
489 1.1 mrg else
490 1.1 mrg {
491 1.1 mrg // Skip over unittest block by counting { }
492 1.1 mrg Loc loc = token.loc;
493 1.1 mrg int braces = 0;
494 1.1 mrg while (1)
495 1.1 mrg {
496 1.1 mrg nextToken();
497 1.1 mrg switch (token.value)
498 1.1 mrg {
499 1.1 mrg case TOK.leftCurly:
500 1.1 mrg ++braces;
501 1.1 mrg continue;
502 1.1 mrg
503 1.1 mrg case TOK.rightCurly:
504 1.1 mrg if (--braces)
505 1.1 mrg continue;
506 1.1 mrg nextToken();
507 1.1 mrg break;
508 1.1 mrg
509 1.1 mrg case TOK.endOfFile:
510 1.1 mrg /* { */
511 1.1 mrg error(loc, "closing `}` of unittest not found before end of file");
512 1.1 mrg goto Lerror;
513 1.1 mrg
514 1.1 mrg default:
515 1.1 mrg continue;
516 1.1 mrg }
517 1.1 mrg break;
518 1.1 mrg }
519 1.1 mrg // Workaround 14894. Add an empty unittest declaration to keep
520 1.1 mrg // the number of symbols in this scope independent of -unittest.
521 1.1 mrg s = new AST.UnitTestDeclaration(loc, token.loc, STC.undefined_, null);
522 1.1 mrg }
523 1.1 mrg break;
524 1.1 mrg
525 1.1 mrg case TOK.new_:
526 1.1 mrg s = parseNew(pAttrs);
527 1.1 mrg break;
528 1.1 mrg
529 1.1 mrg case TOK.colon:
530 1.1 mrg case TOK.leftCurly:
531 1.1 mrg error("declaration expected, not `%s`", token.toChars());
532 1.1 mrg goto Lerror;
533 1.1 mrg
534 1.1 mrg case TOK.rightCurly:
535 1.1 mrg case TOK.endOfFile:
536 1.1 mrg if (once)
537 1.1 mrg error("declaration expected, not `%s`", token.toChars());
538 1.1 mrg return decldefs;
539 1.1 mrg
540 1.1 mrg case TOK.static_:
541 1.1 mrg {
542 1.1 mrg const next = peekNext();
543 1.1 mrg if (next == TOK.this_)
544 1.1 mrg s = parseStaticCtor(pAttrs);
545 1.1 mrg else if (next == TOK.tilde)
546 1.1 mrg s = parseStaticDtor(pAttrs);
547 1.1 mrg else if (next == TOK.assert_)
548 1.1 mrg s = parseStaticAssert();
549 1.1 mrg else if (next == TOK.if_)
550 1.1 mrg {
551 1.1 mrg const Loc loc = token.loc;
552 1.1 mrg condition = parseStaticIfCondition();
553 1.1 mrg AST.Dsymbols* athen;
554 1.1 mrg if (token.value == TOK.colon)
555 1.1 mrg athen = parseBlock(pLastDecl);
556 1.1 mrg else
557 1.1 mrg {
558 1.1 mrg const lookingForElseSave = lookingForElse;
559 1.1 mrg lookingForElse = token.loc;
560 1.1 mrg athen = parseBlock(pLastDecl);
561 1.1 mrg lookingForElse = lookingForElseSave;
562 1.1 mrg }
563 1.1 mrg AST.Dsymbols* aelse = null;
564 1.1 mrg if (token.value == TOK.else_)
565 1.1 mrg {
566 1.1 mrg const elseloc = token.loc;
567 1.1 mrg nextToken();
568 1.1 mrg aelse = parseBlock(pLastDecl);
569 1.1 mrg checkDanglingElse(elseloc);
570 1.1 mrg }
571 1.1 mrg s = new AST.StaticIfDeclaration(loc, condition, athen, aelse);
572 1.1 mrg }
573 1.1 mrg else if (next == TOK.import_)
574 1.1 mrg {
575 1.1 mrg a = parseImport();
576 1.1 mrg // keep pLastDecl
577 1.1 mrg }
578 1.1 mrg else if (next == TOK.foreach_ || next == TOK.foreach_reverse_)
579 1.1 mrg {
580 1.1 mrg s = parseForeach!(AST.StaticForeachDeclaration)(token.loc, pLastDecl);
581 1.1 mrg }
582 1.1 mrg else
583 1.1 mrg {
584 1.1 mrg stc = STC.static_;
585 1.1 mrg goto Lstc;
586 1.1 mrg }
587 1.1 mrg break;
588 1.1 mrg }
589 1.1 mrg case TOK.const_:
590 1.1 mrg if (peekNext() == TOK.leftParenthesis)
591 1.1 mrg goto Ldeclaration;
592 1.1 mrg stc = STC.const_;
593 1.1 mrg goto Lstc;
594 1.1 mrg
595 1.1 mrg case TOK.immutable_:
596 1.1 mrg if (peekNext() == TOK.leftParenthesis)
597 1.1 mrg goto Ldeclaration;
598 1.1 mrg stc = STC.immutable_;
599 1.1 mrg goto Lstc;
600 1.1 mrg
601 1.1 mrg case TOK.shared_:
602 1.1 mrg {
603 1.1 mrg const next = peekNext();
604 1.1 mrg if (next == TOK.leftParenthesis)
605 1.1 mrg goto Ldeclaration;
606 1.1 mrg if (next == TOK.static_)
607 1.1 mrg {
608 1.1 mrg TOK next2 = peekNext2();
609 1.1 mrg if (next2 == TOK.this_)
610 1.1 mrg {
611 1.1 mrg s = parseSharedStaticCtor(pAttrs);
612 1.1 mrg break;
613 1.1 mrg }
614 1.1 mrg if (next2 == TOK.tilde)
615 1.1 mrg {
616 1.1 mrg s = parseSharedStaticDtor(pAttrs);
617 1.1 mrg break;
618 1.1 mrg }
619 1.1 mrg }
620 1.1 mrg stc = STC.shared_;
621 1.1 mrg goto Lstc;
622 1.1 mrg }
623 1.1 mrg case TOK.inout_:
624 1.1 mrg if (peekNext() == TOK.leftParenthesis)
625 1.1 mrg goto Ldeclaration;
626 1.1 mrg stc = STC.wild;
627 1.1 mrg goto Lstc;
628 1.1 mrg
629 1.1 mrg case TOK.final_:
630 1.1 mrg stc = STC.final_;
631 1.1 mrg goto Lstc;
632 1.1 mrg
633 1.1 mrg case TOK.auto_:
634 1.1 mrg stc = STC.auto_;
635 1.1 mrg goto Lstc;
636 1.1 mrg
637 1.1 mrg case TOK.scope_:
638 1.1 mrg stc = STC.scope_;
639 1.1 mrg goto Lstc;
640 1.1 mrg
641 1.1 mrg case TOK.override_:
642 1.1 mrg stc = STC.override_;
643 1.1 mrg goto Lstc;
644 1.1 mrg
645 1.1 mrg case TOK.abstract_:
646 1.1 mrg stc = STC.abstract_;
647 1.1 mrg goto Lstc;
648 1.1 mrg
649 1.1 mrg case TOK.synchronized_:
650 1.1 mrg stc = STC.synchronized_;
651 1.1 mrg goto Lstc;
652 1.1 mrg
653 1.1 mrg case TOK.nothrow_:
654 1.1 mrg stc = STC.nothrow_;
655 1.1 mrg goto Lstc;
656 1.1 mrg
657 1.1 mrg case TOK.pure_:
658 1.1 mrg stc = STC.pure_;
659 1.1 mrg goto Lstc;
660 1.1 mrg
661 1.1 mrg case TOK.ref_:
662 1.1 mrg stc = STC.ref_;
663 1.1 mrg goto Lstc;
664 1.1 mrg
665 1.1 mrg case TOK.gshared:
666 1.1 mrg stc = STC.gshared;
667 1.1 mrg goto Lstc;
668 1.1 mrg
669 1.1 mrg case TOK.at:
670 1.1 mrg {
671 1.1 mrg AST.Expressions* exps = null;
672 1.1 mrg stc = parseAttribute(exps);
673 1.1 mrg if (stc)
674 1.1 mrg goto Lstc; // it's a predefined attribute
675 1.1 mrg // no redundant/conflicting check for UDAs
676 1.1 mrg pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps);
677 1.1 mrg goto Lautodecl;
678 1.1 mrg }
679 1.1 mrg Lstc:
680 1.1 mrg pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc);
681 1.1 mrg nextToken();
682 1.1 mrg
683 1.1 mrg Lautodecl:
684 1.1 mrg
685 1.1 mrg /* Look for auto initializers:
686 1.1 mrg * storage_class identifier = initializer;
687 1.1 mrg * storage_class identifier(...) = initializer;
688 1.1 mrg */
689 1.1 mrg if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
690 1.1 mrg {
691 1.1 mrg a = parseAutoDeclarations(getStorageClass!AST(pAttrs), pAttrs.comment);
692 1.1 mrg if (a && a.dim)
693 1.1 mrg *pLastDecl = (*a)[a.dim - 1];
694 1.1 mrg if (pAttrs.udas)
695 1.1 mrg {
696 1.1 mrg s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
697 1.1 mrg pAttrs.udas = null;
698 1.1 mrg }
699 1.1 mrg break;
700 1.1 mrg }
701 1.1 mrg
702 1.1 mrg /* Look for return type inference for template functions.
703 1.1 mrg */
704 1.1 mrg Token* tk;
705 1.1 mrg if (token.value == TOK.identifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
706 1.1 mrg (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ ||
707 1.1 mrg tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo ||
708 1.1 mrg tk.value == TOK.identifier && tk.ident == Id._body))
709 1.1 mrg {
710 1.1 mrg // @@@DEPRECATED_2.117@@@
711 1.1 mrg // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
712 1.1 mrg // Deprecated in 2.097 - Can be removed from 2.117
713 1.1 mrg // The deprecation period is longer than usual as `body`
714 1.1 mrg // was quite widely used.
715 1.1 mrg if (tk.value == TOK.identifier && tk.ident == Id._body)
716 1.1 mrg deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
717 1.1 mrg
718 1.1 mrg a = parseDeclarations(true, pAttrs, pAttrs.comment);
719 1.1 mrg if (a && a.dim)
720 1.1 mrg *pLastDecl = (*a)[a.dim - 1];
721 1.1 mrg if (pAttrs.udas)
722 1.1 mrg {
723 1.1 mrg s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
724 1.1 mrg pAttrs.udas = null;
725 1.1 mrg }
726 1.1 mrg break;
727 1.1 mrg }
728 1.1 mrg
729 1.1 mrg a = parseBlock(pLastDecl, pAttrs);
730 1.1 mrg auto stc2 = getStorageClass!AST(pAttrs);
731 1.1 mrg if (stc2 != STC.undefined_)
732 1.1 mrg {
733 1.1 mrg s = new AST.StorageClassDeclaration(stc2, a);
734 1.1 mrg }
735 1.1 mrg if (pAttrs.udas)
736 1.1 mrg {
737 1.1 mrg if (s)
738 1.1 mrg {
739 1.1 mrg a = new AST.Dsymbols();
740 1.1 mrg a.push(s);
741 1.1 mrg }
742 1.1 mrg s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
743 1.1 mrg pAttrs.udas = null;
744 1.1 mrg }
745 1.1 mrg break;
746 1.1 mrg
747 1.1 mrg case TOK.deprecated_:
748 1.1 mrg {
749 1.1 mrg stc |= STC.deprecated_;
750 1.1 mrg if (!parseDeprecatedAttribute(pAttrs.depmsg))
751 1.1 mrg goto Lstc;
752 1.1 mrg
753 1.1 mrg a = parseBlock(pLastDecl, pAttrs);
754 1.1 mrg s = new AST.DeprecatedDeclaration(pAttrs.depmsg, a);
755 1.1 mrg pAttrs.depmsg = null;
756 1.1 mrg break;
757 1.1 mrg }
758 1.1 mrg case TOK.leftBracket:
759 1.1 mrg {
760 1.1 mrg if (peekNext() == TOK.rightBracket)
761 1.1 mrg error("empty attribute list is not allowed");
762 1.1 mrg error("use `@(attributes)` instead of `[attributes]`");
763 1.1 mrg AST.Expressions* exps = parseArguments();
764 1.1 mrg // no redundant/conflicting check for UDAs
765 1.1 mrg
766 1.1 mrg pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps);
767 1.1 mrg a = parseBlock(pLastDecl, pAttrs);
768 1.1 mrg if (pAttrs.udas)
769 1.1 mrg {
770 1.1 mrg s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
771 1.1 mrg pAttrs.udas = null;
772 1.1 mrg }
773 1.1 mrg break;
774 1.1 mrg }
775 1.1 mrg case TOK.extern_:
776 1.1 mrg {
777 1.1 mrg if (peekNext() != TOK.leftParenthesis)
778 1.1 mrg {
779 1.1 mrg stc = STC.extern_;
780 1.1 mrg goto Lstc;
781 1.1 mrg }
782 1.1 mrg
783 1.1 mrg const linkLoc = token.loc;
784 1.1 mrg auto res = parseLinkage();
785 1.1 mrg if (pAttrs.link != LINK.default_)
786 1.1 mrg {
787 1.1 mrg if (pAttrs.link != res.link)
788 1.1 mrg {
789 1.1 mrg error("conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link));
790 1.1 mrg }
791 1.1 mrg else if (res.idents || res.identExps || res.cppmangle != CPPMANGLE.def)
792 1.1 mrg {
793 1.1 mrg // Allow:
794 1.1 mrg // extern(C++, foo) extern(C++, bar) void foo();
795 1.1 mrg // to be equivalent with:
796 1.1 mrg // extern(C++, foo.bar) void foo();
797 1.1 mrg // Allow also:
798 1.1 mrg // extern(C++, "ns") extern(C++, class) struct test {}
799 1.1 mrg // extern(C++, class) extern(C++, "ns") struct test {}
800 1.1 mrg }
801 1.1 mrg else
802 1.1 mrg error("redundant linkage `extern (%s)`", AST.linkageToChars(pAttrs.link));
803 1.1 mrg }
804 1.1 mrg pAttrs.link = res.link;
805 1.1 mrg this.linkage = res.link;
806 1.1 mrg this.linkLoc = linkLoc;
807 1.1 mrg a = parseBlock(pLastDecl, pAttrs);
808 1.1 mrg if (res.idents)
809 1.1 mrg {
810 1.1 mrg assert(res.link == LINK.cpp);
811 1.1 mrg assert(res.idents.dim);
812 1.1 mrg for (size_t i = res.idents.dim; i;)
813 1.1 mrg {
814 1.1 mrg Identifier id = (*res.idents)[--i];
815 1.1 mrg if (s)
816 1.1 mrg {
817 1.1 mrg a = new AST.Dsymbols();
818 1.1 mrg a.push(s);
819 1.1 mrg }
820 1.1 mrg s = new AST.Nspace(linkLoc, id, null, a);
821 1.1 mrg }
822 1.1 mrg pAttrs.link = LINK.default_;
823 1.1 mrg }
824 1.1 mrg else if (res.identExps)
825 1.1 mrg {
826 1.1 mrg assert(res.link == LINK.cpp);
827 1.1 mrg assert(res.identExps.dim);
828 1.1 mrg for (size_t i = res.identExps.dim; i;)
829 1.1 mrg {
830 1.1 mrg AST.Expression exp = (*res.identExps)[--i];
831 1.1 mrg if (s)
832 1.1 mrg {
833 1.1 mrg a = new AST.Dsymbols();
834 1.1 mrg a.push(s);
835 1.1 mrg }
836 1.1 mrg s = new AST.CPPNamespaceDeclaration(linkLoc, exp, a);
837 1.1 mrg }
838 1.1 mrg pAttrs.link = LINK.default_;
839 1.1 mrg }
840 1.1 mrg else if (res.cppmangle != CPPMANGLE.def)
841 1.1 mrg {
842 1.1 mrg assert(res.link == LINK.cpp);
843 1.1 mrg s = new AST.CPPMangleDeclaration(linkLoc, res.cppmangle, a);
844 1.1 mrg }
845 1.1 mrg else if (pAttrs.link != LINK.default_)
846 1.1 mrg {
847 1.1 mrg s = new AST.LinkDeclaration(linkLoc, pAttrs.link, a);
848 1.1 mrg pAttrs.link = LINK.default_;
849 1.1 mrg }
850 1.1 mrg break;
851 1.1 mrg }
852 1.1 mrg
853 1.1 mrg case TOK.private_:
854 1.1 mrg prot = AST.Visibility.Kind.private_;
855 1.1 mrg goto Lprot;
856 1.1 mrg
857 1.1 mrg case TOK.package_:
858 1.1 mrg prot = AST.Visibility.Kind.package_;
859 1.1 mrg goto Lprot;
860 1.1 mrg
861 1.1 mrg case TOK.protected_:
862 1.1 mrg prot = AST.Visibility.Kind.protected_;
863 1.1 mrg goto Lprot;
864 1.1 mrg
865 1.1 mrg case TOK.public_:
866 1.1 mrg prot = AST.Visibility.Kind.public_;
867 1.1 mrg goto Lprot;
868 1.1 mrg
869 1.1 mrg case TOK.export_:
870 1.1 mrg prot = AST.Visibility.Kind.export_;
871 1.1 mrg goto Lprot;
872 1.1 mrg Lprot:
873 1.1 mrg {
874 1.1 mrg if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
875 1.1 mrg {
876 1.1 mrg if (pAttrs.visibility.kind != prot)
877 1.1 mrg error("conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot));
878 1.1 mrg else
879 1.1 mrg error("redundant visibility attribute `%s`", AST.visibilityToChars(prot));
880 1.1 mrg }
881 1.1 mrg pAttrs.visibility.kind = prot;
882 1.1 mrg
883 1.1 mrg nextToken();
884 1.1 mrg
885 1.1 mrg // optional qualified package identifier to bind
886 1.1 mrg // visibility to
887 1.1 mrg Identifier[] pkg_prot_idents;
888 1.1 mrg if (pAttrs.visibility.kind == AST.Visibility.Kind.package_ && token.value == TOK.leftParenthesis)
889 1.1 mrg {
890 1.1 mrg pkg_prot_idents = parseQualifiedIdentifier("protection package");
891 1.1 mrg if (pkg_prot_idents)
892 1.1 mrg check(TOK.rightParenthesis);
893 1.1 mrg else
894 1.1 mrg {
895 1.1 mrg while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
896 1.1 mrg nextToken();
897 1.1 mrg nextToken();
898 1.1 mrg break;
899 1.1 mrg }
900 1.1 mrg }
901 1.1 mrg
902 1.1 mrg const attrloc = token.loc;
903 1.1 mrg a = parseBlock(pLastDecl, pAttrs);
904 1.1 mrg if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
905 1.1 mrg {
906 1.1 mrg if (pAttrs.visibility.kind == AST.Visibility.Kind.package_ && pkg_prot_idents)
907 1.1 mrg s = new AST.VisibilityDeclaration(attrloc, pkg_prot_idents, a);
908 1.1 mrg else
909 1.1 mrg s = new AST.VisibilityDeclaration(attrloc, pAttrs.visibility, a);
910 1.1 mrg
911 1.1 mrg pAttrs.visibility = AST.Visibility(AST.Visibility.Kind.undefined);
912 1.1 mrg }
913 1.1 mrg break;
914 1.1 mrg }
915 1.1 mrg case TOK.align_:
916 1.1 mrg {
917 1.1 mrg const attrLoc = token.loc;
918 1.1 mrg
919 1.1 mrg nextToken();
920 1.1 mrg
921 1.1 mrg AST.Expression e = null; // default
922 1.1 mrg if (token.value == TOK.leftParenthesis)
923 1.1 mrg {
924 1.1 mrg nextToken();
925 1.1 mrg e = parseAssignExp();
926 1.1 mrg check(TOK.rightParenthesis);
927 1.1 mrg }
928 1.1 mrg
929 1.1 mrg if (pAttrs.setAlignment)
930 1.1 mrg {
931 1.1 mrg if (e)
932 1.1 mrg error("redundant alignment attribute `align(%s)`", e.toChars());
933 1.1 mrg else
934 1.1 mrg error("redundant alignment attribute `align`");
935 1.1 mrg }
936 1.1 mrg
937 1.1 mrg pAttrs.setAlignment = true;
938 1.1 mrg pAttrs.ealign = e;
939 1.1 mrg a = parseBlock(pLastDecl, pAttrs);
940 1.1 mrg if (pAttrs.setAlignment)
941 1.1 mrg {
942 1.1 mrg s = new AST.AlignDeclaration(attrLoc, pAttrs.ealign, a);
943 1.1 mrg pAttrs.setAlignment = false;
944 1.1 mrg pAttrs.ealign = null;
945 1.1 mrg }
946 1.1 mrg break;
947 1.1 mrg }
948 1.1 mrg case TOK.pragma_:
949 1.1 mrg {
950 1.1 mrg AST.Expressions* args = null;
951 1.1 mrg const loc = token.loc;
952 1.1 mrg
953 1.1 mrg nextToken();
954 1.1 mrg check(TOK.leftParenthesis);
955 1.1 mrg if (token.value != TOK.identifier)
956 1.1 mrg {
957 1.1 mrg error("`pragma(identifier)` expected");
958 1.1 mrg goto Lerror;
959 1.1 mrg }
960 1.1 mrg Identifier ident = token.ident;
961 1.1 mrg nextToken();
962 1.1 mrg if (token.value == TOK.comma && peekNext() != TOK.rightParenthesis)
963 1.1 mrg args = parseArguments(); // pragma(identifier, args...)
964 1.1 mrg else
965 1.1 mrg check(TOK.rightParenthesis); // pragma(identifier)
966 1.1 mrg
967 1.1 mrg AST.Dsymbols* a2 = null;
968 1.1 mrg if (token.value == TOK.semicolon)
969 1.1 mrg {
970 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=2354
971 1.1 mrg * Accept single semicolon as an empty
972 1.1 mrg * DeclarationBlock following attribute.
973 1.1 mrg *
974 1.1 mrg * Attribute DeclarationBlock
975 1.1 mrg * Pragma DeclDef
976 1.1 mrg * ;
977 1.1 mrg */
978 1.1 mrg nextToken();
979 1.1 mrg }
980 1.1 mrg else
981 1.1 mrg a2 = parseBlock(pLastDecl);
982 1.1 mrg s = new AST.PragmaDeclaration(loc, ident, args, a2);
983 1.1 mrg break;
984 1.1 mrg }
985 1.1 mrg case TOK.debug_:
986 1.1 mrg startloc = token.loc;
987 1.1 mrg nextToken();
988 1.1 mrg if (token.value == TOK.assign)
989 1.1 mrg {
990 1.1 mrg s = parseDebugSpecification();
991 1.1 mrg break;
992 1.1 mrg }
993 1.1 mrg condition = parseDebugCondition();
994 1.1 mrg goto Lcondition;
995 1.1 mrg
996 1.1 mrg case TOK.version_:
997 1.1 mrg startloc = token.loc;
998 1.1 mrg nextToken();
999 1.1 mrg if (token.value == TOK.assign)
1000 1.1 mrg {
1001 1.1 mrg s = parseVersionSpecification();
1002 1.1 mrg break;
1003 1.1 mrg }
1004 1.1 mrg condition = parseVersionCondition();
1005 1.1 mrg goto Lcondition;
1006 1.1 mrg
1007 1.1 mrg Lcondition:
1008 1.1 mrg {
1009 1.1 mrg AST.Dsymbols* athen;
1010 1.1 mrg if (token.value == TOK.colon)
1011 1.1 mrg athen = parseBlock(pLastDecl);
1012 1.1 mrg else
1013 1.1 mrg {
1014 1.1 mrg const lookingForElseSave = lookingForElse;
1015 1.1 mrg lookingForElse = token.loc;
1016 1.1 mrg athen = parseBlock(pLastDecl);
1017 1.1 mrg lookingForElse = lookingForElseSave;
1018 1.1 mrg }
1019 1.1 mrg AST.Dsymbols* aelse = null;
1020 1.1 mrg if (token.value == TOK.else_)
1021 1.1 mrg {
1022 1.1 mrg const elseloc = token.loc;
1023 1.1 mrg nextToken();
1024 1.1 mrg aelse = parseBlock(pLastDecl);
1025 1.1 mrg checkDanglingElse(elseloc);
1026 1.1 mrg }
1027 1.1 mrg s = new AST.ConditionalDeclaration(startloc, condition, athen, aelse);
1028 1.1 mrg break;
1029 1.1 mrg }
1030 1.1 mrg case TOK.semicolon:
1031 1.1 mrg // empty declaration
1032 1.1 mrg //error("empty declaration");
1033 1.1 mrg nextToken();
1034 1.1 mrg continue;
1035 1.1 mrg
1036 1.1 mrg default:
1037 1.1 mrg error("declaration expected, not `%s`", token.toChars());
1038 1.1 mrg Lerror:
1039 1.1 mrg while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
1040 1.1 mrg nextToken();
1041 1.1 mrg nextToken();
1042 1.1 mrg s = null;
1043 1.1 mrg continue;
1044 1.1 mrg }
1045 1.1 mrg
1046 1.1 mrg if (s)
1047 1.1 mrg {
1048 1.1 mrg if (!s.isAttribDeclaration())
1049 1.1 mrg *pLastDecl = s;
1050 1.1 mrg decldefs.push(s);
1051 1.1 mrg addComment(s, pAttrs.comment);
1052 1.1 mrg }
1053 1.1 mrg else if (a && a.dim)
1054 1.1 mrg {
1055 1.1 mrg decldefs.append(a);
1056 1.1 mrg }
1057 1.1 mrg }
1058 1.1 mrg while (!once);
1059 1.1 mrg
1060 1.1 mrg linkage = linksave;
1061 1.1 mrg
1062 1.1 mrg return decldefs;
1063 1.1 mrg }
1064 1.1 mrg
1065 1.1 mrg /*****************************************
1066 1.1 mrg * Parse auto declarations of the form:
1067 1.1 mrg * storageClass ident = init, ident = init, ... ;
1068 1.1 mrg * and return the array of them.
1069 1.1 mrg * Starts with token on the first ident.
1070 1.1 mrg * Ends with scanner past closing ';'
1071 1.1 mrg */
1072 1.1 mrg private AST.Dsymbols* parseAutoDeclarations(StorageClass storageClass, const(char)* comment)
1073 1.1 mrg {
1074 1.1 mrg //printf("parseAutoDeclarations\n");
1075 1.1 mrg auto a = new AST.Dsymbols();
1076 1.1 mrg
1077 1.1 mrg while (1)
1078 1.1 mrg {
1079 1.1 mrg const loc = token.loc;
1080 1.1 mrg Identifier ident = token.ident;
1081 1.1 mrg nextToken(); // skip over ident
1082 1.1 mrg
1083 1.1 mrg AST.TemplateParameters* tpl = null;
1084 1.1 mrg if (token.value == TOK.leftParenthesis)
1085 1.1 mrg tpl = parseTemplateParameterList();
1086 1.1 mrg
1087 1.1 mrg check(TOK.assign); // skip over '='
1088 1.1 mrg AST.Initializer _init = parseInitializer();
1089 1.1 mrg auto v = new AST.VarDeclaration(loc, null, ident, _init, storageClass);
1090 1.1 mrg
1091 1.1 mrg AST.Dsymbol s = v;
1092 1.1 mrg if (tpl)
1093 1.1 mrg {
1094 1.1 mrg auto a2 = new AST.Dsymbols();
1095 1.1 mrg a2.push(v);
1096 1.1 mrg auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0);
1097 1.1 mrg s = tempdecl;
1098 1.1 mrg }
1099 1.1 mrg a.push(s);
1100 1.1 mrg switch (token.value)
1101 1.1 mrg {
1102 1.1 mrg case TOK.semicolon:
1103 1.1 mrg nextToken();
1104 1.1 mrg addComment(s, comment);
1105 1.1 mrg break;
1106 1.1 mrg
1107 1.1 mrg case TOK.comma:
1108 1.1 mrg nextToken();
1109 1.1 mrg if (!(token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign)))
1110 1.1 mrg {
1111 1.1 mrg error("identifier expected following comma");
1112 1.1 mrg break;
1113 1.1 mrg }
1114 1.1 mrg addComment(s, comment);
1115 1.1 mrg continue;
1116 1.1 mrg
1117 1.1 mrg default:
1118 1.1 mrg error("semicolon expected following auto declaration, not `%s`", token.toChars());
1119 1.1 mrg break;
1120 1.1 mrg }
1121 1.1 mrg break;
1122 1.1 mrg }
1123 1.1 mrg return a;
1124 1.1 mrg }
1125 1.1 mrg
1126 1.1 mrg /********************************************
1127 1.1 mrg * Parse declarations after an align, visibility, or extern decl.
1128 1.1 mrg */
1129 1.1 mrg private AST.Dsymbols* parseBlock(AST.Dsymbol* pLastDecl, PrefixAttributes!AST* pAttrs = null)
1130 1.1 mrg {
1131 1.1 mrg AST.Dsymbols* a = null;
1132 1.1 mrg
1133 1.1 mrg //printf("parseBlock()\n");
1134 1.1 mrg switch (token.value)
1135 1.1 mrg {
1136 1.1 mrg case TOK.semicolon:
1137 1.1 mrg error("declaration expected following attribute, not `;`");
1138 1.1 mrg nextToken();
1139 1.1 mrg break;
1140 1.1 mrg
1141 1.1 mrg case TOK.endOfFile:
1142 1.1 mrg error("declaration expected following attribute, not end of file");
1143 1.1 mrg break;
1144 1.1 mrg
1145 1.1 mrg case TOK.leftCurly:
1146 1.1 mrg {
1147 1.1 mrg const lookingForElseSave = lookingForElse;
1148 1.1 mrg lookingForElse = Loc();
1149 1.1 mrg
1150 1.1 mrg nextToken();
1151 1.1 mrg a = parseDeclDefs(0, pLastDecl);
1152 1.1 mrg if (token.value != TOK.rightCurly)
1153 1.1 mrg {
1154 1.1 mrg /* { */
1155 1.1 mrg error("matching `}` expected, not `%s`", token.toChars());
1156 1.1 mrg }
1157 1.1 mrg else
1158 1.1 mrg nextToken();
1159 1.1 mrg lookingForElse = lookingForElseSave;
1160 1.1 mrg break;
1161 1.1 mrg }
1162 1.1 mrg case TOK.colon:
1163 1.1 mrg nextToken();
1164 1.1 mrg a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
1165 1.1 mrg break;
1166 1.1 mrg
1167 1.1 mrg default:
1168 1.1 mrg a = parseDeclDefs(1, pLastDecl, pAttrs);
1169 1.1 mrg break;
1170 1.1 mrg }
1171 1.1 mrg return a;
1172 1.1 mrg }
1173 1.1 mrg
1174 1.1 mrg /**
1175 1.1 mrg * Provide an error message if `added` contains storage classes which are
1176 1.1 mrg * redundant with those in `orig`; otherwise, return the combination.
1177 1.1 mrg *
1178 1.1 mrg * Params:
1179 1.1 mrg * orig = The already applied storage class.
1180 1.1 mrg * added = The new storage class to add to `orig`.
1181 1.1 mrg *
1182 1.1 mrg * Returns:
1183 1.1 mrg * The combination of both storage classes (`orig | added`).
1184 1.1 mrg */
1185 1.1 mrg private StorageClass appendStorageClass(StorageClass orig, StorageClass added)
1186 1.1 mrg {
1187 1.1 mrg void checkConflictSTCGroup(bool at = false)(StorageClass group)
1188 1.1 mrg {
1189 1.1 mrg if (added & group && orig & group & ((orig & group) - 1))
1190 1.1 mrg error(
1191 1.1 mrg at ? "conflicting attribute `@%s`"
1192 1.1 mrg : "conflicting attribute `%s`",
1193 1.1 mrg token.toChars());
1194 1.1 mrg }
1195 1.1 mrg
1196 1.1 mrg if (orig & added)
1197 1.1 mrg {
1198 1.1 mrg OutBuffer buf;
1199 1.1 mrg AST.stcToBuffer(&buf, added);
1200 1.1 mrg error("redundant attribute `%s`", buf.peekChars());
1201 1.1 mrg return orig | added;
1202 1.1 mrg }
1203 1.1 mrg
1204 1.1 mrg const Redundant = (STC.const_ | STC.scope_ |
1205 1.1 mrg (global.params.previewIn ? STC.ref_ : 0));
1206 1.1 mrg orig |= added;
1207 1.1 mrg
1208 1.1 mrg if ((orig & STC.in_) && (added & Redundant))
1209 1.1 mrg {
1210 1.1 mrg if (added & STC.const_)
1211 1.1 mrg error("attribute `const` is redundant with previously-applied `in`");
1212 1.1 mrg else if (global.params.previewIn)
1213 1.1 mrg {
1214 1.1 mrg error("attribute `%s` is redundant with previously-applied `in`",
1215 1.1 mrg (orig & STC.scope_) ? "scope".ptr : "ref".ptr);
1216 1.1 mrg }
1217 1.1 mrg else
1218 1.1 mrg error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
1219 1.1 mrg return orig;
1220 1.1 mrg }
1221 1.1 mrg
1222 1.1 mrg if ((added & STC.in_) && (orig & Redundant))
1223 1.1 mrg {
1224 1.1 mrg if (orig & STC.const_)
1225 1.1 mrg error("attribute `in` cannot be added after `const`: remove `const`");
1226 1.1 mrg else if (global.params.previewIn)
1227 1.1 mrg {
1228 1.1 mrg // Windows `printf` does not support `%1$s`
1229 1.1 mrg const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr;
1230 1.1 mrg error("attribute `in` cannot be added after `%s`: remove `%s`",
1231 1.1 mrg stc_str, stc_str);
1232 1.1 mrg }
1233 1.1 mrg else
1234 1.1 mrg error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
1235 1.1 mrg return orig;
1236 1.1 mrg }
1237 1.1 mrg
1238 1.1 mrg checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest);
1239 1.1 mrg checkConflictSTCGroup(STC.gshared | STC.shared_);
1240 1.1 mrg checkConflictSTCGroup!true(STC.safeGroup);
1241 1.1 mrg
1242 1.1 mrg return orig;
1243 1.1 mrg }
1244 1.1 mrg
1245 1.1 mrg /***********************************************
1246 1.1 mrg * Parse attribute(s), lexer is on '@'.
1247 1.1 mrg *
1248 1.1 mrg * Attributes can be builtin (e.g. `@safe`, `@nogc`, etc...),
1249 1.1 mrg * or be user-defined (UDAs). In the former case, we return the storage
1250 1.1 mrg * class via the return value, while in thelater case we return `0`
1251 1.1 mrg * and set `pudas`.
1252 1.1 mrg *
1253 1.1 mrg * Params:
1254 1.1 mrg * pudas = An array of UDAs to append to
1255 1.1 mrg *
1256 1.1 mrg * Returns:
1257 1.1 mrg * If the attribute is builtin, the return value will be non-zero.
1258 1.1 mrg * Otherwise, 0 is returned, and `pudas` will be appended to.
1259 1.1 mrg */
1260 1.1 mrg private StorageClass parseAttribute(ref AST.Expressions* udas)
1261 1.1 mrg {
1262 1.1 mrg nextToken();
1263 1.1 mrg if (token.value == TOK.identifier)
1264 1.1 mrg {
1265 1.1 mrg // If we find a builtin attribute, we're done, return immediately.
1266 1.1 mrg if (StorageClass stc = isBuiltinAtAttribute(token.ident))
1267 1.1 mrg return stc;
1268 1.1 mrg
1269 1.1 mrg // Allow identifier, template instantiation, or function call
1270 1.1 mrg // for `@Argument` (single UDA) form.
1271 1.1 mrg AST.Expression exp = parsePrimaryExp();
1272 1.1 mrg if (token.value == TOK.leftParenthesis)
1273 1.1 mrg {
1274 1.1 mrg const loc = token.loc;
1275 1.1 mrg exp = new AST.CallExp(loc, exp, parseArguments());
1276 1.1 mrg }
1277 1.1 mrg
1278 1.1 mrg if (udas is null)
1279 1.1 mrg udas = new AST.Expressions();
1280 1.1 mrg udas.push(exp);
1281 1.1 mrg return 0;
1282 1.1 mrg }
1283 1.1 mrg
1284 1.1 mrg if (token.value == TOK.leftParenthesis)
1285 1.1 mrg {
1286 1.1 mrg // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
1287 1.1 mrg if (peekNext() == TOK.rightParenthesis)
1288 1.1 mrg error("empty attribute list is not allowed");
1289 1.1 mrg udas = AST.UserAttributeDeclaration.concat(udas, parseArguments());
1290 1.1 mrg return 0;
1291 1.1 mrg }
1292 1.1 mrg
1293 1.1 mrg if (token.isKeyword())
1294 1.1 mrg error("`%s` is a keyword, not an `@` attribute", token.toChars());
1295 1.1 mrg else
1296 1.1 mrg error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token.toChars());
1297 1.1 mrg
1298 1.1 mrg return 0;
1299 1.1 mrg }
1300 1.1 mrg
1301 1.1 mrg /***********************************************
1302 1.1 mrg * Parse const/immutable/shared/inout/nothrow/pure postfix
1303 1.1 mrg */
1304 1.1 mrg private StorageClass parsePostfix(StorageClass storageClass, AST.Expressions** pudas)
1305 1.1 mrg {
1306 1.1 mrg while (1)
1307 1.1 mrg {
1308 1.1 mrg StorageClass stc;
1309 1.1 mrg switch (token.value)
1310 1.1 mrg {
1311 1.1 mrg case TOK.const_:
1312 1.1 mrg stc = STC.const_;
1313 1.1 mrg break;
1314 1.1 mrg
1315 1.1 mrg case TOK.immutable_:
1316 1.1 mrg stc = STC.immutable_;
1317 1.1 mrg break;
1318 1.1 mrg
1319 1.1 mrg case TOK.shared_:
1320 1.1 mrg stc = STC.shared_;
1321 1.1 mrg break;
1322 1.1 mrg
1323 1.1 mrg case TOK.inout_:
1324 1.1 mrg stc = STC.wild;
1325 1.1 mrg break;
1326 1.1 mrg
1327 1.1 mrg case TOK.nothrow_:
1328 1.1 mrg stc = STC.nothrow_;
1329 1.1 mrg break;
1330 1.1 mrg
1331 1.1 mrg case TOK.pure_:
1332 1.1 mrg stc = STC.pure_;
1333 1.1 mrg break;
1334 1.1 mrg
1335 1.1 mrg case TOK.return_:
1336 1.1 mrg stc = STC.return_;
1337 1.1 mrg if (peekNext() == TOK.scope_)
1338 1.1 mrg stc |= STC.returnScope; // recognize `return scope`
1339 1.1 mrg break;
1340 1.1 mrg
1341 1.1 mrg case TOK.scope_:
1342 1.1 mrg stc = STC.scope_;
1343 1.1 mrg break;
1344 1.1 mrg
1345 1.1 mrg case TOK.at:
1346 1.1 mrg {
1347 1.1 mrg AST.Expressions* udas = null;
1348 1.1 mrg stc = parseAttribute(udas);
1349 1.1 mrg if (udas)
1350 1.1 mrg {
1351 1.1 mrg if (pudas)
1352 1.1 mrg *pudas = AST.UserAttributeDeclaration.concat(*pudas, udas);
1353 1.1 mrg else
1354 1.1 mrg {
1355 1.1 mrg // Disallow:
1356 1.1 mrg // void function() @uda fp;
1357 1.1 mrg // () @uda { return 1; }
1358 1.1 mrg error("user-defined attributes cannot appear as postfixes");
1359 1.1 mrg }
1360 1.1 mrg continue;
1361 1.1 mrg }
1362 1.1 mrg break;
1363 1.1 mrg }
1364 1.1 mrg default:
1365 1.1 mrg return storageClass;
1366 1.1 mrg }
1367 1.1 mrg storageClass = appendStorageClass(storageClass, stc);
1368 1.1 mrg nextToken();
1369 1.1 mrg }
1370 1.1 mrg }
1371 1.1 mrg
1372 1.1 mrg private StorageClass parseTypeCtor()
1373 1.1 mrg {
1374 1.1 mrg StorageClass storageClass = STC.undefined_;
1375 1.1 mrg
1376 1.1 mrg while (1)
1377 1.1 mrg {
1378 1.1 mrg if (peekNext() == TOK.leftParenthesis)
1379 1.1 mrg return storageClass;
1380 1.1 mrg
1381 1.1 mrg StorageClass stc;
1382 1.1 mrg switch (token.value)
1383 1.1 mrg {
1384 1.1 mrg case TOK.const_:
1385 1.1 mrg stc = STC.const_;
1386 1.1 mrg break;
1387 1.1 mrg
1388 1.1 mrg case TOK.immutable_:
1389 1.1 mrg stc = STC.immutable_;
1390 1.1 mrg break;
1391 1.1 mrg
1392 1.1 mrg case TOK.shared_:
1393 1.1 mrg stc = STC.shared_;
1394 1.1 mrg break;
1395 1.1 mrg
1396 1.1 mrg case TOK.inout_:
1397 1.1 mrg stc = STC.wild;
1398 1.1 mrg break;
1399 1.1 mrg
1400 1.1 mrg default:
1401 1.1 mrg return storageClass;
1402 1.1 mrg }
1403 1.1 mrg storageClass = appendStorageClass(storageClass, stc);
1404 1.1 mrg nextToken();
1405 1.1 mrg }
1406 1.1 mrg }
1407 1.1 mrg
1408 1.1 mrg /**************************************
1409 1.1 mrg * Parse constraint.
1410 1.1 mrg * Constraint is of the form:
1411 1.1 mrg * if ( ConstraintExpression )
1412 1.1 mrg */
1413 1.1 mrg private AST.Expression parseConstraint()
1414 1.1 mrg {
1415 1.1 mrg AST.Expression e = null;
1416 1.1 mrg if (token.value == TOK.if_)
1417 1.1 mrg {
1418 1.1 mrg nextToken(); // skip over 'if'
1419 1.1 mrg check(TOK.leftParenthesis);
1420 1.1 mrg e = parseExpression();
1421 1.1 mrg check(TOK.rightParenthesis);
1422 1.1 mrg }
1423 1.1 mrg return e;
1424 1.1 mrg }
1425 1.1 mrg
1426 1.1 mrg /**************************************
1427 1.1 mrg * Parse a TemplateDeclaration.
1428 1.1 mrg */
1429 1.1 mrg private AST.TemplateDeclaration parseTemplateDeclaration(bool ismixin = false)
1430 1.1 mrg {
1431 1.1 mrg AST.TemplateDeclaration tempdecl;
1432 1.1 mrg Identifier id;
1433 1.1 mrg AST.TemplateParameters* tpl;
1434 1.1 mrg AST.Dsymbols* decldefs;
1435 1.1 mrg AST.Expression constraint = null;
1436 1.1 mrg const loc = token.loc;
1437 1.1 mrg
1438 1.1 mrg nextToken();
1439 1.1 mrg if (token.value != TOK.identifier)
1440 1.1 mrg {
1441 1.1 mrg error("identifier expected following `template`");
1442 1.1 mrg goto Lerr;
1443 1.1 mrg }
1444 1.1 mrg id = token.ident;
1445 1.1 mrg nextToken();
1446 1.1 mrg tpl = parseTemplateParameterList();
1447 1.1 mrg if (!tpl)
1448 1.1 mrg goto Lerr;
1449 1.1 mrg
1450 1.1 mrg constraint = parseConstraint();
1451 1.1 mrg
1452 1.1 mrg if (token.value != TOK.leftCurly)
1453 1.1 mrg {
1454 1.1 mrg error("members of template declaration expected");
1455 1.1 mrg goto Lerr;
1456 1.1 mrg }
1457 1.1 mrg decldefs = parseBlock(null);
1458 1.1 mrg
1459 1.1 mrg tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
1460 1.1 mrg return tempdecl;
1461 1.1 mrg
1462 1.1 mrg Lerr:
1463 1.1 mrg return null;
1464 1.1 mrg }
1465 1.1 mrg
1466 1.1 mrg /******************************************
1467 1.1 mrg * Parse template parameter list.
1468 1.1 mrg * Input:
1469 1.1 mrg * flag 0: parsing "( list )"
1470 1.1 mrg * 1: parsing non-empty "list $(RPAREN)"
1471 1.1 mrg */
1472 1.1 mrg private AST.TemplateParameters* parseTemplateParameterList(int flag = 0)
1473 1.1 mrg {
1474 1.1 mrg auto tpl = new AST.TemplateParameters();
1475 1.1 mrg
1476 1.1 mrg if (!flag && token.value != TOK.leftParenthesis)
1477 1.1 mrg {
1478 1.1 mrg error("parenthesized template parameter list expected following template identifier");
1479 1.1 mrg goto Lerr;
1480 1.1 mrg }
1481 1.1 mrg nextToken();
1482 1.1 mrg
1483 1.1 mrg // Get array of TemplateParameters
1484 1.1 mrg if (flag || token.value != TOK.rightParenthesis)
1485 1.1 mrg {
1486 1.1 mrg while (token.value != TOK.rightParenthesis)
1487 1.1 mrg {
1488 1.1 mrg AST.TemplateParameter tp;
1489 1.1 mrg Loc loc;
1490 1.1 mrg Identifier tp_ident = null;
1491 1.1 mrg AST.Type tp_spectype = null;
1492 1.1 mrg AST.Type tp_valtype = null;
1493 1.1 mrg AST.Type tp_defaulttype = null;
1494 1.1 mrg AST.Expression tp_specvalue = null;
1495 1.1 mrg AST.Expression tp_defaultvalue = null;
1496 1.1 mrg
1497 1.1 mrg // Get TemplateParameter
1498 1.1 mrg
1499 1.1 mrg // First, look ahead to see if it is a TypeParameter or a ValueParameter
1500 1.1 mrg const tv = peekNext();
1501 1.1 mrg if (token.value == TOK.alias_)
1502 1.1 mrg {
1503 1.1 mrg // AliasParameter
1504 1.1 mrg nextToken();
1505 1.1 mrg loc = token.loc; // todo
1506 1.1 mrg AST.Type spectype = null;
1507 1.1 mrg if (isDeclaration(&token, NeedDeclaratorId.must, TOK.reserved, null))
1508 1.1 mrg {
1509 1.1 mrg spectype = parseType(&tp_ident);
1510 1.1 mrg }
1511 1.1 mrg else
1512 1.1 mrg {
1513 1.1 mrg if (token.value != TOK.identifier)
1514 1.1 mrg {
1515 1.1 mrg error("identifier expected for template `alias` parameter");
1516 1.1 mrg goto Lerr;
1517 1.1 mrg }
1518 1.1 mrg tp_ident = token.ident;
1519 1.1 mrg nextToken();
1520 1.1 mrg }
1521 1.1 mrg RootObject spec = null;
1522 1.1 mrg if (token.value == TOK.colon) // : Type
1523 1.1 mrg {
1524 1.1 mrg nextToken();
1525 1.1 mrg if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
1526 1.1 mrg spec = parseType();
1527 1.1 mrg else
1528 1.1 mrg spec = parseCondExp();
1529 1.1 mrg }
1530 1.1 mrg RootObject def = null;
1531 1.1 mrg if (token.value == TOK.assign) // = Type
1532 1.1 mrg {
1533 1.1 mrg nextToken();
1534 1.1 mrg if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
1535 1.1 mrg def = parseType();
1536 1.1 mrg else
1537 1.1 mrg def = parseCondExp();
1538 1.1 mrg }
1539 1.1 mrg tp = new AST.TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
1540 1.1 mrg }
1541 1.1 mrg else if (tv == TOK.colon || tv == TOK.assign || tv == TOK.comma || tv == TOK.rightParenthesis)
1542 1.1 mrg {
1543 1.1 mrg // TypeParameter
1544 1.1 mrg if (token.value != TOK.identifier)
1545 1.1 mrg {
1546 1.1 mrg error("identifier expected for template type parameter");
1547 1.1 mrg goto Lerr;
1548 1.1 mrg }
1549 1.1 mrg loc = token.loc;
1550 1.1 mrg tp_ident = token.ident;
1551 1.1 mrg nextToken();
1552 1.1 mrg if (token.value == TOK.colon) // : Type
1553 1.1 mrg {
1554 1.1 mrg nextToken();
1555 1.1 mrg tp_spectype = parseType();
1556 1.1 mrg }
1557 1.1 mrg if (token.value == TOK.assign) // = Type
1558 1.1 mrg {
1559 1.1 mrg nextToken();
1560 1.1 mrg tp_defaulttype = parseType();
1561 1.1 mrg }
1562 1.1 mrg tp = new AST.TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1563 1.1 mrg }
1564 1.1 mrg else if (token.value == TOK.identifier && tv == TOK.dotDotDot)
1565 1.1 mrg {
1566 1.1 mrg // ident...
1567 1.1 mrg loc = token.loc;
1568 1.1 mrg tp_ident = token.ident;
1569 1.1 mrg nextToken();
1570 1.1 mrg nextToken();
1571 1.1 mrg tp = new AST.TemplateTupleParameter(loc, tp_ident);
1572 1.1 mrg }
1573 1.1 mrg else if (token.value == TOK.this_)
1574 1.1 mrg {
1575 1.1 mrg // ThisParameter
1576 1.1 mrg nextToken();
1577 1.1 mrg if (token.value != TOK.identifier)
1578 1.1 mrg {
1579 1.1 mrg error("identifier expected for template `this` parameter");
1580 1.1 mrg goto Lerr;
1581 1.1 mrg }
1582 1.1 mrg loc = token.loc;
1583 1.1 mrg tp_ident = token.ident;
1584 1.1 mrg nextToken();
1585 1.1 mrg if (token.value == TOK.colon) // : Type
1586 1.1 mrg {
1587 1.1 mrg nextToken();
1588 1.1 mrg tp_spectype = parseType();
1589 1.1 mrg }
1590 1.1 mrg if (token.value == TOK.assign) // = Type
1591 1.1 mrg {
1592 1.1 mrg nextToken();
1593 1.1 mrg tp_defaulttype = parseType();
1594 1.1 mrg }
1595 1.1 mrg tp = new AST.TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1596 1.1 mrg }
1597 1.1 mrg else
1598 1.1 mrg {
1599 1.1 mrg // ValueParameter
1600 1.1 mrg loc = token.loc; // todo
1601 1.1 mrg tp_valtype = parseType(&tp_ident);
1602 1.1 mrg if (!tp_ident)
1603 1.1 mrg {
1604 1.1 mrg error("identifier expected for template value parameter");
1605 1.1 mrg tp_ident = Identifier.idPool("error");
1606 1.1 mrg }
1607 1.1 mrg if (token.value == TOK.colon) // : CondExpression
1608 1.1 mrg {
1609 1.1 mrg nextToken();
1610 1.1 mrg tp_specvalue = parseCondExp();
1611 1.1 mrg }
1612 1.1 mrg if (token.value == TOK.assign) // = CondExpression
1613 1.1 mrg {
1614 1.1 mrg nextToken();
1615 1.1 mrg tp_defaultvalue = parseDefaultInitExp();
1616 1.1 mrg }
1617 1.1 mrg tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1618 1.1 mrg }
1619 1.1 mrg tpl.push(tp);
1620 1.1 mrg if (token.value != TOK.comma)
1621 1.1 mrg break;
1622 1.1 mrg nextToken();
1623 1.1 mrg }
1624 1.1 mrg }
1625 1.1 mrg check(TOK.rightParenthesis);
1626 1.1 mrg
1627 1.1 mrg Lerr:
1628 1.1 mrg return tpl;
1629 1.1 mrg }
1630 1.1 mrg
1631 1.1 mrg /******************************************
1632 1.1 mrg * Parse template mixin.
1633 1.1 mrg * mixin Foo;
1634 1.1 mrg * mixin Foo!(args);
1635 1.1 mrg * mixin a.b.c!(args).Foo!(args);
1636 1.1 mrg * mixin Foo!(args) identifier;
1637 1.1 mrg * mixin typeof(expr).identifier!(args);
1638 1.1 mrg */
1639 1.1 mrg private AST.Dsymbol parseMixin()
1640 1.1 mrg {
1641 1.1 mrg AST.TemplateMixin tm;
1642 1.1 mrg Identifier id;
1643 1.1 mrg AST.Objects* tiargs;
1644 1.1 mrg
1645 1.1 mrg //printf("parseMixin()\n");
1646 1.1 mrg const locMixin = token.loc;
1647 1.1 mrg nextToken(); // skip 'mixin'
1648 1.1 mrg
1649 1.1 mrg auto loc = token.loc;
1650 1.1 mrg AST.TypeQualified tqual = null;
1651 1.1 mrg if (token.value == TOK.dot)
1652 1.1 mrg {
1653 1.1 mrg id = Id.empty;
1654 1.1 mrg }
1655 1.1 mrg else
1656 1.1 mrg {
1657 1.1 mrg if (token.value == TOK.typeof_)
1658 1.1 mrg {
1659 1.1 mrg tqual = parseTypeof();
1660 1.1 mrg check(TOK.dot);
1661 1.1 mrg }
1662 1.1 mrg if (token.value != TOK.identifier)
1663 1.1 mrg {
1664 1.1 mrg error("identifier expected, not `%s`", token.toChars());
1665 1.1 mrg id = Id.empty;
1666 1.1 mrg }
1667 1.1 mrg else
1668 1.1 mrg id = token.ident;
1669 1.1 mrg nextToken();
1670 1.1 mrg }
1671 1.1 mrg
1672 1.1 mrg while (1)
1673 1.1 mrg {
1674 1.1 mrg tiargs = null;
1675 1.1 mrg if (token.value == TOK.not)
1676 1.1 mrg {
1677 1.1 mrg tiargs = parseTemplateArguments();
1678 1.1 mrg }
1679 1.1 mrg
1680 1.1 mrg if (tiargs && token.value == TOK.dot)
1681 1.1 mrg {
1682 1.1 mrg auto tempinst = new AST.TemplateInstance(loc, id, tiargs);
1683 1.1 mrg if (!tqual)
1684 1.1 mrg tqual = new AST.TypeInstance(loc, tempinst);
1685 1.1 mrg else
1686 1.1 mrg tqual.addInst(tempinst);
1687 1.1 mrg tiargs = null;
1688 1.1 mrg }
1689 1.1 mrg else
1690 1.1 mrg {
1691 1.1 mrg if (!tqual)
1692 1.1 mrg tqual = new AST.TypeIdentifier(loc, id);
1693 1.1 mrg else
1694 1.1 mrg tqual.addIdent(id);
1695 1.1 mrg }
1696 1.1 mrg
1697 1.1 mrg if (token.value != TOK.dot)
1698 1.1 mrg break;
1699 1.1 mrg
1700 1.1 mrg nextToken();
1701 1.1 mrg if (token.value != TOK.identifier)
1702 1.1 mrg {
1703 1.1 mrg error("identifier expected following `.` instead of `%s`", token.toChars());
1704 1.1 mrg break;
1705 1.1 mrg }
1706 1.1 mrg loc = token.loc;
1707 1.1 mrg id = token.ident;
1708 1.1 mrg nextToken();
1709 1.1 mrg }
1710 1.1 mrg
1711 1.1 mrg id = null;
1712 1.1 mrg if (token.value == TOK.identifier)
1713 1.1 mrg {
1714 1.1 mrg id = token.ident;
1715 1.1 mrg nextToken();
1716 1.1 mrg }
1717 1.1 mrg
1718 1.1 mrg tm = new AST.TemplateMixin(locMixin, id, tqual, tiargs);
1719 1.1 mrg if (token.value != TOK.semicolon)
1720 1.1 mrg error("`;` expected after `mixin`");
1721 1.1 mrg nextToken();
1722 1.1 mrg
1723 1.1 mrg return tm;
1724 1.1 mrg }
1725 1.1 mrg
1726 1.1 mrg /******************************************
1727 1.1 mrg * Parse template arguments.
1728 1.1 mrg * Input:
1729 1.1 mrg * current token is opening '!'
1730 1.1 mrg * Output:
1731 1.1 mrg * current token is one after closing '$(RPAREN)'
1732 1.1 mrg */
1733 1.1 mrg private AST.Objects* parseTemplateArguments()
1734 1.1 mrg {
1735 1.1 mrg AST.Objects* tiargs;
1736 1.1 mrg
1737 1.1 mrg nextToken();
1738 1.1 mrg if (token.value == TOK.leftParenthesis)
1739 1.1 mrg {
1740 1.1 mrg // ident!(template_arguments)
1741 1.1 mrg tiargs = parseTemplateArgumentList();
1742 1.1 mrg }
1743 1.1 mrg else
1744 1.1 mrg {
1745 1.1 mrg // ident!template_argument
1746 1.1 mrg tiargs = parseTemplateSingleArgument();
1747 1.1 mrg }
1748 1.1 mrg if (token.value == TOK.not)
1749 1.1 mrg {
1750 1.1 mrg TOK tok = peekNext();
1751 1.1 mrg if (tok != TOK.is_ && tok != TOK.in_)
1752 1.1 mrg {
1753 1.1 mrg error("multiple ! arguments are not allowed");
1754 1.1 mrg Lagain:
1755 1.1 mrg nextToken();
1756 1.1 mrg if (token.value == TOK.leftParenthesis)
1757 1.1 mrg parseTemplateArgumentList();
1758 1.1 mrg else
1759 1.1 mrg parseTemplateSingleArgument();
1760 1.1 mrg if (token.value == TOK.not && (tok = peekNext()) != TOK.is_ && tok != TOK.in_)
1761 1.1 mrg goto Lagain;
1762 1.1 mrg }
1763 1.1 mrg }
1764 1.1 mrg return tiargs;
1765 1.1 mrg }
1766 1.1 mrg
1767 1.1 mrg /******************************************
1768 1.1 mrg * Parse template argument list.
1769 1.1 mrg * Input:
1770 1.1 mrg * current token is opening '$(LPAREN)',
1771 1.1 mrg * or ',' for __traits
1772 1.1 mrg * Output:
1773 1.1 mrg * current token is one after closing '$(RPAREN)'
1774 1.1 mrg */
1775 1.1 mrg private AST.Objects* parseTemplateArgumentList()
1776 1.1 mrg {
1777 1.1 mrg //printf("Parser::parseTemplateArgumentList()\n");
1778 1.1 mrg auto tiargs = new AST.Objects();
1779 1.1 mrg TOK endtok = TOK.rightParenthesis;
1780 1.1 mrg assert(token.value == TOK.leftParenthesis || token.value == TOK.comma);
1781 1.1 mrg nextToken();
1782 1.1 mrg
1783 1.1 mrg // Get TemplateArgumentList
1784 1.1 mrg while (token.value != endtok)
1785 1.1 mrg {
1786 1.1 mrg tiargs.push(parseTypeOrAssignExp());
1787 1.1 mrg if (token.value != TOK.comma)
1788 1.1 mrg break;
1789 1.1 mrg nextToken();
1790 1.1 mrg }
1791 1.1 mrg check(endtok, "template argument list");
1792 1.1 mrg return tiargs;
1793 1.1 mrg }
1794 1.1 mrg
1795 1.1 mrg /***************************************
1796 1.1 mrg * Parse a Type or an Expression
1797 1.1 mrg * Returns:
1798 1.1 mrg * RootObject representing the AST
1799 1.1 mrg */
1800 1.1 mrg RootObject parseTypeOrAssignExp(TOK endtoken = TOK.reserved)
1801 1.1 mrg {
1802 1.1 mrg return isDeclaration(&token, NeedDeclaratorId.no, endtoken, null)
1803 1.1 mrg ? parseType() // argument is a type
1804 1.1 mrg : parseAssignExp(); // argument is an expression
1805 1.1 mrg }
1806 1.1 mrg
1807 1.1 mrg /*****************************
1808 1.1 mrg * Parse single template argument, to support the syntax:
1809 1.1 mrg * foo!arg
1810 1.1 mrg * Input:
1811 1.1 mrg * current token is the arg
1812 1.1 mrg */
1813 1.1 mrg private AST.Objects* parseTemplateSingleArgument()
1814 1.1 mrg {
1815 1.1 mrg //printf("parseTemplateSingleArgument()\n");
1816 1.1 mrg auto tiargs = new AST.Objects();
1817 1.1 mrg AST.Type ta;
1818 1.1 mrg switch (token.value)
1819 1.1 mrg {
1820 1.1 mrg case TOK.identifier:
1821 1.1 mrg ta = new AST.TypeIdentifier(token.loc, token.ident);
1822 1.1 mrg goto LabelX;
1823 1.1 mrg
1824 1.1 mrg case TOK.vector:
1825 1.1 mrg ta = parseVector();
1826 1.1 mrg goto LabelX;
1827 1.1 mrg
1828 1.1 mrg case TOK.void_:
1829 1.1 mrg ta = AST.Type.tvoid;
1830 1.1 mrg goto LabelX;
1831 1.1 mrg
1832 1.1 mrg case TOK.int8:
1833 1.1 mrg ta = AST.Type.tint8;
1834 1.1 mrg goto LabelX;
1835 1.1 mrg
1836 1.1 mrg case TOK.uns8:
1837 1.1 mrg ta = AST.Type.tuns8;
1838 1.1 mrg goto LabelX;
1839 1.1 mrg
1840 1.1 mrg case TOK.int16:
1841 1.1 mrg ta = AST.Type.tint16;
1842 1.1 mrg goto LabelX;
1843 1.1 mrg
1844 1.1 mrg case TOK.uns16:
1845 1.1 mrg ta = AST.Type.tuns16;
1846 1.1 mrg goto LabelX;
1847 1.1 mrg
1848 1.1 mrg case TOK.int32:
1849 1.1 mrg ta = AST.Type.tint32;
1850 1.1 mrg goto LabelX;
1851 1.1 mrg
1852 1.1 mrg case TOK.uns32:
1853 1.1 mrg ta = AST.Type.tuns32;
1854 1.1 mrg goto LabelX;
1855 1.1 mrg
1856 1.1 mrg case TOK.int64:
1857 1.1 mrg ta = AST.Type.tint64;
1858 1.1 mrg goto LabelX;
1859 1.1 mrg
1860 1.1 mrg case TOK.uns64:
1861 1.1 mrg ta = AST.Type.tuns64;
1862 1.1 mrg goto LabelX;
1863 1.1 mrg
1864 1.1 mrg case TOK.int128:
1865 1.1 mrg ta = AST.Type.tint128;
1866 1.1 mrg goto LabelX;
1867 1.1 mrg
1868 1.1 mrg case TOK.uns128:
1869 1.1 mrg ta = AST.Type.tuns128;
1870 1.1 mrg goto LabelX;
1871 1.1 mrg
1872 1.1 mrg case TOK.float32:
1873 1.1 mrg ta = AST.Type.tfloat32;
1874 1.1 mrg goto LabelX;
1875 1.1 mrg
1876 1.1 mrg case TOK.float64:
1877 1.1 mrg ta = AST.Type.tfloat64;
1878 1.1 mrg goto LabelX;
1879 1.1 mrg
1880 1.1 mrg case TOK.float80:
1881 1.1 mrg ta = AST.Type.tfloat80;
1882 1.1 mrg goto LabelX;
1883 1.1 mrg
1884 1.1 mrg case TOK.imaginary32:
1885 1.1 mrg ta = AST.Type.timaginary32;
1886 1.1 mrg goto LabelX;
1887 1.1 mrg
1888 1.1 mrg case TOK.imaginary64:
1889 1.1 mrg ta = AST.Type.timaginary64;
1890 1.1 mrg goto LabelX;
1891 1.1 mrg
1892 1.1 mrg case TOK.imaginary80:
1893 1.1 mrg ta = AST.Type.timaginary80;
1894 1.1 mrg goto LabelX;
1895 1.1 mrg
1896 1.1 mrg case TOK.complex32:
1897 1.1 mrg ta = AST.Type.tcomplex32;
1898 1.1 mrg goto LabelX;
1899 1.1 mrg
1900 1.1 mrg case TOK.complex64:
1901 1.1 mrg ta = AST.Type.tcomplex64;
1902 1.1 mrg goto LabelX;
1903 1.1 mrg
1904 1.1 mrg case TOK.complex80:
1905 1.1 mrg ta = AST.Type.tcomplex80;
1906 1.1 mrg goto LabelX;
1907 1.1 mrg
1908 1.1 mrg case TOK.bool_:
1909 1.1 mrg ta = AST.Type.tbool;
1910 1.1 mrg goto LabelX;
1911 1.1 mrg
1912 1.1 mrg case TOK.char_:
1913 1.1 mrg ta = AST.Type.tchar;
1914 1.1 mrg goto LabelX;
1915 1.1 mrg
1916 1.1 mrg case TOK.wchar_:
1917 1.1 mrg ta = AST.Type.twchar;
1918 1.1 mrg goto LabelX;
1919 1.1 mrg
1920 1.1 mrg case TOK.dchar_:
1921 1.1 mrg ta = AST.Type.tdchar;
1922 1.1 mrg goto LabelX;
1923 1.1 mrg LabelX:
1924 1.1 mrg tiargs.push(ta);
1925 1.1 mrg nextToken();
1926 1.1 mrg break;
1927 1.1 mrg
1928 1.1 mrg case TOK.int32Literal:
1929 1.1 mrg case TOK.uns32Literal:
1930 1.1 mrg case TOK.int64Literal:
1931 1.1 mrg case TOK.uns64Literal:
1932 1.1 mrg case TOK.int128Literal:
1933 1.1 mrg case TOK.uns128Literal:
1934 1.1 mrg case TOK.float32Literal:
1935 1.1 mrg case TOK.float64Literal:
1936 1.1 mrg case TOK.float80Literal:
1937 1.1 mrg case TOK.imaginary32Literal:
1938 1.1 mrg case TOK.imaginary64Literal:
1939 1.1 mrg case TOK.imaginary80Literal:
1940 1.1 mrg case TOK.null_:
1941 1.1 mrg case TOK.true_:
1942 1.1 mrg case TOK.false_:
1943 1.1 mrg case TOK.charLiteral:
1944 1.1 mrg case TOK.wcharLiteral:
1945 1.1 mrg case TOK.dcharLiteral:
1946 1.1 mrg case TOK.string_:
1947 1.1 mrg case TOK.file:
1948 1.1 mrg case TOK.fileFullPath:
1949 1.1 mrg case TOK.line:
1950 1.1 mrg case TOK.moduleString:
1951 1.1 mrg case TOK.functionString:
1952 1.1 mrg case TOK.prettyFunction:
1953 1.1 mrg case TOK.this_:
1954 1.1 mrg {
1955 1.1 mrg // Template argument is an expression
1956 1.1 mrg AST.Expression ea = parsePrimaryExp();
1957 1.1 mrg tiargs.push(ea);
1958 1.1 mrg break;
1959 1.1 mrg }
1960 1.1 mrg default:
1961 1.1 mrg error("template argument expected following `!`");
1962 1.1 mrg break;
1963 1.1 mrg }
1964 1.1 mrg return tiargs;
1965 1.1 mrg }
1966 1.1 mrg
1967 1.1 mrg /**********************************
1968 1.1 mrg * Parse a static assertion.
1969 1.1 mrg * Current token is 'static'.
1970 1.1 mrg */
1971 1.1 mrg private AST.StaticAssert parseStaticAssert()
1972 1.1 mrg {
1973 1.1 mrg const loc = token.loc;
1974 1.1 mrg AST.Expression exp;
1975 1.1 mrg AST.Expression msg = null;
1976 1.1 mrg
1977 1.1 mrg //printf("parseStaticAssert()\n");
1978 1.1 mrg nextToken();
1979 1.1 mrg nextToken();
1980 1.1 mrg check(TOK.leftParenthesis);
1981 1.1 mrg exp = parseAssignExp();
1982 1.1 mrg if (token.value == TOK.comma)
1983 1.1 mrg {
1984 1.1 mrg nextToken();
1985 1.1 mrg if (token.value != TOK.rightParenthesis)
1986 1.1 mrg {
1987 1.1 mrg msg = parseAssignExp();
1988 1.1 mrg if (token.value == TOK.comma)
1989 1.1 mrg nextToken();
1990 1.1 mrg }
1991 1.1 mrg }
1992 1.1 mrg check(TOK.rightParenthesis);
1993 1.1 mrg check(TOK.semicolon);
1994 1.1 mrg return new AST.StaticAssert(loc, exp, msg);
1995 1.1 mrg }
1996 1.1 mrg
1997 1.1 mrg /***********************************
1998 1.1 mrg * Parse typeof(expression).
1999 1.1 mrg * Current token is on the 'typeof'.
2000 1.1 mrg */
2001 1.1 mrg private AST.TypeQualified parseTypeof()
2002 1.1 mrg {
2003 1.1 mrg AST.TypeQualified t;
2004 1.1 mrg const loc = token.loc;
2005 1.1 mrg
2006 1.1 mrg nextToken();
2007 1.1 mrg check(TOK.leftParenthesis);
2008 1.1 mrg if (token.value == TOK.return_) // typeof(return)
2009 1.1 mrg {
2010 1.1 mrg nextToken();
2011 1.1 mrg t = new AST.TypeReturn(loc);
2012 1.1 mrg }
2013 1.1 mrg else
2014 1.1 mrg {
2015 1.1 mrg AST.Expression exp = parseExpression(); // typeof(expression)
2016 1.1 mrg t = new AST.TypeTypeof(loc, exp);
2017 1.1 mrg }
2018 1.1 mrg check(TOK.rightParenthesis);
2019 1.1 mrg return t;
2020 1.1 mrg }
2021 1.1 mrg
2022 1.1 mrg /***********************************
2023 1.1 mrg * Parse __vector(type).
2024 1.1 mrg * Current token is on the '__vector'.
2025 1.1 mrg */
2026 1.1 mrg private AST.Type parseVector()
2027 1.1 mrg {
2028 1.1 mrg nextToken();
2029 1.1 mrg check(TOK.leftParenthesis);
2030 1.1 mrg AST.Type tb = parseType();
2031 1.1 mrg check(TOK.rightParenthesis);
2032 1.1 mrg return new AST.TypeVector(tb);
2033 1.1 mrg }
2034 1.1 mrg
2035 1.1 mrg /***********************************
2036 1.1 mrg * Parse:
2037 1.1 mrg * extern (linkage)
2038 1.1 mrg * extern (C++, namespaces)
2039 1.1 mrg * extern (C++, "namespace", "namespaces", ...)
2040 1.1 mrg * extern (C++, (StringExp))
2041 1.1 mrg * The parser is on the 'extern' token.
2042 1.1 mrg */
2043 1.1 mrg private ParsedLinkage!(AST) parseLinkage()
2044 1.1 mrg {
2045 1.1 mrg ParsedLinkage!(AST) result;
2046 1.1 mrg nextToken();
2047 1.1 mrg assert(token.value == TOK.leftParenthesis);
2048 1.1 mrg nextToken();
2049 1.1 mrg ParsedLinkage!(AST) returnLinkage(LINK link)
2050 1.1 mrg {
2051 1.1 mrg check(TOK.rightParenthesis);
2052 1.1 mrg result.link = link;
2053 1.1 mrg return result;
2054 1.1 mrg }
2055 1.1 mrg ParsedLinkage!(AST) invalidLinkage()
2056 1.1 mrg {
2057 1.1 mrg error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Windows`, `System`");
2058 1.1 mrg return returnLinkage(LINK.d);
2059 1.1 mrg }
2060 1.1 mrg
2061 1.1 mrg if (token.value != TOK.identifier)
2062 1.1 mrg return returnLinkage(LINK.d);
2063 1.1 mrg
2064 1.1 mrg Identifier id = token.ident;
2065 1.1 mrg nextToken();
2066 1.1 mrg if (id == Id.Windows)
2067 1.1 mrg return returnLinkage(LINK.windows);
2068 1.1 mrg else if (id == Id.D)
2069 1.1 mrg return returnLinkage(LINK.d);
2070 1.1 mrg else if (id == Id.System)
2071 1.1 mrg return returnLinkage(LINK.system);
2072 1.1 mrg else if (id == Id.Objective) // Looking for tokens "Objective-C"
2073 1.1 mrg {
2074 1.1 mrg if (token.value != TOK.min)
2075 1.1 mrg return invalidLinkage();
2076 1.1 mrg
2077 1.1 mrg nextToken();
2078 1.1 mrg if (token.ident != Id.C)
2079 1.1 mrg return invalidLinkage();
2080 1.1 mrg
2081 1.1 mrg nextToken();
2082 1.1 mrg return returnLinkage(LINK.objc);
2083 1.1 mrg }
2084 1.1 mrg else if (id != Id.C)
2085 1.1 mrg return invalidLinkage();
2086 1.1 mrg
2087 1.1 mrg if (token.value != TOK.plusPlus)
2088 1.1 mrg return returnLinkage(LINK.c);
2089 1.1 mrg
2090 1.1 mrg nextToken();
2091 1.1 mrg if (token.value != TOK.comma) // , namespaces or class or struct
2092 1.1 mrg return returnLinkage(LINK.cpp);
2093 1.1 mrg
2094 1.1 mrg nextToken();
2095 1.1 mrg
2096 1.1 mrg if (token.value == TOK.rightParenthesis)
2097 1.1 mrg return returnLinkage(LINK.cpp); // extern(C++,)
2098 1.1 mrg
2099 1.1 mrg if (token.value == TOK.class_ || token.value == TOK.struct_)
2100 1.1 mrg {
2101 1.1 mrg result.cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct;
2102 1.1 mrg nextToken();
2103 1.1 mrg }
2104 1.1 mrg else if (token.value == TOK.identifier) // named scope namespace
2105 1.1 mrg {
2106 1.1 mrg result.idents = new AST.Identifiers();
2107 1.1 mrg while (1)
2108 1.1 mrg {
2109 1.1 mrg Identifier idn = token.ident;
2110 1.1 mrg result.idents.push(idn);
2111 1.1 mrg nextToken();
2112 1.1 mrg if (token.value == TOK.dot)
2113 1.1 mrg {
2114 1.1 mrg nextToken();
2115 1.1 mrg if (token.value == TOK.identifier)
2116 1.1 mrg continue;
2117 1.1 mrg error("identifier expected for C++ namespace");
2118 1.1 mrg result.idents = null; // error occurred, invalidate list of elements.
2119 1.1 mrg }
2120 1.1 mrg break;
2121 1.1 mrg }
2122 1.1 mrg }
2123 1.1 mrg else // non-scoped StringExp namespace
2124 1.1 mrg {
2125 1.1 mrg result.identExps = new AST.Expressions();
2126 1.1 mrg while (1)
2127 1.1 mrg {
2128 1.1 mrg result.identExps.push(parseCondExp());
2129 1.1 mrg if (token.value != TOK.comma)
2130 1.1 mrg break;
2131 1.1 mrg nextToken();
2132 1.1 mrg // Allow trailing commas as done for argument lists, arrays, ...
2133 1.1 mrg if (token.value == TOK.rightParenthesis)
2134 1.1 mrg break;
2135 1.1 mrg }
2136 1.1 mrg }
2137 1.1 mrg return returnLinkage(LINK.cpp);
2138 1.1 mrg }
2139 1.1 mrg
2140 1.1 mrg /***********************************
2141 1.1 mrg * Parse ident1.ident2.ident3
2142 1.1 mrg *
2143 1.1 mrg * Params:
2144 1.1 mrg * entity = what qualified identifier is expected to resolve into.
2145 1.1 mrg * Used only for better error message
2146 1.1 mrg *
2147 1.1 mrg * Returns:
2148 1.1 mrg * array of identifiers with actual qualified one stored last
2149 1.1 mrg */
2150 1.1 mrg private Identifier[] parseQualifiedIdentifier(const(char)* entity)
2151 1.1 mrg {
2152 1.1 mrg Identifier[] qualified;
2153 1.1 mrg
2154 1.1 mrg do
2155 1.1 mrg {
2156 1.1 mrg nextToken();
2157 1.1 mrg if (token.value != TOK.identifier)
2158 1.1 mrg {
2159 1.1 mrg error("`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars());
2160 1.1 mrg return qualified;
2161 1.1 mrg }
2162 1.1 mrg
2163 1.1 mrg Identifier id = token.ident;
2164 1.1 mrg qualified ~= id;
2165 1.1 mrg
2166 1.1 mrg nextToken();
2167 1.1 mrg }
2168 1.1 mrg while (token.value == TOK.dot);
2169 1.1 mrg
2170 1.1 mrg return qualified;
2171 1.1 mrg }
2172 1.1 mrg
2173 1.1 mrg private AST.DebugSymbol parseDebugSpecification()
2174 1.1 mrg {
2175 1.1 mrg AST.DebugSymbol s;
2176 1.1 mrg nextToken();
2177 1.1 mrg if (token.value == TOK.identifier)
2178 1.1 mrg s = new AST.DebugSymbol(token.loc, token.ident);
2179 1.1 mrg else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2180 1.1 mrg s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
2181 1.1 mrg else
2182 1.1 mrg {
2183 1.1 mrg error("identifier or integer expected, not `%s`", token.toChars());
2184 1.1 mrg s = null;
2185 1.1 mrg }
2186 1.1 mrg nextToken();
2187 1.1 mrg if (token.value != TOK.semicolon)
2188 1.1 mrg error("semicolon expected");
2189 1.1 mrg nextToken();
2190 1.1 mrg return s;
2191 1.1 mrg }
2192 1.1 mrg
2193 1.1 mrg /**************************************
2194 1.1 mrg * Parse a debug conditional
2195 1.1 mrg */
2196 1.1 mrg private AST.Condition parseDebugCondition()
2197 1.1 mrg {
2198 1.1 mrg uint level = 1;
2199 1.1 mrg Identifier id = null;
2200 1.1 mrg Loc loc = token.loc;
2201 1.1 mrg
2202 1.1 mrg if (token.value == TOK.leftParenthesis)
2203 1.1 mrg {
2204 1.1 mrg nextToken();
2205 1.1 mrg
2206 1.1 mrg if (token.value == TOK.identifier)
2207 1.1 mrg id = token.ident;
2208 1.1 mrg else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2209 1.1 mrg level = cast(uint)token.unsvalue;
2210 1.1 mrg else
2211 1.1 mrg error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars());
2212 1.1 mrg loc = token.loc;
2213 1.1 mrg nextToken();
2214 1.1 mrg check(TOK.rightParenthesis);
2215 1.1 mrg }
2216 1.1 mrg return new AST.DebugCondition(loc, mod, level, id);
2217 1.1 mrg }
2218 1.1 mrg
2219 1.1 mrg /**************************************
2220 1.1 mrg * Parse a version specification
2221 1.1 mrg */
2222 1.1 mrg private AST.VersionSymbol parseVersionSpecification()
2223 1.1 mrg {
2224 1.1 mrg AST.VersionSymbol s;
2225 1.1 mrg nextToken();
2226 1.1 mrg if (token.value == TOK.identifier)
2227 1.1 mrg s = new AST.VersionSymbol(token.loc, token.ident);
2228 1.1 mrg else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2229 1.1 mrg s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
2230 1.1 mrg else
2231 1.1 mrg {
2232 1.1 mrg error("identifier or integer expected, not `%s`", token.toChars());
2233 1.1 mrg s = null;
2234 1.1 mrg }
2235 1.1 mrg nextToken();
2236 1.1 mrg if (token.value != TOK.semicolon)
2237 1.1 mrg error("semicolon expected");
2238 1.1 mrg nextToken();
2239 1.1 mrg return s;
2240 1.1 mrg }
2241 1.1 mrg
2242 1.1 mrg /**************************************
2243 1.1 mrg * Parse a version conditional
2244 1.1 mrg */
2245 1.1 mrg private AST.Condition parseVersionCondition()
2246 1.1 mrg {
2247 1.1 mrg uint level = 1;
2248 1.1 mrg Identifier id = null;
2249 1.1 mrg Loc loc;
2250 1.1 mrg
2251 1.1 mrg if (token.value == TOK.leftParenthesis)
2252 1.1 mrg {
2253 1.1 mrg nextToken();
2254 1.1 mrg /* Allow:
2255 1.1 mrg * version (unittest)
2256 1.1 mrg * version (assert)
2257 1.1 mrg * even though they are keywords
2258 1.1 mrg */
2259 1.1 mrg loc = token.loc;
2260 1.1 mrg if (token.value == TOK.identifier)
2261 1.1 mrg id = token.ident;
2262 1.1 mrg else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2263 1.1 mrg level = cast(uint)token.unsvalue;
2264 1.1 mrg else if (token.value == TOK.unittest_)
2265 1.1 mrg id = Identifier.idPool(Token.toString(TOK.unittest_));
2266 1.1 mrg else if (token.value == TOK.assert_)
2267 1.1 mrg id = Identifier.idPool(Token.toString(TOK.assert_));
2268 1.1 mrg else
2269 1.1 mrg error("identifier or integer expected inside `version(...)`, not `%s`", token.toChars());
2270 1.1 mrg nextToken();
2271 1.1 mrg check(TOK.rightParenthesis);
2272 1.1 mrg }
2273 1.1 mrg else
2274 1.1 mrg error("(condition) expected following `version`");
2275 1.1 mrg return new AST.VersionCondition(loc, mod, level, id);
2276 1.1 mrg }
2277 1.1 mrg
2278 1.1 mrg /***********************************************
2279 1.1 mrg * static if (expression)
2280 1.1 mrg * body
2281 1.1 mrg * else
2282 1.1 mrg * body
2283 1.1 mrg * Current token is 'static'.
2284 1.1 mrg */
2285 1.1 mrg private AST.Condition parseStaticIfCondition()
2286 1.1 mrg {
2287 1.1 mrg AST.Expression exp;
2288 1.1 mrg AST.Condition condition;
2289 1.1 mrg const loc = token.loc;
2290 1.1 mrg
2291 1.1 mrg nextToken();
2292 1.1 mrg nextToken();
2293 1.1 mrg if (token.value == TOK.leftParenthesis)
2294 1.1 mrg {
2295 1.1 mrg nextToken();
2296 1.1 mrg exp = parseAssignExp();
2297 1.1 mrg check(TOK.rightParenthesis);
2298 1.1 mrg }
2299 1.1 mrg else
2300 1.1 mrg {
2301 1.1 mrg error("(expression) expected following `static if`");
2302 1.1 mrg exp = null;
2303 1.1 mrg }
2304 1.1 mrg condition = new AST.StaticIfCondition(loc, exp);
2305 1.1 mrg return condition;
2306 1.1 mrg }
2307 1.1 mrg
2308 1.1 mrg /*****************************************
2309 1.1 mrg * Parse a constructor definition:
2310 1.1 mrg * this(parameters) { body }
2311 1.1 mrg * or postblit:
2312 1.1 mrg * this(this) { body }
2313 1.1 mrg * or constructor template:
2314 1.1 mrg * this(templateparameters)(parameters) { body }
2315 1.1 mrg * Current token is 'this'.
2316 1.1 mrg */
2317 1.1 mrg private AST.Dsymbol parseCtor(PrefixAttributes!AST* pAttrs)
2318 1.1 mrg {
2319 1.1 mrg AST.Expressions* udas = null;
2320 1.1 mrg const loc = token.loc;
2321 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2322 1.1 mrg
2323 1.1 mrg nextToken();
2324 1.1 mrg if (token.value == TOK.leftParenthesis && peekNext() == TOK.this_ && peekNext2() == TOK.rightParenthesis)
2325 1.1 mrg {
2326 1.1 mrg // this(this) { ... }
2327 1.1 mrg nextToken();
2328 1.1 mrg nextToken();
2329 1.1 mrg check(TOK.rightParenthesis);
2330 1.1 mrg
2331 1.1 mrg stc = parsePostfix(stc, &udas);
2332 1.1 mrg if (stc & STC.immutable_)
2333 1.1 mrg deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit.");
2334 1.1 mrg if (stc & STC.shared_)
2335 1.1 mrg deprecation("`shared` postblit is deprecated. Please use an unqualified postblit.");
2336 1.1 mrg if (stc & STC.const_)
2337 1.1 mrg deprecation("`const` postblit is deprecated. Please use an unqualified postblit.");
2338 1.1 mrg if (stc & STC.static_)
2339 1.1 mrg error(loc, "postblit cannot be `static`");
2340 1.1 mrg
2341 1.1 mrg auto f = new AST.PostBlitDeclaration(loc, Loc.initial, stc, Id.postblit);
2342 1.1 mrg AST.Dsymbol s = parseContracts(f);
2343 1.1 mrg if (udas)
2344 1.1 mrg {
2345 1.1 mrg auto a = new AST.Dsymbols();
2346 1.1 mrg a.push(f);
2347 1.1 mrg s = new AST.UserAttributeDeclaration(udas, a);
2348 1.1 mrg }
2349 1.1 mrg return s;
2350 1.1 mrg }
2351 1.1 mrg
2352 1.1 mrg /* Look ahead to see if:
2353 1.1 mrg * this(...)(...)
2354 1.1 mrg * which is a constructor template
2355 1.1 mrg */
2356 1.1 mrg AST.TemplateParameters* tpl = null;
2357 1.1 mrg if (token.value == TOK.leftParenthesis && peekPastParen(&token).value == TOK.leftParenthesis)
2358 1.1 mrg {
2359 1.1 mrg tpl = parseTemplateParameterList();
2360 1.1 mrg }
2361 1.1 mrg
2362 1.1 mrg /* Just a regular constructor
2363 1.1 mrg */
2364 1.1 mrg auto parameterList = parseParameterList(null);
2365 1.1 mrg stc = parsePostfix(stc, &udas);
2366 1.1 mrg
2367 1.1 mrg if (parameterList.varargs != VarArg.none || AST.Parameter.dim(parameterList.parameters) != 0)
2368 1.1 mrg {
2369 1.1 mrg if (stc & STC.static_)
2370 1.1 mrg error(loc, "constructor cannot be static");
2371 1.1 mrg }
2372 1.1 mrg else if (StorageClass ss = stc & (STC.shared_ | STC.static_)) // this()
2373 1.1 mrg {
2374 1.1 mrg if (ss == STC.static_)
2375 1.1 mrg error(loc, "use `static this()` to declare a static constructor");
2376 1.1 mrg else if (ss == (STC.shared_ | STC.static_))
2377 1.1 mrg error(loc, "use `shared static this()` to declare a shared static constructor");
2378 1.1 mrg }
2379 1.1 mrg
2380 1.1 mrg AST.Expression constraint = tpl ? parseConstraint() : null;
2381 1.1 mrg
2382 1.1 mrg AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // RetrunType -> auto
2383 1.1 mrg tf = tf.addSTC(stc);
2384 1.1 mrg
2385 1.1 mrg auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf);
2386 1.1 mrg AST.Dsymbol s = parseContracts(f);
2387 1.1 mrg if (udas)
2388 1.1 mrg {
2389 1.1 mrg auto a = new AST.Dsymbols();
2390 1.1 mrg a.push(f);
2391 1.1 mrg s = new AST.UserAttributeDeclaration(udas, a);
2392 1.1 mrg }
2393 1.1 mrg
2394 1.1 mrg if (tpl)
2395 1.1 mrg {
2396 1.1 mrg // Wrap a template around it
2397 1.1 mrg auto decldefs = new AST.Dsymbols();
2398 1.1 mrg decldefs.push(s);
2399 1.1 mrg s = new AST.TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs);
2400 1.1 mrg }
2401 1.1 mrg
2402 1.1 mrg return s;
2403 1.1 mrg }
2404 1.1 mrg
2405 1.1 mrg /*****************************************
2406 1.1 mrg * Parse a destructor definition:
2407 1.1 mrg * ~this() { body }
2408 1.1 mrg * Current token is '~'.
2409 1.1 mrg */
2410 1.1 mrg private AST.Dsymbol parseDtor(PrefixAttributes!AST* pAttrs)
2411 1.1 mrg {
2412 1.1 mrg AST.Expressions* udas = null;
2413 1.1 mrg const loc = token.loc;
2414 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2415 1.1 mrg
2416 1.1 mrg nextToken();
2417 1.1 mrg check(TOK.this_);
2418 1.1 mrg check(TOK.leftParenthesis);
2419 1.1 mrg check(TOK.rightParenthesis);
2420 1.1 mrg
2421 1.1 mrg stc = parsePostfix(stc, &udas);
2422 1.1 mrg if (StorageClass ss = stc & (STC.shared_ | STC.static_))
2423 1.1 mrg {
2424 1.1 mrg if (ss == STC.static_)
2425 1.1 mrg error(loc, "use `static ~this()` to declare a static destructor");
2426 1.1 mrg else if (ss == (STC.shared_ | STC.static_))
2427 1.1 mrg error(loc, "use `shared static ~this()` to declare a shared static destructor");
2428 1.1 mrg }
2429 1.1 mrg
2430 1.1 mrg auto f = new AST.DtorDeclaration(loc, Loc.initial, stc, Id.dtor);
2431 1.1 mrg AST.Dsymbol s = parseContracts(f);
2432 1.1 mrg if (udas)
2433 1.1 mrg {
2434 1.1 mrg auto a = new AST.Dsymbols();
2435 1.1 mrg a.push(f);
2436 1.1 mrg s = new AST.UserAttributeDeclaration(udas, a);
2437 1.1 mrg }
2438 1.1 mrg return s;
2439 1.1 mrg }
2440 1.1 mrg
2441 1.1 mrg /*****************************************
2442 1.1 mrg * Parse a static constructor definition:
2443 1.1 mrg * static this() { body }
2444 1.1 mrg * Current token is 'static'.
2445 1.1 mrg */
2446 1.1 mrg private AST.Dsymbol parseStaticCtor(PrefixAttributes!AST* pAttrs)
2447 1.1 mrg {
2448 1.1 mrg //Expressions *udas = NULL;
2449 1.1 mrg const loc = token.loc;
2450 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2451 1.1 mrg
2452 1.1 mrg nextToken();
2453 1.1 mrg nextToken();
2454 1.1 mrg check(TOK.leftParenthesis);
2455 1.1 mrg check(TOK.rightParenthesis);
2456 1.1 mrg
2457 1.1 mrg stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
2458 1.1 mrg if (stc & STC.shared_)
2459 1.1 mrg error(loc, "use `shared static this()` to declare a shared static constructor");
2460 1.1 mrg else if (stc & STC.static_)
2461 1.1 mrg appendStorageClass(stc, STC.static_); // complaint for the redundancy
2462 1.1 mrg else if (StorageClass modStc = stc & STC.TYPECTOR)
2463 1.1 mrg {
2464 1.1 mrg OutBuffer buf;
2465 1.1 mrg AST.stcToBuffer(&buf, modStc);
2466 1.1 mrg error(loc, "static constructor cannot be `%s`", buf.peekChars());
2467 1.1 mrg }
2468 1.1 mrg stc &= ~(STC.static_ | STC.TYPECTOR);
2469 1.1 mrg
2470 1.1 mrg auto f = new AST.StaticCtorDeclaration(loc, Loc.initial, stc);
2471 1.1 mrg AST.Dsymbol s = parseContracts(f);
2472 1.1 mrg return s;
2473 1.1 mrg }
2474 1.1 mrg
2475 1.1 mrg /*****************************************
2476 1.1 mrg * Parse a static destructor definition:
2477 1.1 mrg * static ~this() { body }
2478 1.1 mrg * Current token is 'static'.
2479 1.1 mrg */
2480 1.1 mrg private AST.Dsymbol parseStaticDtor(PrefixAttributes!AST* pAttrs)
2481 1.1 mrg {
2482 1.1 mrg AST.Expressions* udas = null;
2483 1.1 mrg const loc = token.loc;
2484 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2485 1.1 mrg
2486 1.1 mrg nextToken();
2487 1.1 mrg nextToken();
2488 1.1 mrg check(TOK.this_);
2489 1.1 mrg check(TOK.leftParenthesis);
2490 1.1 mrg check(TOK.rightParenthesis);
2491 1.1 mrg
2492 1.1 mrg stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
2493 1.1 mrg if (stc & STC.shared_)
2494 1.1 mrg error(loc, "use `shared static ~this()` to declare a shared static destructor");
2495 1.1 mrg else if (stc & STC.static_)
2496 1.1 mrg appendStorageClass(stc, STC.static_); // complaint for the redundancy
2497 1.1 mrg else if (StorageClass modStc = stc & STC.TYPECTOR)
2498 1.1 mrg {
2499 1.1 mrg OutBuffer buf;
2500 1.1 mrg AST.stcToBuffer(&buf, modStc);
2501 1.1 mrg error(loc, "static destructor cannot be `%s`", buf.peekChars());
2502 1.1 mrg }
2503 1.1 mrg stc &= ~(STC.static_ | STC.TYPECTOR);
2504 1.1 mrg
2505 1.1 mrg auto f = new AST.StaticDtorDeclaration(loc, Loc.initial, stc);
2506 1.1 mrg AST.Dsymbol s = parseContracts(f);
2507 1.1 mrg if (udas)
2508 1.1 mrg {
2509 1.1 mrg auto a = new AST.Dsymbols();
2510 1.1 mrg a.push(f);
2511 1.1 mrg s = new AST.UserAttributeDeclaration(udas, a);
2512 1.1 mrg }
2513 1.1 mrg return s;
2514 1.1 mrg }
2515 1.1 mrg
2516 1.1 mrg /*****************************************
2517 1.1 mrg * Parse a shared static constructor definition:
2518 1.1 mrg * shared static this() { body }
2519 1.1 mrg * Current token is 'shared'.
2520 1.1 mrg */
2521 1.1 mrg private AST.Dsymbol parseSharedStaticCtor(PrefixAttributes!AST* pAttrs)
2522 1.1 mrg {
2523 1.1 mrg //Expressions *udas = NULL;
2524 1.1 mrg const loc = token.loc;
2525 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2526 1.1 mrg
2527 1.1 mrg nextToken();
2528 1.1 mrg nextToken();
2529 1.1 mrg nextToken();
2530 1.1 mrg check(TOK.leftParenthesis);
2531 1.1 mrg check(TOK.rightParenthesis);
2532 1.1 mrg
2533 1.1 mrg stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
2534 1.1 mrg if (StorageClass ss = stc & (STC.shared_ | STC.static_))
2535 1.1 mrg appendStorageClass(stc, ss); // complaint for the redundancy
2536 1.1 mrg else if (StorageClass modStc = stc & STC.TYPECTOR)
2537 1.1 mrg {
2538 1.1 mrg OutBuffer buf;
2539 1.1 mrg AST.stcToBuffer(&buf, modStc);
2540 1.1 mrg error(loc, "shared static constructor cannot be `%s`", buf.peekChars());
2541 1.1 mrg }
2542 1.1 mrg stc &= ~(STC.static_ | STC.TYPECTOR);
2543 1.1 mrg
2544 1.1 mrg auto f = new AST.SharedStaticCtorDeclaration(loc, Loc.initial, stc);
2545 1.1 mrg AST.Dsymbol s = parseContracts(f);
2546 1.1 mrg return s;
2547 1.1 mrg }
2548 1.1 mrg
2549 1.1 mrg /*****************************************
2550 1.1 mrg * Parse a shared static destructor definition:
2551 1.1 mrg * shared static ~this() { body }
2552 1.1 mrg * Current token is 'shared'.
2553 1.1 mrg */
2554 1.1 mrg private AST.Dsymbol parseSharedStaticDtor(PrefixAttributes!AST* pAttrs)
2555 1.1 mrg {
2556 1.1 mrg AST.Expressions* udas = null;
2557 1.1 mrg const loc = token.loc;
2558 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2559 1.1 mrg
2560 1.1 mrg nextToken();
2561 1.1 mrg nextToken();
2562 1.1 mrg nextToken();
2563 1.1 mrg check(TOK.this_);
2564 1.1 mrg check(TOK.leftParenthesis);
2565 1.1 mrg check(TOK.rightParenthesis);
2566 1.1 mrg
2567 1.1 mrg stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
2568 1.1 mrg if (StorageClass ss = stc & (STC.shared_ | STC.static_))
2569 1.1 mrg appendStorageClass(stc, ss); // complaint for the redundancy
2570 1.1 mrg else if (StorageClass modStc = stc & STC.TYPECTOR)
2571 1.1 mrg {
2572 1.1 mrg OutBuffer buf;
2573 1.1 mrg AST.stcToBuffer(&buf, modStc);
2574 1.1 mrg error(loc, "shared static destructor cannot be `%s`", buf.peekChars());
2575 1.1 mrg }
2576 1.1 mrg stc &= ~(STC.static_ | STC.TYPECTOR);
2577 1.1 mrg
2578 1.1 mrg auto f = new AST.SharedStaticDtorDeclaration(loc, Loc.initial, stc);
2579 1.1 mrg AST.Dsymbol s = parseContracts(f);
2580 1.1 mrg if (udas)
2581 1.1 mrg {
2582 1.1 mrg auto a = new AST.Dsymbols();
2583 1.1 mrg a.push(f);
2584 1.1 mrg s = new AST.UserAttributeDeclaration(udas, a);
2585 1.1 mrg }
2586 1.1 mrg return s;
2587 1.1 mrg }
2588 1.1 mrg
2589 1.1 mrg /*****************************************
2590 1.1 mrg * Parse an invariant definition:
2591 1.1 mrg * invariant { statements... }
2592 1.1 mrg * invariant() { statements... }
2593 1.1 mrg * invariant (expression);
2594 1.1 mrg * Current token is 'invariant'.
2595 1.1 mrg */
2596 1.1 mrg private AST.Dsymbol parseInvariant(PrefixAttributes!AST* pAttrs)
2597 1.1 mrg {
2598 1.1 mrg const loc = token.loc;
2599 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2600 1.1 mrg
2601 1.1 mrg nextToken();
2602 1.1 mrg if (token.value == TOK.leftParenthesis) // optional () or invariant (expression);
2603 1.1 mrg {
2604 1.1 mrg nextToken();
2605 1.1 mrg if (token.value != TOK.rightParenthesis) // invariant (expression);
2606 1.1 mrg {
2607 1.1 mrg AST.Expression e = parseAssignExp(), msg = null;
2608 1.1 mrg if (token.value == TOK.comma)
2609 1.1 mrg {
2610 1.1 mrg nextToken();
2611 1.1 mrg if (token.value != TOK.rightParenthesis)
2612 1.1 mrg {
2613 1.1 mrg msg = parseAssignExp();
2614 1.1 mrg if (token.value == TOK.comma)
2615 1.1 mrg nextToken();
2616 1.1 mrg }
2617 1.1 mrg }
2618 1.1 mrg check(TOK.rightParenthesis);
2619 1.1 mrg check(TOK.semicolon);
2620 1.1 mrg e = new AST.AssertExp(loc, e, msg);
2621 1.1 mrg auto fbody = new AST.ExpStatement(loc, e);
2622 1.1 mrg auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody);
2623 1.1 mrg return f;
2624 1.1 mrg }
2625 1.1 mrg nextToken();
2626 1.1 mrg }
2627 1.1 mrg
2628 1.1 mrg auto fbody = parseStatement(ParseStatementFlags.curly);
2629 1.1 mrg auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody);
2630 1.1 mrg return f;
2631 1.1 mrg }
2632 1.1 mrg
2633 1.1 mrg /*****************************************
2634 1.1 mrg * Parse a unittest definition:
2635 1.1 mrg * unittest { body }
2636 1.1 mrg * Current token is 'unittest'.
2637 1.1 mrg */
2638 1.1 mrg private AST.Dsymbol parseUnitTest(PrefixAttributes!AST* pAttrs)
2639 1.1 mrg {
2640 1.1 mrg const loc = token.loc;
2641 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2642 1.1 mrg
2643 1.1 mrg nextToken();
2644 1.1 mrg
2645 1.1 mrg const(char)* begPtr = token.ptr + 1; // skip '{'
2646 1.1 mrg const(char)* endPtr = null;
2647 1.1 mrg AST.Statement sbody = parseStatement(ParseStatementFlags.curly, &endPtr);
2648 1.1 mrg
2649 1.1 mrg /** Extract unittest body as a string. Must be done eagerly since memory
2650 1.1 mrg will be released by the lexer before doc gen. */
2651 1.1 mrg char* docline = null;
2652 1.1 mrg if (global.params.doDocComments && endPtr > begPtr)
2653 1.1 mrg {
2654 1.1 mrg /* Remove trailing whitespaces */
2655 1.1 mrg for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
2656 1.1 mrg {
2657 1.1 mrg endPtr = p;
2658 1.1 mrg }
2659 1.1 mrg
2660 1.1 mrg size_t len = endPtr - begPtr;
2661 1.1 mrg if (len > 0)
2662 1.1 mrg {
2663 1.1 mrg docline = cast(char*)mem.xmalloc_noscan(len + 2);
2664 1.1 mrg memcpy(docline, begPtr, len);
2665 1.1 mrg docline[len] = '\n'; // Terminate all lines by LF
2666 1.1 mrg docline[len + 1] = '\0';
2667 1.1 mrg }
2668 1.1 mrg }
2669 1.1 mrg
2670 1.1 mrg auto f = new AST.UnitTestDeclaration(loc, token.loc, stc, docline);
2671 1.1 mrg f.fbody = sbody;
2672 1.1 mrg return f;
2673 1.1 mrg }
2674 1.1 mrg
2675 1.1 mrg /*****************************************
2676 1.1 mrg * Parse a new definition:
2677 1.1 mrg * @disable new();
2678 1.1 mrg * Current token is 'new'.
2679 1.1 mrg */
2680 1.1 mrg private AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs)
2681 1.1 mrg {
2682 1.1 mrg const loc = token.loc;
2683 1.1 mrg StorageClass stc = getStorageClass!AST(pAttrs);
2684 1.1 mrg if (!(stc & STC.disable))
2685 1.1 mrg {
2686 1.1 mrg error("`new` allocator must be annotated with `@disabled`");
2687 1.1 mrg }
2688 1.1 mrg nextToken();
2689 1.1 mrg
2690 1.1 mrg /* @@@DEPRECATED_2.108@@@
2691 1.1 mrg * After deprecation period (2.108), remove all code in the version(all) block.
2692 1.1 mrg */
2693 1.1 mrg version (all)
2694 1.1 mrg {
2695 1.1 mrg auto parameterList = parseParameterList(null); // parameterList ignored
2696 1.1 mrg if (parameterList.parameters.length > 0 || parameterList.varargs != VarArg.none)
2697 1.1 mrg deprecation("`new` allocator with non-empty parameter list is deprecated");
2698 1.1 mrg auto f = new AST.NewDeclaration(loc, stc);
2699 1.1 mrg if (token.value != TOK.semicolon)
2700 1.1 mrg {
2701 1.1 mrg deprecation("`new` allocator with function definition is deprecated");
2702 1.1 mrg parseContracts(f); // body ignored
2703 1.1 mrg f.fbody = null;
2704 1.1 mrg f.fensures = null;
2705 1.1 mrg f.frequires = null;
2706 1.1 mrg }
2707 1.1 mrg else
2708 1.1 mrg nextToken();
2709 1.1 mrg return f;
2710 1.1 mrg }
2711 1.1 mrg else
2712 1.1 mrg {
2713 1.1 mrg check(TOK.leftParenthesis);
2714 1.1 mrg check(TOK.rightParenthesis);
2715 1.1 mrg check(TOK.semicolon);
2716 1.1 mrg return new AST.NewDeclaration(loc, stc);
2717 1.1 mrg }
2718 1.1 mrg }
2719 1.1 mrg
2720 1.1 mrg /**********************************************
2721 1.1 mrg * Parse parameter list.
2722 1.1 mrg */
2723 1.1 mrg private AST.ParameterList parseParameterList(AST.TemplateParameters** tpl)
2724 1.1 mrg {
2725 1.1 mrg auto parameters = new AST.Parameters();
2726 1.1 mrg VarArg varargs = VarArg.none;
2727 1.1 mrg int hasdefault = 0;
2728 1.1 mrg StorageClass varargsStc;
2729 1.1 mrg
2730 1.1 mrg // Attributes allowed for ...
2731 1.1 mrg enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_ | STC.returnScope;
2732 1.1 mrg
2733 1.1 mrg check(TOK.leftParenthesis);
2734 1.1 mrg while (1)
2735 1.1 mrg {
2736 1.1 mrg Identifier ai = null;
2737 1.1 mrg AST.Type at;
2738 1.1 mrg StorageClass storageClass = 0;
2739 1.1 mrg StorageClass stc;
2740 1.1 mrg AST.Expression ae;
2741 1.1 mrg AST.Expressions* udas = null;
2742 1.1 mrg for (; 1; nextToken())
2743 1.1 mrg {
2744 1.1 mrg L3:
2745 1.1 mrg switch (token.value)
2746 1.1 mrg {
2747 1.1 mrg case TOK.rightParenthesis:
2748 1.1 mrg if (storageClass != 0 || udas !is null)
2749 1.1 mrg error("basic type expected, not `)`");
2750 1.1 mrg break;
2751 1.1 mrg
2752 1.1 mrg case TOK.dotDotDot:
2753 1.1 mrg varargs = VarArg.variadic;
2754 1.1 mrg varargsStc = storageClass;
2755 1.1 mrg if (varargsStc & ~VarArgsStc)
2756 1.1 mrg {
2757 1.1 mrg OutBuffer buf;
2758 1.1 mrg AST.stcToBuffer(&buf, varargsStc & ~VarArgsStc);
2759 1.1 mrg error("variadic parameter cannot have attributes `%s`", buf.peekChars());
2760 1.1 mrg varargsStc &= VarArgsStc;
2761 1.1 mrg }
2762 1.1 mrg nextToken();
2763 1.1 mrg break;
2764 1.1 mrg
2765 1.1 mrg case TOK.const_:
2766 1.1 mrg if (peekNext() == TOK.leftParenthesis)
2767 1.1 mrg goto default;
2768 1.1 mrg stc = STC.const_;
2769 1.1 mrg goto L2;
2770 1.1 mrg
2771 1.1 mrg case TOK.immutable_:
2772 1.1 mrg if (peekNext() == TOK.leftParenthesis)
2773 1.1 mrg goto default;
2774 1.1 mrg stc = STC.immutable_;
2775 1.1 mrg goto L2;
2776 1.1 mrg
2777 1.1 mrg case TOK.shared_:
2778 1.1 mrg if (peekNext() == TOK.leftParenthesis)
2779 1.1 mrg goto default;
2780 1.1 mrg stc = STC.shared_;
2781 1.1 mrg goto L2;
2782 1.1 mrg
2783 1.1 mrg case TOK.inout_:
2784 1.1 mrg if (peekNext() == TOK.leftParenthesis)
2785 1.1 mrg goto default;
2786 1.1 mrg stc = STC.wild;
2787 1.1 mrg goto L2;
2788 1.1 mrg case TOK.at:
2789 1.1 mrg {
2790 1.1 mrg AST.Expressions* exps = null;
2791 1.1 mrg StorageClass stc2 = parseAttribute(exps);
2792 1.1 mrg if (stc2 & atAttrGroup)
2793 1.1 mrg {
2794 1.1 mrg error("`@%s` attribute for function parameter is not supported", token.toChars());
2795 1.1 mrg }
2796 1.1 mrg else
2797 1.1 mrg {
2798 1.1 mrg udas = AST.UserAttributeDeclaration.concat(udas, exps);
2799 1.1 mrg }
2800 1.1 mrg if (token.value == TOK.dotDotDot)
2801 1.1 mrg error("variadic parameter cannot have user-defined attributes");
2802 1.1 mrg if (stc2)
2803 1.1 mrg nextToken();
2804 1.1 mrg goto L3;
2805 1.1 mrg // Don't call nextToken again.
2806 1.1 mrg }
2807 1.1 mrg case TOK.in_:
2808 1.1 mrg if (global.params.vin)
2809 1.1 mrg message(scanloc, "Usage of 'in' on parameter");
2810 1.1 mrg stc = STC.in_;
2811 1.1 mrg goto L2;
2812 1.1 mrg
2813 1.1 mrg case TOK.out_:
2814 1.1 mrg stc = STC.out_;
2815 1.1 mrg goto L2;
2816 1.1 mrg
2817 1.1 mrg case TOK.ref_:
2818 1.1 mrg stc = STC.ref_;
2819 1.1 mrg goto L2;
2820 1.1 mrg
2821 1.1 mrg case TOK.lazy_:
2822 1.1 mrg stc = STC.lazy_;
2823 1.1 mrg goto L2;
2824 1.1 mrg
2825 1.1 mrg case TOK.scope_:
2826 1.1 mrg stc = STC.scope_;
2827 1.1 mrg goto L2;
2828 1.1 mrg
2829 1.1 mrg case TOK.final_:
2830 1.1 mrg stc = STC.final_;
2831 1.1 mrg goto L2;
2832 1.1 mrg
2833 1.1 mrg case TOK.auto_:
2834 1.1 mrg stc = STC.auto_;
2835 1.1 mrg goto L2;
2836 1.1 mrg
2837 1.1 mrg case TOK.return_:
2838 1.1 mrg stc = STC.return_;
2839 1.1 mrg if (peekNext() == TOK.scope_)
2840 1.1 mrg stc |= STC.returnScope;
2841 1.1 mrg goto L2;
2842 1.1 mrg L2:
2843 1.1 mrg storageClass = appendStorageClass(storageClass, stc);
2844 1.1 mrg continue;
2845 1.1 mrg
2846 1.1 mrg version (none)
2847 1.1 mrg {
2848 1.1 mrg case TOK.static_:
2849 1.1 mrg stc = STC.static_;
2850 1.1 mrg goto L2;
2851 1.1 mrg
2852 1.1 mrg case TOK.auto_:
2853 1.1 mrg storageClass = STC.auto_;
2854 1.1 mrg goto L4;
2855 1.1 mrg
2856 1.1 mrg case TOK.alias_:
2857 1.1 mrg storageClass = STC.alias_;
2858 1.1 mrg goto L4;
2859 1.1 mrg L4:
2860 1.1 mrg nextToken();
2861 1.1 mrg ai = null;
2862 1.1 mrg if (token.value == TOK.identifier)
2863 1.1 mrg {
2864 1.1 mrg ai = token.ident;
2865 1.1 mrg nextToken();
2866 1.1 mrg }
2867 1.1 mrg
2868 1.1 mrg at = null; // no type
2869 1.1 mrg ae = null; // no default argument
2870 1.1 mrg if (token.value == TOK.assign) // = defaultArg
2871 1.1 mrg {
2872 1.1 mrg nextToken();
2873 1.1 mrg ae = parseDefaultInitExp();
2874 1.1 mrg hasdefault = 1;
2875 1.1 mrg }
2876 1.1 mrg else
2877 1.1 mrg {
2878 1.1 mrg if (hasdefault)
2879 1.1 mrg error("default argument expected for `alias %s`", ai ? ai.toChars() : "");
2880 1.1 mrg }
2881 1.1 mrg goto L3;
2882 1.1 mrg }
2883 1.1 mrg default:
2884 1.1 mrg {
2885 1.1 mrg stc = storageClass & (STC.IOR | STC.lazy_);
2886 1.1 mrg // if stc is not a power of 2
2887 1.1 mrg if (stc & (stc - 1) && !(stc == (STC.in_ | STC.ref_)))
2888 1.1 mrg error("incompatible parameter storage classes");
2889 1.1 mrg //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
2890 1.1 mrg //error("scope cannot be ref or out");
2891 1.1 mrg
2892 1.1 mrg if (tpl && token.value == TOK.identifier)
2893 1.1 mrg {
2894 1.1 mrg const tv = peekNext();
2895 1.1 mrg if (tv == TOK.comma || tv == TOK.rightParenthesis || tv == TOK.dotDotDot)
2896 1.1 mrg {
2897 1.1 mrg Identifier id = Identifier.generateId("__T");
2898 1.1 mrg const loc = token.loc;
2899 1.1 mrg at = new AST.TypeIdentifier(loc, id);
2900 1.1 mrg if (!*tpl)
2901 1.1 mrg *tpl = new AST.TemplateParameters();
2902 1.1 mrg AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null);
2903 1.1 mrg (*tpl).push(tp);
2904 1.1 mrg
2905 1.1 mrg ai = token.ident;
2906 1.1 mrg nextToken();
2907 1.1 mrg }
2908 1.1 mrg else goto _else;
2909 1.1 mrg }
2910 1.1 mrg else
2911 1.1 mrg {
2912 1.1 mrg _else:
2913 1.1 mrg at = parseType(&ai);
2914 1.1 mrg }
2915 1.1 mrg ae = null;
2916 1.1 mrg if (token.value == TOK.assign) // = defaultArg
2917 1.1 mrg {
2918 1.1 mrg nextToken();
2919 1.1 mrg ae = parseDefaultInitExp();
2920 1.1 mrg hasdefault = 1;
2921 1.1 mrg }
2922 1.1 mrg else
2923 1.1 mrg {
2924 1.1 mrg if (hasdefault)
2925 1.1 mrg error("default argument expected for `%s`", ai ? ai.toChars() : at.toChars());
2926 1.1 mrg }
2927 1.1 mrg auto param = new AST.Parameter(storageClass | STC.parameter, at, ai, ae, null);
2928 1.1 mrg if (udas)
2929 1.1 mrg {
2930 1.1 mrg auto a = new AST.Dsymbols();
2931 1.1 mrg auto udad = new AST.UserAttributeDeclaration(udas, a);
2932 1.1 mrg param.userAttribDecl = udad;
2933 1.1 mrg }
2934 1.1 mrg if (token.value == TOK.at)
2935 1.1 mrg {
2936 1.1 mrg AST.Expressions* exps = null;
2937 1.1 mrg StorageClass stc2 = parseAttribute(exps);
2938 1.1 mrg if (stc2 & atAttrGroup)
2939 1.1 mrg {
2940 1.1 mrg error("`@%s` attribute for function parameter is not supported", token.toChars());
2941 1.1 mrg }
2942 1.1 mrg else
2943 1.1 mrg {
2944 1.1 mrg error("user-defined attributes cannot appear as postfixes", token.toChars());
2945 1.1 mrg }
2946 1.1 mrg if (stc2)
2947 1.1 mrg nextToken();
2948 1.1 mrg }
2949 1.1 mrg if (token.value == TOK.dotDotDot)
2950 1.1 mrg {
2951 1.1 mrg /* This is:
2952 1.1 mrg * at ai ...
2953 1.1 mrg */
2954 1.1 mrg if (storageClass & (STC.out_ | STC.ref_))
2955 1.1 mrg error("variadic argument cannot be `out` or `ref`");
2956 1.1 mrg varargs = VarArg.typesafe;
2957 1.1 mrg parameters.push(param);
2958 1.1 mrg nextToken();
2959 1.1 mrg break;
2960 1.1 mrg }
2961 1.1 mrg parameters.push(param);
2962 1.1 mrg if (token.value == TOK.comma)
2963 1.1 mrg {
2964 1.1 mrg nextToken();
2965 1.1 mrg goto L1;
2966 1.1 mrg }
2967 1.1 mrg break;
2968 1.1 mrg }
2969 1.1 mrg }
2970 1.1 mrg break;
2971 1.1 mrg }
2972 1.1 mrg break;
2973 1.1 mrg
2974 1.1 mrg L1:
2975 1.1 mrg }
2976 1.1 mrg check(TOK.rightParenthesis);
2977 1.1 mrg return AST.ParameterList(parameters, varargs, varargsStc);
2978 1.1 mrg }
2979 1.1 mrg
2980 1.1 mrg /*************************************
2981 1.1 mrg */
2982 1.1 mrg private AST.EnumDeclaration parseEnum()
2983 1.1 mrg {
2984 1.1 mrg AST.EnumDeclaration e;
2985 1.1 mrg Identifier id;
2986 1.1 mrg AST.Type memtype;
2987 1.1 mrg auto loc = token.loc;
2988 1.1 mrg
2989 1.1 mrg // printf("Parser::parseEnum()\n");
2990 1.1 mrg nextToken();
2991 1.1 mrg id = null;
2992 1.1 mrg if (token.value == TOK.identifier)
2993 1.1 mrg {
2994 1.1 mrg id = token.ident;
2995 1.1 mrg nextToken();
2996 1.1 mrg }
2997 1.1 mrg
2998 1.1 mrg memtype = null;
2999 1.1 mrg if (token.value == TOK.colon)
3000 1.1 mrg {
3001 1.1 mrg nextToken();
3002 1.1 mrg int alt = 0;
3003 1.1 mrg const typeLoc = token.loc;
3004 1.1 mrg memtype = parseBasicType();
3005 1.1 mrg memtype = parseDeclarator(memtype, alt, null);
3006 1.1 mrg checkCstyleTypeSyntax(typeLoc, memtype, alt, null);
3007 1.1 mrg }
3008 1.1 mrg
3009 1.1 mrg e = new AST.EnumDeclaration(loc, id, memtype);
3010 1.1 mrg if (token.value == TOK.semicolon && id)
3011 1.1 mrg nextToken();
3012 1.1 mrg else if (token.value == TOK.leftCurly)
3013 1.1 mrg {
3014 1.1 mrg bool isAnonymousEnum = !id;
3015 1.1 mrg TOK prevTOK;
3016 1.1 mrg
3017 1.1 mrg //printf("enum definition\n");
3018 1.1 mrg e.members = new AST.Dsymbols();
3019 1.1 mrg nextToken();
3020 1.1 mrg const(char)[] comment = token.blockComment;
3021 1.1 mrg while (token.value != TOK.rightCurly)
3022 1.1 mrg {
3023 1.1 mrg /* Can take the following forms...
3024 1.1 mrg * 1. ident
3025 1.1 mrg * 2. ident = value
3026 1.1 mrg * 3. type ident = value
3027 1.1 mrg * ... prefixed by valid attributes
3028 1.1 mrg */
3029 1.1 mrg loc = token.loc;
3030 1.1 mrg
3031 1.1 mrg AST.Type type = null;
3032 1.1 mrg Identifier ident = null;
3033 1.1 mrg
3034 1.1 mrg AST.Expressions* udas;
3035 1.1 mrg StorageClass stc;
3036 1.1 mrg AST.Expression deprecationMessage;
3037 1.1 mrg enum attributeErrorMessage = "`%s` is not a valid attribute for enum members";
3038 1.1 mrg while(token.value != TOK.rightCurly
3039 1.1 mrg && token.value != TOK.comma
3040 1.1 mrg && token.value != TOK.assign)
3041 1.1 mrg {
3042 1.1 mrg switch(token.value)
3043 1.1 mrg {
3044 1.1 mrg case TOK.at:
3045 1.1 mrg if (StorageClass _stc = parseAttribute(udas))
3046 1.1 mrg {
3047 1.1 mrg if (_stc == STC.disable)
3048 1.1 mrg stc |= _stc;
3049 1.1 mrg else
3050 1.1 mrg {
3051 1.1 mrg OutBuffer buf;
3052 1.1 mrg AST.stcToBuffer(&buf, _stc);
3053 1.1 mrg error(attributeErrorMessage, buf.peekChars());
3054 1.1 mrg }
3055 1.1 mrg prevTOK = token.value;
3056 1.1 mrg nextToken();
3057 1.1 mrg }
3058 1.1 mrg break;
3059 1.1 mrg case TOK.deprecated_:
3060 1.1 mrg stc |= STC.deprecated_;
3061 1.1 mrg if (!parseDeprecatedAttribute(deprecationMessage))
3062 1.1 mrg {
3063 1.1 mrg prevTOK = token.value;
3064 1.1 mrg nextToken();
3065 1.1 mrg }
3066 1.1 mrg break;
3067 1.1 mrg case TOK.identifier:
3068 1.1 mrg const tv = peekNext();
3069 1.1 mrg if (tv == TOK.assign || tv == TOK.comma || tv == TOK.rightCurly)
3070 1.1 mrg {
3071 1.1 mrg ident = token.ident;
3072 1.1 mrg type = null;
3073 1.1 mrg prevTOK = token.value;
3074 1.1 mrg nextToken();
3075 1.1 mrg }
3076 1.1 mrg else
3077 1.1 mrg {
3078 1.1 mrg goto default;
3079 1.1 mrg }
3080 1.1 mrg break;
3081 1.1 mrg default:
3082 1.1 mrg if (isAnonymousEnum)
3083 1.1 mrg {
3084 1.1 mrg type = parseType(&ident, null);
3085 1.1 mrg if (type == AST.Type.terror)
3086 1.1 mrg {
3087 1.1 mrg type = null;
3088 1.1 mrg prevTOK = token.value;
3089 1.1 mrg nextToken();
3090 1.1 mrg }
3091 1.1 mrg else
3092 1.1 mrg {
3093 1.1 mrg prevTOK = TOK.identifier;
3094 1.1 mrg }
3095 1.1 mrg }
3096 1.1 mrg else
3097 1.1 mrg {
3098 1.1 mrg error(attributeErrorMessage, token.toChars());
3099 1.1 mrg prevTOK = token.value;
3100 1.1 mrg nextToken();
3101 1.1 mrg }
3102 1.1 mrg break;
3103 1.1 mrg }
3104 1.1 mrg if (token.value == TOK.comma)
3105 1.1 mrg {
3106 1.1 mrg prevTOK = token.value;
3107 1.1 mrg }
3108 1.1 mrg }
3109 1.1 mrg
3110 1.1 mrg if (type && type != AST.Type.terror)
3111 1.1 mrg {
3112 1.1 mrg if (!ident)
3113 1.1 mrg error("no identifier for declarator `%s`", type.toChars());
3114 1.1 mrg if (!isAnonymousEnum)
3115 1.1 mrg error("type only allowed if anonymous enum and no enum type");
3116 1.1 mrg }
3117 1.1 mrg AST.Expression value;
3118 1.1 mrg if (token.value == TOK.assign)
3119 1.1 mrg {
3120 1.1 mrg if (prevTOK == TOK.identifier)
3121 1.1 mrg {
3122 1.1 mrg nextToken();
3123 1.1 mrg value = parseAssignExp();
3124 1.1 mrg }
3125 1.1 mrg else
3126 1.1 mrg {
3127 1.1 mrg error("assignment must be preceded by an identifier");
3128 1.1 mrg nextToken();
3129 1.1 mrg }
3130 1.1 mrg }
3131 1.1 mrg else
3132 1.1 mrg {
3133 1.1 mrg value = null;
3134 1.1 mrg if (type && type != AST.Type.terror && isAnonymousEnum)
3135 1.1 mrg error("if type, there must be an initializer");
3136 1.1 mrg }
3137 1.1 mrg
3138 1.1 mrg AST.DeprecatedDeclaration dd;
3139 1.1 mrg if (deprecationMessage)
3140 1.1 mrg {
3141 1.1 mrg dd = new AST.DeprecatedDeclaration(deprecationMessage, null);
3142 1.1 mrg stc |= STC.deprecated_;
3143 1.1 mrg }
3144 1.1 mrg
3145 1.1 mrg auto em = new AST.EnumMember(loc, ident, value, type, stc, null, dd);
3146 1.1 mrg e.members.push(em);
3147 1.1 mrg
3148 1.1 mrg if (udas)
3149 1.1 mrg {
3150 1.1 mrg auto s = new AST.Dsymbols();
3151 1.1 mrg s.push(em);
3152 1.1 mrg auto uad = new AST.UserAttributeDeclaration(udas, s);
3153 1.1 mrg em.userAttribDecl = uad;
3154 1.1 mrg }
3155 1.1 mrg
3156 1.1 mrg if (token.value == TOK.rightCurly)
3157 1.1 mrg {
3158 1.1 mrg }
3159 1.1 mrg else
3160 1.1 mrg {
3161 1.1 mrg addComment(em, comment);
3162 1.1 mrg comment = null;
3163 1.1 mrg check(TOK.comma);
3164 1.1 mrg }
3165 1.1 mrg addComment(em, comment);
3166 1.1 mrg comment = token.blockComment;
3167 1.1 mrg
3168 1.1 mrg if (token.value == TOK.endOfFile)
3169 1.1 mrg {
3170 1.1 mrg error("premature end of file");
3171 1.1 mrg break;
3172 1.1 mrg }
3173 1.1 mrg }
3174 1.1 mrg nextToken();
3175 1.1 mrg }
3176 1.1 mrg else
3177 1.1 mrg error("enum declaration is invalid");
3178 1.1 mrg
3179 1.1 mrg //printf("-parseEnum() %s\n", e.toChars());
3180 1.1 mrg return e;
3181 1.1 mrg }
3182 1.1 mrg
3183 1.1 mrg /********************************
3184 1.1 mrg * Parse struct, union, interface, class.
3185 1.1 mrg */
3186 1.1 mrg private AST.Dsymbol parseAggregate()
3187 1.1 mrg {
3188 1.1 mrg AST.TemplateParameters* tpl = null;
3189 1.1 mrg AST.Expression constraint;
3190 1.1 mrg const loc = token.loc;
3191 1.1 mrg TOK tok = token.value;
3192 1.1 mrg
3193 1.1 mrg //printf("Parser::parseAggregate()\n");
3194 1.1 mrg nextToken();
3195 1.1 mrg Identifier id;
3196 1.1 mrg if (token.value != TOK.identifier)
3197 1.1 mrg {
3198 1.1 mrg id = null;
3199 1.1 mrg }
3200 1.1 mrg else
3201 1.1 mrg {
3202 1.1 mrg id = token.ident;
3203 1.1 mrg nextToken();
3204 1.1 mrg
3205 1.1 mrg if (token.value == TOK.leftParenthesis)
3206 1.1 mrg {
3207 1.1 mrg // struct/class template declaration.
3208 1.1 mrg tpl = parseTemplateParameterList();
3209 1.1 mrg constraint = parseConstraint();
3210 1.1 mrg }
3211 1.1 mrg }
3212 1.1 mrg
3213 1.1 mrg // Collect base class(es)
3214 1.1 mrg AST.BaseClasses* baseclasses = null;
3215 1.1 mrg if (token.value == TOK.colon)
3216 1.1 mrg {
3217 1.1 mrg if (tok != TOK.interface_ && tok != TOK.class_)
3218 1.1 mrg error("base classes are not allowed for `%s`, did you mean `;`?", Token.toChars(tok));
3219 1.1 mrg nextToken();
3220 1.1 mrg baseclasses = parseBaseClasses();
3221 1.1 mrg }
3222 1.1 mrg
3223 1.1 mrg if (token.value == TOK.if_)
3224 1.1 mrg {
3225 1.1 mrg if (constraint)
3226 1.1 mrg error("template constraints appear both before and after BaseClassList, put them before");
3227 1.1 mrg constraint = parseConstraint();
3228 1.1 mrg }
3229 1.1 mrg if (constraint)
3230 1.1 mrg {
3231 1.1 mrg if (!id)
3232 1.1 mrg error("template constraints not allowed for anonymous `%s`", Token.toChars(tok));
3233 1.1 mrg if (!tpl)
3234 1.1 mrg error("template constraints only allowed for templates");
3235 1.1 mrg }
3236 1.1 mrg
3237 1.1 mrg AST.Dsymbols* members = null;
3238 1.1 mrg if (token.value == TOK.leftCurly)
3239 1.1 mrg {
3240 1.1 mrg //printf("aggregate definition\n");
3241 1.1 mrg const lookingForElseSave = lookingForElse;
3242 1.1 mrg lookingForElse = Loc();
3243 1.1 mrg nextToken();
3244 1.1 mrg members = parseDeclDefs(0);
3245 1.1 mrg lookingForElse = lookingForElseSave;
3246 1.1 mrg if (token.value != TOK.rightCurly)
3247 1.1 mrg {
3248 1.1 mrg /* { */
3249 1.1 mrg error("`}` expected following members in `%s` declaration at %s",
3250 1.1 mrg Token.toChars(tok), loc.toChars());
3251 1.1 mrg }
3252 1.1 mrg nextToken();
3253 1.1 mrg }
3254 1.1 mrg else if (token.value == TOK.semicolon && id)
3255 1.1 mrg {
3256 1.1 mrg if (baseclasses || constraint)
3257 1.1 mrg error("members expected");
3258 1.1 mrg nextToken();
3259 1.1 mrg }
3260 1.1 mrg else
3261 1.1 mrg {
3262 1.1 mrg error("{ } expected following `%s` declaration", Token.toChars(tok));
3263 1.1 mrg }
3264 1.1 mrg
3265 1.1 mrg AST.AggregateDeclaration a;
3266 1.1 mrg switch (tok)
3267 1.1 mrg {
3268 1.1 mrg case TOK.interface_:
3269 1.1 mrg if (!id)
3270 1.1 mrg error(loc, "anonymous interfaces not allowed");
3271 1.1 mrg a = new AST.InterfaceDeclaration(loc, id, baseclasses);
3272 1.1 mrg a.members = members;
3273 1.1 mrg break;
3274 1.1 mrg
3275 1.1 mrg case TOK.class_:
3276 1.1 mrg if (!id)
3277 1.1 mrg error(loc, "anonymous classes not allowed");
3278 1.1 mrg bool inObject = md && !md.packages && md.id == Id.object;
3279 1.1 mrg a = new AST.ClassDeclaration(loc, id, baseclasses, members, inObject);
3280 1.1 mrg break;
3281 1.1 mrg
3282 1.1 mrg case TOK.struct_:
3283 1.1 mrg if (id)
3284 1.1 mrg {
3285 1.1 mrg bool inObject = md && !md.packages && md.id == Id.object;
3286 1.1 mrg a = new AST.StructDeclaration(loc, id, inObject);
3287 1.1 mrg a.members = members;
3288 1.1 mrg }
3289 1.1 mrg else
3290 1.1 mrg {
3291 1.1 mrg /* Anonymous structs/unions are more like attributes.
3292 1.1 mrg */
3293 1.1 mrg assert(!tpl);
3294 1.1 mrg return new AST.AnonDeclaration(loc, false, members);
3295 1.1 mrg }
3296 1.1 mrg break;
3297 1.1 mrg
3298 1.1 mrg case TOK.union_:
3299 1.1 mrg if (id)
3300 1.1 mrg {
3301 1.1 mrg a = new AST.UnionDeclaration(loc, id);
3302 1.1 mrg a.members = members;
3303 1.1 mrg }
3304 1.1 mrg else
3305 1.1 mrg {
3306 1.1 mrg /* Anonymous structs/unions are more like attributes.
3307 1.1 mrg */
3308 1.1 mrg assert(!tpl);
3309 1.1 mrg return new AST.AnonDeclaration(loc, true, members);
3310 1.1 mrg }
3311 1.1 mrg break;
3312 1.1 mrg
3313 1.1 mrg default:
3314 1.1 mrg assert(0);
3315 1.1 mrg }
3316 1.1 mrg
3317 1.1 mrg if (tpl)
3318 1.1 mrg {
3319 1.1 mrg // Wrap a template around the aggregate declaration
3320 1.1 mrg auto decldefs = new AST.Dsymbols();
3321 1.1 mrg decldefs.push(a);
3322 1.1 mrg auto tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs);
3323 1.1 mrg return tempdecl;
3324 1.1 mrg }
3325 1.1 mrg return a;
3326 1.1 mrg }
3327 1.1 mrg
3328 1.1 mrg /*******************************************
3329 1.1 mrg */
3330 1.1 mrg private AST.BaseClasses* parseBaseClasses()
3331 1.1 mrg {
3332 1.1 mrg auto baseclasses = new AST.BaseClasses();
3333 1.1 mrg
3334 1.1 mrg for (; 1; nextToken())
3335 1.1 mrg {
3336 1.1 mrg auto b = new AST.BaseClass(parseBasicType());
3337 1.1 mrg baseclasses.push(b);
3338 1.1 mrg if (token.value != TOK.comma)
3339 1.1 mrg break;
3340 1.1 mrg }
3341 1.1 mrg return baseclasses;
3342 1.1 mrg }
3343 1.1 mrg
3344 1.1 mrg AST.Dsymbols* parseImport()
3345 1.1 mrg {
3346 1.1 mrg auto decldefs = new AST.Dsymbols();
3347 1.1 mrg Identifier aliasid = null;
3348 1.1 mrg
3349 1.1 mrg int isstatic = token.value == TOK.static_;
3350 1.1 mrg if (isstatic)
3351 1.1 mrg nextToken();
3352 1.1 mrg
3353 1.1 mrg //printf("Parser::parseImport()\n");
3354 1.1 mrg do
3355 1.1 mrg {
3356 1.1 mrg L1:
3357 1.1 mrg nextToken();
3358 1.1 mrg if (token.value != TOK.identifier)
3359 1.1 mrg {
3360 1.1 mrg error("identifier expected following `import`");
3361 1.1 mrg break;
3362 1.1 mrg }
3363 1.1 mrg
3364 1.1 mrg const loc = token.loc;
3365 1.1 mrg Identifier id = token.ident;
3366 1.1 mrg Identifier[] a;
3367 1.1 mrg nextToken();
3368 1.1 mrg if (!aliasid && token.value == TOK.assign)
3369 1.1 mrg {
3370 1.1 mrg aliasid = id;
3371 1.1 mrg goto L1;
3372 1.1 mrg }
3373 1.1 mrg while (token.value == TOK.dot)
3374 1.1 mrg {
3375 1.1 mrg a ~= id;
3376 1.1 mrg nextToken();
3377 1.1 mrg if (token.value != TOK.identifier)
3378 1.1 mrg {
3379 1.1 mrg error("identifier expected following `package`");
3380 1.1 mrg break;
3381 1.1 mrg }
3382 1.1 mrg id = token.ident;
3383 1.1 mrg nextToken();
3384 1.1 mrg }
3385 1.1 mrg
3386 1.1 mrg auto s = new AST.Import(loc, a, id, aliasid, isstatic);
3387 1.1 mrg decldefs.push(s);
3388 1.1 mrg
3389 1.1 mrg /* Look for
3390 1.1 mrg * : alias=name, alias=name;
3391 1.1 mrg * syntax.
3392 1.1 mrg */
3393 1.1 mrg if (token.value == TOK.colon)
3394 1.1 mrg {
3395 1.1 mrg do
3396 1.1 mrg {
3397 1.1 mrg nextToken();
3398 1.1 mrg if (token.value != TOK.identifier)
3399 1.1 mrg {
3400 1.1 mrg error("identifier expected following `:`");
3401 1.1 mrg break;
3402 1.1 mrg }
3403 1.1 mrg Identifier _alias = token.ident;
3404 1.1 mrg Identifier name;
3405 1.1 mrg nextToken();
3406 1.1 mrg if (token.value == TOK.assign)
3407 1.1 mrg {
3408 1.1 mrg nextToken();
3409 1.1 mrg if (token.value != TOK.identifier)
3410 1.1 mrg {
3411 1.1 mrg error("identifier expected following `%s=`", _alias.toChars());
3412 1.1 mrg break;
3413 1.1 mrg }
3414 1.1 mrg name = token.ident;
3415 1.1 mrg nextToken();
3416 1.1 mrg }
3417 1.1 mrg else
3418 1.1 mrg {
3419 1.1 mrg name = _alias;
3420 1.1 mrg _alias = null;
3421 1.1 mrg }
3422 1.1 mrg s.addAlias(name, _alias);
3423 1.1 mrg }
3424 1.1 mrg while (token.value == TOK.comma);
3425 1.1 mrg break; // no comma-separated imports of this form
3426 1.1 mrg }
3427 1.1 mrg aliasid = null;
3428 1.1 mrg }
3429 1.1 mrg while (token.value == TOK.comma);
3430 1.1 mrg
3431 1.1 mrg if (token.value == TOK.semicolon)
3432 1.1 mrg nextToken();
3433 1.1 mrg else
3434 1.1 mrg {
3435 1.1 mrg error("`;` expected");
3436 1.1 mrg nextToken();
3437 1.1 mrg }
3438 1.1 mrg
3439 1.1 mrg return decldefs;
3440 1.1 mrg }
3441 1.1 mrg
3442 1.1 mrg AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null)
3443 1.1 mrg {
3444 1.1 mrg /* Take care of the storage class prefixes that
3445 1.1 mrg * serve as type attributes:
3446 1.1 mrg * const type
3447 1.1 mrg * immutable type
3448 1.1 mrg * shared type
3449 1.1 mrg * inout type
3450 1.1 mrg * inout const type
3451 1.1 mrg * shared const type
3452 1.1 mrg * shared inout type
3453 1.1 mrg * shared inout const type
3454 1.1 mrg */
3455 1.1 mrg StorageClass stc = 0;
3456 1.1 mrg while (1)
3457 1.1 mrg {
3458 1.1 mrg switch (token.value)
3459 1.1 mrg {
3460 1.1 mrg case TOK.const_:
3461 1.1 mrg if (peekNext() == TOK.leftParenthesis)
3462 1.1 mrg break; // const as type constructor
3463 1.1 mrg stc |= STC.const_; // const as storage class
3464 1.1 mrg nextToken();
3465 1.1 mrg continue;
3466 1.1 mrg
3467 1.1 mrg case TOK.immutable_:
3468 1.1 mrg if (peekNext() == TOK.leftParenthesis)
3469 1.1 mrg break;
3470 1.1 mrg stc |= STC.immutable_;
3471 1.1 mrg nextToken();
3472 1.1 mrg continue;
3473 1.1 mrg
3474 1.1 mrg case TOK.shared_:
3475 1.1 mrg if (peekNext() == TOK.leftParenthesis)
3476 1.1 mrg break;
3477 1.1 mrg stc |= STC.shared_;
3478 1.1 mrg nextToken();
3479 1.1 mrg continue;
3480 1.1 mrg
3481 1.1 mrg case TOK.inout_:
3482 1.1 mrg if (peekNext() == TOK.leftParenthesis)
3483 1.1 mrg break;
3484 1.1 mrg stc |= STC.wild;
3485 1.1 mrg nextToken();
3486 1.1 mrg continue;
3487 1.1 mrg
3488 1.1 mrg default:
3489 1.1 mrg break;
3490 1.1 mrg }
3491 1.1 mrg break;
3492 1.1 mrg }
3493 1.1 mrg
3494 1.1 mrg const typeLoc = token.loc;
3495 1.1 mrg
3496 1.1 mrg AST.Type t;
3497 1.1 mrg t = parseBasicType();
3498 1.1 mrg
3499 1.1 mrg int alt = 0;
3500 1.1 mrg t = parseDeclarator(t, alt, pident, ptpl);
3501 1.1 mrg checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : null);
3502 1.1 mrg
3503 1.1 mrg t = t.addSTC(stc);
3504 1.1 mrg return t;
3505 1.1 mrg }
3506 1.1 mrg
3507 1.1 mrg private AST.Type parseBasicType(bool dontLookDotIdents = false)
3508 1.1 mrg {
3509 1.1 mrg AST.Type t;
3510 1.1 mrg Loc loc;
3511 1.1 mrg Identifier id;
3512 1.1 mrg //printf("parseBasicType()\n");
3513 1.1 mrg switch (token.value)
3514 1.1 mrg {
3515 1.1 mrg case TOK.void_:
3516 1.1 mrg t = AST.Type.tvoid;
3517 1.1 mrg goto LabelX;
3518 1.1 mrg
3519 1.1 mrg case TOK.int8:
3520 1.1 mrg t = AST.Type.tint8;
3521 1.1 mrg goto LabelX;
3522 1.1 mrg
3523 1.1 mrg case TOK.uns8:
3524 1.1 mrg t = AST.Type.tuns8;
3525 1.1 mrg goto LabelX;
3526 1.1 mrg
3527 1.1 mrg case TOK.int16:
3528 1.1 mrg t = AST.Type.tint16;
3529 1.1 mrg goto LabelX;
3530 1.1 mrg
3531 1.1 mrg case TOK.uns16:
3532 1.1 mrg t = AST.Type.tuns16;
3533 1.1 mrg goto LabelX;
3534 1.1 mrg
3535 1.1 mrg case TOK.int32:
3536 1.1 mrg t = AST.Type.tint32;
3537 1.1 mrg goto LabelX;
3538 1.1 mrg
3539 1.1 mrg case TOK.uns32:
3540 1.1 mrg t = AST.Type.tuns32;
3541 1.1 mrg goto LabelX;
3542 1.1 mrg
3543 1.1 mrg case TOK.int64:
3544 1.1 mrg t = AST.Type.tint64;
3545 1.1 mrg nextToken();
3546 1.1 mrg if (token.value == TOK.int64) // if `long long`
3547 1.1 mrg {
3548 1.1 mrg error("use `long` for a 64 bit integer instead of `long long`");
3549 1.1 mrg nextToken();
3550 1.1 mrg }
3551 1.1 mrg else if (token.value == TOK.float64) // if `long double`
3552 1.1 mrg {
3553 1.1 mrg error("use `real` instead of `long double`");
3554 1.1 mrg t = AST.Type.tfloat80;
3555 1.1 mrg nextToken();
3556 1.1 mrg }
3557 1.1 mrg break;
3558 1.1 mrg
3559 1.1 mrg case TOK.uns64:
3560 1.1 mrg t = AST.Type.tuns64;
3561 1.1 mrg goto LabelX;
3562 1.1 mrg
3563 1.1 mrg case TOK.int128:
3564 1.1 mrg t = AST.Type.tint128;
3565 1.1 mrg goto LabelX;
3566 1.1 mrg
3567 1.1 mrg case TOK.uns128:
3568 1.1 mrg t = AST.Type.tuns128;
3569 1.1 mrg goto LabelX;
3570 1.1 mrg
3571 1.1 mrg case TOK.float32:
3572 1.1 mrg t = AST.Type.tfloat32;
3573 1.1 mrg goto LabelX;
3574 1.1 mrg
3575 1.1 mrg case TOK.float64:
3576 1.1 mrg t = AST.Type.tfloat64;
3577 1.1 mrg goto LabelX;
3578 1.1 mrg
3579 1.1 mrg case TOK.float80:
3580 1.1 mrg t = AST.Type.tfloat80;
3581 1.1 mrg goto LabelX;
3582 1.1 mrg
3583 1.1 mrg case TOK.imaginary32:
3584 1.1 mrg t = AST.Type.timaginary32;
3585 1.1 mrg goto LabelX;
3586 1.1 mrg
3587 1.1 mrg case TOK.imaginary64:
3588 1.1 mrg t = AST.Type.timaginary64;
3589 1.1 mrg goto LabelX;
3590 1.1 mrg
3591 1.1 mrg case TOK.imaginary80:
3592 1.1 mrg t = AST.Type.timaginary80;
3593 1.1 mrg goto LabelX;
3594 1.1 mrg
3595 1.1 mrg case TOK.complex32:
3596 1.1 mrg t = AST.Type.tcomplex32;
3597 1.1 mrg goto LabelX;
3598 1.1 mrg
3599 1.1 mrg case TOK.complex64:
3600 1.1 mrg t = AST.Type.tcomplex64;
3601 1.1 mrg goto LabelX;
3602 1.1 mrg
3603 1.1 mrg case TOK.complex80:
3604 1.1 mrg t = AST.Type.tcomplex80;
3605 1.1 mrg goto LabelX;
3606 1.1 mrg
3607 1.1 mrg case TOK.bool_:
3608 1.1 mrg t = AST.Type.tbool;
3609 1.1 mrg goto LabelX;
3610 1.1 mrg
3611 1.1 mrg case TOK.char_:
3612 1.1 mrg t = AST.Type.tchar;
3613 1.1 mrg goto LabelX;
3614 1.1 mrg
3615 1.1 mrg case TOK.wchar_:
3616 1.1 mrg t = AST.Type.twchar;
3617 1.1 mrg goto LabelX;
3618 1.1 mrg
3619 1.1 mrg case TOK.dchar_:
3620 1.1 mrg t = AST.Type.tdchar;
3621 1.1 mrg goto LabelX;
3622 1.1 mrg LabelX:
3623 1.1 mrg nextToken();
3624 1.1 mrg break;
3625 1.1 mrg
3626 1.1 mrg case TOK.this_:
3627 1.1 mrg case TOK.super_:
3628 1.1 mrg case TOK.identifier:
3629 1.1 mrg loc = token.loc;
3630 1.1 mrg id = token.ident;
3631 1.1 mrg nextToken();
3632 1.1 mrg if (token.value == TOK.not)
3633 1.1 mrg {
3634 1.1 mrg // ident!(template_arguments)
3635 1.1 mrg auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
3636 1.1 mrg t = parseBasicTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents);
3637 1.1 mrg }
3638 1.1 mrg else
3639 1.1 mrg {
3640 1.1 mrg t = parseBasicTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents);
3641 1.1 mrg }
3642 1.1 mrg break;
3643 1.1 mrg
3644 1.1 mrg case TOK.mixin_:
3645 1.1 mrg // https://dlang.org/spec/expression.html#mixin_types
3646 1.1 mrg loc = token.loc;
3647 1.1 mrg nextToken();
3648 1.1 mrg if (token.value != TOK.leftParenthesis)
3649 1.1 mrg error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
3650 1.1 mrg auto exps = parseArguments();
3651 1.1 mrg t = new AST.TypeMixin(loc, exps);
3652 1.1 mrg break;
3653 1.1 mrg
3654 1.1 mrg case TOK.dot:
3655 1.1 mrg // Leading . as in .foo
3656 1.1 mrg t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents);
3657 1.1 mrg break;
3658 1.1 mrg
3659 1.1 mrg case TOK.typeof_:
3660 1.1 mrg // typeof(expression)
3661 1.1 mrg t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
3662 1.1 mrg break;
3663 1.1 mrg
3664 1.1 mrg case TOK.vector:
3665 1.1 mrg t = parseVector();
3666 1.1 mrg break;
3667 1.1 mrg
3668 1.1 mrg case TOK.traits:
3669 1.1 mrg if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
3670 1.1 mrg if (te.ident)
3671 1.1 mrg {
3672 1.1 mrg t = new AST.TypeTraits(token.loc, te);
3673 1.1 mrg break;
3674 1.1 mrg }
3675 1.1 mrg t = new AST.TypeError;
3676 1.1 mrg break;
3677 1.1 mrg
3678 1.1 mrg case TOK.const_:
3679 1.1 mrg // const(type)
3680 1.1 mrg nextToken();
3681 1.1 mrg check(TOK.leftParenthesis);
3682 1.1 mrg t = parseType().addSTC(STC.const_);
3683 1.1 mrg check(TOK.rightParenthesis);
3684 1.1 mrg break;
3685 1.1 mrg
3686 1.1 mrg case TOK.immutable_:
3687 1.1 mrg // immutable(type)
3688 1.1 mrg nextToken();
3689 1.1 mrg check(TOK.leftParenthesis);
3690 1.1 mrg t = parseType().addSTC(STC.immutable_);
3691 1.1 mrg check(TOK.rightParenthesis);
3692 1.1 mrg break;
3693 1.1 mrg
3694 1.1 mrg case TOK.shared_:
3695 1.1 mrg // shared(type)
3696 1.1 mrg nextToken();
3697 1.1 mrg check(TOK.leftParenthesis);
3698 1.1 mrg t = parseType().addSTC(STC.shared_);
3699 1.1 mrg check(TOK.rightParenthesis);
3700 1.1 mrg break;
3701 1.1 mrg
3702 1.1 mrg case TOK.inout_:
3703 1.1 mrg // wild(type)
3704 1.1 mrg nextToken();
3705 1.1 mrg check(TOK.leftParenthesis);
3706 1.1 mrg t = parseType().addSTC(STC.wild);
3707 1.1 mrg check(TOK.rightParenthesis);
3708 1.1 mrg break;
3709 1.1 mrg
3710 1.1 mrg default:
3711 1.1 mrg error("basic type expected, not `%s`", token.toChars());
3712 1.1 mrg if (token.value == TOK.else_)
3713 1.1 mrg errorSupplemental(token.loc, "There's no `static else`, use `else` instead.");
3714 1.1 mrg t = AST.Type.terror;
3715 1.1 mrg break;
3716 1.1 mrg }
3717 1.1 mrg return t;
3718 1.1 mrg }
3719 1.1 mrg
3720 1.1 mrg private AST.Type parseBasicTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents)
3721 1.1 mrg {
3722 1.1 mrg AST.Type maybeArray = null;
3723 1.1 mrg // See https://issues.dlang.org/show_bug.cgi?id=1215
3724 1.1 mrg // A basic type can look like MyType (typical case), but also:
3725 1.1 mrg // MyType.T -> A type
3726 1.1 mrg // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3727 1.1 mrg // MyType[expr].T -> A type.
3728 1.1 mrg // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3729 1.1 mrg // (iif MyType[expr].T is a Ttuple)
3730 1.1 mrg while (1)
3731 1.1 mrg {
3732 1.1 mrg switch (token.value)
3733 1.1 mrg {
3734 1.1 mrg case TOK.dot:
3735 1.1 mrg {
3736 1.1 mrg nextToken();
3737 1.1 mrg if (token.value != TOK.identifier)
3738 1.1 mrg {
3739 1.1 mrg error("identifier expected following `.` instead of `%s`", token.toChars());
3740 1.1 mrg break;
3741 1.1 mrg }
3742 1.1 mrg if (maybeArray)
3743 1.1 mrg {
3744 1.1 mrg // This is actually a TypeTuple index, not an {a/s}array.
3745 1.1 mrg // We need to have a while loop to unwind all index taking:
3746 1.1 mrg // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3747 1.1 mrg AST.Objects dimStack;
3748 1.1 mrg AST.Type t = maybeArray;
3749 1.1 mrg while (true)
3750 1.1 mrg {
3751 1.1 mrg if (t.ty == Tsarray)
3752 1.1 mrg {
3753 1.1 mrg // The index expression is an Expression.
3754 1.1 mrg AST.TypeSArray a = cast(AST.TypeSArray)t;
3755 1.1 mrg dimStack.push(a.dim.syntaxCopy());
3756 1.1 mrg t = a.next.syntaxCopy();
3757 1.1 mrg }
3758 1.1 mrg else if (t.ty == Taarray)
3759 1.1 mrg {
3760 1.1 mrg // The index expression is a Type. It will be interpreted as an expression at semantic time.
3761 1.1 mrg AST.TypeAArray a = cast(AST.TypeAArray)t;
3762 1.1 mrg dimStack.push(a.index.syntaxCopy());
3763 1.1 mrg t = a.next.syntaxCopy();
3764 1.1 mrg }
3765 1.1 mrg else
3766 1.1 mrg {
3767 1.1 mrg break;
3768 1.1 mrg }
3769 1.1 mrg }
3770 1.1 mrg assert(dimStack.dim > 0);
3771 1.1 mrg // We're good. Replay indices in the reverse order.
3772 1.1 mrg tid = cast(AST.TypeQualified)t;
3773 1.1 mrg while (dimStack.dim)
3774 1.1 mrg {
3775 1.1 mrg tid.addIndex(dimStack.pop());
3776 1.1 mrg }
3777 1.1 mrg maybeArray = null;
3778 1.1 mrg }
3779 1.1 mrg const loc = token.loc;
3780 1.1 mrg Identifier id = token.ident;
3781 1.1 mrg nextToken();
3782 1.1 mrg if (token.value == TOK.not)
3783 1.1 mrg {
3784 1.1 mrg auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
3785 1.1 mrg tid.addInst(tempinst);
3786 1.1 mrg }
3787 1.1 mrg else
3788 1.1 mrg tid.addIdent(id);
3789 1.1 mrg continue;
3790 1.1 mrg }
3791 1.1 mrg case TOK.leftBracket:
3792 1.1 mrg {
3793 1.1 mrg if (dontLookDotIdents) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911
3794 1.1 mrg goto Lend;
3795 1.1 mrg
3796 1.1 mrg nextToken();
3797 1.1 mrg AST.Type t = maybeArray ? maybeArray : cast(AST.Type)tid;
3798 1.1 mrg if (token.value == TOK.rightBracket)
3799 1.1 mrg {
3800 1.1 mrg // It's a dynamic array, and we're done:
3801 1.1 mrg // T[].U does not make sense.
3802 1.1 mrg t = new AST.TypeDArray(t);
3803 1.1 mrg nextToken();
3804 1.1 mrg return t;
3805 1.1 mrg }
3806 1.1 mrg else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
3807 1.1 mrg {
3808 1.1 mrg // This can be one of two things:
3809 1.1 mrg // 1 - an associative array declaration, T[type]
3810 1.1 mrg // 2 - an associative array declaration, T[expr]
3811 1.1 mrg // These can only be disambiguated later.
3812 1.1 mrg AST.Type index = parseType(); // [ type ]
3813 1.1 mrg maybeArray = new AST.TypeAArray(t, index);
3814 1.1 mrg check(TOK.rightBracket);
3815 1.1 mrg }
3816 1.1 mrg else
3817 1.1 mrg {
3818 1.1 mrg // This can be one of three things:
3819 1.1 mrg // 1 - an static array declaration, T[expr]
3820 1.1 mrg // 2 - a slice, T[expr .. expr]
3821 1.1 mrg // 3 - a template parameter pack index expression, T[expr].U
3822 1.1 mrg // 1 and 3 can only be disambiguated later.
3823 1.1 mrg //printf("it's type[expression]\n");
3824 1.1 mrg inBrackets++;
3825 1.1 mrg AST.Expression e = parseAssignExp(); // [ expression ]
3826 1.1 mrg if (token.value == TOK.slice)
3827 1.1 mrg {
3828 1.1 mrg // It's a slice, and we're done.
3829 1.1 mrg nextToken();
3830 1.1 mrg AST.Expression e2 = parseAssignExp(); // [ exp .. exp ]
3831 1.1 mrg t = new AST.TypeSlice(t, e, e2);
3832 1.1 mrg inBrackets--;
3833 1.1 mrg check(TOK.rightBracket);
3834 1.1 mrg return t;
3835 1.1 mrg }
3836 1.1 mrg else
3837 1.1 mrg {
3838 1.1 mrg maybeArray = new AST.TypeSArray(t, e);
3839 1.1 mrg inBrackets--;
3840 1.1 mrg check(TOK.rightBracket);
3841 1.1 mrg continue;
3842 1.1 mrg }
3843 1.1 mrg }
3844 1.1 mrg break;
3845 1.1 mrg }
3846 1.1 mrg default:
3847 1.1 mrg goto Lend;
3848 1.1 mrg }
3849 1.1 mrg }
3850 1.1 mrg Lend:
3851 1.1 mrg return maybeArray ? maybeArray : cast(AST.Type)tid;
3852 1.1 mrg }
3853 1.1 mrg
3854 1.1 mrg /******************************************
3855 1.1 mrg * Parse suffixes to type t.
3856 1.1 mrg * *
3857 1.1 mrg * []
3858 1.1 mrg * [AssignExpression]
3859 1.1 mrg * [AssignExpression .. AssignExpression]
3860 1.1 mrg * [Type]
3861 1.1 mrg * delegate Parameters MemberFunctionAttributes(opt)
3862 1.1 mrg * function Parameters FunctionAttributes(opt)
3863 1.1 mrg * Params:
3864 1.1 mrg * t = the already parsed type
3865 1.1 mrg * Returns:
3866 1.1 mrg * t with the suffixes added
3867 1.1 mrg * See_Also:
3868 1.1 mrg * https://dlang.org/spec/declaration.html#TypeSuffixes
3869 1.1 mrg */
3870 1.1 mrg private AST.Type parseTypeSuffixes(AST.Type t)
3871 1.1 mrg {
3872 1.1 mrg //printf("parseTypeSuffixes()\n");
3873 1.1 mrg while (1)
3874 1.1 mrg {
3875 1.1 mrg switch (token.value)
3876 1.1 mrg {
3877 1.1 mrg case TOK.mul:
3878 1.1 mrg t = new AST.TypePointer(t);
3879 1.1 mrg nextToken();
3880 1.1 mrg continue;
3881 1.1 mrg
3882 1.1 mrg case TOK.leftBracket:
3883 1.1 mrg // Handle []. Make sure things like
3884 1.1 mrg // int[3][1] a;
3885 1.1 mrg // is (array[1] of array[3] of int)
3886 1.1 mrg nextToken();
3887 1.1 mrg if (token.value == TOK.rightBracket)
3888 1.1 mrg {
3889 1.1 mrg t = new AST.TypeDArray(t); // []
3890 1.1 mrg nextToken();
3891 1.1 mrg }
3892 1.1 mrg else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
3893 1.1 mrg {
3894 1.1 mrg // It's an associative array declaration
3895 1.1 mrg //printf("it's an associative array\n");
3896 1.1 mrg AST.Type index = parseType(); // [ type ]
3897 1.1 mrg t = new AST.TypeAArray(t, index);
3898 1.1 mrg check(TOK.rightBracket);
3899 1.1 mrg }
3900 1.1 mrg else
3901 1.1 mrg {
3902 1.1 mrg //printf("it's type[expression]\n");
3903 1.1 mrg inBrackets++;
3904 1.1 mrg AST.Expression e = parseAssignExp(); // [ expression ]
3905 1.1 mrg if (!e)
3906 1.1 mrg {
3907 1.1 mrg inBrackets--;
3908 1.1 mrg check(TOK.rightBracket);
3909 1.1 mrg continue;
3910 1.1 mrg }
3911 1.1 mrg if (token.value == TOK.slice)
3912 1.1 mrg {
3913 1.1 mrg nextToken();
3914 1.1 mrg AST.Expression e2 = parseAssignExp(); // [ exp .. exp ]
3915 1.1 mrg t = new AST.TypeSlice(t, e, e2);
3916 1.1 mrg }
3917 1.1 mrg else
3918 1.1 mrg {
3919 1.1 mrg t = new AST.TypeSArray(t, e);
3920 1.1 mrg }
3921 1.1 mrg inBrackets--;
3922 1.1 mrg check(TOK.rightBracket);
3923 1.1 mrg }
3924 1.1 mrg continue;
3925 1.1 mrg
3926 1.1 mrg case TOK.delegate_:
3927 1.1 mrg case TOK.function_:
3928 1.1 mrg {
3929 1.1 mrg // Handle delegate declaration:
3930 1.1 mrg // t delegate(parameter list) nothrow pure
3931 1.1 mrg // t function(parameter list) nothrow pure
3932 1.1 mrg const save = token.value;
3933 1.1 mrg nextToken();
3934 1.1 mrg
3935 1.1 mrg auto parameterList = parseParameterList(null);
3936 1.1 mrg
3937 1.1 mrg StorageClass stc = parsePostfix(STC.undefined_, null);
3938 1.1 mrg auto tf = new AST.TypeFunction(parameterList, t, linkage, stc);
3939 1.1 mrg if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild | STC.return_))
3940 1.1 mrg {
3941 1.1 mrg if (save == TOK.function_)
3942 1.1 mrg error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions");
3943 1.1 mrg else
3944 1.1 mrg tf = cast(AST.TypeFunction)tf.addSTC(stc);
3945 1.1 mrg }
3946 1.1 mrg t = save == TOK.delegate_ ? new AST.TypeDelegate(tf) : new AST.TypePointer(tf); // pointer to function
3947 1.1 mrg continue;
3948 1.1 mrg }
3949 1.1 mrg default:
3950 1.1 mrg return t;
3951 1.1 mrg }
3952 1.1 mrg assert(0);
3953 1.1 mrg }
3954 1.1 mrg assert(0);
3955 1.1 mrg }
3956 1.1 mrg
3957 1.1 mrg /**********************
3958 1.1 mrg * Parse Declarator
3959 1.1 mrg * Params:
3960 1.1 mrg * t = base type to start with
3961 1.1 mrg * palt = OR in 1 for C-style function pointer declaration syntax,
3962 1.1 mrg * 2 for C-style array declaration syntax, otherwise don't modify
3963 1.1 mrg * pident = set to Identifier if there is one, null if not
3964 1.1 mrg * tpl = if !null, then set to TemplateParameterList
3965 1.1 mrg * storageClass = any storage classes seen so far
3966 1.1 mrg * pdisable = set to true if @disable seen
3967 1.1 mrg * pudas = any user defined attributes seen so far. Merged with any more found
3968 1.1 mrg * Returns:
3969 1.1 mrg * type declared
3970 1.1 mrg * Reference: https://dlang.org/spec/declaration.html#Declarator
3971 1.1 mrg */
3972 1.1 mrg private AST.Type parseDeclarator(AST.Type t, ref int palt, Identifier* pident,
3973 1.1 mrg AST.TemplateParameters** tpl = null, StorageClass storageClass = 0,
3974 1.1 mrg bool* pdisable = null, AST.Expressions** pudas = null)
3975 1.1 mrg {
3976 1.1 mrg //printf("parseDeclarator(tpl = %p)\n", tpl);
3977 1.1 mrg t = parseTypeSuffixes(t);
3978 1.1 mrg AST.Type ts;
3979 1.1 mrg switch (token.value)
3980 1.1 mrg {
3981 1.1 mrg case TOK.identifier:
3982 1.1 mrg if (pident)
3983 1.1 mrg *pident = token.ident;
3984 1.1 mrg else
3985 1.1 mrg error("unexpected identifier `%s` in declarator", token.ident.toChars());
3986 1.1 mrg ts = t;
3987 1.1 mrg nextToken();
3988 1.1 mrg break;
3989 1.1 mrg
3990 1.1 mrg case TOK.leftParenthesis:
3991 1.1 mrg {
3992 1.1 mrg // like: T (*fp)();
3993 1.1 mrg // like: T ((*fp))();
3994 1.1 mrg if (peekNext() == TOK.mul || peekNext() == TOK.leftParenthesis)
3995 1.1 mrg {
3996 1.1 mrg /* Parse things with parentheses around the identifier, like:
3997 1.1 mrg * int (*ident[3])[]
3998 1.1 mrg * although the D style would be:
3999 1.1 mrg * int[]*[3] ident
4000 1.1 mrg */
4001 1.1 mrg palt |= 1;
4002 1.1 mrg nextToken();
4003 1.1 mrg ts = parseDeclarator(t, palt, pident);
4004 1.1 mrg check(TOK.rightParenthesis);
4005 1.1 mrg break;
4006 1.1 mrg }
4007 1.1 mrg ts = t;
4008 1.1 mrg
4009 1.1 mrg Token* peekt = &token;
4010 1.1 mrg /* Completely disallow C-style things like:
4011 1.1 mrg * T (a);
4012 1.1 mrg * Improve error messages for the common bug of a missing return type
4013 1.1 mrg * by looking to see if (a) looks like a parameter list.
4014 1.1 mrg */
4015 1.1 mrg if (isParameters(&peekt))
4016 1.1 mrg {
4017 1.1 mrg error("function declaration without return type. (Note that constructors are always named `this`)");
4018 1.1 mrg }
4019 1.1 mrg else
4020 1.1 mrg error("unexpected `(` in declarator");
4021 1.1 mrg break;
4022 1.1 mrg }
4023 1.1 mrg default:
4024 1.1 mrg ts = t;
4025 1.1 mrg break;
4026 1.1 mrg }
4027 1.1 mrg
4028 1.1 mrg // parse DeclaratorSuffixes
4029 1.1 mrg while (1)
4030 1.1 mrg {
4031 1.1 mrg switch (token.value)
4032 1.1 mrg {
4033 1.1 mrg static if (CARRAYDECL)
4034 1.1 mrg {
4035 1.1 mrg /* Support C style array syntax:
4036 1.1 mrg * int ident[]
4037 1.1 mrg * as opposed to D-style:
4038 1.1 mrg * int[] ident
4039 1.1 mrg */
4040 1.1 mrg case TOK.leftBracket:
4041 1.1 mrg {
4042 1.1 mrg // This is the old C-style post [] syntax.
4043 1.1 mrg AST.TypeNext ta;
4044 1.1 mrg nextToken();
4045 1.1 mrg if (token.value == TOK.rightBracket)
4046 1.1 mrg {
4047 1.1 mrg // It's a dynamic array
4048 1.1 mrg ta = new AST.TypeDArray(t); // []
4049 1.1 mrg nextToken();
4050 1.1 mrg palt |= 2;
4051 1.1 mrg }
4052 1.1 mrg else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
4053 1.1 mrg {
4054 1.1 mrg // It's an associative array
4055 1.1 mrg //printf("it's an associative array\n");
4056 1.1 mrg AST.Type index = parseType(); // [ type ]
4057 1.1 mrg check(TOK.rightBracket);
4058 1.1 mrg ta = new AST.TypeAArray(t, index);
4059 1.1 mrg palt |= 2;
4060 1.1 mrg }
4061 1.1 mrg else
4062 1.1 mrg {
4063 1.1 mrg //printf("It's a static array\n");
4064 1.1 mrg AST.Expression e = parseAssignExp(); // [ expression ]
4065 1.1 mrg ta = new AST.TypeSArray(t, e);
4066 1.1 mrg check(TOK.rightBracket);
4067 1.1 mrg palt |= 2;
4068 1.1 mrg }
4069 1.1 mrg
4070 1.1 mrg /* Insert ta into
4071 1.1 mrg * ts -> ... -> t
4072 1.1 mrg * so that
4073 1.1 mrg * ts -> ... -> ta -> t
4074 1.1 mrg */
4075 1.1 mrg AST.Type* pt;
4076 1.1 mrg for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
4077 1.1 mrg {
4078 1.1 mrg }
4079 1.1 mrg *pt = ta;
4080 1.1 mrg continue;
4081 1.1 mrg }
4082 1.1 mrg }
4083 1.1 mrg case TOK.leftParenthesis:
4084 1.1 mrg {
4085 1.1 mrg if (tpl)
4086 1.1 mrg {
4087 1.1 mrg Token* tk = peekPastParen(&token);
4088 1.1 mrg if (tk.value == TOK.leftParenthesis)
4089 1.1 mrg {
4090 1.1 mrg /* Look ahead to see if this is (...)(...),
4091 1.1 mrg * i.e. a function template declaration
4092 1.1 mrg */
4093 1.1 mrg //printf("function template declaration\n");
4094 1.1 mrg
4095 1.1 mrg // Gather template parameter list
4096 1.1 mrg *tpl = parseTemplateParameterList();
4097 1.1 mrg }
4098 1.1 mrg else if (tk.value == TOK.assign)
4099 1.1 mrg {
4100 1.1 mrg /* or (...) =,
4101 1.1 mrg * i.e. a variable template declaration
4102 1.1 mrg */
4103 1.1 mrg //printf("variable template declaration\n");
4104 1.1 mrg *tpl = parseTemplateParameterList();
4105 1.1 mrg break;
4106 1.1 mrg }
4107 1.1 mrg }
4108 1.1 mrg
4109 1.1 mrg auto parameterList = parseParameterList(null);
4110 1.1 mrg
4111 1.1 mrg /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
4112 1.1 mrg */
4113 1.1 mrg // merge prefix storage classes
4114 1.1 mrg StorageClass stc = parsePostfix(storageClass, pudas);
4115 1.1 mrg
4116 1.1 mrg AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, stc);
4117 1.1 mrg tf = tf.addSTC(stc);
4118 1.1 mrg if (pdisable)
4119 1.1 mrg *pdisable = stc & STC.disable ? true : false;
4120 1.1 mrg
4121 1.1 mrg /* Insert tf into
4122 1.1 mrg * ts -> ... -> t
4123 1.1 mrg * so that
4124 1.1 mrg * ts -> ... -> tf -> t
4125 1.1 mrg */
4126 1.1 mrg AST.Type* pt;
4127 1.1 mrg for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
4128 1.1 mrg {
4129 1.1 mrg }
4130 1.1 mrg *pt = tf;
4131 1.1 mrg break;
4132 1.1 mrg }
4133 1.1 mrg default:
4134 1.1 mrg break;
4135 1.1 mrg }
4136 1.1 mrg break;
4137 1.1 mrg }
4138 1.1 mrg return ts;
4139 1.1 mrg }
4140 1.1 mrg
4141 1.1 mrg private void parseStorageClasses(ref StorageClass storage_class, ref LINK link,
4142 1.1 mrg ref bool setAlignment, ref AST.Expression ealign, ref AST.Expressions* udas,
4143 1.1 mrg out Loc linkloc)
4144 1.1 mrg {
4145 1.1 mrg StorageClass stc;
4146 1.1 mrg bool sawLinkage = false; // seen a linkage declaration
4147 1.1 mrg
4148 1.1 mrg linkloc = Loc.initial;
4149 1.1 mrg
4150 1.1 mrg while (1)
4151 1.1 mrg {
4152 1.1 mrg switch (token.value)
4153 1.1 mrg {
4154 1.1 mrg case TOK.const_:
4155 1.1 mrg if (peekNext() == TOK.leftParenthesis)
4156 1.1 mrg break; // const as type constructor
4157 1.1 mrg stc = STC.const_; // const as storage class
4158 1.1 mrg goto L1;
4159 1.1 mrg
4160 1.1 mrg case TOK.immutable_:
4161 1.1 mrg if (peekNext() == TOK.leftParenthesis)
4162 1.1 mrg break;
4163 1.1 mrg stc = STC.immutable_;
4164 1.1 mrg goto L1;
4165 1.1 mrg
4166 1.1 mrg case TOK.shared_:
4167 1.1 mrg if (peekNext() == TOK.leftParenthesis)
4168 1.1 mrg break;
4169 1.1 mrg stc = STC.shared_;
4170 1.1 mrg goto L1;
4171 1.1 mrg
4172 1.1 mrg case TOK.inout_:
4173 1.1 mrg if (peekNext() == TOK.leftParenthesis)
4174 1.1 mrg break;
4175 1.1 mrg stc = STC.wild;
4176 1.1 mrg goto L1;
4177 1.1 mrg
4178 1.1 mrg case TOK.static_:
4179 1.1 mrg stc = STC.static_;
4180 1.1 mrg goto L1;
4181 1.1 mrg
4182 1.1 mrg case TOK.final_:
4183 1.1 mrg stc = STC.final_;
4184 1.1 mrg goto L1;
4185 1.1 mrg
4186 1.1 mrg case TOK.auto_:
4187 1.1 mrg stc = STC.auto_;
4188 1.1 mrg goto L1;
4189 1.1 mrg
4190 1.1 mrg case TOK.scope_:
4191 1.1 mrg stc = STC.scope_;
4192 1.1 mrg goto L1;
4193 1.1 mrg
4194 1.1 mrg case TOK.override_:
4195 1.1 mrg stc = STC.override_;
4196 1.1 mrg goto L1;
4197 1.1 mrg
4198 1.1 mrg case TOK.abstract_:
4199 1.1 mrg stc = STC.abstract_;
4200 1.1 mrg goto L1;
4201 1.1 mrg
4202 1.1 mrg case TOK.synchronized_:
4203 1.1 mrg stc = STC.synchronized_;
4204 1.1 mrg goto L1;
4205 1.1 mrg
4206 1.1 mrg case TOK.deprecated_:
4207 1.1 mrg stc = STC.deprecated_;
4208 1.1 mrg goto L1;
4209 1.1 mrg
4210 1.1 mrg case TOK.nothrow_:
4211 1.1 mrg stc = STC.nothrow_;
4212 1.1 mrg goto L1;
4213 1.1 mrg
4214 1.1 mrg case TOK.pure_:
4215 1.1 mrg stc = STC.pure_;
4216 1.1 mrg goto L1;
4217 1.1 mrg
4218 1.1 mrg case TOK.ref_:
4219 1.1 mrg stc = STC.ref_;
4220 1.1 mrg goto L1;
4221 1.1 mrg
4222 1.1 mrg case TOK.gshared:
4223 1.1 mrg stc = STC.gshared;
4224 1.1 mrg goto L1;
4225 1.1 mrg
4226 1.1 mrg case TOK.enum_:
4227 1.1 mrg {
4228 1.1 mrg const tv = peekNext();
4229 1.1 mrg if (tv == TOK.leftCurly || tv == TOK.colon)
4230 1.1 mrg break;
4231 1.1 mrg if (tv == TOK.identifier)
4232 1.1 mrg {
4233 1.1 mrg const nextv = peekNext2();
4234 1.1 mrg if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
4235 1.1 mrg break;
4236 1.1 mrg }
4237 1.1 mrg stc = STC.manifest;
4238 1.1 mrg goto L1;
4239 1.1 mrg }
4240 1.1 mrg
4241 1.1 mrg case TOK.at:
4242 1.1 mrg {
4243 1.1 mrg stc = parseAttribute(udas);
4244 1.1 mrg if (stc)
4245 1.1 mrg goto L1;
4246 1.1 mrg continue;
4247 1.1 mrg }
4248 1.1 mrg L1:
4249 1.1 mrg storage_class = appendStorageClass(storage_class, stc);
4250 1.1 mrg nextToken();
4251 1.1 mrg continue;
4252 1.1 mrg
4253 1.1 mrg case TOK.extern_:
4254 1.1 mrg {
4255 1.1 mrg if (peekNext() != TOK.leftParenthesis)
4256 1.1 mrg {
4257 1.1 mrg stc = STC.extern_;
4258 1.1 mrg goto L1;
4259 1.1 mrg }
4260 1.1 mrg
4261 1.1 mrg if (sawLinkage)
4262 1.1 mrg error("redundant linkage declaration");
4263 1.1 mrg sawLinkage = true;
4264 1.1 mrg linkloc = token.loc;
4265 1.1 mrg auto res = parseLinkage();
4266 1.1 mrg link = res.link;
4267 1.1 mrg if (res.idents || res.identExps)
4268 1.1 mrg {
4269 1.1 mrg error("C++ name spaces not allowed here");
4270 1.1 mrg }
4271 1.1 mrg if (res.cppmangle != CPPMANGLE.def)
4272 1.1 mrg {
4273 1.1 mrg error("C++ mangle declaration not allowed here");
4274 1.1 mrg }
4275 1.1 mrg continue;
4276 1.1 mrg }
4277 1.1 mrg case TOK.align_:
4278 1.1 mrg {
4279 1.1 mrg nextToken();
4280 1.1 mrg setAlignment = true;
4281 1.1 mrg if (token.value == TOK.leftParenthesis)
4282 1.1 mrg {
4283 1.1 mrg nextToken();
4284 1.1 mrg ealign = parseExpression();
4285 1.1 mrg check(TOK.rightParenthesis);
4286 1.1 mrg }
4287 1.1 mrg continue;
4288 1.1 mrg }
4289 1.1 mrg default:
4290 1.1 mrg break;
4291 1.1 mrg }
4292 1.1 mrg break;
4293 1.1 mrg }
4294 1.1 mrg }
4295 1.1 mrg
4296 1.1 mrg /**********************************
4297 1.1 mrg * Parse Declarations.
4298 1.1 mrg * These can be:
4299 1.1 mrg * 1. declarations at global/class level
4300 1.1 mrg * 2. declarations at statement level
4301 1.1 mrg * Return array of Declaration *'s.
4302 1.1 mrg */
4303 1.1 mrg private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
4304 1.1 mrg {
4305 1.1 mrg StorageClass storage_class = STC.undefined_;
4306 1.1 mrg LINK link = linkage;
4307 1.1 mrg Loc linkloc = this.linkLoc;
4308 1.1 mrg bool setAlignment = false;
4309 1.1 mrg AST.Expression ealign;
4310 1.1 mrg AST.Expressions* udas = null;
4311 1.1 mrg
4312 1.1 mrg //printf("parseDeclarations() %s\n", token.toChars());
4313 1.1 mrg if (!comment)
4314 1.1 mrg comment = token.blockComment.ptr;
4315 1.1 mrg
4316 1.1 mrg /* Look for AliasReassignment
4317 1.1 mrg */
4318 1.1 mrg if (token.value == TOK.identifier && peekNext() == TOK.assign)
4319 1.1 mrg return parseAliasReassignment(comment);
4320 1.1 mrg
4321 1.1 mrg /* Declarations that start with `alias`
4322 1.1 mrg */
4323 1.1 mrg bool isAliasDeclaration = false;
4324 1.1 mrg if (token.value == TOK.alias_)
4325 1.1 mrg {
4326 1.1 mrg if (auto a = parseAliasDeclarations(comment))
4327 1.1 mrg return a;
4328 1.1 mrg /* Handle these later:
4329 1.1 mrg * alias StorageClasses type ident;
4330 1.1 mrg */
4331 1.1 mrg isAliasDeclaration = true;
4332 1.1 mrg }
4333 1.1 mrg
4334 1.1 mrg AST.Type ts;
4335 1.1 mrg
4336 1.1 mrg if (!autodecl)
4337 1.1 mrg {
4338 1.1 mrg parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
4339 1.1 mrg
4340 1.1 mrg if (token.value == TOK.enum_)
4341 1.1 mrg {
4342 1.1 mrg AST.Dsymbol d = parseEnum();
4343 1.1 mrg auto a = new AST.Dsymbols();
4344 1.1 mrg a.push(d);
4345 1.1 mrg
4346 1.1 mrg if (udas)
4347 1.1 mrg {
4348 1.1 mrg d = new AST.UserAttributeDeclaration(udas, a);
4349 1.1 mrg a = new AST.Dsymbols();
4350 1.1 mrg a.push(d);
4351 1.1 mrg }
4352 1.1 mrg
4353 1.1 mrg addComment(d, comment);
4354 1.1 mrg return a;
4355 1.1 mrg }
4356 1.1 mrg if (token.value == TOK.struct_ ||
4357 1.1 mrg token.value == TOK.union_ ||
4358 1.1 mrg token.value == TOK.class_ ||
4359 1.1 mrg token.value == TOK.interface_)
4360 1.1 mrg {
4361 1.1 mrg AST.Dsymbol s = parseAggregate();
4362 1.1 mrg auto a = new AST.Dsymbols();
4363 1.1 mrg a.push(s);
4364 1.1 mrg
4365 1.1 mrg if (storage_class)
4366 1.1 mrg {
4367 1.1 mrg s = new AST.StorageClassDeclaration(storage_class, a);
4368 1.1 mrg a = new AST.Dsymbols();
4369 1.1 mrg a.push(s);
4370 1.1 mrg }
4371 1.1 mrg if (setAlignment)
4372 1.1 mrg {
4373 1.1 mrg s = new AST.AlignDeclaration(s.loc, ealign, a);
4374 1.1 mrg a = new AST.Dsymbols();
4375 1.1 mrg a.push(s);
4376 1.1 mrg }
4377 1.1 mrg if (link != linkage)
4378 1.1 mrg {
4379 1.1 mrg s = new AST.LinkDeclaration(linkloc, link, a);
4380 1.1 mrg a = new AST.Dsymbols();
4381 1.1 mrg a.push(s);
4382 1.1 mrg }
4383 1.1 mrg if (udas)
4384 1.1 mrg {
4385 1.1 mrg s = new AST.UserAttributeDeclaration(udas, a);
4386 1.1 mrg a = new AST.Dsymbols();
4387 1.1 mrg a.push(s);
4388 1.1 mrg }
4389 1.1 mrg
4390 1.1 mrg addComment(s, comment);
4391 1.1 mrg return a;
4392 1.1 mrg }
4393 1.1 mrg
4394 1.1 mrg /* Look for auto initializers:
4395 1.1 mrg * storage_class identifier = initializer;
4396 1.1 mrg * storage_class identifier(...) = initializer;
4397 1.1 mrg */
4398 1.1 mrg if ((storage_class || udas) && token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
4399 1.1 mrg {
4400 1.1 mrg AST.Dsymbols* a = parseAutoDeclarations(storage_class, comment);
4401 1.1 mrg if (udas)
4402 1.1 mrg {
4403 1.1 mrg AST.Dsymbol s = new AST.UserAttributeDeclaration(udas, a);
4404 1.1 mrg a = new AST.Dsymbols();
4405 1.1 mrg a.push(s);
4406 1.1 mrg }
4407 1.1 mrg return a;
4408 1.1 mrg }
4409 1.1 mrg
4410 1.1 mrg /* Look for return type inference for template functions.
4411 1.1 mrg */
4412 1.1 mrg {
4413 1.1 mrg Token* tk;
4414 1.1 mrg if ((storage_class || udas) && token.value == TOK.identifier && skipParens(peek(&token), &tk) &&
4415 1.1 mrg skipAttributes(tk, &tk) &&
4416 1.1 mrg (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo ||
4417 1.1 mrg tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body))
4418 1.1 mrg {
4419 1.1 mrg // @@@DEPRECATED_2.117@@@
4420 1.1 mrg // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
4421 1.1 mrg // Deprecated in 2.097 - Can be removed from 2.117
4422 1.1 mrg // The deprecation period is longer than usual as `body`
4423 1.1 mrg // was quite widely used.
4424 1.1 mrg if (tk.value == TOK.identifier && tk.ident == Id._body)
4425 1.1 mrg deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
4426 1.1 mrg
4427 1.1 mrg ts = null;
4428 1.1 mrg }
4429 1.1 mrg else
4430 1.1 mrg {
4431 1.1 mrg ts = parseBasicType();
4432 1.1 mrg ts = parseTypeSuffixes(ts);
4433 1.1 mrg }
4434 1.1 mrg }
4435 1.1 mrg }
4436 1.1 mrg
4437 1.1 mrg if (pAttrs)
4438 1.1 mrg {
4439 1.1 mrg storage_class |= pAttrs.storageClass;
4440 1.1 mrg //pAttrs.storageClass = STC.undefined_;
4441 1.1 mrg }
4442 1.1 mrg
4443 1.1 mrg AST.Type tfirst = null;
4444 1.1 mrg auto a = new AST.Dsymbols();
4445 1.1 mrg
4446 1.1 mrg while (1)
4447 1.1 mrg {
4448 1.1 mrg AST.TemplateParameters* tpl = null;
4449 1.1 mrg bool disable;
4450 1.1 mrg int alt = 0;
4451 1.1 mrg
4452 1.1 mrg const loc = token.loc;
4453 1.1 mrg Identifier ident;
4454 1.1 mrg
4455 1.1 mrg auto t = parseDeclarator(ts, alt, &ident, &tpl, storage_class, &disable, &udas);
4456 1.1 mrg assert(t);
4457 1.1 mrg if (!tfirst)
4458 1.1 mrg tfirst = t;
4459 1.1 mrg else if (t != tfirst)
4460 1.1 mrg error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
4461 1.1 mrg
4462 1.1 mrg bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign);
4463 1.1 mrg if (ident)
4464 1.1 mrg checkCstyleTypeSyntax(loc, t, alt, ident);
4465 1.1 mrg else if (!isThis && (t != AST.Type.terror))
4466 1.1 mrg error("no identifier for declarator `%s`", t.toChars());
4467 1.1 mrg
4468 1.1 mrg if (isAliasDeclaration)
4469 1.1 mrg {
4470 1.1 mrg AST.Declaration v;
4471 1.1 mrg AST.Initializer _init = null;
4472 1.1 mrg
4473 1.1 mrg /* Aliases can no longer have multiple declarators, storage classes,
4474 1.1 mrg * linkages, or auto declarations.
4475 1.1 mrg * These never made any sense, anyway.
4476 1.1 mrg * The code below needs to be fixed to reject them.
4477 1.1 mrg * The grammar has already been fixed to preclude them.
4478 1.1 mrg */
4479 1.1 mrg
4480 1.1 mrg if (udas)
4481 1.1 mrg error("user-defined attributes not allowed for `alias` declarations");
4482 1.1 mrg
4483 1.1 mrg if (token.value == TOK.assign)
4484 1.1 mrg {
4485 1.1 mrg nextToken();
4486 1.1 mrg _init = parseInitializer();
4487 1.1 mrg }
4488 1.1 mrg if (_init)
4489 1.1 mrg {
4490 1.1 mrg if (isThis)
4491 1.1 mrg error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars());
4492 1.1 mrg else
4493 1.1 mrg error("alias cannot have initializer");
4494 1.1 mrg }
4495 1.1 mrg v = new AST.AliasDeclaration(loc, ident, t);
4496 1.1 mrg
4497 1.1 mrg v.storage_class = storage_class;
4498 1.1 mrg if (pAttrs)
4499 1.1 mrg {
4500 1.1 mrg /* AliasDeclaration distinguish @safe, @system, @trusted attributes
4501 1.1 mrg * on prefix and postfix.
4502 1.1 mrg * @safe alias void function() FP1;
4503 1.1 mrg * alias @safe void function() FP2; // FP2 is not @safe
4504 1.1 mrg * alias void function() @safe FP3;
4505 1.1 mrg */
4506 1.1 mrg pAttrs.storageClass &= STC.safeGroup;
4507 1.1 mrg }
4508 1.1 mrg AST.Dsymbol s = v;
4509 1.1 mrg
4510 1.1 mrg if (link != linkage)
4511 1.1 mrg {
4512 1.1 mrg auto ax = new AST.Dsymbols();
4513 1.1 mrg ax.push(v);
4514 1.1 mrg s = new AST.LinkDeclaration(linkloc, link, ax);
4515 1.1 mrg }
4516 1.1 mrg a.push(s);
4517 1.1 mrg switch (token.value)
4518 1.1 mrg {
4519 1.1 mrg case TOK.semicolon:
4520 1.1 mrg nextToken();
4521 1.1 mrg addComment(s, comment);
4522 1.1 mrg break;
4523 1.1 mrg
4524 1.1 mrg case TOK.comma:
4525 1.1 mrg nextToken();
4526 1.1 mrg addComment(s, comment);
4527 1.1 mrg continue;
4528 1.1 mrg
4529 1.1 mrg default:
4530 1.1 mrg error("semicolon expected to close `alias` declaration");
4531 1.1 mrg break;
4532 1.1 mrg }
4533 1.1 mrg }
4534 1.1 mrg else if (t.ty == Tfunction)
4535 1.1 mrg {
4536 1.1 mrg AST.Expression constraint = null;
4537 1.1 mrg //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
4538 1.1 mrg auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : 0), t);
4539 1.1 mrg if (pAttrs)
4540 1.1 mrg pAttrs.storageClass = STC.undefined_;
4541 1.1 mrg if (tpl)
4542 1.1 mrg constraint = parseConstraint();
4543 1.1 mrg AST.Dsymbol s = parseContracts(f);
4544 1.1 mrg auto tplIdent = s.ident;
4545 1.1 mrg
4546 1.1 mrg if (link != linkage)
4547 1.1 mrg {
4548 1.1 mrg auto ax = new AST.Dsymbols();
4549 1.1 mrg ax.push(s);
4550 1.1 mrg s = new AST.LinkDeclaration(linkloc, link, ax);
4551 1.1 mrg }
4552 1.1 mrg if (udas)
4553 1.1 mrg {
4554 1.1 mrg auto ax = new AST.Dsymbols();
4555 1.1 mrg ax.push(s);
4556 1.1 mrg s = new AST.UserAttributeDeclaration(udas, ax);
4557 1.1 mrg }
4558 1.1 mrg
4559 1.1 mrg /* A template parameter list means it's a function template
4560 1.1 mrg */
4561 1.1 mrg if (tpl)
4562 1.1 mrg {
4563 1.1 mrg // Wrap a template around the function declaration
4564 1.1 mrg auto decldefs = new AST.Dsymbols();
4565 1.1 mrg decldefs.push(s);
4566 1.1 mrg auto tempdecl = new AST.TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
4567 1.1 mrg s = tempdecl;
4568 1.1 mrg
4569 1.1 mrg StorageClass stc2 = STC.undefined_;
4570 1.1 mrg if (storage_class & STC.static_)
4571 1.1 mrg {
4572 1.1 mrg assert(f.storage_class & STC.static_);
4573 1.1 mrg f.storage_class &= ~STC.static_;
4574 1.1 mrg stc2 |= STC.static_;
4575 1.1 mrg }
4576 1.1 mrg if (storage_class & STC.deprecated_)
4577 1.1 mrg {
4578 1.1 mrg assert(f.storage_class & STC.deprecated_);
4579 1.1 mrg f.storage_class &= ~STC.deprecated_;
4580 1.1 mrg stc2 |= STC.deprecated_;
4581 1.1 mrg }
4582 1.1 mrg if (stc2 != STC.undefined_)
4583 1.1 mrg {
4584 1.1 mrg auto ax = new AST.Dsymbols();
4585 1.1 mrg ax.push(s);
4586 1.1 mrg s = new AST.StorageClassDeclaration(stc2, ax);
4587 1.1 mrg }
4588 1.1 mrg }
4589 1.1 mrg a.push(s);
4590 1.1 mrg addComment(s, comment);
4591 1.1 mrg }
4592 1.1 mrg else if (ident)
4593 1.1 mrg {
4594 1.1 mrg AST.Initializer _init = null;
4595 1.1 mrg if (token.value == TOK.assign)
4596 1.1 mrg {
4597 1.1 mrg nextToken();
4598 1.1 mrg _init = parseInitializer();
4599 1.1 mrg }
4600 1.1 mrg
4601 1.1 mrg auto v = new AST.VarDeclaration(loc, t, ident, _init);
4602 1.1 mrg v.storage_class = storage_class;
4603 1.1 mrg if (pAttrs)
4604 1.1 mrg pAttrs.storageClass = STC.undefined_;
4605 1.1 mrg
4606 1.1 mrg AST.Dsymbol s = v;
4607 1.1 mrg
4608 1.1 mrg if (tpl && _init)
4609 1.1 mrg {
4610 1.1 mrg auto a2 = new AST.Dsymbols();
4611 1.1 mrg a2.push(s);
4612 1.1 mrg auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0);
4613 1.1 mrg s = tempdecl;
4614 1.1 mrg }
4615 1.1 mrg if (setAlignment)
4616 1.1 mrg {
4617 1.1 mrg auto ax = new AST.Dsymbols();
4618 1.1 mrg ax.push(s);
4619 1.1 mrg s = new AST.AlignDeclaration(v.loc, ealign, ax);
4620 1.1 mrg }
4621 1.1 mrg if (link != linkage)
4622 1.1 mrg {
4623 1.1 mrg auto ax = new AST.Dsymbols();
4624 1.1 mrg ax.push(s);
4625 1.1 mrg s = new AST.LinkDeclaration(linkloc, link, ax);
4626 1.1 mrg }
4627 1.1 mrg if (udas)
4628 1.1 mrg {
4629 1.1 mrg auto ax = new AST.Dsymbols();
4630 1.1 mrg ax.push(s);
4631 1.1 mrg s = new AST.UserAttributeDeclaration(udas, ax);
4632 1.1 mrg }
4633 1.1 mrg a.push(s);
4634 1.1 mrg switch (token.value)
4635 1.1 mrg {
4636 1.1 mrg case TOK.semicolon:
4637 1.1 mrg nextToken();
4638 1.1 mrg addComment(s, comment);
4639 1.1 mrg break;
4640 1.1 mrg
4641 1.1 mrg case TOK.comma:
4642 1.1 mrg nextToken();
4643 1.1 mrg addComment(s, comment);
4644 1.1 mrg continue;
4645 1.1 mrg
4646 1.1 mrg default:
4647 1.1 mrg if (loc.linnum != token.loc.linnum)
4648 1.1 mrg {
4649 1.1 mrg error("semicolon needed to end declaration of `%s`, instead of `%s`", v.toChars(), token.toChars());
4650 1.1 mrg errorSupplemental(loc, "`%s` declared here", v.toChars());
4651 1.1 mrg }
4652 1.1 mrg else
4653 1.1 mrg {
4654 1.1 mrg error("semicolon needed to end declaration of `%s` instead of `%s`", v.toChars(), token.toChars());
4655 1.1 mrg }
4656 1.1 mrg break;
4657 1.1 mrg }
4658 1.1 mrg }
4659 1.1 mrg break;
4660 1.1 mrg }
4661 1.1 mrg return a;
4662 1.1 mrg }
4663 1.1 mrg
4664 1.1 mrg /********************************
4665 1.1 mrg * Parse AliasReassignment:
4666 1.1 mrg * identifier = type;
4667 1.1 mrg * Parser is sitting on the identifier.
4668 1.1 mrg * https://dlang.org/spec/declaration.html#alias-reassignment
4669 1.1 mrg * Params:
4670 1.1 mrg * comment = if not null, comment to attach to symbol
4671 1.1 mrg * Returns:
4672 1.1 mrg * array of symbols
4673 1.1 mrg */
4674 1.1 mrg private AST.Dsymbols* parseAliasReassignment(const(char)* comment)
4675 1.1 mrg {
4676 1.1 mrg const loc = token.loc;
4677 1.1 mrg auto ident = token.ident;
4678 1.1 mrg nextToken();
4679 1.1 mrg nextToken(); // advance past =
4680 1.1 mrg auto t = parseType();
4681 1.1 mrg AST.Dsymbol s = new AST.AliasAssign(loc, ident, t, null);
4682 1.1 mrg check(TOK.semicolon);
4683 1.1 mrg addComment(s, comment);
4684 1.1 mrg auto a = new AST.Dsymbols();
4685 1.1 mrg a.push(s);
4686 1.1 mrg return a;
4687 1.1 mrg }
4688 1.1 mrg
4689 1.1 mrg /********************************
4690 1.1 mrg * Parse declarations that start with `alias`
4691 1.1 mrg * Parser is sitting on the `alias`.
4692 1.1 mrg * https://dlang.org/spec/declaration.html#alias
4693 1.1 mrg * Params:
4694 1.1 mrg * comment = if not null, comment to attach to symbol
4695 1.1 mrg * Returns:
4696 1.1 mrg * array of symbols
4697 1.1 mrg */
4698 1.1 mrg private AST.Dsymbols* parseAliasDeclarations(const(char)* comment)
4699 1.1 mrg {
4700 1.1 mrg const loc = token.loc;
4701 1.1 mrg nextToken();
4702 1.1 mrg Loc linkloc = this.linkLoc;
4703 1.1 mrg AST.Expressions* udas;
4704 1.1 mrg LINK link = linkage;
4705 1.1 mrg StorageClass storage_class = STC.undefined_;
4706 1.1 mrg AST.Expression ealign;
4707 1.1 mrg bool setAlignment = false;
4708 1.1 mrg
4709 1.1 mrg /* Look for:
4710 1.1 mrg * alias Identifier this;
4711 1.1 mrg * https://dlang.org/spec/class.html#alias-this
4712 1.1 mrg */
4713 1.1 mrg if (token.value == TOK.identifier && peekNext() == TOK.this_)
4714 1.1 mrg {
4715 1.1 mrg auto s = new AST.AliasThis(loc, token.ident);
4716 1.1 mrg nextToken();
4717 1.1 mrg check(TOK.this_);
4718 1.1 mrg check(TOK.semicolon);
4719 1.1 mrg auto a = new AST.Dsymbols();
4720 1.1 mrg a.push(s);
4721 1.1 mrg addComment(s, comment);
4722 1.1 mrg return a;
4723 1.1 mrg }
4724 1.1 mrg version (none)
4725 1.1 mrg {
4726 1.1 mrg /* Look for:
4727 1.1 mrg * alias this = identifier;
4728 1.1 mrg */
4729 1.1 mrg if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier)
4730 1.1 mrg {
4731 1.1 mrg check(TOK.this_);
4732 1.1 mrg check(TOK.assign);
4733 1.1 mrg auto s = new AliasThis(loc, token.ident);
4734 1.1 mrg nextToken();
4735 1.1 mrg check(TOK.semicolon);
4736 1.1 mrg auto a = new Dsymbols();
4737 1.1 mrg a.push(s);
4738 1.1 mrg addComment(s, comment);
4739 1.1 mrg return a;
4740 1.1 mrg }
4741 1.1 mrg }
4742 1.1 mrg /* Look for:
4743 1.1 mrg * alias identifier = type;
4744 1.1 mrg * alias identifier(...) = type;
4745 1.1 mrg * https://dlang.org/spec/declaration.html#alias
4746 1.1 mrg */
4747 1.1 mrg if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
4748 1.1 mrg {
4749 1.1 mrg auto a = new AST.Dsymbols();
4750 1.1 mrg while (1)
4751 1.1 mrg {
4752 1.1 mrg auto ident = token.ident;
4753 1.1 mrg nextToken();
4754 1.1 mrg AST.TemplateParameters* tpl = null;
4755 1.1 mrg if (token.value == TOK.leftParenthesis)
4756 1.1 mrg tpl = parseTemplateParameterList();
4757 1.1 mrg check(TOK.assign);
4758 1.1 mrg
4759 1.1 mrg bool hasParsedAttributes;
4760 1.1 mrg void parseAttributes()
4761 1.1 mrg {
4762 1.1 mrg if (hasParsedAttributes) // only parse once
4763 1.1 mrg return;
4764 1.1 mrg hasParsedAttributes = true;
4765 1.1 mrg udas = null;
4766 1.1 mrg storage_class = STC.undefined_;
4767 1.1 mrg link = linkage;
4768 1.1 mrg linkloc = this.linkLoc;
4769 1.1 mrg setAlignment = false;
4770 1.1 mrg ealign = null;
4771 1.1 mrg parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
4772 1.1 mrg }
4773 1.1 mrg
4774 1.1 mrg if (token.value == TOK.at)
4775 1.1 mrg parseAttributes;
4776 1.1 mrg
4777 1.1 mrg AST.Declaration v;
4778 1.1 mrg AST.Dsymbol s;
4779 1.1 mrg
4780 1.1 mrg // try to parse function type:
4781 1.1 mrg // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
4782 1.1 mrg bool attributesAppended;
4783 1.1 mrg const StorageClass funcStc = parseTypeCtor();
4784 1.1 mrg Token* tlu = &token;
4785 1.1 mrg Token* tk;
4786 1.1 mrg if (token.value != TOK.function_ &&
4787 1.1 mrg token.value != TOK.delegate_ &&
4788 1.1 mrg isBasicType(&tlu) && tlu &&
4789 1.1 mrg tlu.value == TOK.leftParenthesis)
4790 1.1 mrg {
4791 1.1 mrg AST.Type tret = parseBasicType();
4792 1.1 mrg auto parameterList = parseParameterList(null);
4793 1.1 mrg
4794 1.1 mrg parseAttributes();
4795 1.1 mrg if (udas)
4796 1.1 mrg error("user-defined attributes not allowed for `alias` declarations");
4797 1.1 mrg
4798 1.1 mrg attributesAppended = true;
4799 1.1 mrg storage_class = appendStorageClass(storage_class, funcStc);
4800 1.1 mrg AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
4801 1.1 mrg v = new AST.AliasDeclaration(loc, ident, tf);
4802 1.1 mrg }
4803 1.1 mrg else if (token.value == TOK.function_ ||
4804 1.1 mrg token.value == TOK.delegate_ ||
4805 1.1 mrg token.value == TOK.leftParenthesis &&
4806 1.1 mrg skipAttributes(peekPastParen(&token), &tk) &&
4807 1.1 mrg (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
4808 1.1 mrg token.value == TOK.leftCurly ||
4809 1.1 mrg token.value == TOK.identifier && peekNext() == TOK.goesTo ||
4810 1.1 mrg token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
4811 1.1 mrg skipAttributes(peekPastParen(peek(&token)), &tk) &&
4812 1.1 mrg (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
4813 1.1 mrg )
4814 1.1 mrg {
4815 1.1 mrg // function (parameters) { statements... }
4816 1.1 mrg // delegate (parameters) { statements... }
4817 1.1 mrg // (parameters) { statements... }
4818 1.1 mrg // (parameters) => expression
4819 1.1 mrg // { statements... }
4820 1.1 mrg // identifier => expression
4821 1.1 mrg // ref (parameters) { statements... }
4822 1.1 mrg // ref (parameters) => expression
4823 1.1 mrg
4824 1.1 mrg s = parseFunctionLiteral();
4825 1.1 mrg
4826 1.1 mrg if (udas !is null)
4827 1.1 mrg {
4828 1.1 mrg if (storage_class != 0)
4829 1.1 mrg error("Cannot put a storage-class in an alias declaration.");
4830 1.1 mrg // parseAttributes shouldn't have set these variables
4831 1.1 mrg assert(link == linkage && !setAlignment && ealign is null);
4832 1.1 mrg auto tpl_ = cast(AST.TemplateDeclaration) s;
4833 1.1 mrg if (tpl_ is null || tpl_.members.dim != 1)
4834 1.1 mrg {
4835 1.1 mrg error("user-defined attributes are not allowed on `alias` declarations");
4836 1.1 mrg }
4837 1.1 mrg else
4838 1.1 mrg {
4839 1.1 mrg auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
4840 1.1 mrg auto tf = cast(AST.TypeFunction) fd.type;
4841 1.1 mrg assert(tf.parameterList.parameters.dim > 0);
4842 1.1 mrg auto as = new AST.Dsymbols();
4843 1.1 mrg (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
4844 1.1 mrg }
4845 1.1 mrg }
4846 1.1 mrg
4847 1.1 mrg v = new AST.AliasDeclaration(loc, ident, s);
4848 1.1 mrg }
4849 1.1 mrg else
4850 1.1 mrg {
4851 1.1 mrg parseAttributes();
4852 1.1 mrg // type
4853 1.1 mrg if (udas)
4854 1.1 mrg error("user-defined attributes not allowed for alias declarations");
4855 1.1 mrg
4856 1.1 mrg auto t = parseType();
4857 1.1 mrg
4858 1.1 mrg // Disallow meaningless storage classes on type aliases
4859 1.1 mrg if (storage_class)
4860 1.1 mrg {
4861 1.1 mrg // Don't raise errors for STC that are part of a function/delegate type, e.g.
4862 1.1 mrg // `alias F = ref pure nothrow @nogc @safe int function();`
4863 1.1 mrg auto tp = t.isTypePointer;
4864 1.1 mrg const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
4865 1.1 mrg const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
4866 1.1 mrg
4867 1.1 mrg if (remStc)
4868 1.1 mrg {
4869 1.1 mrg OutBuffer buf;
4870 1.1 mrg AST.stcToBuffer(&buf, remStc);
4871 1.1 mrg // @@@DEPRECATED_2.103@@@
4872 1.1 mrg // Deprecated in 2020-07, can be made an error in 2.103
4873 1.1 mrg deprecation("storage class `%s` has no effect in type aliases", buf.peekChars());
4874 1.1 mrg }
4875 1.1 mrg }
4876 1.1 mrg
4877 1.1 mrg v = new AST.AliasDeclaration(loc, ident, t);
4878 1.1 mrg }
4879 1.1 mrg if (!attributesAppended)
4880 1.1 mrg storage_class = appendStorageClass(storage_class, funcStc);
4881 1.1 mrg v.storage_class = storage_class;
4882 1.1 mrg
4883 1.1 mrg s = v;
4884 1.1 mrg if (tpl)
4885 1.1 mrg {
4886 1.1 mrg auto a2 = new AST.Dsymbols();
4887 1.1 mrg a2.push(s);
4888 1.1 mrg auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2);
4889 1.1 mrg s = tempdecl;
4890 1.1 mrg }
4891 1.1 mrg if (link != linkage)
4892 1.1 mrg {
4893 1.1 mrg auto a2 = new AST.Dsymbols();
4894 1.1 mrg a2.push(s);
4895 1.1 mrg s = new AST.LinkDeclaration(linkloc, link, a2);
4896 1.1 mrg }
4897 1.1 mrg a.push(s);
4898 1.1 mrg
4899 1.1 mrg switch (token.value)
4900 1.1 mrg {
4901 1.1 mrg case TOK.semicolon:
4902 1.1 mrg nextToken();
4903 1.1 mrg addComment(s, comment);
4904 1.1 mrg break;
4905 1.1 mrg
4906 1.1 mrg case TOK.comma:
4907 1.1 mrg nextToken();
4908 1.1 mrg addComment(s, comment);
4909 1.1 mrg if (token.value != TOK.identifier)
4910 1.1 mrg {
4911 1.1 mrg error("identifier expected following comma, not `%s`", token.toChars());
4912 1.1 mrg break;
4913 1.1 mrg }
4914 1.1 mrg if (peekNext() != TOK.assign && peekNext() != TOK.leftParenthesis)
4915 1.1 mrg {
4916 1.1 mrg error("`=` expected following identifier");
4917 1.1 mrg nextToken();
4918 1.1 mrg break;
4919 1.1 mrg }
4920 1.1 mrg continue;
4921 1.1 mrg
4922 1.1 mrg default:
4923 1.1 mrg error("semicolon expected to close `alias` declaration");
4924 1.1 mrg break;
4925 1.1 mrg }
4926 1.1 mrg break;
4927 1.1 mrg }
4928 1.1 mrg return a;
4929 1.1 mrg }
4930 1.1 mrg
4931 1.1 mrg // alias StorageClasses type ident;
4932 1.1 mrg return null;
4933 1.1 mrg }
4934 1.1 mrg
4935 1.1 mrg private AST.Dsymbol parseFunctionLiteral()
4936 1.1 mrg {
4937 1.1 mrg const loc = token.loc;
4938 1.1 mrg AST.TemplateParameters* tpl = null;
4939 1.1 mrg AST.ParameterList parameterList;
4940 1.1 mrg AST.Type tret = null;
4941 1.1 mrg StorageClass stc = 0;
4942 1.1 mrg TOK save = TOK.reserved;
4943 1.1 mrg
4944 1.1 mrg switch (token.value)
4945 1.1 mrg {
4946 1.1 mrg case TOK.function_:
4947 1.1 mrg case TOK.delegate_:
4948 1.1 mrg save = token.value;
4949 1.1 mrg nextToken();
4950 1.1 mrg if (token.value == TOK.ref_)
4951 1.1 mrg {
4952 1.1 mrg // function ref (parameters) { statements... }
4953 1.1 mrg // delegate ref (parameters) { statements... }
4954 1.1 mrg stc = STC.ref_;
4955 1.1 mrg nextToken();
4956 1.1 mrg }
4957 1.1 mrg if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly)
4958 1.1 mrg {
4959 1.1 mrg // function type (parameters) { statements... }
4960 1.1 mrg // delegate type (parameters) { statements... }
4961 1.1 mrg tret = parseBasicType();
4962 1.1 mrg tret = parseTypeSuffixes(tret); // function return type
4963 1.1 mrg }
4964 1.1 mrg
4965 1.1 mrg if (token.value == TOK.leftParenthesis)
4966 1.1 mrg {
4967 1.1 mrg // function (parameters) { statements... }
4968 1.1 mrg // delegate (parameters) { statements... }
4969 1.1 mrg }
4970 1.1 mrg else
4971 1.1 mrg {
4972 1.1 mrg // function { statements... }
4973 1.1 mrg // delegate { statements... }
4974 1.1 mrg break;
4975 1.1 mrg }
4976 1.1 mrg goto case TOK.leftParenthesis;
4977 1.1 mrg
4978 1.1 mrg case TOK.ref_:
4979 1.1 mrg {
4980 1.1 mrg // ref (parameters) => expression
4981 1.1 mrg // ref (parameters) { statements... }
4982 1.1 mrg stc = STC.ref_;
4983 1.1 mrg nextToken();
4984 1.1 mrg goto case TOK.leftParenthesis;
4985 1.1 mrg }
4986 1.1 mrg case TOK.leftParenthesis:
4987 1.1 mrg {
4988 1.1 mrg // (parameters) => expression
4989 1.1 mrg // (parameters) { statements... }
4990 1.1 mrg parameterList = parseParameterList(&tpl);
4991 1.1 mrg stc = parsePostfix(stc, null);
4992 1.1 mrg if (StorageClass modStc = stc & STC.TYPECTOR)
4993 1.1 mrg {
4994 1.1 mrg if (save == TOK.function_)
4995 1.1 mrg {
4996 1.1 mrg OutBuffer buf;
4997 1.1 mrg AST.stcToBuffer(&buf, modStc);
4998 1.1 mrg error("function literal cannot be `%s`", buf.peekChars());
4999 1.1 mrg }
5000 1.1 mrg else
5001 1.1 mrg save = TOK.delegate_;
5002 1.1 mrg }
5003 1.1 mrg break;
5004 1.1 mrg }
5005 1.1 mrg case TOK.leftCurly:
5006 1.1 mrg // { statements... }
5007 1.1 mrg break;
5008 1.1 mrg
5009 1.1 mrg case TOK.identifier:
5010 1.1 mrg {
5011 1.1 mrg // identifier => expression
5012 1.1 mrg parameterList.parameters = new AST.Parameters();
5013 1.1 mrg Identifier id = Identifier.generateId("__T");
5014 1.1 mrg AST.Type t = new AST.TypeIdentifier(loc, id);
5015 1.1 mrg parameterList.parameters.push(new AST.Parameter(STC.parameter, t, token.ident, null, null));
5016 1.1 mrg
5017 1.1 mrg tpl = new AST.TemplateParameters();
5018 1.1 mrg AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null);
5019 1.1 mrg tpl.push(tp);
5020 1.1 mrg
5021 1.1 mrg nextToken();
5022 1.1 mrg break;
5023 1.1 mrg }
5024 1.1 mrg default:
5025 1.1 mrg assert(0);
5026 1.1 mrg }
5027 1.1 mrg
5028 1.1 mrg auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc);
5029 1.1 mrg tf = cast(AST.TypeFunction)tf.addSTC(stc);
5030 1.1 mrg auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null);
5031 1.1 mrg
5032 1.1 mrg if (token.value == TOK.goesTo)
5033 1.1 mrg {
5034 1.1 mrg check(TOK.goesTo);
5035 1.1 mrg if (token.value == TOK.leftCurly)
5036 1.1 mrg {
5037 1.1 mrg deprecation("Using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
5038 1.1 mrg deprecationSupplemental(token.loc, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
5039 1.1 mrg }
5040 1.1 mrg const returnloc = token.loc;
5041 1.1 mrg AST.Expression ae = parseAssignExp();
5042 1.1 mrg fd.fbody = new AST.ReturnStatement(returnloc, ae);
5043 1.1 mrg fd.endloc = token.loc;
5044 1.1 mrg }
5045 1.1 mrg else
5046 1.1 mrg {
5047 1.1 mrg parseContracts(fd);
5048 1.1 mrg }
5049 1.1 mrg
5050 1.1 mrg if (tpl)
5051 1.1 mrg {
5052 1.1 mrg // Wrap a template around function fd
5053 1.1 mrg auto decldefs = new AST.Dsymbols();
5054 1.1 mrg decldefs.push(fd);
5055 1.1 mrg return new AST.TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs, false, true);
5056 1.1 mrg }
5057 1.1 mrg return fd;
5058 1.1 mrg }
5059 1.1 mrg
5060 1.1 mrg /*****************************************
5061 1.1 mrg * Parse contracts following function declaration.
5062 1.1 mrg */
5063 1.1 mrg private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f)
5064 1.1 mrg {
5065 1.1 mrg LINK linksave = linkage;
5066 1.1 mrg
5067 1.1 mrg bool literal = f.isFuncLiteralDeclaration() !is null;
5068 1.1 mrg
5069 1.1 mrg // The following is irrelevant, as it is overridden by sc.linkage in
5070 1.1 mrg // TypeFunction::semantic
5071 1.1 mrg linkage = LINK.d; // nested functions have D linkage
5072 1.1 mrg bool requireDo = false;
5073 1.1 mrg L1:
5074 1.1 mrg switch (token.value)
5075 1.1 mrg {
5076 1.1 mrg case TOK.goesTo:
5077 1.1 mrg if (requireDo)
5078 1.1 mrg error("missing `do { ... }` after `in` or `out`");
5079 1.1 mrg if (!global.params.shortenedMethods)
5080 1.1 mrg error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
5081 1.1 mrg const returnloc = token.loc;
5082 1.1 mrg nextToken();
5083 1.1 mrg f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
5084 1.1 mrg f.endloc = token.loc;
5085 1.1 mrg check(TOK.semicolon);
5086 1.1 mrg break;
5087 1.1 mrg
5088 1.1 mrg case TOK.leftCurly:
5089 1.1 mrg if (requireDo)
5090 1.1 mrg error("missing `do { ... }` after `in` or `out`");
5091 1.1 mrg f.fbody = parseStatement(ParseStatementFlags.semi);
5092 1.1 mrg f.endloc = endloc;
5093 1.1 mrg break;
5094 1.1 mrg
5095 1.1 mrg case TOK.identifier:
5096 1.1 mrg if (token.ident == Id._body)
5097 1.1 mrg {
5098 1.1 mrg // @@@DEPRECATED_2.117@@@
5099 1.1 mrg // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
5100 1.1 mrg // Deprecated in 2.097 - Can be removed from 2.117
5101 1.1 mrg // The deprecation period is longer than usual as `body`
5102 1.1 mrg // was quite widely used.
5103 1.1 mrg deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
5104 1.1 mrg goto case TOK.do_;
5105 1.1 mrg }
5106 1.1 mrg goto default;
5107 1.1 mrg
5108 1.1 mrg case TOK.do_:
5109 1.1 mrg nextToken();
5110 1.1 mrg f.fbody = parseStatement(ParseStatementFlags.curly);
5111 1.1 mrg f.endloc = endloc;
5112 1.1 mrg break;
5113 1.1 mrg
5114 1.1 mrg version (none)
5115 1.1 mrg {
5116 1.1 mrg // Do we want this for function declarations, so we can do:
5117 1.1 mrg // int x, y, foo(), z;
5118 1.1 mrg case TOK.comma:
5119 1.1 mrg nextToken();
5120 1.1 mrg continue;
5121 1.1 mrg }
5122 1.1 mrg
5123 1.1 mrg case TOK.in_:
5124 1.1 mrg // in { statements... }
5125 1.1 mrg // in (expression)
5126 1.1 mrg auto loc = token.loc;
5127 1.1 mrg nextToken();
5128 1.1 mrg if (!f.frequires)
5129 1.1 mrg {
5130 1.1 mrg f.frequires = new AST.Statements;
5131 1.1 mrg }
5132 1.1 mrg if (token.value == TOK.leftParenthesis)
5133 1.1 mrg {
5134 1.1 mrg nextToken();
5135 1.1 mrg AST.Expression e = parseAssignExp(), msg = null;
5136 1.1 mrg if (token.value == TOK.comma)
5137 1.1 mrg {
5138 1.1 mrg nextToken();
5139 1.1 mrg if (token.value != TOK.rightParenthesis)
5140 1.1 mrg {
5141 1.1 mrg msg = parseAssignExp();
5142 1.1 mrg if (token.value == TOK.comma)
5143 1.1 mrg nextToken();
5144 1.1 mrg }
5145 1.1 mrg }
5146 1.1 mrg check(TOK.rightParenthesis);
5147 1.1 mrg e = new AST.AssertExp(loc, e, msg);
5148 1.1 mrg f.frequires.push(new AST.ExpStatement(loc, e));
5149 1.1 mrg requireDo = false;
5150 1.1 mrg }
5151 1.1 mrg else
5152 1.1 mrg {
5153 1.1 mrg f.frequires.push(parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_));
5154 1.1 mrg requireDo = true;
5155 1.1 mrg }
5156 1.1 mrg goto L1;
5157 1.1 mrg
5158 1.1 mrg case TOK.out_:
5159 1.1 mrg // out { statements... }
5160 1.1 mrg // out (; expression)
5161 1.1 mrg // out (identifier) { statements... }
5162 1.1 mrg // out (identifier; expression)
5163 1.1 mrg auto loc = token.loc;
5164 1.1 mrg nextToken();
5165 1.1 mrg if (!f.fensures)
5166 1.1 mrg {
5167 1.1 mrg f.fensures = new AST.Ensures;
5168 1.1 mrg }
5169 1.1 mrg Identifier id = null;
5170 1.1 mrg if (token.value != TOK.leftCurly)
5171 1.1 mrg {
5172 1.1 mrg check(TOK.leftParenthesis);
5173 1.1 mrg if (token.value != TOK.identifier && token.value != TOK.semicolon)
5174 1.1 mrg error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars());
5175 1.1 mrg if (token.value != TOK.semicolon)
5176 1.1 mrg {
5177 1.1 mrg id = token.ident;
5178 1.1 mrg nextToken();
5179 1.1 mrg }
5180 1.1 mrg if (token.value == TOK.semicolon)
5181 1.1 mrg {
5182 1.1 mrg nextToken();
5183 1.1 mrg AST.Expression e = parseAssignExp(), msg = null;
5184 1.1 mrg if (token.value == TOK.comma)
5185 1.1 mrg {
5186 1.1 mrg nextToken();
5187 1.1 mrg if (token.value != TOK.rightParenthesis)
5188 1.1 mrg {
5189 1.1 mrg msg = parseAssignExp();
5190 1.1 mrg if (token.value == TOK.comma)
5191 1.1 mrg nextToken();
5192 1.1 mrg }
5193 1.1 mrg }
5194 1.1 mrg check(TOK.rightParenthesis);
5195 1.1 mrg e = new AST.AssertExp(loc, e, msg);
5196 1.1 mrg f.fensures.push(AST.Ensure(id, new AST.ExpStatement(loc, e)));
5197 1.1 mrg requireDo = false;
5198 1.1 mrg goto L1;
5199 1.1 mrg }
5200 1.1 mrg check(TOK.rightParenthesis);
5201 1.1 mrg }
5202 1.1 mrg f.fensures.push(AST.Ensure(id, parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_)));
5203 1.1 mrg requireDo = true;
5204 1.1 mrg goto L1;
5205 1.1 mrg
5206 1.1 mrg case TOK.semicolon:
5207 1.1 mrg if (!literal)
5208 1.1 mrg {
5209 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=15799
5210 1.1 mrg // Semicolon becomes a part of function declaration
5211 1.1 mrg // only when 'do' is not required
5212 1.1 mrg if (!requireDo)
5213 1.1 mrg nextToken();
5214 1.1 mrg break;
5215 1.1 mrg }
5216 1.1 mrg goto default;
5217 1.1 mrg
5218 1.1 mrg default:
5219 1.1 mrg if (literal)
5220 1.1 mrg {
5221 1.1 mrg const(char)* sbody = requireDo ? "do " : "";
5222 1.1 mrg error("missing `%s{ ... }` for function literal", sbody);
5223 1.1 mrg }
5224 1.1 mrg else if (!requireDo) // allow contracts even with no body
5225 1.1 mrg {
5226 1.1 mrg TOK t = token.value;
5227 1.1 mrg if (t == TOK.const_ || t == TOK.immutable_ || t == TOK.inout_ || t == TOK.return_ ||
5228 1.1 mrg t == TOK.shared_ || t == TOK.nothrow_ || t == TOK.pure_)
5229 1.1 mrg error("'%s' cannot be placed after a template constraint", token.toChars);
5230 1.1 mrg else if (t == TOK.at)
5231 1.1 mrg error("attributes cannot be placed after a template constraint");
5232 1.1 mrg else if (t == TOK.if_)
5233 1.1 mrg error("cannot use function constraints for non-template functions. Use `static if` instead");
5234 1.1 mrg else
5235 1.1 mrg error("semicolon expected following function declaration");
5236 1.1 mrg }
5237 1.1 mrg break;
5238 1.1 mrg }
5239 1.1 mrg if (literal && !f.fbody)
5240 1.1 mrg {
5241 1.1 mrg // Set empty function body for error recovery
5242 1.1 mrg f.fbody = new AST.CompoundStatement(Loc.initial, cast(AST.Statement)null);
5243 1.1 mrg }
5244 1.1 mrg
5245 1.1 mrg linkage = linksave;
5246 1.1 mrg
5247 1.1 mrg return f;
5248 1.1 mrg }
5249 1.1 mrg
5250 1.1 mrg /*****************************************
5251 1.1 mrg */
5252 1.1 mrg private void checkDanglingElse(Loc elseloc)
5253 1.1 mrg {
5254 1.1 mrg if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0)
5255 1.1 mrg {
5256 1.1 mrg warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
5257 1.1 mrg }
5258 1.1 mrg }
5259 1.1 mrg
5260 1.1 mrg /* *************************
5261 1.1 mrg * Issue errors if C-style syntax
5262 1.1 mrg * Params:
5263 1.1 mrg * alt = !=0 for C-style syntax
5264 1.1 mrg */
5265 1.1 mrg private void checkCstyleTypeSyntax(Loc loc, AST.Type t, int alt, Identifier ident)
5266 1.1 mrg {
5267 1.1 mrg if (!alt)
5268 1.1 mrg return;
5269 1.1 mrg
5270 1.1 mrg const(char)* sp = !ident ? "" : " ";
5271 1.1 mrg const(char)* s = !ident ? "" : ident.toChars();
5272 1.1 mrg error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t.toChars(), sp, s);
5273 1.1 mrg }
5274 1.1 mrg
5275 1.1 mrg /*****************************************
5276 1.1 mrg * Parses `foreach` statements, `static foreach` statements and
5277 1.1 mrg * `static foreach` declarations.
5278 1.1 mrg * Params:
5279 1.1 mrg * Foreach = one of Statement, StaticForeachStatement, StaticForeachDeclaration
5280 1.1 mrg * loc = location of foreach
5281 1.1 mrg * pLastDecl = non-null for StaticForeachDeclaration
5282 1.1 mrg * Returns:
5283 1.1 mrg * the Foreach generated
5284 1.1 mrg */
5285 1.1 mrg private Foreach parseForeach(alias Foreach)(Loc loc, AST.Dsymbol* pLastDecl)
5286 1.1 mrg {
5287 1.1 mrg static if (is(Foreach == AST.StaticForeachStatement) || is(Foreach == AST.StaticForeachDeclaration))
5288 1.1 mrg {
5289 1.1 mrg nextToken();
5290 1.1 mrg }
5291 1.1 mrg
5292 1.1 mrg TOK op = token.value;
5293 1.1 mrg
5294 1.1 mrg nextToken();
5295 1.1 mrg check(TOK.leftParenthesis);
5296 1.1 mrg
5297 1.1 mrg auto parameters = new AST.Parameters();
5298 1.1 mrg Identifier lastai;
5299 1.1 mrg while (1)
5300 1.1 mrg {
5301 1.1 mrg Identifier ai = null;
5302 1.1 mrg AST.Type at;
5303 1.1 mrg
5304 1.1 mrg StorageClass storageClass = 0;
5305 1.1 mrg StorageClass stc = 0;
5306 1.1 mrg Lagain:
5307 1.1 mrg if (stc)
5308 1.1 mrg {
5309 1.1 mrg storageClass = appendStorageClass(storageClass, stc);
5310 1.1 mrg nextToken();
5311 1.1 mrg }
5312 1.1 mrg switch (token.value)
5313 1.1 mrg {
5314 1.1 mrg case TOK.ref_:
5315 1.1 mrg stc = STC.ref_;
5316 1.1 mrg goto Lagain;
5317 1.1 mrg
5318 1.1 mrg case TOK.scope_:
5319 1.1 mrg stc = STC.scope_;
5320 1.1 mrg goto Lagain;
5321 1.1 mrg
5322 1.1 mrg case TOK.out_:
5323 1.1 mrg error("cannot declare `out` loop variable, use `ref` instead");
5324 1.1 mrg stc = STC.out_;
5325 1.1 mrg goto Lagain;
5326 1.1 mrg
5327 1.1 mrg case TOK.enum_:
5328 1.1 mrg stc = STC.manifest;
5329 1.1 mrg goto Lagain;
5330 1.1 mrg
5331 1.1 mrg case TOK.alias_:
5332 1.1 mrg storageClass = appendStorageClass(storageClass, STC.alias_);
5333 1.1 mrg nextToken();
5334 1.1 mrg break;
5335 1.1 mrg
5336 1.1 mrg case TOK.const_:
5337 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5338 1.1 mrg {
5339 1.1 mrg stc = STC.const_;
5340 1.1 mrg goto Lagain;
5341 1.1 mrg }
5342 1.1 mrg break;
5343 1.1 mrg
5344 1.1 mrg case TOK.immutable_:
5345 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5346 1.1 mrg {
5347 1.1 mrg stc = STC.immutable_;
5348 1.1 mrg goto Lagain;
5349 1.1 mrg }
5350 1.1 mrg break;
5351 1.1 mrg
5352 1.1 mrg case TOK.shared_:
5353 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5354 1.1 mrg {
5355 1.1 mrg stc = STC.shared_;
5356 1.1 mrg goto Lagain;
5357 1.1 mrg }
5358 1.1 mrg break;
5359 1.1 mrg
5360 1.1 mrg case TOK.inout_:
5361 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5362 1.1 mrg {
5363 1.1 mrg stc = STC.wild;
5364 1.1 mrg goto Lagain;
5365 1.1 mrg }
5366 1.1 mrg break;
5367 1.1 mrg
5368 1.1 mrg default:
5369 1.1 mrg break;
5370 1.1 mrg }
5371 1.1 mrg if (token.value == TOK.identifier)
5372 1.1 mrg {
5373 1.1 mrg const tv = peekNext();
5374 1.1 mrg if (tv == TOK.comma || tv == TOK.semicolon || tv == TOK.rightParenthesis)
5375 1.1 mrg {
5376 1.1 mrg lastai = token.ident;
5377 1.1 mrg ai = token.ident;
5378 1.1 mrg at = null; // infer argument type
5379 1.1 mrg nextToken();
5380 1.1 mrg goto Larg;
5381 1.1 mrg }
5382 1.1 mrg }
5383 1.1 mrg at = parseType(&ai);
5384 1.1 mrg if (!ai)
5385 1.1 mrg error("no identifier for declarator `%s`", at.toChars());
5386 1.1 mrg Larg:
5387 1.1 mrg auto p = new AST.Parameter(storageClass, at, ai, null, null);
5388 1.1 mrg parameters.push(p);
5389 1.1 mrg if (token.value == TOK.comma)
5390 1.1 mrg {
5391 1.1 mrg nextToken();
5392 1.1 mrg continue;
5393 1.1 mrg }
5394 1.1 mrg break;
5395 1.1 mrg }
5396 1.1 mrg if (token.value != TOK.semicolon)
5397 1.1 mrg {
5398 1.1 mrg error("missing `; expression` before `)` of `foreach`");
5399 1.1 mrg nextToken();
5400 1.1 mrg if (lastai && parameters.length >= 2)
5401 1.1 mrg {
5402 1.1 mrg errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars());
5403 1.1 mrg }
5404 1.1 mrg return null;
5405 1.1 mrg }
5406 1.1 mrg nextToken();
5407 1.1 mrg
5408 1.1 mrg AST.Expression aggr = parseExpression();
5409 1.1 mrg if (token.value == TOK.slice && parameters.dim == 1)
5410 1.1 mrg {
5411 1.1 mrg AST.Parameter p = (*parameters)[0];
5412 1.1 mrg nextToken();
5413 1.1 mrg AST.Expression upr = parseExpression();
5414 1.1 mrg check(TOK.rightParenthesis);
5415 1.1 mrg Loc endloc;
5416 1.1 mrg static if (is(Foreach == AST.Statement) || is(Foreach == AST.StaticForeachStatement))
5417 1.1 mrg {
5418 1.1 mrg AST.Statement _body = parseStatement(0, null, &endloc);
5419 1.1 mrg }
5420 1.1 mrg else
5421 1.1 mrg {
5422 1.1 mrg AST.Statement _body = null;
5423 1.1 mrg }
5424 1.1 mrg auto rangefe = new AST.ForeachRangeStatement(loc, op, p, aggr, upr, _body, endloc);
5425 1.1 mrg static if (is(Foreach == AST.Statement))
5426 1.1 mrg {
5427 1.1 mrg return rangefe;
5428 1.1 mrg }
5429 1.1 mrg else static if(is(Foreach == AST.StaticForeachDeclaration))
5430 1.1 mrg {
5431 1.1 mrg return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, null, rangefe), parseBlock(pLastDecl));
5432 1.1 mrg }
5433 1.1 mrg else static if (is(Foreach == AST.StaticForeachStatement))
5434 1.1 mrg {
5435 1.1 mrg return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, null, rangefe));
5436 1.1 mrg }
5437 1.1 mrg }
5438 1.1 mrg else
5439 1.1 mrg {
5440 1.1 mrg check(TOK.rightParenthesis);
5441 1.1 mrg Loc endloc;
5442 1.1 mrg static if (is(Foreach == AST.Statement) || is(Foreach == AST.StaticForeachStatement))
5443 1.1 mrg {
5444 1.1 mrg AST.Statement _body = parseStatement(0, null, &endloc);
5445 1.1 mrg }
5446 1.1 mrg else
5447 1.1 mrg {
5448 1.1 mrg AST.Statement _body = null;
5449 1.1 mrg }
5450 1.1 mrg auto aggrfe = new AST.ForeachStatement(loc, op, parameters, aggr, _body, endloc);
5451 1.1 mrg static if (is(Foreach == AST.Statement))
5452 1.1 mrg {
5453 1.1 mrg return aggrfe;
5454 1.1 mrg }
5455 1.1 mrg else static if(is(Foreach == AST.StaticForeachDeclaration))
5456 1.1 mrg {
5457 1.1 mrg return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, aggrfe, null), parseBlock(pLastDecl));
5458 1.1 mrg }
5459 1.1 mrg else static if (is(Foreach == AST.StaticForeachStatement))
5460 1.1 mrg {
5461 1.1 mrg return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, aggrfe, null));
5462 1.1 mrg }
5463 1.1 mrg }
5464 1.1 mrg
5465 1.1 mrg }
5466 1.1 mrg
5467 1.1 mrg /***
5468 1.1 mrg * Parse an assignment condition for if or while statements.
5469 1.1 mrg *
5470 1.1 mrg * Returns:
5471 1.1 mrg * The variable that is declared inside the condition
5472 1.1 mrg */
5473 1.1 mrg AST.Parameter parseAssignCondition()
5474 1.1 mrg {
5475 1.1 mrg AST.Parameter param = null;
5476 1.1 mrg StorageClass storageClass = 0;
5477 1.1 mrg StorageClass stc = 0;
5478 1.1 mrg LagainStc:
5479 1.1 mrg if (stc)
5480 1.1 mrg {
5481 1.1 mrg storageClass = appendStorageClass(storageClass, stc);
5482 1.1 mrg nextToken();
5483 1.1 mrg }
5484 1.1 mrg switch (token.value)
5485 1.1 mrg {
5486 1.1 mrg case TOK.ref_:
5487 1.1 mrg stc = STC.ref_;
5488 1.1 mrg goto LagainStc;
5489 1.1 mrg
5490 1.1 mrg case TOK.scope_:
5491 1.1 mrg stc = STC.scope_;
5492 1.1 mrg goto LagainStc;
5493 1.1 mrg
5494 1.1 mrg case TOK.auto_:
5495 1.1 mrg stc = STC.auto_;
5496 1.1 mrg goto LagainStc;
5497 1.1 mrg
5498 1.1 mrg case TOK.const_:
5499 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5500 1.1 mrg {
5501 1.1 mrg stc = STC.const_;
5502 1.1 mrg goto LagainStc;
5503 1.1 mrg }
5504 1.1 mrg break;
5505 1.1 mrg
5506 1.1 mrg case TOK.immutable_:
5507 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5508 1.1 mrg {
5509 1.1 mrg stc = STC.immutable_;
5510 1.1 mrg goto LagainStc;
5511 1.1 mrg }
5512 1.1 mrg break;
5513 1.1 mrg
5514 1.1 mrg case TOK.shared_:
5515 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5516 1.1 mrg {
5517 1.1 mrg stc = STC.shared_;
5518 1.1 mrg goto LagainStc;
5519 1.1 mrg }
5520 1.1 mrg break;
5521 1.1 mrg
5522 1.1 mrg case TOK.inout_:
5523 1.1 mrg if (peekNext() != TOK.leftParenthesis)
5524 1.1 mrg {
5525 1.1 mrg stc = STC.wild;
5526 1.1 mrg goto LagainStc;
5527 1.1 mrg }
5528 1.1 mrg break;
5529 1.1 mrg
5530 1.1 mrg default:
5531 1.1 mrg break;
5532 1.1 mrg }
5533 1.1 mrg auto n = peek(&token);
5534 1.1 mrg if (storageClass != 0 && token.value == TOK.identifier && n.value == TOK.assign)
5535 1.1 mrg {
5536 1.1 mrg Identifier ai = token.ident;
5537 1.1 mrg AST.Type at = null; // infer parameter type
5538 1.1 mrg nextToken();
5539 1.1 mrg check(TOK.assign);
5540 1.1 mrg param = new AST.Parameter(storageClass, at, ai, null, null);
5541 1.1 mrg }
5542 1.1 mrg else if (isDeclaration(&token, NeedDeclaratorId.must, TOK.assign, null))
5543 1.1 mrg {
5544 1.1 mrg Identifier ai;
5545 1.1 mrg AST.Type at = parseType(&ai);
5546 1.1 mrg check(TOK.assign);
5547 1.1 mrg param = new AST.Parameter(storageClass, at, ai, null, null);
5548 1.1 mrg }
5549 1.1 mrg else if (storageClass != 0)
5550 1.1 mrg error("found `%s` while expecting `=` or identifier", n.toChars());
5551 1.1 mrg
5552 1.1 mrg return param;
5553 1.1 mrg }
5554 1.1 mrg
5555 1.1 mrg /*****************************************
5556 1.1 mrg * Input:
5557 1.1 mrg * flags PSxxxx
5558 1.1 mrg * Output:
5559 1.1 mrg * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
5560 1.1 mrg */
5561 1.1 mrg AST.Statement parseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
5562 1.1 mrg {
5563 1.1 mrg AST.Statement s;
5564 1.1 mrg AST.Condition cond;
5565 1.1 mrg AST.Statement ifbody;
5566 1.1 mrg AST.Statement elsebody;
5567 1.1 mrg bool isfinal;
5568 1.1 mrg const loc = token.loc;
5569 1.1 mrg
5570 1.1 mrg //printf("parseStatement()\n");
5571 1.1 mrg if (flags & ParseStatementFlags.curly && token.value != TOK.leftCurly)
5572 1.1 mrg error("statement expected to be `{ }`, not `%s`", token.toChars());
5573 1.1 mrg
5574 1.1 mrg switch (token.value)
5575 1.1 mrg {
5576 1.1 mrg case TOK.identifier:
5577 1.1 mrg {
5578 1.1 mrg /* A leading identifier can be a declaration, label, or expression.
5579 1.1 mrg * The easiest case to check first is label:
5580 1.1 mrg */
5581 1.1 mrg if (peekNext() == TOK.colonColon)
5582 1.1 mrg {
5583 1.1 mrg // skip ident::
5584 1.1 mrg nextToken();
5585 1.1 mrg nextToken();
5586 1.1 mrg error("use `.` for member lookup, not `::`");
5587 1.1 mrg break;
5588 1.1 mrg }
5589 1.1 mrg
5590 1.1 mrg if (peekNext() == TOK.colon)
5591 1.1 mrg {
5592 1.1 mrg // It's a label
5593 1.1 mrg Identifier ident = token.ident;
5594 1.1 mrg nextToken();
5595 1.1 mrg nextToken();
5596 1.1 mrg if (token.value == TOK.rightCurly)
5597 1.1 mrg s = null;
5598 1.1 mrg else if (token.value == TOK.leftCurly)
5599 1.1 mrg s = parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
5600 1.1 mrg else
5601 1.1 mrg s = parseStatement(ParseStatementFlags.semiOk);
5602 1.1 mrg s = new AST.LabelStatement(loc, ident, s);
5603 1.1 mrg break;
5604 1.1 mrg }
5605 1.1 mrg goto case TOK.dot;
5606 1.1 mrg }
5607 1.1 mrg case TOK.dot:
5608 1.1 mrg case TOK.typeof_:
5609 1.1 mrg case TOK.vector:
5610 1.1 mrg case TOK.traits:
5611 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=15163
5612 1.1 mrg * If tokens can be handled as
5613 1.1 mrg * old C-style declaration or D expression, prefer the latter.
5614 1.1 mrg */
5615 1.1 mrg if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
5616 1.1 mrg goto Ldeclaration;
5617 1.1 mrg goto Lexp;
5618 1.1 mrg
5619 1.1 mrg case TOK.assert_:
5620 1.1 mrg case TOK.this_:
5621 1.1 mrg case TOK.super_:
5622 1.1 mrg case TOK.int32Literal:
5623 1.1 mrg case TOK.uns32Literal:
5624 1.1 mrg case TOK.int64Literal:
5625 1.1 mrg case TOK.uns64Literal:
5626 1.1 mrg case TOK.int128Literal:
5627 1.1 mrg case TOK.uns128Literal:
5628 1.1 mrg case TOK.float32Literal:
5629 1.1 mrg case TOK.float64Literal:
5630 1.1 mrg case TOK.float80Literal:
5631 1.1 mrg case TOK.imaginary32Literal:
5632 1.1 mrg case TOK.imaginary64Literal:
5633 1.1 mrg case TOK.imaginary80Literal:
5634 1.1 mrg case TOK.charLiteral:
5635 1.1 mrg case TOK.wcharLiteral:
5636 1.1 mrg case TOK.dcharLiteral:
5637 1.1 mrg case TOK.null_:
5638 1.1 mrg case TOK.true_:
5639 1.1 mrg case TOK.false_:
5640 1.1 mrg case TOK.string_:
5641 1.1 mrg case TOK.leftParenthesis:
5642 1.1 mrg case TOK.cast_:
5643 1.1 mrg case TOK.mul:
5644 1.1 mrg case TOK.min:
5645 1.1 mrg case TOK.add:
5646 1.1 mrg case TOK.tilde:
5647 1.1 mrg case TOK.not:
5648 1.1 mrg case TOK.plusPlus:
5649 1.1 mrg case TOK.minusMinus:
5650 1.1 mrg case TOK.new_:
5651 1.1 mrg case TOK.delete_:
5652 1.1 mrg case TOK.delegate_:
5653 1.1 mrg case TOK.function_:
5654 1.1 mrg case TOK.typeid_:
5655 1.1 mrg case TOK.is_:
5656 1.1 mrg case TOK.leftBracket:
5657 1.1 mrg case TOK.file:
5658 1.1 mrg case TOK.fileFullPath:
5659 1.1 mrg case TOK.line:
5660 1.1 mrg case TOK.moduleString:
5661 1.1 mrg case TOK.functionString:
5662 1.1 mrg case TOK.prettyFunction:
5663 1.1 mrg Lexp:
5664 1.1 mrg {
5665 1.1 mrg AST.Expression exp = parseExpression();
5666 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=15103
5667 1.1 mrg * Improve declaration / initialization syntax error message
5668 1.1 mrg * Error: found 'foo' when expecting ';' following statement
5669 1.1 mrg * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
5670 1.1 mrg */
5671 1.1 mrg if (token.value == TOK.identifier && exp.op == EXP.identifier)
5672 1.1 mrg {
5673 1.1 mrg error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
5674 1.1 mrg nextToken();
5675 1.1 mrg }
5676 1.1 mrg else
5677 1.1 mrg {
5678 1.1 mrg /*
5679 1.1 mrg * https://issues.dlang.org/show_bug.cgi?id=22529
5680 1.1 mrg * Avoid empty declaration error in case of missing semicolon
5681 1.1 mrg * followed by another token and another semicolon. E.g.:
5682 1.1 mrg *
5683 1.1 mrg * foo()
5684 1.1 mrg * return;
5685 1.1 mrg *
5686 1.1 mrg * When the missing `;` error is emitted, token is sitting on return.
5687 1.1 mrg * If we simply use `check` to emit the error, the token is advanced
5688 1.1 mrg * to `;` and the empty statement error would follow. To avoid that,
5689 1.1 mrg * we check if the next token is a semicolon and simply output the error,
5690 1.1 mrg * otherwise we fall back on the old path (advancing the token).
5691 1.1 mrg */
5692 1.1 mrg if (token.value != TOK.semicolon && peek(&token).value == TOK.semicolon)
5693 1.1 mrg error("found `%s` when expecting `;` following statement", token.toChars());
5694 1.1 mrg else
5695 1.1 mrg check(TOK.semicolon, "statement");
5696 1.1 mrg }
5697 1.1 mrg s = new AST.ExpStatement(loc, exp);
5698 1.1 mrg break;
5699 1.1 mrg }
5700 1.1 mrg case TOK.static_:
5701 1.1 mrg {
5702 1.1 mrg // Look ahead to see if it's static assert() or static if()
5703 1.1 mrg const tv = peekNext();
5704 1.1 mrg if (tv == TOK.assert_)
5705 1.1 mrg {
5706 1.1 mrg s = new AST.StaticAssertStatement(parseStaticAssert());
5707 1.1 mrg break;
5708 1.1 mrg }
5709 1.1 mrg if (tv == TOK.if_)
5710 1.1 mrg {
5711 1.1 mrg cond = parseStaticIfCondition();
5712 1.1 mrg goto Lcondition;
5713 1.1 mrg }
5714 1.1 mrg if (tv == TOK.foreach_ || tv == TOK.foreach_reverse_)
5715 1.1 mrg {
5716 1.1 mrg s = parseForeach!(AST.StaticForeachStatement)(loc, null);
5717 1.1 mrg if (flags & ParseStatementFlags.scope_)
5718 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
5719 1.1 mrg break;
5720 1.1 mrg }
5721 1.1 mrg if (tv == TOK.import_)
5722 1.1 mrg {
5723 1.1 mrg AST.Dsymbols* imports = parseImport();
5724 1.1 mrg s = new AST.ImportStatement(loc, imports);
5725 1.1 mrg if (flags & ParseStatementFlags.scope_)
5726 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
5727 1.1 mrg break;
5728 1.1 mrg }
5729 1.1 mrg goto Ldeclaration;
5730 1.1 mrg }
5731 1.1 mrg case TOK.final_:
5732 1.1 mrg if (peekNext() == TOK.switch_)
5733 1.1 mrg {
5734 1.1 mrg nextToken();
5735 1.1 mrg isfinal = true;
5736 1.1 mrg goto Lswitch;
5737 1.1 mrg }
5738 1.1 mrg goto Ldeclaration;
5739 1.1 mrg
5740 1.1 mrg case TOK.wchar_:
5741 1.1 mrg case TOK.dchar_:
5742 1.1 mrg case TOK.bool_:
5743 1.1 mrg case TOK.char_:
5744 1.1 mrg case TOK.int8:
5745 1.1 mrg case TOK.uns8:
5746 1.1 mrg case TOK.int16:
5747 1.1 mrg case TOK.uns16:
5748 1.1 mrg case TOK.int32:
5749 1.1 mrg case TOK.uns32:
5750 1.1 mrg case TOK.int64:
5751 1.1 mrg case TOK.uns64:
5752 1.1 mrg case TOK.int128:
5753 1.1 mrg case TOK.uns128:
5754 1.1 mrg case TOK.float32:
5755 1.1 mrg case TOK.float64:
5756 1.1 mrg case TOK.float80:
5757 1.1 mrg case TOK.imaginary32:
5758 1.1 mrg case TOK.imaginary64:
5759 1.1 mrg case TOK.imaginary80:
5760 1.1 mrg case TOK.complex32:
5761 1.1 mrg case TOK.complex64:
5762 1.1 mrg case TOK.complex80:
5763 1.1 mrg case TOK.void_:
5764 1.1 mrg // bug 7773: int.max is always a part of expression
5765 1.1 mrg if (peekNext() == TOK.dot)
5766 1.1 mrg goto Lexp;
5767 1.1 mrg if (peekNext() == TOK.leftParenthesis)
5768 1.1 mrg goto Lexp;
5769 1.1 mrg goto case;
5770 1.1 mrg
5771 1.1 mrg case TOK.alias_:
5772 1.1 mrg case TOK.const_:
5773 1.1 mrg case TOK.auto_:
5774 1.1 mrg case TOK.abstract_:
5775 1.1 mrg case TOK.extern_:
5776 1.1 mrg case TOK.align_:
5777 1.1 mrg case TOK.immutable_:
5778 1.1 mrg case TOK.shared_:
5779 1.1 mrg case TOK.inout_:
5780 1.1 mrg case TOK.deprecated_:
5781 1.1 mrg case TOK.nothrow_:
5782 1.1 mrg case TOK.pure_:
5783 1.1 mrg case TOK.ref_:
5784 1.1 mrg case TOK.gshared:
5785 1.1 mrg case TOK.at:
5786 1.1 mrg case TOK.struct_:
5787 1.1 mrg case TOK.union_:
5788 1.1 mrg case TOK.class_:
5789 1.1 mrg case TOK.interface_:
5790 1.1 mrg Ldeclaration:
5791 1.1 mrg {
5792 1.1 mrg AST.Dsymbols* a = parseDeclarations(false, null, null);
5793 1.1 mrg if (a.dim > 1)
5794 1.1 mrg {
5795 1.1 mrg auto as = new AST.Statements();
5796 1.1 mrg as.reserve(a.dim);
5797 1.1 mrg foreach (i; 0 .. a.dim)
5798 1.1 mrg {
5799 1.1 mrg AST.Dsymbol d = (*a)[i];
5800 1.1 mrg s = new AST.ExpStatement(loc, d);
5801 1.1 mrg as.push(s);
5802 1.1 mrg }
5803 1.1 mrg s = new AST.CompoundDeclarationStatement(loc, as);
5804 1.1 mrg }
5805 1.1 mrg else if (a.dim == 1)
5806 1.1 mrg {
5807 1.1 mrg AST.Dsymbol d = (*a)[0];
5808 1.1 mrg s = new AST.ExpStatement(loc, d);
5809 1.1 mrg }
5810 1.1 mrg else
5811 1.1 mrg s = new AST.ExpStatement(loc, cast(AST.Expression)null);
5812 1.1 mrg if (flags & ParseStatementFlags.scope_)
5813 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
5814 1.1 mrg break;
5815 1.1 mrg }
5816 1.1 mrg case TOK.enum_:
5817 1.1 mrg {
5818 1.1 mrg /* Determine if this is a manifest constant declaration,
5819 1.1 mrg * or a conventional enum.
5820 1.1 mrg */
5821 1.1 mrg AST.Dsymbol d;
5822 1.1 mrg const tv = peekNext();
5823 1.1 mrg if (tv == TOK.leftCurly || tv == TOK.colon)
5824 1.1 mrg d = parseEnum();
5825 1.1 mrg else if (tv != TOK.identifier)
5826 1.1 mrg goto Ldeclaration;
5827 1.1 mrg else
5828 1.1 mrg {
5829 1.1 mrg const nextv = peekNext2();
5830 1.1 mrg if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
5831 1.1 mrg d = parseEnum();
5832 1.1 mrg else
5833 1.1 mrg goto Ldeclaration;
5834 1.1 mrg }
5835 1.1 mrg s = new AST.ExpStatement(loc, d);
5836 1.1 mrg if (flags & ParseStatementFlags.scope_)
5837 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
5838 1.1 mrg break;
5839 1.1 mrg }
5840 1.1 mrg case TOK.mixin_:
5841 1.1 mrg {
5842 1.1 mrg if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
5843 1.1 mrg goto Ldeclaration;
5844 1.1 mrg if (peekNext() == TOK.leftParenthesis)
5845 1.1 mrg {
5846 1.1 mrg // mixin(string)
5847 1.1 mrg AST.Expression e = parseAssignExp();
5848 1.1 mrg check(TOK.semicolon);
5849 1.1 mrg if (e.op == EXP.mixin_)
5850 1.1 mrg {
5851 1.1 mrg AST.MixinExp cpe = cast(AST.MixinExp)e;
5852 1.1 mrg s = new AST.CompileStatement(loc, cpe.exps);
5853 1.1 mrg }
5854 1.1 mrg else
5855 1.1 mrg {
5856 1.1 mrg s = new AST.ExpStatement(loc, e);
5857 1.1 mrg }
5858 1.1 mrg break;
5859 1.1 mrg }
5860 1.1 mrg AST.Dsymbol d = parseMixin();
5861 1.1 mrg s = new AST.ExpStatement(loc, d);
5862 1.1 mrg if (flags & ParseStatementFlags.scope_)
5863 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
5864 1.1 mrg break;
5865 1.1 mrg }
5866 1.1 mrg case TOK.leftCurly:
5867 1.1 mrg {
5868 1.1 mrg const lookingForElseSave = lookingForElse;
5869 1.1 mrg lookingForElse = Loc.initial;
5870 1.1 mrg
5871 1.1 mrg nextToken();
5872 1.1 mrg //if (token.value == TOK.semicolon)
5873 1.1 mrg // error("use `{ }` for an empty statement, not `;`");
5874 1.1 mrg auto statements = new AST.Statements();
5875 1.1 mrg while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
5876 1.1 mrg {
5877 1.1 mrg statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
5878 1.1 mrg }
5879 1.1 mrg if (endPtr)
5880 1.1 mrg *endPtr = token.ptr;
5881 1.1 mrg endloc = token.loc;
5882 1.1 mrg if (pEndloc)
5883 1.1 mrg {
5884 1.1 mrg *pEndloc = token.loc;
5885 1.1 mrg pEndloc = null; // don't set it again
5886 1.1 mrg }
5887 1.1 mrg s = new AST.CompoundStatement(loc, statements);
5888 1.1 mrg if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
5889 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
5890 1.1 mrg check(TOK.rightCurly, "compound statement");
5891 1.1 mrg lookingForElse = lookingForElseSave;
5892 1.1 mrg break;
5893 1.1 mrg }
5894 1.1 mrg case TOK.while_:
5895 1.1 mrg {
5896 1.1 mrg AST.Parameter param = null;
5897 1.1 mrg nextToken();
5898 1.1 mrg check(TOK.leftParenthesis);
5899 1.1 mrg param = parseAssignCondition();
5900 1.1 mrg AST.Expression condition = parseExpression();
5901 1.1 mrg check(TOK.rightParenthesis);
5902 1.1 mrg Loc endloc;
5903 1.1 mrg AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
5904 1.1 mrg s = new AST.WhileStatement(loc, condition, _body, endloc, param);
5905 1.1 mrg break;
5906 1.1 mrg }
5907 1.1 mrg case TOK.semicolon:
5908 1.1 mrg if (!(flags & ParseStatementFlags.semiOk))
5909 1.1 mrg {
5910 1.1 mrg if (flags & ParseStatementFlags.semi)
5911 1.1 mrg deprecation("use `{ }` for an empty statement, not `;`");
5912 1.1 mrg else
5913 1.1 mrg error("use `{ }` for an empty statement, not `;`");
5914 1.1 mrg }
5915 1.1 mrg nextToken();
5916 1.1 mrg s = new AST.ExpStatement(loc, cast(AST.Expression)null);
5917 1.1 mrg break;
5918 1.1 mrg
5919 1.1 mrg case TOK.do_:
5920 1.1 mrg {
5921 1.1 mrg AST.Statement _body;
5922 1.1 mrg AST.Expression condition;
5923 1.1 mrg
5924 1.1 mrg nextToken();
5925 1.1 mrg const lookingForElseSave = lookingForElse;
5926 1.1 mrg lookingForElse = Loc.initial;
5927 1.1 mrg _body = parseStatement(ParseStatementFlags.scope_);
5928 1.1 mrg lookingForElse = lookingForElseSave;
5929 1.1 mrg check(TOK.while_);
5930 1.1 mrg check(TOK.leftParenthesis);
5931 1.1 mrg condition = parseExpression();
5932 1.1 mrg check(TOK.rightParenthesis);
5933 1.1 mrg if (token.value == TOK.semicolon)
5934 1.1 mrg nextToken();
5935 1.1 mrg else
5936 1.1 mrg error("terminating `;` required after do-while statement");
5937 1.1 mrg s = new AST.DoStatement(loc, _body, condition, token.loc);
5938 1.1 mrg break;
5939 1.1 mrg }
5940 1.1 mrg case TOK.for_:
5941 1.1 mrg {
5942 1.1 mrg AST.Statement _init;
5943 1.1 mrg AST.Expression condition;
5944 1.1 mrg AST.Expression increment;
5945 1.1 mrg
5946 1.1 mrg nextToken();
5947 1.1 mrg check(TOK.leftParenthesis);
5948 1.1 mrg if (token.value == TOK.semicolon)
5949 1.1 mrg {
5950 1.1 mrg _init = null;
5951 1.1 mrg nextToken();
5952 1.1 mrg }
5953 1.1 mrg else
5954 1.1 mrg {
5955 1.1 mrg const lookingForElseSave = lookingForElse;
5956 1.1 mrg lookingForElse = Loc.initial;
5957 1.1 mrg _init = parseStatement(0);
5958 1.1 mrg lookingForElse = lookingForElseSave;
5959 1.1 mrg }
5960 1.1 mrg if (token.value == TOK.semicolon)
5961 1.1 mrg {
5962 1.1 mrg condition = null;
5963 1.1 mrg nextToken();
5964 1.1 mrg }
5965 1.1 mrg else
5966 1.1 mrg {
5967 1.1 mrg condition = parseExpression();
5968 1.1 mrg check(TOK.semicolon, "`for` condition");
5969 1.1 mrg }
5970 1.1 mrg if (token.value == TOK.rightParenthesis)
5971 1.1 mrg {
5972 1.1 mrg increment = null;
5973 1.1 mrg nextToken();
5974 1.1 mrg }
5975 1.1 mrg else
5976 1.1 mrg {
5977 1.1 mrg increment = parseExpression();
5978 1.1 mrg check(TOK.rightParenthesis);
5979 1.1 mrg }
5980 1.1 mrg Loc endloc;
5981 1.1 mrg AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
5982 1.1 mrg s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
5983 1.1 mrg break;
5984 1.1 mrg }
5985 1.1 mrg case TOK.foreach_:
5986 1.1 mrg case TOK.foreach_reverse_:
5987 1.1 mrg {
5988 1.1 mrg s = parseForeach!(AST.Statement)(loc, null);
5989 1.1 mrg break;
5990 1.1 mrg }
5991 1.1 mrg case TOK.if_:
5992 1.1 mrg {
5993 1.1 mrg AST.Parameter param = null;
5994 1.1 mrg AST.Expression condition;
5995 1.1 mrg
5996 1.1 mrg nextToken();
5997 1.1 mrg check(TOK.leftParenthesis);
5998 1.1 mrg param = parseAssignCondition();
5999 1.1 mrg condition = parseExpression();
6000 1.1 mrg if (token.value != TOK.rightParenthesis && condition)
6001 1.1 mrg {
6002 1.1 mrg error("missing closing `)` after `if (%s`", param ? "declaration".ptr : condition.toChars());
6003 1.1 mrg }
6004 1.1 mrg else
6005 1.1 mrg check(TOK.rightParenthesis);
6006 1.1 mrg if (token.value == TOK.rightParenthesis)
6007 1.1 mrg {
6008 1.1 mrg if (condition) // if not an error in condition
6009 1.1 mrg error("extra `)` after `if (%s)`", param ? "declaration".ptr : condition.toChars());
6010 1.1 mrg nextToken();
6011 1.1 mrg }
6012 1.1 mrg
6013 1.1 mrg {
6014 1.1 mrg const lookingForElseSave = lookingForElse;
6015 1.1 mrg lookingForElse = loc;
6016 1.1 mrg ifbody = parseStatement(ParseStatementFlags.scope_);
6017 1.1 mrg lookingForElse = lookingForElseSave;
6018 1.1 mrg }
6019 1.1 mrg if (token.value == TOK.else_)
6020 1.1 mrg {
6021 1.1 mrg const elseloc = token.loc;
6022 1.1 mrg nextToken();
6023 1.1 mrg elsebody = parseStatement(ParseStatementFlags.scope_);
6024 1.1 mrg checkDanglingElse(elseloc);
6025 1.1 mrg }
6026 1.1 mrg else
6027 1.1 mrg elsebody = null;
6028 1.1 mrg if (condition && ifbody)
6029 1.1 mrg s = new AST.IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
6030 1.1 mrg else
6031 1.1 mrg s = null; // don't propagate parsing errors
6032 1.1 mrg break;
6033 1.1 mrg }
6034 1.1 mrg
6035 1.1 mrg case TOK.else_:
6036 1.1 mrg error("found `else` without a corresponding `if`, `version` or `debug` statement");
6037 1.1 mrg goto Lerror;
6038 1.1 mrg
6039 1.1 mrg case TOK.scope_:
6040 1.1 mrg if (peekNext() != TOK.leftParenthesis)
6041 1.1 mrg goto Ldeclaration; // scope used as storage class
6042 1.1 mrg nextToken();
6043 1.1 mrg check(TOK.leftParenthesis);
6044 1.1 mrg if (token.value != TOK.identifier)
6045 1.1 mrg {
6046 1.1 mrg error("scope identifier expected");
6047 1.1 mrg goto Lerror;
6048 1.1 mrg }
6049 1.1 mrg else
6050 1.1 mrg {
6051 1.1 mrg TOK t = TOK.onScopeExit;
6052 1.1 mrg Identifier id = token.ident;
6053 1.1 mrg if (id == Id.exit)
6054 1.1 mrg t = TOK.onScopeExit;
6055 1.1 mrg else if (id == Id.failure)
6056 1.1 mrg t = TOK.onScopeFailure;
6057 1.1 mrg else if (id == Id.success)
6058 1.1 mrg t = TOK.onScopeSuccess;
6059 1.1 mrg else
6060 1.1 mrg error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id.toChars());
6061 1.1 mrg nextToken();
6062 1.1 mrg check(TOK.rightParenthesis);
6063 1.1 mrg AST.Statement st = parseStatement(ParseStatementFlags.scope_);
6064 1.1 mrg s = new AST.ScopeGuardStatement(loc, t, st);
6065 1.1 mrg break;
6066 1.1 mrg }
6067 1.1 mrg
6068 1.1 mrg case TOK.debug_:
6069 1.1 mrg nextToken();
6070 1.1 mrg if (token.value == TOK.assign)
6071 1.1 mrg {
6072 1.1 mrg if (auto ds = parseDebugSpecification())
6073 1.1 mrg {
6074 1.1 mrg if (ds.ident)
6075 1.1 mrg ds.error("declaration must be at module level");
6076 1.1 mrg else
6077 1.1 mrg ds.error("level declaration must be at module level");
6078 1.1 mrg }
6079 1.1 mrg break;
6080 1.1 mrg }
6081 1.1 mrg cond = parseDebugCondition();
6082 1.1 mrg goto Lcondition;
6083 1.1 mrg
6084 1.1 mrg case TOK.version_:
6085 1.1 mrg nextToken();
6086 1.1 mrg if (token.value == TOK.assign)
6087 1.1 mrg {
6088 1.1 mrg if (auto vs = parseVersionSpecification())
6089 1.1 mrg {
6090 1.1 mrg if (vs.ident)
6091 1.1 mrg vs.error("declaration must be at module level");
6092 1.1 mrg else
6093 1.1 mrg vs.error("level declaration must be at module level");
6094 1.1 mrg }
6095 1.1 mrg break;
6096 1.1 mrg }
6097 1.1 mrg cond = parseVersionCondition();
6098 1.1 mrg goto Lcondition;
6099 1.1 mrg
6100 1.1 mrg Lcondition:
6101 1.1 mrg {
6102 1.1 mrg const lookingForElseSave = lookingForElse;
6103 1.1 mrg lookingForElse = loc;
6104 1.1 mrg ifbody = parseStatement(0);
6105 1.1 mrg lookingForElse = lookingForElseSave;
6106 1.1 mrg }
6107 1.1 mrg elsebody = null;
6108 1.1 mrg if (token.value == TOK.else_)
6109 1.1 mrg {
6110 1.1 mrg const elseloc = token.loc;
6111 1.1 mrg nextToken();
6112 1.1 mrg elsebody = parseStatement(0);
6113 1.1 mrg checkDanglingElse(elseloc);
6114 1.1 mrg }
6115 1.1 mrg s = new AST.ConditionalStatement(loc, cond, ifbody, elsebody);
6116 1.1 mrg if (flags & ParseStatementFlags.scope_)
6117 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
6118 1.1 mrg break;
6119 1.1 mrg
6120 1.1 mrg case TOK.pragma_:
6121 1.1 mrg {
6122 1.1 mrg Identifier ident;
6123 1.1 mrg AST.Expressions* args = null;
6124 1.1 mrg AST.Statement _body;
6125 1.1 mrg
6126 1.1 mrg nextToken();
6127 1.1 mrg check(TOK.leftParenthesis);
6128 1.1 mrg if (token.value != TOK.identifier)
6129 1.1 mrg {
6130 1.1 mrg error("`pragma(identifier)` expected");
6131 1.1 mrg goto Lerror;
6132 1.1 mrg }
6133 1.1 mrg ident = token.ident;
6134 1.1 mrg nextToken();
6135 1.1 mrg if (token.value == TOK.comma && peekNext() != TOK.rightParenthesis)
6136 1.1 mrg args = parseArguments(); // pragma(identifier, args...);
6137 1.1 mrg else
6138 1.1 mrg check(TOK.rightParenthesis); // pragma(identifier);
6139 1.1 mrg if (token.value == TOK.semicolon)
6140 1.1 mrg {
6141 1.1 mrg nextToken();
6142 1.1 mrg _body = null;
6143 1.1 mrg }
6144 1.1 mrg else
6145 1.1 mrg _body = parseStatement(ParseStatementFlags.semi);
6146 1.1 mrg s = new AST.PragmaStatement(loc, ident, args, _body);
6147 1.1 mrg break;
6148 1.1 mrg }
6149 1.1 mrg case TOK.switch_:
6150 1.1 mrg isfinal = false;
6151 1.1 mrg goto Lswitch;
6152 1.1 mrg
6153 1.1 mrg Lswitch:
6154 1.1 mrg {
6155 1.1 mrg nextToken();
6156 1.1 mrg check(TOK.leftParenthesis);
6157 1.1 mrg AST.Expression condition = parseExpression();
6158 1.1 mrg check(TOK.rightParenthesis);
6159 1.1 mrg AST.Statement _body = parseStatement(ParseStatementFlags.scope_);
6160 1.1 mrg s = new AST.SwitchStatement(loc, condition, _body, isfinal);
6161 1.1 mrg break;
6162 1.1 mrg }
6163 1.1 mrg case TOK.case_:
6164 1.1 mrg {
6165 1.1 mrg AST.Expression exp;
6166 1.1 mrg AST.Expressions cases; // array of Expression's
6167 1.1 mrg AST.Expression last = null;
6168 1.1 mrg
6169 1.1 mrg nextToken();
6170 1.1 mrg do
6171 1.1 mrg {
6172 1.1 mrg exp = parseAssignExp();
6173 1.1 mrg cases.push(exp);
6174 1.1 mrg if (token.value != TOK.comma)
6175 1.1 mrg break;
6176 1.1 mrg nextToken(); //comma
6177 1.1 mrg }
6178 1.1 mrg while (token.value != TOK.colon && token.value != TOK.endOfFile);
6179 1.1 mrg check(TOK.colon);
6180 1.1 mrg
6181 1.1 mrg /* case exp: .. case last:
6182 1.1 mrg */
6183 1.1 mrg if (token.value == TOK.slice)
6184 1.1 mrg {
6185 1.1 mrg if (cases.dim > 1)
6186 1.1 mrg error("only one `case` allowed for start of case range");
6187 1.1 mrg nextToken();
6188 1.1 mrg check(TOK.case_);
6189 1.1 mrg last = parseAssignExp();
6190 1.1 mrg check(TOK.colon);
6191 1.1 mrg }
6192 1.1 mrg
6193 1.1 mrg if (flags & ParseStatementFlags.curlyScope)
6194 1.1 mrg {
6195 1.1 mrg auto statements = new AST.Statements();
6196 1.1 mrg while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
6197 1.1 mrg {
6198 1.1 mrg auto cur = parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
6199 1.1 mrg statements.push(cur);
6200 1.1 mrg
6201 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=21739
6202 1.1 mrg // Stop at the last break s.t. the following non-case statements are
6203 1.1 mrg // not merged into the current case. This can happen for
6204 1.1 mrg // case 1: ... break;
6205 1.1 mrg // debug { case 2: ... }
6206 1.1 mrg if (cur && cur.isBreakStatement())
6207 1.1 mrg break;
6208 1.1 mrg }
6209 1.1 mrg s = new AST.CompoundStatement(loc, statements);
6210 1.1 mrg }
6211 1.1 mrg else
6212 1.1 mrg {
6213 1.1 mrg s = parseStatement(ParseStatementFlags.semi);
6214 1.1 mrg }
6215 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
6216 1.1 mrg
6217 1.1 mrg if (last)
6218 1.1 mrg {
6219 1.1 mrg s = new AST.CaseRangeStatement(loc, exp, last, s);
6220 1.1 mrg }
6221 1.1 mrg else
6222 1.1 mrg {
6223 1.1 mrg // Keep cases in order by building the case statements backwards
6224 1.1 mrg for (size_t i = cases.dim; i; i--)
6225 1.1 mrg {
6226 1.1 mrg exp = cases[i - 1];
6227 1.1 mrg s = new AST.CaseStatement(loc, exp, s);
6228 1.1 mrg }
6229 1.1 mrg }
6230 1.1 mrg break;
6231 1.1 mrg }
6232 1.1 mrg case TOK.default_:
6233 1.1 mrg {
6234 1.1 mrg nextToken();
6235 1.1 mrg check(TOK.colon);
6236 1.1 mrg
6237 1.1 mrg if (flags & ParseStatementFlags.curlyScope)
6238 1.1 mrg {
6239 1.1 mrg auto statements = new AST.Statements();
6240 1.1 mrg while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
6241 1.1 mrg {
6242 1.1 mrg statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
6243 1.1 mrg }
6244 1.1 mrg s = new AST.CompoundStatement(loc, statements);
6245 1.1 mrg }
6246 1.1 mrg else
6247 1.1 mrg s = parseStatement(ParseStatementFlags.semi);
6248 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
6249 1.1 mrg s = new AST.DefaultStatement(loc, s);
6250 1.1 mrg break;
6251 1.1 mrg }
6252 1.1 mrg case TOK.return_:
6253 1.1 mrg {
6254 1.1 mrg AST.Expression exp;
6255 1.1 mrg nextToken();
6256 1.1 mrg exp = token.value == TOK.semicolon ? null : parseExpression();
6257 1.1 mrg check(TOK.semicolon, "`return` statement");
6258 1.1 mrg s = new AST.ReturnStatement(loc, exp);
6259 1.1 mrg break;
6260 1.1 mrg }
6261 1.1 mrg case TOK.break_:
6262 1.1 mrg {
6263 1.1 mrg Identifier ident;
6264 1.1 mrg nextToken();
6265 1.1 mrg ident = null;
6266 1.1 mrg if (token.value == TOK.identifier)
6267 1.1 mrg {
6268 1.1 mrg ident = token.ident;
6269 1.1 mrg nextToken();
6270 1.1 mrg }
6271 1.1 mrg check(TOK.semicolon, "`break` statement");
6272 1.1 mrg s = new AST.BreakStatement(loc, ident);
6273 1.1 mrg break;
6274 1.1 mrg }
6275 1.1 mrg case TOK.continue_:
6276 1.1 mrg {
6277 1.1 mrg Identifier ident;
6278 1.1 mrg nextToken();
6279 1.1 mrg ident = null;
6280 1.1 mrg if (token.value == TOK.identifier)
6281 1.1 mrg {
6282 1.1 mrg ident = token.ident;
6283 1.1 mrg nextToken();
6284 1.1 mrg }
6285 1.1 mrg check(TOK.semicolon, "`continue` statement");
6286 1.1 mrg s = new AST.ContinueStatement(loc, ident);
6287 1.1 mrg break;
6288 1.1 mrg }
6289 1.1 mrg case TOK.goto_:
6290 1.1 mrg {
6291 1.1 mrg Identifier ident;
6292 1.1 mrg nextToken();
6293 1.1 mrg if (token.value == TOK.default_)
6294 1.1 mrg {
6295 1.1 mrg nextToken();
6296 1.1 mrg s = new AST.GotoDefaultStatement(loc);
6297 1.1 mrg }
6298 1.1 mrg else if (token.value == TOK.case_)
6299 1.1 mrg {
6300 1.1 mrg AST.Expression exp = null;
6301 1.1 mrg nextToken();
6302 1.1 mrg if (token.value != TOK.semicolon)
6303 1.1 mrg exp = parseExpression();
6304 1.1 mrg s = new AST.GotoCaseStatement(loc, exp);
6305 1.1 mrg }
6306 1.1 mrg else
6307 1.1 mrg {
6308 1.1 mrg if (token.value != TOK.identifier)
6309 1.1 mrg {
6310 1.1 mrg error("identifier expected following `goto`");
6311 1.1 mrg ident = null;
6312 1.1 mrg }
6313 1.1 mrg else
6314 1.1 mrg {
6315 1.1 mrg ident = token.ident;
6316 1.1 mrg nextToken();
6317 1.1 mrg }
6318 1.1 mrg s = new AST.GotoStatement(loc, ident);
6319 1.1 mrg }
6320 1.1 mrg check(TOK.semicolon, "`goto` statement");
6321 1.1 mrg break;
6322 1.1 mrg }
6323 1.1 mrg case TOK.synchronized_:
6324 1.1 mrg {
6325 1.1 mrg AST.Expression exp;
6326 1.1 mrg AST.Statement _body;
6327 1.1 mrg
6328 1.1 mrg Token* t = peek(&token);
6329 1.1 mrg if (skipAttributes(t, &t) && t.value == TOK.class_)
6330 1.1 mrg goto Ldeclaration;
6331 1.1 mrg
6332 1.1 mrg nextToken();
6333 1.1 mrg if (token.value == TOK.leftParenthesis)
6334 1.1 mrg {
6335 1.1 mrg nextToken();
6336 1.1 mrg exp = parseExpression();
6337 1.1 mrg check(TOK.rightParenthesis);
6338 1.1 mrg }
6339 1.1 mrg else
6340 1.1 mrg exp = null;
6341 1.1 mrg _body = parseStatement(ParseStatementFlags.scope_);
6342 1.1 mrg s = new AST.SynchronizedStatement(loc, exp, _body);
6343 1.1 mrg break;
6344 1.1 mrg }
6345 1.1 mrg case TOK.with_:
6346 1.1 mrg {
6347 1.1 mrg AST.Expression exp;
6348 1.1 mrg AST.Statement _body;
6349 1.1 mrg Loc endloc = loc;
6350 1.1 mrg
6351 1.1 mrg nextToken();
6352 1.1 mrg check(TOK.leftParenthesis);
6353 1.1 mrg exp = parseExpression();
6354 1.1 mrg check(TOK.rightParenthesis);
6355 1.1 mrg _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
6356 1.1 mrg s = new AST.WithStatement(loc, exp, _body, endloc);
6357 1.1 mrg break;
6358 1.1 mrg }
6359 1.1 mrg case TOK.try_:
6360 1.1 mrg {
6361 1.1 mrg AST.Statement _body;
6362 1.1 mrg AST.Catches* catches = null;
6363 1.1 mrg AST.Statement finalbody = null;
6364 1.1 mrg
6365 1.1 mrg nextToken();
6366 1.1 mrg const lookingForElseSave = lookingForElse;
6367 1.1 mrg lookingForElse = Loc.initial;
6368 1.1 mrg _body = parseStatement(ParseStatementFlags.scope_);
6369 1.1 mrg lookingForElse = lookingForElseSave;
6370 1.1 mrg while (token.value == TOK.catch_)
6371 1.1 mrg {
6372 1.1 mrg AST.Statement handler;
6373 1.1 mrg AST.Catch c;
6374 1.1 mrg AST.Type t;
6375 1.1 mrg Identifier id;
6376 1.1 mrg const catchloc = token.loc;
6377 1.1 mrg
6378 1.1 mrg nextToken();
6379 1.1 mrg if (token.value != TOK.leftParenthesis)
6380 1.1 mrg {
6381 1.1 mrg deprecation("`catch` statement without an exception specification is deprecated");
6382 1.1 mrg deprecationSupplemental(token.loc, "use `catch(Throwable)` for old behavior");
6383 1.1 mrg t = null;
6384 1.1 mrg id = null;
6385 1.1 mrg }
6386 1.1 mrg else
6387 1.1 mrg {
6388 1.1 mrg check(TOK.leftParenthesis);
6389 1.1 mrg id = null;
6390 1.1 mrg t = parseType(&id);
6391 1.1 mrg check(TOK.rightParenthesis);
6392 1.1 mrg }
6393 1.1 mrg handler = parseStatement(0);
6394 1.1 mrg c = new AST.Catch(catchloc, t, id, handler);
6395 1.1 mrg if (!catches)
6396 1.1 mrg catches = new AST.Catches();
6397 1.1 mrg catches.push(c);
6398 1.1 mrg }
6399 1.1 mrg
6400 1.1 mrg if (token.value == TOK.finally_)
6401 1.1 mrg {
6402 1.1 mrg nextToken();
6403 1.1 mrg finalbody = parseStatement(ParseStatementFlags.scope_);
6404 1.1 mrg }
6405 1.1 mrg
6406 1.1 mrg s = _body;
6407 1.1 mrg if (!catches && !finalbody)
6408 1.1 mrg error("`catch` or `finally` expected following `try`");
6409 1.1 mrg else
6410 1.1 mrg {
6411 1.1 mrg if (catches)
6412 1.1 mrg s = new AST.TryCatchStatement(loc, _body, catches);
6413 1.1 mrg if (finalbody)
6414 1.1 mrg s = new AST.TryFinallyStatement(loc, s, finalbody);
6415 1.1 mrg }
6416 1.1 mrg break;
6417 1.1 mrg }
6418 1.1 mrg case TOK.throw_:
6419 1.1 mrg {
6420 1.1 mrg AST.Expression exp;
6421 1.1 mrg nextToken();
6422 1.1 mrg exp = parseExpression();
6423 1.1 mrg check(TOK.semicolon, "`throw` statement");
6424 1.1 mrg s = new AST.ThrowStatement(loc, exp);
6425 1.1 mrg break;
6426 1.1 mrg }
6427 1.1 mrg
6428 1.1 mrg case TOK.asm_:
6429 1.1 mrg s = parseAsm();
6430 1.1 mrg break;
6431 1.1 mrg
6432 1.1 mrg case TOK.import_:
6433 1.1 mrg {
6434 1.1 mrg /* https://issues.dlang.org/show_bug.cgi?id=16088
6435 1.1 mrg *
6436 1.1 mrg * At this point it can either be an
6437 1.1 mrg * https://dlang.org/spec/grammar.html#ImportExpression
6438 1.1 mrg * or an
6439 1.1 mrg * https://dlang.org/spec/grammar.html#ImportDeclaration.
6440 1.1 mrg * See if the next token after `import` is a `(`; if so,
6441 1.1 mrg * then it is an import expression.
6442 1.1 mrg */
6443 1.1 mrg if (peekNext() == TOK.leftParenthesis)
6444 1.1 mrg {
6445 1.1 mrg AST.Expression e = parseExpression();
6446 1.1 mrg check(TOK.semicolon);
6447 1.1 mrg s = new AST.ExpStatement(loc, e);
6448 1.1 mrg }
6449 1.1 mrg else
6450 1.1 mrg {
6451 1.1 mrg AST.Dsymbols* imports = parseImport();
6452 1.1 mrg s = new AST.ImportStatement(loc, imports);
6453 1.1 mrg if (flags & ParseStatementFlags.scope_)
6454 1.1 mrg s = new AST.ScopeStatement(loc, s, token.loc);
6455 1.1 mrg }
6456 1.1 mrg break;
6457 1.1 mrg }
6458 1.1 mrg case TOK.template_:
6459 1.1 mrg {
6460 1.1 mrg AST.Dsymbol d = parseTemplateDeclaration();
6461 1.1 mrg s = new AST.ExpStatement(loc, d);
6462 1.1 mrg break;
6463 1.1 mrg }
6464 1.1 mrg default:
6465 1.1 mrg error("found `%s` instead of statement", token.toChars());
6466 1.1 mrg goto Lerror;
6467 1.1 mrg
6468 1.1 mrg Lerror:
6469 1.1 mrg while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
6470 1.1 mrg nextToken();
6471 1.1 mrg if (token.value == TOK.semicolon)
6472 1.1 mrg nextToken();
6473 1.1 mrg s = null;
6474 1.1 mrg break;
6475 1.1 mrg }
6476 1.1 mrg if (pEndloc)
6477 1.1 mrg *pEndloc = prevloc;
6478 1.1 mrg return s;
6479 1.1 mrg }
6480 1.1 mrg
6481 1.1 mrg
6482 1.1 mrg private AST.ExpInitializer parseExpInitializer(Loc loc)
6483 1.1 mrg {
6484 1.1 mrg auto ae = parseAssignExp();
6485 1.1 mrg return new AST.ExpInitializer(loc, ae);
6486 1.1 mrg }
6487 1.1 mrg
6488 1.1 mrg private AST.Initializer parseStructInitializer(Loc loc)
6489 1.1 mrg {
6490 1.1 mrg /* Scan ahead to discern between a struct initializer and
6491 1.1 mrg * parameterless function literal.
6492 1.1 mrg *
6493 1.1 mrg * We'll scan the topmost curly bracket level for statement-related
6494 1.1 mrg * tokens, thereby ruling out a struct initializer. (A struct
6495 1.1 mrg * initializer which itself contains function literals may have
6496 1.1 mrg * statements at nested curly bracket levels.)
6497 1.1 mrg *
6498 1.1 mrg * It's important that this function literal check not be
6499 1.1 mrg * pendantic, otherwise a function having the slightest syntax
6500 1.1 mrg * error would emit confusing errors when we proceed to parse it
6501 1.1 mrg * as a struct initializer.
6502 1.1 mrg *
6503 1.1 mrg * The following two ambiguous cases will be treated as a struct
6504 1.1 mrg * initializer (best we can do without type info):
6505 1.1 mrg * {}
6506 1.1 mrg * {{statements...}} - i.e. it could be struct initializer
6507 1.1 mrg * with one function literal, or function literal having an
6508 1.1 mrg * extra level of curly brackets
6509 1.1 mrg * If a function literal is intended in these cases (unlikely),
6510 1.1 mrg * source can use a more explicit function literal syntax
6511 1.1 mrg * (e.g. prefix with "()" for empty parameter list).
6512 1.1 mrg */
6513 1.1 mrg int braces = 1;
6514 1.1 mrg int parens = 0;
6515 1.1 mrg for (auto t = peek(&token); 1; t = peek(t))
6516 1.1 mrg {
6517 1.1 mrg switch (t.value)
6518 1.1 mrg {
6519 1.1 mrg case TOK.leftParenthesis:
6520 1.1 mrg parens++;
6521 1.1 mrg continue;
6522 1.1 mrg case TOK.rightParenthesis:
6523 1.1 mrg parens--;
6524 1.1 mrg continue;
6525 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=21163
6526 1.1 mrg // lambda params can have the `scope` storage class, e.g
6527 1.1 mrg // `S s = { (scope Type Id){} }`
6528 1.1 mrg case TOK.scope_:
6529 1.1 mrg if (!parens) goto case;
6530 1.1 mrg continue;
6531 1.1 mrg /* Look for a semicolon or keyword of statements which don't
6532 1.1 mrg * require a semicolon (typically containing BlockStatement).
6533 1.1 mrg * Tokens like "else", "catch", etc. are omitted where the
6534 1.1 mrg * leading token of the statement is sufficient.
6535 1.1 mrg */
6536 1.1 mrg case TOK.asm_:
6537 1.1 mrg case TOK.class_:
6538 1.1 mrg case TOK.debug_:
6539 1.1 mrg case TOK.enum_:
6540 1.1 mrg case TOK.if_:
6541 1.1 mrg case TOK.interface_:
6542 1.1 mrg case TOK.pragma_:
6543 1.1 mrg case TOK.semicolon:
6544 1.1 mrg case TOK.struct_:
6545 1.1 mrg case TOK.switch_:
6546 1.1 mrg case TOK.synchronized_:
6547 1.1 mrg case TOK.try_:
6548 1.1 mrg case TOK.union_:
6549 1.1 mrg case TOK.version_:
6550 1.1 mrg case TOK.while_:
6551 1.1 mrg case TOK.with_:
6552 1.1 mrg if (braces == 1)
6553 1.1 mrg return parseExpInitializer(loc);
6554 1.1 mrg continue;
6555 1.1 mrg
6556 1.1 mrg case TOK.leftCurly:
6557 1.1 mrg braces++;
6558 1.1 mrg continue;
6559 1.1 mrg
6560 1.1 mrg case TOK.rightCurly:
6561 1.1 mrg if (--braces == 0)
6562 1.1 mrg break;
6563 1.1 mrg continue;
6564 1.1 mrg
6565 1.1 mrg case TOK.endOfFile:
6566 1.1 mrg break;
6567 1.1 mrg
6568 1.1 mrg default:
6569 1.1 mrg continue;
6570 1.1 mrg }
6571 1.1 mrg break;
6572 1.1 mrg }
6573 1.1 mrg
6574 1.1 mrg auto _is = new AST.StructInitializer(loc);
6575 1.1 mrg bool commaExpected = false;
6576 1.1 mrg nextToken();
6577 1.1 mrg while (1)
6578 1.1 mrg {
6579 1.1 mrg switch (token.value)
6580 1.1 mrg {
6581 1.1 mrg case TOK.identifier:
6582 1.1 mrg {
6583 1.1 mrg
6584 1.1 mrg if (commaExpected)
6585 1.1 mrg error("comma expected separating field initializers");
6586 1.1 mrg const t = peek(&token);
6587 1.1 mrg Identifier id;
6588 1.1 mrg if (t.value == TOK.colon)
6589 1.1 mrg {
6590 1.1 mrg id = token.ident;
6591 1.1 mrg nextToken();
6592 1.1 mrg nextToken(); // skip over ':'
6593 1.1 mrg }
6594 1.1 mrg auto value = parseInitializer();
6595 1.1 mrg _is.addInit(id, value);
6596 1.1 mrg commaExpected = true;
6597 1.1 mrg continue;
6598 1.1 mrg }
6599 1.1 mrg case TOK.comma:
6600 1.1 mrg if (!commaExpected)
6601 1.1 mrg error("expression expected, not `,`");
6602 1.1 mrg nextToken();
6603 1.1 mrg commaExpected = false;
6604 1.1 mrg continue;
6605 1.1 mrg
6606 1.1 mrg case TOK.rightCurly: // allow trailing comma's
6607 1.1 mrg nextToken();
6608 1.1 mrg break;
6609 1.1 mrg
6610 1.1 mrg case TOK.endOfFile:
6611 1.1 mrg error("found end of file instead of initializer");
6612 1.1 mrg break;
6613 1.1 mrg
6614 1.1 mrg default:
6615 1.1 mrg if (commaExpected)
6616 1.1 mrg error("comma expected separating field initializers");
6617 1.1 mrg auto value = parseInitializer();
6618 1.1 mrg _is.addInit(null, value);
6619 1.1 mrg commaExpected = true;
6620 1.1 mrg continue;
6621 1.1 mrg }
6622 1.1 mrg break;
6623 1.1 mrg }
6624 1.1 mrg return _is;
6625 1.1 mrg
6626 1.1 mrg }
6627 1.1 mrg
6628 1.1 mrg /*****************************************
6629 1.1 mrg * Parse initializer for variable declaration.
6630 1.1 mrg */
6631 1.1 mrg private AST.Initializer parseInitializer()
6632 1.1 mrg {
6633 1.1 mrg const loc = token.loc;
6634 1.1 mrg
6635 1.1 mrg switch (token.value)
6636 1.1 mrg {
6637 1.1 mrg case TOK.leftCurly:
6638 1.1 mrg return parseStructInitializer(loc);
6639 1.1 mrg
6640 1.1 mrg case TOK.leftBracket:
6641 1.1 mrg /* Scan ahead to see if it is an array initializer or
6642 1.1 mrg * an expression.
6643 1.1 mrg * If it ends with a ';' ',' or '}', it is an array initializer.
6644 1.1 mrg */
6645 1.1 mrg int brackets = 1;
6646 1.1 mrg for (auto t = peek(&token); 1; t = peek(t))
6647 1.1 mrg {
6648 1.1 mrg switch (t.value)
6649 1.1 mrg {
6650 1.1 mrg case TOK.leftBracket:
6651 1.1 mrg brackets++;
6652 1.1 mrg continue;
6653 1.1 mrg
6654 1.1 mrg case TOK.rightBracket:
6655 1.1 mrg if (--brackets == 0)
6656 1.1 mrg {
6657 1.1 mrg t = peek(t);
6658 1.1 mrg if (t.value != TOK.semicolon && t.value != TOK.comma && t.value != TOK.rightBracket && t.value != TOK.rightCurly)
6659 1.1 mrg return parseExpInitializer(loc);
6660 1.1 mrg break;
6661 1.1 mrg }
6662 1.1 mrg continue;
6663 1.1 mrg
6664 1.1 mrg case TOK.endOfFile:
6665 1.1 mrg break;
6666 1.1 mrg
6667 1.1 mrg default:
6668 1.1 mrg continue;
6669 1.1 mrg }
6670 1.1 mrg break;
6671 1.1 mrg }
6672 1.1 mrg
6673 1.1 mrg auto ia = new AST.ArrayInitializer(loc);
6674 1.1 mrg bool commaExpected = false;
6675 1.1 mrg
6676 1.1 mrg nextToken();
6677 1.1 mrg while (1)
6678 1.1 mrg {
6679 1.1 mrg switch (token.value)
6680 1.1 mrg {
6681 1.1 mrg default:
6682 1.1 mrg if (commaExpected)
6683 1.1 mrg {
6684 1.1 mrg error("comma expected separating array initializers, not `%s`", token.toChars());
6685 1.1 mrg nextToken();
6686 1.1 mrg break;
6687 1.1 mrg }
6688 1.1 mrg auto e = parseAssignExp();
6689 1.1 mrg if (!e)
6690 1.1 mrg break;
6691 1.1 mrg
6692 1.1 mrg AST.Initializer value;
6693 1.1 mrg if (token.value == TOK.colon)
6694 1.1 mrg {
6695 1.1 mrg nextToken();
6696 1.1 mrg value = parseInitializer();
6697 1.1 mrg }
6698 1.1 mrg else
6699 1.1 mrg {
6700 1.1 mrg value = new AST.ExpInitializer(e.loc, e);
6701 1.1 mrg e = null;
6702 1.1 mrg }
6703 1.1 mrg ia.addInit(e, value);
6704 1.1 mrg commaExpected = true;
6705 1.1 mrg continue;
6706 1.1 mrg
6707 1.1 mrg case TOK.leftCurly:
6708 1.1 mrg case TOK.leftBracket:
6709 1.1 mrg if (commaExpected)
6710 1.1 mrg error("comma expected separating array initializers, not `%s`", token.toChars());
6711 1.1 mrg auto value = parseInitializer();
6712 1.1 mrg AST.Expression e;
6713 1.1 mrg
6714 1.1 mrg if (token.value == TOK.colon)
6715 1.1 mrg {
6716 1.1 mrg nextToken();
6717 1.1 mrg if (auto ei = value.isExpInitializer())
6718 1.1 mrg {
6719 1.1 mrg e = ei.exp;
6720 1.1 mrg value = parseInitializer();
6721 1.1 mrg }
6722 1.1 mrg else
6723 1.1 mrg error("initializer expression expected following colon, not `%s`", token.toChars());
6724 1.1 mrg }
6725 1.1 mrg ia.addInit(e, value);
6726 1.1 mrg commaExpected = true;
6727 1.1 mrg continue;
6728 1.1 mrg
6729 1.1 mrg case TOK.comma:
6730 1.1 mrg if (!commaExpected)
6731 1.1 mrg error("expression expected, not `,`");
6732 1.1 mrg nextToken();
6733 1.1 mrg commaExpected = false;
6734 1.1 mrg continue;
6735 1.1 mrg
6736 1.1 mrg case TOK.rightBracket: // allow trailing comma's
6737 1.1 mrg nextToken();
6738 1.1 mrg break;
6739 1.1 mrg
6740 1.1 mrg case TOK.endOfFile:
6741 1.1 mrg error("found `%s` instead of array initializer", token.toChars());
6742 1.1 mrg break;
6743 1.1 mrg }
6744 1.1 mrg break;
6745 1.1 mrg }
6746 1.1 mrg return ia;
6747 1.1 mrg
6748 1.1 mrg case TOK.void_:
6749 1.1 mrg const tv = peekNext();
6750 1.1 mrg if (tv == TOK.semicolon || tv == TOK.comma)
6751 1.1 mrg {
6752 1.1 mrg nextToken();
6753 1.1 mrg return new AST.VoidInitializer(loc);
6754 1.1 mrg }
6755 1.1 mrg return parseExpInitializer(loc);
6756 1.1 mrg
6757 1.1 mrg default:
6758 1.1 mrg return parseExpInitializer(loc);
6759 1.1 mrg }
6760 1.1 mrg }
6761 1.1 mrg
6762 1.1 mrg /*****************************************
6763 1.1 mrg * Parses default argument initializer expression that is an assign expression,
6764 1.1 mrg * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
6765 1.1 mrg */
6766 1.1 mrg private AST.Expression parseDefaultInitExp()
6767 1.1 mrg {
6768 1.1 mrg AST.Expression e = null;
6769 1.1 mrg const tv = peekNext();
6770 1.1 mrg if (tv == TOK.comma || tv == TOK.rightParenthesis)
6771 1.1 mrg {
6772 1.1 mrg switch (token.value)
6773 1.1 mrg {
6774 1.1 mrg case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break;
6775 1.1 mrg case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break;
6776 1.1 mrg case TOK.line: e = new AST.LineInitExp(token.loc); break;
6777 1.1 mrg case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break;
6778 1.1 mrg case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
6779 1.1 mrg case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break;
6780 1.1 mrg default: goto LExp;
6781 1.1 mrg }
6782 1.1 mrg nextToken();
6783 1.1 mrg return e;
6784 1.1 mrg }
6785 1.1 mrg LExp:
6786 1.1 mrg return parseAssignExp();
6787 1.1 mrg }
6788 1.1 mrg
6789 1.1 mrg /********************
6790 1.1 mrg * Parse inline assembler block.
6791 1.1 mrg * Returns:
6792 1.1 mrg * inline assembler block as a Statement
6793 1.1 mrg */
6794 1.1 mrg AST.Statement parseAsm()
6795 1.1 mrg {
6796 1.1 mrg // Parse the asm block into a sequence of AsmStatements,
6797 1.1 mrg // each AsmStatement is one instruction.
6798 1.1 mrg // Separate out labels.
6799 1.1 mrg // Defer parsing of AsmStatements until semantic processing.
6800 1.1 mrg
6801 1.1 mrg const loc = token.loc;
6802 1.1 mrg Loc labelloc;
6803 1.1 mrg
6804 1.1 mrg nextToken();
6805 1.1 mrg StorageClass stc = parsePostfix(STC.undefined_, null);
6806 1.1 mrg if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild))
6807 1.1 mrg error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
6808 1.1 mrg
6809 1.1 mrg check(TOK.leftCurly);
6810 1.1 mrg Token* toklist = null;
6811 1.1 mrg Token** ptoklist = &toklist;
6812 1.1 mrg Identifier label = null;
6813 1.1 mrg auto statements = new AST.Statements();
6814 1.1 mrg size_t nestlevel = 0;
6815 1.1 mrg while (1)
6816 1.1 mrg {
6817 1.1 mrg switch (token.value)
6818 1.1 mrg {
6819 1.1 mrg case TOK.identifier:
6820 1.1 mrg if (!toklist)
6821 1.1 mrg {
6822 1.1 mrg // Look ahead to see if it is a label
6823 1.1 mrg if (peekNext() == TOK.colon)
6824 1.1 mrg {
6825 1.1 mrg // It's a label
6826 1.1 mrg label = token.ident;
6827 1.1 mrg labelloc = token.loc;
6828 1.1 mrg nextToken();
6829 1.1 mrg nextToken();
6830 1.1 mrg continue;
6831 1.1 mrg }
6832 1.1 mrg }
6833 1.1 mrg goto default;
6834 1.1 mrg
6835 1.1 mrg case TOK.leftCurly:
6836 1.1 mrg ++nestlevel;
6837 1.1 mrg goto default;
6838 1.1 mrg
6839 1.1 mrg case TOK.rightCurly:
6840 1.1 mrg if (nestlevel > 0)
6841 1.1 mrg {
6842 1.1 mrg --nestlevel;
6843 1.1 mrg goto default;
6844 1.1 mrg }
6845 1.1 mrg if (toklist || label)
6846 1.1 mrg {
6847 1.1 mrg error("`asm` statements must end in `;`");
6848 1.1 mrg }
6849 1.1 mrg break;
6850 1.1 mrg
6851 1.1 mrg case TOK.semicolon:
6852 1.1 mrg if (nestlevel != 0)
6853 1.1 mrg error("mismatched number of curly brackets");
6854 1.1 mrg
6855 1.1 mrg if (toklist || label)
6856 1.1 mrg {
6857 1.1 mrg // Create AsmStatement from list of tokens we've saved
6858 1.1 mrg AST.Statement s = new AST.AsmStatement(token.loc, toklist);
6859 1.1 mrg toklist = null;
6860 1.1 mrg ptoklist = &toklist;
6861 1.1 mrg if (label)
6862 1.1 mrg {
6863 1.1 mrg s = new AST.LabelStatement(labelloc, label, s);
6864 1.1 mrg label = null;
6865 1.1 mrg }
6866 1.1 mrg statements.push(s);
6867 1.1 mrg }
6868 1.1 mrg nextToken();
6869 1.1 mrg continue;
6870 1.1 mrg
6871 1.1 mrg case TOK.endOfFile:
6872 1.1 mrg /* { */
6873 1.1 mrg error("matching `}` expected, not end of file");
6874 1.1 mrg break;
6875 1.1 mrg
6876 1.1 mrg case TOK.colonColon: // treat as two separate : tokens for iasmgcc
6877 1.1 mrg *ptoklist = allocateToken();
6878 1.1 mrg memcpy(*ptoklist, &token, Token.sizeof);
6879 1.1 mrg (*ptoklist).value = TOK.colon;
6880 1.1 mrg ptoklist = &(*ptoklist).next;
6881 1.1 mrg
6882 1.1 mrg *ptoklist = allocateToken();
6883 1.1 mrg memcpy(*ptoklist, &token, Token.sizeof);
6884 1.1 mrg (*ptoklist).value = TOK.colon;
6885 1.1 mrg ptoklist = &(*ptoklist).next;
6886 1.1 mrg
6887 1.1 mrg *ptoklist = null;
6888 1.1 mrg nextToken();
6889 1.1 mrg continue;
6890 1.1 mrg
6891 1.1 mrg default:
6892 1.1 mrg *ptoklist = allocateToken();
6893 1.1 mrg memcpy(*ptoklist, &token, Token.sizeof);
6894 1.1 mrg ptoklist = &(*ptoklist).next;
6895 1.1 mrg *ptoklist = null;
6896 1.1 mrg nextToken();
6897 1.1 mrg continue;
6898 1.1 mrg }
6899 1.1 mrg break;
6900 1.1 mrg }
6901 1.1 mrg nextToken();
6902 1.1 mrg auto s = new AST.CompoundAsmStatement(loc, statements, stc);
6903 1.1 mrg return s;
6904 1.1 mrg }
6905 1.1 mrg
6906 1.1 mrg /**********************************
6907 1.1 mrg * Issue error if the current token is not `value`,
6908 1.1 mrg * advance to next token.
6909 1.1 mrg * Params:
6910 1.1 mrg * loc = location for error message
6911 1.1 mrg * value = token value to compare with
6912 1.1 mrg */
6913 1.1 mrg void check(Loc loc, TOK value)
6914 1.1 mrg {
6915 1.1 mrg if (token.value != value)
6916 1.1 mrg error(loc, "found `%s` when expecting `%s`", token.toChars(), Token.toChars(value));
6917 1.1 mrg nextToken();
6918 1.1 mrg }
6919 1.1 mrg
6920 1.1 mrg /**********************************
6921 1.1 mrg * Issue error if the current token is not `value`,
6922 1.1 mrg * advance to next token.
6923 1.1 mrg * Params:
6924 1.1 mrg * value = token value to compare with
6925 1.1 mrg */
6926 1.1 mrg void check(TOK value)
6927 1.1 mrg {
6928 1.1 mrg check(token.loc, value);
6929 1.1 mrg }
6930 1.1 mrg
6931 1.1 mrg /**********************************
6932 1.1 mrg * Issue error if the current token is not `value`,
6933 1.1 mrg * advance to next token.
6934 1.1 mrg * Params:
6935 1.1 mrg * value = token value to compare with
6936 1.1 mrg * string = for error message
6937 1.1 mrg */
6938 1.1 mrg void check(TOK value, const(char)* string)
6939 1.1 mrg {
6940 1.1 mrg if (token.value != value)
6941 1.1 mrg error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string);
6942 1.1 mrg nextToken();
6943 1.1 mrg }
6944 1.1 mrg
6945 1.1 mrg private void checkParens(TOK value, AST.Expression e)
6946 1.1 mrg {
6947 1.1 mrg if (precedence[e.op] == PREC.rel && !e.parens)
6948 1.1 mrg error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value));
6949 1.1 mrg }
6950 1.1 mrg
6951 1.1 mrg ///
6952 1.1 mrg enum NeedDeclaratorId
6953 1.1 mrg {
6954 1.1 mrg no, // Declarator part must have no identifier
6955 1.1 mrg opt, // Declarator part identifier is optional
6956 1.1 mrg must, // Declarator part must have identifier
6957 1.1 mrg mustIfDstyle, // Declarator part must have identifier, but don't recognize old C-style syntax
6958 1.1 mrg }
6959 1.1 mrg
6960 1.1 mrg /************************************
6961 1.1 mrg * Determine if the scanner is sitting on the start of a declaration.
6962 1.1 mrg * Params:
6963 1.1 mrg * t = current token of the scanner
6964 1.1 mrg * needId = flag with additional requirements for a declaration
6965 1.1 mrg * endtok = ending token
6966 1.1 mrg * pt = will be set ending token (if not null)
6967 1.1 mrg * Output:
6968 1.1 mrg * true if the token `t` is a declaration, false otherwise
6969 1.1 mrg */
6970 1.1 mrg private bool isDeclaration(Token* t, NeedDeclaratorId needId, TOK endtok, Token** pt)
6971 1.1 mrg {
6972 1.1 mrg //printf("isDeclaration(needId = %d)\n", needId);
6973 1.1 mrg int haveId = 0;
6974 1.1 mrg int haveTpl = 0;
6975 1.1 mrg
6976 1.1 mrg while (1)
6977 1.1 mrg {
6978 1.1 mrg if ((t.value == TOK.const_ || t.value == TOK.immutable_ || t.value == TOK.inout_ || t.value == TOK.shared_) && peek(t).value != TOK.leftParenthesis)
6979 1.1 mrg {
6980 1.1 mrg /* const type
6981 1.1 mrg * immutable type
6982 1.1 mrg * shared type
6983 1.1 mrg * wild type
6984 1.1 mrg */
6985 1.1 mrg t = peek(t);
6986 1.1 mrg continue;
6987 1.1 mrg }
6988 1.1 mrg break;
6989 1.1 mrg }
6990 1.1 mrg
6991 1.1 mrg if (!isBasicType(&t))
6992 1.1 mrg {
6993 1.1 mrg goto Lisnot;
6994 1.1 mrg }
6995 1.1 mrg if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != NeedDeclaratorId.mustIfDstyle))
6996 1.1 mrg goto Lisnot;
6997 1.1 mrg if ((needId == NeedDeclaratorId.no && !haveId) ||
6998 1.1 mrg (needId == NeedDeclaratorId.opt) ||
6999 1.1 mrg (needId == NeedDeclaratorId.must && haveId) ||
7000 1.1 mrg (needId == NeedDeclaratorId.mustIfDstyle && haveId))
7001 1.1 mrg {
7002 1.1 mrg if (pt)
7003 1.1 mrg *pt = t;
7004 1.1 mrg goto Lis;
7005 1.1 mrg }
7006 1.1 mrg goto Lisnot;
7007 1.1 mrg
7008 1.1 mrg Lis:
7009 1.1 mrg //printf("\tis declaration, t = %s\n", t.toChars());
7010 1.1 mrg return true;
7011 1.1 mrg
7012 1.1 mrg Lisnot:
7013 1.1 mrg //printf("\tis not declaration\n");
7014 1.1 mrg return false;
7015 1.1 mrg }
7016 1.1 mrg
7017 1.1 mrg private bool isBasicType(Token** pt)
7018 1.1 mrg {
7019 1.1 mrg // This code parallels parseBasicType()
7020 1.1 mrg Token* t = *pt;
7021 1.1 mrg switch (t.value)
7022 1.1 mrg {
7023 1.1 mrg case TOK.wchar_:
7024 1.1 mrg case TOK.dchar_:
7025 1.1 mrg case TOK.bool_:
7026 1.1 mrg case TOK.char_:
7027 1.1 mrg case TOK.int8:
7028 1.1 mrg case TOK.uns8:
7029 1.1 mrg case TOK.int16:
7030 1.1 mrg case TOK.uns16:
7031 1.1 mrg case TOK.int32:
7032 1.1 mrg case TOK.uns32:
7033 1.1 mrg case TOK.int64:
7034 1.1 mrg case TOK.uns64:
7035 1.1 mrg case TOK.int128:
7036 1.1 mrg case TOK.uns128:
7037 1.1 mrg case TOK.float32:
7038 1.1 mrg case TOK.float64:
7039 1.1 mrg case TOK.float80:
7040 1.1 mrg case TOK.imaginary32:
7041 1.1 mrg case TOK.imaginary64:
7042 1.1 mrg case TOK.imaginary80:
7043 1.1 mrg case TOK.complex32:
7044 1.1 mrg case TOK.complex64:
7045 1.1 mrg case TOK.complex80:
7046 1.1 mrg case TOK.void_:
7047 1.1 mrg t = peek(t);
7048 1.1 mrg break;
7049 1.1 mrg
7050 1.1 mrg case TOK.identifier:
7051 1.1 mrg L5:
7052 1.1 mrg t = peek(t);
7053 1.1 mrg if (t.value == TOK.not)
7054 1.1 mrg {
7055 1.1 mrg goto L4;
7056 1.1 mrg }
7057 1.1 mrg goto L3;
7058 1.1 mrg while (1)
7059 1.1 mrg {
7060 1.1 mrg L2:
7061 1.1 mrg t = peek(t);
7062 1.1 mrg L3:
7063 1.1 mrg if (t.value == TOK.dot)
7064 1.1 mrg {
7065 1.1 mrg Ldot:
7066 1.1 mrg t = peek(t);
7067 1.1 mrg if (t.value != TOK.identifier)
7068 1.1 mrg goto Lfalse;
7069 1.1 mrg t = peek(t);
7070 1.1 mrg if (t.value != TOK.not)
7071 1.1 mrg goto L3;
7072 1.1 mrg L4:
7073 1.1 mrg /* Seen a !
7074 1.1 mrg * Look for:
7075 1.1 mrg * !( args ), !identifier, etc.
7076 1.1 mrg */
7077 1.1 mrg t = peek(t);
7078 1.1 mrg switch (t.value)
7079 1.1 mrg {
7080 1.1 mrg case TOK.identifier:
7081 1.1 mrg goto L5;
7082 1.1 mrg
7083 1.1 mrg case TOK.leftParenthesis:
7084 1.1 mrg if (!skipParens(t, &t))
7085 1.1 mrg goto Lfalse;
7086 1.1 mrg goto L3;
7087 1.1 mrg
7088 1.1 mrg case TOK.wchar_:
7089 1.1 mrg case TOK.dchar_:
7090 1.1 mrg case TOK.bool_:
7091 1.1 mrg case TOK.char_:
7092 1.1 mrg case TOK.int8:
7093 1.1 mrg case TOK.uns8:
7094 1.1 mrg case TOK.int16:
7095 1.1 mrg case TOK.uns16:
7096 1.1 mrg case TOK.int32:
7097 1.1 mrg case TOK.uns32:
7098 1.1 mrg case TOK.int64:
7099 1.1 mrg case TOK.uns64:
7100 1.1 mrg case TOK.int128:
7101 1.1 mrg case TOK.uns128:
7102 1.1 mrg case TOK.float32:
7103 1.1 mrg case TOK.float64:
7104 1.1 mrg case TOK.float80:
7105 1.1 mrg case TOK.imaginary32:
7106 1.1 mrg case TOK.imaginary64:
7107 1.1 mrg case TOK.imaginary80:
7108 1.1 mrg case TOK.complex32:
7109 1.1 mrg case TOK.complex64:
7110 1.1 mrg case TOK.complex80:
7111 1.1 mrg case TOK.void_:
7112 1.1 mrg case TOK.int32Literal:
7113 1.1 mrg case TOK.uns32Literal:
7114 1.1 mrg case TOK.int64Literal:
7115 1.1 mrg case TOK.uns64Literal:
7116 1.1 mrg case TOK.int128Literal:
7117 1.1 mrg case TOK.uns128Literal:
7118 1.1 mrg case TOK.float32Literal:
7119 1.1 mrg case TOK.float64Literal:
7120 1.1 mrg case TOK.float80Literal:
7121 1.1 mrg case TOK.imaginary32Literal:
7122 1.1 mrg case TOK.imaginary64Literal:
7123 1.1 mrg case TOK.imaginary80Literal:
7124 1.1 mrg case TOK.null_:
7125 1.1 mrg case TOK.true_:
7126 1.1 mrg case TOK.false_:
7127 1.1 mrg case TOK.charLiteral:
7128 1.1 mrg case TOK.wcharLiteral:
7129 1.1 mrg case TOK.dcharLiteral:
7130 1.1 mrg case TOK.string_:
7131 1.1 mrg case TOK.file:
7132 1.1 mrg case TOK.fileFullPath:
7133 1.1 mrg case TOK.line:
7134 1.1 mrg case TOK.moduleString:
7135 1.1 mrg case TOK.functionString:
7136 1.1 mrg case TOK.prettyFunction:
7137 1.1 mrg goto L2;
7138 1.1 mrg
7139 1.1 mrg default:
7140 1.1 mrg goto Lfalse;
7141 1.1 mrg }
7142 1.1 mrg }
7143 1.1 mrg break;
7144 1.1 mrg }
7145 1.1 mrg break;
7146 1.1 mrg
7147 1.1 mrg case TOK.dot:
7148 1.1 mrg goto Ldot;
7149 1.1 mrg
7150 1.1 mrg case TOK.typeof_:
7151 1.1 mrg case TOK.vector:
7152 1.1 mrg case TOK.mixin_:
7153 1.1 mrg /* typeof(exp).identifier...
7154 1.1 mrg */
7155 1.1 mrg t = peek(t);
7156 1.1 mrg if (!skipParens(t, &t))
7157 1.1 mrg goto Lfalse;
7158 1.1 mrg goto L3;
7159 1.1 mrg
7160 1.1 mrg case TOK.traits:
7161 1.1 mrg // __traits(getMember
7162 1.1 mrg t = peek(t);
7163 1.1 mrg if (t.value != TOK.leftParenthesis)
7164 1.1 mrg goto Lfalse;
7165 1.1 mrg auto lp = t;
7166 1.1 mrg t = peek(t);
7167 1.1 mrg if (t.value != TOK.identifier || t.ident != Id.getMember)
7168 1.1 mrg goto Lfalse;
7169 1.1 mrg if (!skipParens(lp, &lp))
7170 1.1 mrg goto Lfalse;
7171 1.1 mrg // we are in a lookup for decl VS statement
7172 1.1 mrg // so we expect a declarator following __trait if it's a type.
7173 1.1 mrg // other usages wont be ambiguous (alias, template instance, type qual, etc.)
7174 1.1 mrg if (lp.value != TOK.identifier)
7175 1.1 mrg goto Lfalse;
7176 1.1 mrg
7177 1.1 mrg break;
7178 1.1 mrg
7179 1.1 mrg case TOK.const_:
7180 1.1 mrg case TOK.immutable_:
7181 1.1 mrg case TOK.shared_:
7182 1.1 mrg case TOK.inout_:
7183 1.1 mrg // const(type) or immutable(type) or shared(type) or wild(type)
7184 1.1 mrg t = peek(t);
7185 1.1 mrg if (t.value != TOK.leftParenthesis)
7186 1.1 mrg goto Lfalse;
7187 1.1 mrg t = peek(t);
7188 1.1 mrg if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParenthesis, &t))
7189 1.1 mrg {
7190 1.1 mrg goto Lfalse;
7191 1.1 mrg }
7192 1.1 mrg t = peek(t);
7193 1.1 mrg break;
7194 1.1 mrg
7195 1.1 mrg default:
7196 1.1 mrg goto Lfalse;
7197 1.1 mrg }
7198 1.1 mrg *pt = t;
7199 1.1 mrg //printf("is\n");
7200 1.1 mrg return true;
7201 1.1 mrg
7202 1.1 mrg Lfalse:
7203 1.1 mrg //printf("is not\n");
7204 1.1 mrg return false;
7205 1.1 mrg }
7206 1.1 mrg
7207 1.1 mrg private bool isDeclarator(Token** pt, int* haveId, int* haveTpl, TOK endtok, bool allowAltSyntax = true)
7208 1.1 mrg {
7209 1.1 mrg // This code parallels parseDeclarator()
7210 1.1 mrg Token* t = *pt;
7211 1.1 mrg int parens;
7212 1.1 mrg
7213 1.1 mrg //printf("Parser::isDeclarator() %s\n", t.toChars());
7214 1.1 mrg if (t.value == TOK.assign)
7215 1.1 mrg return false;
7216 1.1 mrg
7217 1.1 mrg while (1)
7218 1.1 mrg {
7219 1.1 mrg parens = false;
7220 1.1 mrg switch (t.value)
7221 1.1 mrg {
7222 1.1 mrg case TOK.mul:
7223 1.1 mrg //case TOK.and:
7224 1.1 mrg t = peek(t);
7225 1.1 mrg continue;
7226 1.1 mrg
7227 1.1 mrg case TOK.leftBracket:
7228 1.1 mrg t = peek(t);
7229 1.1 mrg if (t.value == TOK.rightBracket)
7230 1.1 mrg {
7231 1.1 mrg t = peek(t);
7232 1.1 mrg }
7233 1.1 mrg else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t))
7234 1.1 mrg {
7235 1.1 mrg // It's an associative array declaration
7236 1.1 mrg t = peek(t);
7237 1.1 mrg
7238 1.1 mrg // ...[type].ident
7239 1.1 mrg if (t.value == TOK.dot && peek(t).value == TOK.identifier)
7240 1.1 mrg {
7241 1.1 mrg t = peek(t);
7242 1.1 mrg t = peek(t);
7243 1.1 mrg }
7244 1.1 mrg }
7245 1.1 mrg else
7246 1.1 mrg {
7247 1.1 mrg // [ expression ]
7248 1.1 mrg // [ expression .. expression ]
7249 1.1 mrg if (!isExpression(&t))
7250 1.1 mrg return false;
7251 1.1 mrg if (t.value == TOK.slice)
7252 1.1 mrg {
7253 1.1 mrg t = peek(t);
7254 1.1 mrg if (!isExpression(&t))
7255 1.1 mrg return false;
7256 1.1 mrg if (t.value != TOK.rightBracket)
7257 1.1 mrg return false;
7258 1.1 mrg t = peek(t);
7259 1.1 mrg }
7260 1.1 mrg else
7261 1.1 mrg {
7262 1.1 mrg if (t.value != TOK.rightBracket)
7263 1.1 mrg return false;
7264 1.1 mrg t = peek(t);
7265 1.1 mrg // ...[index].ident
7266 1.1 mrg if (t.value == TOK.dot && peek(t).value == TOK.identifier)
7267 1.1 mrg {
7268 1.1 mrg t = peek(t);
7269 1.1 mrg t = peek(t);
7270 1.1 mrg }
7271 1.1 mrg }
7272 1.1 mrg }
7273 1.1 mrg continue;
7274 1.1 mrg
7275 1.1 mrg case TOK.identifier:
7276 1.1 mrg if (*haveId)
7277 1.1 mrg return false;
7278 1.1 mrg *haveId = true;
7279 1.1 mrg t = peek(t);
7280 1.1 mrg break;
7281 1.1 mrg
7282 1.1 mrg case TOK.leftParenthesis:
7283 1.1 mrg if (!allowAltSyntax)
7284 1.1 mrg return false; // Do not recognize C-style declarations.
7285 1.1 mrg
7286 1.1 mrg t = peek(t);
7287 1.1 mrg if (t.value == TOK.rightParenthesis)
7288 1.1 mrg return false; // () is not a declarator
7289 1.1 mrg
7290 1.1 mrg /* Regard ( identifier ) as not a declarator
7291 1.1 mrg * BUG: what about ( *identifier ) in
7292 1.1 mrg * f(*p)(x);
7293 1.1 mrg * where f is a class instance with overloaded () ?
7294 1.1 mrg * Should we just disallow C-style function pointer declarations?
7295 1.1 mrg */
7296 1.1 mrg if (t.value == TOK.identifier)
7297 1.1 mrg {
7298 1.1 mrg Token* t2 = peek(t);
7299 1.1 mrg if (t2.value == TOK.rightParenthesis)
7300 1.1 mrg return false;
7301 1.1 mrg }
7302 1.1 mrg
7303 1.1 mrg if (!isDeclarator(&t, haveId, null, TOK.rightParenthesis))
7304 1.1 mrg return false;
7305 1.1 mrg t = peek(t);
7306 1.1 mrg parens = true;
7307 1.1 mrg break;
7308 1.1 mrg
7309 1.1 mrg case TOK.delegate_:
7310 1.1 mrg case TOK.function_:
7311 1.1 mrg t = peek(t);
7312 1.1 mrg if (!isParameters(&t))
7313 1.1 mrg return false;
7314 1.1 mrg skipAttributes(t, &t);
7315 1.1 mrg continue;
7316 1.1 mrg
7317 1.1 mrg default:
7318 1.1 mrg break;
7319 1.1 mrg }
7320 1.1 mrg break;
7321 1.1 mrg }
7322 1.1 mrg
7323 1.1 mrg while (1)
7324 1.1 mrg {
7325 1.1 mrg switch (t.value)
7326 1.1 mrg {
7327 1.1 mrg static if (CARRAYDECL)
7328 1.1 mrg {
7329 1.1 mrg case TOK.leftBracket:
7330 1.1 mrg parens = false;
7331 1.1 mrg t = peek(t);
7332 1.1 mrg if (t.value == TOK.rightBracket)
7333 1.1 mrg {
7334 1.1 mrg t = peek(t);
7335 1.1 mrg }
7336 1.1 mrg else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t))
7337 1.1 mrg {
7338 1.1 mrg // It's an associative array declaration
7339 1.1 mrg t = peek(t);
7340 1.1 mrg }
7341 1.1 mrg else
7342 1.1 mrg {
7343 1.1 mrg // [ expression ]
7344 1.1 mrg if (!isExpression(&t))
7345 1.1 mrg return false;
7346 1.1 mrg if (t.value != TOK.rightBracket)
7347 1.1 mrg return false;
7348 1.1 mrg t = peek(t);
7349 1.1 mrg }
7350 1.1 mrg continue;
7351 1.1 mrg }
7352 1.1 mrg
7353 1.1 mrg case TOK.leftParenthesis:
7354 1.1 mrg parens = false;
7355 1.1 mrg if (Token* tk = peekPastParen(t))
7356 1.1 mrg {
7357 1.1 mrg if (tk.value == TOK.leftParenthesis)
7358 1.1 mrg {
7359 1.1 mrg if (!haveTpl)
7360 1.1 mrg return false;
7361 1.1 mrg *haveTpl = 1;
7362 1.1 mrg t = tk;
7363 1.1 mrg }
7364 1.1 mrg else if (tk.value == TOK.assign)
7365 1.1 mrg {
7366 1.1 mrg if (!haveTpl)
7367 1.1 mrg return false;
7368 1.1 mrg *haveTpl = 1;
7369 1.1 mrg *pt = tk;
7370 1.1 mrg return true;
7371 1.1 mrg }
7372 1.1 mrg }
7373 1.1 mrg if (!isParameters(&t))
7374 1.1 mrg return false;
7375 1.1 mrg while (1)
7376 1.1 mrg {
7377 1.1 mrg switch (t.value)
7378 1.1 mrg {
7379 1.1 mrg case TOK.const_:
7380 1.1 mrg case TOK.immutable_:
7381 1.1 mrg case TOK.shared_:
7382 1.1 mrg case TOK.inout_:
7383 1.1 mrg case TOK.pure_:
7384 1.1 mrg case TOK.nothrow_:
7385 1.1 mrg case TOK.return_:
7386 1.1 mrg case TOK.scope_:
7387 1.1 mrg t = peek(t);
7388 1.1 mrg continue;
7389 1.1 mrg
7390 1.1 mrg case TOK.at:
7391 1.1 mrg t = peek(t); // skip '@'
7392 1.1 mrg t = peek(t); // skip identifier
7393 1.1 mrg continue;
7394 1.1 mrg
7395 1.1 mrg default:
7396 1.1 mrg break;
7397 1.1 mrg }
7398 1.1 mrg break;
7399 1.1 mrg }
7400 1.1 mrg continue;
7401 1.1 mrg
7402 1.1 mrg // Valid tokens that follow a declaration
7403 1.1 mrg case TOK.rightParenthesis:
7404 1.1 mrg case TOK.rightBracket:
7405 1.1 mrg case TOK.assign:
7406 1.1 mrg case TOK.comma:
7407 1.1 mrg case TOK.dotDotDot:
7408 1.1 mrg case TOK.semicolon:
7409 1.1 mrg case TOK.leftCurly:
7410 1.1 mrg case TOK.in_:
7411 1.1 mrg case TOK.out_:
7412 1.1 mrg case TOK.do_:
7413 1.1 mrg // The !parens is to disallow unnecessary parentheses
7414 1.1 mrg if (!parens && (endtok == TOK.reserved || endtok == t.value))
7415 1.1 mrg {
7416 1.1 mrg *pt = t;
7417 1.1 mrg return true;
7418 1.1 mrg }
7419 1.1 mrg return false;
7420 1.1 mrg
7421 1.1 mrg case TOK.identifier:
7422 1.1 mrg if (t.ident == Id._body)
7423 1.1 mrg {
7424 1.1 mrg // @@@DEPRECATED_2.117@@@
7425 1.1 mrg // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
7426 1.1 mrg // Deprecated in 2.097 - Can be removed from 2.117
7427 1.1 mrg // The deprecation period is longer than usual as `body`
7428 1.1 mrg // was quite widely used.
7429 1.1 mrg deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
7430 1.1 mrg goto case TOK.do_;
7431 1.1 mrg }
7432 1.1 mrg goto default;
7433 1.1 mrg
7434 1.1 mrg case TOK.if_:
7435 1.1 mrg return haveTpl ? true : false;
7436 1.1 mrg
7437 1.1 mrg // Used for mixin type parsing
7438 1.1 mrg case TOK.endOfFile:
7439 1.1 mrg if (endtok == TOK.endOfFile)
7440 1.1 mrg goto case TOK.do_;
7441 1.1 mrg return false;
7442 1.1 mrg
7443 1.1 mrg default:
7444 1.1 mrg return false;
7445 1.1 mrg }
7446 1.1 mrg }
7447 1.1 mrg assert(0);
7448 1.1 mrg }
7449 1.1 mrg
7450 1.1 mrg private bool isParameters(Token** pt)
7451 1.1 mrg {
7452 1.1 mrg // This code parallels parseParameterList()
7453 1.1 mrg Token* t = *pt;
7454 1.1 mrg
7455 1.1 mrg //printf("isParameters()\n");
7456 1.1 mrg if (t.value != TOK.leftParenthesis)
7457 1.1 mrg return false;
7458 1.1 mrg
7459 1.1 mrg t = peek(t);
7460 1.1 mrg for (; 1; t = peek(t))
7461 1.1 mrg {
7462 1.1 mrg L1:
7463 1.1 mrg switch (t.value)
7464 1.1 mrg {
7465 1.1 mrg case TOK.rightParenthesis:
7466 1.1 mrg break;
7467 1.1 mrg
7468 1.1 mrg case TOK.at:
7469 1.1 mrg Token* pastAttr;
7470 1.1 mrg if (skipAttributes(t, &pastAttr))
7471 1.1 mrg {
7472 1.1 mrg t = pastAttr;
7473 1.1 mrg goto default;
7474 1.1 mrg }
7475 1.1 mrg break;
7476 1.1 mrg
7477 1.1 mrg case TOK.dotDotDot:
7478 1.1 mrg t = peek(t);
7479 1.1 mrg break;
7480 1.1 mrg
7481 1.1 mrg case TOK.in_:
7482 1.1 mrg case TOK.out_:
7483 1.1 mrg case TOK.ref_:
7484 1.1 mrg case TOK.lazy_:
7485 1.1 mrg case TOK.scope_:
7486 1.1 mrg case TOK.final_:
7487 1.1 mrg case TOK.auto_:
7488 1.1 mrg case TOK.return_:
7489 1.1 mrg continue;
7490 1.1 mrg
7491 1.1 mrg case TOK.const_:
7492 1.1 mrg case TOK.immutable_:
7493 1.1 mrg case TOK.shared_:
7494 1.1 mrg case TOK.inout_:
7495 1.1 mrg t = peek(t);
7496 1.1 mrg if (t.value == TOK.leftParenthesis)
7497 1.1 mrg {
7498 1.1 mrg t = peek(t);
7499 1.1 mrg if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParenthesis, &t))
7500 1.1 mrg return false;
7501 1.1 mrg t = peek(t); // skip past closing ')'
7502 1.1 mrg goto L2;
7503 1.1 mrg }
7504 1.1 mrg goto L1;
7505 1.1 mrg
7506 1.1 mrg version (none)
7507 1.1 mrg {
7508 1.1 mrg case TOK.static_:
7509 1.1 mrg continue;
7510 1.1 mrg case TOK.auto_:
7511 1.1 mrg case TOK.alias_:
7512 1.1 mrg t = peek(t);
7513 1.1 mrg if (t.value == TOK.identifier)
7514 1.1 mrg t = peek(t);
7515 1.1 mrg if (t.value == TOK.assign)
7516 1.1 mrg {
7517 1.1 mrg t = peek(t);
7518 1.1 mrg if (!isExpression(&t))
7519 1.1 mrg return false;
7520 1.1 mrg }
7521 1.1 mrg goto L3;
7522 1.1 mrg }
7523 1.1 mrg
7524 1.1 mrg default:
7525 1.1 mrg {
7526 1.1 mrg if (!isBasicType(&t))
7527 1.1 mrg return false;
7528 1.1 mrg L2:
7529 1.1 mrg int tmp = false;
7530 1.1 mrg if (t.value != TOK.dotDotDot && !isDeclarator(&t, &tmp, null, TOK.reserved))
7531 1.1 mrg return false;
7532 1.1 mrg if (t.value == TOK.assign)
7533 1.1 mrg {
7534 1.1 mrg t = peek(t);
7535 1.1 mrg if (!isExpression(&t))
7536 1.1 mrg return false;
7537 1.1 mrg }
7538 1.1 mrg if (t.value == TOK.dotDotDot)
7539 1.1 mrg {
7540 1.1 mrg t = peek(t);
7541 1.1 mrg break;
7542 1.1 mrg }
7543 1.1 mrg }
7544 1.1 mrg if (t.value == TOK.comma)
7545 1.1 mrg {
7546 1.1 mrg continue;
7547 1.1 mrg }
7548 1.1 mrg break;
7549 1.1 mrg }
7550 1.1 mrg break;
7551 1.1 mrg }
7552 1.1 mrg if (t.value != TOK.rightParenthesis)
7553 1.1 mrg return false;
7554 1.1 mrg t = peek(t);
7555 1.1 mrg *pt = t;
7556 1.1 mrg return true;
7557 1.1 mrg }
7558 1.1 mrg
7559 1.1 mrg private bool isExpression(Token** pt)
7560 1.1 mrg {
7561 1.1 mrg // This is supposed to determine if something is an expression.
7562 1.1 mrg // What it actually does is scan until a closing right bracket
7563 1.1 mrg // is found.
7564 1.1 mrg
7565 1.1 mrg Token* t = *pt;
7566 1.1 mrg int brnest = 0;
7567 1.1 mrg int panest = 0;
7568 1.1 mrg int curlynest = 0;
7569 1.1 mrg
7570 1.1 mrg for (;; t = peek(t))
7571 1.1 mrg {
7572 1.1 mrg switch (t.value)
7573 1.1 mrg {
7574 1.1 mrg case TOK.leftBracket:
7575 1.1 mrg brnest++;
7576 1.1 mrg continue;
7577 1.1 mrg
7578 1.1 mrg case TOK.rightBracket:
7579 1.1 mrg if (--brnest >= 0)
7580 1.1 mrg continue;
7581 1.1 mrg break;
7582 1.1 mrg
7583 1.1 mrg case TOK.leftParenthesis:
7584 1.1 mrg panest++;
7585 1.1 mrg continue;
7586 1.1 mrg
7587 1.1 mrg case TOK.comma:
7588 1.1 mrg if (brnest || panest)
7589 1.1 mrg continue;
7590 1.1 mrg break;
7591 1.1 mrg
7592 1.1 mrg case TOK.rightParenthesis:
7593 1.1 mrg if (--panest >= 0)
7594 1.1 mrg continue;
7595 1.1 mrg break;
7596 1.1 mrg
7597 1.1 mrg case TOK.leftCurly:
7598 1.1 mrg curlynest++;
7599 1.1 mrg continue;
7600 1.1 mrg
7601 1.1 mrg case TOK.rightCurly:
7602 1.1 mrg if (--curlynest >= 0)
7603 1.1 mrg continue;
7604 1.1 mrg return false;
7605 1.1 mrg
7606 1.1 mrg case TOK.slice:
7607 1.1 mrg if (brnest)
7608 1.1 mrg continue;
7609 1.1 mrg break;
7610 1.1 mrg
7611 1.1 mrg case TOK.semicolon:
7612 1.1 mrg if (curlynest)
7613 1.1 mrg continue;
7614 1.1 mrg return false;
7615 1.1 mrg
7616 1.1 mrg case TOK.endOfFile:
7617 1.1 mrg return false;
7618 1.1 mrg
7619 1.1 mrg default:
7620 1.1 mrg continue;
7621 1.1 mrg }
7622 1.1 mrg break;
7623 1.1 mrg }
7624 1.1 mrg
7625 1.1 mrg *pt = t;
7626 1.1 mrg return true;
7627 1.1 mrg }
7628 1.1 mrg
7629 1.1 mrg /*******************************************
7630 1.1 mrg * Skip parentheses.
7631 1.1 mrg * Params:
7632 1.1 mrg * t = on opening $(LPAREN)
7633 1.1 mrg * pt = *pt is set to token past '$(RPAREN)' on true
7634 1.1 mrg * Returns:
7635 1.1 mrg * true successful
7636 1.1 mrg * false some parsing error
7637 1.1 mrg */
7638 1.1 mrg bool skipParens(Token* t, Token** pt)
7639 1.1 mrg {
7640 1.1 mrg if (t.value != TOK.leftParenthesis)
7641 1.1 mrg return false;
7642 1.1 mrg
7643 1.1 mrg int parens = 0;
7644 1.1 mrg
7645 1.1 mrg while (1)
7646 1.1 mrg {
7647 1.1 mrg switch (t.value)
7648 1.1 mrg {
7649 1.1 mrg case TOK.leftParenthesis:
7650 1.1 mrg parens++;
7651 1.1 mrg break;
7652 1.1 mrg
7653 1.1 mrg case TOK.rightParenthesis:
7654 1.1 mrg parens--;
7655 1.1 mrg if (parens < 0)
7656 1.1 mrg goto Lfalse;
7657 1.1 mrg if (parens == 0)
7658 1.1 mrg goto Ldone;
7659 1.1 mrg break;
7660 1.1 mrg
7661 1.1 mrg case TOK.endOfFile:
7662 1.1 mrg goto Lfalse;
7663 1.1 mrg
7664 1.1 mrg default:
7665 1.1 mrg break;
7666 1.1 mrg }
7667 1.1 mrg t = peek(t);
7668 1.1 mrg }
7669 1.1 mrg Ldone:
7670 1.1 mrg if (pt)
7671 1.1 mrg *pt = peek(t); // skip found rparen
7672 1.1 mrg return true;
7673 1.1 mrg
7674 1.1 mrg Lfalse:
7675 1.1 mrg return false;
7676 1.1 mrg }
7677 1.1 mrg
7678 1.1 mrg private bool skipParensIf(Token* t, Token** pt)
7679 1.1 mrg {
7680 1.1 mrg if (t.value != TOK.leftParenthesis)
7681 1.1 mrg {
7682 1.1 mrg if (pt)
7683 1.1 mrg *pt = t;
7684 1.1 mrg return true;
7685 1.1 mrg }
7686 1.1 mrg return skipParens(t, pt);
7687 1.1 mrg }
7688 1.1 mrg
7689 1.1 mrg //returns true if the next value (after optional matching parens) is expected
7690 1.1 mrg private bool hasOptionalParensThen(Token* t, TOK expected)
7691 1.1 mrg {
7692 1.1 mrg Token* tk;
7693 1.1 mrg if (!skipParensIf(t, &tk))
7694 1.1 mrg return false;
7695 1.1 mrg return tk.value == expected;
7696 1.1 mrg }
7697 1.1 mrg
7698 1.1 mrg /*******************************************
7699 1.1 mrg * Skip attributes.
7700 1.1 mrg * Input:
7701 1.1 mrg * t is on a candidate attribute
7702 1.1 mrg * Output:
7703 1.1 mrg * *pt is set to first non-attribute token on success
7704 1.1 mrg * Returns:
7705 1.1 mrg * true successful
7706 1.1 mrg * false some parsing error
7707 1.1 mrg */
7708 1.1 mrg private bool skipAttributes(Token* t, Token** pt)
7709 1.1 mrg {
7710 1.1 mrg while (1)
7711 1.1 mrg {
7712 1.1 mrg switch (t.value)
7713 1.1 mrg {
7714 1.1 mrg case TOK.const_:
7715 1.1 mrg case TOK.immutable_:
7716 1.1 mrg case TOK.shared_:
7717 1.1 mrg case TOK.inout_:
7718 1.1 mrg case TOK.final_:
7719 1.1 mrg case TOK.auto_:
7720 1.1 mrg case TOK.scope_:
7721 1.1 mrg case TOK.override_:
7722 1.1 mrg case TOK.abstract_:
7723 1.1 mrg case TOK.synchronized_:
7724 1.1 mrg break;
7725 1.1 mrg
7726 1.1 mrg case TOK.deprecated_:
7727 1.1 mrg if (peek(t).value == TOK.leftParenthesis)
7728 1.1 mrg {
7729 1.1 mrg t = peek(t);
7730 1.1 mrg if (!skipParens(t, &t))
7731 1.1 mrg goto Lerror;
7732 1.1 mrg // t is on the next of closing parenthesis
7733 1.1 mrg continue;
7734 1.1 mrg }
7735 1.1 mrg break;
7736 1.1 mrg
7737 1.1 mrg case TOK.nothrow_:
7738 1.1 mrg case TOK.pure_:
7739 1.1 mrg case TOK.ref_:
7740 1.1 mrg case TOK.gshared:
7741 1.1 mrg case TOK.return_:
7742 1.1 mrg break;
7743 1.1 mrg
7744 1.1 mrg case TOK.at:
7745 1.1 mrg t = peek(t);
7746 1.1 mrg if (t.value == TOK.identifier)
7747 1.1 mrg {
7748 1.1 mrg /* @identifier
7749 1.1 mrg * @identifier!arg
7750 1.1 mrg * @identifier!(arglist)
7751 1.1 mrg * any of the above followed by (arglist)
7752 1.1 mrg * @predefined_attribute
7753 1.1 mrg */
7754 1.1 mrg if (isBuiltinAtAttribute(t.ident))
7755 1.1 mrg break;
7756 1.1 mrg t = peek(t);
7757 1.1 mrg if (t.value == TOK.not)
7758 1.1 mrg {
7759 1.1 mrg t = peek(t);
7760 1.1 mrg if (t.value == TOK.leftParenthesis)
7761 1.1 mrg {
7762 1.1 mrg // @identifier!(arglist)
7763 1.1 mrg if (!skipParens(t, &t))
7764 1.1 mrg goto Lerror;
7765 1.1 mrg // t is on the next of closing parenthesis
7766 1.1 mrg }
7767 1.1 mrg else
7768 1.1 mrg {
7769 1.1 mrg // @identifier!arg
7770 1.1 mrg // Do low rent skipTemplateArgument
7771 1.1 mrg if (t.value == TOK.vector)
7772 1.1 mrg {
7773 1.1 mrg // identifier!__vector(type)
7774 1.1 mrg t = peek(t);
7775 1.1 mrg if (!skipParens(t, &t))
7776 1.1 mrg goto Lerror;
7777 1.1 mrg }
7778 1.1 mrg else
7779 1.1 mrg t = peek(t);
7780 1.1 mrg }
7781 1.1 mrg }
7782 1.1 mrg if (t.value == TOK.leftParenthesis)
7783 1.1 mrg {
7784 1.1 mrg if (!skipParens(t, &t))
7785 1.1 mrg goto Lerror;
7786 1.1 mrg // t is on the next of closing parenthesis
7787 1.1 mrg continue;
7788 1.1 mrg }
7789 1.1 mrg continue;
7790 1.1 mrg }
7791 1.1 mrg if (t.value == TOK.leftParenthesis)
7792 1.1 mrg {
7793 1.1 mrg // @( ArgumentList )
7794 1.1 mrg if (!skipParens(t, &t))
7795 1.1 mrg goto Lerror;
7796 1.1 mrg // t is on the next of closing parenthesis
7797 1.1 mrg continue;
7798 1.1 mrg }
7799 1.1 mrg goto Lerror;
7800 1.1 mrg
7801 1.1 mrg default:
7802 1.1 mrg goto Ldone;
7803 1.1 mrg }
7804 1.1 mrg t = peek(t);
7805 1.1 mrg }
7806 1.1 mrg Ldone:
7807 1.1 mrg if (pt)
7808 1.1 mrg *pt = t;
7809 1.1 mrg return true;
7810 1.1 mrg
7811 1.1 mrg Lerror:
7812 1.1 mrg return false;
7813 1.1 mrg }
7814 1.1 mrg
7815 1.1 mrg AST.Expression parseExpression()
7816 1.1 mrg {
7817 1.1 mrg auto loc = token.loc;
7818 1.1 mrg
7819 1.1 mrg //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
7820 1.1 mrg auto e = parseAssignExp();
7821 1.1 mrg while (token.value == TOK.comma)
7822 1.1 mrg {
7823 1.1 mrg nextToken();
7824 1.1 mrg auto e2 = parseAssignExp();
7825 1.1 mrg e = new AST.CommaExp(loc, e, e2, false);
7826 1.1 mrg loc = token.loc;
7827 1.1 mrg }
7828 1.1 mrg return e;
7829 1.1 mrg }
7830 1.1 mrg
7831 1.1 mrg /********************************* Expression Parser ***************************/
7832 1.1 mrg
7833 1.1 mrg AST.Expression parsePrimaryExp()
7834 1.1 mrg {
7835 1.1 mrg AST.Expression e;
7836 1.1 mrg AST.Type t;
7837 1.1 mrg Identifier id;
7838 1.1 mrg const loc = token.loc;
7839 1.1 mrg
7840 1.1 mrg //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
7841 1.1 mrg switch (token.value)
7842 1.1 mrg {
7843 1.1 mrg case TOK.identifier:
7844 1.1 mrg {
7845 1.1 mrg if (peekNext() == TOK.arrow)
7846 1.1 mrg {
7847 1.1 mrg // skip `identifier ->`
7848 1.1 mrg nextToken();
7849 1.1 mrg nextToken();
7850 1.1 mrg error("use `.` for member lookup, not `->`");
7851 1.1 mrg goto Lerr;
7852 1.1 mrg }
7853 1.1 mrg
7854 1.1 mrg if (peekNext() == TOK.goesTo)
7855 1.1 mrg goto case_delegate;
7856 1.1 mrg
7857 1.1 mrg id = token.ident;
7858 1.1 mrg nextToken();
7859 1.1 mrg TOK save;
7860 1.1 mrg if (token.value == TOK.not && (save = peekNext()) != TOK.is_ && save != TOK.in_)
7861 1.1 mrg {
7862 1.1 mrg // identifier!(template-argument-list)
7863 1.1 mrg auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
7864 1.1 mrg e = new AST.ScopeExp(loc, tempinst);
7865 1.1 mrg }
7866 1.1 mrg else
7867 1.1 mrg e = new AST.IdentifierExp(loc, id);
7868 1.1 mrg break;
7869 1.1 mrg }
7870 1.1 mrg case TOK.dollar:
7871 1.1 mrg if (!inBrackets)
7872 1.1 mrg error("`$` is valid only inside [] of index or slice");
7873 1.1 mrg e = new AST.DollarExp(loc);
7874 1.1 mrg nextToken();
7875 1.1 mrg break;
7876 1.1 mrg
7877 1.1 mrg case TOK.dot:
7878 1.1 mrg // Signal global scope '.' operator with "" identifier
7879 1.1 mrg e = new AST.IdentifierExp(loc, Id.empty);
7880 1.1 mrg break;
7881 1.1 mrg
7882 1.1 mrg case TOK.this_:
7883 1.1 mrg e = new AST.ThisExp(loc);
7884 1.1 mrg nextToken();
7885 1.1 mrg break;
7886 1.1 mrg
7887 1.1 mrg case TOK.super_:
7888 1.1 mrg e = new AST.SuperExp(loc);
7889 1.1 mrg nextToken();
7890 1.1 mrg break;
7891 1.1 mrg
7892 1.1 mrg case TOK.int32Literal:
7893 1.1 mrg e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
7894 1.1 mrg nextToken();
7895 1.1 mrg break;
7896 1.1 mrg
7897 1.1 mrg case TOK.uns32Literal:
7898 1.1 mrg e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
7899 1.1 mrg nextToken();
7900 1.1 mrg break;
7901 1.1 mrg
7902 1.1 mrg case TOK.int64Literal:
7903 1.1 mrg e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
7904 1.1 mrg nextToken();
7905 1.1 mrg break;
7906 1.1 mrg
7907 1.1 mrg case TOK.uns64Literal:
7908 1.1 mrg e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
7909 1.1 mrg nextToken();
7910 1.1 mrg break;
7911 1.1 mrg
7912 1.1 mrg case TOK.float32Literal:
7913 1.1 mrg e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
7914 1.1 mrg nextToken();
7915 1.1 mrg break;
7916 1.1 mrg
7917 1.1 mrg case TOK.float64Literal:
7918 1.1 mrg e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
7919 1.1 mrg nextToken();
7920 1.1 mrg break;
7921 1.1 mrg
7922 1.1 mrg case TOK.float80Literal:
7923 1.1 mrg e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
7924 1.1 mrg nextToken();
7925 1.1 mrg break;
7926 1.1 mrg
7927 1.1 mrg case TOK.imaginary32Literal:
7928 1.1 mrg e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
7929 1.1 mrg nextToken();
7930 1.1 mrg break;
7931 1.1 mrg
7932 1.1 mrg case TOK.imaginary64Literal:
7933 1.1 mrg e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
7934 1.1 mrg nextToken();
7935 1.1 mrg break;
7936 1.1 mrg
7937 1.1 mrg case TOK.imaginary80Literal:
7938 1.1 mrg e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
7939 1.1 mrg nextToken();
7940 1.1 mrg break;
7941 1.1 mrg
7942 1.1 mrg case TOK.null_:
7943 1.1 mrg e = new AST.NullExp(loc);
7944 1.1 mrg nextToken();
7945 1.1 mrg break;
7946 1.1 mrg
7947 1.1 mrg case TOK.file:
7948 1.1 mrg {
7949 1.1 mrg const(char)* s = loc.filename ? loc.filename : mod.ident.toChars();
7950 1.1 mrg e = new AST.StringExp(loc, s.toDString());
7951 1.1 mrg nextToken();
7952 1.1 mrg break;
7953 1.1 mrg }
7954 1.1 mrg case TOK.fileFullPath:
7955 1.1 mrg {
7956 1.1 mrg assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
7957 1.1 mrg const s = FileName.toAbsolute(loc.filename);
7958 1.1 mrg e = new AST.StringExp(loc, s.toDString());
7959 1.1 mrg nextToken();
7960 1.1 mrg break;
7961 1.1 mrg }
7962 1.1 mrg
7963 1.1 mrg case TOK.line:
7964 1.1 mrg e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32);
7965 1.1 mrg nextToken();
7966 1.1 mrg break;
7967 1.1 mrg
7968 1.1 mrg case TOK.moduleString:
7969 1.1 mrg {
7970 1.1 mrg const(char)* s = md ? md.toChars() : mod.toChars();
7971 1.1 mrg e = new AST.StringExp(loc, s.toDString());
7972 1.1 mrg nextToken();
7973 1.1 mrg break;
7974 1.1 mrg }
7975 1.1 mrg case TOK.functionString:
7976 1.1 mrg e = new AST.FuncInitExp(loc);
7977 1.1 mrg nextToken();
7978 1.1 mrg break;
7979 1.1 mrg
7980 1.1 mrg case TOK.prettyFunction:
7981 1.1 mrg e = new AST.PrettyFuncInitExp(loc);
7982 1.1 mrg nextToken();
7983 1.1 mrg break;
7984 1.1 mrg
7985 1.1 mrg case TOK.true_:
7986 1.1 mrg e = new AST.IntegerExp(loc, 1, AST.Type.tbool);
7987 1.1 mrg nextToken();
7988 1.1 mrg break;
7989 1.1 mrg
7990 1.1 mrg case TOK.false_:
7991 1.1 mrg e = new AST.IntegerExp(loc, 0, AST.Type.tbool);
7992 1.1 mrg nextToken();
7993 1.1 mrg break;
7994 1.1 mrg
7995 1.1 mrg case TOK.charLiteral:
7996 1.1 mrg e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tchar);
7997 1.1 mrg nextToken();
7998 1.1 mrg break;
7999 1.1 mrg
8000 1.1 mrg case TOK.wcharLiteral:
8001 1.1 mrg e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.twchar);
8002 1.1 mrg nextToken();
8003 1.1 mrg break;
8004 1.1 mrg
8005 1.1 mrg case TOK.dcharLiteral:
8006 1.1 mrg e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tdchar);
8007 1.1 mrg nextToken();
8008 1.1 mrg break;
8009 1.1 mrg
8010 1.1 mrg case TOK.string_:
8011 1.1 mrg {
8012 1.1 mrg // cat adjacent strings
8013 1.1 mrg auto s = token.ustring;
8014 1.1 mrg auto len = token.len;
8015 1.1 mrg auto postfix = token.postfix;
8016 1.1 mrg while (1)
8017 1.1 mrg {
8018 1.1 mrg const prev = token;
8019 1.1 mrg nextToken();
8020 1.1 mrg if (token.value == TOK.string_)
8021 1.1 mrg {
8022 1.1 mrg if (token.postfix)
8023 1.1 mrg {
8024 1.1 mrg if (token.postfix != postfix)
8025 1.1 mrg error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
8026 1.1 mrg postfix = token.postfix;
8027 1.1 mrg }
8028 1.1 mrg
8029 1.1 mrg error("Implicit string concatenation is error-prone and disallowed in D");
8030 1.1 mrg errorSupplemental(token.loc, "Use the explicit syntax instead " ~
8031 1.1 mrg "(concatenating literals is `@nogc`): %s ~ %s",
8032 1.1 mrg prev.toChars(), token.toChars());
8033 1.1 mrg
8034 1.1 mrg const len1 = len;
8035 1.1 mrg const len2 = token.len;
8036 1.1 mrg len = len1 + len2;
8037 1.1 mrg auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
8038 1.1 mrg memcpy(s2, s, len1 * char.sizeof);
8039 1.1 mrg memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
8040 1.1 mrg s = s2;
8041 1.1 mrg }
8042 1.1 mrg else
8043 1.1 mrg break;
8044 1.1 mrg }
8045 1.1 mrg e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
8046 1.1 mrg break;
8047 1.1 mrg }
8048 1.1 mrg case TOK.void_:
8049 1.1 mrg t = AST.Type.tvoid;
8050 1.1 mrg goto LabelX;
8051 1.1 mrg
8052 1.1 mrg case TOK.int8:
8053 1.1 mrg t = AST.Type.tint8;
8054 1.1 mrg goto LabelX;
8055 1.1 mrg
8056 1.1 mrg case TOK.uns8:
8057 1.1 mrg t = AST.Type.tuns8;
8058 1.1 mrg goto LabelX;
8059 1.1 mrg
8060 1.1 mrg case TOK.int16:
8061 1.1 mrg t = AST.Type.tint16;
8062 1.1 mrg goto LabelX;
8063 1.1 mrg
8064 1.1 mrg case TOK.uns16:
8065 1.1 mrg t = AST.Type.tuns16;
8066 1.1 mrg goto LabelX;
8067 1.1 mrg
8068 1.1 mrg case TOK.int32:
8069 1.1 mrg t = AST.Type.tint32;
8070 1.1 mrg goto LabelX;
8071 1.1 mrg
8072 1.1 mrg case TOK.uns32:
8073 1.1 mrg t = AST.Type.tuns32;
8074 1.1 mrg goto LabelX;
8075 1.1 mrg
8076 1.1 mrg case TOK.int64:
8077 1.1 mrg t = AST.Type.tint64;
8078 1.1 mrg goto LabelX;
8079 1.1 mrg
8080 1.1 mrg case TOK.uns64:
8081 1.1 mrg t = AST.Type.tuns64;
8082 1.1 mrg goto LabelX;
8083 1.1 mrg
8084 1.1 mrg case TOK.int128:
8085 1.1 mrg t = AST.Type.tint128;
8086 1.1 mrg goto LabelX;
8087 1.1 mrg
8088 1.1 mrg case TOK.uns128:
8089 1.1 mrg t = AST.Type.tuns128;
8090 1.1 mrg goto LabelX;
8091 1.1 mrg
8092 1.1 mrg case TOK.float32:
8093 1.1 mrg t = AST.Type.tfloat32;
8094 1.1 mrg goto LabelX;
8095 1.1 mrg
8096 1.1 mrg case TOK.float64:
8097 1.1 mrg t = AST.Type.tfloat64;
8098 1.1 mrg goto LabelX;
8099 1.1 mrg
8100 1.1 mrg case TOK.float80:
8101 1.1 mrg t = AST.Type.tfloat80;
8102 1.1 mrg goto LabelX;
8103 1.1 mrg
8104 1.1 mrg case TOK.imaginary32:
8105 1.1 mrg t = AST.Type.timaginary32;
8106 1.1 mrg goto LabelX;
8107 1.1 mrg
8108 1.1 mrg case TOK.imaginary64:
8109 1.1 mrg t = AST.Type.timaginary64;
8110 1.1 mrg goto LabelX;
8111 1.1 mrg
8112 1.1 mrg case TOK.imaginary80:
8113 1.1 mrg t = AST.Type.timaginary80;
8114 1.1 mrg goto LabelX;
8115 1.1 mrg
8116 1.1 mrg case TOK.complex32:
8117 1.1 mrg t = AST.Type.tcomplex32;
8118 1.1 mrg goto LabelX;
8119 1.1 mrg
8120 1.1 mrg case TOK.complex64:
8121 1.1 mrg t = AST.Type.tcomplex64;
8122 1.1 mrg goto LabelX;
8123 1.1 mrg
8124 1.1 mrg case TOK.complex80:
8125 1.1 mrg t = AST.Type.tcomplex80;
8126 1.1 mrg goto LabelX;
8127 1.1 mrg
8128 1.1 mrg case TOK.bool_:
8129 1.1 mrg t = AST.Type.tbool;
8130 1.1 mrg goto LabelX;
8131 1.1 mrg
8132 1.1 mrg case TOK.char_:
8133 1.1 mrg t = AST.Type.tchar;
8134 1.1 mrg goto LabelX;
8135 1.1 mrg
8136 1.1 mrg case TOK.wchar_:
8137 1.1 mrg t = AST.Type.twchar;
8138 1.1 mrg goto LabelX;
8139 1.1 mrg
8140 1.1 mrg case TOK.dchar_:
8141 1.1 mrg t = AST.Type.tdchar;
8142 1.1 mrg goto LabelX;
8143 1.1 mrg LabelX:
8144 1.1 mrg nextToken();
8145 1.1 mrg if (token.value == TOK.leftParenthesis)
8146 1.1 mrg {
8147 1.1 mrg e = new AST.TypeExp(loc, t);
8148 1.1 mrg e = new AST.CallExp(loc, e, parseArguments());
8149 1.1 mrg break;
8150 1.1 mrg }
8151 1.1 mrg check(TOK.dot, t.toChars());
8152 1.1 mrg if (token.value != TOK.identifier)
8153 1.1 mrg {
8154 1.1 mrg error("found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars());
8155 1.1 mrg goto Lerr;
8156 1.1 mrg }
8157 1.1 mrg e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
8158 1.1 mrg nextToken();
8159 1.1 mrg break;
8160 1.1 mrg
8161 1.1 mrg case TOK.typeof_:
8162 1.1 mrg {
8163 1.1 mrg t = parseTypeof();
8164 1.1 mrg e = new AST.TypeExp(loc, t);
8165 1.1 mrg break;
8166 1.1 mrg }
8167 1.1 mrg case TOK.vector:
8168 1.1 mrg {
8169 1.1 mrg t = parseVector();
8170 1.1 mrg e = new AST.TypeExp(loc, t);
8171 1.1 mrg break;
8172 1.1 mrg }
8173 1.1 mrg case TOK.typeid_:
8174 1.1 mrg {
8175 1.1 mrg nextToken();
8176 1.1 mrg check(TOK.leftParenthesis, "`typeid`");
8177 1.1 mrg RootObject o = parseTypeOrAssignExp();
8178 1.1 mrg check(TOK.rightParenthesis);
8179 1.1 mrg e = new AST.TypeidExp(loc, o);
8180 1.1 mrg break;
8181 1.1 mrg }
8182 1.1 mrg case TOK.traits:
8183 1.1 mrg {
8184 1.1 mrg /* __traits(identifier, args...)
8185 1.1 mrg */
8186 1.1 mrg Identifier ident;
8187 1.1 mrg AST.Objects* args = null;
8188 1.1 mrg
8189 1.1 mrg nextToken();
8190 1.1 mrg check(TOK.leftParenthesis);
8191 1.1 mrg if (token.value != TOK.identifier)
8192 1.1 mrg {
8193 1.1 mrg error("`__traits(identifier, args...)` expected");
8194 1.1 mrg goto Lerr;
8195 1.1 mrg }
8196 1.1 mrg ident = token.ident;
8197 1.1 mrg nextToken();
8198 1.1 mrg if (token.value == TOK.comma)
8199 1.1 mrg args = parseTemplateArgumentList(); // __traits(identifier, args...)
8200 1.1 mrg else
8201 1.1 mrg check(TOK.rightParenthesis); // __traits(identifier)
8202 1.1 mrg
8203 1.1 mrg e = new AST.TraitsExp(loc, ident, args);
8204 1.1 mrg break;
8205 1.1 mrg }
8206 1.1 mrg case TOK.is_:
8207 1.1 mrg {
8208 1.1 mrg AST.Type targ;
8209 1.1 mrg Identifier ident = null;
8210 1.1 mrg AST.Type tspec = null;
8211 1.1 mrg TOK tok = TOK.reserved;
8212 1.1 mrg TOK tok2 = TOK.reserved;
8213 1.1 mrg AST.TemplateParameters* tpl = null;
8214 1.1 mrg
8215 1.1 mrg nextToken();
8216 1.1 mrg if (token.value == TOK.leftParenthesis)
8217 1.1 mrg {
8218 1.1 mrg nextToken();
8219 1.1 mrg if (token.value == TOK.identifier && peekNext() == TOK.leftParenthesis)
8220 1.1 mrg {
8221 1.1 mrg error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
8222 1.1 mrg nextToken();
8223 1.1 mrg Token* tempTok = peekPastParen(&token);
8224 1.1 mrg memcpy(&token, tempTok, Token.sizeof);
8225 1.1 mrg goto Lerr;
8226 1.1 mrg }
8227 1.1 mrg targ = parseType(&ident);
8228 1.1 mrg if (token.value == TOK.colon || token.value == TOK.equal)
8229 1.1 mrg {
8230 1.1 mrg tok = token.value;
8231 1.1 mrg nextToken();
8232 1.1 mrg if (tok == TOK.equal && (token.value == TOK.struct_ || token.value == TOK.union_
8233 1.1 mrg || token.value == TOK.class_ || token.value == TOK.super_ || token.value == TOK.enum_
8234 1.1 mrg || token.value == TOK.interface_ || token.value == TOK.package_ || token.value == TOK.module_
8235 1.1 mrg || token.value == TOK.argumentTypes || token.value == TOK.parameters
8236 1.1 mrg || token.value == TOK.const_ && peekNext() == TOK.rightParenthesis
8237 1.1 mrg || token.value == TOK.immutable_ && peekNext() == TOK.rightParenthesis
8238 1.1 mrg || token.value == TOK.shared_ && peekNext() == TOK.rightParenthesis
8239 1.1 mrg || token.value == TOK.inout_ && peekNext() == TOK.rightParenthesis || token.value == TOK.function_
8240 1.1 mrg || token.value == TOK.delegate_ || token.value == TOK.return_
8241 1.1 mrg || (token.value == TOK.vector && peekNext() == TOK.rightParenthesis)))
8242 1.1 mrg {
8243 1.1 mrg tok2 = token.value;
8244 1.1 mrg nextToken();
8245 1.1 mrg }
8246 1.1 mrg else
8247 1.1 mrg {
8248 1.1 mrg tspec = parseType();
8249 1.1 mrg }
8250 1.1 mrg }
8251 1.1 mrg if (tspec)
8252 1.1 mrg {
8253 1.1 mrg if (token.value == TOK.comma)
8254 1.1 mrg tpl = parseTemplateParameterList(1);
8255 1.1 mrg else
8256 1.1 mrg {
8257 1.1 mrg tpl = new AST.TemplateParameters();
8258 1.1 mrg check(TOK.rightParenthesis);
8259 1.1 mrg }
8260 1.1 mrg }
8261 1.1 mrg else
8262 1.1 mrg check(TOK.rightParenthesis);
8263 1.1 mrg }
8264 1.1 mrg else
8265 1.1 mrg {
8266 1.1 mrg error("`type identifier : specialization` expected following `is`");
8267 1.1 mrg goto Lerr;
8268 1.1 mrg }
8269 1.1 mrg e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
8270 1.1 mrg break;
8271 1.1 mrg }
8272 1.1 mrg case TOK.assert_:
8273 1.1 mrg {
8274 1.1 mrg // https://dlang.org/spec/expression.html#assert_expressions
8275 1.1 mrg AST.Expression msg = null;
8276 1.1 mrg
8277 1.1 mrg nextToken();
8278 1.1 mrg check(TOK.leftParenthesis, "`assert`");
8279 1.1 mrg e = parseAssignExp();
8280 1.1 mrg if (token.value == TOK.comma)
8281 1.1 mrg {
8282 1.1 mrg nextToken();
8283 1.1 mrg if (token.value != TOK.rightParenthesis)
8284 1.1 mrg {
8285 1.1 mrg msg = parseAssignExp();
8286 1.1 mrg if (token.value == TOK.comma)
8287 1.1 mrg nextToken();
8288 1.1 mrg }
8289 1.1 mrg }
8290 1.1 mrg check(TOK.rightParenthesis);
8291 1.1 mrg e = new AST.AssertExp(loc, e, msg);
8292 1.1 mrg break;
8293 1.1 mrg }
8294 1.1 mrg case TOK.mixin_:
8295 1.1 mrg {
8296 1.1 mrg // https://dlang.org/spec/expression.html#mixin_expressions
8297 1.1 mrg nextToken();
8298 1.1 mrg if (token.value != TOK.leftParenthesis)
8299 1.1 mrg error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
8300 1.1 mrg auto exps = parseArguments();
8301 1.1 mrg e = new AST.MixinExp(loc, exps);
8302 1.1 mrg break;
8303 1.1 mrg }
8304 1.1 mrg case TOK.import_:
8305 1.1 mrg {
8306 1.1 mrg nextToken();
8307 1.1 mrg check(TOK.leftParenthesis, "`import`");
8308 1.1 mrg e = parseAssignExp();
8309 1.1 mrg check(TOK.rightParenthesis);
8310 1.1 mrg e = new AST.ImportExp(loc, e);
8311 1.1 mrg break;
8312 1.1 mrg }
8313 1.1 mrg case TOK.new_:
8314 1.1 mrg e = parseNewExp(null);
8315 1.1 mrg break;
8316 1.1 mrg
8317 1.1 mrg case TOK.ref_:
8318 1.1 mrg {
8319 1.1 mrg if (peekNext() == TOK.leftParenthesis)
8320 1.1 mrg {
8321 1.1 mrg Token* tk = peekPastParen(peek(&token));
8322 1.1 mrg if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
8323 1.1 mrg {
8324 1.1 mrg // ref (arguments) => expression
8325 1.1 mrg // ref (arguments) { statements... }
8326 1.1 mrg goto case_delegate;
8327 1.1 mrg }
8328 1.1 mrg }
8329 1.1 mrg nextToken();
8330 1.1 mrg error("found `%s` when expecting function literal following `ref`", token.toChars());
8331 1.1 mrg goto Lerr;
8332 1.1 mrg }
8333 1.1 mrg case TOK.leftParenthesis:
8334 1.1 mrg {
8335 1.1 mrg Token* tk = peekPastParen(&token);
8336 1.1 mrg if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
8337 1.1 mrg {
8338 1.1 mrg // (arguments) => expression
8339 1.1 mrg // (arguments) { statements... }
8340 1.1 mrg goto case_delegate;
8341 1.1 mrg }
8342 1.1 mrg
8343 1.1 mrg // ( expression )
8344 1.1 mrg nextToken();
8345 1.1 mrg e = parseExpression();
8346 1.1 mrg e.parens = 1;
8347 1.1 mrg check(loc, TOK.rightParenthesis);
8348 1.1 mrg break;
8349 1.1 mrg }
8350 1.1 mrg case TOK.leftBracket:
8351 1.1 mrg {
8352 1.1 mrg /* Parse array literals and associative array literals:
8353 1.1 mrg * [ value, value, value ... ]
8354 1.1 mrg * [ key:value, key:value, key:value ... ]
8355 1.1 mrg */
8356 1.1 mrg auto values = new AST.Expressions();
8357 1.1 mrg AST.Expressions* keys = null;
8358 1.1 mrg
8359 1.1 mrg nextToken();
8360 1.1 mrg while (token.value != TOK.rightBracket && token.value != TOK.endOfFile)
8361 1.1 mrg {
8362 1.1 mrg e = parseAssignExp();
8363 1.1 mrg if (token.value == TOK.colon && (keys || values.dim == 0))
8364 1.1 mrg {
8365 1.1 mrg nextToken();
8366 1.1 mrg if (!keys)
8367 1.1 mrg keys = new AST.Expressions();
8368 1.1 mrg keys.push(e);
8369 1.1 mrg e = parseAssignExp();
8370 1.1 mrg }
8371 1.1 mrg else if (keys)
8372 1.1 mrg {
8373 1.1 mrg error("`key:value` expected for associative array literal");
8374 1.1 mrg keys = null;
8375 1.1 mrg }
8376 1.1 mrg values.push(e);
8377 1.1 mrg if (token.value == TOK.rightBracket)
8378 1.1 mrg break;
8379 1.1 mrg check(TOK.comma);
8380 1.1 mrg }
8381 1.1 mrg check(loc, TOK.rightBracket);
8382 1.1 mrg
8383 1.1 mrg if (keys)
8384 1.1 mrg e = new AST.AssocArrayLiteralExp(loc, keys, values);
8385 1.1 mrg else
8386 1.1 mrg e = new AST.ArrayLiteralExp(loc, null, values);
8387 1.1 mrg break;
8388 1.1 mrg }
8389 1.1 mrg case TOK.leftCurly:
8390 1.1 mrg case TOK.function_:
8391 1.1 mrg case TOK.delegate_:
8392 1.1 mrg case_delegate:
8393 1.1 mrg {
8394 1.1 mrg AST.Dsymbol s = parseFunctionLiteral();
8395 1.1 mrg e = new AST.FuncExp(loc, s);
8396 1.1 mrg break;
8397 1.1 mrg }
8398 1.1 mrg
8399 1.1 mrg default:
8400 1.1 mrg error("expression expected, not `%s`", token.toChars());
8401 1.1 mrg Lerr:
8402 1.1 mrg // Anything for e, as long as it's not NULL
8403 1.1 mrg e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
8404 1.1 mrg nextToken();
8405 1.1 mrg break;
8406 1.1 mrg }
8407 1.1 mrg return e;
8408 1.1 mrg }
8409 1.1 mrg
8410 1.1 mrg private AST.Expression parseUnaryExp()
8411 1.1 mrg {
8412 1.1 mrg AST.Expression e;
8413 1.1 mrg const loc = token.loc;
8414 1.1 mrg
8415 1.1 mrg switch (token.value)
8416 1.1 mrg {
8417 1.1 mrg case TOK.and:
8418 1.1 mrg nextToken();
8419 1.1 mrg e = parseUnaryExp();
8420 1.1 mrg e = new AST.AddrExp(loc, e);
8421 1.1 mrg break;
8422 1.1 mrg
8423 1.1 mrg case TOK.plusPlus:
8424 1.1 mrg nextToken();
8425 1.1 mrg e = parseUnaryExp();
8426 1.1 mrg //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8427 1.1 mrg e = new AST.PreExp(EXP.prePlusPlus, loc, e);
8428 1.1 mrg break;
8429 1.1 mrg
8430 1.1 mrg case TOK.minusMinus:
8431 1.1 mrg nextToken();
8432 1.1 mrg e = parseUnaryExp();
8433 1.1 mrg //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8434 1.1 mrg e = new AST.PreExp(EXP.preMinusMinus, loc, e);
8435 1.1 mrg break;
8436 1.1 mrg
8437 1.1 mrg case TOK.mul:
8438 1.1 mrg nextToken();
8439 1.1 mrg e = parseUnaryExp();
8440 1.1 mrg e = new AST.PtrExp(loc, e);
8441 1.1 mrg break;
8442 1.1 mrg
8443 1.1 mrg case TOK.min:
8444 1.1 mrg nextToken();
8445 1.1 mrg e = parseUnaryExp();
8446 1.1 mrg e = new AST.NegExp(loc, e);
8447 1.1 mrg break;
8448 1.1 mrg
8449 1.1 mrg case TOK.add:
8450 1.1 mrg nextToken();
8451 1.1 mrg e = parseUnaryExp();
8452 1.1 mrg e = new AST.UAddExp(loc, e);
8453 1.1 mrg break;
8454 1.1 mrg
8455 1.1 mrg case TOK.not:
8456 1.1 mrg nextToken();
8457 1.1 mrg e = parseUnaryExp();
8458 1.1 mrg e = new AST.NotExp(loc, e);
8459 1.1 mrg break;
8460 1.1 mrg
8461 1.1 mrg case TOK.tilde:
8462 1.1 mrg nextToken();
8463 1.1 mrg e = parseUnaryExp();
8464 1.1 mrg e = new AST.ComExp(loc, e);
8465 1.1 mrg break;
8466 1.1 mrg
8467 1.1 mrg case TOK.delete_:
8468 1.1 mrg // @@@DEPRECATED_2.109@@@
8469 1.1 mrg // Use of `delete` keyword has been an error since 2.099.
8470 1.1 mrg // Remove from the parser after 2.109.
8471 1.1 mrg nextToken();
8472 1.1 mrg e = parseUnaryExp();
8473 1.1 mrg e = new AST.DeleteExp(loc, e, false);
8474 1.1 mrg break;
8475 1.1 mrg
8476 1.1 mrg case TOK.cast_: // cast(type) expression
8477 1.1 mrg {
8478 1.1 mrg nextToken();
8479 1.1 mrg check(TOK.leftParenthesis);
8480 1.1 mrg /* Look for cast(), cast(const), cast(immutable),
8481 1.1 mrg * cast(shared), cast(shared const), cast(wild), cast(shared wild)
8482 1.1 mrg */
8483 1.1 mrg ubyte m = 0;
8484 1.1 mrg while (1)
8485 1.1 mrg {
8486 1.1 mrg switch (token.value)
8487 1.1 mrg {
8488 1.1 mrg case TOK.const_:
8489 1.1 mrg if (peekNext() == TOK.leftParenthesis)
8490 1.1 mrg break; // const as type constructor
8491 1.1 mrg m |= MODFlags.const_; // const as storage class
8492 1.1 mrg nextToken();
8493 1.1 mrg continue;
8494 1.1 mrg
8495 1.1 mrg case TOK.immutable_:
8496 1.1 mrg if (peekNext() == TOK.leftParenthesis)
8497 1.1 mrg break;
8498 1.1 mrg m |= MODFlags.immutable_;
8499 1.1 mrg nextToken();
8500 1.1 mrg continue;
8501 1.1 mrg
8502 1.1 mrg case TOK.shared_:
8503 1.1 mrg if (peekNext() == TOK.leftParenthesis)
8504 1.1 mrg break;
8505 1.1 mrg m |= MODFlags.shared_;
8506 1.1 mrg nextToken();
8507 1.1 mrg continue;
8508 1.1 mrg
8509 1.1 mrg case TOK.inout_:
8510 1.1 mrg if (peekNext() == TOK.leftParenthesis)
8511 1.1 mrg break;
8512 1.1 mrg m |= MODFlags.wild;
8513 1.1 mrg nextToken();
8514 1.1 mrg continue;
8515 1.1 mrg
8516 1.1 mrg default:
8517 1.1 mrg break;
8518 1.1 mrg }
8519 1.1 mrg break;
8520 1.1 mrg }
8521 1.1 mrg if (token.value == TOK.rightParenthesis)
8522 1.1 mrg {
8523 1.1 mrg nextToken();
8524 1.1 mrg e = parseUnaryExp();
8525 1.1 mrg e = new AST.CastExp(loc, e, m);
8526 1.1 mrg }
8527 1.1 mrg else
8528 1.1 mrg {
8529 1.1 mrg AST.Type t = parseType(); // cast( type )
8530 1.1 mrg t = t.addMod(m); // cast( const type )
8531 1.1 mrg check(TOK.rightParenthesis);
8532 1.1 mrg e = parseUnaryExp();
8533 1.1 mrg e = new AST.CastExp(loc, e, t);
8534 1.1 mrg }
8535 1.1 mrg break;
8536 1.1 mrg }
8537 1.1 mrg case TOK.inout_:
8538 1.1 mrg case TOK.shared_:
8539 1.1 mrg case TOK.const_:
8540 1.1 mrg case TOK.immutable_: // immutable(type)(arguments) / immutable(type).init
8541 1.1 mrg {
8542 1.1 mrg StorageClass stc = parseTypeCtor();
8543 1.1 mrg
8544 1.1 mrg AST.Type t = parseBasicType();
8545 1.1 mrg t = t.addSTC(stc);
8546 1.1 mrg
8547 1.1 mrg if (stc == 0 && token.value == TOK.dot)
8548 1.1 mrg {
8549 1.1 mrg nextToken();
8550 1.1 mrg if (token.value != TOK.identifier)
8551 1.1 mrg {
8552 1.1 mrg error("identifier expected following `(type)`.");
8553 1.1 mrg return null;
8554 1.1 mrg }
8555 1.1 mrg e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
8556 1.1 mrg nextToken();
8557 1.1 mrg e = parsePostExp(e);
8558 1.1 mrg }
8559 1.1 mrg else
8560 1.1 mrg {
8561 1.1 mrg e = new AST.TypeExp(loc, t);
8562 1.1 mrg if (token.value != TOK.leftParenthesis)
8563 1.1 mrg {
8564 1.1 mrg error("`(arguments)` expected following `%s`", t.toChars());
8565 1.1 mrg return e;
8566 1.1 mrg }
8567 1.1 mrg e = new AST.CallExp(loc, e, parseArguments());
8568 1.1 mrg }
8569 1.1 mrg break;
8570 1.1 mrg }
8571 1.1 mrg case TOK.leftParenthesis:
8572 1.1 mrg {
8573 1.1 mrg auto tk = peek(&token);
8574 1.1 mrg static if (CCASTSYNTAX)
8575 1.1 mrg {
8576 1.1 mrg // If cast
8577 1.1 mrg if (isDeclaration(tk, NeedDeclaratorId.no, TOK.rightParenthesis, &tk))
8578 1.1 mrg {
8579 1.1 mrg tk = peek(tk); // skip over right parenthesis
8580 1.1 mrg switch (tk.value)
8581 1.1 mrg {
8582 1.1 mrg case TOK.not:
8583 1.1 mrg tk = peek(tk);
8584 1.1 mrg if (tk.value == TOK.is_ || tk.value == TOK.in_) // !is or !in
8585 1.1 mrg break;
8586 1.1 mrg goto case;
8587 1.1 mrg
8588 1.1 mrg case TOK.dot:
8589 1.1 mrg case TOK.plusPlus:
8590 1.1 mrg case TOK.minusMinus:
8591 1.1 mrg case TOK.delete_:
8592 1.1 mrg case TOK.new_:
8593 1.1 mrg case TOK.leftParenthesis:
8594 1.1 mrg case TOK.identifier:
8595 1.1 mrg case TOK.this_:
8596 1.1 mrg case TOK.super_:
8597 1.1 mrg case TOK.int32Literal:
8598 1.1 mrg case TOK.uns32Literal:
8599 1.1 mrg case TOK.int64Literal:
8600 1.1 mrg case TOK.uns64Literal:
8601 1.1 mrg case TOK.int128Literal:
8602 1.1 mrg case TOK.uns128Literal:
8603 1.1 mrg case TOK.float32Literal:
8604 1.1 mrg case TOK.float64Literal:
8605 1.1 mrg case TOK.float80Literal:
8606 1.1 mrg case TOK.imaginary32Literal:
8607 1.1 mrg case TOK.imaginary64Literal:
8608 1.1 mrg case TOK.imaginary80Literal:
8609 1.1 mrg case TOK.null_:
8610 1.1 mrg case TOK.true_:
8611 1.1 mrg case TOK.false_:
8612 1.1 mrg case TOK.charLiteral:
8613 1.1 mrg case TOK.wcharLiteral:
8614 1.1 mrg case TOK.dcharLiteral:
8615 1.1 mrg case TOK.string_:
8616 1.1 mrg version (none)
8617 1.1 mrg {
8618 1.1 mrg case TOK.tilde:
8619 1.1 mrg case TOK.and:
8620 1.1 mrg case TOK.mul:
8621 1.1 mrg case TOK.min:
8622 1.1 mrg case TOK.add:
8623 1.1 mrg }
8624 1.1 mrg case TOK.function_:
8625 1.1 mrg case TOK.delegate_:
8626 1.1 mrg case TOK.typeof_:
8627 1.1 mrg case TOK.traits:
8628 1.1 mrg case TOK.vector:
8629 1.1 mrg case TOK.file:
8630 1.1 mrg case TOK.fileFullPath:
8631 1.1 mrg case TOK.line:
8632 1.1 mrg case TOK.moduleString:
8633 1.1 mrg case TOK.functionString:
8634 1.1 mrg case TOK.prettyFunction:
8635 1.1 mrg case TOK.wchar_:
8636 1.1 mrg case TOK.dchar_:
8637 1.1 mrg case TOK.bool_:
8638 1.1 mrg case TOK.char_:
8639 1.1 mrg case TOK.int8:
8640 1.1 mrg case TOK.uns8:
8641 1.1 mrg case TOK.int16:
8642 1.1 mrg case TOK.uns16:
8643 1.1 mrg case TOK.int32:
8644 1.1 mrg case TOK.uns32:
8645 1.1 mrg case TOK.int64:
8646 1.1 mrg case TOK.uns64:
8647 1.1 mrg case TOK.int128:
8648 1.1 mrg case TOK.uns128:
8649 1.1 mrg case TOK.float32:
8650 1.1 mrg case TOK.float64:
8651 1.1 mrg case TOK.float80:
8652 1.1 mrg case TOK.imaginary32:
8653 1.1 mrg case TOK.imaginary64:
8654 1.1 mrg case TOK.imaginary80:
8655 1.1 mrg case TOK.complex32:
8656 1.1 mrg case TOK.complex64:
8657 1.1 mrg case TOK.complex80:
8658 1.1 mrg case TOK.void_:
8659 1.1 mrg {
8660 1.1 mrg // (type) una_exp
8661 1.1 mrg nextToken();
8662 1.1 mrg auto t = parseType();
8663 1.1 mrg check(TOK.rightParenthesis);
8664 1.1 mrg
8665 1.1 mrg // if .identifier
8666 1.1 mrg // or .identifier!( ... )
8667 1.1 mrg if (token.value == TOK.dot)
8668 1.1 mrg {
8669 1.1 mrg if (peekNext() != TOK.identifier && peekNext() != TOK.new_)
8670 1.1 mrg {
8671 1.1 mrg error("identifier or new keyword expected following `(...)`.");
8672 1.1 mrg return null;
8673 1.1 mrg }
8674 1.1 mrg e = new AST.TypeExp(loc, t);
8675 1.1 mrg e.parens = true;
8676 1.1 mrg e = parsePostExp(e);
8677 1.1 mrg }
8678 1.1 mrg else
8679 1.1 mrg {
8680 1.1 mrg e = parseUnaryExp();
8681 1.1 mrg e = new AST.CastExp(loc, e, t);
8682 1.1 mrg error("C style cast illegal, use `%s`", e.toChars());
8683 1.1 mrg }
8684 1.1 mrg return e;
8685 1.1 mrg }
8686 1.1 mrg default:
8687 1.1 mrg break;
8688 1.1 mrg }
8689 1.1 mrg }
8690 1.1 mrg }
8691 1.1 mrg e = parsePrimaryExp();
8692 1.1 mrg e = parsePostExp(e);
8693 1.1 mrg break;
8694 1.1 mrg }
8695 1.1 mrg case TOK.throw_:
8696 1.1 mrg {
8697 1.1 mrg nextToken();
8698 1.1 mrg // Deviation from the DIP:
8699 1.1 mrg // Parse AssignExpression instead of Expression to avoid conflicts for comma
8700 1.1 mrg // separated lists, e.g. function arguments
8701 1.1 mrg AST.Expression exp = parseAssignExp();
8702 1.1 mrg e = new AST.ThrowExp(loc, exp);
8703 1.1 mrg break;
8704 1.1 mrg }
8705 1.1 mrg
8706 1.1 mrg default:
8707 1.1 mrg e = parsePrimaryExp();
8708 1.1 mrg e = parsePostExp(e);
8709 1.1 mrg break;
8710 1.1 mrg }
8711 1.1 mrg assert(e);
8712 1.1 mrg
8713 1.1 mrg // ^^ is right associative and has higher precedence than the unary operators
8714 1.1 mrg while (token.value == TOK.pow)
8715 1.1 mrg {
8716 1.1 mrg nextToken();
8717 1.1 mrg AST.Expression e2 = parseUnaryExp();
8718 1.1 mrg e = new AST.PowExp(loc, e, e2);
8719 1.1 mrg }
8720 1.1 mrg
8721 1.1 mrg return e;
8722 1.1 mrg }
8723 1.1 mrg
8724 1.1 mrg private AST.Expression parsePostExp(AST.Expression e)
8725 1.1 mrg {
8726 1.1 mrg while (1)
8727 1.1 mrg {
8728 1.1 mrg const loc = token.loc;
8729 1.1 mrg switch (token.value)
8730 1.1 mrg {
8731 1.1 mrg case TOK.dot:
8732 1.1 mrg nextToken();
8733 1.1 mrg if (token.value == TOK.identifier)
8734 1.1 mrg {
8735 1.1 mrg Identifier id = token.ident;
8736 1.1 mrg
8737 1.1 mrg nextToken();
8738 1.1 mrg if (token.value == TOK.not && peekNext() != TOK.is_ && peekNext() != TOK.in_)
8739 1.1 mrg {
8740 1.1 mrg AST.Objects* tiargs = parseTemplateArguments();
8741 1.1 mrg e = new AST.DotTemplateInstanceExp(loc, e, id, tiargs);
8742 1.1 mrg }
8743 1.1 mrg else
8744 1.1 mrg e = new AST.DotIdExp(loc, e, id);
8745 1.1 mrg continue;
8746 1.1 mrg }
8747 1.1 mrg if (token.value == TOK.new_)
8748 1.1 mrg {
8749 1.1 mrg e = parseNewExp(e);
8750 1.1 mrg continue;
8751 1.1 mrg }
8752 1.1 mrg error("identifier or `new` expected following `.`, not `%s`", token.toChars());
8753 1.1 mrg break;
8754 1.1 mrg
8755 1.1 mrg case TOK.plusPlus:
8756 1.1 mrg e = new AST.PostExp(EXP.plusPlus, loc, e);
8757 1.1 mrg break;
8758 1.1 mrg
8759 1.1 mrg case TOK.minusMinus:
8760 1.1 mrg e = new AST.PostExp(EXP.minusMinus, loc, e);
8761 1.1 mrg break;
8762 1.1 mrg
8763 1.1 mrg case TOK.leftParenthesis:
8764 1.1 mrg e = new AST.CallExp(loc, e, parseArguments());
8765 1.1 mrg continue;
8766 1.1 mrg
8767 1.1 mrg case TOK.leftBracket:
8768 1.1 mrg {
8769 1.1 mrg // array dereferences:
8770 1.1 mrg // array[index]
8771 1.1 mrg // array[]
8772 1.1 mrg // array[lwr .. upr]
8773 1.1 mrg AST.Expression index;
8774 1.1 mrg AST.Expression upr;
8775 1.1 mrg auto arguments = new AST.Expressions();
8776 1.1 mrg
8777 1.1 mrg inBrackets++;
8778 1.1 mrg nextToken();
8779 1.1 mrg while (token.value != TOK.rightBracket && token.value != TOK.endOfFile)
8780 1.1 mrg {
8781 1.1 mrg index = parseAssignExp();
8782 1.1 mrg if (token.value == TOK.slice)
8783 1.1 mrg {
8784 1.1 mrg // array[..., lwr..upr, ...]
8785 1.1 mrg nextToken();
8786 1.1 mrg upr = parseAssignExp();
8787 1.1 mrg arguments.push(new AST.IntervalExp(loc, index, upr));
8788 1.1 mrg }
8789 1.1 mrg else
8790 1.1 mrg arguments.push(index);
8791 1.1 mrg if (token.value == TOK.rightBracket)
8792 1.1 mrg break;
8793 1.1 mrg check(TOK.comma);
8794 1.1 mrg }
8795 1.1 mrg check(TOK.rightBracket);
8796 1.1 mrg inBrackets--;
8797 1.1 mrg e = new AST.ArrayExp(loc, e, arguments);
8798 1.1 mrg continue;
8799 1.1 mrg }
8800 1.1 mrg default:
8801 1.1 mrg return e;
8802 1.1 mrg }
8803 1.1 mrg nextToken();
8804 1.1 mrg }
8805 1.1 mrg }
8806 1.1 mrg
8807 1.1 mrg private AST.Expression parseMulExp()
8808 1.1 mrg {
8809 1.1 mrg const loc = token.loc;
8810 1.1 mrg auto e = parseUnaryExp();
8811 1.1 mrg
8812 1.1 mrg while (1)
8813 1.1 mrg {
8814 1.1 mrg switch (token.value)
8815 1.1 mrg {
8816 1.1 mrg case TOK.mul:
8817 1.1 mrg nextToken();
8818 1.1 mrg auto e2 = parseUnaryExp();
8819 1.1 mrg e = new AST.MulExp(loc, e, e2);
8820 1.1 mrg continue;
8821 1.1 mrg
8822 1.1 mrg case TOK.div:
8823 1.1 mrg nextToken();
8824 1.1 mrg auto e2 = parseUnaryExp();
8825 1.1 mrg e = new AST.DivExp(loc, e, e2);
8826 1.1 mrg continue;
8827 1.1 mrg
8828 1.1 mrg case TOK.mod:
8829 1.1 mrg nextToken();
8830 1.1 mrg auto e2 = parseUnaryExp();
8831 1.1 mrg e = new AST.ModExp(loc, e, e2);
8832 1.1 mrg continue;
8833 1.1 mrg
8834 1.1 mrg default:
8835 1.1 mrg break;
8836 1.1 mrg }
8837 1.1 mrg break;
8838 1.1 mrg }
8839 1.1 mrg return e;
8840 1.1 mrg }
8841 1.1 mrg
8842 1.1 mrg private AST.Expression parseAddExp()
8843 1.1 mrg {
8844 1.1 mrg const loc = token.loc;
8845 1.1 mrg auto e = parseMulExp();
8846 1.1 mrg
8847 1.1 mrg while (1)
8848 1.1 mrg {
8849 1.1 mrg switch (token.value)
8850 1.1 mrg {
8851 1.1 mrg case TOK.add:
8852 1.1 mrg nextToken();
8853 1.1 mrg auto e2 = parseMulExp();
8854 1.1 mrg e = new AST.AddExp(loc, e, e2);
8855 1.1 mrg continue;
8856 1.1 mrg
8857 1.1 mrg case TOK.min:
8858 1.1 mrg nextToken();
8859 1.1 mrg auto e2 = parseMulExp();
8860 1.1 mrg e = new AST.MinExp(loc, e, e2);
8861 1.1 mrg continue;
8862 1.1 mrg
8863 1.1 mrg case TOK.tilde:
8864 1.1 mrg nextToken();
8865 1.1 mrg auto e2 = parseMulExp();
8866 1.1 mrg e = new AST.CatExp(loc, e, e2);
8867 1.1 mrg continue;
8868 1.1 mrg
8869 1.1 mrg default:
8870 1.1 mrg break;
8871 1.1 mrg }
8872 1.1 mrg break;
8873 1.1 mrg }
8874 1.1 mrg return e;
8875 1.1 mrg }
8876 1.1 mrg
8877 1.1 mrg private AST.Expression parseShiftExp()
8878 1.1 mrg {
8879 1.1 mrg const loc = token.loc;
8880 1.1 mrg auto e = parseAddExp();
8881 1.1 mrg
8882 1.1 mrg while (1)
8883 1.1 mrg {
8884 1.1 mrg switch (token.value)
8885 1.1 mrg {
8886 1.1 mrg case TOK.leftShift:
8887 1.1 mrg nextToken();
8888 1.1 mrg auto e2 = parseAddExp();
8889 1.1 mrg e = new AST.ShlExp(loc, e, e2);
8890 1.1 mrg continue;
8891 1.1 mrg
8892 1.1 mrg case TOK.rightShift:
8893 1.1 mrg nextToken();
8894 1.1 mrg auto e2 = parseAddExp();
8895 1.1 mrg e = new AST.ShrExp(loc, e, e2);
8896 1.1 mrg continue;
8897 1.1 mrg
8898 1.1 mrg case TOK.unsignedRightShift:
8899 1.1 mrg nextToken();
8900 1.1 mrg auto e2 = parseAddExp();
8901 1.1 mrg e = new AST.UshrExp(loc, e, e2);
8902 1.1 mrg continue;
8903 1.1 mrg
8904 1.1 mrg default:
8905 1.1 mrg break;
8906 1.1 mrg }
8907 1.1 mrg break;
8908 1.1 mrg }
8909 1.1 mrg return e;
8910 1.1 mrg }
8911 1.1 mrg
8912 1.1 mrg private AST.Expression parseCmpExp()
8913 1.1 mrg {
8914 1.1 mrg const loc = token.loc;
8915 1.1 mrg
8916 1.1 mrg auto e = parseShiftExp();
8917 1.1 mrg EXP op = EXP.reserved;
8918 1.1 mrg
8919 1.1 mrg switch (token.value)
8920 1.1 mrg {
8921 1.1 mrg case TOK.equal: op = EXP.equal; goto Lequal;
8922 1.1 mrg case TOK.notEqual: op = EXP.notEqual; goto Lequal;
8923 1.1 mrg Lequal:
8924 1.1 mrg nextToken();
8925 1.1 mrg auto e2 = parseShiftExp();
8926 1.1 mrg e = new AST.EqualExp(op, loc, e, e2);
8927 1.1 mrg break;
8928 1.1 mrg
8929 1.1 mrg case TOK.not:
8930 1.1 mrg {
8931 1.1 mrg // Attempt to identify '!is'
8932 1.1 mrg const tv = peekNext();
8933 1.1 mrg if (tv == TOK.in_)
8934 1.1 mrg {
8935 1.1 mrg nextToken();
8936 1.1 mrg nextToken();
8937 1.1 mrg auto e2 = parseShiftExp();
8938 1.1 mrg e = new AST.InExp(loc, e, e2);
8939 1.1 mrg e = new AST.NotExp(loc, e);
8940 1.1 mrg break;
8941 1.1 mrg }
8942 1.1 mrg if (tv != TOK.is_)
8943 1.1 mrg break;
8944 1.1 mrg nextToken();
8945 1.1 mrg op = EXP.notIdentity;
8946 1.1 mrg goto Lidentity;
8947 1.1 mrg }
8948 1.1 mrg case TOK.is_: op = EXP.identity; goto Lidentity;
8949 1.1 mrg Lidentity:
8950 1.1 mrg nextToken();
8951 1.1 mrg auto e2 = parseShiftExp();
8952 1.1 mrg e = new AST.IdentityExp(op, loc, e, e2);
8953 1.1 mrg break;
8954 1.1 mrg
8955 1.1 mrg case TOK.lessThan: op = EXP.lessThan; goto Lcmp;
8956 1.1 mrg case TOK.lessOrEqual: op = EXP.lessOrEqual; goto Lcmp;
8957 1.1 mrg case TOK.greaterThan: op = EXP.greaterThan; goto Lcmp;
8958 1.1 mrg case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
8959 1.1 mrg Lcmp:
8960 1.1 mrg nextToken();
8961 1.1 mrg auto e2 = parseShiftExp();
8962 1.1 mrg e = new AST.CmpExp(op, loc, e, e2);
8963 1.1 mrg break;
8964 1.1 mrg
8965 1.1 mrg case TOK.in_:
8966 1.1 mrg nextToken();
8967 1.1 mrg auto e2 = parseShiftExp();
8968 1.1 mrg e = new AST.InExp(loc, e, e2);
8969 1.1 mrg break;
8970 1.1 mrg
8971 1.1 mrg default:
8972 1.1 mrg break;
8973 1.1 mrg }
8974 1.1 mrg return e;
8975 1.1 mrg }
8976 1.1 mrg
8977 1.1 mrg private AST.Expression parseAndExp()
8978 1.1 mrg {
8979 1.1 mrg Loc loc = token.loc;
8980 1.1 mrg auto e = parseCmpExp();
8981 1.1 mrg while (token.value == TOK.and)
8982 1.1 mrg {
8983 1.1 mrg checkParens(TOK.and, e);
8984 1.1 mrg nextToken();
8985 1.1 mrg auto e2 = parseCmpExp();
8986 1.1 mrg checkParens(TOK.and, e2);
8987 1.1 mrg e = new AST.AndExp(loc, e, e2);
8988 1.1 mrg loc = token.loc;
8989 1.1 mrg }
8990 1.1 mrg return e;
8991 1.1 mrg }
8992 1.1 mrg
8993 1.1 mrg private AST.Expression parseXorExp()
8994 1.1 mrg {
8995 1.1 mrg const loc = token.loc;
8996 1.1 mrg
8997 1.1 mrg auto e = parseAndExp();
8998 1.1 mrg while (token.value == TOK.xor)
8999 1.1 mrg {
9000 1.1 mrg checkParens(TOK.xor, e);
9001 1.1 mrg nextToken();
9002 1.1 mrg auto e2 = parseAndExp();
9003 1.1 mrg checkParens(TOK.xor, e2);
9004 1.1 mrg e = new AST.XorExp(loc, e, e2);
9005 1.1 mrg }
9006 1.1 mrg return e;
9007 1.1 mrg }
9008 1.1 mrg
9009 1.1 mrg private AST.Expression parseOrExp()
9010 1.1 mrg {
9011 1.1 mrg const loc = token.loc;
9012 1.1 mrg
9013 1.1 mrg auto e = parseXorExp();
9014 1.1 mrg while (token.value == TOK.or)
9015 1.1 mrg {
9016 1.1 mrg checkParens(TOK.or, e);
9017 1.1 mrg nextToken();
9018 1.1 mrg auto e2 = parseXorExp();
9019 1.1 mrg checkParens(TOK.or, e2);
9020 1.1 mrg e = new AST.OrExp(loc, e, e2);
9021 1.1 mrg }
9022 1.1 mrg return e;
9023 1.1 mrg }
9024 1.1 mrg
9025 1.1 mrg private AST.Expression parseAndAndExp()
9026 1.1 mrg {
9027 1.1 mrg const loc = token.loc;
9028 1.1 mrg
9029 1.1 mrg auto e = parseOrExp();
9030 1.1 mrg while (token.value == TOK.andAnd)
9031 1.1 mrg {
9032 1.1 mrg nextToken();
9033 1.1 mrg auto e2 = parseOrExp();
9034 1.1 mrg e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
9035 1.1 mrg }
9036 1.1 mrg return e;
9037 1.1 mrg }
9038 1.1 mrg
9039 1.1 mrg private AST.Expression parseOrOrExp()
9040 1.1 mrg {
9041 1.1 mrg const loc = token.loc;
9042 1.1 mrg
9043 1.1 mrg auto e = parseAndAndExp();
9044 1.1 mrg while (token.value == TOK.orOr)
9045 1.1 mrg {
9046 1.1 mrg nextToken();
9047 1.1 mrg auto e2 = parseAndAndExp();
9048 1.1 mrg e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
9049 1.1 mrg }
9050 1.1 mrg return e;
9051 1.1 mrg }
9052 1.1 mrg
9053 1.1 mrg private AST.Expression parseCondExp()
9054 1.1 mrg {
9055 1.1 mrg const loc = token.loc;
9056 1.1 mrg
9057 1.1 mrg auto e = parseOrOrExp();
9058 1.1 mrg if (token.value == TOK.question)
9059 1.1 mrg {
9060 1.1 mrg nextToken();
9061 1.1 mrg auto e1 = parseExpression();
9062 1.1 mrg check(TOK.colon);
9063 1.1 mrg auto e2 = parseCondExp();
9064 1.1 mrg e = new AST.CondExp(loc, e, e1, e2);
9065 1.1 mrg }
9066 1.1 mrg return e;
9067 1.1 mrg }
9068 1.1 mrg
9069 1.1 mrg AST.Expression parseAssignExp()
9070 1.1 mrg {
9071 1.1 mrg AST.Expression e;
9072 1.1 mrg e = parseCondExp();
9073 1.1 mrg if (e is null)
9074 1.1 mrg return e;
9075 1.1 mrg
9076 1.1 mrg // require parens for e.g. `t ? a = 1 : b = 2`
9077 1.1 mrg void checkRequiredParens()
9078 1.1 mrg {
9079 1.1 mrg if (e.op == EXP.question && !e.parens)
9080 1.1 mrg dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
9081 1.1 mrg e.toChars(), Token.toChars(token.value));
9082 1.1 mrg }
9083 1.1 mrg
9084 1.1 mrg const loc = token.loc;
9085 1.1 mrg switch (token.value)
9086 1.1 mrg {
9087 1.1 mrg case TOK.assign:
9088 1.1 mrg checkRequiredParens();
9089 1.1 mrg nextToken();
9090 1.1 mrg auto e2 = parseAssignExp();
9091 1.1 mrg e = new AST.AssignExp(loc, e, e2);
9092 1.1 mrg break;
9093 1.1 mrg
9094 1.1 mrg case TOK.addAssign:
9095 1.1 mrg checkRequiredParens();
9096 1.1 mrg nextToken();
9097 1.1 mrg auto e2 = parseAssignExp();
9098 1.1 mrg e = new AST.AddAssignExp(loc, e, e2);
9099 1.1 mrg break;
9100 1.1 mrg
9101 1.1 mrg case TOK.minAssign:
9102 1.1 mrg checkRequiredParens();
9103 1.1 mrg nextToken();
9104 1.1 mrg auto e2 = parseAssignExp();
9105 1.1 mrg e = new AST.MinAssignExp(loc, e, e2);
9106 1.1 mrg break;
9107 1.1 mrg
9108 1.1 mrg case TOK.mulAssign:
9109 1.1 mrg checkRequiredParens();
9110 1.1 mrg nextToken();
9111 1.1 mrg auto e2 = parseAssignExp();
9112 1.1 mrg e = new AST.MulAssignExp(loc, e, e2);
9113 1.1 mrg break;
9114 1.1 mrg
9115 1.1 mrg case TOK.divAssign:
9116 1.1 mrg checkRequiredParens();
9117 1.1 mrg nextToken();
9118 1.1 mrg auto e2 = parseAssignExp();
9119 1.1 mrg e = new AST.DivAssignExp(loc, e, e2);
9120 1.1 mrg break;
9121 1.1 mrg
9122 1.1 mrg case TOK.modAssign:
9123 1.1 mrg checkRequiredParens();
9124 1.1 mrg nextToken();
9125 1.1 mrg auto e2 = parseAssignExp();
9126 1.1 mrg e = new AST.ModAssignExp(loc, e, e2);
9127 1.1 mrg break;
9128 1.1 mrg
9129 1.1 mrg case TOK.powAssign:
9130 1.1 mrg checkRequiredParens();
9131 1.1 mrg nextToken();
9132 1.1 mrg auto e2 = parseAssignExp();
9133 1.1 mrg e = new AST.PowAssignExp(loc, e, e2);
9134 1.1 mrg break;
9135 1.1 mrg
9136 1.1 mrg case TOK.andAssign:
9137 1.1 mrg checkRequiredParens();
9138 1.1 mrg nextToken();
9139 1.1 mrg auto e2 = parseAssignExp();
9140 1.1 mrg e = new AST.AndAssignExp(loc, e, e2);
9141 1.1 mrg break;
9142 1.1 mrg
9143 1.1 mrg case TOK.orAssign:
9144 1.1 mrg checkRequiredParens();
9145 1.1 mrg nextToken();
9146 1.1 mrg auto e2 = parseAssignExp();
9147 1.1 mrg e = new AST.OrAssignExp(loc, e, e2);
9148 1.1 mrg break;
9149 1.1 mrg
9150 1.1 mrg case TOK.xorAssign:
9151 1.1 mrg checkRequiredParens();
9152 1.1 mrg nextToken();
9153 1.1 mrg auto e2 = parseAssignExp();
9154 1.1 mrg e = new AST.XorAssignExp(loc, e, e2);
9155 1.1 mrg break;
9156 1.1 mrg
9157 1.1 mrg case TOK.leftShiftAssign:
9158 1.1 mrg checkRequiredParens();
9159 1.1 mrg nextToken();
9160 1.1 mrg auto e2 = parseAssignExp();
9161 1.1 mrg e = new AST.ShlAssignExp(loc, e, e2);
9162 1.1 mrg break;
9163 1.1 mrg
9164 1.1 mrg case TOK.rightShiftAssign:
9165 1.1 mrg checkRequiredParens();
9166 1.1 mrg nextToken();
9167 1.1 mrg auto e2 = parseAssignExp();
9168 1.1 mrg e = new AST.ShrAssignExp(loc, e, e2);
9169 1.1 mrg break;
9170 1.1 mrg
9171 1.1 mrg case TOK.unsignedRightShiftAssign:
9172 1.1 mrg checkRequiredParens();
9173 1.1 mrg nextToken();
9174 1.1 mrg auto e2 = parseAssignExp();
9175 1.1 mrg e = new AST.UshrAssignExp(loc, e, e2);
9176 1.1 mrg break;
9177 1.1 mrg
9178 1.1 mrg case TOK.concatenateAssign:
9179 1.1 mrg checkRequiredParens();
9180 1.1 mrg nextToken();
9181 1.1 mrg auto e2 = parseAssignExp();
9182 1.1 mrg e = new AST.CatAssignExp(loc, e, e2);
9183 1.1 mrg break;
9184 1.1 mrg
9185 1.1 mrg default:
9186 1.1 mrg break;
9187 1.1 mrg }
9188 1.1 mrg
9189 1.1 mrg return e;
9190 1.1 mrg }
9191 1.1 mrg
9192 1.1 mrg /*************************
9193 1.1 mrg * Collect argument list.
9194 1.1 mrg * Assume current token is ',', '$(LPAREN)' or '['.
9195 1.1 mrg */
9196 1.1 mrg private AST.Expressions* parseArguments()
9197 1.1 mrg {
9198 1.1 mrg // function call
9199 1.1 mrg AST.Expressions* arguments;
9200 1.1 mrg
9201 1.1 mrg arguments = new AST.Expressions();
9202 1.1 mrg const endtok = token.value == TOK.leftBracket ? TOK.rightBracket : TOK.rightParenthesis;
9203 1.1 mrg
9204 1.1 mrg nextToken();
9205 1.1 mrg
9206 1.1 mrg while (token.value != endtok && token.value != TOK.endOfFile)
9207 1.1 mrg {
9208 1.1 mrg auto arg = parseAssignExp();
9209 1.1 mrg arguments.push(arg);
9210 1.1 mrg if (token.value != TOK.comma)
9211 1.1 mrg break;
9212 1.1 mrg
9213 1.1 mrg nextToken(); //comma
9214 1.1 mrg }
9215 1.1 mrg
9216 1.1 mrg check(endtok);
9217 1.1 mrg
9218 1.1 mrg return arguments;
9219 1.1 mrg }
9220 1.1 mrg
9221 1.1 mrg /*******************************************
9222 1.1 mrg */
9223 1.1 mrg private AST.Expression parseNewExp(AST.Expression thisexp)
9224 1.1 mrg {
9225 1.1 mrg const loc = token.loc;
9226 1.1 mrg
9227 1.1 mrg nextToken();
9228 1.1 mrg AST.Expressions* arguments = null;
9229 1.1 mrg
9230 1.1 mrg // An anonymous nested class starts with "class"
9231 1.1 mrg if (token.value == TOK.class_)
9232 1.1 mrg {
9233 1.1 mrg nextToken();
9234 1.1 mrg if (token.value == TOK.leftParenthesis)
9235 1.1 mrg arguments = parseArguments();
9236 1.1 mrg
9237 1.1 mrg AST.BaseClasses* baseclasses = null;
9238 1.1 mrg if (token.value != TOK.leftCurly)
9239 1.1 mrg baseclasses = parseBaseClasses();
9240 1.1 mrg
9241 1.1 mrg Identifier id = null;
9242 1.1 mrg AST.Dsymbols* members = null;
9243 1.1 mrg
9244 1.1 mrg if (token.value != TOK.leftCurly)
9245 1.1 mrg {
9246 1.1 mrg error("`{ members }` expected for anonymous class");
9247 1.1 mrg }
9248 1.1 mrg else
9249 1.1 mrg {
9250 1.1 mrg nextToken();
9251 1.1 mrg members = parseDeclDefs(0);
9252 1.1 mrg if (token.value != TOK.rightCurly)
9253 1.1 mrg error("class member expected");
9254 1.1 mrg nextToken();
9255 1.1 mrg }
9256 1.1 mrg
9257 1.1 mrg auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
9258 1.1 mrg auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments);
9259 1.1 mrg return e;
9260 1.1 mrg }
9261 1.1 mrg
9262 1.1 mrg const stc = parseTypeCtor();
9263 1.1 mrg auto t = parseBasicType(true);
9264 1.1 mrg t = parseTypeSuffixes(t);
9265 1.1 mrg t = t.addSTC(stc);
9266 1.1 mrg if (t.ty == Taarray)
9267 1.1 mrg {
9268 1.1 mrg AST.TypeAArray taa = cast(AST.TypeAArray)t;
9269 1.1 mrg AST.Type index = taa.index;
9270 1.1 mrg auto edim = AST.typeToExpression(index);
9271 1.1 mrg if (!edim)
9272 1.1 mrg {
9273 1.1 mrg error("cannot create a `%s` with `new`", t.toChars);
9274 1.1 mrg return new AST.NullExp(loc);
9275 1.1 mrg }
9276 1.1 mrg t = new AST.TypeSArray(taa.next, edim);
9277 1.1 mrg }
9278 1.1 mrg else if (token.value == TOK.leftParenthesis && t.ty != Tsarray)
9279 1.1 mrg {
9280 1.1 mrg arguments = parseArguments();
9281 1.1 mrg }
9282 1.1 mrg
9283 1.1 mrg auto e = new AST.NewExp(loc, thisexp, t, arguments);
9284 1.1 mrg return e;
9285 1.1 mrg }
9286 1.1 mrg
9287 1.1 mrg /**********************************************
9288 1.1 mrg */
9289 1.1 mrg private void addComment(AST.Dsymbol s, const(char)* blockComment)
9290 1.1 mrg {
9291 1.1 mrg if (s !is null)
9292 1.1 mrg this.addComment(s, blockComment.toDString());
9293 1.1 mrg }
9294 1.1 mrg
9295 1.1 mrg private void addComment(AST.Dsymbol s, const(char)[] blockComment)
9296 1.1 mrg {
9297 1.1 mrg if (s !is null)
9298 1.1 mrg {
9299 1.1 mrg s.addComment(combineComments(blockComment, token.lineComment, true));
9300 1.1 mrg token.lineComment = null;
9301 1.1 mrg }
9302 1.1 mrg }
9303 1.1 mrg
9304 1.1 mrg /**********************************************
9305 1.1 mrg * Recognize builtin @ attributes
9306 1.1 mrg * Params:
9307 1.1 mrg * ident = identifier
9308 1.1 mrg * Returns:
9309 1.1 mrg * storage class for attribute, 0 if not
9310 1.1 mrg */
9311 1.1 mrg static StorageClass isBuiltinAtAttribute(Identifier ident)
9312 1.1 mrg {
9313 1.1 mrg return (ident == Id.property) ? STC.property :
9314 1.1 mrg (ident == Id.nogc) ? STC.nogc :
9315 1.1 mrg (ident == Id.safe) ? STC.safe :
9316 1.1 mrg (ident == Id.trusted) ? STC.trusted :
9317 1.1 mrg (ident == Id.system) ? STC.system :
9318 1.1 mrg (ident == Id.live) ? STC.live :
9319 1.1 mrg (ident == Id.future) ? STC.future :
9320 1.1 mrg (ident == Id.disable) ? STC.disable :
9321 1.1 mrg 0;
9322 1.1 mrg }
9323 1.1 mrg
9324 1.1 mrg enum StorageClass atAttrGroup =
9325 1.1 mrg STC.property |
9326 1.1 mrg STC.nogc |
9327 1.1 mrg STC.safe |
9328 1.1 mrg STC.trusted |
9329 1.1 mrg STC.system |
9330 1.1 mrg STC.live |
9331 1.1 mrg /*STC.future |*/ // probably should be included
9332 1.1 mrg STC.disable;
9333 1.1 mrg }
9334 1.1 mrg
9335 1.1 mrg enum PREC : int
9336 1.1 mrg {
9337 1.1 mrg zero,
9338 1.1 mrg expr,
9339 1.1 mrg assign,
9340 1.1 mrg cond,
9341 1.1 mrg oror,
9342 1.1 mrg andand,
9343 1.1 mrg or,
9344 1.1 mrg xor,
9345 1.1 mrg and,
9346 1.1 mrg equal,
9347 1.1 mrg rel,
9348 1.1 mrg shift,
9349 1.1 mrg add,
9350 1.1 mrg mul,
9351 1.1 mrg pow,
9352 1.1 mrg unary,
9353 1.1 mrg primary,
9354 1.1 mrg }
9355 1.1 mrg
9356 1.1 mrg /**********************************
9357 1.1 mrg * Set operator precedence for each operator.
9358 1.1 mrg *
9359 1.1 mrg * Used by hdrgen
9360 1.1 mrg */
9361 1.1 mrg immutable PREC[EXP.max + 1] precedence =
9362 1.1 mrg [
9363 1.1 mrg EXP.type : PREC.expr,
9364 1.1 mrg EXP.error : PREC.expr,
9365 1.1 mrg EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
9366 1.1 mrg
9367 1.1 mrg EXP.typeof_ : PREC.primary,
9368 1.1 mrg EXP.mixin_ : PREC.primary,
9369 1.1 mrg
9370 1.1 mrg EXP.import_ : PREC.primary,
9371 1.1 mrg EXP.dotVariable : PREC.primary,
9372 1.1 mrg EXP.scope_ : PREC.primary,
9373 1.1 mrg EXP.identifier : PREC.primary,
9374 1.1 mrg EXP.this_ : PREC.primary,
9375 1.1 mrg EXP.super_ : PREC.primary,
9376 1.1 mrg EXP.int64 : PREC.primary,
9377 1.1 mrg EXP.float64 : PREC.primary,
9378 1.1 mrg EXP.complex80 : PREC.primary,
9379 1.1 mrg EXP.null_ : PREC.primary,
9380 1.1 mrg EXP.string_ : PREC.primary,
9381 1.1 mrg EXP.arrayLiteral : PREC.primary,
9382 1.1 mrg EXP.assocArrayLiteral : PREC.primary,
9383 1.1 mrg EXP.classReference : PREC.primary,
9384 1.1 mrg EXP.file : PREC.primary,
9385 1.1 mrg EXP.fileFullPath : PREC.primary,
9386 1.1 mrg EXP.line : PREC.primary,
9387 1.1 mrg EXP.moduleString : PREC.primary,
9388 1.1 mrg EXP.functionString : PREC.primary,
9389 1.1 mrg EXP.prettyFunction : PREC.primary,
9390 1.1 mrg EXP.typeid_ : PREC.primary,
9391 1.1 mrg EXP.is_ : PREC.primary,
9392 1.1 mrg EXP.assert_ : PREC.primary,
9393 1.1 mrg EXP.halt : PREC.primary,
9394 1.1 mrg EXP.template_ : PREC.primary,
9395 1.1 mrg EXP.dSymbol : PREC.primary,
9396 1.1 mrg EXP.function_ : PREC.primary,
9397 1.1 mrg EXP.variable : PREC.primary,
9398 1.1 mrg EXP.symbolOffset : PREC.primary,
9399 1.1 mrg EXP.structLiteral : PREC.primary,
9400 1.1 mrg EXP.compoundLiteral : PREC.primary,
9401 1.1 mrg EXP.arrayLength : PREC.primary,
9402 1.1 mrg EXP.delegatePointer : PREC.primary,
9403 1.1 mrg EXP.delegateFunctionPointer : PREC.primary,
9404 1.1 mrg EXP.remove : PREC.primary,
9405 1.1 mrg EXP.tuple : PREC.primary,
9406 1.1 mrg EXP.traits : PREC.primary,
9407 1.1 mrg EXP.default_ : PREC.primary,
9408 1.1 mrg EXP.overloadSet : PREC.primary,
9409 1.1 mrg EXP.void_ : PREC.primary,
9410 1.1 mrg EXP.vectorArray : PREC.primary,
9411 1.1 mrg EXP._Generic : PREC.primary,
9412 1.1 mrg
9413 1.1 mrg // post
9414 1.1 mrg EXP.dotTemplateInstance : PREC.primary,
9415 1.1 mrg EXP.dotIdentifier : PREC.primary,
9416 1.1 mrg EXP.dotTemplateDeclaration : PREC.primary,
9417 1.1 mrg EXP.dot : PREC.primary,
9418 1.1 mrg EXP.dotType : PREC.primary,
9419 1.1 mrg EXP.plusPlus : PREC.primary,
9420 1.1 mrg EXP.minusMinus : PREC.primary,
9421 1.1 mrg EXP.prePlusPlus : PREC.primary,
9422 1.1 mrg EXP.preMinusMinus : PREC.primary,
9423 1.1 mrg EXP.call : PREC.primary,
9424 1.1 mrg EXP.slice : PREC.primary,
9425 1.1 mrg EXP.array : PREC.primary,
9426 1.1 mrg EXP.index : PREC.primary,
9427 1.1 mrg
9428 1.1 mrg EXP.delegate_ : PREC.unary,
9429 1.1 mrg EXP.address : PREC.unary,
9430 1.1 mrg EXP.star : PREC.unary,
9431 1.1 mrg EXP.negate : PREC.unary,
9432 1.1 mrg EXP.uadd : PREC.unary,
9433 1.1 mrg EXP.not : PREC.unary,
9434 1.1 mrg EXP.tilde : PREC.unary,
9435 1.1 mrg EXP.delete_ : PREC.unary,
9436 1.1 mrg EXP.new_ : PREC.unary,
9437 1.1 mrg EXP.newAnonymousClass : PREC.unary,
9438 1.1 mrg EXP.cast_ : PREC.unary,
9439 1.1 mrg EXP.throw_ : PREC.unary,
9440 1.1 mrg
9441 1.1 mrg EXP.vector : PREC.unary,
9442 1.1 mrg EXP.pow : PREC.pow,
9443 1.1 mrg
9444 1.1 mrg EXP.mul : PREC.mul,
9445 1.1 mrg EXP.div : PREC.mul,
9446 1.1 mrg EXP.mod : PREC.mul,
9447 1.1 mrg
9448 1.1 mrg EXP.add : PREC.add,
9449 1.1 mrg EXP.min : PREC.add,
9450 1.1 mrg EXP.concatenate : PREC.add,
9451 1.1 mrg
9452 1.1 mrg EXP.leftShift : PREC.shift,
9453 1.1 mrg EXP.rightShift : PREC.shift,
9454 1.1 mrg EXP.unsignedRightShift : PREC.shift,
9455 1.1 mrg
9456 1.1 mrg EXP.lessThan : PREC.rel,
9457 1.1 mrg EXP.lessOrEqual : PREC.rel,
9458 1.1 mrg EXP.greaterThan : PREC.rel,
9459 1.1 mrg EXP.greaterOrEqual : PREC.rel,
9460 1.1 mrg EXP.in_ : PREC.rel,
9461 1.1 mrg
9462 1.1 mrg /* Note that we changed precedence, so that < and != have the same
9463 1.1 mrg * precedence. This change is in the parser, too.
9464 1.1 mrg */
9465 1.1 mrg EXP.equal : PREC.rel,
9466 1.1 mrg EXP.notEqual : PREC.rel,
9467 1.1 mrg EXP.identity : PREC.rel,
9468 1.1 mrg EXP.notIdentity : PREC.rel,
9469 1.1 mrg
9470 1.1 mrg EXP.and : PREC.and,
9471 1.1 mrg EXP.xor : PREC.xor,
9472 1.1 mrg EXP.or : PREC.or,
9473 1.1 mrg
9474 1.1 mrg EXP.andAnd : PREC.andand,
9475 1.1 mrg EXP.orOr : PREC.oror,
9476 1.1 mrg
9477 1.1 mrg EXP.question : PREC.cond,
9478 1.1 mrg
9479 1.1 mrg EXP.assign : PREC.assign,
9480 1.1 mrg EXP.construct : PREC.assign,
9481 1.1 mrg EXP.blit : PREC.assign,
9482 1.1 mrg EXP.addAssign : PREC.assign,
9483 1.1 mrg EXP.minAssign : PREC.assign,
9484 1.1 mrg EXP.concatenateAssign : PREC.assign,
9485 1.1 mrg EXP.concatenateElemAssign : PREC.assign,
9486 1.1 mrg EXP.concatenateDcharAssign : PREC.assign,
9487 1.1 mrg EXP.mulAssign : PREC.assign,
9488 1.1 mrg EXP.divAssign : PREC.assign,
9489 1.1 mrg EXP.modAssign : PREC.assign,
9490 1.1 mrg EXP.powAssign : PREC.assign,
9491 1.1 mrg EXP.leftShiftAssign : PREC.assign,
9492 1.1 mrg EXP.rightShiftAssign : PREC.assign,
9493 1.1 mrg EXP.unsignedRightShiftAssign : PREC.assign,
9494 1.1 mrg EXP.andAssign : PREC.assign,
9495 1.1 mrg EXP.orAssign : PREC.assign,
9496 1.1 mrg EXP.xorAssign : PREC.assign,
9497 1.1 mrg
9498 1.1 mrg EXP.comma : PREC.expr,
9499 1.1 mrg EXP.declaration : PREC.expr,
9500 1.1 mrg
9501 1.1 mrg EXP.interval : PREC.assign,
9502 1.1 mrg ];
9503 1.1 mrg
9504 1.1 mrg enum ParseStatementFlags : int
9505 1.1 mrg {
9506 1.1 mrg semi = 1, // empty ';' statements are allowed, but deprecated
9507 1.1 mrg scope_ = 2, // start a new scope
9508 1.1 mrg curly = 4, // { } statement is required
9509 1.1 mrg curlyScope = 8, // { } starts a new scope
9510 1.1 mrg semiOk = 0x10, // empty ';' are really ok
9511 1.1 mrg }
9512 1.1 mrg
9513 1.1 mrg struct PrefixAttributes(AST)
9514 1.1 mrg {
9515 1.1 mrg StorageClass storageClass;
9516 1.1 mrg AST.Expression depmsg;
9517 1.1 mrg LINK link;
9518 1.1 mrg AST.Visibility visibility;
9519 1.1 mrg bool setAlignment;
9520 1.1 mrg AST.Expression ealign;
9521 1.1 mrg AST.Expressions* udas;
9522 1.1 mrg const(char)* comment;
9523 1.1 mrg }
9524 1.1 mrg
9525 1.1 mrg /// The result of the `ParseLinkage` function
9526 1.1 mrg struct ParsedLinkage(AST)
9527 1.1 mrg {
9528 1.1 mrg /// What linkage was specified
9529 1.1 mrg LINK link;
9530 1.1 mrg /// If `extern(C++, class|struct)`, contains the `class|struct`
9531 1.1 mrg CPPMANGLE cppmangle;
9532 1.1 mrg /// If `extern(C++, some.identifier)`, will be the identifiers
9533 1.1 mrg AST.Identifiers* idents;
9534 1.1 mrg /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
9535 1.1 mrg AST.Expressions* identExps;
9536 1.1 mrg }
9537 1.1 mrg
9538 1.1 mrg
9539 1.1 mrg /*********************************** Private *************************************/
9540 1.1 mrg
9541 1.1 mrg /***********************
9542 1.1 mrg * How multiple declarations are parsed.
9543 1.1 mrg * If 1, treat as C.
9544 1.1 mrg * If 0, treat:
9545 1.1 mrg * int *p, i;
9546 1.1 mrg * as:
9547 1.1 mrg * int* p;
9548 1.1 mrg * int* i;
9549 1.1 mrg */
9550 1.1 mrg private enum CDECLSYNTAX = 0;
9551 1.1 mrg
9552 1.1 mrg /*****
9553 1.1 mrg * Support C cast syntax:
9554 1.1 mrg * (type)(expression)
9555 1.1 mrg */
9556 1.1 mrg private enum CCASTSYNTAX = 1;
9557 1.1 mrg
9558 1.1 mrg /*****
9559 1.1 mrg * Support postfix C array declarations, such as
9560 1.1 mrg * int a[3][4];
9561 1.1 mrg */
9562 1.1 mrg private enum CARRAYDECL = 1;
9563 1.1 mrg
9564 1.1 mrg /*****************************
9565 1.1 mrg * Destructively extract storage class from pAttrs.
9566 1.1 mrg */
9567 1.1 mrg private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
9568 1.1 mrg {
9569 1.1 mrg StorageClass stc = STC.undefined_;
9570 1.1 mrg if (pAttrs)
9571 1.1 mrg {
9572 1.1 mrg stc = pAttrs.storageClass;
9573 1.1 mrg pAttrs.storageClass = STC.undefined_;
9574 1.1 mrg }
9575 1.1 mrg return stc;
9576 1.1 mrg }
9577 1.1 mrg
9578 1.1 mrg /**************************************
9579 1.1 mrg * dump mixin expansion to file for better debugging
9580 1.1 mrg */
9581 1.1 mrg private bool writeMixin(const(char)[] s, ref Loc loc)
9582 1.1 mrg {
9583 1.1 mrg if (!global.params.mixinOut)
9584 1.1 mrg return false;
9585 1.1 mrg
9586 1.1 mrg OutBuffer* ob = global.params.mixinOut;
9587 1.1 mrg
9588 1.1 mrg ob.writestring("// expansion at ");
9589 1.1 mrg ob.writestring(loc.toChars());
9590 1.1 mrg ob.writenl();
9591 1.1 mrg
9592 1.1 mrg global.params.mixinLines++;
9593 1.1 mrg
9594 1.1 mrg loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum);
9595 1.1 mrg
9596 1.1 mrg // write by line to create consistent line endings
9597 1.1 mrg size_t lastpos = 0;
9598 1.1 mrg for (size_t i = 0; i < s.length; ++i)
9599 1.1 mrg {
9600 1.1 mrg // detect LF and CRLF
9601 1.1 mrg const c = s[i];
9602 1.1 mrg if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
9603 1.1 mrg {
9604 1.1 mrg ob.writestring(s[lastpos .. i]);
9605 1.1 mrg ob.writenl();
9606 1.1 mrg global.params.mixinLines++;
9607 1.1 mrg if (c == '\r')
9608 1.1 mrg ++i;
9609 1.1 mrg lastpos = i + 1;
9610 1.1 mrg }
9611 1.1 mrg }
9612 1.1 mrg
9613 1.1 mrg if(lastpos < s.length)
9614 1.1 mrg ob.writestring(s[lastpos .. $]);
9615 1.1 mrg
9616 1.1 mrg if (s.length == 0 || s[$-1] != '\n')
9617 1.1 mrg {
9618 1.1 mrg ob.writenl(); // ensure empty line after expansion
9619 1.1 mrg global.params.mixinLines++;
9620 1.1 mrg }
9621 1.1 mrg ob.writenl();
9622 1.1 mrg global.params.mixinLines++;
9623 1.1 mrg
9624 1.1 mrg return true;
9625 1.1 mrg }
9626