1 /* Digital Mars DMDScript source code. 2 * Copyright (c) 2000-2002 by Chromium Communications 3 * D version Copyright (c) 2004-2010 by Digital Mars 4 * Distributed under the Boost Software License, Version 1.0. 5 * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 * written by Walter Bright 7 * http://www.digitalmars.com 8 * 9 * D2 port by Dmitry Olshansky 10 * 11 * DMDScript is implemented in the D Programming Language, 12 * http://www.digitalmars.com/d/ 13 * 14 * For a C++ implementation of DMDScript, including COM support, see 15 * http://www.digitalmars.com/dscript/cppscript.html 16 */ 17 18 19 module dmdscript.parse; 20 21 import dmdscript.script; 22 import dmdscript.lexer; 23 import dmdscript.functiondefinition; 24 import dmdscript.expression; 25 import dmdscript.statement; 26 import dmdscript.identifier; 27 import dmdscript.ir; 28 import dmdscript.errmsgs; 29 30 class Parser : Lexer 31 { 32 uint flags; 33 34 enum 35 { 36 normal = 0, 37 initial = 1, 38 39 allowIn = 0, 40 noIn = 2, 41 42 // Flag if we're in the for statement header, as 43 // automatic semicolon insertion is suppressed inside it. 44 inForHeader = 4, 45 } 46 47 FunctionDefinition lastnamedfunc; 48 49 50 this(d_string sourcename, d_string base, int useStringtable) 51 { 52 //writefln("Parser.this(base = '%s')", base); 53 super(sourcename, base, useStringtable); 54 nextToken(); // start up the scanner 55 } 56 57 ~this() 58 { 59 lastnamedfunc = null; 60 } 61 62 63 /********************************************** 64 * Return !=0 on error, and fill in *perrinfo. 65 */ 66 67 static int parseFunctionDefinition(out FunctionDefinition pfd, 68 immutable(char)[] params, immutable(char)[] bdy, out ErrInfo perrinfo) 69 { 70 Parser p; 71 Identifier*[] parameters; 72 TopStatement[] topstatements; 73 FunctionDefinition fd = null; 74 int result; 75 76 p = new Parser("anonymous", params, 0); 77 78 // Parse FormalParameterList 79 while(p.token.value != TOKeof) 80 { 81 if(p.token.value != TOKidentifier) 82 { 83 p.error(errmsgtbl[ERR_FPL_EXPECTED_IDENTIFIER], p.token.toString()); 84 goto Lreturn; 85 } 86 parameters ~= p.token.ident; 87 p.nextToken(); 88 if(p.token.value == TOKcomma) 89 p.nextToken(); 90 else if(p.token.value == TOKeof) 91 break; 92 else 93 { 94 p.error(errmsgtbl[ERR_FPL_EXPECTED_COMMA], p.token.toString()); 95 goto Lreturn; 96 } 97 } 98 if(p.errinfo.message) 99 goto Lreturn; 100 101 delete p; 102 103 // Parse StatementList 104 p = new Parser("anonymous", bdy, 0); 105 for(;; ) 106 { 107 TopStatement ts; 108 109 if(p.token.value == TOKeof) 110 break; 111 ts = p.parseStatement(); 112 topstatements ~= ts; 113 } 114 115 fd = new FunctionDefinition(0, 0, null, parameters, topstatements); 116 117 118 Lreturn: 119 pfd = fd; 120 perrinfo = p.errinfo; 121 result = (p.errinfo.message != null); 122 delete p; 123 p = null; 124 return result; 125 } 126 127 /********************************************** 128 * Return !=0 on error, and fill in *perrinfo. 129 */ 130 131 int parseProgram(out TopStatement[] topstatements, ErrInfo *perrinfo) 132 { 133 topstatements = parseTopStatements(); 134 check(TOKeof); 135 //writef("parseProgram done\n"); 136 *perrinfo = errinfo; 137 //clearstack(); 138 return errinfo.message != null; 139 } 140 141 TopStatement[] parseTopStatements() 142 { 143 TopStatement[] topstatements; 144 TopStatement ts; 145 146 //writefln("parseTopStatements()"); 147 for(;; ) 148 { 149 switch(token.value) 150 { 151 case TOKfunction: 152 ts = parseFunction(0); 153 topstatements ~= ts; 154 break; 155 156 case TOKeof: 157 return topstatements; 158 159 case TOKrbrace: 160 return topstatements; 161 162 default: 163 ts = parseStatement(); 164 topstatements ~= ts; 165 break; 166 } 167 } 168 assert(0); 169 } 170 171 /*************************** 172 * flag: 173 * 0 Function statement 174 * 1 Function literal 175 */ 176 177 TopStatement parseFunction(int flag) 178 { 179 Identifier* name; 180 Identifier*[] parameters; 181 TopStatement[] topstatements; 182 FunctionDefinition f; 183 Expression e = null; 184 Loc loc; 185 186 //writef("parseFunction()\n"); 187 loc = currentline; 188 nextToken(); 189 name = null; 190 if(token.value == TOKidentifier) 191 { 192 name = token.ident; 193 nextToken(); 194 195 if(!flag && token.value == TOKdot) 196 { 197 // Regard: 198 // function A.B() { } 199 // as: 200 // A.B = function() { } 201 // This is not ECMA, but a jscript feature 202 203 e = new IdentifierExpression(loc, name); 204 name = null; 205 206 while(token.value == TOKdot) 207 { 208 nextToken(); 209 if(token.value == TOKidentifier) 210 { 211 e = new DotExp(loc, e, token.ident); 212 nextToken(); 213 } 214 else 215 { 216 error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_2PARAM], ".", token.toString()); 217 break; 218 } 219 } 220 } 221 } 222 223 check(TOKlparen); 224 if(token.value == TOKrparen) 225 nextToken(); 226 else 227 { 228 for(;; ) 229 { 230 if(token.value == TOKidentifier) 231 { 232 parameters ~= token.ident; 233 nextToken(); 234 if(token.value == TOKcomma) 235 { 236 nextToken(); 237 continue; 238 } 239 if(!check(TOKrparen)) 240 break; 241 } 242 else 243 error(ERR_EXPECTED_IDENTIFIER); 244 break; 245 } 246 } 247 248 check(TOKlbrace); 249 topstatements = parseTopStatements(); 250 check(TOKrbrace); 251 252 f = new FunctionDefinition(loc, 0, name, parameters, topstatements); 253 f.isliteral = flag; 254 lastnamedfunc = f; 255 256 //writef("parseFunction() done\n"); 257 if(!e) 258 return f; 259 260 // Construct: 261 // A.B = function() { } 262 263 Expression e2 = new FunctionLiteral(loc, f); 264 265 e = new AssignExp(loc, e, e2); 266 267 Statement s = new ExpStatement(loc, e); 268 269 return s; 270 } 271 272 /***************************************** 273 */ 274 275 Statement parseStatement() 276 { 277 Statement s; 278 Token *t; 279 Loc loc; 280 281 //writefln("parseStatement()"); 282 loc = currentline; 283 switch(token.value) 284 { 285 case TOKidentifier: 286 case TOKthis: 287 // Need to look ahead to see if it is a declaration, label, or expression 288 t = peek(&token); 289 if(t.value == TOKcolon && token.value == TOKidentifier) 290 { // It's a label 291 Identifier *ident; 292 293 ident = token.ident; 294 nextToken(); 295 nextToken(); 296 s = parseStatement(); 297 s = new LabelStatement(loc, ident, s); 298 } 299 else if(t.value == TOKassign || 300 t.value == TOKdot || 301 t.value == TOKlbracket) 302 { 303 Expression exp; 304 305 exp = parseExpression(); 306 parseOptionalSemi(); 307 s = new ExpStatement(loc, exp); 308 } 309 else 310 { 311 Expression exp; 312 313 exp = parseExpression(initial); 314 parseOptionalSemi(); 315 s = new ExpStatement(loc, exp); 316 } 317 break; 318 319 case TOKreal: 320 case TOKstring: 321 case TOKdelete: 322 case TOKlparen: 323 case TOKplusplus: 324 case TOKminusminus: 325 case TOKplus: 326 case TOKminus: 327 case TOKnot: 328 case TOKtilde: 329 case TOKtypeof: 330 case TOKnull: 331 case TOKnew: 332 case TOKtrue: 333 case TOKfalse: 334 case TOKvoid: 335 { Expression exp; 336 337 exp = parseExpression(initial); 338 parseOptionalSemi(); 339 s = new ExpStatement(loc, exp); 340 break; } 341 342 case TOKvar: 343 { 344 Identifier *ident; 345 Expression init; 346 VarDeclaration v; 347 VarStatement vs; 348 349 vs = new VarStatement(loc); 350 s = vs; 351 352 nextToken(); 353 for(;; ) 354 { 355 loc = currentline; 356 357 if(token.value != TOKidentifier) 358 { 359 error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_PARAM], token.toString()); 360 break; 361 } 362 ident = token.ident; 363 init = null; 364 nextToken(); 365 if(token.value == TOKassign) 366 { 367 uint flags_save; 368 369 nextToken(); 370 flags_save = flags; 371 flags &= ~initial; 372 init = parseAssignExp(); 373 flags = flags_save; 374 } 375 v = new VarDeclaration(loc, ident, init); 376 vs.vardecls ~= v; 377 if(token.value != TOKcomma) 378 break; 379 nextToken(); 380 } 381 if(!(flags & inForHeader)) 382 parseOptionalSemi(); 383 break; 384 } 385 386 case TOKlbrace: 387 { BlockStatement bs; 388 389 nextToken(); 390 bs = new BlockStatement(loc); 391 /*while(token.value != TOKrbrace) 392 { 393 if(token.value == TOKeof) 394 { 395 error(ERR_UNTERMINATED_BLOCK); 396 break; 397 } 398 bs.statements ~= parseStatement(); 399 }*/ 400 bs.statements ~= parseTopStatements(); 401 s = bs; 402 nextToken(); 403 404 // The following is to accommodate the jscript bug: 405 // if (i) {return(0);}; else ... 406 /*if(token.value == TOKsemicolon) 407 nextToken();*/ 408 409 break; } 410 411 case TOKif: 412 { Expression condition; 413 Statement ifbody; 414 Statement elsebody; 415 416 nextToken(); 417 condition = parseParenExp(); 418 ifbody = parseStatement(); 419 if(token.value == TOKelse) 420 { 421 nextToken(); 422 elsebody = parseStatement(); 423 } 424 else 425 elsebody = null; 426 s = new IfStatement(loc, condition, ifbody, elsebody); 427 break; } 428 429 case TOKswitch: 430 { Expression condition; 431 Statement bdy; 432 433 nextToken(); 434 condition = parseParenExp(); 435 bdy = parseStatement(); 436 s = new SwitchStatement(loc, condition, bdy); 437 break; } 438 439 case TOKcase: 440 { Expression exp; 441 442 nextToken(); 443 exp = parseExpression(); 444 check(TOKcolon); 445 s = new CaseStatement(loc, exp); 446 break; } 447 448 case TOKdefault: 449 nextToken(); 450 check(TOKcolon); 451 s = new DefaultStatement(loc); 452 break; 453 454 case TOKwhile: 455 { Expression condition; 456 Statement bdy; 457 458 nextToken(); 459 condition = parseParenExp(); 460 bdy = parseStatement(); 461 s = new WhileStatement(loc, condition, bdy); 462 break; } 463 464 case TOKsemicolon: 465 nextToken(); 466 s = new EmptyStatement(loc); 467 break; 468 469 case TOKdo: 470 { Statement bdy; 471 Expression condition; 472 473 nextToken(); 474 bdy = parseStatement(); 475 check(TOKwhile); 476 condition = parseParenExp(); 477 //We do what most browsers now do, ie allow missing ';' 478 //like " do{ statement; }while(e) statement; " and that even w/o linebreak 479 if(token.value == TOKsemicolon) 480 nextToken(); 481 //parseOptionalSemi(); 482 s = new DoStatement(loc, bdy, condition); 483 break; } 484 485 case TOKfor: 486 { 487 Statement init; 488 Statement bdy; 489 490 nextToken(); 491 flags |= inForHeader; 492 check(TOKlparen); 493 if(token.value == TOKvar) 494 { 495 init = parseStatement(); 496 } 497 else 498 { 499 Expression e; 500 501 e = parseOptionalExpression(noIn); 502 init = e ? new ExpStatement(loc, e) : null; 503 } 504 505 if(token.value == TOKsemicolon) 506 { 507 Expression condition; 508 Expression increment; 509 510 nextToken(); 511 condition = parseOptionalExpression(); 512 check(TOKsemicolon); 513 increment = parseOptionalExpression(); 514 check(TOKrparen); 515 flags &= ~inForHeader; 516 517 bdy = parseStatement(); 518 s = new ForStatement(loc, init, condition, increment, bdy); 519 } 520 else if(token.value == TOKin) 521 { 522 Expression inexp; 523 VarStatement vs; 524 525 // Check that there's only one VarDeclaration 526 // in init. 527 if(init.st == VARSTATEMENT) 528 { 529 vs = cast(VarStatement)init; 530 if(vs.vardecls.length != 1) 531 error(errmsgtbl[ERR_TOO_MANY_IN_VARS], vs.vardecls.length); 532 } 533 534 nextToken(); 535 inexp = parseExpression(); 536 check(TOKrparen); 537 flags &= ~inForHeader; 538 bdy = parseStatement(); 539 s = new ForInStatement(loc, init, inexp, bdy); 540 } 541 else 542 { 543 error(errmsgtbl[ERR_IN_EXPECTED], token.toString()); 544 s = null; 545 } 546 break; 547 } 548 549 case TOKwith: 550 { Expression exp; 551 Statement bdy; 552 553 nextToken(); 554 exp = parseParenExp(); 555 bdy = parseStatement(); 556 s = new WithStatement(loc, exp, bdy); 557 break; } 558 559 case TOKbreak: 560 { Identifier *ident; 561 562 nextToken(); 563 if(token.sawLineTerminator && token.value != TOKsemicolon) 564 { // Assume we saw a semicolon 565 ident = null; 566 } 567 else 568 { 569 if(token.value == TOKidentifier) 570 { 571 ident = token.ident; 572 nextToken(); 573 } 574 else 575 ident = null; 576 parseOptionalSemi(); 577 } 578 s = new BreakStatement(loc, ident); 579 break; } 580 581 case TOKcontinue: 582 { Identifier *ident; 583 584 nextToken(); 585 if(token.sawLineTerminator && token.value != TOKsemicolon) 586 { // Assume we saw a semicolon 587 ident = null; 588 } 589 else 590 { 591 if(token.value == TOKidentifier) 592 { 593 ident = token.ident; 594 nextToken(); 595 } 596 else 597 ident = null; 598 parseOptionalSemi(); 599 } 600 s = new ContinueStatement(loc, ident); 601 break; } 602 603 case TOKgoto: 604 { Identifier *ident; 605 606 nextToken(); 607 if(token.value != TOKidentifier) 608 { 609 error(errmsgtbl[ERR_GOTO_LABEL_EXPECTED], token.toString()); 610 s = null; 611 break; 612 } 613 ident = token.ident; 614 nextToken(); 615 parseOptionalSemi(); 616 s = new GotoStatement(loc, ident); 617 break; } 618 619 case TOKreturn: 620 { Expression exp; 621 622 nextToken(); 623 if(token.sawLineTerminator && token.value != TOKsemicolon) 624 { // Assume we saw a semicolon 625 s = new ReturnStatement(loc, null); 626 } 627 else 628 { 629 exp = parseOptionalExpression(); 630 parseOptionalSemi(); 631 s = new ReturnStatement(loc, exp); 632 } 633 break; } 634 635 case TOKthrow: 636 { Expression exp; 637 638 nextToken(); 639 exp = parseExpression(); 640 parseOptionalSemi(); 641 s = new ThrowStatement(loc, exp); 642 break; } 643 644 case TOKtry: 645 { Statement bdy; 646 Identifier *catchident; 647 Statement catchbody; 648 Statement finalbody; 649 650 nextToken(); 651 bdy = parseStatement(); 652 if(token.value == TOKcatch) 653 { 654 nextToken(); 655 check(TOKlparen); 656 catchident = null; 657 if(token.value == TOKidentifier) 658 catchident = token.ident; 659 check(TOKidentifier); 660 check(TOKrparen); 661 catchbody = parseStatement(); 662 } 663 else 664 { 665 catchident = null; 666 catchbody = null; 667 } 668 669 if(token.value == TOKfinally) 670 { 671 nextToken(); 672 finalbody = parseStatement(); 673 } 674 else 675 finalbody = null; 676 677 if(!catchbody && !finalbody) 678 { 679 error(ERR_TRY_CATCH_EXPECTED); 680 s = null; 681 } 682 else 683 { 684 s = new TryStatement(loc, bdy, catchident, catchbody, finalbody); 685 } 686 break; } 687 688 default: 689 error(errmsgtbl[ERR_STATEMENT_EXPECTED], token.toString()); 690 nextToken(); 691 s = null; 692 break; 693 } 694 695 //writefln("parseStatement() done"); 696 return s; 697 } 698 699 700 701 Expression parseOptionalExpression(uint flags = 0) 702 { 703 Expression e; 704 705 if(token.value == TOKsemicolon || token.value == TOKrparen) 706 e = null; 707 else 708 e = parseExpression(flags); 709 return e; 710 } 711 712 // Follow ECMA 7.8.1 rules for inserting semicolons 713 void parseOptionalSemi() 714 { 715 if(token.value != TOKeof && 716 token.value != TOKrbrace && 717 !(token.sawLineTerminator && (flags & inForHeader) == 0) 718 ) 719 check(TOKsemicolon); 720 } 721 722 int check(TOK value) 723 { 724 if(token.value != value) 725 { 726 error(errmsgtbl[ERR_EXPECTED_GENERIC], token.toString(), Token.toString(value)); 727 return 0; 728 } 729 nextToken(); 730 return 1; 731 } 732 733 /********************************* Expression Parser ***************************/ 734 735 736 Expression parseParenExp() 737 { 738 Expression e; 739 740 check(TOKlparen); 741 e = parseExpression(); 742 check(TOKrparen); 743 return e; 744 } 745 746 Expression parsePrimaryExp(int innew) 747 { 748 Expression e; 749 Loc loc; 750 751 loc = currentline; 752 switch(token.value) 753 { 754 case TOKthis: 755 e = new ThisExpression(loc); 756 nextToken(); 757 break; 758 759 case TOKnull: 760 e = new NullExpression(loc); 761 nextToken(); 762 break; 763 case TOKtrue: 764 e = new BooleanExpression(loc, 1); 765 nextToken(); 766 break; 767 768 case TOKfalse: 769 e = new BooleanExpression(loc, 0); 770 nextToken(); 771 break; 772 773 case TOKreal: 774 e = new RealExpression(loc, token.realvalue); 775 nextToken(); 776 break; 777 778 case TOKstring: 779 e = new StringExpression(loc, token..string); 780 token..string = null; // release to gc 781 nextToken(); 782 break; 783 784 case TOKregexp: 785 e = new RegExpLiteral(loc, token..string); 786 token..string = null; // release to gc 787 nextToken(); 788 break; 789 790 case TOKidentifier: 791 e = new IdentifierExpression(loc, token.ident); 792 token.ident = null; // release to gc 793 nextToken(); 794 break; 795 796 case TOKlparen: 797 e = parseParenExp(); 798 break; 799 800 case TOKlbracket: 801 e = parseArrayLiteral(); 802 break; 803 804 case TOKlbrace: 805 /*if(flags & initial) 806 { 807 error(ERR_OBJ_LITERAL_IN_INITIALIZER); 808 nextToken(); 809 return null; 810 }*/ 811 e = parseObjectLiteral(); 812 break; 813 814 case TOKfunction: 815 // if (flags & initial) 816 // goto Lerror; 817 e = parseFunctionLiteral(); 818 break; 819 820 case TOKnew: 821 { Expression newarg; 822 Expression[] arguments; 823 824 nextToken(); 825 newarg = parsePrimaryExp(1); 826 arguments = parseArguments(); 827 e = new NewExp(loc, newarg, arguments); 828 break; } 829 830 default: 831 // Lerror: 832 error(errmsgtbl[ERR_EXPECTED_EXPRESSION], token.toString()); 833 nextToken(); 834 return null; 835 } 836 return parsePostExp(e, innew); 837 } 838 839 Expression[] parseArguments() 840 { 841 Expression[] arguments = null; 842 843 if(token.value == TOKlparen) 844 { 845 nextToken(); 846 if(token.value != TOKrparen) 847 { 848 for(;; ) 849 { 850 Expression arg; 851 852 arg = parseAssignExp(); 853 arguments ~= arg; 854 if(token.value == TOKrparen) 855 break; 856 if(!check(TOKcomma)) 857 break; 858 } 859 } 860 nextToken(); 861 } 862 return arguments; 863 } 864 865 Expression parseArrayLiteral() 866 { 867 Expression e; 868 Expression[] elements; 869 Loc loc; 870 871 //writef("parseArrayLiteral()\n"); 872 loc = currentline; 873 check(TOKlbracket); 874 if(token.value != TOKrbracket) 875 { 876 for(;; ) 877 { 878 if(token.value == TOKcomma) 879 // Allow things like [1,2,,,3,] 880 // Like Explorer 4, and unlike Netscape, the 881 // trailing , indicates another null element. 882 //Netscape was right - FIXED 883 elements ~= cast(Expression)null; 884 else if(token.value == TOKrbracket) 885 { 886 //elements ~= cast(Expression)null; 887 break; 888 } 889 else 890 { 891 e = parseAssignExp(); 892 elements ~= e; 893 if(token.value != TOKcomma) 894 break; 895 } 896 nextToken(); 897 } 898 } 899 check(TOKrbracket); 900 e = new ArrayLiteral(loc, elements); 901 return e; 902 } 903 904 Expression parseObjectLiteral() 905 { 906 Expression e; 907 Field[] fields; 908 Loc loc; 909 910 //writef("parseObjectLiteral()\n"); 911 loc = currentline; 912 check(TOKlbrace); 913 if(token.value == TOKrbrace) 914 nextToken(); 915 else 916 { 917 for(;; ) 918 { 919 Field f; 920 Identifier* ident; 921 switch(token.value){ 922 case TOKidentifier: 923 ident = token.ident; 924 break; 925 case TOKstring,TOKnumber,TOKreal: 926 ident = Identifier.build(token.toString()); 927 break; 928 default: 929 error(ERR_EXPECTED_IDENTIFIER); 930 break; 931 } 932 nextToken(); 933 check(TOKcolon); 934 f = new Field(ident, parseAssignExp()); 935 fields ~= f; 936 if(token.value != TOKcomma) 937 break; 938 nextToken(); 939 if(token.value == TOKrbrace)//allow trailing comma 940 break; 941 } 942 check(TOKrbrace); 943 } 944 e = new ObjectLiteral(loc, fields); 945 return e; 946 } 947 948 Expression parseFunctionLiteral() 949 { 950 FunctionDefinition f; 951 Loc loc; 952 953 loc = currentline; 954 f = cast(FunctionDefinition)parseFunction(1); 955 return new FunctionLiteral(loc, f); 956 } 957 958 Expression parsePostExp(Expression e, int innew) 959 { 960 Loc loc; 961 962 for(;; ) 963 { 964 loc = currentline; 965 //loc = (Loc)token.ptr; 966 switch(token.value) 967 { 968 case TOKdot: 969 nextToken(); 970 if(token.value == TOKidentifier) 971 { 972 e = new DotExp(loc, e, token.ident); 973 } 974 else 975 { 976 error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_2PARAM], ".", token.toString()); 977 return e; 978 } 979 break; 980 981 case TOKplusplus: 982 if(token.sawLineTerminator && !(flags & inForHeader)) 983 goto Linsert; 984 e = new PostIncExp(loc, e); 985 break; 986 987 case TOKminusminus: 988 if(token.sawLineTerminator && !(flags & inForHeader)) 989 { 990 Linsert: 991 // insert automatic semicolon 992 insertSemicolon(token.sawLineTerminator); 993 return e; 994 } 995 e = new PostDecExp(loc, e); 996 break; 997 998 case TOKlparen: 999 { // function call 1000 Expression[] arguments; 1001 1002 if(innew) 1003 return e; 1004 arguments = parseArguments(); 1005 e = new CallExp(loc, e, arguments); 1006 continue; 1007 } 1008 1009 case TOKlbracket: 1010 { // array dereference 1011 Expression index; 1012 1013 nextToken(); 1014 index = parseExpression(); 1015 check(TOKrbracket); 1016 e = new ArrayExp(loc, e, index); 1017 continue; 1018 } 1019 1020 default: 1021 return e; 1022 } 1023 nextToken(); 1024 } 1025 assert(0); 1026 } 1027 1028 Expression parseUnaryExp() 1029 { 1030 Expression e; 1031 Loc loc; 1032 1033 loc = currentline; 1034 switch(token.value) 1035 { 1036 case TOKplusplus: 1037 nextToken(); 1038 e = parseUnaryExp(); 1039 e = new PreExp(loc, IRpreinc, e); 1040 break; 1041 1042 case TOKminusminus: 1043 nextToken(); 1044 e = parseUnaryExp(); 1045 e = new PreExp(loc, IRpredec, e); 1046 break; 1047 1048 case TOKminus: 1049 nextToken(); 1050 e = parseUnaryExp(); 1051 e = new XUnaExp(loc, TOKneg, IRneg, e); 1052 break; 1053 1054 case TOKplus: 1055 nextToken(); 1056 e = parseUnaryExp(); 1057 e = new XUnaExp(loc, TOKpos, IRpos, e); 1058 break; 1059 1060 case TOKnot: 1061 nextToken(); 1062 e = parseUnaryExp(); 1063 e = new NotExp(loc, e); 1064 break; 1065 1066 case TOKtilde: 1067 nextToken(); 1068 e = parseUnaryExp(); 1069 e = new XUnaExp(loc, TOKtilde, IRcom, e); 1070 break; 1071 1072 case TOKdelete: 1073 nextToken(); 1074 e = parsePrimaryExp(0); 1075 e = new DeleteExp(loc, e); 1076 break; 1077 1078 case TOKtypeof: 1079 nextToken(); 1080 e = parseUnaryExp(); 1081 e = new XUnaExp(loc, TOKtypeof, IRtypeof, e); 1082 break; 1083 1084 case TOKvoid: 1085 nextToken(); 1086 e = parseUnaryExp(); 1087 e = new XUnaExp(loc, TOKvoid, IRundefined, e); 1088 break; 1089 1090 default: 1091 e = parsePrimaryExp(0); 1092 break; 1093 } 1094 return e; 1095 } 1096 1097 Expression parseMulExp() 1098 { 1099 Expression e; 1100 Expression e2; 1101 Loc loc; 1102 1103 loc = currentline; 1104 e = parseUnaryExp(); 1105 for(;; ) 1106 { 1107 switch(token.value) 1108 { 1109 case TOKmultiply: 1110 nextToken(); 1111 e2 = parseUnaryExp(); 1112 e = new XBinExp(loc, TOKmultiply, IRmul, e, e2); 1113 continue; 1114 1115 case TOKregexp: 1116 // Rescan as if it was a "/" 1117 rescan(); 1118 goto case; 1119 case TOKdivide: 1120 nextToken(); 1121 e2 = parseUnaryExp(); 1122 e = new XBinExp(loc, TOKdivide, IRdiv, e, e2); 1123 continue; 1124 1125 case TOKpercent: 1126 nextToken(); 1127 e2 = parseUnaryExp(); 1128 e = new XBinExp(loc, TOKpercent, IRmod, e, e2); 1129 continue; 1130 1131 default: 1132 break; 1133 } 1134 break; 1135 } 1136 return e; 1137 } 1138 1139 Expression parseAddExp() 1140 { 1141 Expression e; 1142 Expression e2; 1143 Loc loc; 1144 1145 loc = currentline; 1146 e = parseMulExp(); 1147 for(;; ) 1148 { 1149 switch(token.value) 1150 { 1151 case TOKplus: 1152 nextToken(); 1153 e2 = parseMulExp(); 1154 e = new AddExp(loc, e, e2); 1155 continue; 1156 1157 case TOKminus: 1158 nextToken(); 1159 e2 = parseMulExp(); 1160 e = new XBinExp(loc, TOKminus, IRsub, e, e2); 1161 continue; 1162 1163 default: 1164 break; 1165 } 1166 break; 1167 } 1168 return e; 1169 } 1170 1171 Expression parseShiftExp() 1172 { 1173 Expression e; 1174 Expression e2; 1175 Loc loc; 1176 1177 loc = currentline; 1178 e = parseAddExp(); 1179 for(;; ) 1180 { 1181 uint ircode; 1182 TOK op = token.value; 1183 1184 switch(op) 1185 { 1186 case TOKshiftleft: ircode = IRshl; goto L1; 1187 case TOKshiftright: ircode = IRshr; goto L1; 1188 case TOKushiftright: ircode = IRushr; goto L1; 1189 1190 L1: nextToken(); 1191 e2 = parseAddExp(); 1192 e = new XBinExp(loc, op, ircode, e, e2); 1193 continue; 1194 1195 default: 1196 break; 1197 } 1198 break; 1199 } 1200 return e; 1201 } 1202 1203 Expression parseRelExp() 1204 { 1205 Expression e; 1206 Expression e2; 1207 Loc loc; 1208 1209 loc = currentline; 1210 e = parseShiftExp(); 1211 for(;; ) 1212 { 1213 uint ircode; 1214 TOK op = token.value; 1215 1216 switch(op) 1217 { 1218 case TOKless: ircode = IRclt; goto L1; 1219 case TOKlessequal: ircode = IRcle; goto L1; 1220 case TOKgreater: ircode = IRcgt; goto L1; 1221 case TOKgreaterequal: ircode = IRcge; goto L1; 1222 1223 L1: 1224 nextToken(); 1225 e2 = parseShiftExp(); 1226 e = new CmpExp(loc, op, ircode, e, e2); 1227 continue; 1228 1229 case TOKinstanceof: 1230 nextToken(); 1231 e2 = parseShiftExp(); 1232 e = new XBinExp(loc, TOKinstanceof, IRinstance, e, e2); 1233 continue; 1234 1235 case TOKin: 1236 if(flags & noIn) 1237 break; // disallow 1238 nextToken(); 1239 e2 = parseShiftExp(); 1240 e = new InExp(loc, e, e2); 1241 continue; 1242 1243 default: 1244 break; 1245 } 1246 break; 1247 } 1248 return e; 1249 } 1250 1251 Expression parseEqualExp() 1252 { 1253 Expression e; 1254 Expression e2; 1255 Loc loc; 1256 1257 loc = currentline; 1258 e = parseRelExp(); 1259 for(;; ) 1260 { 1261 uint ircode; 1262 TOK op = token.value; 1263 1264 switch(op) 1265 { 1266 case TOKequal: ircode = IRceq; goto L1; 1267 case TOKnotequal: ircode = IRcne; goto L1; 1268 case TOKidentity: ircode = IRcid; goto L1; 1269 case TOKnonidentity: ircode = IRcnid; goto L1; 1270 1271 L1: 1272 nextToken(); 1273 e2 = parseRelExp(); 1274 e = new CmpExp(loc, op, ircode, e, e2); 1275 continue; 1276 1277 default: 1278 break; 1279 } 1280 break; 1281 } 1282 return e; 1283 } 1284 1285 Expression parseAndExp() 1286 { 1287 Expression e; 1288 Expression e2; 1289 Loc loc; 1290 1291 loc = currentline; 1292 e = parseEqualExp(); 1293 while(token.value == TOKand) 1294 { 1295 nextToken(); 1296 e2 = parseEqualExp(); 1297 e = new XBinExp(loc, TOKand, IRand, e, e2); 1298 } 1299 return e; 1300 } 1301 1302 Expression parseXorExp() 1303 { 1304 Expression e; 1305 Expression e2; 1306 Loc loc; 1307 1308 loc = currentline; 1309 e = parseAndExp(); 1310 while(token.value == TOKxor) 1311 { 1312 nextToken(); 1313 e2 = parseAndExp(); 1314 e = new XBinExp(loc, TOKxor, IRxor, e, e2); 1315 } 1316 return e; 1317 } 1318 1319 Expression parseOrExp() 1320 { 1321 Expression e; 1322 Expression e2; 1323 Loc loc; 1324 1325 loc = currentline; 1326 e = parseXorExp(); 1327 while(token.value == TOKor) 1328 { 1329 nextToken(); 1330 e2 = parseXorExp(); 1331 e = new XBinExp(loc, TOKor, IRor, e, e2); 1332 } 1333 return e; 1334 } 1335 1336 Expression parseAndAndExp() 1337 { 1338 Expression e; 1339 Expression e2; 1340 Loc loc; 1341 1342 loc = currentline; 1343 e = parseOrExp(); 1344 while(token.value == TOKandand) 1345 { 1346 nextToken(); 1347 e2 = parseOrExp(); 1348 e = new AndAndExp(loc, e, e2); 1349 } 1350 return e; 1351 } 1352 1353 Expression parseOrOrExp() 1354 { 1355 Expression e; 1356 Expression e2; 1357 Loc loc; 1358 1359 loc = currentline; 1360 e = parseAndAndExp(); 1361 while(token.value == TOKoror) 1362 { 1363 nextToken(); 1364 e2 = parseAndAndExp(); 1365 e = new OrOrExp(loc, e, e2); 1366 } 1367 return e; 1368 } 1369 1370 Expression parseCondExp() 1371 { 1372 Expression e; 1373 Expression e1; 1374 Expression e2; 1375 Loc loc; 1376 1377 loc = currentline; 1378 e = parseOrOrExp(); 1379 if(token.value == TOKquestion) 1380 { 1381 nextToken(); 1382 e1 = parseAssignExp(); 1383 check(TOKcolon); 1384 e2 = parseAssignExp(); 1385 e = new CondExp(loc, e, e1, e2); 1386 } 1387 return e; 1388 } 1389 1390 Expression parseAssignExp() 1391 { 1392 Expression e; 1393 Expression e2; 1394 Loc loc; 1395 1396 loc = currentline; 1397 e = parseCondExp(); 1398 for(;; ) 1399 { 1400 uint ircode; 1401 TOK op = token.value; 1402 1403 switch(op) 1404 { 1405 case TOKassign: 1406 nextToken(); 1407 e2 = parseAssignExp(); 1408 e = new AssignExp(loc, e, e2); 1409 continue; 1410 1411 case TOKplusass: 1412 nextToken(); 1413 e2 = parseAssignExp(); 1414 e = new AddAssignExp(loc, e, e2); 1415 continue; 1416 1417 case TOKminusass: ircode = IRsub; goto L1; 1418 case TOKmultiplyass: ircode = IRmul; goto L1; 1419 case TOKdivideass: ircode = IRdiv; goto L1; 1420 case TOKpercentass: ircode = IRmod; goto L1; 1421 case TOKandass: ircode = IRand; goto L1; 1422 case TOKorass: ircode = IRor; goto L1; 1423 case TOKxorass: ircode = IRxor; goto L1; 1424 case TOKshiftleftass: ircode = IRshl; goto L1; 1425 case TOKshiftrightass: ircode = IRshr; goto L1; 1426 case TOKushiftrightass: ircode = IRushr; goto L1; 1427 1428 L1: nextToken(); 1429 e2 = parseAssignExp(); 1430 e = new BinAssignExp(loc, op, ircode, e, e2); 1431 continue; 1432 1433 default: 1434 break; 1435 } 1436 break; 1437 } 1438 return e; 1439 } 1440 1441 Expression parseExpression(uint flags = 0) 1442 { 1443 Expression e; 1444 Expression e2; 1445 Loc loc; 1446 uint flags_save; 1447 1448 //writefln("Parser.parseExpression()"); 1449 flags_save = this.flags; 1450 this.flags = flags; 1451 loc = currentline; 1452 e = parseAssignExp(); 1453 while(token.value == TOKcomma) 1454 { 1455 nextToken(); 1456 e2 = parseAssignExp(); 1457 e = new CommaExp(loc, e, e2); 1458 } 1459 this.flags = flags_save; 1460 return e; 1461 } 1462 } 1463 1464 /********************************* ***************************/ 1465