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