#include "variable.h" #include #include typedef Bu::ExceptionBase VariableException; bool VariableRef::operator==( const VariableRef &rhs ) const { return sid == rhs.sid && sName == rhs.sName; } Variable::Variable() : eType( tNull ), iValue( 0 ) { } Variable::Variable( const Variable &src ) : eType( tNull ), iValue( 0 ) { (*this) = src; } Variable::Variable( Type eType ) : eType( eType ), iValue( 0 ) { initType(); } Variable::Variable( int64_t iValue ) : eType( tInt ), iValue( iValue ) { } Variable::Variable( double fValue ) : eType( tFloat ), fValue( fValue ) { } Variable::Variable( bool bValue ) : eType( tBool ), bValue( bValue ) { } Variable::Variable( const Bu::String &sValue ) : eType( tString ), iValue( 0 ) { this->sValue = new Bu::String( sValue ); } Variable::Variable( Variable *pValue ) : eType( tVarPtr ), pValue( pValue ) { } Variable::~Variable() { deinitType(); } Variable Variable::newSituationName( const Bu::String &s ) { Variable v( tSituation ); (*v.sValue) = s; return v; } Variable Variable::newVariableName( const Bu::String &s, ScopeId sid ) { Variable v( tVariable ); v.rValue->sName = s; v.rValue->sid = sid; return v; } bool Variable::getBool() const { return bValue; } int64_t Variable::getInt() const { return iValue; } double Variable::getFloat() const { return fValue; } Bu::String Variable::getString() const { if( eType != tString && eType != tSituation ) throw Bu::ExceptionBase("That's not a string."); return *sValue; } VariableRef Variable::getVariableRef() const { return *rValue; } Variable *Variable::getVariablePtr() const { return pValue; } const Variable::VariableArray &Variable::getList() const { return *lValue; } const Variable::VariableHash &Variable::getHash() const { return *hValue; } Variable Variable::to( Type e ) const { if( e == eType ) return *this; switch( eType ) { case tNull: switch( e ) { case tNull: break; case tBool: break; case tInt: break; case tFloat: break; case tString: return Variable("(null)"); case tList: break; case tDictionary: break; } break; case tBool: switch( e ) { case tNull: break; case tBool: break; case tInt: break; case tFloat: break; case tString: return bValue?Variable("true"):Variable("false"); case tList: break; case tDictionary: break; } break; case tInt: switch( e ) { case tNull: break; case tBool: break; case tInt: break; case tFloat: return Variable( (double)iValue ); case tString: return Variable( Bu::String("%1").arg( iValue ) ); case tList: break; case tDictionary: break; } break; case tFloat: switch( e ) { case tNull: break; case tBool: break; case tInt: return Variable( (int64_t)fValue ); case tFloat: break; case tString: return Variable( Bu::String("%1").arg( fValue ) ); case tList: break; case tDictionary: break; } break; case tString: switch( e ) { case tNull: break; case tBool: break; case tInt: return Variable( strtoll(sValue->getStr(), NULL, 10 ) ); case tFloat: return Variable( strtod(sValue->getStr(), NULL ) ); case tString: break; case tList: break; case tDictionary: break; } break; case tList: switch( e ) { case tNull: break; case tBool: break; case tInt: break; case tFloat: break; case tString: break; case tList: break; case tDictionary: break; } break; case tDictionary: switch( e ) { case tNull: break; case tBool: break; case tInt: break; case tFloat: break; case tString: break; case tList: break; case tDictionary: break; } break; } throw VariableException("Could not convert from %d to %d.\n", eType, e ); } void Variable::insert( const Variable &vKey, const Variable &vValue ) { if( eType == tDictionary ) hValue->insert( vKey, vValue ); else if( eType == tList ) lValue->get( vKey.getInt() ) = vValue; else throw Bu::ExceptionBase("Insert on non-dictionary and non-list."); } bool Variable::has( const Variable &vKey ) { if( eType == tDictionary ) return hValue->has( vKey ); else if( eType == tList ) { for( VariableArray::const_iterator i = const_cast(lValue)->begin(); i; i++ ) { if( (*i) == vKey ) return true; } return false; } else throw Bu::ExceptionBase("Insert on non-dictionary."); } Variable &Variable::get( const Variable &vKey ) { if( eType == tDictionary ) return hValue->get( vKey ); else if( eType == tList ) return lValue->get( vKey.getInt() ); else throw Bu::ExceptionBase("Index on non-dictionary and non-list."); } Variable &Variable::operator=( const Variable &rhs ) { deinitType(); eType = rhs.eType; initType(); switch( eType ) { case tNull: break; case tBool: bValue = rhs.bValue; break; case tInt: iValue = rhs.iValue; break; case tFloat: fValue = rhs.fValue; break; case tString: case tSituation: (*sValue) = *rhs.sValue; break; case tVariable: (*rValue) = *rhs.rValue; break; case tList: (*lValue) = *rhs.lValue; break; case tDictionary: (*hValue) = *rhs.hValue; break; case tVarPtr: pValue = rhs.pValue; break; } } Variable &Variable::operator+=( const Variable &rhs ) { switch( eType ) { case tNull: throw VariableException("You cannot add nulls."); case tBool: throw VariableException("You cannot add bools."); case tInt: switch( rhs.eType ) { case tInt: iValue += rhs.iValue; break; case tFloat: { double dTmp = iValue; eType = tFloat; fValue = dTmp + rhs.fValue; } break; default: throw VariableException("Int += invalid..."); } break; case tFloat: switch( rhs.eType ) { case tInt: fValue += rhs.iValue; break; case tFloat: fValue += rhs.fValue; break; default: throw VariableException("Int += invalid..."); } break; case tString: (*sValue).append( *(rhs.to( tString ).sValue) ); break; case tSituation: throw VariableException("You cannot add situations."); break; case tVariable: throw VariableException("You cannot add variable names."); break; case tList: (*lValue).append( rhs ); break; } return *this; } Variable &Variable::operator-=( const Variable &rhs ) { switch( eType ) { case tNull: throw VariableException("You cannot subtract nulls."); case tBool: throw VariableException("You cannot subtract bools."); case tInt: switch( rhs.eType ) { case tInt: iValue -= rhs.iValue; break; case tFloat: { double dTmp = iValue; eType = tFloat; fValue = dTmp - rhs.fValue; } break; default: throw VariableException("Int -= invalid..."); } break; case tFloat: switch( rhs.eType ) { case tInt: fValue -= rhs.iValue; break; case tFloat: fValue -= rhs.fValue; break; default: throw VariableException("Int -= invalid..."); } break; case tString: throw VariableException("You cannot subtract strings."); break; case tSituation: throw VariableException("You cannot subtract situations."); break; case tVariable: throw VariableException("You cannot subtract variable names."); break; case tList: (*lValue).erase( rhs ); break; case tDictionary: (*hValue).erase( rhs ); break; } return *this; } Variable &Variable::operator*=( const Variable &rhs ) { switch( eType ) { case tNull: throw VariableException("You cannot multiply nulls."); case tBool: throw VariableException("You cannot multiply bools."); case tInt: switch( rhs.eType ) { case tInt: iValue *= rhs.iValue; break; case tFloat: { double dTmp = iValue; eType = tFloat; fValue = dTmp * rhs.fValue; } break; default: throw VariableException("Int *= invalid..."); } break; case tFloat: switch( rhs.eType ) { case tInt: fValue *= rhs.iValue; break; case tFloat: fValue *= rhs.fValue; break; default: throw VariableException("Int *= invalid..."); } break; case tString: throw VariableException("You cannot multiply strings."); break; case tSituation: throw VariableException("You cannot multiply situations."); break; case tVariable: throw VariableException("You cannot multiply variable names."); break; case tList: throw VariableException("You cannot multiply lists."); break; case tDictionary: throw VariableException("You cannot multiply dictionaries."); break; } return *this; } Variable &Variable::operator/=( const Variable &rhs ) { switch( eType ) { case tNull: throw VariableException("You cannot divide nulls."); case tBool: throw VariableException("You cannot divide bools."); case tInt: switch( rhs.eType ) { case tInt: iValue /= rhs.iValue; break; case tFloat: { double dTmp = iValue; eType = tFloat; fValue = dTmp / rhs.fValue; } break; default: throw VariableException("Int /= invalid..."); } break; case tFloat: switch( rhs.eType ) { case tInt: fValue /= rhs.iValue; break; case tFloat: fValue /= rhs.fValue; break; default: throw VariableException("Int /= invalid..."); } break; case tString: throw VariableException("You cannot divide strings."); break; case tSituation: throw VariableException("You cannot divide situations."); break; case tVariable: throw VariableException("You cannot divide variable names."); break; case tList: throw VariableException("You cannot divide lists."); break; case tDictionary: throw VariableException("You cannot divide dictionaries."); break; } return *this; } Variable Variable::operator+( const Variable &rhs ) const { if( eType != rhs.eType ) { Type eNew = bestType( eType, rhs.eType ); if( eType != eNew ) { return to( eNew ) + rhs; } else { return *this + rhs.to( eNew ); } } else { switch( eType ) { case tNull: throw VariableException("You cannot add nulls."); case tBool: throw VariableException("You cannot add booleans."); case tInt: return Variable( iValue + rhs.iValue ); case tFloat: return Variable( fValue + rhs.fValue ); case tString: return Variable( *sValue + *rhs.sValue ); case tList: { Variable vRet( tList ); vRet.lValue->append( *lValue ); vRet.lValue->append( *rhs.lValue ); return vRet; } case tDictionary: throw VariableException("You cannot add dictionaries."); break; case tSituation: throw VariableException("You cannot add situations."); case tVariable: throw VariableException("You cannot add variables."); } } } Variable Variable::operator-( const Variable &rhs ) const { if( eType != rhs.eType ) { Type eNew = bestType( eType, rhs.eType ); if( eType != eNew ) { return to( eNew ) - rhs; } else { return *this - rhs.to( eNew ); } } else { switch( eType ) { case tNull: throw VariableException("You cannot subtract nulls."); case tBool: throw VariableException("You cannot subtract booleans."); case tInt: return Variable( iValue - rhs.iValue ); case tFloat: return Variable( fValue - rhs.fValue ); case tString: throw VariableException("You cannot subtract strings."); case tList: throw VariableException("You cannot subtract lists...yet."); // TODO: make this work case tDictionary: throw VariableException("You cannot subtract dictionaries."); break; case tSituation: throw VariableException("You cannot subtract situations."); case tVariable: throw VariableException("You cannot subtract variables."); } } } Variable Variable::operator*( const Variable &rhs ) const { if( eType != rhs.eType ) { Type eNew = bestType( eType, rhs.eType ); if( eType != eNew ) { return to( eNew ) * rhs; } else { return *this * rhs.to( eNew ); } } else { switch( eType ) { case tNull: throw VariableException("You cannot multiply nulls."); case tBool: throw VariableException("You cannot multiply booleans."); case tInt: return Variable( iValue * rhs.iValue ); case tFloat: return Variable( fValue * rhs.fValue ); case tString: throw VariableException("You cannot multiply strings."); case tList: throw VariableException("You cannot multiply lists."); case tDictionary: throw VariableException("You cannot multiply dictionaries."); break; case tSituation: throw VariableException("You cannot multiply situations."); case tVariable: throw VariableException("You cannot multiply variables."); } } } Variable Variable::operator/( const Variable &rhs ) const { if( eType != rhs.eType ) { Type eNew = bestType( eType, rhs.eType ); if( eType != eNew ) { return to( eNew ) / rhs; } else { return *this / rhs.to( eNew ); } } else { switch( eType ) { case tNull: throw VariableException("You cannot divide nulls."); case tBool: throw VariableException("You cannot divide booleans."); case tInt: return Variable( iValue / rhs.iValue ); case tFloat: return Variable( fValue / rhs.fValue ); case tString: throw VariableException("You cannot divide strings."); case tList: throw VariableException("You cannot divide lists."); case tDictionary: throw VariableException("You cannot divide dictionaries."); break; case tSituation: throw VariableException("You cannot divide situations."); case tVariable: throw VariableException("You cannot divide variables."); } } } Variable Variable::operator-() const { switch( eType ) { case tNull: throw VariableException("You cannot negate nulls."); case tBool: throw VariableException("You cannot negate booleans."); case tInt: return Variable( -iValue ); case tFloat: return Variable( -fValue ); case tString: throw VariableException("You cannot negate strings."); case tList: throw VariableException("You cannot negate lists."); case tDictionary: throw VariableException("You cannot negate dictionaries."); case tSituation: throw VariableException("You cannot negate situations."); case tVariable: throw VariableException("You cannot negate variables."); } } bool Variable::operator==( const Variable &rhs ) const { if( eType != rhs.eType ) return false; switch( eType ) { case tNull: return true; case tBool: return bValue == rhs.bValue; case tInt: return iValue == rhs.iValue; case tFloat: return fValue == rhs.fValue; case tString: case tSituation: return (*sValue) == (*rhs.sValue); case tVariable: return (*rValue) == (*rhs.rValue); case tList: return (*lValue) == (*rhs.lValue); case tDictionary: return (*hValue) == (*rhs.hValue); } } bool Variable::operator!=( const Variable &rhs ) const { return !(*this == rhs); } bool Variable::operator>( const Variable &rhs ) const { if( eType != rhs.eType ) return false; switch( eType ) { case tNull: throw Bu::ExceptionBase("You cannot use > to compare nulls."); case tBool: throw Bu::ExceptionBase("You cannot use > to compare bools."); case tInt: return iValue > rhs.iValue; case tFloat: return fValue > rhs.fValue; case tString: case tSituation: case tVariable: throw Bu::ExceptionBase("You cannot use > to compare strings."); case tList: throw Bu::ExceptionBase("You cannot use > to compare lists."); case tDictionary: throw Bu::ExceptionBase("You cannot use > to compare dictionary."); } } bool Variable::operator<( const Variable &rhs ) const { if( eType != rhs.eType ) return false; switch( eType ) { case tNull: throw Bu::ExceptionBase("You cannot use < to compare nulls."); case tBool: throw Bu::ExceptionBase("You cannot use < to compare bools."); case tInt: return iValue < rhs.iValue; case tFloat: return fValue < rhs.fValue; case tString: case tSituation: case tVariable: throw Bu::ExceptionBase("You cannot use < to compare strings."); case tList: throw Bu::ExceptionBase("You cannot use < to compare lists."); case tDictionary: throw Bu::ExceptionBase("You cannot use < to compare dictionary."); } } bool Variable::operator>=( const Variable &rhs ) const { if( eType != rhs.eType ) return false; switch( eType ) { case tNull: throw Bu::ExceptionBase("You cannot use >= to compare nulls."); case tBool: throw Bu::ExceptionBase("You cannot use >= to compare bools."); case tInt: return iValue >= rhs.iValue; case tFloat: return fValue >= rhs.fValue; case tString: case tSituation: case tVariable: throw Bu::ExceptionBase("You cannot use >= to compare strings."); case tList: throw Bu::ExceptionBase("You cannot use >= to compare lists."); case tDictionary: throw Bu::ExceptionBase("You cannot use >= to compare dictionary."); } } bool Variable::operator<=( const Variable &rhs ) const { if( eType != rhs.eType ) return false; switch( eType ) { case tNull: throw Bu::ExceptionBase("You cannot use <= to compare nulls."); case tBool: throw Bu::ExceptionBase("You cannot use <= to compare bools."); case tInt: return iValue <= rhs.iValue; case tFloat: return fValue <= rhs.fValue; case tString: case tSituation: case tVariable: throw Bu::ExceptionBase("You cannot use <= to compare strings."); case tList: throw Bu::ExceptionBase("You cannot use <= to compare lists."); case tDictionary: throw Bu::ExceptionBase("You cannot use <= to compare dictionary."); } } void Variable::initType() { iValue = 0; switch( eType ) { case tString: case tSituation: sValue = new Bu::String(); break; case tVariable: rValue = new VariableRef(); break; case tList: lValue = new VariableArray(); break; case tDictionary: hValue = new VariableHash(); break; } } void Variable::deinitType() { switch( eType ) { case tString: case tSituation: delete sValue; break; case tVariable: delete rValue; break; case tList: delete lValue; break; case tDictionary: delete hValue; break; } iValue = 0; } Variable::Type Variable::bestType( Variable::Type t1, Variable::Type t2 ) const { Type tBest = Bu::max( t1, t2 ); return tBest; } template<> uint32_t Bu::__calcHashCode( const Variable &k ) { switch( k.getType() ) { case Variable::tNull: return 0; case Variable::tInt: return k.iValue; case Variable::tFloat: return k.fValue; case Variable::tString: case Variable::tSituation: return Bu::__calcHashCode( *k.sValue ); case Variable::tVariable: throw VariableException("You cannot use a variable ref as a key in a dictionary."); case Variable::tList: throw VariableException("You cannot use a list as a key in a dictionary."); case Variable::tDictionary: throw VariableException("You cannot use a dictionary as a key in a dictionary."); } } template<> bool Bu::__cmpHashKeys( const Variable &a, const Variable &b ) { return a == b; } Bu::Formatter &operator<<( Bu::Formatter &f, const Variable &v ) { switch( v.eType ) { case Variable::tNull: return f << "(null)"; case Variable::tBool: return f << v.bValue; case Variable::tInt: return f << v.iValue << "i"; case Variable::tFloat: return f << v.fValue << "f"; case Variable::tString: return f << '"' << *v.sValue << '"'; case Variable::tSituation: return f << "<<" << *v.sValue << ">>"; case Variable::tVariable: return f << "(varref:\"" << v.rValue->sName << "\")"; case Variable::tList: return f << *v.lValue; case Variable::tDictionary: return f << *v.hValue; case Variable::tVarPtr: return f << "(varptr:" << *v.pValue << ")"; } return f << "ERROR"; }