Internal data type handling changed
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 3 Jan 2006 10:05:28 +0000 (10:05 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 3 Jan 2006 10:05:28 +0000 (10:05 +0000)
include/nxsl.h
include/nxsl_classes.h
src/libnxsl/env.cpp
src/libnxsl/functions.cpp
src/libnxsl/parser.l
src/libnxsl/parser.y
src/libnxsl/program.cpp
src/libnxsl/value.cpp

index d28ab00..542f78a 100644 (file)
@@ -57,6 +57,7 @@
 #define NXSL_ERR_REAL_VALUE               10
 #define NXSL_ERR_NO_FUNCTION              11
 #define NXSL_ERR_INVALID_ARGUMENT_COUNT   12
+#define NXSL_ERR_TYPE_CAST                13
 
 
 //
index 7dff66b..c233c25 100644 (file)
 
 
 //
-// Value flags
+// Data types
 //
 
-#define VALUE_IS_NULL         ((DWORD)0x0001)
-#define VALUE_STRING_IS_VALID ((DWORD)0x0002)
-#define VALUE_IS_NUMERIC      ((DWORD)0x0004)
-#define VALUE_IS_REAL         ((DWORD)0x0008)
+#define NXSL_DT_NULL       0
+#define NXSL_DT_STRING     1
+#define NXSL_DT_REAL       2
+#define NXSL_DT_INT32      3
+#define NXSL_DT_INT64      4
+#define NXSL_DT_UINT32     5
+#define NXSL_DT_UINT64     6
 
 
 //
@@ -65,36 +68,77 @@ public:
 class LIBNXSL_EXPORTABLE NXSL_Value
 {
 protected:
-   DWORD m_dwFlags;
    DWORD m_dwStrLen;
    char *m_pszValStr;
-   int m_iValInt;
-   double m_dValFloat;
-
-   void UpdateNumbers(void);
+   BYTE m_nDataType;
+   BYTE m_bStringIsValid;
+   union
+   {
+      LONG nInt32;
+      DWORD uInt32;
+      INT64 nInt64;
+      QWORD uInt64;
+      double dReal;
+   } m_number;
+
+   void UpdateNumber(void);
    void UpdateString(void);
 
 public:
    NXSL_Value(void);
    NXSL_Value(NXSL_Value *);
-   NXSL_Value(int nValue);
+   NXSL_Value(LONG nValue);
+   NXSL_Value(INT64 nValue);
+   NXSL_Value(DWORD uValue);
+   NXSL_Value(QWORD uValue);
    NXSL_Value(double dValue);
    NXSL_Value(char *pszValue);
    ~NXSL_Value();
 
-   BOOL IsNull(void) { return (m_dwFlags & VALUE_IS_NULL) ? TRUE : FALSE; }
-   BOOL IsNumeric(void) { return (m_dwFlags & VALUE_IS_NUMERIC) ? TRUE : FALSE; }
-   BOOL IsReal(void) { return (m_dwFlags & VALUE_IS_REAL) ? TRUE : FALSE; }
+   void Set(LONG nValue);
+
+   BOOL Convert(int nDataType);
+   int DataType(void) { return m_nDataType; }
+
+   BOOL IsNull(void) { return (m_nDataType == NXSL_DT_NULL); }
+   BOOL IsNumeric(void) { return (m_nDataType > NXSL_DT_STRING); }
+   BOOL IsReal(void) { return (m_nDataType == NXSL_DT_REAL); }
+   BOOL IsInteger(void) { return (m_nDataType > NXSL_DT_REAL); }
+   BOOL IsUnsigned(void) { return (m_nDataType >= NXSL_DT_UINT32); }
+   BOOL IsZero(void);
+   BOOL IsNonZero(void);
+
    char *GetValueAsString(DWORD *pdwLen);
    char *GetValueAsCString(void);
-   int GetValueAsInt(void);
+   LONG GetValueAsInt32(void);
+   DWORD GetValueAsUInt32(void);
+   INT64 GetValueAsInt64(void);
+   QWORD GetValueAsUInt64(void);
    double GetValueAsReal(void);
 
    void Concatenate(char *pszString, DWORD dwLen);
+   
    void Increment(void);
    void Decrement(void);
    void Negate(void);
-   void Set(int nValue);
+   void BitNot(void);
+
+   void Add(NXSL_Value *pVal);
+   void Sub(NXSL_Value *pVal);
+   void Mul(NXSL_Value *pVal);
+   void Div(NXSL_Value *pVal);
+   void Rem(NXSL_Value *pVal);
+   void BitAnd(NXSL_Value *pVal);
+   void BitOr(NXSL_Value *pVal);
+   void BitXor(NXSL_Value *pVal);
+   void LShift(int nBits);
+   void RShift(int nBits);
+
+   BOOL EQ(NXSL_Value *pVal);
+   BOOL LT(NXSL_Value *pVal);
+   BOOL LE(NXSL_Value *pVal);
+   BOOL GT(NXSL_Value *pVal);
+   BOOL GE(NXSL_Value *pVal);
 };
 
 
index 98b3628..f107aa0 100644 (file)
@@ -30,6 +30,7 @@
 
 int F_abs(int argc, NXSL_Value **argv, NXSL_Value **ppResult);
 int F_pow(int argc, NXSL_Value **argv, NXSL_Value **ppResult);
+int F_typeof(int argc, NXSL_Value **argv, NXSL_Value **ppResult);
 
 
 //
@@ -39,7 +40,8 @@ int F_pow(int argc, NXSL_Value **argv, NXSL_Value **ppResult);
 static NXSL_ExtFunction m_builtinFunctions[] =
 {
    { "abs", F_abs, 1 },
-   { "pow", F_pow, 2 }
+   { "pow", F_pow, 2 },
+   { "typeof", F_typeof, 1 }
 };
 
 
index 2fdf005..8527374 100644 (file)
 
 
 //
+// Type of value
+//
+
+int F_typeof(int argc, NXSL_Value **argv, NXSL_Value **ppResult)
+{
+   static char *dt[] = { "null", "string", "real", "int32",
+                         "int64", "uint32", "uint64" };
+   
+   *ppResult = new NXSL_Value(dt[argv[0]->DataType()]);
+   return 0;
+}
+
+
+//
 // Absolute value
 //
 
@@ -36,9 +50,16 @@ int F_abs(int argc, NXSL_Value **argv, NXSL_Value **ppResult)
    if (argv[0]->IsNumeric())
    {
       if (argv[0]->IsReal())
+      {
          *ppResult = new NXSL_Value(fabs(argv[0]->GetValueAsReal()));
+      }
       else
-         *ppResult = new NXSL_Value(abs(argv[0]->GetValueAsInt()));
+      {
+         *ppResult = new NXSL_Value(argv[0]);
+         if (!argv[0]->IsUnsigned())
+            if ((*ppResult)->GetValueAsInt64() < 0)
+               (*ppResult)->Negate();
+      }
       nRet = 0;
    }
    else
index 105c0be..e5ef8a0 100644 (file)
@@ -7,6 +7,9 @@
 whitespace     [[:blank:]\t\r]+
 identifier     [A-Za-z_\$][A-Za-z_\$0-9]*
 integer                \-?(0x)?[0-9]+
+uint32         {integer}U
+int64          {integer}L
+uint64         {integer}(UL|LU)
 real           \-?[0-9]+\.[0-9]+
 escape         \\[bnrt0\"]
 
@@ -32,7 +35,24 @@ escape               \\[bnrt0\"]
 <INITIAL>"sub"         return T_SUB;
 
 <INITIAL>{identifier}  { m_plval->valStr = strdup(yytext); return T_IDENTIFIER; }
-<INITIAL>{integer}     { m_plval->valInt = strtoul(yytext, NULL, 0); return T_INTEGER; }
+<INITIAL>{integer}     {
+                               INT64 nVal;
+
+                               nVal = strtoll(yytext, NULL, 0);
+                               if ((nVal < -2147483647) || (nVal > 2147483647))
+                               {
+                                       m_plval->valInt64 = nVal;
+                                       return T_INT64;
+                               }
+                               else
+                               {
+                                       m_plval->valInt32 = (LONG)nVal;
+                                       return T_INT32;
+                               }
+                       }
+<INITIAL>{uint32}      { m_plval->valUInt32 = strtoul(yytext, NULL, 0); return T_UINT32; }
+<INITIAL>{int64}       { m_plval->valInt64 = strtoll(yytext, NULL, 0); return T_INT64; }
+<INITIAL>{uint64}      { m_plval->valUInt64 = strtoull(yytext, NULL, 0); return T_UINT64; }
 <INITIAL>{real}                { m_plval->valReal = strtod(yytext, NULL); return T_REAL; }
 
 <INITIAL>"=="  return T_EQ;
index a8e00ba..81d601c 100644 (file)
@@ -24,7 +24,10 @@ int yylex(YYSTYPE *lvalp, NXSL_Lexer *pLexer);
 
 %union
 {
-       int valInt;
+       LONG valInt32;
+       DWORD valUInt32;
+       INT64 valInt64;
+       QWORD valUInt64;
        char *valStr;
        double valReal;
        NXSL_Value *pConstant;
@@ -40,8 +43,11 @@ int yylex(YYSTYPE *lvalp, NXSL_Lexer *pLexer);
 %token T_SUB
 
 %token <valStr> T_IDENTIFIER
-%token <valInt> T_INTEGER
 %token <valStr> T_STRING
+%token <valInt32> T_INT32
+%token <valUInt32> T_UINT32
+%token <valInt64> T_INT64
+%token <valUInt64> T_UINT64
 %token <valReal> T_REAL
 
 %right '='
@@ -61,7 +67,7 @@ int yylex(YYSTYPE *lvalp, NXSL_Lexer *pLexer);
 
 %type <pConstant> Constant
 %type <valStr> FunctionName
-%type <valInt> ParameterList
+%type <valInt32> ParameterList
 %type <pInstruction> SimpleStatementKeyword
 
 %start Script
@@ -375,7 +381,19 @@ Constant:
        $$ = new NXSL_Value($1);
        free($1);
 }
-|      T_INTEGER
+|      T_INT32
+{
+       $$ = new NXSL_Value($1);
+}
+|      T_UINT32
+{
+       $$ = new NXSL_Value($1);
+}
+|      T_INT64
+{
+       $$ = new NXSL_Value($1);
+}
+|      T_UINT64
 {
        $$ = new NXSL_Value($1);
 }
index 7e75a5e..a3b6413 100644 (file)
@@ -28,7 +28,7 @@
 // Constants
 //
 
-#define MAX_ERROR_NUMBER         12
+#define MAX_ERROR_NUMBER         13
 #define CONTROL_STACK_LIMIT      32768
 
 
@@ -67,11 +67,57 @@ static TCHAR *m_szErrorMessage[MAX_ERROR_NUMBER] =
    _T("Divide by zero"),
    _T("Invalid operation with real numbers"),
    _T("Function not found"),
-   _T("Invalid number of function's arguments")
+   _T("Invalid number of function's arguments"),
+   _T("Cannot do automatic type cast")
 };
 
 
 //
+// Determine operation data type
+//
+
+static int SelectResultType(int nType1, int nType2, int nOp)
+{
+   int nType;
+
+   if (nOp == OPCODE_DIV)
+   {
+      nType = NXSL_DT_REAL;
+   }
+   else
+   {
+      if ((nType1 == NXSL_DT_REAL) || (nType2 == NXSL_DT_REAL))
+      {
+         if ((nOp == OPCODE_REM) || (nOp == OPCODE_LSHIFT) ||
+             (nOp == OPCODE_RSHIFT) || (nOp == OPCODE_BIT_AND) ||
+             (nOp == OPCODE_BIT_OR) || (nOp == OPCODE_BIT_XOR))
+         {
+            nType = NXSL_DT_NULL;   // Error
+         }
+         else
+         {
+            nType = NXSL_DT_REAL;
+         }
+      }
+      else
+      {
+         if (((nType1 >= NXSL_DT_UINT32) && (nType2 < NXSL_DT_UINT32)) ||
+             ((nType1 < NXSL_DT_UINT32) && (nType2 >= NXSL_DT_UINT32)))
+         {
+            // One operand signed, other unsigned, convert both to signed
+            if (nType1 >= NXSL_DT_UINT32)
+               nType1 -= 2;
+            else if (nType2 >= NXSL_DT_UINT32)
+               nType2 -= 2;
+         }
+         nType = max(nType1, nType2);
+      }
+   }
+   return nType;
+}
+
+
+//
 // Constructor
 //
 
@@ -401,7 +447,7 @@ void NXSL_Program::Execute(void)
          {
             if (pValue->IsNumeric())
             {
-               if (pValue->GetValueAsInt() == 0)
+               if (pValue->IsZero())
                   dwNext = cp->m_operand.m_dwAddr;
             }
             else
@@ -606,10 +652,8 @@ void NXSL_Program::DoBinaryOperation(int nOpCode)
    NXSL_Value *pVal1, *pVal2, *pRes = NULL;
    char *pszText1, *pszText2;
    DWORD dwLen1, dwLen2;
-   BOOL bRealOp;
-   double dVal;
-   int nVal;
-   int nResult;
+   int nType;
+   LONG nResult;
 
    pVal2 = (NXSL_Value *)m_pDataStack->Pop();
    pVal1 = (NXSL_Value *)m_pDataStack->Pop();
@@ -619,218 +663,121 @@ void NXSL_Program::DoBinaryOperation(int nOpCode)
       if ((!pVal1->IsNull() && !pVal2->IsNull()) ||
           (nOpCode == OPCODE_EQ) || (nOpCode == OPCODE_NE))
       {
-         if (pVal1->IsNumeric() && pVal2->IsNumeric())
+         if (pVal1->IsNumeric() && pVal2->IsNumeric() && (nOpCode != OPCODE_CONCAT))
          {
-            bRealOp = (pVal1->IsReal() || pVal2->IsReal());
-            switch(nOpCode)
+            nType = SelectResultType(pVal1->DataType(), pVal2->DataType(), nOpCode);
+            if (nType != NXSL_DT_NULL)
             {
-               case OPCODE_ADD:
-                  if (bRealOp)
-                  {
-                     dVal = pVal1->GetValueAsReal() + pVal2->GetValueAsReal();
-                     pRes = new NXSL_Value(dVal);
-                  }
-                  else
-                  {
-                     nVal = pVal1->GetValueAsInt() + pVal2->GetValueAsInt();
-                     pRes = new NXSL_Value(nVal);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_SUB:
-                  if (bRealOp)
-                  {
-                     dVal = pVal1->GetValueAsReal() - pVal2->GetValueAsReal();
-                     pRes = new NXSL_Value(dVal);
-                  }
-                  else
-                  {
-                     nVal = pVal1->GetValueAsInt() - pVal2->GetValueAsInt();
-                     pRes = new NXSL_Value(nVal);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_MUL:
-                  if (bRealOp)
-                  {
-                     dVal = pVal1->GetValueAsReal() * pVal2->GetValueAsReal();
-                     pRes = new NXSL_Value(dVal);
-                  }
-                  else
-                  {
-                     nVal = pVal1->GetValueAsInt() * pVal2->GetValueAsInt();
-                     pRes = new NXSL_Value(nVal);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_DIV:
-                  if (pVal2->GetValueAsReal() != 0)
-                  {
-                     dVal = pVal1->GetValueAsReal() / pVal2->GetValueAsReal();
-                     pRes = new NXSL_Value(dVal);
-                  }
-                  else
-                  {
-                     Error(9);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_REM:
-                  if (!bRealOp)
-                  {
-                     if (pVal2->GetValueAsInt() != 0)
-                     {
-                        nVal = pVal1->GetValueAsInt() % pVal2->GetValueAsInt();
-                        pRes = new NXSL_Value(nVal);
-                     }
-                     else
-                     {
-                        Error(9);
-                     }
-                  }
-                  else
-                  {
-                     Error(10);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_CONCAT:
-                  pRes = pVal1;
-                  pszText2 = pVal2->GetValueAsString(&dwLen2);
-                  pRes->Concatenate(pszText2, dwLen2);
-                  delete pVal2;
-                  break;
-               case OPCODE_EQ:
-               case OPCODE_NE:
-                  if (bRealOp)
-                     nResult = (pVal1->GetValueAsReal() == pVal2->GetValueAsReal());
-                  else
-                     nResult = (pVal1->GetValueAsInt() == pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value((nOpCode == OPCODE_EQ) ? nResult : !nResult);
-                  break;
-               case OPCODE_LT:
-                  if (bRealOp)
-                     nResult = (pVal1->GetValueAsReal() < pVal2->GetValueAsReal());
-                  else
-                     nResult = (pVal1->GetValueAsInt() < pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value(nResult);
-                  break;
-               case OPCODE_LE:
-                  if (bRealOp)
-                     nResult = (pVal1->GetValueAsReal() <= pVal2->GetValueAsReal());
-                  else
-                     nResult = (pVal1->GetValueAsInt() <= pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value(nResult);
-                  break;
-               case OPCODE_GT:
-                  if (bRealOp)
-                     nResult = (pVal1->GetValueAsReal() > pVal2->GetValueAsReal());
-                  else
-                     nResult = (pVal1->GetValueAsInt() > pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value(nResult);
-                  break;
-               case OPCODE_GE:
-                  if (bRealOp)
-                     nResult = (pVal1->GetValueAsReal() >= pVal2->GetValueAsReal());
-                  else
-                     nResult = (pVal1->GetValueAsInt() >= pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value(nResult);
-                  break;
-               case OPCODE_LSHIFT:
-                  if (!bRealOp)
-                  {
-                     nResult = (pVal1->GetValueAsInt() << pVal2->GetValueAsInt());
-                     pRes = new NXSL_Value(nResult);
-                  }
-                  else
-                  {
-                     Error(10);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_RSHIFT:
-                  if (!bRealOp)
-                  {
-                     nResult = (pVal1->GetValueAsInt() >> pVal2->GetValueAsInt());
-                     pRes = new NXSL_Value(nResult);
-                  }
-                  else
-                  {
-                     Error(10);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_BIT_AND:
-                  if (!bRealOp)
-                  {
-                     nResult = (pVal1->GetValueAsInt() & pVal2->GetValueAsInt());
-                     pRes = new NXSL_Value(nResult);
-                  }
-                  else
-                  {
-                     Error(10);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_BIT_OR:
-                  if (!bRealOp)
-                  {
-                     nResult = (pVal1->GetValueAsInt() | pVal2->GetValueAsInt());
-                     pRes = new NXSL_Value(nResult);
-                  }
-                  else
-                  {
-                     Error(10);
-                  }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_BIT_XOR:
-                  if (!bRealOp)
-                  {
-                     nResult = (pVal1->GetValueAsInt() ^ pVal2->GetValueAsInt());
-                     pRes = new NXSL_Value(nResult);
-                  }
-                  else
+               if ((pVal1->Convert(nType)) && (pVal2->Convert(nType)))
+               {
+                  switch(nOpCode)
                   {
-                     Error(10);
+                     case OPCODE_ADD:
+                        pRes = pVal1;
+                        pRes->Add(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_SUB:
+                        pRes = pVal1;
+                        pRes->Sub(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_MUL:
+                        pRes = pVal1;
+                        pRes->Mul(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_DIV:
+                        pRes = pVal1;
+                        pRes->Div(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_REM:
+                        pRes = pVal1;
+                        pRes->Rem(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_EQ:
+                     case OPCODE_NE:
+                        nResult = pVal1->EQ(pVal2);
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value((nOpCode == OPCODE_EQ) ? nResult : !nResult);
+                        break;
+                     case OPCODE_LT:
+                        nResult = pVal1->LT(pVal2);
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value(nResult);
+                        break;
+                     case OPCODE_LE:
+                        nResult = pVal1->LE(pVal2);
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value(nResult);
+                        break;
+                     case OPCODE_GT:
+                        nResult = pVal1->GT(pVal2);
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value(nResult);
+                        break;
+                     case OPCODE_GE:
+                        nResult = pVal1->GE(pVal2);
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value(nResult);
+                        break;
+                     case OPCODE_LSHIFT:
+                        pRes = pVal1;
+                        pRes->LShift(pVal2->GetValueAsInt32());
+                        delete pVal2;
+                        break;
+                     case OPCODE_RSHIFT:
+                        pRes = pVal1;
+                        pRes->RShift(pVal2->GetValueAsInt32());
+                        delete pVal2;
+                        break;
+                     case OPCODE_BIT_AND:
+                        pRes = pVal1;
+                        pRes->BitAnd(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_BIT_OR:
+                        pRes = pVal1;
+                        pRes->BitOr(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_BIT_XOR:
+                        pRes = pVal1;
+                        pRes->BitXor(pVal2);
+                        delete pVal2;
+                        break;
+                     case OPCODE_AND:
+                        nResult = (pVal1->IsNonZero() && pVal2->IsNonZero());
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value(nResult);
+                        break;
+                     case OPCODE_OR:
+                        nResult = (pVal1->IsNonZero() || pVal2->IsNonZero());
+                        delete pVal1;
+                        delete pVal2;
+                        pRes = new NXSL_Value(nResult);
+                        break;
+                     default:
+                        Error(NXSL_ERR_INTERNAL);
+                        break;
                   }
-                  delete pVal1;
-                  delete pVal2;
-                  break;
-               case OPCODE_AND:
-                  nResult = (pVal1->GetValueAsInt() && pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value(nResult);
-                  break;
-               case OPCODE_OR:
-                  nResult = (pVal1->GetValueAsInt() || pVal2->GetValueAsInt());
-                  delete pVal1;
-                  delete pVal2;
-                  pRes = new NXSL_Value(nResult);
-                  break;
-               default:
-                  Error(6);
-                  break;
+               }
+               else
+               {
+                  Error(NXSL_ERR_TYPE_CAST);
+               }
+            }
+            else
+            {
+               Error(NXSL_ERR_REAL_VALUE);
             }
          }
          else
@@ -933,35 +880,35 @@ void NXSL_Program::DoUnaryOperation(int nOpCode)
             case OPCODE_NOT:
                if (!pVal->IsReal())
                {
-                  pVal->Set(!pVal->GetValueAsInt());
+                  pVal->Set((LONG)pVal->IsZero());
                }
                else
                {
-                  Error(10);
+                  Error(NXSL_ERR_REAL_VALUE);
                }
                break;
             case OPCODE_BIT_NOT:
                if (!pVal->IsReal())
                {
-                  pVal->Set(~pVal->GetValueAsInt());
+                  pVal->BitNot();
                }
                else
                {
-                  Error(10);
+                  Error(NXSL_ERR_REAL_VALUE);
                }
                break;
             default:
-               Error(6);
+               Error(NXSL_ERR_INTERNAL);
                break;
          }
       }
       else
       {
-         Error(4);
+         Error(NXSL_ERR_NOT_NUMBER);
       }
    }
    else
    {
-      Error(1);
+      Error(NXSL_ERR_DATA_STACK_UNDERFLOW);
    }
 }
index 810d0fb..eef97a6 100644 (file)
 
 
 //
+// Assign value to correct number field
+//
+
+#define ASSIGN_NUMERIC_VALUE(x) \
+{ \
+   switch(m_nDataType) \
+   { \
+      case NXSL_DT_INT32: \
+         m_number.nInt32 = (x); \
+         break; \
+      case NXSL_DT_UINT32: \
+         m_number.uInt32 = (x); \
+         break; \
+      case NXSL_DT_INT64: \
+         m_number.nInt64 = (x); \
+         break; \
+      case NXSL_DT_UINT64: \
+         m_number.uInt64 = (x); \
+         break; \
+      case NXSL_DT_REAL: \
+         m_number.dReal = (x); \
+         break; \
+      default: \
+         break; \
+   } \
+}
+
+
+//
+// Retrieve correct number field
+//
+
+#define RETRIEVE_NUMERIC_VALUE(x, dt) \
+{ \
+   switch(m_nDataType) \
+   { \
+      case NXSL_DT_INT32: \
+         x = (dt)m_number.nInt32; \
+         break; \
+      case NXSL_DT_UINT32: \
+         x = (dt)m_number.uInt32; \
+         break; \
+      case NXSL_DT_INT64: \
+         x = (dt)m_number.nInt64; \
+         break; \
+      case NXSL_DT_UINT64: \
+         x = (dt)m_number.uInt64; \
+         break; \
+      case NXSL_DT_REAL: \
+         x = (dt)m_number.dReal; \
+         break; \
+      default: \
+         x = 0; \
+         break; \
+   } \
+}
+
+
+//
 // Constructors
 //
 
 NXSL_Value::NXSL_Value(void)
 {
-   m_dwFlags = VALUE_IS_NULL;
+   m_nDataType = NXSL_DT_NULL;
    m_pszValStr = NULL;
+   m_bStringIsValid = FALSE;
 }
 
 NXSL_Value::NXSL_Value(NXSL_Value *pValue)
 {
    if (pValue != NULL)
    {
-      m_dwFlags = pValue->m_dwFlags;
-      if (pValue->m_dwFlags & VALUE_STRING_IS_VALID)
+      m_nDataType = pValue->m_nDataType;
+      memcpy(&m_number, &pValue->m_number, sizeof(m_number));
+      m_bStringIsValid = pValue->m_bStringIsValid;
+      if (m_bStringIsValid)
       {
          m_dwStrLen = pValue->m_dwStrLen;
          m_pszValStr = (char *)nx_memdup(pValue->m_pszValStr, m_dwStrLen + 1);
@@ -48,39 +110,61 @@ NXSL_Value::NXSL_Value(NXSL_Value *pValue)
       {
          m_pszValStr = NULL;
       }
-      m_iValInt = pValue->m_iValInt;
-      m_dValFloat = pValue->m_dValFloat;
    }
    else
    {
-      m_dwFlags = VALUE_IS_NULL;
+      m_nDataType = NXSL_DT_NULL;
       m_pszValStr = NULL;
    }
 }
 
-NXSL_Value::NXSL_Value(int nValue)
+NXSL_Value::NXSL_Value(LONG nValue)
+{
+   m_nDataType = NXSL_DT_INT32;
+   m_pszValStr = NULL;
+   m_bStringIsValid = FALSE;
+   m_number.nInt32 = nValue;
+}
+
+NXSL_Value::NXSL_Value(DWORD uValue)
+{
+   m_nDataType = NXSL_DT_UINT32;
+   m_pszValStr = NULL;
+   m_bStringIsValid = FALSE;
+   m_number.uInt32 = uValue;
+}
+
+NXSL_Value::NXSL_Value(INT64 nValue)
 {
-   m_dwFlags = VALUE_IS_NUMERIC;
+   m_nDataType = NXSL_DT_INT64;
    m_pszValStr = NULL;
-   m_iValInt = nValue;
-   m_dValFloat = nValue;
+   m_bStringIsValid = FALSE;
+   m_number.nInt64 = nValue;
+}
+
+NXSL_Value::NXSL_Value(QWORD uValue)
+{
+   m_nDataType = NXSL_DT_UINT64;
+   m_pszValStr = NULL;
+   m_bStringIsValid = FALSE;
+   m_number.uInt64 = uValue;
 }
 
 NXSL_Value::NXSL_Value(double dValue)
 {
+   m_nDataType = NXSL_DT_REAL;
    m_pszValStr = NULL;
-   m_iValInt = (int)dValue;
-   m_dValFloat = dValue;
-   m_dwFlags = VALUE_IS_NUMERIC;
-   if ((double)m_iValInt != m_dValFloat)
-      m_dwFlags |= VALUE_IS_REAL;
+   m_bStringIsValid = FALSE;
+   m_number.dReal = dValue;
 }
 
 NXSL_Value::NXSL_Value(char *pszValue)
 {
+   m_nDataType = NXSL_DT_STRING;
    m_dwStrLen = strlen(pszValue);
    m_pszValStr = strdup(pszValue);
-   UpdateNumbers();
+   m_bStringIsValid = TRUE;
+   UpdateNumber();
 }
 
 
@@ -95,31 +179,52 @@ NXSL_Value::~NXSL_Value()
 
 
 //
-// Update flags and values after string change
+// Set value
 //
 
-void NXSL_Value::UpdateNumbers(void)
+void NXSL_Value::Set(LONG nValue)
+{
+   m_nDataType = NXSL_DT_INT32;
+   safe_free(m_pszValStr);
+   m_pszValStr = NULL;
+   m_bStringIsValid = FALSE;
+   m_number.nInt32 = nValue;
+}
+
+
+//
+// Update numeric value after string change
+//
+
+void NXSL_Value::UpdateNumber(void)
 {
    char *eptr;
+   INT64 nVal;
+   double dVal;
 
-   m_dwFlags = VALUE_STRING_IS_VALID;
-   m_iValInt = strtol(m_pszValStr, &eptr, 0);
+   nVal = strtoll(m_pszValStr, &eptr, 0);
    if ((*eptr == 0) && ((DWORD)(eptr - m_pszValStr) == m_dwStrLen))
    {
-      m_dwFlags |= VALUE_IS_NUMERIC;
-      m_dValFloat = m_iValInt;
+      if (nVal > 0x7FFFFFFF)
+      {
+         m_nDataType = NXSL_DT_INT64;
+         m_number.nInt64 = nVal;
+      }
+      else
+      {
+         m_nDataType = NXSL_DT_INT32;
+         m_number.nInt32 = (LONG)nVal;
+      }
    }
    else
    {
-      m_dValFloat = strtod(m_pszValStr, &eptr);
+      dVal = strtod(m_pszValStr, &eptr);
       if ((*eptr == 0) && ((DWORD)(eptr - m_pszValStr) == m_dwStrLen))
       {
-         m_dwFlags |= VALUE_IS_NUMERIC;
-         m_iValInt = (int)m_dValFloat;
+         m_nDataType = NXSL_DT_REAL;
+         m_number.dReal = dVal;
       }
    }
-   if ((double)m_iValInt != m_dValFloat)
-      m_dwFlags |= VALUE_IS_REAL;
 }
 
 
@@ -132,15 +237,88 @@ void NXSL_Value::UpdateString(void)
    char szBuffer[64];
 
    safe_free(m_pszValStr);
-   if (m_dwFlags & VALUE_IS_REAL)
-      sprintf(szBuffer, "%f", m_dValFloat);
-   else if (m_dwFlags & VALUE_IS_NUMERIC)
-      sprintf(szBuffer, "%d", m_iValInt);
-   else
-      szBuffer[0] = 0;
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         sprintf(szBuffer, "%d", m_number.nInt32);
+         break;
+      case NXSL_DT_UINT32:
+         sprintf(szBuffer, "%u", m_number.uInt32);
+         break;
+      case NXSL_DT_INT64:
+         sprintf(szBuffer, INT64_FMT, m_number.nInt64);
+         break;
+      case NXSL_DT_UINT64:
+         sprintf(szBuffer, UINT64_FMT, m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         sprintf(szBuffer, "%f", m_number.dReal);
+         break;
+      default:
+         szBuffer[0] = 0;
+         break;
+   }
    m_dwStrLen = strlen(szBuffer);
    m_pszValStr = strdup(szBuffer);
-   m_dwFlags |= VALUE_STRING_IS_VALID;
+   m_bStringIsValid = TRUE;
+}
+
+
+//
+// Convert to another data type
+//
+
+BOOL NXSL_Value::Convert(int nDataType)
+{
+   LONG nInt32;
+   DWORD uInt32;
+   INT64 nInt64;
+   QWORD uInt64;
+   double dReal;
+   BOOL bRet = TRUE;
+
+   if (m_nDataType == nDataType)
+      return TRUE;
+
+   switch(nDataType)
+   {
+      case NXSL_DT_INT32:
+         RETRIEVE_NUMERIC_VALUE(nInt32, LONG);
+         m_nDataType = nDataType;
+         m_number.nInt32 = nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         RETRIEVE_NUMERIC_VALUE(uInt32, DWORD);
+         m_nDataType = nDataType;
+         m_number.uInt32 = uInt32;
+         break;
+      case NXSL_DT_INT64:
+         RETRIEVE_NUMERIC_VALUE(nInt64, INT64);
+         m_nDataType = nDataType;
+         m_number.nInt64 = nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         RETRIEVE_NUMERIC_VALUE(uInt64, QWORD);
+         m_nDataType = nDataType;
+         m_number.uInt64 = uInt64;
+         break;
+      case NXSL_DT_REAL:
+         if (m_nDataType == NXSL_DT_UINT64)
+         {
+            bRet = FALSE;
+         }
+         else
+         {
+            dReal = GetValueAsReal();
+            m_nDataType = nDataType;
+            m_number.dReal = dReal;
+         }
+         break;
+      default:
+         bRet = FALSE;
+         break;
+   }
+   return bRet;
 }
 
 
@@ -150,10 +328,10 @@ void NXSL_Value::UpdateString(void)
 
 char *NXSL_Value::GetValueAsCString(void)
 {
-   if (m_dwFlags & VALUE_IS_NULL)
+   if (IsNull())
       return NULL;
 
-   if (!(m_dwFlags & VALUE_STRING_IS_VALID))
+   if (!m_bStringIsValid)
       UpdateString();
    return m_pszValStr;
 }
@@ -165,10 +343,10 @@ char *NXSL_Value::GetValueAsCString(void)
 
 char *NXSL_Value::GetValueAsString(DWORD *pdwLen)
 {
-   if (m_dwFlags & VALUE_IS_NULL)
+   if (IsNull())
       return NULL;
 
-   if (!(m_dwFlags & VALUE_STRING_IS_VALID))
+   if (!m_bStringIsValid)
       UpdateString();
    *pdwLen = m_dwStrLen;
    return m_pszValStr;
@@ -176,15 +354,54 @@ char *NXSL_Value::GetValueAsString(DWORD *pdwLen)
 
 
 //
-// Get value as integer
+// Get value as 32 bit integer
+//
+
+LONG NXSL_Value::GetValueAsInt32(void)
+{
+   LONG nVal;
+
+   RETRIEVE_NUMERIC_VALUE(nVal, LONG);
+   return nVal;
+}
+
+
+//
+// Get value as unsigned 32 bit integer
+//
+
+DWORD NXSL_Value::GetValueAsUInt32(void)
+{
+   DWORD uVal;
+
+   RETRIEVE_NUMERIC_VALUE(uVal, DWORD);
+   return uVal;
+}
+
+
+//
+// Get value as 64 bit integer
 //
 
-int NXSL_Value::GetValueAsInt(void)
+INT64 NXSL_Value::GetValueAsInt64(void)
 {
-   if (m_dwFlags & VALUE_IS_NULL)
-      return 0;
+   INT64 nVal;
 
-   return (m_dwFlags & VALUE_IS_NUMERIC) ? m_iValInt : 0;
+   RETRIEVE_NUMERIC_VALUE(nVal, INT64);
+   return nVal;
+}
+
+
+//
+// Get value as unsigned 64 bit integer
+//
+
+QWORD NXSL_Value::GetValueAsUInt64(void)
+{
+   QWORD uVal;
+
+   RETRIEVE_NUMERIC_VALUE(uVal, QWORD);
+   return uVal;
 }
 
 
@@ -194,10 +411,30 @@ int NXSL_Value::GetValueAsInt(void)
 
 double NXSL_Value::GetValueAsReal(void)
 {
-   if (m_dwFlags & VALUE_IS_NULL)
-      return 0;
+   double dVal;
 
-   return (m_dwFlags & VALUE_IS_NUMERIC) ? m_dValFloat : 0;
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         dVal = (double)m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         dVal = (double)m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         dVal = (double)m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         dVal = (double)((INT64)m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         dVal = m_number.dReal;
+         break;
+      default:
+         dVal = 0;
+         break;
+   }
+   return dVal;
 }
 
 
@@ -207,13 +444,13 @@ double NXSL_Value::GetValueAsReal(void)
 
 void NXSL_Value::Concatenate(char *pszString, DWORD dwLen)
 {
-   if (!(m_dwFlags & VALUE_STRING_IS_VALID))
+   if (!m_bStringIsValid)
       UpdateString();
    m_pszValStr = (char *)realloc(m_pszValStr, m_dwStrLen + dwLen + 1);
    memcpy(&m_pszValStr[m_dwStrLen], pszString, dwLen);
    m_dwStrLen += dwLen;
    m_pszValStr[m_dwStrLen] = 0;
-   UpdateNumbers();
+   UpdateNumber();
 }
 
 
@@ -223,21 +460,31 @@ void NXSL_Value::Concatenate(char *pszString, DWORD dwLen)
 
 void NXSL_Value::Increment(void)
 {
-   if (m_dwFlags & VALUE_IS_NUMERIC)
+   if (IsNumeric())
    {
-      if (m_dwFlags & VALUE_IS_REAL)
-      {
-         m_dValFloat++;
-         m_iValInt = (int)m_dValFloat;
-      }
-      else
+      switch(m_nDataType)
       {
-         m_iValInt++;
-         m_dValFloat = m_iValInt;
+         case NXSL_DT_INT32:
+            m_number.nInt32++;
+            break;
+         case NXSL_DT_UINT32:
+            m_number.uInt32++;
+            break;
+         case NXSL_DT_INT64:
+            m_number.nInt64++;
+            break;
+         case NXSL_DT_UINT64:
+            m_number.uInt64++;
+            break;
+         case NXSL_DT_REAL:
+            m_number.dReal++;
+            break;
+         default:
+            break;
       }
       safe_free(m_pszValStr);
       m_pszValStr = NULL;
-      m_dwFlags &= ~VALUE_STRING_IS_VALID;
+      m_bStringIsValid = FALSE;
    }
 }
 
@@ -248,21 +495,31 @@ void NXSL_Value::Increment(void)
 
 void NXSL_Value::Decrement(void)
 {
-   if (m_dwFlags & VALUE_IS_NUMERIC)
+   if (IsNumeric())
    {
-      if (m_dwFlags & VALUE_IS_REAL)
-      {
-         m_dValFloat--;
-         m_iValInt = (int)m_dValFloat;
-      }
-      else
+      switch(m_nDataType)
       {
-         m_iValInt--;
-         m_dValFloat = m_iValInt;
+         case NXSL_DT_INT32:
+            m_number.nInt32++;
+            break;
+         case NXSL_DT_UINT32:
+            m_number.uInt32++;
+            break;
+         case NXSL_DT_INT64:
+            m_number.nInt64++;
+            break;
+         case NXSL_DT_UINT64:
+            m_number.uInt64++;
+            break;
+         case NXSL_DT_REAL:
+            m_number.dReal++;
+            break;
+         default:
+            break;
       }
       safe_free(m_pszValStr);
       m_pszValStr = NULL;
-      m_dwFlags &= ~VALUE_STRING_IS_VALID;
+      m_bStringIsValid = FALSE;
    }
 }
 
@@ -273,34 +530,502 @@ void NXSL_Value::Decrement(void)
 
 void NXSL_Value::Negate(void)
 {
-   if (m_dwFlags & VALUE_IS_NUMERIC)
+   if (IsNumeric())
    {
-      if (m_dwFlags & VALUE_IS_REAL)
+      switch(m_nDataType)
       {
-         m_dValFloat = -m_dValFloat;
-         m_iValInt = (int)m_dValFloat;
+         case NXSL_DT_INT32:
+            m_number.nInt32 = -m_number.nInt32;
+            break;
+         case NXSL_DT_UINT32:
+            m_number.nInt32 = -((LONG)m_number.uInt32);
+            m_nDataType = NXSL_DT_INT32;
+            break;
+         case NXSL_DT_INT64:
+            m_number.nInt64 = -m_number.nInt64;
+            break;
+         case NXSL_DT_UINT64:
+            m_number.nInt64 = -((INT64)m_number.uInt64);
+            m_nDataType = NXSL_DT_INT64;
+            break;
+         case NXSL_DT_REAL:
+            m_number.dReal = -m_number.dReal;
+            break;
+         default:
+            break;
       }
-      else
+      safe_free(m_pszValStr);
+      m_pszValStr = NULL;
+      m_bStringIsValid = FALSE;
+   }
+}
+
+
+//
+// Bitwise NOT
+//
+
+void NXSL_Value::BitNot(void)
+{
+   if (IsNumeric())
+   {
+      switch(m_nDataType)
       {
-         m_iValInt = -m_iValInt;
-         m_dValFloat = m_iValInt;
+         case NXSL_DT_INT32:
+            m_number.nInt32 = ~m_number.nInt32;
+            break;
+         case NXSL_DT_UINT32:
+            m_number.nInt32 = ~m_number.uInt32;
+            break;
+         case NXSL_DT_INT64:
+            m_number.nInt64 = ~m_number.nInt64;
+            break;
+         case NXSL_DT_UINT64:
+            m_number.nInt64 = ~m_number.uInt64;
+            break;
+         default:
+            break;
       }
       safe_free(m_pszValStr);
       m_pszValStr = NULL;
-      m_dwFlags &= ~VALUE_STRING_IS_VALID;
+      m_bStringIsValid = FALSE;
    }
 }
 
 
 //
-// Set to numeric value
+// Check if value is zero
 //
 
-void NXSL_Value::Set(int nValue)
+BOOL NXSL_Value::IsZero(void)
 {
-   safe_free(m_pszValStr);
-   m_dwFlags = VALUE_IS_NUMERIC;
-   m_pszValStr = NULL;
-   m_iValInt = nValue;
-   m_dValFloat = nValue;
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 == 0);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 == 0);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 == 0);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 == 0);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal == 0);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+
+//
+// Check if value is not a zero
+//
+
+BOOL NXSL_Value::IsNonZero(void)
+{
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 != 0);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 != 0);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 != 0);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 != 0);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal != 0);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+
+//
+// Compare value
+// All these functions assumes that both values have same type
+//
+
+BOOL NXSL_Value::EQ(NXSL_Value *pVal)
+{
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 == pVal->m_number.nInt32);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 == pVal->m_number.uInt32);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 == pVal->m_number.nInt64);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 == pVal->m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal == pVal->m_number.dReal);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+BOOL NXSL_Value::LT(NXSL_Value *pVal)
+{
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 < pVal->m_number.nInt32);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 < pVal->m_number.uInt32);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 < pVal->m_number.nInt64);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 < pVal->m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal < pVal->m_number.dReal);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+BOOL NXSL_Value::LE(NXSL_Value *pVal)
+{
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 <= pVal->m_number.nInt32);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 <= pVal->m_number.uInt32);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 <= pVal->m_number.nInt64);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 <= pVal->m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal <= pVal->m_number.dReal);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+BOOL NXSL_Value::GT(NXSL_Value *pVal)
+{
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 > pVal->m_number.nInt32);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 > pVal->m_number.uInt32);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 > pVal->m_number.nInt64);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 > pVal->m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal > pVal->m_number.dReal);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+BOOL NXSL_Value::GE(NXSL_Value *pVal)
+{
+   BOOL bVal = FALSE;
+
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         bVal = (m_number.nInt32 >= pVal->m_number.nInt32);
+         break;
+      case NXSL_DT_UINT32:
+         bVal = (m_number.uInt32 >= pVal->m_number.uInt32);
+         break;
+      case NXSL_DT_INT64:
+         bVal = (m_number.nInt64 >= pVal->m_number.nInt64);
+         break;
+      case NXSL_DT_UINT64:
+         bVal = (m_number.uInt64 >= pVal->m_number.uInt64);
+         break;
+      case NXSL_DT_REAL:
+         bVal = (m_number.dReal >= pVal->m_number.dReal);
+         break;
+      default:
+         break;
+   }
+   return bVal;
+}
+
+
+//
+// Arithmetic and bit operations
+// All these functions assumes that both values have same type
+//
+
+void NXSL_Value::Add(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 += pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 += pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 += pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 += pVal->m_number.uInt64;
+         break;
+      case NXSL_DT_REAL:
+         m_number.dReal += pVal->m_number.dReal;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::Sub(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 -= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 -= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 -= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 -= pVal->m_number.uInt64;
+         break;
+      case NXSL_DT_REAL:
+         m_number.dReal -= pVal->m_number.dReal;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::Mul(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 *= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 *= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 *= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 *= pVal->m_number.uInt64;
+         break;
+      case NXSL_DT_REAL:
+         m_number.dReal *= pVal->m_number.dReal;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::Div(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 /= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 /= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 /= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 /= pVal->m_number.uInt64;
+         break;
+      case NXSL_DT_REAL:
+         m_number.dReal /= pVal->m_number.dReal;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::Rem(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 %= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 %= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 %= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 %= pVal->m_number.uInt64;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::BitAnd(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 &= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 &= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 &= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 &= pVal->m_number.uInt64;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::BitOr(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 |= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 |= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 |= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 |= pVal->m_number.uInt64;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::BitXor(NXSL_Value *pVal)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 ^= pVal->m_number.nInt32;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 ^= pVal->m_number.uInt32;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 ^= pVal->m_number.nInt64;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 ^= pVal->m_number.uInt64;
+         break;
+      default:
+         break;
+   }
+}
+
+
+//
+// Bit shift operations
+//
+
+void NXSL_Value::LShift(int nBits)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 <<= nBits;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 <<= nBits;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 <<= nBits;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 <<= nBits;
+         break;
+      default:
+         break;
+   }
+}
+
+void NXSL_Value::RShift(int nBits)
+{
+   switch(m_nDataType)
+   {
+      case NXSL_DT_INT32:
+         m_number.nInt32 >>= nBits;
+         break;
+      case NXSL_DT_UINT32:
+         m_number.uInt32 >>= nBits;
+         break;
+      case NXSL_DT_INT64:
+         m_number.nInt64 >>= nBits;
+         break;
+      case NXSL_DT_UINT64:
+         m_number.uInt64 >>= nBits;
+         break;
+      default:
+         break;
+   }
 }