/// <summary>
        /// Called when the item is an if item.
        /// </summary>
        /// <param name="target">The object that was passed to IParseItem.Visit.</param>
        /// <returns>The passed target or a modification of it.</returns>
        /// <exception cref="System.ArgumentNullException">If target is null.</exception>
        public IParseItem Visit(IfItem target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            ILGenerator gen = compiler.CurrentGenerator;
            Label next = gen.DefineLabel(), end = gen.DefineLabel();

            // if (!{Exp}.IsTrue) goto next;
            target.Exp.Accept(this);
            gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("get_IsTrue"));
            gen.Emit(OpCodes.Brfalse, next);

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

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

            // next:
            gen.MarkLabel(next);
            foreach (var item in target.Elses)
            {
                // if (!{item.Item1}.IsTrue) goto next;
                next = gen.DefineLabel();
                item.Expression.Accept(this);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod("get_IsTrue"));
                gen.Emit(OpCodes.Brfalse, next);

                // {item.Item2}
                item.Block.Accept(this);

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

                // next:
                gen.MarkLabel(next);
            }
            if (target.ElseBlock != null)
                target.ElseBlock.Accept(this);

            // end:
            gen.MarkLabel(end);

            return target;
        }
        /// <summary>
        /// Called when the item is an if item.
        /// </summary>
        /// <param name="target">The object that was passed to IParseItem.Visit.</param>
        /// <returns>The passed target or a modification of it.</returns>
        /// <exception cref="System.ArgumentNullException">If target is null.</exception>
        public IParseItem Visit(IfItem target)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            target.Exp.Accept(this);

            using (tree.Block(true))
                target.Block.Accept(this);

            for (int i = 0; i < target.Elses.Count; i++)
            {
                using (tree.Block(true))
                {
                    target.Elses[i].Expression.Accept(this);
                    target.Elses[i].Block.Accept(this);
                }
            }

            if (target.ElseBlock != null)
            {
                using (tree.Block(true))
                    target.ElseBlock.Accept(this);
            }

            return target;
        }
        /// <summary>
        /// Reads an if statement from the input.
        /// </summary>
        /// <param name="input">Where to read input from.</param>
        /// <param name="prev">The token to append what is read into.</param>
        /// <returns>The object that was read.</returns>
        protected virtual IParseStatement ReadIf(ITokenizer input, ref Token prev)
        {
            var debug = input.Read(); // read 'if'
            IfItem i = new IfItem();
            if (debug.Value != "if")
                throw new InvalidOperationException(string.Format(Resources.MustBeOn, "if", "ReadIf"));

            // read the initial expression
            i.Exp = ReadExp(input, ref debug);

            // read 'then'
            var name = Read(input, ref debug);
            if (name.Value != "then")
                throw new SyntaxException(
                    string.Format(Resources.TokenInvalid, name.Value, "if"),
                    input.Name, debug);

            // read the block
            var readBlock = ReadBlock(input, ref debug);
            i.Block = readBlock;

            // handle elseif(s)
            while ((name = input.Peek()).Value == "elseif")
            {
                Read(input, ref debug); // read 'elseif'

                // read the expression
                var readExp = ReadExp(input, ref debug);

                // read 'then'
                name = Read(input, ref debug);
                if (name.Value != "then")
                    throw new SyntaxException(
                        string.Format(Resources.TokenInvalid, name.Value, "elseif"),
                        input.Name, debug);

                // read the block
                readBlock = ReadBlock(input, ref debug);
                i.AddElse(readExp, readBlock);
            }

            // handle else
            if (name.Value != "else" && name.Value != "end")
                throw new SyntaxException(
                    string.Format(Resources.TokenInvalid, name.Value, "if"),
                    input.Name, debug);
            if (name.Value == "else")
            {
                Read(input, ref debug); // read 'else'

                // read the block
                readBlock = ReadBlock(input, ref debug);
                i.ElseBlock = readBlock;
            }

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

            prev.Append(debug);
            i.Debug = debug;
            return i;
        }