5 // Cesar Octavio Lopez Nataren
7 // (C) 2003, 2004 Cesar Octavio Lopez Nataren, <cesar@ciencias.unam.mx>
8 // Copyright (C) 2005 Novell Inc (http://novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
34 using System.Reflection;
35 using System.Reflection.Emit;
36 using System.Collections;
38 namespace Microsoft.JScript {
40 internal interface ICanModifyContext {
42 // Populate the symbol table before resolving references
44 void PopulateContext (Environment env, string ns);
45 void EmitDecls (EmitContext ec);
48 internal class If : AST, ICanModifyContext {
50 internal AST cond, true_stm, false_stm;
52 internal If (AST parent, AST condition, AST true_stm, AST false_stm, Location location)
53 : base (parent, location)
55 this.cond = condition;
56 this.true_stm = true_stm;
57 this.false_stm = false_stm;
60 public override string ToString ()
62 StringBuilder sb = new StringBuilder ();
65 sb.Append (cond.ToString ());
67 sb.Append (true_stm.ToString ());
68 if (false_stm != null)
69 sb.Append (false_stm.ToString ());
71 return sb.ToString ();
74 void ICanModifyContext.PopulateContext (Environment env, string ns)
76 if (true_stm is ICanModifyContext)
77 ((ICanModifyContext) true_stm).PopulateContext (env, ns);
79 if (false_stm is ICanModifyContext)
80 ((ICanModifyContext) false_stm).PopulateContext (env, ns);
83 void ICanModifyContext.EmitDecls (EmitContext ec)
85 if (true_stm is ICanModifyContext)
86 ((ICanModifyContext) true_stm).EmitDecls (ec);
88 if (false_stm is ICanModifyContext)
89 ((ICanModifyContext) false_stm).EmitDecls (ec);
92 internal override bool Resolve (Environment env)
98 r &= ((Exp) cond).Resolve (env, false);
100 if (true_stm != null)
102 r &= ((Exp) true_stm).Resolve (env, true);
104 r &= true_stm.Resolve (env);
106 if (false_stm != null)
107 if (false_stm is Exp)
108 r &= ((Exp) false_stm).Resolve (env, true);
110 r &= false_stm.Resolve (env);
114 internal override void Emit (EmitContext ec)
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)
123 ig.Emit (OpCodes.Br, merge_lbl);
124 ig.MarkLabel (false_lbl);
125 if (false_stm != null)
127 ig.MarkLabel (merge_lbl);
130 internal override void PropagateParent (AST parent)
132 base.PropagateParent (parent);
133 true_stm.PropagateParent (this);
134 false_stm.PropagateParent (this);
138 abstract class Jump : AST {
139 protected string label = String.Empty;
140 protected object binding;
142 internal Jump (AST parent, Location location)
143 : base (parent, location)
147 bool IsLabel (object binding)
149 return binding.GetType () == typeof (Labelled);
152 protected bool ValidLabel ()
154 binding = SemanticAnalyser.GetLabel (label);
155 if (binding == null || !IsLabel (binding))
156 throw new Exception ("error JS1026: Label not found");
160 internal override void PropagateParent (AST parent)
162 base.PropagateParent (parent);
166 internal class Continue : Jump {
167 internal Continue (AST parent, string label, Location location)
168 : base (parent, location)
173 internal override bool Resolve (Environment env)
176 throw new Exception ("A continue can't be outside a iteration stm");
177 if (label != String.Empty)
178 return ValidLabel ();
182 internal override void Emit (EmitContext ec)
184 if (label == String.Empty) {
185 ec.ig.Emit (OpCodes.Br, ec.LoopBegin);
188 ec.ig.Emit (OpCodes.Br, (binding as Labelled).InitAddrs);
192 internal class Break : Jump {
194 internal Break (AST parent, string label, Location location)
195 : base (parent, location)
200 internal override bool Resolve (Environment env)
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 ();
209 internal override void Emit (EmitContext ec)
211 if (label == String.Empty) {
212 ec.ig.Emit (OpCodes.Br, ec.LoopEnd);
215 ec.ig.Emit (OpCodes.Br, (binding as Labelled).EndAddrs);
218 internal override void PropagateParent (AST parent)
220 base.PropagateParent (parent);
224 internal class NotVoidReturnEventArgs : EventArgs {
227 internal delegate void NotVoidReturnEventHandler (object sender, NotVoidReturnEventArgs args);
229 internal class Return : AST, ICanModifyContext {
231 internal AST expression;
232 private bool exp_returns_void = false;
233 public event NotVoidReturnEventHandler not_void_return;
235 internal Return (Location location)
236 : base (null, location)
240 internal void OnNotVoidReturn (NotVoidReturnEventArgs args)
242 if (not_void_return != null)
243 not_void_return (this, args);
246 internal void Init (AST parent, AST exp)
248 this.parent = parent;
250 Function cont_func = GetContainerFunction;
251 this.not_void_return = new NotVoidReturnEventHandler (cont_func.NotVoidReturnHappened);
254 public override string ToString ()
256 if (expression != null)
257 return expression.ToString ();
262 void ICanModifyContext.PopulateContext (Environment env, string ns)
264 if (expression is ICanModifyContext)
265 ((ICanModifyContext) expression).PopulateContext (env, ns);
268 void ICanModifyContext.EmitDecls (EmitContext ec)
270 if (expression is ICanModifyContext)
271 ((ICanModifyContext) expression).EmitDecls (ec);
274 internal override bool Resolve (Environment env)
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;
282 Call call = (Call) ast;
283 if (call.member_exp is Identifier) {
284 object obj = env.Get (String.Empty, ((Identifier) call.member_exp).name);
286 exp_returns_void = ((Function) obj).HandleReturnType == typeof (void);
290 OnNotVoidReturn (null);
291 return expression.Resolve (env);
296 internal override void Emit (EmitContext ec)
298 ILGenerator ig = ec.ig;
299 Label lbl = ig.DefineLabel ();
300 LocalBuilder loc = null;
302 if (expression != null) {
303 expression.Emit (ec);
304 loc = ig.DeclareLocal (typeof (object));
306 if (exp_returns_void)
307 ig.Emit (OpCodes.Ldnull);
309 ig.Emit (OpCodes.Stloc, loc);
312 ig.Emit (OpCodes.Br, lbl);
316 ig.Emit (OpCodes.Ldloc, loc);
320 internal class DoWhile : AST, ICanModifyContext {
324 internal DoWhile (Location location)
325 : base (null, location)
329 internal void Init (AST parent, AST stm, AST exp)
331 this.parent = parent;
336 void ICanModifyContext.PopulateContext (Environment env, string ns)
338 if (stm is ICanModifyContext)
339 ((ICanModifyContext) stm).PopulateContext (env, ns);
342 void ICanModifyContext.EmitDecls (EmitContext ec)
344 if (stm is ICanModifyContext)
345 ((ICanModifyContext) stm).EmitDecls (ec);
348 internal override bool Resolve (Environment env)
353 r &= stm.Resolve (env);
355 r &= exp.Resolve (env);
359 internal override void Emit (EmitContext ec)
361 ILGenerator ig = ec.ig;
362 Label old_begin = ec.LoopBegin;
363 Label old_end = ec.LoopEnd;
364 Label body_label = ig.DefineLabel ();
366 ec.LoopBegin = ig.DefineLabel ();
367 ec.LoopEnd = ig.DefineLabel ();
369 ig.MarkLabel (body_label);
374 ig.MarkLabel (ec.LoopBegin);
376 if (parent.GetType () == typeof (Labelled))
377 ig.MarkLabel ((parent as Labelled).InitAddrs);
379 CodeGenerator.fall_false (ec, exp, body_label);
380 ig.MarkLabel (ec.LoopEnd);
382 ec.LoopBegin = old_begin;
383 ec.LoopEnd = old_end;
388 internal class While : AST, ICanModifyContext {
391 internal While (Location location)
392 : base (null, location)
396 internal void Init (AST parent, AST exp, AST stm)
398 this.parent = parent;
403 void ICanModifyContext.PopulateContext (Environment env, string ns)
405 if (stm is ICanModifyContext)
406 ((ICanModifyContext) stm).PopulateContext (env, ns);
409 void ICanModifyContext.EmitDecls (EmitContext ec)
411 if (stm is ICanModifyContext)
412 ((ICanModifyContext) stm).EmitDecls (ec);
415 internal override bool Resolve (Environment env)
420 r &= ((Exp) exp).Resolve (env, false);
422 r &= exp.Resolve (env);
424 r &= stm.Resolve (env);
428 internal override void Emit (EmitContext ec)
430 ILGenerator ig = ec.ig;
431 Label old_begin = ec.LoopBegin;
432 Label old_end = ec.LoopEnd;
434 ec.LoopBegin = ig.DefineLabel ();
435 ec.LoopEnd = ig.DefineLabel ();
437 Label body_label = ig.DefineLabel ();
439 ig.Emit (OpCodes.Br, ec.LoopBegin);
440 ig.MarkLabel (body_label);
445 ig.MarkLabel (ec.LoopBegin);
447 if (parent.GetType () == typeof (Labelled))
448 ig.MarkLabel ((parent as Labelled).InitAddrs);
450 CodeGenerator.fall_false (ec, exp, body_label);
451 ig.MarkLabel (ec.LoopEnd);
453 ec.LoopBegin = old_begin;
454 ec.LoopEnd = old_end;
457 public override string ToString ()
463 internal class For : AST, ICanModifyContext {
465 AST [] exprs = new AST [3];
468 internal For (AST parent, AST init, AST test, AST incr, AST body, Location location)
469 : base (parent, location)
477 void ICanModifyContext.PopulateContext (Environment env, string ns)
479 foreach (AST ast in exprs)
480 if (ast is ICanModifyContext)
481 ((ICanModifyContext) ast).PopulateContext (env, ns);
483 if (stms is ICanModifyContext)
484 ((ICanModifyContext) stms).PopulateContext (env, ns);
487 void ICanModifyContext.EmitDecls (EmitContext ec)
489 foreach (AST ast in exprs)
490 if (ast is ICanModifyContext)
491 ((ICanModifyContext) ast).EmitDecls (ec);
493 if (stms is ICanModifyContext)
494 ((ICanModifyContext) stms).EmitDecls (ec);
497 internal override bool Resolve (Environment env)
501 foreach (AST ast in exprs)
502 r &= ast.Resolve (env);
504 r &= stms.Resolve (env);
508 internal override void Emit (EmitContext ec)
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 ();
523 ec.LoopBegin = ig.DefineLabel ();
524 ec.LoopEnd = ig.DefineLabel ();
527 ig.MarkLabel (ec.LoopBegin);
534 if (tmp != null && tmp is Expression) {
535 ArrayList t = ((Expression) tmp).exprs;
536 AST a = (AST) t [t.Count - 1];
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);
544 if (rel.op == JSToken.GreaterThan)
545 ig.Emit (OpCodes.Ble, forward);
547 ig.Emit (OpCodes.Bge, forward);
554 if (parent.GetType () == typeof (Labelled))
555 ig.MarkLabel ((parent as Labelled).InitAddrs);
562 ig.Emit (OpCodes.Br, back);
563 ig.MarkLabel (forward);
564 ig.MarkLabel (ec.LoopEnd);
566 ec.LoopBegin = old_begin;
567 ec.LoopEnd = old_end;
571 internal class Switch : AST, ICanModifyContext {
574 internal ArrayList case_clauses;
575 internal ArrayList default_clauses;
576 internal ArrayList sec_case_clauses;
578 internal Switch (AST parent, Location location)
579 : base (parent, location)
581 case_clauses = new ArrayList ();
582 default_clauses = new ArrayList ();
583 sec_case_clauses = new ArrayList ();
586 internal void AddClause (Clause clause, ClauseType clause_type)
588 if (clause_type == ClauseType.Case)
589 case_clauses.Add (clause);
590 else if (clause_type == ClauseType.CaseAfterDefault)
591 sec_case_clauses.Add (clause);
594 void ICanModifyContext.PopulateContext (Environment env, string ns)
596 foreach (AST ast in case_clauses)
597 if (ast is ICanModifyContext)
598 ((ICanModifyContext) ast).PopulateContext (env, ns);
600 foreach (AST ast in default_clauses)
601 if (ast is ICanModifyContext)
602 ((ICanModifyContext) ast).PopulateContext (env, ns);
604 foreach (AST ast in sec_case_clauses)
605 if (ast is ICanModifyContext)
606 ((ICanModifyContext) ast).PopulateContext (env, ns);
609 void ICanModifyContext.EmitDecls (EmitContext ec)
611 foreach (AST ast in case_clauses)
612 if (ast is ICanModifyContext)
613 ((ICanModifyContext) ast).EmitDecls (ec);
615 foreach (AST ast in default_clauses)
616 if (ast is ICanModifyContext)
617 ((ICanModifyContext) ast).EmitDecls (ec);
619 foreach (AST ast in sec_case_clauses)
620 if (ast is ICanModifyContext)
621 ((ICanModifyContext) ast).EmitDecls (ec);
624 internal override bool Resolve (Environment env)
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);
641 internal override void Emit (EmitContext ec)
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 ();
652 LocalBuilder loc = ig.DeclareLocal (typeof (object));
653 ig.Emit (OpCodes.Stloc, loc);
655 foreach (Clause c in case_clauses) {
656 ig.Emit (OpCodes.Ldloc, loc);
657 c.EmitConditional (ec);
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);
667 ig.Emit (OpCodes.Br, init_default);
669 /* emit the stms from case_clauses */
670 foreach (Clause c in case_clauses) {
671 ig.MarkLabel (c.matched_block);
675 ig.MarkLabel (init_default);
676 foreach (AST ast in default_clauses)
678 ig.MarkLabel (end_of_default);
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);
686 ig.MarkLabel (ec.LoopEnd);
687 ec.LoopEnd = old_end;
691 internal class Clause : AST, ICanModifyContext {
693 internal ArrayList stm_list;
694 internal Label matched_block;
696 internal Clause (AST parent, Location location)
697 : base (parent, location)
699 stm_list = new ArrayList ();
702 internal void AddStm (AST stm)
707 void ICanModifyContext.PopulateContext (Environment env, string ns)
709 foreach (AST ast in stm_list)
710 if (ast is ICanModifyContext)
711 ((ICanModifyContext) ast).PopulateContext (env, ns);
715 void ICanModifyContext.EmitDecls (EmitContext ec)
717 foreach (AST ast in stm_list)
718 if (ast is ICanModifyContext)
719 ((ICanModifyContext) ast).EmitDecls (ec);
722 internal override bool Resolve (Environment env)
726 r &= exp.Resolve (env);
727 foreach (AST ast in stm_list)
728 r &= ast.Resolve (env);
732 internal void EmitConditional (EmitContext 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);
742 internal void EmitStms (EmitContext ec)
744 foreach (AST ast in stm_list)
748 internal override void Emit (EmitContext ec)
753 internal class Catch : AST, ICanModifyContext {
755 internal AST catch_cond;
758 internal FieldBuilder field_info;
759 internal LocalBuilder local_builder;
761 internal Catch (string id, AST catch_cond, AST stms, AST parent, Location location)
762 : base (parent, location)
765 this.catch_cond = catch_cond;
769 void ICanModifyContext.PopulateContext (Environment env, string ns)
771 if (stms is ICanModifyContext)
772 ((ICanModifyContext) stms).PopulateContext (env, ns);
775 void ICanModifyContext.EmitDecls (EmitContext ec)
777 if (stms is ICanModifyContext)
778 ((ICanModifyContext) stms).EmitDecls (ec);
781 internal override bool Resolve (Environment env)
785 r &= stms.Resolve (env);
789 internal override void Emit (EmitContext ec)
791 ILGenerator ig = ec.ig;
792 Type t = typeof (object);
793 bool in_function = InFunction;
796 local_builder = ig.DeclareLocal (t);
798 field_info = ec.type_builder.DefineField (mangle_id (id), t, FieldAttributes.Public | FieldAttributes.Static);
800 ig.BeginCatchBlock (typeof (Exception));
801 CodeGenerator.load_engine (in_function, ig);
802 ig.Emit (OpCodes.Call, typeof (Try).GetMethod ("JScriptExceptionValue"));
805 ig.Emit (OpCodes.Stloc, local_builder);
807 ig.Emit (OpCodes.Stsfld, field_info);
812 internal string mangle_id (string id)
818 internal class Labelled : AST, ICanModifyContext {
824 internal Labelled (AST parent, Location location)
825 : base (parent, location)
829 internal Label InitAddrs {
830 set { init_addrs = value; }
831 get { return init_addrs; }
834 internal Label EndAddrs {
835 set { end_addrs = value; }
836 get { return end_addrs; }
839 internal void Init (AST parent, string name, AST stm, Location location)
841 this.parent = parent;
844 this.location = location;
847 void ICanModifyContext.PopulateContext (Environment env, string ns)
849 if (stm is ICanModifyContext)
850 ((ICanModifyContext) stm).PopulateContext (env, ns);
853 void ICanModifyContext.EmitDecls (EmitContext ec)
855 if (stm is ICanModifyContext)
856 ((ICanModifyContext) stm).EmitDecls (ec);
859 internal override bool Resolve (Environment env)
862 SemanticAnalyser.AddLabel (name, this);
863 } catch (ArgumentException) {
864 throw new Exception ("error JS1025: Label redefined");
868 SemanticAnalyser.RemoveLabel (name);
872 internal override void Emit (EmitContext ec)
874 ILGenerator ig = ec.ig;
876 init_addrs = ig.DefineLabel ();
877 end_addrs = ig.DefineLabel ();
880 ig.MarkLabel (init_addrs);
884 ig.MarkLabel (end_addrs);
887 bool IsLoop (AST ast)
889 Type t = ast.GetType ();
890 return t == typeof (For) || t == typeof (While) || t == typeof (DoWhile) || t == typeof (ForIn);
893 public override string ToString ()