Exemple #1
0
        public static List <LogInfo> Math(EngineState s, CodeCommand cmd)
        {
            List <LogInfo> logs = new List <LogInfo>();

            CodeInfo_Math info = cmd.Info.Cast <CodeInfo_Math>();

            MathType type = info.Type;

            switch (type)
            {
            case MathType.Add:
            case MathType.Sub:
            case MathType.Mul:
            case MathType.Div:
            {
                MathInfo_Arithmetic subInfo = info.SubInfo.Cast <MathInfo_Arithmetic>();

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                if (!NumberHelper.ParseDecimal(srcStr1, out decimal src1))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr1}] is not a valid integer"));
                }
                if (!NumberHelper.ParseDecimal(srcStr2, out decimal src2))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr2}] is not a valid integer"));
                }

                decimal destInt;
                switch (type)
                {
                case MathType.Add:
                    destInt = src1 + src2;
                    break;

                case MathType.Sub:
                    destInt = src1 - src2;
                    break;

                case MathType.Mul:
                    destInt = src1 * src2;
                    break;

                case MathType.Div:
                    destInt = src1 / src2;
                    break;

                default:
                    throw new InternalException("Internal Logic Error at Math,Arithmetic");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destInt.ToString(CultureInfo.InvariantCulture)));
            }
            break;

            case MathType.IntDiv:
            {
                MathInfo_IntDiv subInfo = info.SubInfo.Cast <MathInfo_IntDiv>();

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                if (srcStr1.StartsWith("-", StringComparison.Ordinal) ||
                    srcStr2.StartsWith("-", StringComparison.Ordinal))
                {         // Signed
                    if (!NumberHelper.ParseInt64(srcStr1, out long src1))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr1}] is not a valid integer"));
                    }
                    if (!NumberHelper.ParseInt64(srcStr2, out long src2))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr2}] is not a valid integer"));
                    }

                    long q = src1 / src2;
                    long r = src1 % src2;

                    logs.AddRange(Variables.SetVariable(s, subInfo.QuotientVar, q.ToString()));
                    logs.AddRange(Variables.SetVariable(s, subInfo.RemainderVar, r.ToString()));
                }
                else
                {         // Unsigned
                    if (!NumberHelper.ParseUInt64(srcStr1, out ulong src1))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr1}] is not a valid integer"));
                    }
                    if (!NumberHelper.ParseUInt64(srcStr2, out ulong src2))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr2}] is not a valid integer"));
                    }

                    ulong q = src1 / src2;
                    ulong r = src1 % src2;

                    logs.AddRange(Variables.SetVariable(s, subInfo.QuotientVar, q.ToString()));
                    logs.AddRange(Variables.SetVariable(s, subInfo.RemainderVar, r.ToString()));
                }
            }
            break;

            case MathType.Neg:
            {
                MathInfo_Neg subInfo = info.SubInfo.Cast <MathInfo_Neg>();

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (!NumberHelper.ParseDecimal(srcStr, out decimal src))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                }

                decimal destInt = src * -1;
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destInt.ToString(CultureInfo.InvariantCulture)));
            }
            break;

            case MathType.ToSign:
            case MathType.ToUnsign:
            {
                // Math,IntSign,<DestVar>,<Src>,<BitSize>
                // Math,IntUnsign,<DestVar>,<Src>,<BitSize>
                MathInfo_IntegerSignedness subInfo = info.SubInfo.Cast <MathInfo_IntegerSignedness>();

                string srcStr     = StringEscaper.Preprocess(s, subInfo.Src);
                string bitSizeStr = StringEscaper.Preprocess(s, subInfo.BitSize);
                string errorMsg   = ParseAndCheckBitSize(bitSizeStr, out int bitSize);
                if (errorMsg != null)
                {
                    return(LogInfo.LogErrorMessage(logs, errorMsg));
                }

                string destStr;
                if (info.Type == MathType.ToSign)
                {         // Unsigned int to signed int
                    switch (bitSize)
                    {
                    case 8:
                    {
                        if (!NumberHelper.ParseUInt8(srcStr, out byte src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((sbyte)src).ToString();
                    }
                    break;

                    case 16:
                    {
                        if (!NumberHelper.ParseUInt16(srcStr, out ushort src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((short)src).ToString();
                    }
                    break;

                    case 32:
                    {
                        if (!NumberHelper.ParseUInt32(srcStr, out uint src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((int)src).ToString();
                    }
                    break;

                    case 64:
                    {
                        if (!NumberHelper.ParseUInt64(srcStr, out ulong src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((long)src).ToString();
                    }
                    break;

                    default:
                        throw new InternalException("Internal Logic Error at Math,ToSign");
                    }
                }
                else
                {         // Signed int to unsigned int
                    switch (bitSize)
                    {
                    case 8:
                    {
                        if (!NumberHelper.ParseInt8(srcStr, out sbyte src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((byte)src).ToString();
                    }
                    break;

                    case 16:
                    {
                        if (!NumberHelper.ParseInt16(srcStr, out short src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((ushort)src).ToString();
                    }
                    break;

                    case 32:
                    {
                        if (!NumberHelper.ParseInt32(srcStr, out int src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((uint)src).ToString();
                    }
                    break;

                    case 64:
                    {
                        if (!NumberHelper.ParseInt64(srcStr, out long src))
                        {
                            return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                        }

                        destStr = ((ulong)src).ToString();
                    }
                    break;

                    default:
                        throw new InternalException("Internal Logic Error at Math,ToUnsign");
                    }
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.BoolAnd:
            case MathType.BoolOr:
            case MathType.BoolXor:
            {
                MathInfo_BoolLogicOperation subInfo = info.SubInfo.Cast <MathInfo_BoolLogicOperation>();

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                bool src1;
                if (NumberHelper.ParseInt64(srcStr1, out long srcInt1))         // C-Style Boolean
                {
                    src1 = srcInt1 != 0;
                }
                else if (srcStr1.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    src1 = true;
                }
                else if (srcStr1.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    src1 = false;
                }
                else
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr1}] is not valid boolean value"));
                }

                bool src2;
                if (NumberHelper.ParseInt64(srcStr2, out long srcInt2))         // C-Style Boolean
                {
                    src2 = srcInt2 != 0;
                }
                else if (srcStr2.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    src2 = true;
                }
                else if (srcStr2.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    src2 = false;
                }
                else
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr2}] is not valid boolean value"));
                }

                bool dest;
                switch (type)
                {
                case MathType.BoolAnd:
                    dest = src1 && src2;
                    break;

                case MathType.BoolOr:
                    dest = src1 || src2;
                    break;

                case MathType.BoolXor:
                    dest = src1 ^ src2;
                    break;

                default:
                    throw new InternalException("Internal Logic Error at Math,BoolLogicOper");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString()));
            }
            break;

            case MathType.BoolNot:
            {
                MathInfo_BoolNot subInfo = info.SubInfo.Cast <MathInfo_BoolNot>();

                bool   src;
                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (NumberHelper.ParseInt64(srcStr, out long srcInt))         // C-Style Boolean
                {
                    src = srcInt != 0;
                }
                else if (srcStr.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    src = true;
                }
                else if (srcStr.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    src = false;
                }
                else
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not valid boolean value"));
                }

                bool dest = !src;
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString()));
            }
            break;

            case MathType.BitAnd:
            case MathType.BitOr:
            case MathType.BitXor:
            {
                MathInfo_BitLogicOperation subInfo = info.SubInfo.Cast <MathInfo_BitLogicOperation>();

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                if (!NumberHelper.ParseUInt64(srcStr1, out ulong src1))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr1}] is not a valid integer"));
                }
                if (!NumberHelper.ParseUInt64(srcStr2, out ulong src2))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr2}] is not a valid integer"));
                }

                ulong dest;
                switch (type)
                {
                case MathType.BitAnd:
                    dest = src1 & src2;
                    break;

                case MathType.BitOr:
                    dest = src1 | src2;
                    break;

                case MathType.BitXor:
                    dest = src1 ^ src2;
                    break;

                default:
                    throw new InternalException("Internal Logic Error at Math,BitLogicOper");
                }

                string destStr = dest.ToString();
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.BitNot:
            {
                MathInfo_BitNot subInfo = info.SubInfo.Cast <MathInfo_BitNot>();

                string srcStr     = StringEscaper.Preprocess(s, subInfo.Src);
                string bitSizeStr = StringEscaper.Preprocess(s, subInfo.BitSize);
                string errorMsg   = ParseAndCheckBitSize(bitSizeStr, out int bitSize);
                if (errorMsg != null)
                {
                    return(LogInfo.LogErrorMessage(logs, errorMsg));
                }

                string destStr;
                switch (bitSize)
                {
                case 8:
                {
                    if (!NumberHelper.ParseUInt8(srcStr, out byte src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    destStr = ((byte)~src).ToString();
                }
                break;

                case 16:
                {
                    if (!NumberHelper.ParseUInt16(srcStr, out ushort src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    destStr = ((ushort)~src).ToString();
                }
                break;

                case 32:
                {
                    if (!NumberHelper.ParseUInt32(srcStr, out uint src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    destStr = (~src).ToString();
                }
                break;

                case 64:
                {
                    if (!NumberHelper.ParseUInt64(srcStr, out ulong src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    destStr = (~src).ToString();
                }
                break;

                default:
                    throw new InternalException("Internal Logic Error at Math,BitNot");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.BitShift:
            {
                MathInfo_BitShift subInfo = info.SubInfo.Cast <MathInfo_BitShift>();

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);

                string shiftStr = StringEscaper.Preprocess(s, subInfo.Shift);
                if (!NumberHelper.ParseInt32(shiftStr, out int shift))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{shiftStr}] is not a valid integer"));
                }

                string directionStr = StringEscaper.Preprocess(s, subInfo.Direction);
                bool   isLeft       = false;
                if (directionStr.Equals("Left", StringComparison.OrdinalIgnoreCase))
                {
                    isLeft = true;
                }
                else if (!directionStr.Equals("Right", StringComparison.OrdinalIgnoreCase))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{directionStr}] must be one of [Left, Right]"));
                }

                string bitSizeStr = StringEscaper.Preprocess(s, subInfo.BitSize);
                string errorMsg   = ParseAndCheckBitSize(bitSizeStr, out int bitSize);
                if (errorMsg != null)
                {
                    return(LogInfo.LogErrorMessage(logs, errorMsg));
                }

                string destStr;
                switch (bitSize)
                {
                case 8:
                {
                    if (!NumberHelper.ParseUInt8(srcStr, out byte src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    byte dest;
                    if (isLeft)
                    {
                        dest = (byte)(src << shift);
                    }
                    else
                    {
                        dest = (byte)(src >> shift);
                    }
                    destStr = dest.ToString();
                }
                break;

                case 16:
                {
                    if (!NumberHelper.ParseUInt16(srcStr, out ushort src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    ushort dest;
                    if (isLeft)
                    {
                        dest = (ushort)(src << shift);
                    }
                    else
                    {
                        dest = (ushort)(src >> shift);
                    }
                    destStr = dest.ToString();
                }
                break;

                case 32:
                {
                    if (!NumberHelper.ParseUInt32(srcStr, out uint src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    uint dest;
                    if (isLeft)
                    {
                        dest = src << shift;
                    }
                    else
                    {
                        dest = src >> shift;
                    }
                    destStr = dest.ToString();
                }
                break;

                case 64:
                {
                    if (!NumberHelper.ParseUInt64(srcStr, out ulong src))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                    }

                    ulong dest;
                    if (isLeft)
                    {
                        dest = src << shift;
                    }
                    else
                    {
                        dest = src >> shift;
                    }
                    destStr = dest.ToString();
                }
                break;

                default:
                    throw new InternalException("Internal Logic Error at Math,BitShift");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.Ceil:
            case MathType.Floor:
            case MathType.Round:
            {
                MathInfo_CeilFloorRound subInfo = info.SubInfo.Cast <MathInfo_CeilFloorRound>();

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (!NumberHelper.ParseInt64(srcStr, out long srcInt))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                }

                string unitStr = StringEscaper.Preprocess(s, subInfo.Unit);
                // Is roundToStr number?
                if (!NumberHelper.ParseInt64(unitStr, out long unit))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{unitStr}] is not a valid integer"));
                }
                if (unit < 0)
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{unit}] must be positive integer"));
                }

                long destInt;
                long remainder = srcInt % unit;
                switch (type)
                {
                case MathType.Ceil:
                    destInt = srcInt - remainder + unit;
                    break;

                case MathType.Floor:
                    destInt = srcInt - remainder;
                    break;

                case MathType.Round:
                    if ((unit - 1) / 2 < remainder)
                    {
                        destInt = srcInt - remainder + unit;
                    }
                    else
                    {
                        destInt = srcInt - remainder;
                    }
                    break;

                default:
                    throw new InternalException($"Internal Logic Error at Math,{info.Type}");
                }

                List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, destInt.ToString());
                logs.AddRange(varLogs);
            }
            break;

            case MathType.Abs:
            {
                MathInfo_Abs subInfo = info.SubInfo.Cast <MathInfo_Abs>();

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (!NumberHelper.ParseDecimal(srcStr, out decimal src))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{srcStr}] is not a valid integer"));
                }

                decimal dest = System.Math.Abs(src);
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString(CultureInfo.InvariantCulture)));
            }
            break;

            case MathType.Pow:
            {
                MathInfo_Pow subInfo = info.SubInfo.Cast <MathInfo_Pow>();

                string baseStr = StringEscaper.Preprocess(s, subInfo.Base);
                if (!NumberHelper.ParseDecimal(baseStr, out decimal _base))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{baseStr}] is not a valid integer"));
                }

                string powerStr = StringEscaper.Preprocess(s, subInfo.Power);
                if (!NumberHelper.ParseUInt32(powerStr, out uint power))
                {
                    return(LogInfo.LogErrorMessage(logs, $"[{baseStr}] is not a postivie integer"));
                }

                decimal dest = NumberHelper.DecimalPower(_base, power);
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString(CultureInfo.InvariantCulture)));
            }
            break;

            case MathType.Hex:
            case MathType.Dec:
            {
                MathInfo_HexDec subInfo = info.SubInfo.Cast <MathInfo_HexDec>();

                string intStr     = StringEscaper.Preprocess(s, subInfo.Src);
                string bitSizeStr = StringEscaper.Preprocess(s, subInfo.BitSize);
                string errorMsg   = ParseAndCheckBitSize(bitSizeStr, out int bitSize);
                if (errorMsg != null)
                {
                    return(LogInfo.LogErrorMessage(logs, errorMsg));
                }

                string dest;
                switch (bitSize)
                {
                case 8:
                    if (!NumberHelper.ParseSignedAsUInt8(intStr, out byte u8))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{intStr}] is not a valid 8bit integer"));
                    }
                    dest = info.Type == MathType.Hex ? $"0x{u8:X2}" : u8.ToString();
                    break;

                case 16:
                    if (!NumberHelper.ParseSignedAsUInt16(intStr, out ushort u16))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{intStr}] is not a valid 16bit integer"));
                    }
                    dest = info.Type == MathType.Hex ? $"0x{u16:X4}" : u16.ToString();
                    break;

                case 32:
                    if (!NumberHelper.ParseSignedAsUInt32(intStr, out uint u32))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{intStr}] is not a valid 32bit integer"));
                    }
                    dest = info.Type == MathType.Hex ? $"0x{u32:X8}" : u32.ToString();
                    break;

                case 64:
                    if (!NumberHelper.ParseSignedAsUInt64(intStr, out ulong u64))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{intStr}] is not a valid 64bit integer"));
                    }
                    dest = info.Type == MathType.Hex ? $"0x{u64:X16}" : u64.ToString();
                    break;

                default:
                    throw new InternalException($"Internal Logic Error at Math,{info.Type}");
                }

                List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, dest);
                logs.AddRange(varLogs);
            }
            break;

            case MathType.Rand:
            {
                MathInfo_Rand subInfo = info.SubInfo.Cast <MathInfo_Rand>();

                int min = 0;
                if (subInfo.Min != null)
                {
                    string minStr = StringEscaper.Preprocess(s, subInfo.Min);
                    if (!NumberHelper.ParseInt32(minStr, out min))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{minStr}] is not a valid integer"));
                    }
                    if (min < 0)
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{min}] must be positive integer"));
                    }
                }

                int max = 65536;
                if (subInfo.Max != null)
                {
                    string maxStr = StringEscaper.Preprocess(s, subInfo.Max);
                    if (!NumberHelper.ParseInt32(maxStr, out max))
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{maxStr}] is not a valid integer"));
                    }
                    if (max < 0)
                    {
                        return(LogInfo.LogErrorMessage(logs, $"[{max}] must be positive integer"));
                    }
                    if (max <= min)
                    {
                        return(LogInfo.LogErrorMessage(logs, "Maximum bounds must be larger than minimum value"));
                    }
                }

                int destInt = s.Random.Next() % (max - min) + min;

                List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, destInt.ToString());
                logs.AddRange(varLogs);
            }
            break;

            default:     // Error
                throw new InternalException("Internal Logic Error at CommandMath.Math");
            }

            return(logs);
        }
Exemple #2
0
        public static List <LogInfo> Math(EngineState s, CodeCommand cmd)
        {
            List <LogInfo> logs = new List <LogInfo>();

            Debug.Assert(cmd.Info.GetType() == typeof(CodeInfo_Math));
            CodeInfo_Math info = cmd.Info as CodeInfo_Math;

            MathType type = info.Type;

            switch (type)
            {
            case MathType.Add:
            case MathType.Sub:
            case MathType.Mul:
            case MathType.Div:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_Arithmetic));
                MathInfo_Arithmetic subInfo = info.SubInfo as MathInfo_Arithmetic;

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                if (!NumberHelper.ParseDecimal(srcStr1, out decimal src1))
                {
                    throw new ExecuteException($"[{srcStr1}] is not a valid integer");
                }
                if (!NumberHelper.ParseDecimal(srcStr2, out decimal src2))
                {
                    throw new ExecuteException($"[{srcStr2}] is not a valid integer");
                }

                decimal destInt;
                if (type == MathType.Add)
                {
                    destInt = src1 + src2;
                }
                else if (type == MathType.Sub)
                {
                    destInt = src1 - src2;
                }
                else if (type == MathType.Mul)
                {
                    destInt = src1 * src2;
                }
                else if (type == MathType.Div)
                {
                    destInt = src1 / src2;
                }
                else
                {
                    throw new InternalException($"Internal Logic Error at Math,Arithmetic");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destInt.ToString()));
            }
            break;

            case MathType.IntDiv:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_IntDiv));
                MathInfo_IntDiv subInfo = info.SubInfo as MathInfo_IntDiv;

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                if (srcStr1.StartsWith("-", StringComparison.Ordinal) || srcStr2.StartsWith("-", StringComparison.Ordinal))
                {         // Signed
                    if (!NumberHelper.ParseInt64(srcStr1, out long src1))
                    {
                        throw new ExecuteException($"[{srcStr1}] is not a valid integer");
                    }
                    if (!NumberHelper.ParseInt64(srcStr2, out long src2))
                    {
                        throw new ExecuteException($"[{srcStr2}] is not a valid integer");
                    }

                    long q = src1 / src2;
                    long r = src1 % src2;

                    logs.AddRange(Variables.SetVariable(s, subInfo.QuotientVar, q.ToString()));
                    logs.AddRange(Variables.SetVariable(s, subInfo.RemainderVar, r.ToString()));
                }
                else
                {         // Unsigned
                    if (!NumberHelper.ParseUInt64(srcStr1, out ulong src1))
                    {
                        throw new ExecuteException($"[{srcStr1}] is not a valid integer");
                    }
                    if (!NumberHelper.ParseUInt64(srcStr2, out ulong src2))
                    {
                        throw new ExecuteException($"[{srcStr2}] is not a valid integer");
                    }

                    ulong q = src1 / src2;
                    ulong r = src1 % src2;

                    logs.AddRange(Variables.SetVariable(s, subInfo.QuotientVar, q.ToString()));
                    logs.AddRange(Variables.SetVariable(s, subInfo.RemainderVar, r.ToString()));
                }
            }
            break;

            case MathType.Neg:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_Neg));
                MathInfo_Neg subInfo = info.SubInfo as MathInfo_Neg;

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (!NumberHelper.ParseDecimal(srcStr, out decimal src))
                {
                    throw new ExecuteException($"[{srcStr}] is not a valid integer");
                }

                decimal destInt = (src * -1);
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destInt.ToString()));
            }
            break;

            case MathType.ToSign:
            case MathType.ToUnsign:
            {
                // Math,IntSign,<DestVar>,<Src>,[8|16|32|64]
                // Math,IntUnsign,<DestVar>,<Src>,[8|16|32|64]

                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_IntegerSignedness));
                MathInfo_IntegerSignedness subInfo = info.SubInfo as MathInfo_IntegerSignedness;

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);

                string destStr;
                if (info.Type == MathType.ToSign)
                {         // Unsigned int to signed int
                    switch (subInfo.BitSize)
                    {
                    case 8:
                    {
                        if (!NumberHelper.ParseUInt8(srcStr, out byte src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((sbyte)src).ToString();
                    }
                    break;

                    case 16:
                    {
                        if (!NumberHelper.ParseUInt16(srcStr, out ushort src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((short)src).ToString();
                    }
                    break;

                    case 32:
                    {
                        if (!NumberHelper.ParseUInt32(srcStr, out uint src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((int)src).ToString();
                    }
                    break;

                    case 64:
                    {
                        if (!NumberHelper.ParseUInt64(srcStr, out ulong src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((long)src).ToString();
                    }
                    break;

                    default:
                        throw new InternalException($"Internal Logic Error at Math,ToSign");
                    }
                }
                else
                {         // Signed int to unsigned int
                    switch (subInfo.BitSize)
                    {
                    case 8:
                    {
                        if (!NumberHelper.ParseInt8(srcStr, out sbyte src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((byte)src).ToString();
                    }
                    break;

                    case 16:
                    {
                        if (!NumberHelper.ParseInt16(srcStr, out short src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((ushort)src).ToString();
                    }
                    break;

                    case 32:
                    {
                        if (!NumberHelper.ParseInt32(srcStr, out int src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((uint)src).ToString();
                    }
                    break;

                    case 64:
                    {
                        if (!NumberHelper.ParseInt64(srcStr, out long src))
                        {
                            throw new ExecuteException($"[{srcStr}] is not a valid integer");
                        }

                        destStr = ((ulong)src).ToString();
                    }
                    break;

                    default:
                        throw new InternalException($"Internal Logic Error at Math,ToUnsign");
                    }
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.BoolAnd:
            case MathType.BoolOr:
            case MathType.BoolXor:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_BoolLogicOper));
                MathInfo_BoolLogicOper subInfo = info.SubInfo as MathInfo_BoolLogicOper;

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                bool src1 = false;
                if (srcStr1.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    src1 = true;
                }
                else if (!srcStr1.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ExecuteException($"[{srcStr1}] is not valid boolean value");
                }

                bool src2 = false;
                if (srcStr2.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    src2 = true;
                }
                else if (!srcStr2.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ExecuteException($"[{srcStr2}] is not valid boolean value");
                }

                bool dest;
                if (type == MathType.BoolAnd)
                {
                    dest = src1 && src2;
                }
                else if (type == MathType.BoolOr)
                {
                    dest = src1 || src2;
                }
                else if (type == MathType.BoolXor)
                {
                    dest = src1 ^ src2;
                }
                else
                {
                    throw new InternalException($"Internal Logic Error at Math,BoolLogicOper");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString()));
            }
            break;

            case MathType.BoolNot:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_BoolNot));
                MathInfo_BoolNot subInfo = info.SubInfo as MathInfo_BoolNot;

                bool   src    = false;
                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (srcStr.Equals("True", StringComparison.OrdinalIgnoreCase))
                {
                    src = true;
                }
                else if (!srcStr.Equals("False", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ExecuteException($"[{srcStr}] is not valid boolean value");
                }

                bool dest = !src;
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString()));
            }
            break;

            case MathType.BitAnd:
            case MathType.BitOr:
            case MathType.BitXor:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_BitLogicOper));
                MathInfo_BitLogicOper subInfo = info.SubInfo as MathInfo_BitLogicOper;

                string srcStr1 = StringEscaper.Preprocess(s, subInfo.Src1);
                string srcStr2 = StringEscaper.Preprocess(s, subInfo.Src2);

                if (!NumberHelper.ParseUInt64(srcStr1, out ulong src1))
                {
                    throw new ExecuteException($"[{srcStr1}] is not a valid integer");
                }
                if (!NumberHelper.ParseUInt64(srcStr2, out ulong src2))
                {
                    throw new ExecuteException($"[{srcStr2}] is not a valid integer");
                }

                ulong dest;
                if (type == MathType.BitAnd)
                {
                    dest = src1 & src2;
                }
                else if (type == MathType.BitOr)
                {
                    dest = src1 | src2;
                }
                else if (type == MathType.BitXor)
                {
                    dest = src1 ^ src2;
                }
                else
                {
                    throw new InternalException($"Internal Logic Error at Math,BitLogicOper");
                }

                string destStr = dest.ToString();
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.BitNot:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_BitNot));
                MathInfo_BitNot subInfo = info.SubInfo as MathInfo_BitNot;

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                string destStr;

                switch (subInfo.BitSize)
                {
                case 8:
                {
                    if (!NumberHelper.ParseUInt8(srcStr, out byte src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    destStr = ((byte)(~src)).ToString();
                }
                break;

                case 16:
                {
                    if (!NumberHelper.ParseUInt16(srcStr, out ushort src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    destStr = ((ushort)(~src)).ToString();
                }
                break;

                case 32:
                {
                    if (!NumberHelper.ParseUInt32(srcStr, out uint src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    destStr = ((uint)(~src)).ToString();
                }
                break;

                case 64:
                {
                    if (!NumberHelper.ParseUInt64(srcStr, out ulong src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    destStr = ((ulong)(~src)).ToString();
                }
                break;

                default:
                    throw new InternalException($"Internal Logic Error at Math,BitNot");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.BitShift:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_BitShift));
                MathInfo_BitShift subInfo = info.SubInfo as MathInfo_BitShift;

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);

                string shiftStr = StringEscaper.Preprocess(s, subInfo.Shift);
                if (!NumberHelper.ParseInt32(shiftStr, out int shift))
                {
                    throw new ExecuteException($"[{shiftStr}] is not a valid integer");
                }

                string leftRightStr = StringEscaper.Preprocess(s, subInfo.LeftRight);
                bool   isLeft       = false;
                if (leftRightStr.Equals("Left", StringComparison.OrdinalIgnoreCase))
                {
                    isLeft = true;
                }
                else if (!leftRightStr.Equals("Right", StringComparison.OrdinalIgnoreCase))
                {
                    throw new ExecuteException($"[{leftRightStr}] must be one of [Left, Right]");
                }

                string destStr;
                switch (subInfo.BitSize)
                {
                case 8:
                {
                    if (!NumberHelper.ParseUInt8(srcStr, out byte src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    byte dest;
                    if (isLeft)
                    {
                        dest = (byte)(src << shift);
                    }
                    else
                    {
                        dest = (byte)(src >> shift);
                    }
                    destStr = dest.ToString();
                }
                break;

                case 16:
                {
                    if (!NumberHelper.ParseUInt16(srcStr, out ushort src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    ushort dest;
                    if (isLeft)
                    {
                        dest = (ushort)(src << shift);
                    }
                    else
                    {
                        dest = (ushort)(src >> shift);
                    }
                    destStr = dest.ToString();
                }
                break;

                case 32:
                {
                    if (!NumberHelper.ParseUInt32(srcStr, out uint src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    uint dest;
                    if (isLeft)
                    {
                        dest = (uint)(src << shift);
                    }
                    else
                    {
                        dest = (uint)(src >> shift);
                    }
                    destStr = dest.ToString();
                }
                break;

                case 64:
                {
                    if (!NumberHelper.ParseUInt64(srcStr, out ulong src))
                    {
                        throw new ExecuteException($"[{srcStr}] is not a valid integer");
                    }

                    ulong dest;
                    if (isLeft)
                    {
                        dest = (ulong)(src << shift);
                    }
                    else
                    {
                        dest = (ulong)(src >> shift);
                    }
                    destStr = dest.ToString();
                }
                break;

                default:
                    throw new InternalException($"Internal Logic Error at Math,BitShift");
                }

                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, destStr));
            }
            break;

            case MathType.Ceil:
            case MathType.Floor:
            case MathType.Round:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_CeilFloorRound));
                MathInfo_CeilFloorRound subInfo = info.SubInfo as MathInfo_CeilFloorRound;

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (!NumberHelper.ParseInt64(srcStr, out long srcInt))
                {
                    throw new ExecuteException($"[{srcStr}] is not a valid integer");
                }

                string unitStr = StringEscaper.Preprocess(s, subInfo.Unit);
                // Is roundToStr number?
                if (!NumberHelper.ParseInt64(unitStr, out long unit))
                {
                    throw new ExecuteException($"[{unitStr}] is not a valid integer");
                }
                if (unit < 0)
                {
                    throw new ExecuteException($"[{unit}] must be positive integer");
                }

                long destInt;
                long remainder = srcInt % unit;
                if (type == MathType.Ceil)
                {
                    destInt = srcInt - remainder + unit;
                }
                else if (type == MathType.Floor)
                {
                    destInt = srcInt - remainder;
                }
                else         // if (type == StrFormatType.Round)
                {
                    if ((unit - 1) / 2 < remainder)
                    {
                        destInt = srcInt - remainder + unit;
                    }
                    else
                    {
                        destInt = srcInt - remainder;
                    }
                }

                List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, destInt.ToString());
                logs.AddRange(varLogs);
            }
            break;

            case MathType.Abs:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_Abs));
                MathInfo_Abs subInfo = info.SubInfo as MathInfo_Abs;

                string srcStr = StringEscaper.Preprocess(s, subInfo.Src);
                if (!NumberHelper.ParseDecimal(srcStr, out decimal src))
                {
                    throw new ExecuteException($"[{srcStr}] is not a valid integer");
                }

                decimal dest = System.Math.Abs(src);
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString()));
            }
            break;

            case MathType.Pow:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_Pow));
                MathInfo_Pow subInfo = info.SubInfo as MathInfo_Pow;

                string baseStr = StringEscaper.Preprocess(s, subInfo.Base);
                if (!NumberHelper.ParseDecimal(baseStr, out decimal _base))
                {
                    throw new ExecuteException($"[{baseStr}] is not a valid integer");
                }

                string powerStr = StringEscaper.Preprocess(s, subInfo.Power);
                if (!NumberHelper.ParseUInt32(powerStr, out uint power))
                {
                    throw new ExecuteException($"[{baseStr}] is not a postivie integer");
                }

                decimal dest = NumberHelper.DecimalPower(_base, power);
                logs.AddRange(Variables.SetVariable(s, subInfo.DestVar, dest.ToString()));
            }
            break;

            case MathType.Hex:
            {
                Debug.Assert(info.SubInfo.GetType() == typeof(MathInfo_Hex));
                MathInfo_Hex subInfo = info.SubInfo as MathInfo_Hex;

                string intStr = StringEscaper.Preprocess(s, subInfo.Integer);
                string dest;
                switch (subInfo.BitSize)
                {
                case 8:
                    if (!NumberHelper.ParseSignedUInt8(intStr, out byte u8))
                    {
                        throw new ExecuteException($"[{intStr}] is not a valid 8bit integer");
                    }
                    dest = u8.ToString("X2");
                    break;

                case 16:
                    if (!NumberHelper.ParseSignedUInt16(intStr, out ushort u16))
                    {
                        throw new ExecuteException($"[{intStr}] is not a valid 16bit integer");
                    }
                    dest = u16.ToString("X4");
                    break;

                case 32:
                    if (!NumberHelper.ParseSignedUInt32(intStr, out uint u32))
                    {
                        throw new ExecuteException($"[{intStr}] is not a valid 32bit integer");
                    }
                    dest = u32.ToString("X8");
                    break;

                case 64:
                    if (!NumberHelper.ParseSignedUInt64(intStr, out ulong u64))
                    {
                        throw new ExecuteException($"[{intStr}] is not a valid 64bit integer");
                    }
                    dest = u64.ToString("X16");
                    break;

                default:
                    throw new InternalException($"Internal Logic Error at Math,Hex");
                }

                List <LogInfo> varLogs = Variables.SetVariable(s, subInfo.DestVar, dest);
                logs.AddRange(varLogs);
            }
            break;

            default:     // Error
                throw new InvalidCodeCommandException($"Wrong MathType [{type}]");
            }

            return(logs);
        }