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