5 // Cesar Octavio Lopez Nataren
7 // (C) 2003, Cesar Octavio Lopez Nataren, <cesar@ciencias.unam.mx>
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
32 using System.Collections;
33 using System.Reflection.Emit;
35 namespace Microsoft.JScript {
37 public class ForIn : AST, ICanModifyContext {
41 internal ForIn (AST parent, AST lhs, AST obj, AST body, Location location)
42 : base (parent, location)
49 public static IEnumerator JScriptGetEnumerator (object coll)
51 IEnumerable e = coll as IEnumerable;
53 throw new JScriptException(JSError.NotCollection);
55 return e.GetEnumerator();
58 void ICanModifyContext.PopulateContext (Environment env, string ns)
60 if (lhs is ICanModifyContext)
61 ((ICanModifyContext) lhs).PopulateContext (env, ns);
63 if (body is ICanModifyContext)
64 ((ICanModifyContext) body).PopulateContext (env, ns);
67 void ICanModifyContext.EmitDecls (EmitContext ec)
69 if (lhs is ICanModifyContext)
70 ((ICanModifyContext) lhs).EmitDecls (ec);
72 if (body is ICanModifyContext)
73 ((ICanModifyContext) body).EmitDecls (ec);
76 internal override bool Resolve (Environment env)
80 if (lhs is VariableStatement)
81 ((ICanModifyContext) lhs).PopulateContext (env, String.Empty);
83 r &= lhs.Resolve (env);
85 r &= obj.Resolve (env);
88 r &= body.Resolve (env);
92 internal override void Emit (EmitContext ec)
94 ILGenerator ig = ec.ig;
95 bool varStm = lhs is VariableStatement;
99 VariableStatement stm = (VariableStatement) lhs;
100 ig.Emit (OpCodes.Ldnull);
101 var = TypeManager.Get (((VariableDeclaration) stm.var_decls [0]).id);
102 set_builder (ig, var);
107 CodeGenerator.load_engine (InFunction, ig);
110 Type convert = typeof (Convert);
111 ig.Emit (OpCodes.Call, convert.GetMethod ("ToForInObject"));
112 ig.Emit (OpCodes.Call, typeof (ForIn).GetMethod ("JScriptGetEnumerator"));
113 Type ienumerator = typeof (IEnumerator);
114 LocalBuilder iter = ig.DeclareLocal (ienumerator);
115 LocalBuilder current = ig.DeclareLocal (typeof (object));
117 ig.Emit (OpCodes.Stloc, iter);
119 Label init_loop = ig.DefineLabel ();
120 Label move_next = ig.DefineLabel ();
121 Label exit = ig.DefineLabel ();
123 ig.Emit (OpCodes.Br, move_next);
124 ig.MarkLabel (init_loop);
129 ig.MarkLabel (move_next);
131 ig.Emit (OpCodes.Ldloc, iter);
132 ig.Emit (OpCodes.Callvirt, ienumerator.GetMethod ("MoveNext"));
134 ig.Emit (OpCodes.Brfalse, exit);
136 ig.Emit (OpCodes.Ldloc, iter);
137 ig.Emit (OpCodes.Callvirt, ienumerator.GetProperty ("Current").GetGetMethod ());
138 ig.Emit (OpCodes.Stloc, current);
139 ig.Emit (OpCodes.Ldloc, current);
142 set_builder (ig, var);
144 if (lhs is Expression) {
145 AST ast = ((Expression) lhs).Last;
146 if (ast is Identifier)
147 ((Identifier) ast).EmitStore (ec);
149 throw new NotImplementedException ();
151 throw new NotImplementedException ();
154 ig.Emit (OpCodes.Br, init_loop);
158 void set_builder (ILGenerator ig, object builder)
160 if (builder is FieldBuilder)
161 ig.Emit (OpCodes.Stsfld, (FieldBuilder) builder);
162 else if (builder is LocalBuilder)
163 ig.Emit (OpCodes.Stloc, (LocalBuilder) builder);