value.cpp

来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 462 行

CPP
462
字号
///////////////////////////////////////////////////////////////////////////////
// $Header: /shorthand/src/value.cpp 6     2/14/03 4:20a Arm $
//-----------------------------------------------------------------------------
// Project: ShortHand interpreter
// Author: Andrei Remenchuk <andrei@remenchuk.com>
//-----------------------------------------------------------------------------
// value.cpp: ShortHand value object
///////////////////////////////////////////////////////////////////////////////
#include "value.h"
#include "object.h"
#include "datetime.h"
#include "except.h"
#include "sharray.h"
#include "hash.h"
#include <errno.h>

ShhValue ShhValue::EMPTY("");

static ShhValue null_value;

const char* ShhValue::getTypeName() const
{
    switch(m_type)
    {
    case SHH_INT: 
        return "integer";

    case SHH_FLOAT:
        return "decimal";

    case SHH_DATE:
        return "date";
    
    case SHH_STRING:
        return "string";
    
    case SHH_OBJECT:
        return "object";
    
    case SHH_ARRAY:
        return "array";

    case SHH_HASH:
        return "hash";

    default:
        return "undefined";
    }
}

int ShhValue::toInt() const
{
    if (m_type == SHH_INT) return m_value.u_int;
    else if (m_type == SHH_FLOAT) return (int) m_value.u_float;
    else if (m_type == SHH_STRING) 
    {
        char* e = NULL;
        int x = strtol(m_value.u_string, &e, 10);
        if (e == NULL || *e == '\0')
        {
            return x;
        }
        else
            return 0;
    }
    else if (m_type == SHH_DATE) return m_value.u_date[0]; /* jdn */
    else return (int) m_value.u_object;
}


double ShhValue::toFloat() const
{
    if (m_type == SHH_FLOAT) return m_value.u_float;
    else if (m_type == SHH_INT) return m_value.u_int;
    else if (m_type == SHH_DATE) return (double) toInt();
    else if (m_type == SHH_STRING) 
    {
        char* e = NULL;
        double x = strtod(m_value.u_string, &e);
        if (e == NULL || *e == '\0')
        {
            return x;
        }
        else
            return 0.0;
    }
    else return (int) m_value.u_object;
}

ShhObject* ShhValue::toObject() const
{
    if (m_type == SHH_OBJECT) return m_value.u_object;
    else if (m_type == SHH_ARRAY) return m_value.u_array;
    else if (m_type == SHH_HASH) return m_value.u_hash;
    else return NULL;
 
}

void ShhValue::toString(string& s) const
{
    if (m_type == SHH_INT) s.printf("%d", m_value.u_int);
    else if (m_type == SHH_STRING) s = m_value.u_string;
    else if (m_type == SHH_FLOAT)  s.printf("%.15g", m_value.u_float);
    else if (m_type == SHH_DATE)   
    {
        datetime dt; toDate(dt);
        dt.common_print(s);
    }
    else if (m_type == SHH_ARRAY) s.printf("array<%08x>", m_value.u_array);
    else if (m_type == SHH_HASH) s.printf("hash<%08x>", m_value.u_hash);
    else s.printf("object<%08x>", m_value.u_object);
}

/**
 * Optimized version of toString() that doesn't create a copy 
 * of the string if this ShhValue object already is string.
 * If it's not, supplied variable, backupBuffer is used to 
 * accomodate value converted from other data type.
 */
const char* ShhValue::toSZ(string& backupBuffer) const 
{
    if (m_type == SHH_STRING) return m_value.u_string; /* shortcut */
    else
    {
        toString(backupBuffer);
        return backupBuffer.cstr();
    }
}

void ShhValue::toDate(datetime& dt) const
{
    if (m_type == SHH_DATE) 
    {
        dt.import_jdx(m_value.u_date);
    }
    else if (m_type == SHH_INT || m_type == SHH_FLOAT)
    {
        dt.import_jdn(toInt());
    }
    else if (m_type == SHH_STRING)
    {
        if (!dt.import_mysql(m_value.u_string))
        {
            throw new ShhObjectException(4198, "Cannot convert string \"%s\" to date", m_value.u_string);
        }
    }
    else if (m_type == SHH_OBJECT)
    {
        throw new ShhObjectException(4199, "Cannot convert object to date");
    }
}


ShhValue ShhValue::null() 
{
    return null_value;
}

bool ShhValue::isLikeNumber() const
{
    if (m_type == SHH_INT || m_type == SHH_FLOAT) return true;
    else if (m_type == SHH_STRING)
    {
        char* e = NULL;
        long i_probe = strtol(m_value.u_string, &e, 10);
        if ((e == NULL || *e == '\0') && errno != ERANGE) 
        {
            return true; // can be converted to integer number
        }
        e = NULL;
        double f_probe = strtod(m_value.u_string, &e);
        if ((e == NULL || *e == '\0') && errno != ERANGE)
        {
            return true; // can be converted to decimal number
        }
    }
    return false;
}

bool ShhValue::isLikeInt() const
{
    if (m_type == SHH_INT) return true;
    else if (m_type == SHH_STRING)
    {
        char* e = NULL;
        long i_probe = strtol(m_value.u_string, &e, 10);
        if ((e == NULL || *e == '\0') && errno != ERANGE) 
        {
            return true; // can be converted to integer number
        }
    }
    return false;
}

bool ShhValue::isLikeFloat() const
{
    if (m_type == SHH_FLOAT) return true;
    else if (m_type == SHH_STRING)
    {
        if (isLikeInt()) return false;
        char* e = NULL;
        double f_probe = strtod(m_value.u_string, &e);
        if ((e == NULL || *e == '\0') && errno != ERANGE)
        {
            return true; // can be converted to decimal number
        }
    }
    return false;
}


ShhValue operator +  (const ShhValue& a, const ShhValue& b)
{
    if (a.isFloat() || b.isFloat())
        return ShhValue( a.toFloat() + b.toFloat() );
    
    else if (a.isDate())
    {
        datetime dt; a.toDate(dt); dt.add_days(b.toInt());
        return ShhValue(dt);
    }
    else if (b.isDate())
    {
        datetime dt; b.toDate(dt); dt.add_days(a.toInt());
        return ShhValue(dt);
    }
    else if (a.isLikeNumber() || b.isLikeNumber())
    {
        ShhValue result;
        if (a.isLikeFloat() || b.isLikeFloat())
            result.setFloat(a.toFloat() + b.toFloat());
        else
            result.setInt(a.toInt() + b.toInt());
        return result;
    }
    else
    {

        return ShhValue( a.toInt() + b.toInt() );
    }

}

ShhValue operator -  (const ShhValue& a, const ShhValue& b)
{
    ShhValue result;
    if (a.isFloat() || b.isFloat())
        result.setFloat( a.toFloat() - b.toFloat() );

    else if (a.isDate())
    {
        datetime dt; a.toDate(dt); dt.add_days(-b.toInt());
        result.setDate(dt);
    }
    else if (a.isLikeNumber() || b.isLikeNumber())
    {
        if (a.isLikeFloat() || b.isLikeFloat())
            result.setFloat(a.toFloat() - b.toFloat());
        else
            result.setInt(a.toInt() - b.toInt());
    }
    else 
        result.setInt( a.toInt() - b.toInt() );
    return result;
}

ShhValue operator *  (const ShhValue& a, const ShhValue& b)
{
    if (a.isFloat() || b.isFloat())
        return ShhValue( a.toFloat() * b.toFloat() );
    else if (a.isLikeNumber() || b.isLikeNumber())
    {
        ShhValue result;
        if (a.isLikeFloat() || b.isLikeFloat())
            result.setFloat(a.toFloat() * b.toFloat());
        else
            result.setInt(a.toInt() * b.toInt());
        return result;
    }
    else 
        return ShhValue( a.toInt() * b.toInt() );
}

ShhValue operator /  (const ShhValue& a, const ShhValue& b)
{
    ShhValue result;
    if (a.isFloat() || b.isFloat())
    {
        double denominator = b.toFloat();
        if (denominator == 0.0) throw new ShhObjectException(4171, "Division by zero");
        result.setFloat(a.toFloat() / denominator);
        
    }
    else if (a.isLikeNumber() || b.isLikeNumber())
    {
        if (a.isLikeInt() && b.isLikeInt())
        {
            int denominator = b.toInt();
            if (denominator == 0) throw new ShhObjectException(4171, "Division by zero");
            result.setInt(a.toInt() / denominator);
        }
        else
        {
            double denominator = b.toFloat();
            if (denominator == 0.0) throw new ShhObjectException(4171, "Division by zero");
            result.setFloat(a.toFloat() / denominator);
        }
    }
    else 
    {
        int denominator = b.toInt();
        if (denominator == 0) throw new ShhObjectException(4171, "Division by zero");
        result.setFloat( a.toInt() / denominator );
    }
    return result;
}

bool    operator == (const ShhValue& a, const ShhValue& b)
{
    
    if (a.isLikeFloat() || b.isLikeFloat())
        return a.toFloat() == b.toFloat();

    else if (a.isDate() && b.isDate())
    {
        datetime one, two;
        a.toDate(one); b.toDate(two);
        return compare_dates(one, two) == 0;
    }   

    else if (a.isObject() || b.isObject())
    {
        return a.toInt() == b.toInt();
    }
   
    else if (a.isString() && b.isString() || (a.isEmpty() || b.isEmpty()))
    {
        string s1, s2;
        a.toString(s1); b.toString(s2);
        return strcmp( s1, s2 )  == 0;
    }
    else 
    {
        return a.toInt() == b.toInt();
    }
}

bool    operator != (const ShhValue& a, const ShhValue& b)
{
    if (a.isLikeFloat() || b.isLikeFloat())

        return a.toFloat() != b.toFloat();
    
    else if (a.isDate() && b.isDate())
    {
        datetime one, two;
        a.toDate(one); b.toDate(two);
        return compare_dates(one, two) != 0;
    }   

    else if (a.isObject() || b.isObject())
    {
        return a.toInt() != b.toInt();
    }

    else if (a.isString() && b.isString() || (a.isEmpty() || b.isEmpty()))
    {
        string s1, s2;
        a.toString(s1); b.toString(s2);
        return strcmp( s1, s2 )  != 0;
    }
    else 
        return a.toInt() != b.toInt();
}

bool    operator <  (const ShhValue& a, const ShhValue& b)
{
    if (a.isLikeFloat() || b.isLikeFloat())
        return a.toFloat() < b.toFloat();
   
    else if (a.isDate() && b.isDate())
    {
        datetime one, two;
        a.toDate(one); b.toDate(two);
        return compare_dates(one, two) < 0;
    }   
    else if (a.isString() && b.isString())
    {
        string s1, s2;
        a.toString(s1); b.toString(s2);
        return strcmp( s1, s2 ) < 0;
    }
    else 
        return a.toInt() < b.toInt();
}

bool    operator >  (const ShhValue& a, const ShhValue& b)
{
    if (a.isLikeFloat() || b.isLikeFloat())
        return a.toFloat() > b.toFloat();
   
    else if (a.isDate() && b.isDate())
    {
        datetime one, two;
        a.toDate(one); b.toDate(two);
        return compare_dates(one, two) > 0;
    }   
    else if (a.isString() && b.isString())
    {
        string s1, s2;
        a.toString(s1); b.toString(s2);
        return strcmp( s1, s2 ) > 0;
    }
    else 
        return a.toInt() > b.toInt();
}

bool    operator <= (const ShhValue& a, const ShhValue& b)
{
    if (a.isLikeFloat() || b.isLikeFloat())
        return a.toFloat() <= b.toFloat();
   
    else if (a.isDate() && b.isDate())
    {
        datetime one, two;
        a.toDate(one); b.toDate(two);
        return compare_dates(one, two) <= 0;
    }   
    else if (a.isString() && b.isString())
    {
        string s1, s2;
        a.toString(s1); b.toString(s2);
        return strcmp( s1, s2 ) <= 0;
    }
    else 
        return a.toInt() <= b.toInt();
}

bool    operator >= (const ShhValue& a, const ShhValue& b)
{
    if (a.isLikeFloat() || b.isLikeFloat())
        return a.toFloat() >= b.toFloat();
   
    else if (a.isDate() && b.isDate())
    {
        datetime one, two;
        a.toDate(one); b.toDate(two);
        return compare_dates(one, two) >= 0;
    }   
    else if (a.isString() && b.isString())
    {
        string s1, s2;
        a.toString(s1); b.toString(s2);
        return strcmp( s1, s2 ) >= 0;
    }
    else 
        return a.toInt() >= b.toInt();
}



⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?