/*============================================================================
    ORCA Interpreter
    Copyright (C) 2005-2006  Karl Robillard

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
===========================================================================*/

#include "os.h"
#include "ovalue.h"


void orErrorOp( const char* name, OValue* val )
{
    orError( "Invalid type %s for %s", orDatatypeName( orType(val) ), name );
}


void orOpAdd( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResult( OT_INTEGER, orInt(a1) + orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            orResultDECIMAL( (double) orInt(a1) + orDecimal(b) );
            return;
        }
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                tmp = orInt(a1) + b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResultDECIMAL( orDecimal(a1) + (double) orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            orResultDECIMAL( orDecimal(a1) + orDecimal(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                tmp = (int) orDecimal(a1) + b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue* res;
            
            res = a1;
            
            res->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] + b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] + orInt(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] + (int) orDecimal(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_TIME) )
    {
        if( orIs(b, OT_TIME) )
        {
            orSeconds(a1) += orSeconds(b);
            return;
        }
    }
    orErrorOp( "+", a1 );
}


void orOpSub( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResult( OT_INTEGER, orInt(a1) - orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            orResultDECIMAL( (double) orInt(a1) - orDecimal(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                tmp = orInt(a1) - b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResultDECIMAL( orDecimal(a1) - (double) orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            orResultDECIMAL( orDecimal(a1) - orDecimal(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                tmp = (int) orDecimal(a1) - b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue* res;
            
            res = a1;
            
            res->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] - b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] - orInt(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] - (int) orDecimal(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_TIME) )
    {
        if( orIs(b, OT_TIME) )
        {
            orSeconds(a1) -= orSeconds(b);
            return;
        }
    }
    orErrorOp( "-", a1 );
}


void orOpMul( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResult( OT_INTEGER, orInt(a1) * orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            orResultDECIMAL( (double) orInt(a1) * orDecimal(b) );
            return;
        }
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                tmp = orInt(a1) * b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResultDECIMAL( orDecimal(a1) * (double) orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            orResultDECIMAL( orDecimal(a1) * orDecimal(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                tmp = (int) orDecimal(a1) * b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue* res;
            
            res = a1;
            
            res->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] * b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] * orInt(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                tmp = a1->tuple[i] * (int) orDecimal(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        a1 = b;
    }
    orErrorOp( "*", a1 );
}


void orOpDiv( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            if( orInt(b) == 0 )
                goto div0;
            orResult( OT_INTEGER, orInt(a1) / orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            if( orDecimal(b) == 0.0 )
                goto div0;
            orResultDECIMAL( (double) orInt(a1) / orDecimal(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                if( b->tuple[i] == 0 )
                    goto div0;
                tmp = orInt(a1) / b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            if( orInt(b) == 0 )
                goto div0;
            orResultDECIMAL( orDecimal(a1) / (double) orInt(b) );
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            if( orDecimal(b) == 0.0 )
                goto div0;
            orResultDECIMAL( orDecimal(a1) / orDecimal(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                if( b->tuple[i] == 0 )
                    goto div0;
                tmp = (int) orDecimal(a1) / b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int tmp, i;
            OValue* res;
            
            res = a1;
            
            res->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < res->argc; i++ )
            {
                if( b->tuple[i] == 0 )
                    goto div0;
                tmp = a1->tuple[i] / b->tuple[i];
                res->tuple[i] = orToByteRange(tmp);
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                if( orInt(b) == 0 )
                    goto div0;
                tmp = a1->tuple[i] / orInt(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int tmp, i;
            OValue *res;

            res = a1;

            for( i = 0; i < res->argc; i++ )
            {
                if( orDecimal(b) == 0 )
                    goto div0;
                tmp = a1->tuple[i] / (int) orDecimal(b);
                res->tuple[i] = orToByteRange(tmp);
            }            
            return;
        }
        a1 = b;
    }
    orErrorOp( "/", a1 );
    return;

div0:

    orErrorT( OR_ERROR_MATH, "Divide by zero" );
}


#define CMP_LESS     0
#define CMP_EQUAL    1
#define CMP_GREATER  2
#define CMP_ERROR_B  3
#define CMP_ERROR_A  4

/*
  Returns CMP_ value.
*/
static int compareValue( const OValue* a, const OValue* b )
{
    if( orIs(a, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            if( orInt(a) > orInt(b) )
                return CMP_GREATER;
            if( orInt(a) < orInt(b) )
                return CMP_LESS;
            return CMP_EQUAL;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            double da = (double) orInt(a);
            if( da > orDecimal(b) )
                return CMP_GREATER;
            if( da < orDecimal(b) )
                return CMP_LESS;
            return CMP_EQUAL;
        }
        return CMP_ERROR_B;
    }
    else if( orIs(a, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            double db = (double) orInt(b);
            if( orDecimal(a) > db )
                return CMP_GREATER;
            if( orDecimal(a) < db )
                return CMP_LESS;
            return CMP_EQUAL;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            if( orDecimal(a) > orDecimal(b) )
                return CMP_GREATER;
            if( orDecimal(a) < orDecimal(b) )
                return CMP_LESS;
            return CMP_EQUAL;
        }
        return CMP_ERROR_B;
    }
    else if( orIs(a, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i, len;            
            len = orTupleLen(a) > orTupleLen(b) ? orTupleLen(a) : orTupleLen(b);
            for( i = 0; i < len; i++ )
            {
                if( a->tuple[i] > b->tuple[i] )
                    return CMP_GREATER;
                if( a->tuple[i] < b->tuple[i] )
                    return CMP_LESS;
            }
            return CMP_EQUAL;
        }
        return CMP_ERROR_B;
    }
    return CMP_ERROR_A;
}


void orOpGreater( OValue* a1 )
{
    OValue* b = a1 + 1;
    switch( compareValue( a1, b ) )
    {
        case CMP_LESS:
        case CMP_EQUAL:
            orResult( OT_LOGIC, OR_FALSE );
            break;
        case CMP_GREATER:
            orResult( OT_LOGIC, OR_TRUE );
            break;
        case CMP_ERROR_B:
            a1 = b;
        case CMP_ERROR_A:
            orErrorOp( ">", a1 );
            break;
    }
}


void orOpLess( OValue* a1 )
{
    OValue* b = a1 + 1;
    switch( compareValue( a1, b ) )
    {
        case CMP_LESS:
            orResult( OT_LOGIC, OR_TRUE );
            break;
        case CMP_EQUAL:
        case CMP_GREATER:
            orResult( OT_LOGIC, OR_FALSE );
            break;
        case CMP_ERROR_B:
            a1 = b;
        case CMP_ERROR_A:
            orErrorOp( "<", a1 );
            break;
    }
}


#define LOWERCASE(c) \
    if( (c >= 'A') && (c <= 'Z') ) \
        c = c + ('a' - 'A')

static int stringSame( const OValue* a, const OValue* b, int compareCase )
{
    OString* sa;
    OString* sb;
    int lenA;
    int lenB;

    sa   = orSTRING(a);
    lenA = orSeriesLen(sa, a);

    sb   = orSTRING(b);
    lenB = orSeriesLen(sb, b);

    if( lenA == lenB )
    {
        const char* ca;
        const char* cb;
        const char* end;

        ca  = orStrChars( sa, a );
        cb  = orStrChars( sb, b );

        if( ca == cb )
            return 1;

        end = ca + lenA;

        if( compareCase )
        {
            while( ca != end )
            {
                if( *ca++ != *cb++ )
                    return 0;
            }
        }
        else
        {
            while( ca != end )
            {
                lenA = *ca++;
                lenB = *cb++;

                LOWERCASE( lenA );
                LOWERCASE( lenB );

                if( lenA != lenB )
                    return 0;
            }
        }
        return 1;
    }

    return 0;
}


static int orTypeEqual( const OValue* a, const OValue* b )
{
    int logic = 0;

    if( orType(a) == orType(b) )
    {
        switch( orType(a) )
        {
            case OT_BLOCK:
            case OT_PAREN:
            case OT_PATH:
            case OT_LITPATH:
            case OT_SETPATH:
                // TODO: compare all values.
                if( (a->series.n == b->series.n) &&
                    (a->series.it == b->series.it) )
                    logic = 1;
                break;

            case OT_STRING:
            case OT_ISSUE:
            case OT_TAG:
            case OT_FILE:
                logic = stringSame( a, b, 0 );
                break;

            case OT_BINARY:
            case OT_BITSET:
                logic = stringSame( a, b, 1 );
                break;

            case OT_TUPLE:
                logic = (compareValue( a, b ) == CMP_EQUAL) ? 1 : 0;
                break;

            case OT_DECIMAL:
                if( orDecimal(a) == orDecimal(b) )
                    logic = 1;
                break;

            case OT_CHAR:
            case OT_LOGIC:
            case OT_INTEGER:
                if( orInt(a) == orInt(b) )
                    logic = 1;
                break;

            case OT_WORD:
                if( orAtom(a) == orAtom(b) )
                    logic = 1;
                break;
        }
    }

    return logic;
}


int orEqual( const OValue* a, const OValue* b )
{
    if( orIsWord(orType(a)) && orIsWord(orType(b)) )
    {
        if( orAtom(a) == orAtom(b) )
            return 1;
    }
    else if( orIs(a, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            if( orInt(a) == orInt(b) )
                return 1;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            if( ((double) orInt(a)) == orDecimal(b) )
                return 1;
        }
        return 0;
    }
    else if( orIs(a, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            if( orDecimal(a) == ((double) orInt(b)) )
                return 1;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            if( orDecimal(a) == orDecimal(b) )
                return 1;
        }
        return 0;
    }

    return orTypeEqual( a, b );
}


void orOpTypeEqual( OValue* a1 )
{
    int logic = orTypeEqual( a1, a1 + 1 );
    orResult( OT_LOGIC, logic );
}


void orOpEqual( OValue* a1 )
{
    int logic = orEqual( a1, a1 + 1 );
    orResult( OT_LOGIC, logic );
}


void orOpNotEqual( OValue* a1 )
{
    int logic = orEqual( a1, a1 + 1 ) ^ 1;
    orResult( OT_LOGIC, logic );
}


void orOpSame( OValue* a1 )
{
    int logic = 0;
    OValue* b = a1 + 1;

    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
            logic = (orInt(a1) == orInt(b));
        else if( orIs(b, OT_DECIMAL) )
            logic = ((double) orInt(a1) == orDecimal(b));
    }
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_INTEGER) )
            logic = (orDecimal(a1) == (double) orInt(b));
        else if( orIs(b, OT_DECIMAL) )
            logic = (orDecimal(a1) == orDecimal(b));
    }
    else if( orType(a1) == orType(b) )
    {
        if( orIs(a1, OT_WORD) )
        {
            if( (a1->word.atom == b->word.atom) &&
                (a1->word.context == b->word.context) )
                logic = 1;
        }
        else if( orIs(a1, OT_OBJECT) )
        {
            if( a1->index == b->index )
                logic = 1;
        }
        else if( orIsSeries( orType(a1) ) )
        {
            if( (a1->series.n == b->series.n) &&
                (a1->series.it == b->series.it) )
                logic = 1;
        }
        else if( orIs(a1, OT_TUPLE) )
        {
            logic = compareValue( a1, b );
        }
    }
    orResult( OT_LOGIC, logic );
}


void orOpLTEqual( OValue* a1 )
{
    OValue* b = a1 + 1;
    switch( compareValue( a1, b ) )
    {
        case CMP_LESS:
        case CMP_EQUAL:
            orResult( OT_LOGIC, OR_TRUE );
            break;
        case CMP_GREATER:
            orResult( OT_LOGIC, OR_FALSE );
            break;
        case CMP_ERROR_B:
            a1 = b;
        case CMP_ERROR_A:
            orErrorOp( "<=", a1 );
            break;
    }
}


void orOpGTEqual( OValue* a1 )
{
    OValue* b = a1 + 1;
    switch( compareValue( a1, b ) )
    {
        case CMP_LESS:
            orResult( OT_LOGIC, OR_FALSE );
            break;
        case CMP_EQUAL:
        case CMP_GREATER:
            orResult( OT_LOGIC, OR_TRUE );
            break;
        case CMP_ERROR_B:
            a1 = b;
        case CMP_ERROR_A:
            orErrorOp( ">=", a1 );
            break;
    }
}


void orOpAnd( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResult( OT_INTEGER, orInt(a1) & orInt(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                res->tuple[i] =  orInt(a1) & b->tuple[i];
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
#ifdef LANG_ORCA
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                res->tuple[i] =  (int) orDecimal(a1) & b->tuple[i];
            }   

            orResultCopy( *res );
            return;
        }
        a1 = b;
    }
#endif
    else if( orIs(a1, OT_LOGIC) )
    {
        if( orIs(b, OT_LOGIC) )
        {
            orResult( OT_LOGIC, orInt(a1) & orInt(b) );
            return;
        }
        else if( orIs(b, OT_NONE) )
        {
            // Weird - cannot take none as first argument.
            orResultFALSE;
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i;            
            a1->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < a1->argc; i++ )
            {
                a1->tuple[i] = a1->tuple[i] & b->tuple[i];
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int i;
            for( i = 0; i < a1->argc; i++ )
            {
                a1->tuple[i] = a1->tuple[i] & orInt(b);
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int i;
            for( i = 0; i < a1->argc; i++ )
            {
                a1->tuple[i] = a1->tuple[i] & (int) orDecimal(b);                     
            }            
            return;
        }
        a1 = b;
    }
    orErrorOp( "and", a1 );
}


void orOpOr( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResult( OT_INTEGER, orInt(a1) | orInt(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                res->tuple[i] =  orInt(a1) | b->tuple[i];
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
#ifdef LANG_ORCA
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                res->tuple[i] =  (int) orDecimal(a1) | b->tuple[i];
            }   

            orResultCopy( *res );
            return;
        }
        a1 = b;
    }
#endif
    else if( orIs(a1, OT_LOGIC) )
    {
        if( orIs(b, OT_LOGIC) )
        {
            orResult( OT_LOGIC, orInt(a1) | orInt(b) );
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i;            
            a1->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < a1->argc; i++ )
            {
                a1->tuple[i] = a1->tuple[i] | b->tuple[i];
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int i;
#ifndef LANG_ORCA
            int tmp;
#endif
            for( i = 0; i < a1->argc; i++ )
            {
#ifdef LANG_ORCA
                a1->tuple[i] = a1->tuple[i] | orInt(b);
#else
                tmp =  orToByteRange( orInt(b) );
                if( tmp == 0 )
                    a1->tuple[i] = 0;
                else if( tmp == 255 )
                    a1->tuple[i] = 255;
                else
                    a1->tuple[i] = a1->tuple[i] | orInt(b);
#endif
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int i;
#ifndef LANG_ORCA
            int tmp;
#endif
            for( i = 0; i < a1->argc; i++ )
            {
#ifdef LANG_ORCA
                a1->tuple[i] = a1->tuple[i] | (int) orDecimal(b);
#else
                tmp =  orToByteRange( (int) orDecimal(b) );
                if( tmp == 0 )
                    a1->tuple[i] = 0;
                else if( tmp == 255 )
                    a1->tuple[i] = 255;
                else
                    a1->tuple[i] = a1->tuple[i] | orToByteRange( (int) orDecimal(b) );
#endif
            }            
            return;
        }
        a1 = b;
    }
    orErrorOp( "or", a1 );
}


void orOpXor( OValue* a1 )
{
    OValue* b = a1 + 1;
    if( orIs(a1, OT_INTEGER) )
    {
        if( orIs(b, OT_INTEGER) )
        {
            orResult( OT_INTEGER, orInt(a1) ^ orInt(b) );
            return;
        }
#ifdef LANG_ORCA
        else if( orIs(b, OT_TUPLE) )
        {
            int i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                res->tuple[i] =  orInt(a1) ^ b->tuple[i];
            }   

            orResultCopy( *res );
            return;
        }
#endif
        a1 = b;
    }
#ifdef LANG_ORCA
    else if( orIs(a1, OT_DECIMAL) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i;
            OValue *res;

            res = b; 

            for( i = 0; i < res->argc; i++ )
            {
                res->tuple[i] =  (int) orDecimal(a1) ^ b->tuple[i];
            }   

            orResultCopy( *res );
            return;
        }
        a1 = b;
    }
#endif
    else if( orIs(a1, OT_LOGIC) )
    {
        if( orIs(b, OT_LOGIC) )
        {
            orResult( OT_LOGIC, orInt(a1) ^ orInt(b) );
            return;
        }
        a1 = b;
    }
    else if( orIs(a1, OT_TUPLE) )
    {
        if( orIs(b, OT_TUPLE) )
        {
            int i;            
            a1->argc = a1->argc > b->argc ? a1->argc : b->argc;
            for( i = 0; i < a1->argc; i++ )
            {
                a1->tuple[i] = a1->tuple[i] ^ b->tuple[i];
            }
            return;
        }
        else if( orIs(b, OT_INTEGER) )
        {
            int i;
#ifndef LANG_ORCA
            int tmp;
#endif
            for( i = 0; i < a1->argc; i++ )
            {
#ifdef LANG_ORCA
                a1->tuple[i] = a1->tuple[i] ^ orInt(b);
#else
                tmp =  orToByteRange( orInt(b) );
                if( tmp == 0 )
                    a1->tuple[i] = 0;
                else if( tmp == 255 )
                    a1->tuple[i] = 255;
                else
                    a1->tuple[i] = a1->tuple[i] ^ orToByteRange( orInt(b) );
#endif
            }            
            return;
        }
        else if( orIs(b, OT_DECIMAL) )
        {
            int i;
#ifndef LANG_ORCA
            int tmp;
#endif
            for( i = 0; i < a1->argc; i++ )
            {
#ifdef LANG_ORCA
                a1->tuple[i] = a1->tuple[i] ^ (int) orDecimal(b);
#else
                tmp =  orToByteRange( (int) orDecimal(b) );
                if( tmp == 0 )
                    a1->tuple[i] = 0;
                else if( tmp == 255 )
                    a1->tuple[i] = 255;
                else
                    a1->tuple[i] = a1->tuple[i] ^ orToByteRange( (int) orDecimal(b) );
#endif
            }            
            return;
        }
        a1 = b;
    }
    orErrorOp( "xor", a1 );
}


void orOddNative( OValue* a1 )
{
    int logic = 0;
    if( orIs(a1, OT_DECIMAL) )
        logic = ((int) orDecimal(a1)) & 1;
    else
        logic = orInt(a1) & 1;
    orResult( OT_LOGIC, logic );
}


void orEvenNative( OValue* a1 )
{
    orOddNative( a1 );
    orInt(a1) ^= 1;
}


void orMakeOps()
{
    orMakeOp( orOpAdd,      "+" );
    orMakeOp( orOpSub,      "-" );
    orMakeOp( orOpMul,      "*" );
    orMakeOp( orOpDiv,      "/" );
    orMakeOp( orOpGreater,  ">" );
    orMakeOp( orOpLess,     "<" );
    orMakeOp( orOpEqual,    "=" );
    orMakeOp( orOpNotEqual, "<>" );
    orMakeOp( orOpLTEqual,  "<=" );
    orMakeOp( orOpGTEqual,  ">=" );
    orMakeOp( orOpTypeEqual,"==" );
    orMakeOp( orOpSame,     "=?" );
    orMakeOp( orOpAnd,      "and" );
    orMakeOp( orOpOr,       "or"  );
    orMakeOp( orOpXor,      "xor" );

    orNative( orOpEqual,     "equal?" );
    orNative( orOpTypeEqual, "strict-equal?" );
    orNative( orOpSame,      "same?" );
    orNative( orOpGreater,   "greater?" );
    orNative( orOpLess,      "lesser?" );
    orNative( orOpGTEqual,   "greater-or-equal?" );
    orNative( orOpLTEqual,   "lesser-or-equal?" );
    orNative( orOddNative,   "odd?" );
    orNative( orEvenNative,  "even?" );
}


/*EOF*/
