(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / Microsoft.JScript / Microsoft.JScript / Statement.cs
blobe810f25bc1ed5213b1f8d92a03c2d501266a0d4f
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 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.Text;
33 using System.Reflection;
34 using System.Reflection.Emit;
35 using System.Collections;
37 namespace Microsoft.JScript {
39 internal class If : AST {
41 internal AST cond, true_stm, false_stm;
43 internal If (AST parent, AST condition, AST true_stm, AST false_stm, int line_number)
45 this.cond = condition;
46 this.true_stm = true_stm;
47 this.false_stm = false_stm;
48 this.line_number = line_number;
51 public override string ToString ()
53 StringBuilder sb = new StringBuilder ();
55 if (cond != null)
56 sb.Append (cond.ToString ());
57 if (true_stm != null)
58 sb.Append (true_stm.ToString ());
59 if (false_stm != null)
60 sb.Append (false_stm.ToString ());
62 return sb.ToString ();
65 internal override bool Resolve (IdentificationTable context)
67 bool r = true;
69 if (cond != null)
70 if (cond is Exp)
71 r &= ((Exp) cond).Resolve (context, false);
73 if (true_stm != null)
74 if (true_stm is Exp)
75 r &= ((Exp) true_stm).Resolve (context, true);
76 else
77 r &= true_stm.Resolve (context);
79 if (false_stm != null)
80 if (false_stm is Exp)
81 r &= ((Exp) false_stm).Resolve (context, true);
82 else
83 r &= false_stm.Resolve (context);
84 return r;
87 internal override void Emit (EmitContext ec)
89 ILGenerator ig = ec.ig;
90 Label false_lbl = ig.DefineLabel ();
91 Label merge_lbl = ig.DefineLabel ();
92 CodeGenerator.fall_true (ec, cond, false_lbl);
93 if (true_stm != null)
94 true_stm.Emit (ec);
95 ig.Emit (OpCodes.Br, merge_lbl);
96 ig.MarkLabel (false_lbl);
97 if (false_stm != null)
98 false_stm.Emit (ec);
99 ig.MarkLabel (merge_lbl);
103 abstract class Jump : AST {
104 protected string label = String.Empty;
105 protected object binding;
107 bool IsLabel (object binding)
109 return binding.GetType () == typeof (Labelled);
112 protected bool ValidLabel ()
114 binding = SemanticAnalyser.GetLabel (label);
115 if (binding == null || !IsLabel (binding))
116 throw new Exception ("error JS1026: Label not found");
117 return true;
121 internal class Continue : Jump {
122 internal Continue (AST parent, string label, int line_number)
124 this.parent = parent;
125 Console.WriteLine ("Continue.parent = {0}", this.parent);
126 this.label += label;
127 this.line_number = line_number;
130 internal override bool Resolve (IdentificationTable context)
132 if (!InLoop)
133 throw new Exception ("A continue can't be outside a iteration stm");
134 if (label != String.Empty)
135 return ValidLabel ();
136 return true;
139 internal override void Emit (EmitContext ec)
141 if (label == String.Empty) {
142 ec.ig.Emit (OpCodes.Br, ec.LoopBegin);
143 return;
145 ec.ig.Emit (OpCodes.Br, (binding as Labelled).InitAddrs);
149 internal class Break : Jump {
151 internal Break (AST parent, string label, int line_number)
153 this.parent = parent;
154 Console.WriteLine ("Break.parent = {0}", this.parent);
155 this.label += label;
156 this.line_number = line_number;
159 internal override bool Resolve (IdentificationTable context)
161 if (!InLoop && !InSwitch)
162 throw new Exception ("A break statement can't be outside a switch or iteration stm");
163 if (label != String.Empty)
164 return ValidLabel ();
165 return true;
168 internal override void Emit (EmitContext ec)
170 if (label == String.Empty) {
171 ec.ig.Emit (OpCodes.Br, ec.LoopEnd);
172 return;
174 ec.ig.Emit (OpCodes.Br, (binding as Labelled).EndAddrs);
178 internal class NotVoidReturnEventArgs : EventArgs {
181 internal delegate void NotVoidReturnEventHandler (object sender, NotVoidReturnEventArgs args);
183 internal class Return : AST {
185 internal AST expression;
186 public event NotVoidReturnEventHandler not_void_return;
189 internal void OnNotVoidReturn (NotVoidReturnEventArgs args)
191 if (not_void_return != null)
192 not_void_return (this, args);
195 internal Return (AST parent, AST exp, int line_number)
197 this.parent = parent;
198 expression = exp;
199 this.line_number = line_number;
200 Function cont_func = GetContainerFunction;
201 this.not_void_return = new NotVoidReturnEventHandler (cont_func.NotVoidReturnHappened);
204 public override string ToString ()
206 if (expression != null)
207 return expression.ToString ();
208 else
209 return String.Empty;
212 internal override bool Resolve (IdentificationTable context)
214 if (!InFunction)
215 throw new Exception ("error JS1018: 'return' statement outside of function");
216 if (expression != null) {
217 OnNotVoidReturn (null);
218 return expression.Resolve (context);
219 } else
220 return true;
223 internal override void Emit (EmitContext ec)
225 ILGenerator ig = ec.ig;
226 Label lbl = ig.DefineLabel ();
227 LocalBuilder loc = null;
229 if (expression != null) {
230 expression.Emit (ec);
231 loc = ig.DeclareLocal (typeof (object));
232 ig.Emit (OpCodes.Stloc, loc);
235 ig.Emit (OpCodes.Br, lbl);
236 ig.MarkLabel (lbl);
238 if (loc != null)
239 ig.Emit (OpCodes.Ldloc, loc);
243 internal class DoWhile : AST {
245 AST stm, exp;
247 internal void Init (AST parent, AST stm, AST exp, int line_number)
249 this.parent = parent;
250 Console.WriteLine ("DoWhile.parent = {0}", this.parent);
251 this.stm = stm;
252 this.exp = exp;
253 this.line_number = line_number;
256 internal override bool Resolve (IdentificationTable context)
258 bool r = true;
260 if (stm != null)
261 r &= stm.Resolve (context);
262 if (exp != null)
263 r &= exp.Resolve (context);
264 return r;
267 internal override void Emit (EmitContext ec)
269 ILGenerator ig = ec.ig;
270 Label old_begin = ec.LoopBegin;
271 Label old_end = ec.LoopEnd;
272 Label body_label = ig.DefineLabel ();
274 ec.LoopBegin = ig.DefineLabel ();
275 ec.LoopEnd = ig.DefineLabel ();
277 ig.MarkLabel (body_label);
279 if (stm != null)
280 stm.Emit (ec);
282 ig.MarkLabel (ec.LoopBegin);
284 if (parent.GetType () == typeof (Labelled))
285 ig.MarkLabel ((parent as Labelled).InitAddrs);
287 CodeGenerator.fall_false (ec, exp, body_label);
288 ig.MarkLabel (ec.LoopEnd);
290 ec.LoopBegin = old_begin;
291 ec.LoopEnd = old_end;
296 internal class While : AST {
297 AST exp, stm;
299 internal void Init (AST parent, AST exp, AST stm, int line_number)
301 this.parent = parent;
302 this.exp = exp;
303 this.stm = stm;
304 this.line_number = line_number;
307 internal override bool Resolve (IdentificationTable context)
309 bool r = true;
310 if (exp != null)
311 if (exp is Exp)
312 r &= ((Exp) exp).Resolve (context, false);
313 else
314 r &= exp.Resolve (context);
315 if (stm != null)
316 r &= stm.Resolve (context);
317 return r;
320 internal override void Emit (EmitContext ec)
322 ILGenerator ig = ec.ig;
323 Label old_begin = ec.LoopBegin;
324 Label old_end = ec.LoopEnd;
326 ec.LoopBegin = ig.DefineLabel ();
327 ec.LoopEnd = ig.DefineLabel ();
329 Label body_label = ig.DefineLabel ();
331 ig.Emit (OpCodes.Br, ec.LoopBegin);
332 ig.MarkLabel (body_label);
334 if (stm != null)
335 stm.Emit (ec);
337 ig.MarkLabel (ec.LoopBegin);
339 if (parent.GetType () == typeof (Labelled))
340 ig.MarkLabel ((parent as Labelled).InitAddrs);
342 CodeGenerator.fall_false (ec, exp, body_label);
343 ig.MarkLabel (ec.LoopEnd);
345 ec.LoopBegin = old_begin;
346 ec.LoopEnd = old_end;
349 public override string ToString ()
351 return "while";
355 internal class For : AST {
357 AST [] exprs = new AST [3];
358 AST stms;
360 internal For (AST parent, int line_number, AST init, AST test, AST incr, AST body)
362 this.parent = parent;
363 this.line_number = line_number;
364 exprs [0] = init;
365 exprs [1] = test;
366 exprs [2] = incr;
367 stms = body;
370 internal override bool Resolve (IdentificationTable context)
372 bool r = true;
373 foreach (AST ast in exprs)
374 if (ast != null)
375 r &= ast.Resolve (context);
376 if (stms != null)
377 r &= stms.Resolve (context);
378 return true;
381 internal override void Emit (EmitContext ec)
383 AST tmp;
384 ILGenerator ig = ec.ig;
385 Label old_begin = ec.LoopBegin;
386 Label old_end = ec.LoopEnd;
387 Label back = ig.DefineLabel ();
388 Label forward = ig.DefineLabel ();
391 /* emit init expr */
392 tmp = exprs [0];
393 if (tmp != null)
394 tmp.Emit (ec);
396 ec.LoopBegin = ig.DefineLabel ();
397 ec.LoopEnd = ig.DefineLabel ();
399 ig.MarkLabel (back);
400 ig.MarkLabel (ec.LoopBegin);
402 /* emit condition */
403 tmp = exprs [1];
404 if (tmp != null)
405 tmp.Emit (ec);
407 if (tmp != null && tmp is Expression) {
408 ArrayList t = ((Expression) tmp).exprs;
409 AST a = (AST) t [t.Count - 1];
410 if (a is Equality)
411 ig.Emit (OpCodes.Brfalse, forward);
412 else if (a is Relational) {
413 ig.Emit (OpCodes.Ldc_I4_0);
414 ig.Emit (OpCodes.Conv_R8);
415 ig.Emit (OpCodes.Bge, forward);
418 /* emit stms */
419 if (stms != null)
420 stms.Emit (ec);
422 if (parent.GetType () == typeof (Labelled))
423 ig.MarkLabel ((parent as Labelled).InitAddrs);
425 tmp = exprs [2];
426 /* emit increment */
427 if (tmp != null)
428 tmp.Emit (ec);
430 ig.Emit (OpCodes.Br, back);
431 ig.MarkLabel (forward);
432 ig.MarkLabel (ec.LoopEnd);
434 ec.LoopBegin = old_begin;
435 ec.LoopEnd = old_end;
439 public class Switch : AST {
441 internal AST exp;
442 internal ArrayList case_clauses;
443 internal ArrayList default_clauses;
444 internal ArrayList sec_case_clauses;
446 internal Switch (AST parent, int line_number)
448 this.parent = parent;
449 this.line_number = line_number;
450 case_clauses = new ArrayList ();
451 default_clauses = new ArrayList ();
452 sec_case_clauses = new ArrayList ();
455 internal void AddClause (Clause clause, ClauseType clause_type)
457 if (clause_type == ClauseType.Case)
458 case_clauses.Add (clause);
459 else if (clause_type == ClauseType.CaseAfterDefault)
460 sec_case_clauses.Add (clause);
463 internal override bool Resolve (IdentificationTable context)
465 bool r = true;
466 if (exp != null)
467 r &= exp.Resolve (context);
468 if (case_clauses != null)
469 foreach (Clause c in case_clauses)
470 r &= c.Resolve (context);
471 if (default_clauses != null)
472 foreach (AST dc in default_clauses)
473 r &= dc.Resolve (context);
474 if (sec_case_clauses != null)
475 foreach (Clause sc in sec_case_clauses)
476 r &= sc.Resolve (context);
477 return r;
480 internal override void Emit (EmitContext ec)
482 if (exp != null)
483 exp.Emit (ec);
485 ILGenerator ig = ec.ig;
486 Label init_default = ig.DefineLabel ();
487 Label end_of_default = ig.DefineLabel ();
488 ec.LoopEnd = ig.DefineLabel ();
490 LocalBuilder loc = ig.DeclareLocal (typeof (object));
491 ig.Emit (OpCodes.Stloc, loc);
493 foreach (Clause c in case_clauses) {
494 ig.Emit (OpCodes.Ldloc, loc);
495 c.EmitConditional (ec);
498 /* emit conditionals from clauses that come after the default clause */
499 if (sec_case_clauses != null && sec_case_clauses.Count > 0) {
500 foreach (Clause c in sec_case_clauses) {
501 ig.Emit (OpCodes.Ldloc, loc);
502 c.EmitConditional (ec);
505 ig.Emit (OpCodes.Br, init_default);
507 /* emit the stms from case_clauses */
508 foreach (Clause c in case_clauses) {
509 ig.MarkLabel (c.matched_block);
510 c.EmitStms (ec);
513 ig.MarkLabel (init_default);
514 foreach (AST ast in default_clauses)
515 ast.Emit (ec);
516 ig.MarkLabel (end_of_default);
518 if (sec_case_clauses != null && sec_case_clauses.Count > 0) {
519 foreach (Clause c in sec_case_clauses) {
520 ig.MarkLabel (c.matched_block);
521 c.EmitStms (ec);
524 ig.MarkLabel (ec.LoopEnd);
528 public class Clause : AST {
529 internal AST exp;
530 internal ArrayList stm_list;
531 internal Label matched_block;
533 public Clause (AST parent)
535 this.parent = parent;
536 stm_list = new ArrayList ();
539 internal void AddStm (AST stm)
541 stm_list.Add (stm);
544 internal override bool Resolve (IdentificationTable context)
546 bool r = true;
547 if (exp != null)
548 r &= exp.Resolve (context);
549 foreach (AST ast in stm_list)
550 r &= ast.Resolve (context);
551 return r;
554 internal void EmitConditional (EmitContext ec)
556 if (exp != null)
557 exp.Emit (ec);
558 ILGenerator ig = ec.ig;
559 matched_block = ig.DefineLabel ();
560 ig.Emit (OpCodes.Call, typeof (StrictEquality).GetMethod ("JScriptStrictEquals"));
561 ig.Emit (OpCodes.Brtrue, matched_block);
564 internal void EmitStms (EmitContext ec)
566 ILGenerator ig = ec.ig;
567 foreach (AST ast in stm_list)
568 ast.Emit (ec);
571 internal override void Emit (EmitContext ec)
576 internal class Catch : AST {
577 internal string id;
578 internal AST catch_cond;
579 internal AST stms;
581 FieldBuilder field_info;
582 LocalBuilder local_builder;
584 internal Catch (string id, AST catch_cond, AST stms, AST parent, int line_number)
586 this.id = id;
587 this.catch_cond = catch_cond;
588 this.stms = stms;
589 this.line_number = line_number;
592 internal override bool Resolve (IdentificationTable context)
594 bool r = true;
595 if (stms != null)
596 r &= stms.Resolve (context);
597 return r;
600 internal override void Emit (EmitContext ec)
602 ILGenerator ig = ec.ig;
603 Type t = typeof (object);
604 bool not_in_func = parent == null;
606 if (not_in_func)
607 field_info = ec.type_builder.DefineField (mangle_id (id), t, FieldAttributes.Public | FieldAttributes.Static);
608 else
609 local_builder = ig.DeclareLocal (t);
611 ig.BeginCatchBlock (typeof (Exception));
612 if (not_in_func) {
613 ig.Emit (OpCodes.Ldarg_0);
614 ig.Emit (OpCodes.Ldfld, typeof (ScriptObject).GetField ("engine"));
615 ig.Emit (OpCodes.Call, typeof (Try).GetMethod ("JScriptExceptionValue"));
616 ig.Emit (OpCodes.Stsfld, field_info);
617 } else {
618 ig.Emit (OpCodes.Ldarg_1);
619 ig.Emit (OpCodes.Call, typeof (Try).GetMethod ("JScriptExceptionValue"));
620 ig.Emit (OpCodes.Stloc, local_builder);
622 stms.Emit (ec);
625 internal string mangle_id (string id)
627 return id + ":0";
631 internal class Labelled : AST {
632 string name;
633 Label init_addrs;
634 Label end_addrs;
635 AST stm;
637 internal Label InitAddrs {
638 set { init_addrs = value; }
639 get { return init_addrs; }
642 internal Label EndAddrs {
643 set { end_addrs = value; }
644 get { return end_addrs; }
647 internal void Init (AST parent, string name, AST stm, int line_number)
649 this.parent = parent;
650 Console.WriteLine ("labelled.parent = {0}", this.parent);
651 this.name = name;
652 this.stm = stm;
653 this.line_number = line_number;
656 internal override bool Resolve (IdentificationTable context)
658 try {
659 SemanticAnalyser.AddLabel (name, this);
660 } catch (ArgumentException e) {
661 throw new Exception ("error JS1025: Label redefined");
663 if (stm != null)
664 stm.Resolve (context);
665 SemanticAnalyser.RemoveLabel (name);
666 return true;
669 internal override void Emit (EmitContext ec)
671 ILGenerator ig = ec.ig;
673 init_addrs = ig.DefineLabel ();
674 end_addrs = ig.DefineLabel ();
676 if (!IsLoop (stm))
677 ig.MarkLabel (init_addrs);
679 stm.Emit (ec);
681 ig.MarkLabel (end_addrs);
684 bool IsLoop (AST ast)
686 Type t = ast.GetType ();
687 return t == typeof (For) || t == typeof (While) || t == typeof (DoWhile) || t == typeof (ForIn);
690 public override string ToString ()
692 return "Labelled";