1 /** 2 Copyright: Copyright (c) 2017-2019 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 /// Grammar 7 /// Lexer 8 /// Recursive descent parser 9 /// For expressions pratt parser is used 10 /// Copyright (c) 2017, Jean-Marc Bourguet 11 /// https://github.com/bourguet/operator_precedence_parsing/blob/86c11baa737673da521c9cb488fdc3b25d73f0b6/pratt_tdop_parser.py 12 module vox.fe.passes.parser; 13 14 import std.format : formattedWrite; 15 import std.string : format; 16 import std.range : repeat; 17 import std.stdio; 18 import std.conv : to; 19 20 import vox.all; 21 22 23 // Grammar 24 /** 25 <module> = <declaration>* EOF 26 <declaration> = <alias_decl> / <func_decl> / <var_decl> / <struct_decl> / <enum_decl> 27 28 <alias_decl> = "alias" <id> "=" <expr> ";" 29 <func_decl> = <type> <identifier> ("[" <template_args> "]")? "(" <param_list> ")" (<block_statement> / ';') 30 <param_list> = <parameter> "," <parameter_list> / <parameter>? 31 <parameter> = <type> <identifier>? 32 33 <var_decl> = <type> <identifier> ("=" <expression>)? ";" 34 <struct_decl> = "struct" <identifier> ("[" <template_args> "]")? "{" <declaration>* "}" 35 <enum_decl> = <enum_decl_single> / <enum_decl_multi> 36 <enum_decl_multi> = "enum" [<identifier>] [":" <type>] "{" (<identifier> ["=" <expr>] ",") * "}" 37 <enum_decl_single> = "enum" <identifier> [ "=" <expr> ] ";" 38 39 <statement> = "if" <paren_expression> <statement> ("else" <statement>)? 40 "while" <paren_expression> <statement> / 41 "do" <statement> "while" <paren_expression> ";" / 42 "return" <expression>? ";" / 43 "continue" ";" / 44 "break" ";" / 45 <block_statement> / 46 <expression> ("=" <expression>)? ";" / 47 <declaration_statement> 48 49 <declaration_statement> = <declaration> 50 <block_statement> = "{" <statement>* "}" 51 52 <expression> = <test> 53 <test> = <sum> | <sum> ("=="|"!="|"<"|">"|"<="|">=") <sum> 54 <sum> = <term> / <sum> ("+"|"-") <term> 55 <term> = <identifier> "(" <expression_list> ")" / <identifier> "[" <expression> "]" / <identifier> / <int_literal> / <string_literal> / <paren_expression> 56 <paren_expression> = "(" <expression> ")" 57 58 <expression_list> = (<expression> ",")* 59 <identifier> = [_a-zA-Z] [_a-zA-Z0-9]* 60 61 <type> = (<type_basic> / <type_struct>) <type_specializer>* 62 <type_specializer> = "*" / "[" <expression> "]" / "[" "]" / "function" "(" <param_list> ")" 63 <type_basic> = ("i8" | "i16" | "i32" | "i64" | 64 "u8" | "u16" | "u32" | "u64" | "void" | "f32" | "f64") 65 66 <type_struct> = <identifier> 67 68 <int_literal> = <literal_dec_int> / <literal_hex_int> / <literal_bin_int> 69 <literal_dec_int> = 0|[1-9][0-9_]* 70 <literal_hex_int> = ("0x"|"0X")[0-9A-Fa-f_]+ 71 <literal_bin_int> = ("0b"|"0B")[01_]+ 72 */ 73 74 void pass_parser(ref CompilationContext ctx, CompilePassPerModule[] subPasses) { 75 Parser parser = Parser(&ctx); 76 77 foreach (ref SourceFileInfo file; ctx.files.data) 78 { 79 parser.parseModule(file.mod, file.firstTokenIndex); 80 81 if (ctx.printAstFresh) { 82 writefln("// AST fresh `%s`", file.name); 83 print_ast(ctx.getAstNodeIndex(file.mod), &ctx, 2); 84 } 85 } 86 } 87 88 // Attribute stack has the following structure at runtime 89 // 90 // - uneffective attributes (0 or more) 91 // - broadcasted attributes (0 or more) 92 // - immediate attributes (0 or more) top of the stack 93 // 94 // when a new attribute is parsed it is added to the top of the attribute stack 95 // 96 struct BroadcastedAttribState 97 { 98 // Number of attributes on the top of `attributeStack`, but below immediate attributes, 99 // that will be applied to the next declaration 100 // after application they will remain on the stack 101 ushort numBroadcastedAttributes; 102 103 // one bit per attribute in BuiltinFlagAttrib set 104 // will be added to the next declaration 105 // and will remain until the end of the scope 106 ushort broadcastedFlagAttributes; 107 } 108 109 struct ImmediateAttribState 110 { 111 // Number of attributes on the top of `attributeStack`, that 112 // will be added to the next declaration 113 // and will be dropped from the stack 114 ushort numImmediateAttributes; 115 116 // one bit per attribute in BuiltinFlagAttrib set 117 // will be added to the next declaration 118 // and will be zeroed 119 ushort immediateFlagAttributes; 120 } 121 122 struct AttribState 123 { 124 BroadcastedAttribState broadcasted; 125 ImmediateAttribState immediate; 126 127 ushort numEffectiveAttributes() { return cast(ushort)(broadcasted.numBroadcastedAttributes + immediate.numImmediateAttributes); } 128 ushort effectiveFlagAttributes() { return broadcasted.broadcastedFlagAttributes | immediate.immediateFlagAttributes; } 129 130 bool isStaticDecl() { 131 return cast(bool)(effectiveFlagAttributes & BuiltinFlagAttrib.isStatic); 132 } 133 } 134 135 struct ScopeTempData 136 { 137 BroadcastedAttribState prevBroadcasted; 138 bool isNonScope; 139 } 140 141 //version = print_parse; 142 struct Parser 143 { 144 CompilationContext* context; 145 ModuleDeclNode* currentModule; 146 /// For member functions 147 /// module, struct or function 148 AstIndex declarationOwner; 149 ScopeIndex currentScopeIndex; 150 151 // Current token 152 Token tok; 153 154 // Saved to ScopeTempData on scope push/pop 155 AttribState attribState; 156 // Attributes affecting next declaration 157 AstNodes attributeStack; 158 159 // Allocates AttributeInfo in AST arena, so it will be before next AST node allocated. 160 // returns 0 or AstFlags.hasAttributes flag. Must be added to node flags. 161 ushort createAttributeInfo() { 162 ushort declFlags; 163 //writefln("%s %s", attribState.immediateFlagAttributes, attribState.broadcastedFlagAttributes); 164 if (attribState.isStaticDecl) { 165 declFlags |= AstFlags.isGlobal; 166 } else { 167 switch (declarationOwner.astType(context)) { 168 case AstType.decl_struct: 169 declFlags |= AstFlags.isMember; 170 break; 171 case AstType.decl_module: 172 declFlags |= AstFlags.isGlobal; 173 break; 174 default: break; 175 } 176 } 177 178 attribState.immediate.immediateFlagAttributes = 0; 179 180 if (attribState.numEffectiveAttributes == 0) return declFlags; 181 182 declFlags |= AstFlags.hasAttributes; 183 184 AstNodes attributes; 185 attributes.voidPut(context.arrayArena, attribState.numEffectiveAttributes); 186 uint attribFlags; 187 188 auto offset = attributeStack.length - attribState.numEffectiveAttributes; 189 foreach(i; 0..attribState.numEffectiveAttributes) { 190 AstIndex attrib = attributeStack[offset + i]; 191 attributes[i] = attrib; 192 attribFlags |= calcAttribFlags(attrib, context); 193 } 194 195 attributeStack.unput(attribState.immediate.numImmediateAttributes); 196 attribState.immediate.numImmediateAttributes = 0; 197 198 context.appendAst!AttributeInfo(attributes, attribFlags); 199 return declFlags; 200 } 201 202 SourceLocation loc() { 203 return context.tokenLocationBuffer[tok.index]; 204 } 205 206 int nesting; 207 auto indent(uint var) { return ' '.repeat(var*2); } 208 struct PrintScope { Parser* p; ~this(){--p.nesting;}} 209 PrintScope scop(Args...)(string name, Args args) { write(indent(nesting)); writefln(name, args); ++nesting; return PrintScope(&this); } 210 211 void nextToken() 212 { 213 do { 214 ++tok.index; 215 tok.type = context.tokenBuffer[tok.index]; 216 } 217 while (tok.type == TokenType.COMMENT); 218 } 219 220 void skipPast(TokenType tokType) 221 { 222 while (tok.type != TokenType.EOI) 223 { 224 ++tok.index; 225 tok.type = context.tokenBuffer[tok.index]; 226 if (tok.type == tokType) { 227 nextToken; 228 break; 229 } 230 } 231 } 232 233 bool hasMoreTokens() { 234 return tok.type != TokenType.EOI; 235 } 236 237 AstIndex make(T, Args...)(TokenIndex start, Args args) { 238 return context.appendAst!T(start, args); 239 } 240 // Will attach attributes if present 241 AstIndex makeDecl(T, Args...)(TokenIndex start, Args args) { 242 auto flags = createAttributeInfo; 243 AstIndex declIndex = context.appendAst!T(start, args); 244 if (flags) { 245 AstNode* declNode = context.getAstNode(declIndex); 246 declNode.flags |= flags; 247 } 248 return declIndex; 249 } 250 AstIndex makeExpr(T, Args...)(TokenIndex start, Args args) { 251 return context.appendAst!T(start, AstIndex.init, args); 252 } 253 254 void expect(TokenType type, string after = null) { 255 if (tok.type != type) { 256 const(char)[] tokenString = context.getTokenString(tok.index); 257 if (after) 258 context.unrecoverable_error(tok.index, "Expected `%s` after %s, while got `%s` token '%s'", 259 type, after, tok.type, tokenString); 260 else 261 context.unrecoverable_error(tok.index, "Expected `%s` token, while got `%s` token '%s'", 262 type, tok.type, tokenString); 263 } 264 } 265 266 void expectAndConsume(TokenType type, string after = null) { 267 expect(type, after); 268 nextToken; 269 } 270 271 Identifier makeIdentifier(TokenIndex index) 272 { 273 const(char)[] str = context.getTokenString(index); 274 return context.idMap.getOrReg(context, str); 275 } 276 277 Identifier expectIdentifier(string after = null) 278 { 279 TokenIndex index = tok.index; 280 expectAndConsume(TokenType.IDENTIFIER, after); 281 Identifier id = makeIdentifier(index); 282 return id; 283 } 284 285 // temp data is used instead of separate stack to push/pop 286 ScopeTempData pushScope(string name, ScopeKind kind) 287 { 288 ScopeTempData temp; 289 temp.prevBroadcasted = attribState.broadcasted; 290 291 context.assertf(attribState.immediate == ImmediateAttribState.init, 292 "No immediate attributes should remain before new scope"); 293 294 if (kind == ScopeKind.no_scope) 295 { 296 // no_scope scopes do not effectively introduce a new scope for attributes, nor for declarations/statements 297 temp.isNonScope = true; 298 299 // Outer effective attributes are effective inside no_scope scopes 300 attribState = AttribState(attribState.broadcasted); 301 } 302 else 303 { 304 // Outer attributes are not visible inside 305 attribState = AttribState.init; 306 307 ScopeIndex newScopeIndex = context.appendScope; 308 Scope* newScope = context.getAstScope(newScopeIndex); 309 newScope.debugName = name; 310 newScope.kind = kind; 311 newScope.owner = declarationOwner; 312 313 newScope.parentScope = currentScopeIndex; 314 currentScopeIndex = newScopeIndex; 315 } 316 317 return temp; 318 } 319 320 void popScope(ScopeTempData temp) 321 { 322 context.assertf(attribState.immediate == ImmediateAttribState.init, 323 "No immediate attributes should remain at the end of the scope"); 324 325 // How many attributes were introduced in the current scope compared to previous 326 ushort numScopeAttributes = 0; 327 if (attribState.broadcasted.numBroadcastedAttributes > temp.prevBroadcasted.numBroadcastedAttributes) 328 numScopeAttributes = cast(ushort)(attribState.broadcasted.numBroadcastedAttributes - temp.prevBroadcasted.numBroadcastedAttributes); 329 330 // mark the rest of effective nodes as broadcasted 331 auto offset = attributeStack.length - numScopeAttributes; 332 foreach(i; 0..numScopeAttributes) { 333 AstIndex attrib = attributeStack[offset + i]; 334 attrib.flags(context) |= AnyAttributeFlags.isBroadcasted; 335 } 336 337 // drop broadcasted attributes introduced by this scope at the end of the scope 338 attributeStack.unput(numScopeAttributes); 339 340 if (temp.isNonScope) 341 { 342 // no scope was introduced 343 } 344 else 345 { 346 currentScopeIndex = currentScopeIndex.get_scope(context).parentScope; 347 } 348 349 attribState = AttribState(temp.prevBroadcasted); 350 } 351 352 // ------------------------------ PARSING ---------------------------------- 353 354 void parseModule(ModuleDeclNode* mod, TokenIndex firstTokenIndex) { // <module> ::= <declaration>* 355 currentModule = mod; 356 scope(exit) currentModule = null; 357 358 version(print_parse) auto s1 = scop("parseModule"); 359 tok.index = firstTokenIndex; 360 tok.type = context.tokenBuffer[tok.index]; 361 expectAndConsume(TokenType.SOI); 362 mod.loc = tok.index; 363 mod.state = AstNodeState.name_register_self_done; 364 declarationOwner = context.getAstNodeIndex(mod); 365 366 ScopeTempData scope_temp = pushScope("Module", ScopeKind.global); 367 mod.memberScope = currentScopeIndex; 368 parse_module_decl(); 369 parse_declarations(mod.declarations, TokenType.EOI); 370 popScope(scope_temp); 371 } 372 373 void parse_declarations(ref AstNodes declarations, TokenType until) { // <declaration>* 374 while (tok.type != until) 375 { 376 if (tok.type == TokenType.EOI) break; 377 parse_declaration(declarations); 378 } 379 } 380 381 void parse_declaration(ref AstNodes items) // <declaration> ::= <func_declaration> / <var_declaration> / <struct_declaration> 382 { 383 version(print_parse) auto s1 = scop("parse_declaration %s", loc); 384 385 switch(tok.type) with(TokenType) 386 { 387 case ALIAS_SYM: // <alias_decl> ::= "alias" <id> "=" <expr> ";" 388 AstIndex declIndex = parse_alias(); 389 items.put(context.arrayArena, declIndex); 390 return; 391 case STRUCT_SYM, UNION_SYM: // <struct_declaration> ::= "struct" <id> "{" <declaration>* "}" 392 AstIndex declIndex = parse_struct(); 393 items.put(context.arrayArena, declIndex); 394 return; 395 case ENUM: 396 AstIndex declIndex = parse_enum(); 397 items.put(context.arrayArena, declIndex); 398 return; 399 case IMPORT_SYM: 400 AstIndex declIndex = parse_import(); 401 items.put(context.arrayArena, declIndex); 402 return; 403 case MODULE_SYM: 404 context.error(tok.index, "Module declaration can only occur as first declaration of the module"); 405 skipPast(TokenType.SEMICOLON); 406 AstIndex declIndex = context.getAstNodeIndex(currentModule); 407 items.put(context.arrayArena, declIndex); 408 return; 409 case HASH_IF, HASH_VERSION: 410 AstIndex declIndex = parse_hash_if(); 411 items.put(context.arrayArena, declIndex); 412 return; 413 case HASH_ASSERT: 414 AstIndex declIndex = parse_hash_assert(); 415 items.put(context.arrayArena, declIndex); 416 return; 417 case HASH_FOREACH: 418 AstIndex declIndex = parse_hash_foreach(); 419 items.put(context.arrayArena, declIndex); 420 return; 421 case AT: 422 parse_attribute(items); 423 return; 424 case TYPE_AUTO: 425 parse_auto_decl(items); 426 return; 427 default: // <func_declaration> / <var_declaration> 428 TokenIndex start = tok.index; 429 AstIndex body_start = AstIndex(context.astBuffer.uintLength); 430 AstIndex typeIndex = expr(PreferType.yes, 0); 431 AstIndex nodeIndex = parse_var_func_declaration_after_type(start, body_start, typeIndex, ConsumeTerminator.yes, TokenType.SEMICOLON); 432 AstIndex declIndex = nodeIndex; 433 items.put(context.arrayArena, declIndex); 434 return; 435 } 436 assert(false); 437 } 438 439 void parse_single_attribute(TokenIndex start) 440 { 441 Identifier attributeId = expectIdentifier("@"); 442 443 switch(attributeId.index) { 444 case CommonIds.id_extern.index: 445 parse_extern_attribute(start); 446 break; 447 case CommonIds.id_static.index: 448 attribState.immediate.immediateFlagAttributes |= BuiltinFlagAttrib.isStatic; 449 break; 450 default: 451 context.unrecoverable_error(start, "Unknown built-in attribute `%s`", context.idString(attributeId)); 452 } 453 } 454 455 // parses all attributes and one or more declarations that it is attached too 456 void parse_attribute(ref AstNodes declarations) 457 { 458 while(true) 459 { 460 TokenIndex start = tok.index; 461 nextToken; // skip @ 462 parse_single_attribute(start); 463 464 switch(tok.type) 465 { 466 case TokenType.AT: 467 break; // next attribute 468 case TokenType.COLON: 469 nextToken; // skip : 470 // Mark all immediate attributes as scoped attributes. 471 // They will be effective until the end of current scope, then the will be popped by popScope 472 attribState.broadcasted.numBroadcastedAttributes += attribState.immediate.numImmediateAttributes; 473 attribState.immediate.numImmediateAttributes = 0; 474 // Mark all immediate flag attributes as scoped attributes. 475 attribState.broadcasted.broadcastedFlagAttributes |= attribState.immediate.immediateFlagAttributes; 476 attribState.immediate.immediateFlagAttributes = 0; 477 // next comes another attribute or declaration 478 if (tok.type == TokenType.AT) break; // next attribute 479 return; // back to declaration/statement parsing 480 case TokenType.LCURLY: 481 nextToken; // skip { 482 // all attributes before {} will be applied to all declarations in {} 483 // attributes before {} are initially classified as immediate 484 // Remove them, and then move them into the scope 485 // @attr1 @attr2 { // number of attributes == numImmediateAttributes 486 // decl1; 487 // decl2; 488 // } 489 // is the same as: 490 // { 491 // @attr1 @attr2: 492 // decl1; 493 // decl2; 494 // } 495 496 // number of attributes 497 ushort numImmediateAttributes = attribState.immediate.numImmediateAttributes; 498 // save immediate flag attributes 499 auto immediateFlagAttributes = attribState.immediate.immediateFlagAttributes; 500 501 // remove attributes from current scope 502 attribState.immediate.numImmediateAttributes = 0; 503 504 // remove flag attributes from current scope 505 attribState.immediate.immediateFlagAttributes = 0; 506 507 // enter the scope 508 ScopeTempData scope_temp = pushScope("@{}", ScopeKind.no_scope); 509 510 // restore flag attributes, but now they are in the nested scope 511 attribState.immediate.immediateFlagAttributes = immediateFlagAttributes; 512 513 // add them as @: attributes 514 attribState.broadcasted.numBroadcastedAttributes += numImmediateAttributes; 515 516 // declarations 517 parse_declarations(declarations, TokenType.RCURLY); 518 519 // @: attributes are cleared by the scope end inside popScope 520 popScope(scope_temp); 521 522 expectAndConsume(TokenType.RCURLY, "@{"); 523 return; 524 default: 525 parse_declaration(declarations); 526 return; 527 } 528 } 529 } 530 531 void parse_extern_attribute(TokenIndex start) 532 { 533 expectAndConsume(TokenType.LPAREN, "@extern"); 534 535 Identifier externKindId; 536 if (tok.type == TokenType.MODULE_SYM) { 537 externKindId = CommonIds.id_module; 538 expectAndConsume(TokenType.MODULE_SYM, "@extern("); 539 } else { 540 externKindId = expectIdentifier("@extern("); 541 } 542 543 AstIndex attribute; 544 switch(externKindId.index) { 545 case CommonIds.id_syscall.index: 546 expectAndConsume(TokenType.COMMA, "@extern(syscall"); 547 expect(TT.INT_DEC_LITERAL, "@extern(syscall,"); 548 string value = cast(string)context.getTokenString(tok.index); 549 import std.algorithm.iteration : filter; 550 uint syscallNumber = value.filter!(c => c != '_').to!uint; 551 nextToken; // skip integer 552 attribute = make!BuiltinAttribNode(start, BuiltinAttribSubType.extern_syscall, syscallNumber); 553 break; 554 case CommonIds.id_module.index: 555 expectAndConsume(TokenType.COMMA, "@extern(module"); 556 expect(TT.STRING_LITERAL, "@extern(module,"); 557 string value = cast(string)context.getTokenString(tok.index); 558 nextToken; // skip lib name 559 Identifier moduleId = context.idMap.getOrReg(context, value[1..$-1]); 560 attribute = make!BuiltinAttribNode(start, BuiltinAttribSubType.extern_module, moduleId.index); 561 break; 562 default: 563 context.unrecoverable_error(start, "Unknown @extern kind `%s`", context.idString(externKindId)); 564 } 565 566 expectAndConsume(TokenType.RPAREN, "@extern(..."); 567 ++attribState.immediate.numImmediateAttributes; 568 attributeStack.put(context.arrayArena, attribute); 569 } 570 571 /// <alias_decl> ::= "alias" <id> "=" <expr> ";" 572 AstIndex parse_alias() 573 { 574 TokenIndex start = tok.index; 575 nextToken; // skip "alias" 576 577 Identifier aliasId = expectIdentifier(); 578 expectAndConsume(TokenType.EQUAL); 579 580 AstIndex initializerIndex = expr(PreferType.no); 581 expectAndConsume(TokenType.SEMICOLON); 582 583 return makeDecl!AliasDeclNode(start, currentScopeIndex, aliasId, initializerIndex); 584 } 585 586 /// Parses expression preferring types, if identifier follows, parses as var/func declaration 587 AstIndex parse_expr_or_id_decl(ConsumeTerminator consume_terminator, TokenType var_terminator = TokenType.init) 588 { 589 TokenIndex start = tok.index; 590 AstIndex body_start = AstIndex(context.astBuffer.uintLength); 591 AstIndex expr_or_type = expr(PreferType.yes); 592 593 if (tok.type == TokenType.IDENTIFIER) 594 { 595 // declaration 596 return parse_var_func_declaration_after_type(start, body_start, expr_or_type, consume_terminator, var_terminator); 597 } 598 else 599 { 600 // expression 601 AstNode* statementNode = context.getAstNode(expr_or_type); 602 if (consume_terminator) expectAndConsume(var_terminator); 603 return expr_or_type; 604 } 605 } 606 607 enum ConsumeTerminator : bool { no, yes } 608 609 bool canBeType(AstIndex someExpr) 610 { 611 switch(someExpr.astType(context)) with(AstType) 612 { 613 case type_basic, type_ptr, type_static_array, type_slice, type_func_sig: 614 case expr_name_use, expr_member, expr_index, expr_slice: 615 return true; 616 default: 617 return false; 618 } 619 } 620 621 AstIndex parse_var_func_declaration_after_type(TokenIndex start, AstIndex body_start, AstIndex typeIndex, ConsumeTerminator consume_terminator, TokenType var_terminator) 622 { 623 version(print_parse) auto s2 = scop("<func_declaration> / <var_declaration> %s", start); 624 625 TokenIndex idPos = tok.index; 626 Identifier declarationId = expectIdentifier(); 627 628 if (!canBeType(typeIndex)) 629 { 630 context.error(idPos, 631 "Invalid expression. Missing `;` before `%s`", context.idString(declarationId)); 632 } 633 634 AstIndex initializerIndex; 635 if (tok.type == TokenType.EQUAL) // "=" <expression> 636 { 637 // <var_decl> = <type> <identifier> ("=" <expression>)? ";" 638 nextToken; // skip "=" 639 initializerIndex = expr(PreferType.no); 640 } 641 642 if (tok.type == TokenType.SEMICOLON || tok.type == TokenType.COMMA) // <var_declaration> ::= <type> <id> (";" / ",") 643 { 644 // variable 645 version(print_parse) auto s3 = scop("<var_declaration> %s", start); 646 if (consume_terminator) expectAndConsume(var_terminator); 647 // leave ";" or "," for parent to decide 648 AstIndex varIndex = makeDecl!VariableDeclNode(idPos, currentScopeIndex, typeIndex, initializerIndex, declarationId); 649 return varIndex; 650 } 651 else if (tok.type == TokenType.LBRACKET) // <func_declaration> ::= <type> <id> "[" <template_params> "]" "(" <param_list> ")" (<block_statement> / ';') 652 { 653 // templated function 654 AstNodes template_params; 655 ushort numParamsBeforeVariadic; 656 parse_template_parameters(template_params, numParamsBeforeVariadic); 657 AstIndex body = parse_func(idPos, typeIndex, declarationId); 658 AstIndex after_body = AstIndex(context.astBuffer.uintLength); 659 return makeDecl!TemplateDeclNode(idPos, currentScopeIndex, template_params, body, body_start, after_body, declarationId, numParamsBeforeVariadic); 660 } 661 else if (tok.type == TokenType.LPAREN) // <func_declaration> ::= <type> <id> "(" <param_list> ")" (<block_statement> / ';') 662 { 663 // function 664 return parse_func(idPos, typeIndex, declarationId); 665 } 666 else 667 { 668 context.unrecoverable_error(tok.index, "Expected '(' or ';', while got '%s'", context.getTokenString(tok.index)); 669 } 670 } 671 672 AstIndex parse_func(TokenIndex start, AstIndex typeIndex, Identifier declarationId) 673 { 674 version(print_parse) auto s3 = scop("<func_declaration> %s", start); 675 AstNodes params; 676 ushort funcFlags; 677 678 // make all attributes apply to both function and the signature 679 auto beforeAttribState = attribState; 680 681 // make all attributes broadcasted, so that they are not removed when function is created 682 attribState.broadcasted.numBroadcastedAttributes += attribState.immediate.numImmediateAttributes; 683 attribState.immediate.numImmediateAttributes = 0; 684 attribState.broadcasted.broadcastedFlagAttributes |= attribState.immediate.immediateFlagAttributes; 685 attribState.immediate.immediateFlagAttributes = 0; 686 687 AstIndex funcIndex = makeDecl!FunctionDeclNode(start, context.getAstNodeIndex(currentModule), ScopeIndex(), AstIndex(), declarationId); 688 auto func = funcIndex.get!FunctionDeclNode(context); 689 690 // no attributes go to the function body or to the parameters 691 attribState = AttribState.init; 692 693 AstIndex prevOwner = declarationOwner; 694 declarationOwner = funcIndex; 695 scope(exit) declarationOwner = prevOwner; 696 697 ScopeTempData scope_temp = pushScope(context.idString(declarationId), ScopeKind.local); 698 scope(exit) popScope(scope_temp); 699 700 // set scope for a function 701 ScopeIndex parameterScope = currentScopeIndex; 702 func.parameterScope = parameterScope; 703 704 // add this pointer parameter 705 if (func.isMember) 706 { 707 AstIndex structName = make!NameUseExprNode(start, currentScopeIndex, prevOwner.get!StructDeclNode(context).id); 708 NameUseExprNode* name = structName.get_name_use(context); 709 name.resolve(prevOwner, context); 710 name.flags |= AstFlags.isType; 711 name.state = AstNodeState.name_resolve_done; 712 AstIndex thisType = make!PtrTypeNode(start, CommonAstNodes.type_type, structName); 713 714 // parameter 715 AstIndex param = make!VariableDeclNode(start, currentScopeIndex, thisType, AstIndex.init, CommonIds.id_this, ushort(0)); 716 VariableDeclNode* paramNode = param.get!VariableDeclNode(context); 717 paramNode.flags |= VariableFlags.isParameter; 718 params.put(context.arrayArena, param); 719 } 720 721 // restore attributes for signature to consume 722 attribState = beforeAttribState; 723 724 CallConvention callConvention = context.defaultCallConvention; 725 AstIndex signature = makeDecl!FunctionSignatureNode(start, typeIndex, params, callConvention); 726 727 // store remaining state back 728 scope_temp.prevBroadcasted = attribState.broadcasted; 729 // no attributes go to the parameters and body 730 attribState = AttribState.init; 731 732 parseParameters(signature, NeedRegNames.yes); // functions need to register their param names 733 func.signature = signature; 734 735 currentScopeIndex.get_scope(context).owner = funcIndex; 736 737 if (tok.type == TokenType.HASH_INLINE) 738 { 739 nextToken; // skip #inline 740 func.flags |= FuncDeclFlags.isInline; 741 } 742 743 if (tok.type != TokenType.SEMICOLON) 744 { 745 func.block_stmt = block_stmt(); 746 signature.flags(context) |= FuncSignatureFlags.attachedToFunctionWithBody; 747 } 748 else expectAndConsume(TokenType.SEMICOLON); // external function 749 750 return funcIndex; 751 } 752 753 enum NeedRegNames : bool { no, yes } 754 // if nameReg is `no` parameters are put in name_register_done state 755 void parseParameters(AstIndex signature, NeedRegNames nameReg) 756 { 757 auto sig = signature.get!FunctionSignatureNode(context); 758 expectAndConsume(TokenType.LPAREN); 759 760 ubyte numDefaultArgs = 0; 761 while (tok.type != TokenType.RPAREN) 762 { 763 if (tok.type == TokenType.EOI) break; 764 765 // <param> ::= <type> <identifier>? 766 TokenIndex paramStart = tok.index; 767 AstIndex paramType = expr(PreferType.yes, 0); 768 Identifier paramId; 769 ushort flags = VariableFlags.isParameter; 770 size_t paramIndex = sig.parameters.length; 771 AstIndex defaultValue; 772 773 if (tok.type == TokenType.DOT_DOT_DOT) // expanded type 774 { 775 if (sig.hasExpandedParam) { 776 context.error(tok.index, "Cannot have two expanded parameters"); 777 } 778 nextToken; // skip ... 779 flags |= VariableFlags.isVariadicParam; 780 sig.flags |= FuncSignatureFlags.hasExpandedParam; 781 sig.numParamsBeforeVariadic = cast(ushort)paramIndex; 782 } 783 784 if (tok.type == TokenType.IDENTIFIER) // named parameter 785 { 786 paramStart = tok.index; 787 paramId = expectIdentifier(); 788 } 789 else // anon parameter 790 { 791 flags |= VariableFlags.isAnonymous; 792 paramId = context.idMap.getOrRegFormatted(context, "__param_%s", paramIndex); 793 } 794 795 // default argument 796 if (tok.type == TokenType.EQUAL) 797 { 798 nextToken; // skip = 799 defaultValue = expr(PreferType.yes, 0); 800 801 ++sig.numDefaultArgs; 802 } 803 else 804 { 805 // all default arguments must be at the end of param list 806 if (sig.numDefaultArgs != 0) 807 context.error(paramStart, 808 "Default argument expected for %s", context.idString(paramId)); 809 } 810 811 AstIndex param = makeDecl!VariableDeclNode(paramStart, currentScopeIndex, paramType, defaultValue, paramId); 812 VariableDeclNode* paramNode = param.get!VariableDeclNode(context); 813 if (paramNode.isGlobal) context.error(paramNode.loc, "Parameters cannot be @static"); 814 paramNode.flags |= flags; 815 paramNode.scopeIndex = cast(typeof(paramNode.scopeIndex))paramIndex; 816 if (nameReg == NeedRegNames.no) 817 paramNode.state = AstNodeState.name_register_nested_done; 818 819 sig.parameters.put(context.arrayArena, param); 820 if (tok.type == TokenType.COMMA) nextToken; // skip "," 821 else break; 822 } 823 if (!sig.hasExpandedParam) 824 sig.numParamsBeforeVariadic = cast(ushort)sig.parameters.length; 825 826 expectAndConsume(TokenType.RPAREN); 827 } 828 829 // 0+ non-variadic params, ? variadic params 830 void parse_template_parameters(ref AstNodes params, out ushort numParamsBeforeVariadic) 831 { 832 expectAndConsume(TokenType.LBRACKET); 833 834 bool hasVaridic = false; 835 while (tok.type != TokenType.RBRACKET) 836 { 837 if (tok.type == TokenType.EOI) break; 838 839 // <type_param> ::= <identifier> 840 TokenIndex paramStart = tok.index; 841 Identifier paramId = expectIdentifier(); 842 ushort paramIndex = cast(ushort)params.length; 843 844 AstIndex param = makeDecl!TemplateParamDeclNode(paramStart, paramId, paramIndex); 845 if (tok.type == TokenType.DOT_DOT_DOT) { 846 nextToken; // skip "..." 847 param.flags(context) |= TemplateParamDeclFlags.isVariadic; 848 if (hasVaridic) { 849 context.error(param.loc(context), 850 "Only single variadic template parameter allowed"); 851 } 852 hasVaridic = true; 853 numParamsBeforeVariadic = paramIndex; 854 } 855 else 856 { 857 // In the future we may allow non-variadic template params after variadic one 858 if (hasVaridic) 859 context.error(param.loc(context), 860 "Cannot have template parameters after variadic parameter (WIP)"); 861 } 862 863 params.put(context.arrayArena, param); 864 865 if (tok.type == TokenType.COMMA) nextToken; // skip "," 866 else break; 867 } 868 869 if (!hasVaridic) numParamsBeforeVariadic = cast(ushort)params.length; 870 871 expectAndConsume(TokenType.RBRACKET); 872 } 873 874 ushort parse_argument_list(ref AstNodes expressions) 875 { 876 ushort flags; 877 // COMMA_PREC is used in `expr` because we don't want to grab the comma, e.g. it is NOT a sequence operator. 878 while (tok.type != TokenType.RPAREN) 879 { 880 AstIndex exprIndex; 881 if (tok.type == TokenType.IDENTIFIER) 882 { 883 Token idToken = tok; 884 nextToken; // skip id 885 if (tok.type == TokenType.COLON) 886 { 887 flags |= CallExprFlags.hasNamedArgs; 888 // named argument 889 nextToken; // skip : 890 Identifier paramId = makeIdentifier(idToken.index); 891 AstIndex child = expr(PreferType.no, COMMA_PREC); 892 exprIndex = make!NamedArgumenExprNode(idToken.index, paramId, child); 893 } 894 else 895 { 896 // regular expression, undo identifier 897 tok = idToken; 898 exprIndex = expr(PreferType.no, COMMA_PREC); 899 } 900 } 901 else 902 { 903 exprIndex = expr(PreferType.no, COMMA_PREC); 904 } 905 expressions.put(context.arrayArena, exprIndex); 906 907 // allows trailing comma too 908 if (tok.type == TokenType.COMMA) 909 nextToken; 910 } 911 expectAndConsume(TokenType.RPAREN); 912 return flags; 913 } 914 915 // <struct_declaration> ::= "struct" <id> ("[" <template_params> "]")? "{" <declaration>* "}" / 916 // "struct" <id> ("[" <template_params> "]")? ";" 917 AstIndex parse_struct() 918 { 919 ushort structFlags; 920 if (tok.type == TokenType.UNION_SYM) { 921 structFlags |= StructFlags.isUnion; 922 } 923 924 TokenIndex start = tok.index; 925 AstIndex body_start = AstIndex(context.astBuffer.uintLength); 926 927 version(print_parse) auto s2 = scop("struct %s", start); 928 nextToken; // skip "struct" 929 Identifier structId = expectIdentifier(); 930 931 AstIndex parse_rest() 932 { 933 if (tok.type == TokenType.SEMICOLON) 934 { 935 nextToken; // skip semicolon 936 AstIndex structIndex = makeDecl!StructDeclNode(start, currentScopeIndex, ScopeIndex(), structId); 937 StructDeclNode* s = structIndex.get!StructDeclNode(context); 938 s.flags |= structFlags | StructFlags.isOpaque; 939 return structIndex; 940 } 941 942 AstIndex structIndex = makeDecl!StructDeclNode(start, currentScopeIndex, ScopeIndex(), structId); 943 StructDeclNode* s = structIndex.get!StructDeclNode(context); 944 s.flags |= structFlags; 945 946 ScopeTempData scope_temp = pushScope(context.idString(structId), ScopeKind.member); 947 scope(exit) popScope(scope_temp); 948 949 s.memberScope = currentScopeIndex; 950 951 // no attributes go to the body 952 attribState = AttribState.init; 953 954 expectAndConsume(TokenType.LCURLY); 955 { 956 AstIndex prevOwner = declarationOwner; 957 declarationOwner = structIndex; 958 scope(exit) declarationOwner = prevOwner; 959 960 parse_declarations(s.declarations, TokenType.RCURLY); 961 962 ushort varIndex = 0; 963 foreach(AstIndex declIndex; s.declarations) { 964 AstNode* declNode = context.getAstNode(declIndex); 965 if (declNode.astType == AstType.decl_var) { 966 declNode.as!VariableDeclNode(context).scopeIndex = varIndex++; 967 } 968 } 969 } 970 expectAndConsume(TokenType.RCURLY); 971 972 return structIndex; 973 } 974 975 AstNodes template_params; 976 if (tok.type == TokenType.LBRACKET) // <func_declaration> ::= "struct" <id> "[" <template_params> "]" 977 { 978 ushort numParamsBeforeVariadic; 979 parse_template_parameters(template_params, numParamsBeforeVariadic); 980 AstIndex body = parse_rest(); 981 AstIndex after_body = AstIndex(context.astBuffer.uintLength); 982 return makeDecl!TemplateDeclNode(start, currentScopeIndex, template_params, body, body_start, after_body, structId, numParamsBeforeVariadic); 983 } 984 985 return parse_rest(); 986 } 987 988 // <enum_decl> = <enum_decl_single> / <enum_decl_multi> 989 // <enum_decl_multi> = "enum" [<identifier>] [":" <type>] {" <identifier> ["=" <expr>] ,* "}" 990 // <enum_decl_single> = "enum" <identifier> [ "=" <expr> ] ";" 991 992 // enum i32 e2; // manifest constant, invalid, need initializer 993 // enum e3 = 3; // manifest constant 994 // enum i32 e4 = 4; // manifest constant 995 996 // enum { e5 } // anon type 997 // enum : i32 { e6 } // anon type 998 999 // enum e1; // type 1000 // enum e7 : i32 { e7 } // type 1001 // enum e8 : i32; // type, body omitted 1002 // enum e9 { e9 } // type 1003 AstIndex parse_enum() 1004 { 1005 TokenIndex start = tok.index; 1006 nextToken; // slip `enum` 1007 1008 AstIndex intType = CommonAstNodes.type_i32; 1009 1010 AstIndex parseColonType() 1011 { 1012 nextToken; // skip ":" 1013 AstIndex type = expr(PreferType.yes, 0); 1014 if (!type) 1015 context.unrecoverable_error(tok.index, 1016 "Expected type after `enum :`, while got `%s`", context.getTokenString(tok.index)); 1017 1018 return type; 1019 } 1020 1021 AstNodes tryParseEnumBody(AstIndex type) 1022 { 1023 if (tok.type == TokenType.SEMICOLON) { 1024 nextToken; // skip ";" 1025 return AstNodes(); 1026 } else if (tok.type == TokenType.LCURLY) { 1027 return parse_enum_body(type); 1028 } else { 1029 context.unrecoverable_error(tok.index, 1030 "Expected `;` or `{` at the end of enum declaration, while got `%s`", 1031 context.getTokenString(tok.index)); 1032 } 1033 } 1034 1035 // enum T e4 = initializer; 1036 AstIndex parseTypeEnum() 1037 { 1038 AstIndex type = expr(PreferType.yes, 0); 1039 if (!type) 1040 context.unrecoverable_error(tok.index, 1041 "Expected type after `enum`, while got `%s`", 1042 context.getTokenString(tok.index)); 1043 1044 Identifier enumId = expectIdentifier; 1045 expectAndConsume(TokenType.EQUAL); // "=" 1046 AstIndex value = expr(PreferType.no); // initializer 1047 1048 auto member = makeDecl!EnumMemberDecl(start, currentScopeIndex, type, value, enumId); 1049 1050 expectAndConsume(TokenType.SEMICOLON); // ";" 1051 1052 // enum i32 e4 = 4; 1053 return member; 1054 } 1055 1056 // can be both enum identifier and type identifier 1057 if (tok.type == TokenType.IDENTIFIER) 1058 { 1059 Token copy = tok; // save 1060 TokenIndex id = tok.index; 1061 nextToken; // skip identifier 1062 1063 // enum type with no type or body 1064 // enum e1; 1065 if (tok.type == TokenType.SEMICOLON) 1066 { 1067 nextToken; // skip ";" 1068 Identifier enumId = makeIdentifier(id); 1069 ScopeIndex memberScope; // no scope 1070 1071 return makeDecl!EnumDeclaration(start, currentScopeIndex, memberScope, AstNodes(), intType, enumId); 1072 } 1073 else if (tok.type == TokenType.EQUAL) 1074 { 1075 nextToken; // skip "=" 1076 Identifier enumId = makeIdentifier(id); 1077 AstIndex value = expr(PreferType.no); 1078 // type will be taken from initializer 1079 auto member = make!EnumMemberDecl(start, currentScopeIndex, AstIndex.init, value, enumId); 1080 1081 expectAndConsume(TokenType.SEMICOLON); // ";" 1082 1083 // enum e3 = 3; 1084 return member; 1085 } 1086 // enum e7 : i32 ... 1087 else if (tok.type == TokenType.COLON) 1088 { 1089 Identifier enumId = makeIdentifier(id); 1090 AstIndex memberType = parseColonType; 1091 ScopeTempData scope_temp = pushScope(context.idString(enumId), ScopeKind.member); 1092 ScopeIndex memberScope = currentScopeIndex; 1093 AstIndex enumIndex = makeDecl!EnumDeclaration(start, ScopeIndex.init, memberScope, AstNodes.init, memberType, enumId); 1094 currentScopeIndex.get_scope(context).owner = enumIndex; 1095 auto enumNode = enumIndex.get!EnumDeclaration(context); 1096 AstNodes members = tryParseEnumBody(enumIndex); 1097 popScope(scope_temp); 1098 enumNode.declarations = members; 1099 enumNode.parentScope = currentScopeIndex; 1100 1101 // enum e7 : i32 { e7 } 1102 // enum e8 : i32; 1103 return enumIndex; 1104 } 1105 else if (tok.type == TokenType.LCURLY) 1106 { 1107 Identifier enumId = makeIdentifier(id); 1108 AstIndex memberType = intType; 1109 ScopeTempData scope_temp = pushScope(context.idString(enumId), ScopeKind.member); 1110 ScopeIndex memberScope = currentScopeIndex; 1111 AstIndex enumIndex = makeDecl!EnumDeclaration(start, ScopeIndex.init, memberScope, AstNodes.init, memberType, enumId); 1112 currentScopeIndex.get_scope(context).owner = enumIndex; 1113 auto enumNode = enumIndex.get!EnumDeclaration(context); 1114 AstNodes members = parse_enum_body(enumIndex); 1115 popScope(scope_temp); 1116 enumNode.declarations = members; 1117 enumNode.parentScope = currentScopeIndex; 1118 1119 // enum e9 { e9 } 1120 return enumIndex; 1121 } 1122 else 1123 { 1124 tok = copy; // restore 1125 return parseTypeEnum; 1126 } 1127 } 1128 else if (tok.type == TokenType.COLON) 1129 { 1130 AstIndex memberType = parseColonType; 1131 AstNodes members = parse_enum_body(memberType); 1132 ScopeIndex memberScope; // no scope 1133 1134 // enum : i32 { e6 } 1135 return makeDecl!EnumDeclaration(start, currentScopeIndex, memberScope, members, memberType); 1136 } 1137 else if (tok.type == TokenType.LCURLY) 1138 { 1139 AstIndex memberType = intType; 1140 AstNodes members = parse_enum_body(memberType); 1141 ScopeIndex memberScope; // no scope 1142 1143 // enum { e5 } 1144 return makeDecl!EnumDeclaration(start, currentScopeIndex, memberScope, members, memberType); 1145 } 1146 else if (isBasicTypeToken(tok.type)) 1147 { 1148 return parseTypeEnum; 1149 } 1150 else 1151 { 1152 context.unrecoverable_error(tok.index, 1153 "Invalid enum declaration, got %s after `enum`", 1154 context.getTokenString(tok.index)); 1155 } 1156 } 1157 1158 AstIndex parse_import() 1159 { 1160 TokenIndex start = tok.index; 1161 version(print_parse) auto s = scop("import %s", start); 1162 nextToken; // skip "import" 1163 Identifier id; 1164 1165 while (true) { 1166 string after = id.isDefined ? "import" : null; 1167 id = context.idMap.getOrRegFqn(context, FullyQualifiedName(id, expectIdentifier(after))); 1168 1169 if (tok.type == TokenType.DOT) { 1170 nextToken; // skip "." 1171 } else if (tok.type == TokenType.SEMICOLON) { 1172 nextToken; // skip ";" 1173 break; 1174 } else { 1175 context.unrecoverable_error(tok.index, 1176 "Expected `;` or `.` after identifier, while got `%s`", 1177 context.getTokenString(tok.index)); 1178 } 1179 } 1180 return makeDecl!ImportDeclNode(start, currentScopeIndex, id); 1181 } 1182 1183 void parse_module_decl() 1184 { 1185 TokenIndex start = tok.index; 1186 AstIndex parentPackage = CommonAstNodes.node_root_package; 1187 AstIndex conflictingModule; 1188 AstIndex conflictingModPack; 1189 1190 // module declaration 1191 if (tok.type == TokenType.MODULE_SYM) 1192 { 1193 nextToken; // skip "module" 1194 1195 Identifier lastId; 1196 while (true) { 1197 Identifier newId = expectIdentifier(); 1198 lastId = context.idMap.getOrRegFqn(context, FullyQualifiedName(lastId, newId)); 1199 1200 if (tok.type == TokenType.DOT) { 1201 nextToken; // skip "." 1202 auto parentPackageNode = parentPackage.get!PackageDeclNode(context); 1203 parentPackage = parentPackageNode.getOrCreateSubpackage(start, lastId, conflictingModule, context); 1204 } else if (tok.type == TokenType.SEMICOLON) { 1205 nextToken; // skip ";" 1206 currentModule.fqn = lastId; 1207 break; 1208 } else { 1209 context.unrecoverable_error(tok.index, 1210 "Expected `;` or `.` after identifier, while got `%s`", 1211 context.getTokenString(tok.index)); 1212 } 1213 } 1214 1215 currentModule.loc = start; 1216 } 1217 else 1218 { 1219 currentModule.loc = context.files[currentModule.moduleIndex.fileIndex].firstTokenIndex; 1220 } 1221 1222 currentModule.parentPackage = parentPackage; 1223 auto parentPackageNode = parentPackage.get!PackageDeclNode(context); 1224 parentPackageNode.addModule(start, currentModule.fqn, context.getAstNodeIndex(currentModule), conflictingModPack, context); 1225 context.modules.put(context.arrayArena, currentModule.fqn, context.getAstNodeIndex(currentModule)); 1226 void modConflict(ModuleDeclNode* newMod, ModuleDeclNode* oldMod) 1227 { 1228 context.error(newMod.loc, 1229 "Module `%s` in file %s conflicts with another module `%s` in file %s", 1230 newMod.fqn.pr(context), 1231 context.files[newMod.moduleIndex.fileIndex].name, 1232 oldMod.fqn.pr(context), 1233 context.files[oldMod.moduleIndex.fileIndex].name, ); 1234 } 1235 1236 void modPackConflict(ModuleDeclNode* newMod, PackageDeclNode* oldPack) 1237 { 1238 context.error(newMod.loc, 1239 "Module `%s` in file %s conflicts with package `%s` in files %s", 1240 newMod.fqn.pr(context), 1241 context.files[newMod.moduleIndex.fileIndex].name, 1242 oldPack.fqn.pr(context), 1243 PackageFilesPrinter(oldPack, context)); 1244 } 1245 1246 if (conflictingModule.isDefined) { 1247 modConflict(currentModule, conflictingModule.get!ModuleDeclNode(context)); 1248 } 1249 1250 if (conflictingModPack.isDefined) { 1251 AstNode* conflictingNode = conflictingModPack.get_node(context); 1252 if (conflictingNode.astType == AstType.decl_module) { 1253 modConflict(currentModule, conflictingNode.as!ModuleDeclNode(context)); 1254 // module foo from file bar.d conflicts with another module foo from file foo.d 1255 } else { 1256 context.assertf(conflictingNode.astType == AstType.decl_package, "Must be package"); 1257 modPackConflict(currentModule, conflictingNode.as!PackageDeclNode(context)); 1258 } 1259 } 1260 } 1261 1262 AstIndex parse_hash_assert() /* "#assert(" <condition>, <message> ");"*/ 1263 { 1264 TokenIndex start = tok.index; 1265 nextToken; // skip "#assert" 1266 1267 if (tok.type != TokenType.LPAREN) 1268 context.unrecoverable_error(tok.index, 1269 "Expected `(` after #assert, while got `%s`", 1270 context.getTokenString(tok.index)); 1271 nextToken; // skip ( 1272 1273 AstIndex condition = expr(PreferType.no); 1274 AstIndex message; 1275 1276 if (tok.type != TokenType.RPAREN) 1277 { 1278 if (tok.type != TokenType.COMMA) 1279 context.unrecoverable_error(tok.index, 1280 "Expected `,` after condition of #assert, while got `%s`", 1281 context.getTokenString(tok.index)); 1282 1283 nextToken; // skip , 1284 1285 message = expr(PreferType.no); 1286 } 1287 1288 if (tok.type != TokenType.RPAREN) 1289 context.unrecoverable_error(tok.index, 1290 "Expected `)` after message of #assert, while got `%s`", 1291 context.getTokenString(tok.index)); 1292 nextToken; // skip ) 1293 1294 if (tok.type != TokenType.SEMICOLON) 1295 context.unrecoverable_error(tok.index, 1296 "Expected `;` after #assert, while got `%s`", 1297 context.getTokenString(tok.index)); 1298 nextToken; // skip ; 1299 1300 return make!StaticAssertDeclNode(start, condition, message); 1301 } 1302 1303 void parseItems(alias itemParser)(ref AstNodes items, ScopeKind scopeKind) 1304 { 1305 TokenIndex start = tok.index; 1306 if (tok.type == TokenType.LCURLY) 1307 { 1308 nextToken; // skip { 1309 ScopeTempData scope_temp = pushScope(null, scopeKind); 1310 while (tok.type != TokenType.RCURLY) 1311 { 1312 if (tok.type == TokenType.EOI) break; 1313 itemParser(items); 1314 } 1315 popScope(scope_temp); 1316 expectAndConsume(TokenType.RCURLY); 1317 } 1318 else 1319 { 1320 itemParser(items); 1321 } 1322 } 1323 1324 void parseStaticIfThenElse(ref AstNodes thenStatements, ref AstNodes elseStatements) 1325 { 1326 if (declarationOwner.astType(context) == AstType.decl_function) 1327 { 1328 parseItems!statement(thenStatements, ScopeKind.no_scope); 1329 if (tok.type == TokenType.ELSE_SYM) { /* ... "else" <statement> */ 1330 nextToken; // skip else 1331 parseItems!statement(elseStatements, ScopeKind.no_scope); 1332 } 1333 } 1334 else 1335 { 1336 parseItems!parse_declaration(thenStatements, ScopeKind.no_scope); 1337 if (tok.type == TokenType.ELSE_SYM) { /* ... "else" <decl> */ 1338 nextToken; // skip else 1339 parseItems!parse_declaration(elseStatements, ScopeKind.no_scope); 1340 } 1341 } 1342 } 1343 1344 AstIndex parse_hash_if() /* "#if/#version" <paren_expr> <statement/decl> */ 1345 { 1346 TokenIndex start = tok.index; 1347 if (tok.type == TokenType.HASH_IF) 1348 { 1349 nextToken; // skip #if 1350 AstIndex condition = paren_expr(); 1351 AstNodes thenStatements; 1352 AstNodes elseStatements; 1353 parseStaticIfThenElse(thenStatements, elseStatements); 1354 return make!StaticIfDeclNode(start, AstIndex.init, AstIndex.init, 0, condition, thenStatements, elseStatements); 1355 } 1356 else 1357 { 1358 nextToken; // skip #version 1359 expectAndConsume(TokenType.LPAREN, "#version"); 1360 Identifier versionId = expectIdentifier("#version("); 1361 expectAndConsume(TokenType.RPAREN, "#version(id"); 1362 AstNodes thenStatements; 1363 AstNodes elseStatements; 1364 parseStaticIfThenElse(thenStatements, elseStatements); 1365 return make!StaticVersionDeclNode(start, AstIndex.init, AstIndex.init, 0, versionId, thenStatements, elseStatements); 1366 } 1367 } 1368 1369 AstIndex parse_hash_foreach() /* "#foreach" "(" [<index_id>], <val_id> ";" <ct_expr> ")" <statement> */ 1370 { 1371 TokenIndex start = tok.index; 1372 nextToken; // skip "#foreach" 1373 1374 expectAndConsume(TokenType.LPAREN); // ( 1375 1376 AstNodes init_statements; 1377 1378 // <init> 1379 Identifier keyId = expectIdentifier; 1380 Identifier valId; 1381 if (tok.type == TokenType.COMMA) 1382 { 1383 nextToken; // skip "," 1384 valId = expectIdentifier; 1385 expectAndConsume(TokenType.SEMICOLON); 1386 } 1387 else if (tok.type == TokenType.SEMICOLON) 1388 { 1389 valId = keyId; 1390 keyId = Identifier.init; 1391 expectAndConsume(TokenType.SEMICOLON); 1392 } 1393 else 1394 { 1395 context.unrecoverable_error(tok.index, 1396 "Expected `;` after key and value of #foreach, instead got `%s`", 1397 context.getTokenString(tok.index)); 1398 } 1399 1400 // <ct_expr> 1401 AstIndex ct_expr = expr(PreferType.no); 1402 expectAndConsume(TokenType.RPAREN); 1403 1404 AstIndex body_start = AstIndex(context.astBuffer.uintLength); 1405 AstNodes body; 1406 statement_as_array(body); 1407 AstIndex after_body = AstIndex(context.astBuffer.uintLength); 1408 return make!StaticForeachDeclNode(start, AstIndex.init, AstIndex.init, 0, currentScopeIndex, keyId, valId, ct_expr, body, body_start, after_body); 1409 } 1410 1411 AstNodes parse_enum_body(AstIndex type) { // { id [= val], ... } 1412 expectAndConsume(TokenType.LCURLY); 1413 AstNodes members; 1414 ushort varIndex = 0; 1415 while (tok.type != TokenType.RCURLY) 1416 { 1417 if (tok.type == TokenType.EOI) break; 1418 1419 TokenIndex start = tok.index; 1420 Identifier id = expectIdentifier; 1421 AstIndex value; 1422 1423 if (tok.type == TokenType.EQUAL) 1424 { 1425 nextToken; // skip "=" 1426 value = expr(PreferType.no); 1427 } 1428 1429 auto member = makeDecl!EnumMemberDecl(start, currentScopeIndex, type, value, id); 1430 EnumMemberDecl* memberNode = context.getAst!EnumMemberDecl(member); 1431 memberNode.scopeIndex = varIndex++; 1432 members.put(context.arrayArena, member); 1433 1434 if (tok.type == TokenType.COMMA) { 1435 nextToken; // skip "," 1436 } else break; 1437 } 1438 expectAndConsume(TokenType.RCURLY); 1439 return members; 1440 } 1441 1442 void parse_block(ref AstNodes statements) // "{" <statement>* "}" 1443 { 1444 expectAndConsume(TokenType.LCURLY); 1445 while (tok.type != TokenType.RCURLY) 1446 { 1447 if (tok.type == TokenType.EOI) break; 1448 statement(statements); 1449 } 1450 expectAndConsume(TokenType.RCURLY); 1451 } 1452 1453 AstIndex block_stmt() // <block_statement> ::= "{" <statement>* "}" 1454 { 1455 version(print_parse) auto s1 = scop("block_stmt %s", loc); 1456 TokenIndex start = tok.index; 1457 ScopeTempData scope_temp = pushScope("Block", ScopeKind.local); 1458 AstNodes statements; 1459 parse_block(statements); 1460 popScope(scope_temp); 1461 return make!BlockStmtNode(start, statements); 1462 } 1463 1464 void statement_as_array(ref AstNodes statements) 1465 { 1466 if (tok.type == TokenType.LCURLY) 1467 { 1468 parse_block(statements); 1469 } 1470 else 1471 { 1472 statement(statements); 1473 } 1474 } 1475 1476 void statement(ref AstNodes items) 1477 { 1478 version(print_parse) auto s1 = scop("statement %s", loc); 1479 TokenIndex start = tok.index; 1480 switch (tok.type) 1481 { 1482 // declarations 1483 case TokenType.ALIAS_SYM: 1484 items.put(context.arrayArena, parse_alias()); 1485 return; 1486 case TokenType.STRUCT_SYM, TokenType.UNION_SYM: 1487 items.put(context.arrayArena, parse_struct()); 1488 return; 1489 case TokenType.ENUM: 1490 items.put(context.arrayArena, parse_enum()); 1491 return; 1492 case TokenType.IMPORT_SYM: 1493 items.put(context.arrayArena, parse_import()); 1494 return; 1495 case TokenType.HASH_IF, TokenType.HASH_VERSION: 1496 items.put(context.arrayArena, parse_hash_if()); 1497 return; 1498 case TokenType.HASH_ASSERT: 1499 items.put(context.arrayArena, parse_hash_assert()); 1500 return; 1501 case TokenType.HASH_FOREACH: 1502 items.put(context.arrayArena, parse_hash_foreach()); 1503 return; 1504 1505 // statements 1506 case TokenType.IF_SYM: /* "if" <paren_expr> <statement> */ 1507 nextToken; 1508 AstIndex condition = paren_expr(); 1509 ScopeTempData scope_temp = pushScope("Then", ScopeKind.local); 1510 AstNodes thenStatements; 1511 statement_as_array(thenStatements); 1512 popScope(scope_temp); 1513 AstNodes elseStatements; 1514 if (tok.type == TokenType.ELSE_SYM) { /* ... "else" <statement> */ 1515 nextToken; 1516 ScopeTempData scope_temp2 = pushScope("Else", ScopeKind.local); 1517 statement_as_array(elseStatements); 1518 popScope(scope_temp2); 1519 } 1520 AstIndex stmt = make!IfStmtNode(start, condition, thenStatements, elseStatements); 1521 items.put(context.arrayArena, stmt); 1522 return; 1523 case TokenType.WHILE_SYM: /* "while" <paren_expr> <statement> */ 1524 nextToken; 1525 ScopeTempData scope_temp = pushScope("While", ScopeKind.local); 1526 AstIndex condition = paren_expr(); 1527 AstNodes statements; 1528 statement_as_array(statements); 1529 popScope(scope_temp); 1530 AstIndex stmt = make!WhileStmtNode(start, condition, statements); 1531 items.put(context.arrayArena, stmt); 1532 return; 1533 case TokenType.DO_SYM: /* "do" <statement> "while" <paren_expr> ";" */ 1534 nextToken; 1535 ScopeTempData scope_temp = pushScope("do", ScopeKind.local); 1536 AstNodes statements; 1537 statement_as_array(statements); 1538 expectAndConsume(TokenType.WHILE_SYM); 1539 AstIndex condition = paren_expr(); 1540 popScope(scope_temp); 1541 expectAndConsume(TokenType.SEMICOLON); 1542 AstIndex stmt = make!DoWhileStmtNode(start, condition, statements); 1543 items.put(context.arrayArena, stmt); 1544 return; 1545 case TokenType.FOR_SYM: /* "for" "(" <statement> ";" <statement> ";" "while" <paren_expr> ";" */ 1546 items.put(context.arrayArena, parse_for()); 1547 return; 1548 case TokenType.SWITCH_SYM: 1549 items.put(context.arrayArena, parse_switch()); 1550 return; 1551 case TokenType.RETURN_SYM: /* return <expr> */ 1552 nextToken; 1553 AstIndex expression = tok.type != TokenType.SEMICOLON ? expr(PreferType.no) : AstIndex.init; 1554 expectAndConsume(TokenType.SEMICOLON); 1555 context.assertf(declarationOwner.isDefined && declarationOwner.astType(context) == AstType.decl_function, start, "Return statement is not inside function"); 1556 AstIndex stmt = make!ReturnStmtNode(start, declarationOwner, expression); 1557 items.put(context.arrayArena, stmt); 1558 return; 1559 case TokenType.BREAK_SYM: /* break; */ 1560 nextToken; 1561 expectAndConsume(TokenType.SEMICOLON); 1562 AstIndex stmt = make!BreakStmtNode(start); 1563 items.put(context.arrayArena, stmt); 1564 return; 1565 case TokenType.CONTINUE_SYM: /* continue; */ 1566 nextToken; 1567 expectAndConsume(TokenType.SEMICOLON); 1568 AstIndex stmt = make!ContinueStmtNode(start); 1569 items.put(context.arrayArena, stmt); 1570 return; 1571 case TokenType.SEMICOLON: /* ";" */ 1572 context.error(tok.index, "Cannot use `;` as an empty statement. Use `{}` instead"); 1573 nextToken; 1574 return; 1575 case TokenType.LCURLY: /* "{" { <statement> } "}" */ 1576 items.put(context.arrayArena, block_stmt()); 1577 return; 1578 case TokenType.AT: 1579 parse_attribute(items); 1580 return; 1581 case TokenType.TYPE_AUTO: 1582 parse_auto_decl(items); 1583 return; 1584 default: 1585 { 1586 // expression or var/func declaration 1587 version(print_parse) auto s2 = scop("default %s", loc); 1588 // <expr> ";" / var decl / func decl 1589 AstIndex expression = parse_expr_or_id_decl(ConsumeTerminator.yes, TokenType.SEMICOLON); 1590 items.put(context.arrayArena, expression); 1591 return; 1592 } 1593 } 1594 } 1595 1596 void parse_auto_decl(ref AstNodes items) 1597 { 1598 TokenIndex start = tok.index; 1599 AstIndex body_start = AstIndex(context.astBuffer.uintLength); 1600 nextToken; // skip auto 1601 AstIndex declIndex = parse_var_func_declaration_after_type(start, body_start, CommonAstNodes.type_auto, ConsumeTerminator.yes, TokenType.SEMICOLON); 1602 AstNode* declNode = declIndex.get_node(context); 1603 switch(declNode.astType) 1604 { 1605 case AstType.decl_var: 1606 if (declNode.as!VariableDeclNode(context).initializer.isUndefined) { 1607 context.error(declNode.loc, "variables declared as `auto` must have an initializer"); 1608 } 1609 break; 1610 case AstType.decl_template: 1611 case AstType.decl_function: 1612 context.error(declNode.loc, "functions cannot return `auto`"); 1613 break; 1614 default: 1615 context.internal_error(declNode.loc, "auto declaration of %s", declNode.astType); 1616 } 1617 items.put(context.arrayArena, declIndex); 1618 } 1619 1620 AstIndex parse_for() // "for" "(" <init>,... ";" <cond> ";" <increment> ")" <statement> 1621 { 1622 TokenIndex start = tok.index; 1623 nextToken; // skip "for" 1624 1625 expectAndConsume(TokenType.LPAREN); // ( 1626 1627 ScopeTempData scope_temp = pushScope("For", ScopeKind.local); 1628 scope(exit) popScope(scope_temp); 1629 1630 AstNodes init_statements; 1631 1632 // <init> 1633 while (tok.type != TokenType.SEMICOLON) // check after trailing comma 1634 { 1635 AstIndex init_stmt = parse_expr_or_id_decl(ConsumeTerminator.no); 1636 init_statements.put(context.arrayArena, init_stmt); 1637 1638 if (tok.type == TokenType.COMMA) 1639 nextToken; // skip "," 1640 else break; 1641 } 1642 expectAndConsume(TokenType.SEMICOLON); 1643 1644 // <cond> 1645 AstIndex condition; 1646 if (tok.type != TokenType.SEMICOLON) { 1647 condition = expr(PreferType.no); 1648 } 1649 expectAndConsume(TokenType.SEMICOLON); 1650 1651 AstNodes increment_statements; 1652 // <increment> 1653 while (tok.type != TokenType.RPAREN) // check after trailing comma 1654 { 1655 AstIndex incExpr = expr(PreferType.no); 1656 AstNode* incExprNode = context.getAstNode(incExpr); 1657 increment_statements.put(context.arrayArena, incExpr); 1658 1659 if (tok.type == TokenType.COMMA) 1660 nextToken; // skip "," 1661 else break; 1662 } 1663 expectAndConsume(TokenType.RPAREN); 1664 1665 AstNodes statements; 1666 statement_as_array(statements); 1667 1668 return make!ForStmtNode(start, init_statements, condition, increment_statements, statements); 1669 } 1670 1671 AstIndex parse_switch() /* "switch" "(" <expr> ")" "{" <switch_case> "}" */ 1672 { 1673 TokenIndex start = tok.index; 1674 nextToken; // skip "switch" 1675 1676 AstIndex condition = paren_expr(); 1677 1678 Array!SwitchCase cases; 1679 AstIndex elseBlock; 1680 expectAndConsume(TokenType.LCURLY); 1681 while (tok.type != TokenType.RCURLY) 1682 { 1683 if (tok.type == TokenType.EOI) break; 1684 1685 // case expression 1686 if (tok.type != TokenType.ELSE_SYM) /* <expr> <block> */ 1687 { 1688 auto expr = expr(PreferType.no); 1689 auto block = block_stmt(); 1690 cases.put(context.arrayArena, SwitchCase(expr, block)); 1691 } 1692 else /* "else" <block> */ 1693 { 1694 nextToken; // skip "else" 1695 if (elseBlock.isDefined) 1696 { 1697 // todo: error 1698 // must occur 0 or 1 times 1699 } 1700 elseBlock = block_stmt(); 1701 } 1702 } 1703 expectAndConsume(TokenType.RCURLY); 1704 1705 return make!SwitchStmtNode(start, condition, elseBlock, cases); 1706 } 1707 1708 AstIndex paren_expr() { /* <paren_expr> ::= "(" <expr> ")" */ 1709 version(print_parse) auto s1 = scop("paren_expr %s", loc); 1710 expectAndConsume(TokenType.LPAREN); 1711 auto res = expr(PreferType.no); 1712 expectAndConsume(TokenType.RPAREN); 1713 return res; 1714 } 1715 1716 AstIndex expr(PreferType preferType, int rbp = 0) 1717 { 1718 Token t = tok; 1719 nextToken; 1720 1721 NullInfo null_info = g_tokenLookups.null_lookup[t.type]; 1722 AstIndex node = null_info.parser_null(this, preferType, t, null_info.rbp); 1723 int nbp = null_info.nbp; // next bp 1724 int lbp = g_tokenLookups.left_lookup[tok.type].lbp; 1725 //writefln("%s %s rbp %s lbp %s nbp %s", t, tok, rbp, lbp, nbp); 1726 1727 while (rbp < lbp && lbp < nbp) 1728 { 1729 t = tok; 1730 nextToken; 1731 LeftInfo left_info = g_tokenLookups.left_lookup[t.type]; 1732 nbp = left_info.nbp; // next bp 1733 // parser can modify nbp in case infix operator want to become postfix, like * 1734 node = left_info.parser_left(this, preferType, t, left_info.rbp, node, nbp); 1735 lbp = g_tokenLookups.left_lookup[tok.type].lbp; 1736 //writefln("%s %s rbp %s lbp %s nbp %s", t, tok, rbp, lbp, nbp); 1737 } 1738 1739 return node; 1740 } 1741 } 1742 1743 /// Controls the expression parser 1744 /// Forces * expression to be parsed as pointer type 1745 /// Disables slice parsing for [] expression 1746 enum PreferType : bool { 1747 no = false, 1748 yes = true, 1749 } 1750 1751 /// min and max binding powers 1752 enum MIN_BP = 0; 1753 enum MAX_BP = 10000; 1754 enum COMMA_PREC = 10; 1755 1756 alias LeftParser = AstIndex function(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp); 1757 alias NullParser = AstIndex function(ref Parser p, PreferType preferType, Token token, int rbp); 1758 1759 AstIndex left_error_parser(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) 1760 { 1761 if (token.type == TokenType.EOI) 1762 p.context.unrecoverable_error(token.index, "Unexpected end of input"); 1763 else 1764 p.context.unrecoverable_error(token.index, "%s is not an expression", token.type); 1765 } 1766 1767 AstIndex null_error_parser(ref Parser p, PreferType preferType, Token token, int rbp) 1768 { 1769 if (token.type == TokenType.EOI) 1770 p.context.unrecoverable_error(token.index, "Unexpected end of input"); 1771 else 1772 p.context.unrecoverable_error(token.index, "%s is not an expression", token.type); 1773 } 1774 1775 struct LeftInfo 1776 { 1777 LeftParser parser_left = &left_error_parser; 1778 int lbp = MIN_BP; 1779 int rbp = MIN_BP; 1780 int nbp = MIN_BP; 1781 } 1782 1783 struct NullInfo 1784 { 1785 NullParser parser_null = &null_error_parser; 1786 int lbp = MIN_BP; 1787 int rbp = MIN_BP; 1788 int nbp = MIN_BP; 1789 } 1790 1791 struct TokenLookups 1792 { 1793 LeftInfo[TokenType.max+1] left_lookup; 1794 NullInfo[TokenType.max+1] null_lookup; 1795 } 1796 1797 __gshared immutable TokenLookups g_tokenLookups = cexp_parser(); 1798 1799 private TokenLookups cexp_parser() 1800 { 1801 TokenLookups res; 1802 1803 TokenType strToTok(string str) 1804 { 1805 import std.algorithm.searching : countUntil; 1806 ptrdiff_t pos = countUntil(tokStrings, str); 1807 assert(pos != -1, str ~ " not found"); 1808 return cast(TokenType)pos; 1809 } 1810 1811 void _RegisterNull(int lbp, int rbp, int nbp, NullParser p, string[] tokens...) { 1812 foreach (string token; tokens) res.null_lookup[strToTok(token)] = NullInfo(p, lbp, rbp, nbp); 1813 } 1814 1815 void _RegisterLeft(int lbp, int rbp, int nbp, LeftParser p, string[] tokens...) { 1816 foreach (string token; tokens) res.left_lookup[strToTok(token)] = LeftInfo(p, lbp, rbp, nbp); 1817 } 1818 1819 void nilfix(int bp, NullParser nud, string[] tokens...) { 1820 _RegisterNull(MIN_BP, MIN_BP, MAX_BP, nud, tokens); 1821 } 1822 1823 void prefix(int bp, NullParser nud, string[] tokens...) { 1824 _RegisterNull(MIN_BP, bp, MAX_BP, nud, tokens); 1825 } 1826 1827 void suffix(int bp, LeftParser led, string[] tokens...) { 1828 _RegisterLeft(bp, MIN_BP, MAX_BP, led, tokens); 1829 } 1830 1831 void infixL(int bp, LeftParser led, string[] tokens...) { 1832 _RegisterLeft(bp, bp, bp + 1, led, tokens); 1833 } 1834 1835 void infixR(int bp, LeftParser led, string[] tokens...) { 1836 _RegisterLeft(bp, bp - 1, bp + 1, led, tokens); 1837 } 1838 1839 void infixN(int bp, LeftParser led, string[] tokens...) { 1840 _RegisterLeft(bp, bp, bp, led, tokens); 1841 } 1842 1843 // Compare the code below with this table of C operator precedence: 1844 // http://en.cppreference.com/w/c/language/operator_precedence 1845 1846 suffix(310, &leftIncDec, ["++", "--"]); 1847 infixL(310, &leftFuncCall, "("); 1848 infixL(310, &leftIndex, "["); 1849 infixL(310, &leftOpDot, "."); 1850 //infixL(310, &leftBinaryOp, "->"); 1851 1852 // 29 -- binds to everything except function call, indexing, postfix ops 1853 prefix(290, &nullPrefixOp, ["+", "-", "!", "~", "*", "&", "++", "--", "@"]); 1854 prefix(290, &nullPrefixAttribute, ["@"]); 1855 prefix(290, &nullCast, "cast"); 1856 1857 infixL(250, &leftFunctionOp, ["function"]); 1858 infixL(250, &leftStarOp, ["*"]); 1859 infixL(250, &leftBinaryOp, ["/", "%"]); 1860 1861 infixL(230, &leftBinaryOp, ["+", "-"]); 1862 infixL(210, &leftBinaryOp, ["<<", ">>", ">>>"]); 1863 infixL(190, &leftBinaryOp, ["<", ">", "<=", ">="]); 1864 infixL(170, &leftBinaryOp, ["!=", "=="]); 1865 1866 infixL(150, &leftBinaryOp, "&"); 1867 infixL(130, &leftBinaryOp, "^"); 1868 infixL(110, &leftBinaryOp, "|"); 1869 infixL(90, &leftBinaryOp, "&&"); 1870 infixL(70, &leftBinaryOp, "||"); 1871 1872 // Right associative: a = b = 2 is a = (b = 2) 1873 infixR(30, &leftAssignOp, ["=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|="]); 1874 1875 // 0 precedence -- doesn"t bind until ) 1876 prefix(0, &nullParen, "("); // for grouping 1877 1878 // 0 precedence -- never used 1879 nilfix(0, &nullLiteral, [ 1880 "#id", "$id", 1881 "auto", "noreturn","void", "bool", "null", 1882 "i8", "i16", "i32", "i64", 1883 "u8", "u16", "u32", "u64", 1884 "f32", "f64", 1885 "$alias", "$type", 1886 "true", "false", 1887 "#special_kw", 1888 "#int_dec_lit", "#int_bin_lit", "#int_hex_lit", "#float_dec_lit", "#str_lit", "#char_lit"] 1889 ); 1890 nilfix(0, &null_error_parser, [")", "]", ":", "#eoi", ";"]); 1891 return res; 1892 } 1893 1894 // Null Denotations -- tokens that take nothing on the left 1895 1896 AstIndex parseIntLiteralType(string suffix, TokenIndex tok, CompilationContext* c) { 1897 if (suffix.length == 0) return AstIndex(); 1898 switch(suffix) { 1899 case "i8": return CommonAstNodes.type_i8; 1900 case "i16": return CommonAstNodes.type_i16; 1901 case "i32": return CommonAstNodes.type_i32; 1902 case "i64": return CommonAstNodes.type_i64; 1903 case "u8": return CommonAstNodes.type_u8; 1904 case "u16": return CommonAstNodes.type_u16; 1905 case "u32": return CommonAstNodes.type_u32; 1906 case "u64": return CommonAstNodes.type_u64; 1907 default: c.internal_error(tok, "Unexpected type suffix `%s`", suffix); 1908 } 1909 } 1910 1911 // id, int_literal, string_literal 1912 AstIndex nullLiteral(ref Parser p, PreferType preferType, Token token, int rbp) { 1913 import std.algorithm : filter; 1914 import std.range : walkLength; 1915 import std.conv : parse; 1916 import std.typecons : Yes; 1917 CompilationContext* c = p.context; 1918 switch(token.type) with(TokenType) 1919 { 1920 case IDENTIFIER: 1921 Identifier id = p.makeIdentifier(token.index); 1922 return p.make!NameUseExprNode(token.index, p.currentScopeIndex, id); 1923 case CASH_IDENTIFIER: 1924 Identifier id = p.makeIdentifier(token.index); 1925 if (id.index >= commonId_builtin_func_first && id.index <= commonId_builtin_func_last) 1926 { 1927 uint builtinIndex = id.index - commonId_builtin_func_first; 1928 return builtinFuncsArray[builtinIndex]; 1929 } 1930 c.error(token.index, "Invalid $ identifier %s", c.idString(id)); 1931 return p.make!NameUseExprNode(token.index, p.currentScopeIndex, id); 1932 case SPECIAL_KW: 1933 Identifier id = p.makeIdentifier(token.index); 1934 c.assertf(id.index >= commonId_special_keyword_first && id.index <= commonId_special_keyword_last, 1935 "Invalid special keyword %s", c.idString(id)); 1936 uint keywordIndex = id.index - commonId_special_keyword_first; 1937 SpecialKeyword kw = cast(SpecialKeyword)keywordIndex; 1938 IrIndex irValue = eval_literal_special(kw, token.index, p.currentScopeIndex, c); 1939 return c.appendAst!SpecialLiteralExprNode(token.index, irValue, kw); 1940 case NULL: 1941 return p.makeExpr!NullLiteralExprNode(token.index); 1942 case TRUE_LITERAL: 1943 return p.makeExpr!BoolLiteralExprNode(token.index, true); 1944 case FALSE_LITERAL: 1945 return p.makeExpr!BoolLiteralExprNode(token.index, false); 1946 case STRING_LITERAL: 1947 // omit " at the start and end of token 1948 string value = cast(string)c.getTokenString(token.index)[1..$-1]; 1949 1950 // handle escape sequences and copy string to RO buffer. 1951 value = handleEscapedString(c.roStaticDataBuffer, value); 1952 c.roStaticDataBuffer.put(0); // add zero terminator 1953 1954 AstIndex type = CommonAstNodes.type_u8Slice; 1955 IrIndex irValue = makeStringLiteralIrConstant(value, p.currentModule.objectSymIndex, c); 1956 return p.make!StringLiteralExprNode(token.index, type, irValue, value); 1957 case CHAR_LITERAL: 1958 // omit ' at the start and end of token 1959 string value = cast(string)c.getTokenString(token.index)[1..$-1]; 1960 dchar charVal = getCharValue(value); 1961 return p.makeExpr!IntLiteralExprNode(token.index, cast(uint)charVal); 1962 case INT_DEC_LITERAL: 1963 string value = cast(string)c.getTokenString(token.index); 1964 auto filtered = value.filter!(c => c != '_'); 1965 auto result = filtered.parse!(ulong, typeof(filtered), Yes.doCount); 1966 AstIndex type = parseIntLiteralType(value[$-filtered.walkLength..$], token.index, c); 1967 return c.appendAst!IntLiteralExprNode(token.index, type, result.data); 1968 case INT_HEX_LITERAL: 1969 string value = cast(string)c.getTokenString(token.index); 1970 auto filtered = value[2..$].filter!(c => c != '_'); 1971 auto result = filtered.parse!(ulong, typeof(filtered), Yes.doCount)(16); // skip 0x, 0X 1972 AstIndex type = parseIntLiteralType(value[$-filtered.walkLength..$], token.index, c); 1973 return c.appendAst!IntLiteralExprNode(token.index, type, result.data); 1974 case INT_BIN_LITERAL: 1975 string value = cast(string)c.getTokenString(token.index); 1976 auto filtered = value[2..$].filter!(c => c != '_'); 1977 auto result = filtered.parse!(ulong, typeof(filtered), Yes.doCount)(2); // skip 0b, 0B 1978 AstIndex type = parseIntLiteralType(value[$-filtered.walkLength..$], token.index, c); 1979 return c.appendAst!IntLiteralExprNode(token.index, type, result.data); 1980 case FLOAT_DEC_LITERAL: 1981 string value = cast(string)c.getTokenString(token.index); 1982 auto filtered = value.filter!(c => c != '_'); 1983 auto result = filtered.parse!(double, typeof(filtered), Yes.doCount); 1984 AstIndex type; 1985 if (!filtered.empty) { 1986 string suffix = value[$-filtered.walkLength..$]; 1987 if (suffix == "f32") 1988 type = CommonAstNodes.type_f32; 1989 else { 1990 c.assertf(suffix == "f64", token.index, "Unexpected type suffix `%s`", suffix); 1991 type = CommonAstNodes.type_f64; 1992 } 1993 } 1994 return c.appendAst!FloatLiteralExprNode(token.index, type, result.data); 1995 case TYPE_AUTO: 1996 c.error(token.index, "`auto` can only be used to declare varible in a function body"); 1997 BasicType t = token.type.tokenTypeToBasicType; 1998 return c.basicTypeNodes(t); 1999 case TYPE_NORETURN, TYPE_VOID, TYPE_BOOL, 2000 TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_U8, TYPE_U16, TYPE_U32, TYPE_U64, 2001 TYPE_F32, TYPE_F64, 2002 TYPE_ALIAS, TYPE_TYPE: 2003 BasicType t = token.type.tokenTypeToBasicType; 2004 return c.basicTypeNodes(t); 2005 default: 2006 c.internal_error("nullLiteral %s", token.type); 2007 } 2008 } 2009 2010 // Arithmetic grouping 2011 AstIndex nullParen(ref Parser p, PreferType preferType, Token token, int rbp) { 2012 AstIndex r = p.expr(PreferType.no, rbp); 2013 p.expectAndConsume(TokenType.RPAREN); 2014 //r.flags |= NFLG.parenthesis; // NOTE: needed if ternary operator is needed 2015 return r; 2016 } 2017 2018 AstIndex nullPrefixAttribute(ref Parser p, PreferType preferType, Token token, int rbp) { 2019 if (!preferType) p.context.unrecoverable_error(token.index, "Unexpected attribute"); 2020 while(true) { 2021 p.parse_single_attribute(p.tok.index); 2022 if (p.tok.type == TokenType.AT) { 2023 p.nextToken; // skip @ 2024 continue; 2025 } 2026 break; 2027 } 2028 return p.expr(preferType, rbp); 2029 } 2030 2031 // Prefix operator 2032 // ["+", "-", "!", "~", "*", "&", "++", "--"] <expr> 2033 AstIndex nullPrefixOp(ref Parser p, PreferType preferType, Token token, int rbp) { 2034 AstIndex right = p.expr(PreferType.no, rbp); 2035 UnOp op; 2036 switch(token.type) with(TokenType) 2037 { 2038 case PLUS: return right; 2039 case MINUS: 2040 AstNode* rightNode = p.context.getAstNode(right); 2041 if (rightNode.astType == AstType.literal_int) { 2042 (cast(IntLiteralExprNode*)rightNode).negate(token.index, *p.context); 2043 return right; 2044 } else if (rightNode.astType == AstType.literal_float) { 2045 (cast(FloatLiteralExprNode*)rightNode).negate(token.index, *p.context); 2046 return right; 2047 } 2048 op = UnOp.GENERIC_MINUS; 2049 break; 2050 case NOT: op = UnOp.logicalNot; break; 2051 case TILDE: op = UnOp.bitwiseNot; break; 2052 case STAR: op = UnOp.deref; break; 2053 case AND: op = UnOp.addrOf; break; 2054 case PLUS_PLUS: op = UnOp.preIncrement; break; 2055 case MINUS_MINUS: op = UnOp.preDecrement; break; 2056 default: p.context.unreachable; 2057 } 2058 return p.makeExpr!UnaryExprNode(token.index, op, right); 2059 } 2060 2061 // "cast" "(" <expr> ")" <expr> 2062 AstIndex nullCast(ref Parser p, PreferType preferType, Token token, int rbp) { 2063 p.expectAndConsume(TokenType.LPAREN); 2064 AstIndex type = p.expr(PreferType.yes, 0); 2065 p.expectAndConsume(TokenType.RPAREN); 2066 AstIndex right = p.expr(PreferType.no, rbp); 2067 return p.make!TypeConvExprNode(token.index, type, right); 2068 } 2069 2070 // Left Denotations -- tokens that take an expression on the left 2071 2072 // <expr> "++" / "--" 2073 AstIndex leftIncDec(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) { 2074 UnOp op; 2075 switch(token.type) with(TokenType) 2076 { 2077 case PLUS_PLUS: op = UnOp.postIncrement; break; 2078 case MINUS_MINUS: op = UnOp.postDecrement; break; 2079 default: p.context.unreachable; 2080 } 2081 return p.makeExpr!UnaryExprNode(token.index, op, left); 2082 } 2083 2084 // <expr> "[" "]" 2085 // <expr> "[" <expr> "," <expr>+ "]" 2086 // <expr> "[" <expr> .. <expr> "]" 2087 AstIndex leftIndex(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex array, ref int nbp) { 2088 AstNodes indices; 2089 if (p.tok.type == TokenType.RBRACKET) 2090 { 2091 p.nextToken; 2092 return p.makeExpr!IndexExprNode(token.index, p.currentScopeIndex, array, indices); 2093 } 2094 AstIndex index = p.expr(PreferType.no, 0); 2095 if (p.tok.type == TokenType.RBRACKET) 2096 { 2097 p.nextToken; 2098 indices.put(p.context.arrayArena, index); 2099 return p.makeExpr!IndexExprNode(token.index, p.currentScopeIndex, array, indices); 2100 } 2101 2102 if (preferType == PreferType.yes) 2103 { 2104 // it is type 2105 p.expectAndConsume(TokenType.RBRACKET); 2106 assert(false); 2107 } 2108 else 2109 { 2110 // it is expression 2111 p.expectAndConsume(TokenType.DOT_DOT); 2112 AstIndex index2 = p.expr(PreferType.no, 0); 2113 p.expectAndConsume(TokenType.RBRACKET); 2114 return p.makeExpr!SliceExprNode(token.index, array, index, index2); 2115 } 2116 } 2117 2118 // member access <expr> . <expr> 2119 AstIndex leftOpDot(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) 2120 { 2121 Identifier id; 2122 if (p.tok.type == TokenType.IDENTIFIER) 2123 { 2124 id = p.makeIdentifier(p.tok.index); 2125 p.nextToken; // skip id 2126 } 2127 else 2128 { 2129 p.context.error(token.index, 2130 "Expected identifier after '.', while got '%s'", 2131 p.context.getTokenString(p.tok.index)); 2132 } 2133 return p.make!MemberExprNode(token.index, p.currentScopeIndex, left, id); 2134 } 2135 2136 AstIndex leftFunctionOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex returnType, ref int nbp) { 2137 CallConvention callConvention = p.context.defaultCallConvention; 2138 auto sig = p.makeDecl!FunctionSignatureNode(token.index, returnType, AstNodes.init, callConvention); 2139 AstIndex prevOwner = p.declarationOwner; // change the owner, so that parameters are inferred as local 2140 p.declarationOwner = sig; 2141 p.parseParameters(sig, p.NeedRegNames.no); // function types don't need to register their param names 2142 p.declarationOwner = prevOwner; 2143 // we don't have to register parameter names, since we have no body 2144 sig.setState(p.context, AstNodeState.name_register_nested_done); 2145 return p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, sig); 2146 } 2147 2148 // multiplication or pointer type 2149 // <expr> * <expr> or <expr>* 2150 AstIndex leftStarOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) { 2151 switch (p.tok.type) with(TokenType) 2152 { 2153 case STAR, COMMA, RPAREN, RBRACKET, LBRACKET, SEMICOLON, FUNCTION_SYM /*,DELEGATE_SYM*/: 2154 // pointer 2155 nbp = 311; // make current node into a postfix op 2156 return p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, left); 2157 case DOT: 2158 // hack for postfix star followed by dot 2159 AstIndex ptr = p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, left); 2160 Token tok = p.tok; 2161 p.nextToken; // skip dot 2162 int nbpDot; 2163 return leftOpDot(p, PreferType.no, tok, 0, ptr, nbpDot); 2164 default: 2165 // otherwise it is multiplication 2166 break; 2167 } 2168 2169 if (preferType) 2170 { 2171 // pointer 2172 return p.make!PtrTypeNode(token.index, CommonAstNodes.type_type, left); 2173 } 2174 2175 // otherwise it is multiplication 2176 AstIndex right = p.expr(PreferType.no, rbp); 2177 BinOp op = BinOp.GENERIC_MUL; 2178 return p.makeExpr!BinaryExprNode(token.index, op, left, right); 2179 } 2180 2181 // Normal binary operator <expr> op <expr> 2182 AstIndex leftBinaryOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) { 2183 AstIndex right = p.expr(PreferType.no, rbp); 2184 BinOp op; 2185 switch(token.type) with(TokenType) 2186 { 2187 // logic ops 2188 case AND_AND: op = BinOp.LOGIC_AND; break; // && 2189 case OR_OR: op = BinOp.LOGIC_OR; break; // || 2190 case EQUAL_EQUAL: op = BinOp.EQUAL; break; // == 2191 case NOT_EQUAL: op = BinOp.NOT_EQUAL; break; // != 2192 case MORE: op = BinOp.GENERIC_GREATER; break; // > 2193 case MORE_EQUAL: op = BinOp.GENERIC_GREATER_EQUAL; break; // >= 2194 case LESS: op = BinOp.GENERIC_LESS; break; // < 2195 case LESS_EQUAL: op = BinOp.GENERIC_LESS_EQUAL; break; // <= 2196 2197 // arithmetic ops 2198 case AND: op = BinOp.BITWISE_AND; break; // & 2199 case OR: op = BinOp.BITWISE_OR; break; // | 2200 case PERCENT: op = BinOp.GENERIC_INT_REM; break; // % 2201 case LESS_LESS: op = BinOp.SHL; break; // << 2202 case MORE_MORE: op = BinOp.ASHR; break; // >> 2203 case MORE_MORE_MORE: op = BinOp.SHR; break; // >>> 2204 case MINUS: op = BinOp.GENERIC_MINUS; break; // - 2205 case PLUS: op = BinOp.GENERIC_PLUS; break; // + 2206 case SLASH: op = BinOp.GENERIC_DIV; break; // / 2207 case XOR: op = BinOp.XOR; break; // ^ 2208 2209 default: 2210 p.context.internal_error(token.index, "parse leftBinaryOp %s", token.type); 2211 } 2212 return p.makeExpr!BinaryExprNode(token.index, op, left, right); 2213 } 2214 2215 // Binary assignment operator <expr> op= <expr> 2216 AstIndex leftAssignOp(ref Parser p, PreferType preferType, Token token, int rbp, AstIndex left, ref int nbp) { 2217 AstIndex right = p.expr(PreferType.no, rbp); 2218 BinOp op; 2219 switch(token.type) with(TokenType) 2220 { 2221 // arithmetic opEquals 2222 case EQUAL: op = BinOp.ASSIGN; break; // = 2223 case AND_EQUAL: op = BinOp.BITWISE_AND_ASSIGN; break; // &= 2224 case OR_EQUAL: op = BinOp.BITWISE_OR_ASSIGN; break; // |= 2225 case PERCENT_EQUAL: op = BinOp.GENERIC_INT_REM_ASSIGN; break; // %= 2226 case LESS_LESS_EQUAL: op = BinOp.SHL_ASSIGN; break; // <<= 2227 case MORE_MORE_EQUAL: op = BinOp.ASHR_ASSIGN; break; // >>= 2228 case MORE_MORE_MORE_EQUAL: op = BinOp.SHR_ASSIGN; break; // >>>= 2229 case MINUS_EQUAL: op = BinOp.GENERIC_MINUS_ASSIGN; break; // -= 2230 case PLUS_EQUAL: op = BinOp.GENERIC_PLUS_ASSIGN; break; // += 2231 case SLASH_EQUAL: op = BinOp.GENERIC_DIV_ASSIGN; break; // /= 2232 case STAR_EQUAL: op = BinOp.GENERIC_MUL_ASSIGN; break; // *= 2233 case XOR_EQUAL: op = BinOp.XOR_ASSIGN; break; // ^= 2234 default: 2235 p.context.internal_error(token.index, "parse leftAssignOp %s", token.type); 2236 } 2237 AstNode* leftNode = p.context.getAstNode(left); 2238 leftNode.flags |= AstFlags.isLvalue; 2239 2240 AstIndex assignExpr = p.makeExpr!BinaryExprNode(token.index, op, left, right); 2241 AstNode* assignExprNode = p.context.getAstNode(assignExpr); 2242 assignExprNode.flags |= BinaryOpFlags.isAssignment; 2243 2244 return assignExpr; 2245 } 2246 2247 // <expr> "(" <expr_list> ")" 2248 AstIndex leftFuncCall(ref Parser p, PreferType preferType, Token token, int unused_rbp, AstIndex callee, ref int nbp) { 2249 AstNodes args; 2250 ushort flags = p.parse_argument_list(args); 2251 AstIndex callExpr = p.makeExpr!CallExprNode(token.index, p.currentScopeIndex, callee, args); 2252 callExpr.flags(p.context) |= flags; 2253 return callExpr; 2254 }