f04e9b64b76813bfe5df25a49beba74f30efd7f7
[mono.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / Statement.cs
1 // 
2 // Statement.cs:
3 //
4 // Author:
5 //      Cesar Octavio Lopez Nataren
6 //
7 // (C) 2003, 2004 Cesar Octavio Lopez Nataren, <cesar@ciencias.unam.mx>
8 // Copyright (C) 2005 Novell Inc (http://novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Text;
34 using System.Reflection;
35 using System.Reflection.Emit;
36 using System.Collections;
37
38 namespace Microsoft.JScript {
39
40         internal interface ICanModifyContext {
41                 //
42                 // Populate the symbol table before resolving references
43                 //
44                 void PopulateContext (Environment env, string ns);
45                 void EmitDecls (EmitContext ec);
46         }
47
48         internal class If : AST, ICanModifyContext {
49
50                 internal AST cond, true_stm, false_stm;
51
52                 internal If (AST parent, AST condition, AST true_stm, AST false_stm, Location location)
53                         : base (parent, location)
54                 {
55                         this.cond = condition;
56                         this.true_stm = true_stm;
57                         this.false_stm = false_stm;
58                 }
59
60                 public override string ToString ()
61                 {
62                         StringBuilder sb = new StringBuilder ();
63
64                         if (cond != null)
65                                 sb.Append (cond.ToString ());
66                         if (true_stm != null)
67                                 sb.Append (true_stm.ToString ());
68                         if (false_stm != null)
69                                 sb.Append (false_stm.ToString ());
70                         
71                         return sb.ToString ();
72                 }
73
74                 void ICanModifyContext.PopulateContext (Environment env, string ns)
75                 {
76                         if (true_stm is ICanModifyContext)
77                                 ((ICanModifyContext) true_stm).PopulateContext (env, ns);
78
79                         if (false_stm is ICanModifyContext)
80                                 ((ICanModifyContext) false_stm).PopulateContext (env, ns);
81                 }
82                 
83                 void ICanModifyContext.EmitDecls (EmitContext ec)
84                 {
85                         if (true_stm is ICanModifyContext)
86                                 ((ICanModifyContext) true_stm).EmitDecls (ec);
87
88                         if (false_stm is ICanModifyContext)
89                                 ((ICanModifyContext) false_stm).EmitDecls (ec);
90                 }
91
92                 internal override bool Resolve (Environment env)
93                 {
94                         bool r = true;
95
96                         if (cond != null)
97                                 if (cond is Exp)
98                                         r &= ((Exp) cond).Resolve (env, false);
99
100                         if (true_stm != null)
101                                 if (true_stm is Exp)
102                                         r &= ((Exp) true_stm).Resolve (env, true);
103                                 else
104                                         r &= true_stm.Resolve (env);
105
106                         if (false_stm != null)
107                                 if (false_stm is Exp)
108                                         r &= ((Exp) false_stm).Resolve (env, true);
109                                 else
110                                         r &= false_stm.Resolve (env);
111                         return r;
112                 }
113
114                 internal override void Emit (EmitContext ec)
115                 {
116                         ILGenerator ig = ec.ig;
117                         Label false_lbl = ig.DefineLabel ();
118                         Label merge_lbl = ig.DefineLabel ();
119                         CodeGenerator.fall_true (ec, cond, false_lbl);
120                         CodeGenerator.EmitBox (ig, cond);
121                         if (true_stm != null)
122                                 true_stm.Emit (ec);
123                         ig.Emit (OpCodes.Br, merge_lbl);
124                         ig.MarkLabel (false_lbl);
125                         if (false_stm != null)
126                                 false_stm.Emit (ec);                    
127                         ig.MarkLabel (merge_lbl);
128                 }
129
130                 internal override void PropagateParent (AST parent)
131                 {
132                         base.PropagateParent (parent);
133                         true_stm.PropagateParent (this);
134                         false_stm.PropagateParent (this);
135                 }
136         }
137
138         abstract class Jump : AST {
139                 protected string label = String.Empty;
140                 protected object binding;
141                 
142                 internal Jump (AST parent, Location location)
143                         : base (parent, location)
144                 {
145                 }
146
147                 bool IsLabel (object binding)
148                 {
149                         return binding.GetType () == typeof (Labelled);
150                 }               
151
152                 protected bool ValidLabel ()
153                 {
154                         binding = SemanticAnalyser.GetLabel (label);
155                         if (binding == null || !IsLabel (binding))
156                                 throw new Exception ("error JS1026: Label not found");
157                         return true;
158                 }
159
160                 internal override void PropagateParent (AST parent)
161                 {
162                         base.PropagateParent (parent);
163                 }
164         }
165
166         internal class Continue : Jump {
167                 internal Continue (AST parent, string label, Location location)
168                         : base (parent, location)
169                 {
170                         this.label += label;
171                 }
172
173                 internal override bool Resolve (Environment env)
174                 {
175                         if (!InLoop)
176                                 throw new Exception ("A continue can't be outside a iteration stm");
177                         if (label != String.Empty)
178                                 return ValidLabel ();
179                         return true;
180                 }
181
182                 internal override void Emit (EmitContext ec)
183                 {
184                         if (label == String.Empty) {
185                                 ec.ig.Emit (OpCodes.Br, ec.LoopBegin);
186                                 return;
187                         }
188                         ec.ig.Emit (OpCodes.Br, (binding as Labelled).InitAddrs);
189                 }
190         }
191
192         internal class Break : Jump {
193
194                 internal Break (AST parent, string label, Location location)
195                         : base (parent, location)
196                 {
197                         this.label += label;
198                 }
199
200                 internal override bool Resolve (Environment env)
201                 {
202                         if (!InLoop && !InSwitch)
203                                 throw new Exception ("A break statement can't be outside a switch or iteration stm");
204                         if (label != String.Empty)
205                                 return ValidLabel ();
206                         return true;
207                 }
208
209                 internal override void Emit (EmitContext ec)
210                 {
211                         if (label == String.Empty) {
212                                 ec.ig.Emit (OpCodes.Br, ec.LoopEnd);
213                                 return;
214                         }
215                         ec.ig.Emit (OpCodes.Br, (binding as Labelled).EndAddrs);
216                 }
217
218                 internal override void PropagateParent (AST parent)
219                 {
220                         base.PropagateParent (parent);
221                 }
222         }
223
224         internal class NotVoidReturnEventArgs : EventArgs {
225         }
226                 
227         internal delegate void NotVoidReturnEventHandler (object sender, NotVoidReturnEventArgs args);
228         
229         internal class Return : AST, ICanModifyContext {
230
231                 internal AST expression;
232                 private bool exp_returns_void = false;
233                 public event NotVoidReturnEventHandler not_void_return;
234         
235                 internal Return (Location location)
236                         : base (null, location)
237                 {
238                 }
239                 
240                 internal void OnNotVoidReturn (NotVoidReturnEventArgs args)
241                 {
242                         if (not_void_return != null)
243                                 not_void_return (this, args);
244                 }
245
246                 internal void Init (AST parent, AST exp)
247                 {
248                         this.parent = parent;
249                         expression = exp;
250                         Function cont_func = GetContainerFunction;
251                         this.not_void_return = new NotVoidReturnEventHandler (cont_func.NotVoidReturnHappened);
252                 }
253
254                 public override string ToString ()
255                 {
256                         if (expression != null)
257                                 return expression.ToString ();
258                         else 
259                                 return String.Empty;
260                 }
261
262                 void ICanModifyContext.PopulateContext (Environment env, string ns)
263                 {
264                         if (expression is ICanModifyContext)
265                                 ((ICanModifyContext) expression).PopulateContext (env, ns);
266                 }
267
268                 void ICanModifyContext.EmitDecls (EmitContext ec)
269                 {
270                         if (expression is ICanModifyContext)
271                                 ((ICanModifyContext) expression).EmitDecls (ec);
272                 }
273
274                 internal override bool Resolve (Environment env)
275                 {
276                         if (!InFunction)
277                                 throw new Exception ("error JS1018: 'return' statement outside of function");
278                         if (expression != null) {
279                                 if (expression is Expression) {
280                                         AST ast = ((Expression) expression).Last;
281                                         if (ast is Call) {
282                                                 Call call = (Call) ast;
283                                                 if (call.member_exp is Identifier) {
284                                                         object obj = env.Get (String.Empty, ((Identifier) call.member_exp).name);
285                                                         if (obj is Function)
286                                                                 exp_returns_void = ((Function) obj).HandleReturnType == typeof (void);
287                                                 }
288                                         }
289                                 }                                       
290                                 OnNotVoidReturn (null);
291                                 return expression.Resolve (env);
292                         } else 
293                                 return true;
294                 }
295
296                 internal override void Emit (EmitContext ec)
297                 {
298                         ILGenerator ig = ec.ig;
299                         Label lbl = ig.DefineLabel ();
300                         LocalBuilder loc = null;
301
302                         if (expression != null) {
303                                 expression.Emit (ec);
304                                 loc = ig.DeclareLocal (typeof (object));
305
306                                 if (exp_returns_void)
307                                         ig.Emit (OpCodes.Ldnull);
308
309                                 ig.Emit (OpCodes.Stloc, loc);
310                         }
311                                          
312                         ig.Emit (OpCodes.Br, lbl);
313                         ig.MarkLabel (lbl);
314
315                         if (loc != null)
316                                 ig.Emit (OpCodes.Ldloc, loc);
317                 }
318         }
319
320         internal class DoWhile : AST, ICanModifyContext {
321
322                 AST stm, exp;
323
324                 internal DoWhile (Location location)
325                         : base (null, location)
326                 {
327                 }
328
329                 internal void Init (AST parent, AST stm, AST exp)
330                 {
331                         this.parent = parent;
332                         this.stm = stm;
333                         this.exp = exp;
334                 }
335
336                 void ICanModifyContext.PopulateContext (Environment env, string ns)
337                 {
338                         if (stm is ICanModifyContext)
339                                 ((ICanModifyContext) stm).PopulateContext (env, ns);
340                 }
341
342                 void ICanModifyContext.EmitDecls (EmitContext ec)
343                 {
344                         if (stm is ICanModifyContext)
345                                 ((ICanModifyContext) stm).EmitDecls (ec);
346                 }
347
348                 internal override bool Resolve (Environment env)
349                 {
350                         bool r = true;
351
352                         if (stm != null)
353                                 r &= stm.Resolve (env);
354                         if (exp != null)
355                                 r &= exp.Resolve (env);
356                         return r;
357                 }
358
359                 internal override void Emit (EmitContext ec)
360                 {
361                         ILGenerator ig = ec.ig;
362                         Label old_begin = ec.LoopBegin;
363                         Label old_end = ec.LoopEnd;
364                         Label body_label = ig.DefineLabel ();
365
366                         ec.LoopBegin = ig.DefineLabel ();
367                         ec.LoopEnd = ig.DefineLabel ();
368
369                         ig.MarkLabel (body_label);
370
371                         if (stm != null)
372                                 stm.Emit (ec);
373
374                         ig.MarkLabel (ec.LoopBegin);
375
376                         if (parent.GetType () == typeof (Labelled))
377                                 ig.MarkLabel ((parent as Labelled).InitAddrs);
378
379                         CodeGenerator.fall_false (ec, exp, body_label);
380                         ig.MarkLabel (ec.LoopEnd);
381
382                         ec.LoopBegin = old_begin;
383                         ec.LoopEnd = old_end;
384                 }              
385         }
386
387
388         internal class While : AST, ICanModifyContext {
389                 AST exp, stm;
390
391                 internal While (Location location)
392                         : base (null, location)
393                 {
394                 }
395
396                 internal void Init (AST parent, AST exp, AST stm)
397                 {
398                         this.parent = parent;
399                         this.exp = exp;
400                         this.stm = stm;
401                 }
402
403                 void ICanModifyContext.PopulateContext (Environment env, string ns)
404                 {
405                         if (stm is ICanModifyContext)
406                                 ((ICanModifyContext) stm).PopulateContext (env, ns);
407                 }
408
409                 void ICanModifyContext.EmitDecls (EmitContext ec)
410                 {
411                         if (stm is ICanModifyContext)
412                                 ((ICanModifyContext) stm).EmitDecls (ec);
413                 }
414                 
415                 internal override bool Resolve (Environment env)
416                 {
417                         bool r = true;
418                         if (exp != null)
419                                 if (exp is Exp)
420                                         r &= ((Exp) exp).Resolve (env, false);
421                                 else 
422                                         r &= exp.Resolve (env);
423                         if (stm != null)
424                                 r &= stm.Resolve (env);
425                         return r;
426                 }
427
428                 internal override void Emit (EmitContext ec)
429                 {
430                         ILGenerator ig = ec.ig;
431                         Label old_begin = ec.LoopBegin;
432                         Label old_end = ec.LoopEnd;
433
434                         ec.LoopBegin = ig.DefineLabel ();
435                         ec.LoopEnd = ig.DefineLabel ();
436
437                         Label body_label = ig.DefineLabel ();
438
439                         ig.Emit (OpCodes.Br, ec.LoopBegin);
440                         ig.MarkLabel (body_label);
441                         
442                         if (stm != null)
443                                 stm.Emit (ec);
444                         
445                         ig.MarkLabel (ec.LoopBegin);
446                         
447                         if (parent.GetType () == typeof (Labelled))
448                                 ig.MarkLabel ((parent as Labelled).InitAddrs);
449
450                         CodeGenerator.fall_false (ec, exp, body_label);
451                         ig.MarkLabel (ec.LoopEnd);
452
453                         ec.LoopBegin = old_begin;
454                         ec.LoopEnd = old_end;
455                 }
456
457                 public override string ToString ()
458                 {
459                         return "while";
460                 }
461         }
462
463         internal class For : AST, ICanModifyContext {
464                 
465                 AST [] exprs = new AST [3];
466                 AST stms;
467
468                 internal For (AST parent, AST init, AST test, AST incr, AST body, Location location)
469                         : base (parent, location)
470                 {
471                         exprs [0] = init;
472                         exprs [1] = test;
473                         exprs [2] = incr;
474                         stms = body;
475                 }
476
477                 void ICanModifyContext.PopulateContext (Environment env, string ns)
478                 {
479                         foreach (AST ast in exprs)
480                                 if (ast is ICanModifyContext)
481                                         ((ICanModifyContext) ast).PopulateContext (env, ns);
482
483                         if (stms is ICanModifyContext)
484                                 ((ICanModifyContext) stms).PopulateContext (env, ns);
485                 }
486                 
487                 void ICanModifyContext.EmitDecls (EmitContext ec)
488                 {
489                         foreach (AST ast in exprs)
490                                 if (ast is ICanModifyContext)
491                                         ((ICanModifyContext) ast).EmitDecls (ec);
492
493                         if (stms is ICanModifyContext)
494                                 ((ICanModifyContext) stms).EmitDecls (ec);
495                 }
496
497                 internal override bool Resolve (Environment env)
498                 {
499                         bool r = true;
500
501                         foreach (AST ast in exprs)
502                                 r &= ast.Resolve (env);
503                         if (stms != null)
504                                 r &= stms.Resolve (env);
505                         return true;
506                 }
507
508                 internal override void Emit (EmitContext ec)
509                 {
510                         AST tmp;
511                         ILGenerator ig = ec.ig;
512                         Label old_begin = ec.LoopBegin;
513                         Label old_end = ec.LoopEnd;
514                         Label back = ig.DefineLabel ();
515                         Label forward = ig.DefineLabel ();
516
517
518                         /* emit init expr */
519                         tmp = exprs [0];
520                         if (tmp != null)
521                                 tmp.Emit (ec);
522
523                         ec.LoopBegin = ig.DefineLabel ();
524                         ec.LoopEnd = ig.DefineLabel ();
525                         
526                         ig.MarkLabel (back);
527                         ig.MarkLabel (ec.LoopBegin);
528
529                         /* emit condition */
530                         tmp = exprs [1];
531                         if (tmp != null)
532                                 tmp.Emit (ec);
533
534                         if (tmp != null && tmp is Expression) {
535                                 ArrayList t = ((Expression) tmp).exprs;
536                                 AST a = (AST) t [t.Count - 1];
537                                 if (a is Equality)
538                                         ig.Emit (OpCodes.Brfalse, forward);
539                                 else if (a is Relational) {
540                                         Relational rel = (Relational) a;
541                                         ig.Emit (OpCodes.Ldc_I4_0);
542                                         ig.Emit (OpCodes.Conv_R8);
543
544                                         if (rel.op == JSToken.GreaterThan)
545                                                 ig.Emit (OpCodes.Ble,  forward);
546                                         else
547                                                 ig.Emit (OpCodes.Bge, forward);
548                                 }
549                         }
550                         /* emit stms */
551                         if (stms != null)
552                                 stms.Emit (ec);
553
554                         if (parent.GetType () == typeof (Labelled))
555                                 ig.MarkLabel ((parent as Labelled).InitAddrs);
556
557                         tmp = exprs [2];
558                         /* emit increment */
559                         if (tmp != null)
560                                 tmp.Emit (ec);
561
562                         ig.Emit (OpCodes.Br, back);
563                         ig.MarkLabel (forward);
564                         ig.MarkLabel (ec.LoopEnd);
565
566                         ec.LoopBegin = old_begin;
567                         ec.LoopEnd = old_end;
568                 }
569         }
570
571         internal class Switch : AST, ICanModifyContext {
572
573                 internal AST exp;
574                 internal ArrayList case_clauses;
575                 internal ArrayList default_clauses;
576                 internal ArrayList sec_case_clauses;
577
578                 internal Switch (AST parent, Location location)
579                         : base (parent, location)
580                 {
581                         case_clauses = new ArrayList ();
582                         default_clauses = new ArrayList ();
583                         sec_case_clauses = new ArrayList ();
584                 }
585
586                 internal void AddClause (Clause clause, ClauseType clause_type)
587                 {
588                         if (clause_type == ClauseType.Case)
589                                 case_clauses.Add (clause);
590                         else if (clause_type == ClauseType.CaseAfterDefault)
591                                 sec_case_clauses.Add (clause);
592                 }
593
594                 void ICanModifyContext.PopulateContext (Environment env, string ns)
595                 {
596                         foreach (AST ast in case_clauses)
597                                 if (ast is ICanModifyContext)
598                                         ((ICanModifyContext) ast).PopulateContext (env, ns);
599
600                         foreach (AST ast in default_clauses)
601                                 if (ast is ICanModifyContext)
602                                         ((ICanModifyContext) ast).PopulateContext (env, ns);
603
604                         foreach (AST ast in sec_case_clauses)
605                                 if (ast is ICanModifyContext)
606                                         ((ICanModifyContext) ast).PopulateContext (env, ns);
607                 }
608                 
609                 void ICanModifyContext.EmitDecls (EmitContext ec)
610                 {
611                         foreach (AST ast in case_clauses)
612                                 if (ast is ICanModifyContext)
613                                         ((ICanModifyContext) ast).EmitDecls (ec);
614
615                         foreach (AST ast in default_clauses)
616                                 if (ast is ICanModifyContext)
617                                         ((ICanModifyContext) ast).EmitDecls (ec);
618
619                         foreach (AST ast in sec_case_clauses)
620                                 if (ast is ICanModifyContext)
621                                         ((ICanModifyContext) ast).EmitDecls (ec);
622                 }
623
624                 internal override bool Resolve (Environment env)
625                 {
626                         bool r = true;
627                         if (exp != null)
628                                 r &= exp.Resolve (env);
629                         if (case_clauses != null)
630                                 foreach (Clause c in case_clauses)
631                                         r &= c.Resolve (env);
632                         if (default_clauses != null)
633                                 foreach (AST dc in default_clauses)
634                                         r &= dc.Resolve (env);
635                         if (sec_case_clauses != null)
636                                 foreach (Clause sc in sec_case_clauses)
637                                         r &= sc.Resolve (env);
638                         return r;
639                 }
640
641                 internal override void Emit (EmitContext ec)
642                 {
643                         if (exp != null)
644                                 exp.Emit (ec);
645
646                         ILGenerator ig = ec.ig;
647                         Label init_default = ig.DefineLabel ();
648                         Label end_of_default = ig.DefineLabel ();
649                         Label old_end = ec.LoopEnd;
650                         ec.LoopEnd = ig.DefineLabel ();
651
652                         LocalBuilder loc = ig.DeclareLocal (typeof (object));
653                         ig.Emit (OpCodes.Stloc, loc);
654
655                         foreach (Clause c in case_clauses) {
656                                 ig.Emit (OpCodes.Ldloc, loc);
657                                 c.EmitConditional (ec);
658                         }
659
660                         /* emit conditionals from clauses that come after the default clause */
661                         if (sec_case_clauses != null && sec_case_clauses.Count > 0) {
662                                 foreach (Clause c in sec_case_clauses) {
663                                         ig.Emit (OpCodes.Ldloc, loc);
664                                         c.EmitConditional (ec);
665                                 }
666                         } 
667                         ig.Emit (OpCodes.Br, init_default);
668
669                         /* emit the stms from case_clauses */
670                         foreach (Clause c in case_clauses) {
671                                 ig.MarkLabel (c.matched_block);
672                                 c.EmitStms (ec);                                
673                         }
674                         
675                         ig.MarkLabel (init_default);
676                         foreach (AST ast in default_clauses)
677                                 ast.Emit (ec);
678                         ig.MarkLabel (end_of_default);
679
680                         if (sec_case_clauses != null && sec_case_clauses.Count > 0) {
681                                 foreach (Clause c in sec_case_clauses) {
682                                         ig.MarkLabel (c.matched_block);
683                                         c.EmitStms (ec);                                
684                                 }
685                         } 
686                         ig.MarkLabel (ec.LoopEnd);
687                         ec.LoopEnd = old_end;
688                 }
689         }
690
691         internal class Clause : AST, ICanModifyContext {
692                 internal AST exp;
693                 internal ArrayList stm_list;
694                 internal Label matched_block;
695
696                 internal Clause (AST parent, Location location)
697                         : base (parent, location)
698                 {
699                         stm_list = new ArrayList ();
700                 }
701
702                 internal void AddStm (AST stm)
703                 {
704                         stm_list.Add (stm);
705                 }
706
707                 void ICanModifyContext.PopulateContext (Environment env, string ns)
708                 {
709                         foreach (AST ast in stm_list)
710                                 if (ast is ICanModifyContext)
711                                         ((ICanModifyContext) ast).PopulateContext (env, ns);
712                 }
713                 
714
715                 void ICanModifyContext.EmitDecls (EmitContext ec)
716                 {
717                         foreach (AST ast in stm_list)
718                                 if (ast is ICanModifyContext)
719                                         ((ICanModifyContext) ast).EmitDecls (ec);
720                 }
721
722                 internal override bool Resolve (Environment env)
723                 {
724                         bool r = true;
725                         if (exp != null)
726                                 r &= exp.Resolve (env);
727                         foreach (AST ast in stm_list)
728                                 r &= ast.Resolve (env);
729                         return r;                       
730                 }
731
732                 internal void EmitConditional (EmitContext ec)
733                 {
734                         if (exp != null)
735                                 exp.Emit (ec);
736                         ILGenerator ig = ec.ig;
737                         matched_block = ig.DefineLabel ();
738                         ig.Emit (OpCodes.Call, typeof (StrictEquality).GetMethod ("JScriptStrictEquals"));
739                         ig.Emit (OpCodes.Brtrue, matched_block);
740                 }
741                 
742                 internal void EmitStms (EmitContext ec)
743                 {
744                         foreach (AST ast in stm_list)
745                                 ast.Emit (ec);
746                 }
747
748                 internal override void Emit (EmitContext ec)
749                 {
750                 }       
751         }
752
753         internal class Catch : AST, ICanModifyContext {
754                 internal string id;
755                 internal AST catch_cond;
756                 internal AST stms;
757
758                 internal FieldBuilder field_info;
759                 internal LocalBuilder local_builder;
760
761                 internal Catch (string id, AST catch_cond, AST stms, AST parent, Location location)
762                         : base (parent, location)
763                 {
764                         this.id = id;
765                         this.catch_cond = catch_cond;
766                         this.stms = stms;
767                 }
768
769                 void ICanModifyContext.PopulateContext (Environment env, string ns)
770                 {
771                         if (stms is ICanModifyContext)
772                                 ((ICanModifyContext) stms).PopulateContext (env, ns);
773                 }
774                 
775                 void ICanModifyContext.EmitDecls (EmitContext ec)
776                 {
777                         if (stms is ICanModifyContext)
778                                 ((ICanModifyContext) stms).EmitDecls (ec);
779                 }
780
781                 internal override bool Resolve (Environment env)
782                 {
783                         bool r = true;
784                         if (stms != null)
785                                 r &= stms.Resolve (env);
786                         return r;
787                 }
788
789                 internal override void Emit (EmitContext ec)
790                 {
791                         ILGenerator ig = ec.ig;
792                         Type t = typeof (object);
793                         bool in_function = InFunction;
794
795                         if (in_function)
796                                 local_builder = ig.DeclareLocal (t);
797                         else
798                                 field_info = ec.type_builder.DefineField (mangle_id (id), t, FieldAttributes.Public | FieldAttributes.Static);
799
800                         ig.BeginCatchBlock (typeof (Exception));
801                         CodeGenerator.load_engine (in_function, ig);
802                         ig.Emit (OpCodes.Call, typeof (Try).GetMethod ("JScriptExceptionValue"));
803                         
804                         if (in_function)
805                                 ig.Emit (OpCodes.Stloc, local_builder);
806                         else
807                                 ig.Emit (OpCodes.Stsfld, field_info);
808
809                         stms.Emit (ec);                 
810                 }
811
812                 internal string mangle_id (string id)
813                 {
814                         return id + ":0";
815                 }
816         }
817
818         internal class Labelled : AST, ICanModifyContext {
819                 string name;
820                 Label init_addrs; 
821                 Label end_addrs;
822                 AST stm;
823
824                 internal Labelled (AST parent, Location location)
825                         : base (parent, location)
826                 {
827                 }
828
829                 internal Label InitAddrs {
830                         set { init_addrs = value; }
831                         get { return init_addrs; }
832                 }
833                 
834                 internal Label EndAddrs {
835                         set { end_addrs = value; }
836                         get { return end_addrs; }
837                 }
838
839                 internal void Init (AST parent, string name, AST stm, Location location)
840                 {
841                         this.parent = parent;
842                         this.name = name;
843                         this.stm = stm;
844                         this.location = location;
845                 }
846
847                 void ICanModifyContext.PopulateContext (Environment env, string ns)
848                 {
849                         if (stm is ICanModifyContext)
850                                 ((ICanModifyContext) stm).PopulateContext (env, ns);
851                 }
852                 
853                 void ICanModifyContext.EmitDecls (EmitContext ec)
854                 {
855                         if (stm is ICanModifyContext)
856                                 ((ICanModifyContext) stm).EmitDecls (ec);
857                 }
858
859                 internal override bool Resolve (Environment env)
860                 {
861                         try {
862                                 SemanticAnalyser.AddLabel (name, this);
863                         } catch (ArgumentException) {
864                                 throw new Exception ("error JS1025: Label redefined");
865                         }
866                         if (stm != null)
867                                 stm.Resolve (env);
868                         SemanticAnalyser.RemoveLabel (name);
869                         return true;
870                 }
871
872                 internal override void Emit (EmitContext ec)
873                 {
874                         ILGenerator ig = ec.ig;
875
876                         init_addrs = ig.DefineLabel ();
877                         end_addrs = ig.DefineLabel ();
878
879                         if (!IsLoop (stm))
880                                 ig.MarkLabel (init_addrs);
881
882                         stm.Emit (ec);
883
884                         ig.MarkLabel (end_addrs);
885                 }
886
887                 bool IsLoop (AST ast)
888                 {
889                         Type t = ast.GetType ();
890                         return t == typeof (For) || t == typeof (While) || t == typeof (DoWhile) || t == typeof (ForIn);
891                 }
892
893                 public override string ToString ()
894                 {
895                         return "Labelled";
896                 }
897         }
898 }
899