// group variable
        public LuaValueDataBase EvaluateComplexTerminal()
        {
            if (TryTakeToken("("))
            {
                LuaValueDataBase value = EvaluateOr();

                if (value as LuaValueDataError != null)
                {
                    return(value);
                }

                if (!TryTakeToken(")"))
                {
                    return(Report("Failed to find ')' after '('"));
                }

                return(EvaluatePostExpressions(value));
            }

            string name = TryParseIdentifier();

            if (name == null)
            {
                return(Report("Failed to find variable name"));
            }

            var result = LookupVariable(name);

            if (result as LuaValueDataError != null)
            {
                return(result);
            }

            return(EvaluatePostExpressions(result));
        }
        public LuaValueDataNumber CoerceToNumber(LuaValueDataBase value)
        {
            var valueAsNumber = value as LuaValueDataNumber;

            if (valueAsNumber != null)
            {
                return(valueAsNumber);
            }

            var valueAsString = value as LuaValueDataString;

            if (valueAsString != null)
            {
                if (!double.TryParse(valueAsString.value, out double result))
                {
                    return(null);
                }

                if ((double)(int)result == result)
                {
                    return(new LuaValueDataNumber(result));
                }

                return(new LuaValueDataNumber(result));
            }

            return(null);
        }
        public bool CoerceToBool(LuaValueDataBase value)
        {
            LuaValueDataNil  asNilValue  = value as LuaValueDataNil;
            LuaValueDataBool asBoolValue = value as LuaValueDataBool;

            // 'nil' and 'false' are false, everything else is 'true'
            return(asNilValue != null ? false : (asBoolValue != null ? asBoolValue.value : true));
        }
        // + -
        public LuaValueDataBase EvaluateAdditive()
        {
            LuaValueDataBase lhs = EvaluateMultiplicative();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            string token = TryTakeOneOfTokens(new[] { "+", "-" });

            if (token != null)
            {
                var lhsAsNumber = CoerceToNumber(lhs);

                if (lhsAsNumber == null)
                {
                    return(Report("lhs of a numeric binary operator must be a number"));
                }

                LuaValueDataBase rhs = EvaluateMultiplicative();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                var rhsAsNumber = CoerceToNumber(rhs);

                if (rhsAsNumber == null)
                {
                    return(Report("rhs of a '+' binary operator must be a number"));
                }

                if (token == "+")
                {
                    if (lhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType() && rhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                    {
                        return(new LuaValueDataNumber((int)lhsAsNumber.value + (int)rhsAsNumber.value));
                    }

                    return(new LuaValueDataNumber(lhsAsNumber.value + rhsAsNumber.value));
                }

                if (token == "-")
                {
                    if (lhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType() && rhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                    {
                        return(new LuaValueDataNumber((int)lhsAsNumber.value - (int)rhsAsNumber.value));
                    }

                    return(new LuaValueDataNumber(lhsAsNumber.value - rhsAsNumber.value));
                }
            }

            return(lhs);
        }
        public override bool LuaCompare(LuaValueDataBase rhs)
        {
            var rhsAsMe = rhs as LuaValueDataError;

            if (rhsAsMe == null)
            {
                return(false);
            }

            return(value == rhsAsMe.value);
        }
        public override bool LuaCompare(LuaValueDataBase rhs)
        {
            var rhsAsMe = rhs as LuaValueDataThread;

            if (rhsAsMe == null)
            {
                return(false);
            }

            return(targetAddress == rhsAsMe.targetAddress);
        }
        public override bool LuaCompare(LuaValueDataBase rhs)
        {
            var rhsAsMe = rhs as LuaValueDataNil;

            if (rhsAsMe == null)
            {
                return(false);
            }

            return(true);
        }
        public LuaValueDataBase LookupTableValueMember(LuaValueDataBase value, string name)
        {
            var table = value as LuaValueDataTable;

            if (table == null)
            {
                return(Report("Value is not a table"));
            }

            return(LookupTableMember(table.value, name));
        }
        public LuaValueDataBase Report(LuaValueDataBase value, string error)
        {
            var errorValue = value as LuaValueDataError;

            if (errorValue != null)
            {
                return(new LuaValueDataError(errorValue.value + ", " + error));
            }

            return(Report(error));
        }
        // * /
        public LuaValueDataBase EvaluateMultiplicative()
        {
            LuaValueDataBase lhs = EvaluateUnary();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            string token = TryTakeOneOfTokens(new[] { "*", "/" });

            if (token != null)
            {
                var lhsAsNumber = CoerceToNumber(lhs);

                if (lhsAsNumber == null)
                {
                    return(Report("lhs of a numeric binary operator must be a number"));
                }

                LuaValueDataBase rhs = EvaluateUnary();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                var rhsAsNumber = CoerceToNumber(rhs);

                if (rhsAsNumber == null)
                {
                    return(Report("rhs of a numeric binary operator must be a number"));
                }

                if (token == "*")
                {
                    if (lhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType() && rhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                    {
                        return(new LuaValueDataNumber((int)lhsAsNumber.value * (int)rhsAsNumber.value));
                    }

                    return(new LuaValueDataNumber(lhsAsNumber.value * rhsAsNumber.value));
                }

                if (token == "/")
                {
                    // Always floating-point
                    return(new LuaValueDataNumber(lhsAsNumber.value / rhsAsNumber.value));
                }
            }

            return(lhs);
        }
        public LuaValueDataBase EvaluateAssignment(bool allowSideEffects)
        {
            LuaValueDataBase lhs = EvaluateOr();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            if (TryTakeToken("="))
            {
                LuaValueDataBase rhs = EvaluateOr();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                if (!allowSideEffects)
                {
                    var error = Report("Expression has side-effects");

                    error.evaluationFlags |= DkmEvaluationResultFlags.UnflushedSideEffects;

                    return(error);
                }

                // lhs must be an l-value
                if (lhs.tagAddress == 0 || lhs.originalAddress == 0)
                {
                    return(Report("lhs value cannot be modified"));
                }

                // Try to update the value
                if (!LuaHelpers.TryWriteValue(process, stackFrame, inspectionSession, lhs.tagAddress, lhs.originalAddress, rhs, out string errorText))
                {
                    return(Report(errorText));
                }

                rhs.evaluationFlags |= DkmEvaluationResultFlags.SideEffect;
                return(rhs);
            }

            return(lhs);
        }
        // ..
        public LuaValueDataBase EvaluateConcatenation()
        {
            LuaValueDataBase lhs = EvaluateAdditive();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            if (TryTakeToken(".."))
            {
                LuaValueDataBase rhs = EvaluateAdditive();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                var lhsAsNumber = lhs as LuaValueDataNumber;
                var lhsAsString = lhs as LuaValueDataString;

                if (lhsAsNumber == null && lhsAsString == null)
                {
                    return(Report("lhs of a concatenation operator must be a number or a string"));
                }

                var rhsAsNumber = rhs as LuaValueDataNumber;
                var rhsAsString = rhs as LuaValueDataString;

                if (rhsAsNumber == null && rhsAsString == null)
                {
                    return(Report("rhs of a concatenation operator must be a number or a string"));
                }

                string lhsString = lhsAsNumber != null ? (lhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType() ? $"{(int)lhsAsNumber.value}" : $"{lhsAsNumber.value}") : lhsAsString.value;
                string rhsString = rhsAsNumber != null ? (rhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType() ? $"{(int)rhsAsNumber.value}" : $"{rhsAsNumber.value}") : rhsAsString.value;

                return(new LuaValueDataString(lhsString + rhsString));
            }

            return(lhs);
        }
        public LuaValueDataBase Evaluate(string expression, bool allowSideEffects)
        {
            this.expression = expression;
            this.pos        = 0;

            LuaValueDataBase value = EvaluateAssignment(allowSideEffects);

            if (value as LuaValueDataError != null)
            {
                return(value);
            }

            SkipSpace();

            if (pos < expression.Length)
            {
                return(Report(value, $"Failed to fully parse at '{expression.Substring(pos)}'"));
            }

            return(value);
        }
Exemple #14
0
        // not -
        public LuaValueDataBase EvaluateUnary()
        {
            if (TryTakeNamedToken("not"))
            {
                LuaValueDataBase lhs = EvaluateUnary();

                if (lhs as LuaValueDataError != null)
                {
                    return(lhs);
                }

                return(new LuaValueDataBool(!CoerceToBool(lhs)));
            }

            if (TryTakeToken("-"))
            {
                LuaValueDataBase lhs = EvaluateUnary();

                if (lhs as LuaValueDataError != null)
                {
                    return(lhs);
                }

                var lhsAsNumber = CoerceToNumber(lhs);

                if (lhsAsNumber == null)
                {
                    return(Report("value of the unary '-' operator must be a number"));
                }

                if (lhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                {
                    return(new LuaValueDataNumber(-(int)lhsAsNumber.value));
                }

                return(new LuaValueDataNumber(-lhsAsNumber.value));
            }

            return(EvaluateTerminal());
        }
        // or
        public LuaValueDataBase EvaluateOr()
        {
            LuaValueDataBase lhs = EvaluateAnd();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            if (TryTakeNamedToken("or"))
            {
                LuaValueDataBase rhs = EvaluateAnd();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                return(new LuaValueDataBool(CoerceToBool(lhs) || CoerceToBool(rhs)));
            }

            return(lhs);
        }
        // and
        public LuaValueDataBase EvaluateAnd()
        {
            LuaValueDataBase lhs = EvaluateComparisons();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            if (TryTakeNamedToken("and"))
            {
                LuaValueDataBase rhs = EvaluateComparisons();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                return(new LuaValueDataBool(CoerceToBool(lhs) && CoerceToBool(rhs)));
            }

            return(lhs);
        }
        internal static DkmEvaluationResult EvaluateDataAtLuaValue(DkmInspectionContext inspectionContext, DkmStackWalkFrame stackFrame, string name, string fullName, LuaValueDataBase luaValue, DkmEvaluationResultFlags flags, DkmEvaluationResultAccessType access, DkmEvaluationResultStorageType storage)
        {
            var process = stackFrame.Process;

            if (luaValue == null)
            {
                return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, name, fullName, "Null pointer access", DkmEvaluationResultFlags.Invalid, null));
            }

            string value = EvaluateValueAtLuaValue(process, luaValue, inspectionContext.Radix, out string editableValue, ref flags, out DkmDataAddress dataAddress, out string type);

            if (value == null)
            {
                return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, name, fullName, "Failed to read value", DkmEvaluationResultFlags.Invalid, null));
            }

            DkmEvaluationResultCategory          category      = DkmEvaluationResultCategory.Data;
            DkmEvaluationResultTypeModifierFlags typeModifiers = DkmEvaluationResultTypeModifierFlags.None;

            var dataItem = new LuaEvaluationDataItem
            {
                address      = luaValue.originalAddress,
                type         = type,
                fullName     = fullName,
                luaValueData = luaValue
            };

            return(DkmSuccessEvaluationResult.Create(inspectionContext, stackFrame, name, fullName, flags, value, editableValue, type, category, access, storage, typeModifiers, dataAddress, null, null, dataItem));
        }
        internal static string EvaluateValueAtAddress(DkmProcess process, ulong address, uint radix, out string editableValue, ref DkmEvaluationResultFlags flags, out DkmDataAddress dataAddress, out string type, out LuaValueDataBase luaValueData)
        {
            editableValue = null;
            dataAddress   = null;
            type          = "unknown";

            luaValueData = LuaHelpers.ReadValue(process, address);

            if (luaValueData == null)
            {
                return(null);
            }

            return(EvaluateValueAtLuaValue(process, luaValueData, radix, out editableValue, ref flags, out dataAddress, out type));
        }
        internal static string EvaluateValueAtLuaValue(DkmProcess process, LuaValueDataBase valueBase, uint radix, out string editableValue, ref DkmEvaluationResultFlags flags, out DkmDataAddress dataAddress, out string type)
        {
            editableValue = null;
            dataAddress   = null;
            type          = "unknown";

            if (valueBase == null)
            {
                return(null);
            }

            if (valueBase as LuaValueDataNil != null)
            {
                type = "nil";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly;
                return("nil");
            }

            if (valueBase as LuaValueDataBool != null)
            {
                var value = valueBase as LuaValueDataBool;

                type = "bool";

                if (value.value)
                {
                    flags        |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.Boolean | DkmEvaluationResultFlags.BooleanTrue;
                    editableValue = $"{value.value}";
                    return("true");
                }
                else
                {
                    flags        |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.Boolean;
                    editableValue = $"{value.value}";
                    return("false");
                }
            }

            if (valueBase as LuaValueDataLightUserData != null)
            {
                var value = valueBase as LuaValueDataLightUserData;

                type = "user_data";

                flags        |= DkmEvaluationResultFlags.IsBuiltInType;
                editableValue = $"{value.value}";
                return($"0x{value.value:x}");
            }

            if (valueBase as LuaValueDataNumber != null)
            {
                var value = valueBase as LuaValueDataNumber;

                if (value.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                {
                    type = "int";

                    flags        |= DkmEvaluationResultFlags.IsBuiltInType;
                    editableValue = $"{value.value}";

                    if (radix == 16)
                    {
                        return($"0x{(int)value.value:x8}");
                    }

                    return($"{value.value}");
                }
                else
                {
                    type = "double";

                    flags        |= DkmEvaluationResultFlags.IsBuiltInType;
                    editableValue = $"{value.value}";
                    return($"{value.value}");
                }
            }

            if (valueBase as LuaValueDataString != null)
            {
                var value = valueBase as LuaValueDataString;

                type = value.extendedType == LuaExtendedType.ShortString ? "short_string" : "long_string";

                flags        |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.RawString;
                editableValue = $"{value.value}";
                dataAddress   = DkmDataAddress.Create(process.GetNativeRuntimeInstance(), value.targetAddress, null);
                return($"0x{value.targetAddress:x} \"{value.value}\"");
            }

            if (valueBase as LuaValueDataTable != null)
            {
                var value = valueBase as LuaValueDataTable;

                type = "table";

                flags |= DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;

                var arrayElementCount = value.value.GetArrayElementCount(process);
                var nodeElementCount  = value.value.GetNodeElementCount(process);

                if (arrayElementCount != 0 && nodeElementCount != 0)
                {
                    return($"0x{value.targetAddress:x} table [{arrayElementCount} element(s) and {nodeElementCount} key(s)]");
                }

                if (arrayElementCount != 0)
                {
                    return($"0x{value.targetAddress:x} table [{arrayElementCount} element(s)]");
                }

                if (nodeElementCount != 0)
                {
                    return($"0x{value.targetAddress:x} table [{nodeElementCount} key(s)]");
                }

                if (!value.value.HasMetaTable())
                {
                    flags &= ~DkmEvaluationResultFlags.Expandable;

                    return($"0x{value.targetAddress:x} table [empty]");
                }

                return($"0x{value.targetAddress:x} table");
            }

            if (valueBase as LuaValueDataLuaFunction != null)
            {
                var value = valueBase as LuaValueDataLuaFunction;

                type = "lua_function";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataExternalFunction != null)
            {
                var value = valueBase as LuaValueDataExternalFunction;

                type = "c_function";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataExternalClosure != null)
            {
                var value = valueBase as LuaValueDataExternalClosure;

                type = "c_closure";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataUserData != null)
            {
                var value = valueBase as LuaValueDataUserData;

                type = "user_data";

                flags |= DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataThread != null)
            {
                var value = valueBase as LuaValueDataThread;

                type = "thread";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly;
                return($"0x{value.targetAddress:x}");
            }

            return(null);
        }
        public LuaValueDataBase EvaluatePostExpressions(LuaValueDataBase value)
        {
            if (TryTakeToken(".") || TryTakeToken(":"))
            {
                string name = TryParseIdentifier();

                if (name == null)
                {
                    return(Report("Failed to find member name"));
                }

                if (value is LuaValueDataTable table)
                {
                    value = LookupTableMember(table.value, name);
                }
                else if (value is LuaValueDataUserData userData)
                {
                    if (userData.value.metaTable != null)
                    {
                        value = LookupTableMember(userData.value.metaTable, name);
                    }
                }

                if (value as LuaValueDataError != null)
                {
                    return(value);
                }

                return(EvaluatePostExpressions(value));
            }

            if (TryTakeToken("["))
            {
                var table = value as LuaValueDataTable;

                if (table == null)
                {
                    return(Report("Value is not a table"));
                }

                var index = EvaluateOr();

                if (index as LuaValueDataError != null)
                {
                    return(index);
                }

                if (process == null)
                {
                    return(Report("Can't load table - process memory is not available"));
                }

                // Check array index
                var indexAsNumber = index as LuaValueDataNumber;

                if (indexAsNumber != null && indexAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                {
                    int result = (int)indexAsNumber.value;

                    if (result > 0 && result - 1 < table.value.GetArrayElementCount(process))
                    {
                        if (!TryTakeToken("]"))
                        {
                            return(Report("Failed to find ']' after '['"));
                        }

                        var arrayElements = table.value.GetArrayElements(process);

                        return(EvaluatePostExpressions(arrayElements[result - 1]));
                    }
                }

                foreach (var element in table.value.GetNodeKeys(process))
                {
                    var elementKey = element.LoadKey(process, table.value.batchNodeElementData);

                    if (elementKey.GetType() != index.GetType())
                    {
                        continue;
                    }

                    if (elementKey.LuaCompare(index))
                    {
                        if (!TryTakeToken("]"))
                        {
                            return(Report("Failed to find ']' after '['"));
                        }

                        return(EvaluatePostExpressions(element.LoadValue(process, table.value.batchNodeElementData)));
                    }
                }

                return(Report($"Failed to find key '{index.AsSimpleDisplayString(10)}' in table"));
            }

            return(value);
        }
        // not - #
        public LuaValueDataBase EvaluateUnary()
        {
            if (TryTakeNamedToken("not"))
            {
                LuaValueDataBase lhs = EvaluateUnary();

                if (lhs as LuaValueDataError != null)
                {
                    return(lhs);
                }

                return(new LuaValueDataBool(!CoerceToBool(lhs)));
            }

            if (TryTakeToken("-"))
            {
                LuaValueDataBase lhs = EvaluateUnary();

                if (lhs as LuaValueDataError != null)
                {
                    return(lhs);
                }

                var lhsAsNumber = CoerceToNumber(lhs);

                if (lhsAsNumber == null)
                {
                    return(Report("value of the unary '-' operator must be a number"));
                }

                if (lhsAsNumber.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                {
                    return(new LuaValueDataNumber(-(int)lhsAsNumber.value));
                }

                return(new LuaValueDataNumber(-lhsAsNumber.value));
            }

            if (TryTakeToken("#"))
            {
                LuaValueDataBase lhs = EvaluateUnary();

                if (lhs as LuaValueDataError != null)
                {
                    return(lhs);
                }

                if (process == null)
                {
                    return(Report("Can't load value - process memory is not available"));
                }

                if (lhs is LuaValueDataTable table)
                {
                    return(new LuaValueDataNumber(table.value.arraySize));
                }

                if (lhs is LuaValueDataString str)
                {
                    return(new LuaValueDataNumber(str.value.Length));
                }

                return(Report("Value is not a table or a string"));
            }

            return(EvaluateTerminal());
        }
 public abstract bool LuaCompare(LuaValueDataBase rhs);
        // < > <= >= == ~=
        public LuaValueDataBase EvaluateComparisons()
        {
            LuaValueDataBase lhs = EvaluateConcatenation();

            if (lhs as LuaValueDataError != null)
            {
                return(lhs);
            }

            string token = TryTakeOneOfTokens(new[] { "<=", ">=", "==", "~=", "<", ">" });

            if (token != null)
            {
                LuaValueDataBase rhs = EvaluateConcatenation();

                if (rhs as LuaValueDataError != null)
                {
                    return(rhs);
                }

                if (token == "==")
                {
                    if (lhs.GetType() != rhs.GetType())
                    {
                        return(new LuaValueDataBool(false));
                    }

                    return(new LuaValueDataBool(lhs.LuaCompare(rhs)));
                }

                if (token == "~=")
                {
                    if (lhs.GetType() != rhs.GetType())
                    {
                        return(new LuaValueDataBool(true));
                    }

                    return(new LuaValueDataBool(!lhs.LuaCompare(rhs)));
                }

                // Other relational operators can only be applied to numbers and strings
                var lhsAsNumber = lhs as LuaValueDataNumber;
                var lhsAsString = lhs as LuaValueDataString;

                if (lhsAsNumber == null && lhsAsString == null)
                {
                    return(Report("lhs of a comparison operator must be a number or a string"));
                }

                var rhsAsNumber = rhs as LuaValueDataNumber;
                var rhsAsString = rhs as LuaValueDataString;

                if (rhsAsNumber == null && rhsAsString == null)
                {
                    return(Report("rhs of a comparison operator must be a number or a string"));
                }

                if (lhsAsNumber != null)
                {
                    if (rhsAsNumber == null)
                    {
                        return(Report("lhs of a comparison operator is number but rhs is a string"));
                    }

                    if (token == "<=")
                    {
                        return(new LuaValueDataBool(lhsAsNumber.value <= rhsAsNumber.value));
                    }

                    if (token == ">=")
                    {
                        return(new LuaValueDataBool(lhsAsNumber.value >= rhsAsNumber.value));
                    }

                    if (token == "<")
                    {
                        return(new LuaValueDataBool(lhsAsNumber.value < rhsAsNumber.value));
                    }

                    if (token == ">")
                    {
                        return(new LuaValueDataBool(lhsAsNumber.value > rhsAsNumber.value));
                    }
                }
                else
                {
                    if (rhsAsString == null)
                    {
                        return(Report("lhs of a comparison operator is string but rhs is a number"));
                    }

                    if (token == "<=")
                    {
                        return(new LuaValueDataBool(lhsAsString.value.CompareTo(rhsAsString.value) <= 0));
                    }

                    if (token == ">=")
                    {
                        return(new LuaValueDataBool(lhsAsString.value.CompareTo(rhsAsString.value) >= 0));
                    }

                    if (token == "<")
                    {
                        return(new LuaValueDataBool(lhsAsString.value.CompareTo(rhsAsString.value) < 0));
                    }

                    if (token == ">")
                    {
                        return(new LuaValueDataBool(lhsAsString.value.CompareTo(rhsAsString.value) > 0));
                    }
                }
            }

            return(lhs);
        }