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