/// <summary>
        /// Called when the item is a for numerical 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(ForNumItem target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            ILGenerator gen = compiler.CurrentGenerator;
            target.Break.UserData = target.Break.UserData ?? gen.DefineLabel();
            Label start = gen.DefineLabel();
            Label end = (Label)target.Break.UserData;
            Label sj = gen.DefineLabel(), err = gen.DefineLabel();
            LocalBuilder d = compiler.CreateTemporary(typeof(double?));
            LocalBuilder val = compiler.CreateTemporary(typeof(double));
            LocalBuilder step = compiler.CreateTemporary(typeof(double));
            LocalBuilder limit = compiler.CreateTemporary(typeof(double));

            using (compiler.LocalBlock())
            {
                // d = {Start}.AsDouble();
                target.Start.Accept(this);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("AsDouble"));
                gen.Emit(OpCodes.Stloc, d);

                // if (d.HasValue) goto sj;
                gen.Emit(OpCodes.Ldloca, d);
                gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_HasValue"));
                gen.Emit(OpCodes.Brtrue, sj);

                // err:
                gen.MarkLabel(err);

                // throw new InvalidOperationException("The Start, Limit, and Step of a for loop must result in numbers.");
                gen.Emit(OpCodes.Ldstr, Resources.LoopMustBeNumbers);
                gen.Emit(OpCodes.Newobj, typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }));
                gen.Emit(OpCodes.Throw);

                // sj:
                gen.MarkLabel(sj);

                // val = d.Value;
                gen.Emit(OpCodes.Ldloca, d);
                gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_Value"));
                gen.Emit(OpCodes.Stloc, val);

                if (target.Step != null)
                {
                    // d = {Step}.AsDouble();
                    target.Step.Accept(this);
                    gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("AsDouble"));
                    gen.Emit(OpCodes.Stloc, d);

                    // if (!d.HasValue) goto err;
                    gen.Emit(OpCodes.Ldloca, d);
                    gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_HasValue"));
                    gen.Emit(OpCodes.Brfalse, err);

                    // step = d.Value;
                    gen.Emit(OpCodes.Ldloca, d);
                    gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_Value"));
                }
                else
                {
                    // step = 1.0;
                    gen.Emit(OpCodes.Ldc_R8, 1.0);
                }
                gen.Emit(OpCodes.Stloc, step);

                // d = {Limit}.AsDouble();
                target.Limit.Accept(this);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("AsDouble"));
                gen.Emit(OpCodes.Stloc, d);

                // if (!d.HasValue) goto err;
                gen.Emit(OpCodes.Ldloca, d);
                gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_HasValue"));
                gen.Emit(OpCodes.Brfalse, err);

                // limit = d.Value;
                gen.Emit(OpCodes.Ldloca, d);
                gen.Emit(OpCodes.Callvirt, typeof(double?).GetMethod("get_Value"));
                gen.Emit(OpCodes.Stloc, limit);
                compiler.RemoveTemporary(d);

                // start:
                gen.MarkLabel(start);

                // if (!((step > 0) & (val <= limit)) | ((step <= 0) & (val >= limit))) goto end;
                gen.Emit(OpCodes.Ldloc, step);
                gen.Emit(OpCodes.Ldc_R8, 0.0);
                gen.Emit(OpCodes.Cgt);
                gen.Emit(OpCodes.Ldloc, val);
                gen.Emit(OpCodes.Ldloc, limit);
                gen.Emit(OpCodes.Cgt);
                gen.Emit(OpCodes.Ldc_I4_1);
                gen.Emit(OpCodes.Xor);
                gen.Emit(OpCodes.And);
                gen.Emit(OpCodes.Ldloc, step);
                gen.Emit(OpCodes.Ldc_R8, 0.0);
                gen.Emit(OpCodes.Cgt);
                gen.Emit(OpCodes.Ldc_I4_1);
                gen.Emit(OpCodes.Xor);
                gen.Emit(OpCodes.Ldloc, val);
                gen.Emit(OpCodes.Ldloc, limit);
                gen.Emit(OpCodes.Clt);
                gen.Emit(OpCodes.Ldc_I4_1);
                gen.Emit(OpCodes.Xor);
                gen.Emit(OpCodes.And);
                gen.Emit(OpCodes.Or);
                gen.Emit(OpCodes.Brfalse, end);

                // {name} = E.Runtime.CreateValue((object)val);
                var field = compiler.DefineLocal(target.Name);
                field.StartSet();
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaEnvironment).GetMethod("get_Runtime"));
                gen.Emit(OpCodes.Ldloc, val);
                gen.Emit(OpCodes.Box, typeof(double));
                gen.Emit(OpCodes.Callvirt, typeof(ILuaRuntime).GetMethod("CreateValue"));
                field.EndSet();

                // {Block}
                target.Block.Accept(this);

                // val += step;
                gen.Emit(OpCodes.Ldloc, val);
                gen.Emit(OpCodes.Ldloc, step);
                gen.Emit(OpCodes.Add);
                gen.Emit(OpCodes.Stloc, val);
                compiler.RemoveTemporary(val);
                compiler.RemoveTemporary(step);
                compiler.RemoveTemporary(limit);

                // goto start;
                gen.Emit(OpCodes.Br, start);

                // end:
                gen.MarkLabel(end);
            }
            return target;
        }
Esempio n. 2
0
        /// <summary>
        /// Called when the item is a for numerical 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(ForNumItem target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            using (tree.Block(true))
            {
                tree.DefineLocal(new[] { target.Name });
                tree.DefineLabel(target.Break);

                target.Block.Accept(this);
                if (target.Start != null)
                    target.Start.Accept(this);
                if (target.Limit != null)
                    target.Limit.Accept(this);
                if (target.Step != null)
                    target.Step.Accept(this);
            }
            return target;
        }
Esempio n. 3
0
        /// <summary>
        /// Reads part of a numerical for loop from the input.  The input is 
        /// currently on the equals sign '=' and the debug token currently
        /// contains the parts read for the 'for' loop.  'name' contains the
        /// name of the 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 ForNumItem ReadNumberFor(ITokenizer input, ref Token debug, Token name)
        {
            // read "="
            var temp = Read(input, ref debug);
            if (temp.Value != "=")
                throw new InvalidOperationException(string.Format(Resources.MustBeOn, "=", "ReadNumberFor"));

            // get the 'start' value
            var start = ReadExp(input, ref debug);

            // read ','
            temp = Read(input, ref debug);
            if (temp.Value != ",")
                throw new SyntaxException(
                    string.Format(Resources.TokenInvalidExpecting, temp.Value, "for", ","),
                    input.Name, temp);

            // get the 'limit'
            var limit = ReadExp(input, ref debug);

            // read ','
            IParseExp step = null;
            if (input.Peek().Value == ",")
            {
                Read(input, ref debug);

                // read the 'step'
                step = ReadExp(input, ref debug);
            }

            ForNumItem i = new ForNumItem(new NameItem(name.Value) { Debug = name }, start, limit, step);

            // 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 block
            i.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);

            i.Debug = debug;
            return i;
        }