/// <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("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).GetMethod("get_Runtime")); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetMethod("get_Runtime")); gen.Emit(OpCodes.Ldloc, temp); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod("CreateMultiValue")); gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod("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("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("MoveNext")); gen.Emit(OpCodes.Brfalse, end); // ILuaMultiValue ret = enumerator.Current; gen.Emit(OpCodes.Ldloc, enumerator); gen.Emit(OpCodes.Callvirt, typeof(IEnumerator<ILuaMultiValue>).GetMethod("get_Current")); 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("Dispose")); gen.MarkLabel(endFinally); compiler.RemoveTemporary(enumerable); // } gen.EndExceptionBlock(); } 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("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> /// Reads part of a generic for loop from the input. The input is /// currently on the token after the first name and debug contains /// the parts read for the 'for' loop. 'name' contains the name of /// the first variable. /// </summary> /// <param name="input">Where to read input from/</param> /// <param name="debug">The token that currently holds what was read /// so far in the for statement and should after contain the entire loop.</param> /// <param name="name">The token that contains the name of the variable.</param> /// <returns>The loop object that was read.</returns> protected virtual ForGenItem ReadGenericFor(ITokenizer input, ref Token debug, Token name) { // read the variables List<NameItem> names = new List<NameItem>(); names.Add(new NameItem(name.Value) { Debug = name }); while (input.Peek().Value == ",") { Read(input, ref debug); // read ',' // read the name name = Read(input, ref debug); if (!IsName(name.Value)) throw new SyntaxException( string.Format(Resources.TokenNotAName, "for", name.Value), input.Name, name); if (_reserved.Contains(name.Value)) throw new SyntaxException( string.Format(Resources.TokenReserved, name.Value), input.Name, name); names.Add(new NameItem(name.Value) { Debug = name }); } // check for 'in' name = Read(input, ref debug); if (name.Value != "in") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "for", "in"), input.Name, name); // read the expression-list ForGenItem f = new ForGenItem(names); f.AddExpression(ReadExp(input, ref debug)); while (input.Peek().Value == ",") { Read(input, ref debug); // read "," f.AddExpression(ReadExp(input, ref debug)); } // check for 'do' name = Read(input, ref debug); if (name.Value != "do") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "for", "do"), input.Name, name); // read the chunk f.Block = ReadBlock(input, ref debug); // read 'end' name = Read(input, ref debug); if (name.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "for", "end"), input.Name, name); f.Debug = debug; return f; }