예제 #1
0
        /// <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;
        }
예제 #2
0
        /// <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;
        }
예제 #3
0
        /// <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;
        }