4338602f20756e5145d3824074b0a61ef8054827
[mono.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / Parser.cs
1 //
2 // Parser.cs: Port of Mozilla's Rhino parser.
3 //            This class implements the JScript parser.
4 //
5 // Author:
6 //      Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 //
8 // (C) 2004, Cesar Lopez Nataren
9 // Copyright (C) 2005, Novell Inc (http://novell.com)
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Collections;
34 using System.IO;
35 using System;
36
37 namespace Microsoft.JScript {
38
39         /**
40          * There are three types of functions that can be defined. The first
41          * is a function statement. This is a function appearing as a top-level
42          * statement (i.e., not nested inside some other statement) in either a
43          * script or a function.
44          *
45          * The second is a function expression, which is a function appearing in
46          * an expression except for the third type, which is...
47          *
48          * The third type is a function expression where the expression is the
49          * top-level expression in an expression statement.
50          *
51          * The three types of functions have different treatment and must be
52          * distinquished.
53          */
54         enum FunctionType {
55                 Statement,
56                 Expression,
57                 ExpressionStatement
58         }
59
60         enum ClauseType {
61                 Case,
62                 Default,
63                 CaseAfterDefault
64         }
65
66         internal class Location {
67                 private string source_name;
68                 private int line_number;
69
70                 internal string SourceName {
71                         get { return source_name; }
72                 }
73
74                 internal int LineNumber {
75                         get { return line_number; }
76                 }
77
78                 internal Location (string source_name, int line_number)
79                 {
80                         this.source_name = source_name;
81                         this.line_number = line_number;
82                 }
83         }
84
85         internal class Parser {
86
87                 TokenStream ts;
88                 bool ok; // did the parse encounter an error?
89                 ScriptBlock current_script_or_fn;
90                 int nesting_of_function;
91                 int nesting_of_with;
92                 bool allow_member_expr_as_function_name;
93                 Decompiler decompiler; 
94
95                 internal Parser ()
96                 {
97                 }
98
99                 internal Decompiler CreateDecompiler ()
100                 {
101                         return new Decompiler ();
102                 }
103
104                 /// <summary>
105                 ///   Build a parse tree from a given source_string
106                 /// </summary>
107                 ///
108                 /// <remarks>
109                 ///   return an AST representing the parsed program.
110                 ///    If the parse fails, null will be returned.
111                 /// </remarks>
112                 internal AST Parse (string source_string, string source_location, int line_number)
113                 {
114                         ts = new TokenStream (null, source_string, source_location, line_number);
115                         try {
116                                 return Parse ();
117                         } catch (IOException ex) {
118                                 throw new Exception ("Illegal state exception");
119                         }
120                 }
121
122                 /// <summary>
123                 ///   Build a parse tree from a given source_reader
124                 /// </summary>
125                 ///
126                 /// <remarks>
127                 ///   return an AST representing the parsed program.
128                 ///    If the parse fails, null will be returned.
129                 /// </remarks>
130                 internal AST Parse (StreamReader source_reader, string source_location, int line_number)
131                 {
132                         ts = new TokenStream (source_reader, null, source_location, line_number);
133                         return Parse ();
134                 }
135
136                 void MustMatchToken (int to_match, string message_id)
137                 {
138                         int tt;
139                         if ((tt = ts.GetToken ()) != to_match) {
140                                 ReportError (message_id);
141                                 ts.UnGetToken (tt); // in case the parser decides to continue
142                         }                       
143                 }
144
145                 void ReportError (string message_id)
146                 {
147                         ok = false;
148                         ts.ReportCurrentLineError (message_id);
149                         throw new ParserException ();
150                 }
151         
152                 AST Parse ()
153                 {
154                         decompiler = CreateDecompiler ();
155                         current_script_or_fn = new ScriptBlock (new Location (ts.SourceName, ts.LineNumber));
156                         decompiler.GetCurrentOffset ();
157                         decompiler.AddToken (Token.SCRIPT);
158                         ok = true;
159
160                         try {
161                                 for (;;) {
162                                         ts.allow_reg_exp = true;
163                                         int tt = ts.GetToken ();
164                                         ts.allow_reg_exp = false;
165                                         
166                                         if (tt <= Token.EOF)
167                                                 break;
168
169                                         AST n;
170                                         if (tt == Token.FUNCTION) {
171                                                 try {
172                                                         n = Function (current_script_or_fn, FunctionType.Statement);
173                                                 } catch (ParserException e) {
174                                                         ok = false;
175                                                         break;
176                                                 }
177                                         } else {
178                                                 ts.UnGetToken (tt);
179                                                 n = Statement (current_script_or_fn);
180                                         }
181                                         current_script_or_fn.Add (n);
182                                 }
183                         } catch (StackOverflowException ex) {
184                                 throw new Exception ("Error: too deep parser recursion.");
185                         }
186
187                         if (!ok)
188                                 return null;
189
190                         this.decompiler = null; // It helps GC
191                         return current_script_or_fn;
192                 }
193
194                 internal bool Eof {
195                         get { return ts.EOF; }
196                 }
197
198                 bool InsideFunction {
199                         get { return nesting_of_function != 0; }
200                 }
201
202                 Block ParseFunctionBody (AST parent)
203                 {
204                         ++nesting_of_function;
205                         Block pn = new Block (parent, new Location (ts.SourceName, ts.LineNumber));
206                         try {
207                                 int tt;
208                                 while ((tt = ts.PeekToken ()) > Token.EOF && tt != Token.RC) {
209                                         AST n;
210                                         if (tt == Token.FUNCTION) {
211                                                 ts.GetToken ();
212                                                 n = Function (parent, FunctionType.Statement);
213                                         } else
214                                                 n = Statement (parent);
215                                         pn.Add (n);
216                                 }
217                         } catch (ParserException e) {
218                                 ok = false;
219                         } finally {
220                                 --nesting_of_function;
221                         }
222                         return pn;
223                 }
224
225                 AST Function (AST parent, FunctionType ft)
226                 {
227                         FunctionType synthetic_type = ft;
228                         string name;
229                         AST member_expr = null;
230
231                         if (ts.MatchToken (Token.NAME)) {
232                                 name = ts.GetString;
233                                 if (!ts.MatchToken (Token.LP)) {
234                                         if (allow_member_expr_as_function_name) {
235                                                 // Extension to ECMA: if 'function <name>' does not follow
236                                                 // by '(', assume <name> starts memberExpr
237                                                 // FIXME: is StringLiteral the correct AST to build?
238                                                 decompiler.AddName (name);
239                                                 AST member_expr_head = new StringLiteral (null, name, 
240                                                                           new Location (ts.SourceName, ts.LineNumber));
241                                                 name = "";
242                                                 member_expr = MemberExprTail (parent, false, member_expr_head);
243                                         }
244                                         MustMatchToken (Token.LP, "msg.no.paren.parms");
245                                 }
246                         } else if (ts.MatchToken (Token.LP)) {
247                                 // Anonymous function
248                                 name = "";
249                         } else {
250                                 name = "";
251                                 if (allow_member_expr_as_function_name) {
252                                         // Note that memberExpr can not start with '(' like
253                                         // in function (1+2).toString(), because 'function (' already
254                                         // processed as anonymous function
255                                         member_expr = MemberExpr (parent, false);
256                                 }
257                                 MustMatchToken (Token.LP, "msg.no.paren.parms");
258                         }
259
260                         if (member_expr != null) {
261                                 synthetic_type = FunctionType.Expression;
262                                 decompiler.AddToken (Token.ASSIGN);
263                         }
264                         
265                         bool nested = InsideFunction;
266                         Function fn = CreateFunction (parent, synthetic_type, name);
267
268                         if (nested)
269                                 fn.CheckThis = true;
270                         
271                         if (nested || nesting_of_with > 0) {
272                                 // 1. Nested functions are not affected by the dynamic scope flag
273                                 // as dynamic scope is already a parent of their scope.
274                                 // 2. Functions defined under the with statement also immune to
275                                 // this setup, in which case dynamic scope is ignored in favor
276                                 // of with object.
277                                 fn.IgnoreDynamicScope = true;
278                         }
279
280                         // FIXME: which is old version of Decompiler.MarkFunctionStart
281                         int functionSourceStart = decompiler.MarkFunctionStart ((int) synthetic_type);
282
283                         if (name != "")
284                                 decompiler.AddName (name);
285
286                         ScriptBlock saved_script_or_fn = current_script_or_fn;
287                         int saved_nesting_of_with = nesting_of_with;
288                         nesting_of_with = 0;
289
290                         FormalParameterList _params = new FormalParameterList (new Location (ts.SourceName, ts.LineNumber));
291                         Block body;
292
293                         try {
294                                 decompiler.AddToken (Token.LP);
295                                 if (!ts.MatchToken (Token.RP)) {
296                                         bool first = true;
297                                         do {
298                                                 if (!first)
299                                                         decompiler.AddToken (Token.COMMA);
300                                                 first = false;
301                                                 MustMatchToken (Token.NAME, "msg.no.parm");
302                                                 string s = ts.GetString;
303                                                 _params.Add (s, String.Empty, new Location (ts.SourceName, ts.LineNumber));
304                                                 decompiler.AddName (s);
305                                         } while (ts.MatchToken (Token.COMMA));
306                                         MustMatchToken (Token.RP, "msg.no.paren.after.parms");
307                                 }
308                                 decompiler.AddToken (Token.RP);
309
310                                 MustMatchToken (Token.LC, "msg.no.brace.body");
311                                 decompiler.AddEOL (Token.LC);
312                                 body = ParseFunctionBody (fn);
313                                 MustMatchToken (Token.RC, "msg.no.brace.after.body");
314
315                                 decompiler.AddToken (Token.RC);
316                                 decompiler.MarkFunctionEnd (functionSourceStart);
317
318                                 fn.func_obj.source = decompiler.SourceToString (functionSourceStart);
319
320                                 if (ft != FunctionType.Expression) {
321                                         CheckWellTerminatedFunction ();
322                                         if (member_expr == null)
323                                                 decompiler.AddToken (Token.EOL);
324                                         else
325                                                 decompiler.AddEOL (Token.SEMI);
326                                 }
327                         } finally {
328                                 current_script_or_fn = saved_script_or_fn;
329                                 nesting_of_with = saved_nesting_of_with;
330                         }
331
332                         fn.Init (body, _params);
333                         AST pn;
334
335                         if (member_expr == null) {
336                                 // FIXME
337                                 pn = fn;
338
339                                 // FIXME, research about createExprStatementNoReturn
340                                 if (ft == FunctionType.ExpressionStatement)
341                                         pn = null;
342                         } else {
343                                 // FIXME
344                                 pn = fn;
345                                 pn = new Assign (null, member_expr, pn, JSToken.Assign, false, new Location (ts.SourceName, ts.LineNumber));
346                                 // FIXME, research about createExprStatement
347                                 if (ft != FunctionType.Expression)
348                                         ;
349                         }
350                         return pn;
351                 }
352
353                 Function CreateFunction (AST parent, FunctionType func_type, string name)
354                 {
355                         Function func;
356                         Location location = new Location (ts.SourceName, ts.LineNumber);
357
358                         if (func_type == FunctionType.Statement)
359                                 func = new FunctionDeclaration (parent, name, location);
360                         else if (func_type == FunctionType.Expression)
361                                 func = new FunctionExpression (parent, name, location);
362                         else if (func_type == FunctionType.ExpressionStatement)
363                                 throw new NotImplementedException ();
364                         else
365                                 throw new Exception ("Unknown FunctionType");
366                         return func;
367                 }
368
369                 AST Statements (AST parent)
370                 {
371                         int tt;
372                         Block pn = new Block (parent, new Location (ts.SourceName, ts.LineNumber));
373                         while ((tt = ts.PeekToken ()) > Token.EOF && tt != Token.RC)
374                                 pn.Add (Statement (pn));
375                         return pn;
376                 }
377
378                 AST Condition (AST parent)
379                 {
380                         AST pn;
381                         MustMatchToken (Token.LP, "msg.no.paren.cond");
382                         decompiler.AddToken (Token.LP);
383                         pn = Expr (parent, false);
384                         MustMatchToken (Token.RP, "msg.no.paren.after.cond");
385                         decompiler.AddToken (Token.RP);
386                         return pn;
387                 }
388
389                 void CheckWellTerminated ()
390                 {
391                         int tt = ts.PeekTokenSameLine ();
392                         if (tt == Token.ERROR || tt == Token.EOF || tt == Token.EOL ||
393                             tt == Token.SEMI || tt == Token.RC || tt == Token.FUNCTION)
394                                 return;                 
395                         ReportError ("msg.no.semi.stmt");
396                 }
397
398                 void CheckWellTerminatedFunction ()
399                 {
400                         CheckWellTerminated ();
401                 }
402
403                 string MatchLabel ()
404                 {
405                         int line_number = ts.LineNumber;
406                         string label = null;
407                         int tt;
408                         tt = ts.PeekTokenSameLine ();
409                         if (tt == Token.NAME) {
410                                 ts.GetToken ();
411                                 label = ts.GetString;
412                         }
413                         
414                         if (line_number == ts.LineNumber)
415                                 CheckWellTerminated ();
416                         
417                         return label;
418                 }
419
420                 AST Statement (AST parent)
421                 {
422                         try {
423                                 return StatementHelper (parent);
424                         } catch (ParserException e) {
425                                 // skip to end of statement
426                                 int t;
427                                 do {
428                                         t = ts.GetToken ();
429                                 } while (t != Token.SEMI && t != Token.EOL &&
430                                          t != Token.EOF && t != Token.ERROR);
431                                 // FIXME:
432                                 throw new Exception ("must create expr stm with ");
433                         }
434                 }
435
436                 /**
437                  * Whether the "catch (e: e instanceof Exception) { ... }" syntax
438                  * is implemented.
439                  */
440
441                 AST StatementHelper (AST parent)
442                 {
443                         AST pn = null;
444
445                         // If skipsemi == true, don't add SEMI + EOL to source at the
446                         // end of this statment.  For compound statements, IF/FOR etc.
447                         bool skip_semi = false;
448
449                         int tt;
450                         tt = ts.GetToken ();
451
452                         if (tt == Token.IF) {
453                                 skip_semi = true;
454
455                                 decompiler.AddToken (Token.IF);
456
457                                 AST cond = Condition (parent);
458
459                                 decompiler.AddEOL (Token.LC);
460
461                                 AST if_true = Statement (parent);
462                                 AST if_false = null;
463
464                                 if (ts.MatchToken (Token.ELSE)) {
465                                         decompiler.AddToken (Token.RC);
466                                         decompiler.AddToken (Token.ELSE);
467                                         decompiler.AddEOL (Token.LC);
468                                         if_false = Statement (parent);
469                                 }
470                                 decompiler.AddEOL (Token.RC);
471                                 pn = new If (parent, cond, if_true, if_false, new Location (ts.SourceName, ts.LineNumber));
472                         } else if (tt == Token.SWITCH) {
473                                 skip_semi = true;
474
475                                 decompiler.AddToken (Token.SWITCH);
476
477                                 pn = new Switch (parent, new Location (ts.SourceName, ts.LineNumber));
478                                 Clause cur_case;
479                                 MustMatchToken (Token.LP, "msg.no.paren.switch");
480
481                                 decompiler.AddToken (Token.LP);
482
483                                 ((Switch) pn).exp = Expr (parent, false);
484                                 MustMatchToken (Token.RP, "msg.no.paren.after.switch");
485
486                                 decompiler.AddToken (Token.RP);
487
488                                 MustMatchToken (Token.LC, "msg.no.brace.switch");
489
490                                 decompiler.AddEOL (Token.LC);
491
492                                 ClauseType clause_type = ClauseType.Case;
493
494                                 while ((tt = ts.GetToken ()) != Token.RC && tt != Token.EOF) {
495                                         if (tt == Token.CASE) {
496                                                 decompiler.AddToken (Token.CASE);
497                                                 cur_case = new Clause (pn, new Location (ts.SourceName, ts.LineNumber));
498                                                 cur_case.exp = Expr (pn, false);
499                                                 decompiler.AddEOL (Token.COLON);
500                                                 if (clause_type == ClauseType.Default)
501                                                         clause_type = ClauseType.CaseAfterDefault;
502                                         } else if (tt == Token.DEFAULT) {
503                                                 cur_case = null;
504                                                 clause_type = ClauseType.Default;
505                                                 decompiler.AddToken (Token.DEFAULT);
506                                                 decompiler.AddEOL (Token.COLON);
507                                         } else {
508                                                 cur_case = null;
509                                                 ReportError ("msg.bad.switch");
510                                         }
511                                         MustMatchToken (Token.COLON, "msg.no.colon.case");
512                                         
513                                         while ((tt = ts.PeekToken ()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF) {
514                                                 if (clause_type == ClauseType.Case || clause_type == ClauseType.CaseAfterDefault)
515                                                         cur_case.AddStm (Statement (pn));
516                                                 else if (clause_type == ClauseType.Default)
517                                                         ((Switch) pn).default_clauses.Add (Statement (pn));
518                                         }
519                                         ((Switch) pn).AddClause (cur_case, clause_type);
520                                 }
521                                 decompiler.AddEOL (Token.RC);
522                         } else if (tt == Token.WHILE) {
523                                 skip_semi = true;
524                                 decompiler.AddToken (Token.WHILE);
525                                 While w = new While (new Location (ts.SourceName, ts.LineNumber));
526                                 AST cond = Condition (w);
527                                 decompiler.AddEOL (Token.LC);
528                                 AST body = Statement (w);
529                                 decompiler.AddEOL (Token.RC);
530                                 w.Init (parent, cond, body);
531                                 pn = w;
532                         } else if (tt == Token.DO) {
533                                 decompiler.AddToken (Token.DO);
534                                 decompiler.AddEOL (Token.LC);
535                                 int line_number = ts.LineNumber;
536                                 DoWhile do_while = new DoWhile (new Location (ts.SourceName, line_number));
537                                 AST body = Statement (do_while);
538                                 decompiler.AddToken (Token.RC);
539                                 MustMatchToken (Token.WHILE, "msg.no.while.do");
540                                 decompiler.AddToken (Token.WHILE);
541                                 AST cond = Condition (do_while);
542                                 do_while.Init (parent, body, cond);
543                                 pn  = do_while;
544                         } else if (tt == Token.FOR) {
545                                 skip_semi = true;
546                                 decompiler.AddToken (Token.FOR);
547                                 AST init, cond, incr = null, body;
548
549                                 MustMatchToken (Token.LP, "msg.no.paren.for");
550                                 decompiler.AddToken (Token.LP);
551                                 tt = ts.PeekToken ();
552
553                                 if (tt == Token.SEMI)
554                                         init = null;
555                                 else {
556                                         if (tt == Token.VAR) {
557                                                 // set init to a var list or initial
558                                                 ts.GetToken (); // throw away the 'var' token
559                                                 init = Variables (parent, true);
560                                         } else
561                                                 init = Expr (parent, true);
562                                 }
563                                 
564                                 if (ts.MatchToken (Token.IN)) {
565                                         decompiler.AddToken (Token.IN);
566                                         cond = Expr (parent, false); // 'cond' is the object over which we're iterating
567                                 } else { 
568                                         // ordinary for loop
569                                         MustMatchToken (Token.SEMI, "msg.no.semi.for");
570                                         decompiler.AddToken (Token.SEMI);
571                                         
572                                         if (ts.PeekToken () == Token.SEMI)
573                                                 cond = null; // no loop condition
574                                         else
575                                                 cond = Expr (parent, false);
576
577                                         MustMatchToken (Token.SEMI, "msg.no.semi.for.cond");
578                                         decompiler.AddToken (Token.SEMI);
579
580                                         if (ts.PeekToken () == Token.RP)
581                                                 incr = null;
582                                         else
583                                                 incr = Expr (parent, false);
584                                 }
585
586                                 MustMatchToken (Token.RP, "msg.no.paren.for.ctrl");
587                                 decompiler.AddToken (Token.RP);
588                                 decompiler.AddEOL (Token.LC);
589                                 body = Statement (pn);
590                                 decompiler.AddEOL (Token.RC);
591
592                                 if (incr == null) // cond could be null if 'in obj' got eaten by the init node. 
593                                         pn = new ForIn (parent, init, cond, body, new Location (ts.SourceName, ts.LineNumber));
594                                 else
595                                         pn = new For (parent, init, cond, incr, body, new Location (ts.SourceName, ts.LineNumber));
596                                 body.parent = pn;
597                         } else if (tt == Token.TRY) {
598                                 int line_number = ts.LineNumber;
599                                 AST try_block;
600                                 ArrayList catch_blocks = null;
601                                 AST finally_block = null;
602
603                                 skip_semi = true;
604                                 decompiler.AddToken (Token.TRY);
605                                 decompiler.AddEOL (Token.LC);
606
607                                 try_block = Statement (parent);
608                                 decompiler.AddEOL (Token.RC);
609                                 catch_blocks = new ArrayList ();
610
611                                 bool saw_default_catch = false;
612                                 int peek = ts.PeekToken ();
613
614                                 if (peek == Token.CATCH) {
615                                         while (ts.MatchToken (Token.CATCH)) {
616                                                 if (saw_default_catch)
617                                                         ReportError ("msg.catch.unreachable");
618                                                 decompiler.AddToken (Token.CATCH);
619                                                 MustMatchToken (Token.LP, "msg.no.paren.catch");
620                                                 decompiler.AddToken (Token.LP);
621                                                 MustMatchToken (Token.NAME, "msg.bad.catchcond");
622                                                 string var_name = ts.GetString;
623                                                 decompiler.AddName (var_name);
624                                                 AST catch_cond = null;
625                                                 
626                                                 if (ts.MatchToken (Token.IF)) {
627                                                         decompiler.AddToken (Token.IF);
628                                                         catch_cond = Expr (parent, false);
629                                                 } else
630                                                         saw_default_catch = true;
631                                                 
632                                                 MustMatchToken (Token.RP, "msg.bad.catchcond");
633                                                 decompiler.AddToken (Token.RP);
634                                                 MustMatchToken (Token.LC, "msg.no.brace.catchblock");
635                                                 decompiler.AddEOL (Token.LC);
636
637                                                 catch_blocks.Add (new Catch (var_name, catch_cond, 
638                                                                              Statements (null), parent, new Location (ts.SourceName, line_number)));
639                                                 MustMatchToken (Token.RC, "msg.no.brace.after.body");
640                                                 decompiler.AddEOL (Token.RC);
641                                         }
642                                 } else if (peek != Token.FINALLY)
643                                         MustMatchToken (Token.FINALLY, "msg.try.no.catchfinally");
644                                 
645                                 if (ts.MatchToken (Token.FINALLY)) {
646                                         decompiler.AddToken (Token.FINALLY);
647                                         decompiler.AddEOL (Token.LC);
648                                         finally_block = Statement (parent);
649                                         decompiler.AddEOL (Token.RC);
650                                 }
651                                 pn = new Try (try_block, catch_blocks, finally_block, parent, new Location (ts.SourceName, ts.LineNumber));
652                         } else if (tt == Token.THROW) {
653                                 int line_number = ts.LineNumber;
654                                 decompiler.AddToken (Token.THROW);
655                                 pn = new Throw (Expr (parent, false), new Location (ts.SourceName, ts.LineNumber));
656
657                                 if (line_number == ts.LineNumber)
658                                         CheckWellTerminated ();
659                         } else if (tt == Token.BREAK) {
660                                 decompiler.AddToken (Token.BREAK);
661
662                                 // MatchLabel only matches if there is one
663                                 string label = MatchLabel ();
664
665                                 if (label != null)
666                                         decompiler.AddName (label);
667
668                                 pn = new Break (parent, label, new Location (ts.SourceName, ts.LineNumber));
669                         } else if (tt == Token.CONTINUE) {
670                                 decompiler.AddToken (Token.CONTINUE);
671
672                                 // MatchLabel only matches if there is one
673                                 string label = MatchLabel ();
674
675                                 if (label != null)
676                                         decompiler.AddName (label);
677
678                                 pn = new Continue (parent, label, new Location (ts.SourceName, ts.LineNumber));
679                         } else if (tt == Token.WITH) {
680                                 skip_semi = true;
681                                 decompiler.AddToken (Token.WITH);
682                                 MustMatchToken (Token.LP, "msg.no.paren.with");
683                                 decompiler.AddToken (Token.LP);
684                                 AST obj = Expr (parent, false);
685                                 MustMatchToken (Token.RP, "msg.no.paren.after.with");
686                                 decompiler.AddToken (Token.RP);
687                                 decompiler.AddToken (Token.LC);
688                                 ++nesting_of_with;
689                                 AST body;
690                                 try {
691                                         body = Statement (parent);
692                                 } finally {
693                                         --nesting_of_with;
694                                 }
695                                 decompiler.AddEOL (Token.RC);
696                                 pn = new With (parent, obj, body, new Location (ts.SourceName, ts.LineNumber));
697                         } else if (tt == Token.VAR) {
698                                 int line_number = ts.LineNumber;
699                                 pn = Variables (parent, false);
700                                 if (ts.LineNumber == line_number)
701                                         CheckWellTerminated ();
702                         } else if (tt == Token.RETURN) {
703                                 AST ret_expr = null;
704                                 decompiler.AddToken (Token.RETURN);
705                                 pn = new Return (new Location (ts.SourceName, ts.LineNumber));
706
707                                 if (!InsideFunction)
708                                         ReportError ("msg.bad.return");
709                                 
710                                 /* This is ugly, but we don't want to require a semicolon. */
711                                 ts.allow_reg_exp = true;
712                                 tt = ts.PeekTokenSameLine ();
713                                 ts.allow_reg_exp = false;
714                                 
715                                 int line_number = ts.LineNumber;
716                                 if (tt != Token.EOF && tt != Token.EOL && tt != Token.SEMI && tt != Token.RC) {
717                                         ret_expr = Expr (pn, false);
718                                         if (ts.LineNumber == line_number)
719                                                 CheckWellTerminated ();
720                                 }
721                                 ((Return) pn).Init (parent, ret_expr);
722                         } else if (tt == Token.LC) { 
723                                 skip_semi = true;
724                                 pn = Statements (parent);
725                                 MustMatchToken (Token.RC, "msg.no.brace.block");
726                         } else if (tt == Token.ERROR || tt == Token.EOL || tt == Token.SEMI) {
727                                 // FIXME:
728                                 pn = null;
729                                 skip_semi = true;
730                         } else if (tt == Token.FUNCTION) {
731                                 pn = Function (parent, FunctionType.ExpressionStatement);
732                         } else {
733                                 int last_expr_type = tt;
734                                 int token_number = ts.TokenNumber;
735                                 ts.UnGetToken (tt);
736                                 int line_number = ts.LineNumber;
737
738                                 pn = Expr (parent, false);
739
740                                 if (ts.PeekToken () == Token.COLON) {
741                                         /* check that the last thing the tokenizer returned was a
742                                          * NAME and that only one token was consumed.
743                                          */
744                                         if (last_expr_type != Token.NAME || (ts.TokenNumber != token_number))
745                                                 ReportError ("msg.bad.label");
746                                         
747                                         ts.GetToken (); // eat the colon
748                                         
749                                         string name = ts.GetString;
750
751                                         // bind 'Statement (pn)' to the label
752                                         Labelled labelled = new Labelled (parent, new Location (ts.SourceName, ts.LineNumber));
753                                         labelled.Init (parent, name, Statement (labelled), new Location (ts.SourceName, ts.LineNumber));
754                                         pn = labelled;
755                                         // depend on decompiling lookahead to guess that that
756                                         // last name was a label.
757                                         decompiler.AddEOL (Token.COLON);
758                                         return pn;
759                                 }
760                                 // FIXME:
761                                 // pn = nf.createExprStatement(pn, lineno);
762                                 if (ts.LineNumber == line_number)
763                                         CheckWellTerminated ();
764                         }
765                         ts.MatchToken (Token.SEMI);
766
767                         if (!skip_semi)
768                                 decompiler.AddEOL (Token.SEMI);
769
770                         return pn;
771                 }
772                 
773                 AST Variables (AST parent, bool in_for_init)
774                 {
775                         VariableStatement pn = new VariableStatement (parent, new Location (ts.SourceName, ts.LineNumber));
776                         bool first = true;
777                         decompiler.AddToken (Token.VAR);
778
779                         for (;;) {
780                                 VariableDeclaration name;
781                                 AST init = null;
782                                 MustMatchToken (Token.NAME, "msg.bad.var");
783                                 string s = ts.GetString;
784
785                                 if (!first)
786                                         decompiler.AddToken (Token.COMMA);
787                                 first = false;
788                                 
789                                 decompiler.AddName (s);
790                                 name = new VariableDeclaration (parent, s, null, null, new Location (ts.SourceName, ts.LineNumber));
791
792                                 // ommited check for argument hiding                            
793                                 if (ts.MatchToken (Token.ASSIGN)) {
794                                         decompiler.AddToken (Token.ASSIGN);
795                                         init = AssignExpr (parent, in_for_init);
796                                         name.val = init;
797                                 }
798                                 pn.Add (name);
799
800                                 if (!ts.MatchToken (Token.COMMA))
801                                         break;
802                         }
803                         return pn;
804                 }
805
806                 AST Expr (AST parent, bool in_for_init)
807                 {
808                         Expression pn = new Expression (parent, new Location (ts.SourceName, ts.LineNumber));
809                         AST init = AssignExpr (parent, in_for_init);
810                         pn.Add (init);
811
812                         if (init == null)
813                                 throw new Exception ("Expr, L680, AST is null");
814                         
815                         while (ts.MatchToken (Token.COMMA)) {
816                                 decompiler.AddToken (Token.COMMA);
817                                 pn.Add (AssignExpr (parent, in_for_init));
818                         }
819                         return pn;
820                 }
821
822                 AST AssignExpr (AST parent, bool in_for_init)
823                 {
824                         AST pn = CondExpr (parent, in_for_init);
825                         int tt = ts.PeekToken ();
826
827                         // omitted: "invalid assignment left-hand side" check.
828                         if (tt == Token.ASSIGN) {
829                                 ts.GetToken ();
830                                 decompiler.AddToken (Token.ASSIGN);
831                                 pn = new Assign (parent, pn, AssignExpr (parent, in_for_init), JSToken.Assign, false, new Location (ts.SourceName, ts.LineNumber));
832                                 return pn;
833                         } else if (tt == Token.ASSIGNOP) {
834                                 ts.GetToken ();
835                                 int op = ts.GetOp ();
836                                 decompiler.AddAssignOp (op);
837                                 pn = new Assign (parent, pn, AssignExpr (parent, in_for_init), ToJSToken (op, tt), false, 
838                                          new Location (ts.SourceName, ts.LineNumber));
839                         }
840                         return pn;
841                 }
842
843                 AST CondExpr (AST parent, bool in_for_init)
844                 {
845                         AST if_true;
846                         AST if_false;
847                         AST pn = OrExpr (parent, in_for_init);
848
849                         if (ts.MatchToken (Token.HOOK)) {
850                                 decompiler.AddToken (Token.HOOK);
851                                 if_true = AssignExpr (parent, false);
852                                 MustMatchToken (Token.COLON, "msg.no.colon.cond");
853                                 decompiler.AddToken (Token.COLON);
854                                 if_false = AssignExpr (parent, in_for_init);
855                                 return new Conditional (parent, pn, if_true, if_false, new Location (ts.SourceName, ts.LineNumber));
856                         }
857                         return pn;
858                 }
859
860                 AST OrExpr (AST parent, bool in_for_init)
861                 {
862                         AST pn = AndExpr (parent, in_for_init);
863                         if (ts.MatchToken (Token.OR)) {
864                                 decompiler.AddToken (Token.OR);
865                                 return new Binary (parent, pn, OrExpr (parent, in_for_init), JSToken.LogicalOr, 
866                                            new Location (ts.SourceName, ts.LineNumber));
867                         }
868                         return pn;
869                 }
870
871                 AST AndExpr (AST parent, bool in_for_init)
872                 {
873                         AST pn = BitOrExpr (parent, in_for_init);
874                         if (ts.MatchToken (Token.AND)) {
875                                 decompiler.AddToken (Token.AND);
876                                 return new Binary (parent, pn, AndExpr (parent, in_for_init), JSToken.LogicalAnd,
877                                            new Location (ts.SourceName, ts.LineNumber));
878                         }
879                         return pn;
880                 }
881
882                 AST BitOrExpr (AST parent, bool in_for_init)
883                 {
884                         AST pn = BitXorExpr (parent, in_for_init);
885                         while (ts.MatchToken (Token.BITOR)) {
886                                 decompiler.AddToken (Token.BITOR);
887                                 pn = new Binary (parent, pn, BitXorExpr (parent, in_for_init), JSToken.BitwiseOr,
888                                          new Location (ts.SourceName, ts.LineNumber));
889                         }
890                         return pn;
891                 }
892
893                 AST BitXorExpr (AST parent, bool in_for_init)
894                 {
895                         AST pn = BitAndExpr (parent, in_for_init);
896                         while (ts.MatchToken (Token.BITXOR)) {
897                                 decompiler.AddToken (Token.BITXOR);
898                                 pn = new Binary (parent, pn, BitAndExpr (parent, in_for_init), JSToken.BitwiseXor,
899                                          new Location (ts.SourceName, ts.LineNumber));
900                         }
901                         return pn;
902                 }
903
904                 AST BitAndExpr (AST parent, bool in_for_init)
905                 {
906                         AST pn = EqExpr (parent, in_for_init);
907                         while (ts.MatchToken (Token.BITAND)) {
908                                 decompiler.AddToken (Token.BITAND);
909                                 pn = new Binary (parent, pn, EqExpr (parent, in_for_init), JSToken.BitwiseAnd,
910                                          new Location (ts.SourceName, ts.LineNumber));
911                         }
912                         return pn;
913                 }
914
915                 AST EqExpr (AST parent, bool in_for_init)
916                 {
917                         AST pn = RelExpr (parent, in_for_init);
918                         ArrayList tokens = new ArrayList ();
919                         for (;;) {
920                                 int tt = ts.PeekToken ();
921                                 tokens.Add (tt);
922                                 if (tt == Token.EQ || tt == Token.NE) {
923                                         foreach (int token in tokens)
924                                                 decompiler.AddToken (token);
925                                         tokens.Clear ();
926
927                                         ts.GetToken ();
928                                         pn = new Equality (parent, pn, RelExpr (parent, in_for_init), ToJSToken (tt), 
929                                                    new Location (ts.SourceName, ts.LineNumber));
930                                         continue;
931                                 } else if (tt == Token.SHEQ || tt == Token.SHNE) {
932                                         foreach (int token in tokens)
933                                                 decompiler.AddToken (token);
934                                         tokens.Clear ();
935                                         
936                                         ts.GetToken ();
937                                         pn = new StrictEquality (parent, pn, RelExpr (parent, in_for_init), ToJSToken (tt), new Location (ts.SourceName, ts.LineNumber));
938                                         continue;
939                                 }                               
940                                 break;
941                         }
942                         return pn;
943                 }
944
945                 AST RelExpr (AST parent, bool in_for_init)
946                 {       
947                         AST pn = ShiftExpr (parent);
948                         for (;;) {
949                                 int tt = ts.PeekToken ();
950                                 if (tt == Token.IN) {
951                                         if (in_for_init)
952                                                 break;
953                                         else {
954                                                 ts.GetToken ();
955                                                 decompiler.AddToken (tt);
956                                                 pn = new Relational (parent, pn, ShiftExpr (parent), ToJSToken (tt), new Location (ts.SourceName, ts.LineNumber));
957                                                 continue;
958                                         }
959                                 } else if (tt == Token.INSTANCEOF || tt == Token.LE || tt == Token.LT || tt == Token.GE || tt == Token.GT) {
960                                         ts.GetToken ();
961                                         decompiler.AddToken (tt);
962                                         pn = new Relational (parent, pn, ShiftExpr (parent), ToJSToken (tt), new Location (ts.SourceName, ts.LineNumber));
963                                         continue;
964                                 }
965                                 break;
966                         }
967                         return pn;
968                 }
969
970                 AST ShiftExpr (AST parent)
971                 {
972                         AST pn = AddExpr (parent);
973                         for (;;) {
974                                 int tt = ts.PeekToken ();
975                                 if (tt == Token.LSH || tt == Token.URSH || tt == Token.RSH) {
976                                         ts.GetToken ();
977                                         decompiler.AddToken (tt);
978                                         
979                                         JSToken op = JSToken.LeftShift;
980                                         if (tt == Token.RSH)
981                                                 op = JSToken.RightShift;
982                                         else if (tt == Token.URSH)
983                                                 op = JSToken.UnsignedRightShift;
984
985                                         pn = new Binary (parent, pn, AddExpr (parent), op,
986                                                  new Location (ts.SourceName, ts.LineNumber));
987                                         continue;
988                                 }
989                                 break;
990                         }
991                         return pn;
992                 }
993
994                 AST AddExpr (AST parent)
995                 {
996                         AST pn = MulExpr (parent);
997                         for (;;) {
998                                 int tt = ts.PeekToken ();
999                                 if (tt == Token.ADD || tt == Token.SUB) {
1000                                         ts.GetToken ();
1001                                         decompiler.AddToken (tt);
1002                                         pn = new Binary (parent, pn, MulExpr (parent), ToJSToken (tt),
1003                                                  new Location (ts.SourceName, ts.LineNumber));
1004                                         continue;
1005                                 }
1006                                 break;
1007                         }
1008                         return pn;
1009                 }
1010
1011                 AST MulExpr (AST parent)
1012                 {
1013                         AST pn = UnaryExpr (parent);
1014                         for (;;) {
1015                                 int tt = ts.PeekToken ();
1016                                 if (tt == Token.MUL || tt == Token.DIV || tt == Token.MOD) {
1017                                         ts.GetToken ();
1018                                         decompiler.AddToken (tt);
1019                                         pn = new Binary (parent, pn, UnaryExpr (parent), ToJSToken (tt),
1020                                                  new Location (ts.SourceName, ts.LineNumber));
1021                                         continue;
1022                                 }
1023                                 break;
1024                         }
1025                         return pn;
1026                 }
1027                 
1028                 AST UnaryExpr (AST parent)
1029                 {
1030                         int tt;
1031
1032                         ts.allow_reg_exp = true;
1033                         tt = ts.GetToken ();
1034                         ts.allow_reg_exp = false;
1035
1036                         if (tt == Token.VOID || tt == Token.NOT || tt == Token.BITNOT || tt == Token.TYPEOF ||
1037                             tt == Token.ADD || tt == Token.SUB || tt == Token.DELPROP) {
1038                                 if (tt == Token.VOID || tt == Token.NOT || tt == Token.BITNOT || tt == Token.TYPEOF)
1039                                         decompiler.AddToken (tt);
1040                                 else if (tt == Token.ADD)
1041                                         decompiler.AddToken (Token.POS);
1042                                 else if (tt == Token.SUB)
1043                                         decompiler.AddToken (Token.NEG);
1044                                 else 
1045                                         decompiler.AddToken (tt);
1046
1047                                 Unary u = new Unary (parent, ToJSToken (tt), new Location (ts.SourceName, ts.LineNumber));
1048                                 u.operand = UnaryExpr (u);
1049                                 return u;
1050                         } else if (tt == Token.INC || tt == Token.DEC) {
1051                                 decompiler.AddToken (tt);
1052                                 return new PostOrPrefixOperator (parent, MemberExpr (parent, true), ToJSToken (tt), true,
1053                                                          new Location (ts.SourceName, ts.LineNumber));
1054                         } else if (tt == Token.ERROR) {
1055                                 ;
1056                         } else {
1057                                 ts.UnGetToken (tt);
1058                                 int line_number = ts.LineNumber;
1059                                 
1060                                 AST pn = MemberExpr (parent, true);
1061                                 
1062                                 /* don't look across a newline boundary for a postfix incop.
1063
1064                                 * the rhino scanner seems to work differently than the js
1065                                 * scanner here; in js, it works to have the line number check
1066                                 * precede the peekToken calls.  It'd be better if they had
1067                                 * similar behavior...
1068                                 */
1069                                 int peeked;                             
1070                                 if (((peeked = ts.PeekToken ()) == Token.INC || peeked == Token.DEC) && ts.LineNumber == line_number) {
1071                                         int pf = ts.GetToken ();
1072                                         decompiler.AddToken (pf);
1073                                         return new PostOrPrefixOperator (parent, pn, ToJSToken (peeked), false,
1074                                                                  new Location (ts.SourceName, ts.LineNumber));
1075                                 }
1076                                 return pn;
1077                         }
1078                         return new StringLiteral (null, "Error", new Location (ts.SourceName, ts.LineNumber));  // Only reached on error.  Try to continue.
1079                 }
1080
1081                 JSToken ToJSToken (int tt)
1082                 {
1083                         if (tt == Token.DELPROP)
1084                                 return JSToken.Delete;
1085                         else if (tt == Token.VOID)
1086                                 return JSToken.Void;
1087                         else if (tt == Token.TYPEOF)
1088                                 return JSToken.Typeof;
1089                         else if (tt == Token.INC)
1090                                 return JSToken.Increment;
1091                         else if (tt == Token.DEC)
1092                                 return JSToken.Decrement;
1093                         else if (tt == Token.ADD)
1094                                 return JSToken.Plus;
1095                         else if (tt == Token.SUB)
1096                                 return JSToken.Minus;
1097                         else if (tt == Token.BITNOT)
1098                                 return JSToken.BitwiseNot;
1099                         else if (tt == Token.NOT)
1100                                 return JSToken.LogicalNot;
1101                         else if (tt == Token.EQ)
1102                                 return JSToken.Equal;
1103                         else if (tt == Token.NE)
1104                                 return JSToken.NotEqual;
1105                         else if (tt == Token.SHEQ)
1106                                 return JSToken.StrictEqual;
1107                         else if (tt == Token.SHNE)
1108                                 return JSToken.StrictNotEqual;
1109                         else if (tt == Token.MUL)
1110                                 return JSToken.Multiply;
1111                         else if (tt == Token.DIV)
1112                                 return JSToken.Divide;
1113                         else if (tt == Token.MOD)
1114                                 return JSToken.Modulo;
1115                         else if (tt == Token.IN)
1116                                 return JSToken.In;
1117                         else if (tt == Token.INSTANCEOF)
1118                                 return JSToken.Instanceof;
1119                         else if (tt == Token.LE)
1120                                 return JSToken.LessThanEqual;
1121                         else if (tt == Token.LT)
1122                                 return JSToken.LessThan;
1123                         else if (tt == Token.GE)
1124                                 return JSToken.GreaterThanEqual;
1125                         else if (tt == Token.GT)
1126                                 return JSToken.GreaterThan;
1127                         else
1128                                 throw new NotImplementedException ();
1129                 }
1130
1131                 //
1132                 // Takes care of +=, -=
1133                 //
1134                 JSToken ToJSToken (int left, int right)
1135                 {
1136                         if (right == Token.ASSIGNOP) {
1137                                 if  (left == Token.ADD)
1138                                         return JSToken.PlusAssign;
1139                                 else if (left == Token.SUB)
1140                                         return JSToken.MinusAssign;
1141                                 else if (left == Token.MUL)
1142                                         return JSToken.MultiplyAssign;
1143                                 else if (left == Token.DIV)
1144                                         return JSToken.DivideAssign;
1145                                 else if (left == Token.BITAND)
1146                                         return JSToken.BitwiseAndAssign;
1147                                 else if (left == Token.BITOR)
1148                                         return JSToken.BitwiseOrAssign;
1149                                 else if (left == Token.BITXOR)
1150                                         return JSToken.BitwiseXorAssign;
1151                                 else if (left == Token.MOD)
1152                                         return JSToken.ModuloAssign;
1153                                 else if (left == Token.LSH)
1154                                         return JSToken.LeftShiftAssign;
1155                                 else if (left == Token.RSH)
1156                                         return JSToken.RightShiftAssign;
1157                                 else if (left == Token.URSH)
1158                                         return JSToken.UnsignedRightShiftAssign;
1159                         }
1160                         throw new NotImplementedException ();
1161                 }
1162
1163                 void ArgumentList (AST parent, ICallable list) 
1164                 {
1165                         bool matched;
1166                         ts.allow_reg_exp = true;
1167                         matched = ts.MatchToken (Token.RP);
1168                         ts.allow_reg_exp = false;
1169
1170                         if (!matched) {
1171                                 bool first = true;
1172                                 do {
1173                                         if (!first)
1174                                                 decompiler.AddToken (Token.COMMA);
1175                                         first = false;
1176                                         list.AddArg (AssignExpr (parent, false));
1177                                 } while (ts.MatchToken (Token.COMMA));                          
1178                                 MustMatchToken (Token.RP, "msg.no.paren.arg");
1179                         }
1180                         decompiler.AddToken (Token.RP);
1181                 }
1182
1183                 AST MemberExpr (AST parent, bool allow_call_syntax)
1184                 {
1185                         int tt;
1186                         AST pn;
1187
1188                         /* Check for new expressions. */
1189                         ts.allow_reg_exp = true;
1190                         tt = ts.PeekToken ();
1191                         ts.allow_reg_exp = false;
1192                         
1193                         if (tt == Token.NEW) {
1194                                 /* Eat the NEW token. */
1195                                 ts.GetToken ();
1196                                 decompiler.AddToken (Token.NEW);
1197
1198                                 /* Make a NEW node to append to. */
1199                                 pn = new New (parent, MemberExpr (parent, false), new Location (ts.SourceName, ts.LineNumber));
1200
1201                                 if (ts.MatchToken (Token.LP)) {
1202                                         decompiler.AddToken (Token.LP);
1203                                         ArgumentList (parent, (ICallable) pn);
1204                                 }
1205
1206                                 /* XXX there's a check in the C source against
1207                                  * "too many constructor arguments" - how many
1208                                  * do we claim to support?
1209                                  */
1210
1211                                 /* Experimental syntax:  allow an object literal to follow a new expression,
1212                                  * which will mean a kind of anonymous class built with the JavaAdapter.
1213                                  * the object literal will be passed as an additional argument to the constructor.
1214                                  */
1215
1216                                 tt = ts.PeekToken ();
1217                                 if (tt == Token.LC)
1218                                         pn = PrimaryExpr (parent);
1219                         } else
1220                                 pn = PrimaryExpr (parent);
1221                         return MemberExprTail (pn, allow_call_syntax, pn);
1222                 }
1223
1224                 AST MemberExprTail (AST parent, bool allow_call_syntax, AST pn)
1225                 {
1226                         int tt;
1227
1228                         while ((tt = ts.GetToken ()) > Token.EOF) {
1229                                 if (tt == Token.DOT) {
1230                                         decompiler.AddToken (Token.DOT);
1231                                         MustMatchToken (Token.NAME, "msg.no.name.after.dot");
1232                                         string s = ts.GetString;
1233                                         decompiler.AddName (s);
1234                                         // FIXME: is 'new Identifier' appropriate here?
1235                                         pn = new Binary (parent, pn, 
1236                                                  new Identifier (parent, ts.GetString, new Location (ts.SourceName, ts.LineNumber)),
1237                                                  JSToken.AccessField, new Location (ts.SourceName, ts.LineNumber));
1238                                 } else if (tt == Token.LB) {
1239                                         decompiler.AddToken (Token.LB);
1240                                         Binary b = new Binary (parent, pn, JSToken.LeftBracket, 
1241                                                        new Location (ts.SourceName, ts.LineNumber));
1242                                         b.right = Expr (b, false);
1243                                         pn = b;
1244                                         MustMatchToken (Token.RB, "msg.no.bracket.index");
1245                                         decompiler.AddToken (Token.RB);
1246                                 } else if (allow_call_syntax && tt == Token.LP) {
1247                                         /* make a call node */
1248                                         decompiler.AddToken (Token.LP);
1249                                         pn = new Call (parent, pn, new Location (ts.SourceName, ts.LineNumber));
1250                                         
1251                                         /* Add the arguments to pn, if any are supplied. */
1252                                         ArgumentList (parent, (ICallable) pn);
1253                                 } else {
1254                                         ts.UnGetToken (tt);
1255                                         break;
1256                                 }
1257                         }
1258                         return pn;
1259                 }
1260
1261                 AST PrimaryExpr (AST parent)
1262                 {
1263                         int tt;
1264                         AST pn;
1265
1266                         ts.allow_reg_exp = true;
1267                         tt = ts.GetToken ();
1268                         ts.allow_reg_exp = false;
1269
1270                         if (tt == Token.FUNCTION) {
1271                                 return Function (parent, FunctionType.Expression);
1272                         } else if (tt == Token.LB) {
1273                                 ASTList elems = new ASTList (parent, new Location (ts.SourceName, ts.LineNumber));
1274                                 int skip_count = 0;
1275                                 decompiler.AddToken (Token.LB);
1276                                 bool after_lb_or_comma = true;
1277                                 for (;;) {
1278                                         ts.allow_reg_exp = true;
1279                                         tt = ts.PeekToken ();
1280                                         ts.allow_reg_exp = false;
1281                                         
1282                                         if (tt == Token.COMMA) {
1283                                                 ts.GetToken ();
1284                                                 decompiler.AddToken (Token.COMMA);
1285                                                 if (!after_lb_or_comma) 
1286                                                         after_lb_or_comma = true;
1287                                                 else {
1288                                                         elems.Add (null);
1289                                                         ++skip_count;
1290                                                 }
1291                                         } else if (tt == Token.RB) {
1292                                                 ts.GetToken ();
1293                                                 decompiler.AddToken (Token.RB);
1294                                                 break;
1295                                         } else {
1296                                                 if (!after_lb_or_comma) 
1297                                                         ReportError ("msg.no.bracket.arg");
1298                                                 elems.Add (AssignExpr (parent, false));
1299                                                 after_lb_or_comma = false;
1300                                         }
1301                                 }
1302                                 // FIXME: pass a real Context
1303                                 return new ArrayLiteral (null, elems, skip_count, new Location (ts.SourceName, ts.LineNumber));
1304                         } else if (tt == Token.LC) {
1305                                 Location location = new Location (ts.SourceName, ts.LineNumber);
1306                                 ArrayList elems = new ArrayList ();
1307                                 decompiler.AddToken (Token.LC);
1308
1309                                 if (!ts.MatchToken (Token.RC)) {
1310                                         bool first = true;
1311                                         
1312                                         commaloop: {
1313                                         do {
1314                                                 ObjectLiteralItem property;
1315
1316                                                 if (!first)
1317                                                         decompiler.AddToken (Token.COMMA);
1318                                                 else
1319                                                         first = false;
1320                                                 
1321                                                 tt = ts.GetToken ();
1322                                                 
1323                                                 if (tt == Token.NAME || tt == Token.STRING) {
1324                                                         string s = ts.GetString;
1325                                                         if (tt == Token.NAME)
1326                                                                 decompiler.AddName (s);
1327                                                         else
1328                                                                 decompiler.AddString (s);
1329                                                         property = new ObjectLiteralItem (s);
1330                                                 } else if (tt == Token.NUMBER) {
1331                                                         double n = ts.GetNumber;
1332                                                         decompiler.AddNumber (n);
1333                                                         property = new ObjectLiteralItem (n);
1334                                                 } else if (tt == Token.RC) {
1335                                                         // trailing comma is OK
1336                                                         ts.UnGetToken (tt);
1337                                                         goto leave_commaloop;
1338                                                 } else {
1339                                                         ReportError ("msg.bad.prop");
1340                                                         goto leave_commaloop;
1341                                                 }
1342                                                 MustMatchToken (Token.COLON, "msg.no.colon.prop");
1343                                                 // OBJLIT is used as ':' in object literal for
1344                                                 // decompilation to solve spacing ambiguity.
1345                                                 decompiler.AddToken (Token.OBJECTLIT);
1346                                                 property.exp = AssignExpr (parent, false);
1347                                                 elems.Add (property);
1348                                         } while (ts.MatchToken (Token.COMMA));
1349                                         MustMatchToken (Token.RC, "msg.no.brace.prop");
1350                                         }
1351                                         leave_commaloop:
1352                                         ;
1353                                 }
1354                                 return new ObjectLiteral (elems, location);
1355                         } else if (tt == Token.LP) {
1356                                 decompiler.AddToken (Token.LP);
1357                                 pn = Expr (parent, false);
1358                                 decompiler.AddToken (Token.RP);
1359                                 MustMatchToken (Token.RP, "msg.no.paren");
1360                                 decompiler.AddToken (Token.RP);
1361                                 return pn;
1362                         } else if (tt == Token.NAME) {
1363                                 string name = ts.GetString;
1364                                 decompiler.AddName (name);
1365                                 return new Identifier (parent, name, new Location (ts.SourceName, ts.LineNumber));
1366                         } else if (tt == Token.NUMBER) {
1367                                 double n = ts.GetNumber;
1368                                 decompiler.AddNumber (n);
1369                                 return new NumericLiteral (parent, n, new Location (ts.SourceName, ts.LineNumber));
1370                         } else if (tt == Token.STRING) {
1371                                 string s = ts.GetString;
1372                                 decompiler.AddString (s);
1373                                 return new StringLiteral (null, s, new Location (ts.SourceName, ts.LineNumber));
1374                         } else if (tt == Token.REGEXP) {
1375                                 string flags = ts.reg_exp_flags;
1376                                 ts.reg_exp_flags = null;
1377                                 string re = ts.GetString;
1378                                 decompiler.AddRegexp (re, flags);
1379                                 return new RegExpLiteral (parent, re, flags, new Location (ts.SourceName, ts.LineNumber));
1380                         } else if (tt == Token.NULL) {
1381                                 decompiler.AddToken (tt);
1382                                 // FIXME, build the null object;
1383                                 return null;
1384                         } else if (tt ==  Token.THIS) {
1385                                 decompiler.AddToken (tt);
1386                                 return new This (parent, new Location (ts.SourceName, ts.LineNumber));
1387                         } else if (tt == Token.FALSE || tt == Token.TRUE) {
1388                                 decompiler.AddToken (tt);
1389                                 bool v;
1390                                 if (tt == Token.FALSE)
1391                                         v = false;
1392                                 else
1393                                         v = true;
1394                                 return new BooleanLiteral (null, v, new Location (ts.SourceName, ts.LineNumber));
1395                         } else if (tt == Token.RESERVED) {
1396                                 ReportError ("msg.reserved.id");
1397                         } else if (tt == Token.ERROR) {
1398                                 /* the scanner or one of its subroutines reported the error. */
1399                         } else
1400                                 ReportError ("msg.syntax");
1401                         return null; // should never reach here
1402                 }
1403         }
1404 }