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 + -
显示快捷键?