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