public IParseItem Visit(ForGenItem target) { if (target == null) { throw new ArgumentNullException(nameof(target)); } using (_tree.Block(true)) { _tree.DefineLocal(target.Names); _tree.DefineLabel(target.Break); target.Block.Accept(this); foreach (var item in target.Expressions) { item.Accept(this); } } return(target); }
/// <summary> /// Called when the item is a for generic item. /// </summary> /// <param name="target">The object that was passed to IParseItem.Accept.</param> /// <returns>The passed target or a modification of it.</returns> /// <exception cref="System.ArgumentNullException">If target is null.</exception> public IParseItem Visit(ForGenItem target) { if (target == null) { throw new ArgumentNullException(nameof(target)); } ILGenerator gen = compiler.CurrentGenerator; target.Break.UserData = target.Break.UserData ?? gen.DefineLabel(); Label start = gen.DefineLabel(), end = (Label)target.Break.UserData; LocalBuilder ret = compiler.CreateTemporary(typeof(ILuaMultiValue)); LocalBuilder enumerable = compiler.CreateTemporary(typeof(IEnumerable <ILuaMultiValue>)); LocalBuilder enumerator = compiler.CreateTemporary(typeof(IEnumerator <ILuaMultiValue>)); using (compiler.LocalBlock()) { // temp = new ILuaValue[...]; var temp = compiler.CreateArray(typeof(ILuaValue), target.Expressions.Count); for (int i = 0; i < target.Expressions.Count; i++) { // temp[{i}] = {item}; gen.Emit(OpCodes.Ldloc, temp); gen.Emit(OpCodes.Ldc_I4, i); target.Expressions[i].Accept(this); gen.Emit(OpCodes.Stelem, typeof(ILuaValue)); } // enumerable = E.Runtime.GenericLoop(E, new LuaMultiValue(temp)); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod()); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetProperty(nameof(ILuaEnvironment.Runtime)).GetGetMethod()); gen.Emit(OpCodes.Ldloc, temp); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.CreateMultiValue))); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod(nameof(ILuaRuntime.GenericLoop))); gen.Emit(OpCodes.Stloc, enumerable); compiler.RemoveTemporary(temp); // enumerator = enumerable.GetEnumerator(); gen.Emit(OpCodes.Ldloc, enumerable); gen.Emit(OpCodes.Callvirt, typeof(IEnumerable <ILuaMultiValue>).GetMethod(nameof(IEnumerable.GetEnumerator))); gen.Emit(OpCodes.Stloc, enumerator); // try { Label endTry = gen.BeginExceptionBlock(); gen.MarkLabel(start); // if (!enumerator.MoveNext) goto end; gen.Emit(OpCodes.Ldloc, enumerator); gen.Emit(OpCodes.Callvirt, typeof(IEnumerator).GetMethod(nameof(IEnumerator.MoveNext))); gen.Emit(OpCodes.Brfalse, end); // ILuaMultiValue ret = enumerator.Current; gen.Emit(OpCodes.Ldloc, enumerator); gen.Emit(OpCodes.Callvirt, typeof(IEnumerator <ILuaMultiValue>) .GetProperty(nameof(IEnumerator <ILuaMultiValue> .Current)).GetGetMethod()); gen.Emit(OpCodes.Stloc, ret); compiler.RemoveTemporary(enumerator); for (int i = 0; i < target.Names.Count; i++) { // {_names[i]} = ret[{i}]; var field = compiler.DefineLocal(target.Names[i]); field.StartSet(); gen.Emit(OpCodes.Ldloc, ret); gen.Emit(OpCodes.Ldc_I4, i); gen.Emit(OpCodes.Callvirt, typeof(ILuaMultiValue).GetMethod("get_Item")); field.EndSet(); } compiler.RemoveTemporary(ret); // {Block} target.Block.Accept(this); // goto start; gen.Emit(OpCodes.Br, start); // end: gen.MarkLabel(end); // } finally { gen.Emit(OpCodes.Leave, endTry); gen.BeginFinallyBlock(); // if (enumerable != null) enumerable.Dispose(); Label endFinally = gen.DefineLabel(); gen.Emit(OpCodes.Ldloc, enumerable); gen.Emit(OpCodes.Brfalse, endFinally); gen.Emit(OpCodes.Ldloc, enumerable); gen.Emit(OpCodes.Callvirt, typeof(IDisposable).GetMethod(nameof(IDisposable.Dispose))); gen.MarkLabel(endFinally); compiler.RemoveTemporary(enumerable); // } gen.EndExceptionBlock(); } return(target); }