Example #1
0
        /// <summary>
        /// Called when the item is a binary expression 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(BinOpItem target)
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            ILGenerator gen = compiler.CurrentGenerator;

            if (target.OperationType == BinaryOperationType.And ||
                target.OperationType == BinaryOperationType.Or)
            {
                // object temp = {Lhs};
                var end  = gen.DefineLabel();
                var temp = compiler.CreateTemporary(typeof(ILuaValue));
                target.Lhs.Accept(this);
                gen.Emit(OpCodes.Stloc, temp);

                // Push Lhs onto the stack, if going to end, this will be the result.
                gen.Emit(OpCodes.Ldloc, temp);

                // if (temp.IsTrue) goto end;
                gen.Emit(OpCodes.Ldloc, temp);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetProperty(nameof(ILuaValue.IsTrue)).GetGetMethod());
                if (target.OperationType == BinaryOperationType.And)
                {
                    // We want to break if the value is truthy and it's an OR,
                    // or it's falsy and it's an AND.

                    // Boolean negation.
                    gen.Emit(OpCodes.Ldc_I4_1);
                    gen.Emit(OpCodes.Xor);
                }
                gen.Emit(OpCodes.Brtrue, end);

                // Replace Lhs on stack with Rhs.
                gen.Emit(OpCodes.Pop);
                target.Rhs.Accept(this);

                // :end
                gen.MarkLabel(end);
            }
            else
            {
                //! push {Lhs}.Arithmetic({OperationType}, {Rhs})
                target.Lhs.Accept(this);
                gen.Emit(OpCodes.Ldc_I4, (int)target.OperationType);
                target.Rhs.Accept(this);
                gen.Emit(OpCodes.Callvirt, typeof(ILuaValue).GetMethod(nameof(ILuaValue.Arithmetic)));
            }

            return(target);
        }