Beispiel #1
0
        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);
        }