mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
1994 lines
58 KiB
C++
1994 lines
58 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright 2013 - 2018, Paul Beckingham, Federico Hernandez.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
// http://www.opensource.org/licenses/mit-license.php
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <cmake.h>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <Variant.h>
|
|
#include <Datetime.h>
|
|
#include <Duration.h>
|
|
#include <Lexer.h>
|
|
#include <RX.h>
|
|
#include <shared.h>
|
|
|
|
// These are all error messages generated by the expression evaluator, and are
|
|
// mostly concerned with how various operators interact with the different
|
|
// data types.
|
|
#define STRING_VARIANT_TIME_T "Cannot instantiate this type with a time_t value."
|
|
#define STRING_VARIANT_EXP_BOOL "Cannot exponentiate Booleans"
|
|
#define STRING_VARIANT_EXP_NON_INT "Cannot exponentiate to a non-integer power"
|
|
#define STRING_VARIANT_EXP_STRING "Cannot exponentiate strings"
|
|
#define STRING_VARIANT_EXP_DATE "Cannot exponentiate dates"
|
|
#define STRING_VARIANT_EXP_DURATION "Cannot exponentiate durations"
|
|
#define STRING_VARIANT_SUB_BOOL "Cannot subtract from a Boolean value"
|
|
#define STRING_VARIANT_SUB_STRING "Cannot subtract strings"
|
|
#define STRING_VARIANT_SUB_DATE "Cannot subtract a date"
|
|
#define STRING_VARIANT_ADD_BOOL "Cannot add two Boolean values"
|
|
#define STRING_VARIANT_ADD_DATE "Cannot add two date values"
|
|
#define STRING_VARIANT_MUL_BOOL "Cannot multiply Boolean values"
|
|
#define STRING_VARIANT_MUL_DATE "Cannot multiply date values"
|
|
#define STRING_VARIANT_MUL_REAL_STR "Cannot multiply real numbers by strings"
|
|
#define STRING_VARIANT_MUL_STR_REAL "Cannot multiply strings by real numbers"
|
|
#define STRING_VARIANT_MUL_STR_STR "Cannot multiply strings by strings"
|
|
#define STRING_VARIANT_MUL_STR_DATE "Cannot multiply strings by dates"
|
|
#define STRING_VARIANT_MUL_STR_DUR "Cannot multiply strings by durations"
|
|
#define STRING_VARIANT_MUL_DUR_STR "Cannot multiply durations by strings"
|
|
#define STRING_VARIANT_MUL_DUR_DATE "Cannot multiply durations by dates"
|
|
#define STRING_VARIANT_MUL_DUR_DUR "Cannot multiply durations by durations"
|
|
#define STRING_VARIANT_DIV_BOOL "Cannot divide Boolean values"
|
|
#define STRING_VARIANT_DIV_INT_BOOL "Cannot divide integers by Boolean values"
|
|
#define STRING_VARIANT_DIV_ZERO "Cannot divide by zero"
|
|
#define STRING_VARIANT_DIV_INT_STR "Cannot divide integer by string"
|
|
#define STRING_VARIANT_DIV_INT_DATE "Cannot divide integer by date values"
|
|
#define STRING_VARIANT_DIV_REAL_BOOL "Cannot divide real by Boolean"
|
|
#define STRING_VARIANT_DIV_REAL_STR "Cannot divide real numbers by strings"
|
|
#define STRING_VARIANT_DIV_REAL_DATE "Cannot divide real numbers by dates"
|
|
#define STRING_VARIANT_DIV_DUR_BOOL "Cannot divide duration by Boolean"
|
|
#define STRING_VARIANT_DIV_DUR_STR "Cannot divide durations by strings"
|
|
#define STRING_VARIANT_DIV_DUR_DATE "Cannot divide durations by dates"
|
|
#define STRING_VARIANT_DIV_DUR_DUR "Cannot divide durations by durations"
|
|
#define STRING_VARIANT_MOD_BOOL "Cannot modulo Booleans"
|
|
#define STRING_VARIANT_MOD_DATE "Cannot modulo date values"
|
|
#define STRING_VARIANT_MOD_DUR "Cannot modulo duration values"
|
|
#define STRING_VARIANT_MOD_INT_BOOL "Cannot modulo integer by Boolean"
|
|
#define STRING_VARIANT_MOD_INT_DATE "Cannot modulo integer by date values"
|
|
#define STRING_VARIANT_MOD_INT_DUR "Cannot modulo integer by duration values"
|
|
#define STRING_VARIANT_MOD_INT_STR "Cannot modulo integer by string"
|
|
#define STRING_VARIANT_MOD_REAL_BOOL "Cannot modulo real by Boolean"
|
|
#define STRING_VARIANT_MOD_REAL_DUR "Cannot modulo real by duration values"
|
|
#define STRING_VARIANT_MOD_REAL_DATE "Cannot modulo real numbers by dates"
|
|
#define STRING_VARIANT_MOD_REAL_STR "Cannot modulo real numbers by strings"
|
|
#define STRING_VARIANT_MOD_STR "Cannot modulo string values"
|
|
#define STRING_VARIANT_MOD_ZERO "Cannot modulo zero"
|
|
#define STRING_VARIANT_SQRT_NEG "Cannot take the square root of a negative number."
|
|
|
|
std::string Variant::dateFormat = "";
|
|
bool Variant::searchCaseSensitive = true;
|
|
bool Variant::searchUsingRegex = true;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const Variant& other)
|
|
{
|
|
_type = other._type;
|
|
_bool = other._bool;
|
|
_integer = other._integer;
|
|
_real = other._real;
|
|
_string = other._string;
|
|
_date = other._date;
|
|
_duration = other._duration;
|
|
_source = other._source;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const bool value)
|
|
: _type (Variant::type_boolean)
|
|
, _bool (value)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const int value)
|
|
: _type (Variant::type_integer)
|
|
, _integer (value)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const double value)
|
|
: _type (Variant::type_real)
|
|
, _real (value)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const std::string& value)
|
|
: _type (Variant::type_string)
|
|
, _string (value)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const char* value)
|
|
: _type (Variant::type_string)
|
|
, _string (value)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::Variant (const time_t value, const enum type new_type)
|
|
: _type (new_type)
|
|
{
|
|
switch (new_type)
|
|
{
|
|
case type_date: _date = value; break;
|
|
case type_duration: _duration = value; break;
|
|
default:
|
|
throw std::string (STRING_VARIANT_TIME_T);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Variant::source (const std::string& input)
|
|
{
|
|
_source = input;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string& Variant::source () const
|
|
{
|
|
return _source;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator= (const Variant& other)
|
|
{
|
|
_type = other._type;
|
|
_bool = other._bool;
|
|
_integer = other._integer;
|
|
_real = other._real;
|
|
_string = other._string;
|
|
_date = other._date;
|
|
_duration = other._duration;
|
|
_source = other._source;
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator&& (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
left.cast (type_boolean);
|
|
right.cast (type_boolean);
|
|
|
|
return left._bool && right._bool;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator|| (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
left.cast (type_boolean);
|
|
right.cast (type_boolean);
|
|
|
|
return left._bool || right._bool;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator_xor (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
left.cast (type_boolean);
|
|
right.cast (type_boolean);
|
|
|
|
return (left._bool && !right._bool) ||
|
|
(!left._bool && right._bool);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator< (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (left._type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: return !left._bool && right._bool;
|
|
case type_integer: left.cast (type_integer); return left._integer < right._integer;
|
|
case type_real: left.cast (type_real); return left._real < right._real;
|
|
case type_string: left.cast (type_string); return left._string < right._string;
|
|
case type_date: left.cast (type_date); return left._date < right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration < right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); return left._integer < right._integer;
|
|
case type_integer: return left._integer < right._integer;
|
|
case type_real: left.cast (type_real); return left._real < right._real;
|
|
case type_string: left.cast (type_string); return left._string < right._string;
|
|
case type_date: left.cast (type_date); return left._date < right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration < right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_real); return left._real < right._real;
|
|
case type_integer: right.cast (type_real); return left._real < right._real;
|
|
case type_real: return left._real < right._real;
|
|
case type_string: left.cast (type_string); return left._string < right._string;
|
|
case type_date: left.cast (type_date); return left._date < right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration < right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_string);
|
|
return left._string < right._string;
|
|
|
|
case type_string:
|
|
{
|
|
if (left._string == right._string)
|
|
return false;
|
|
|
|
auto order = Task::customOrder.find (left.source ());
|
|
if (order != Task::customOrder.end ())
|
|
{
|
|
// Guaranteed to be found, because of ColUDA::validate ().
|
|
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
|
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
|
return posLeft < posRight;
|
|
}
|
|
else
|
|
{
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
return left._string < right._string;
|
|
}
|
|
}
|
|
|
|
case type_date:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_date);
|
|
return left._date < right._date;
|
|
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_duration);
|
|
return left._duration < right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_date);
|
|
return left._date < right._date;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_duration);
|
|
return left._duration < right._duration;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator<= (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (left._type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: return !left._bool || right._bool;
|
|
case type_integer: left.cast (type_integer); return left._integer <= right._integer;
|
|
case type_real: left.cast (type_real); return left._real <= right._real;
|
|
case type_string: left.cast (type_string); return left._string <= right._string;
|
|
case type_date: left.cast (type_date); return left._date <= right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration <= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); return left._integer <= right._integer;
|
|
case type_integer: return left._integer <= right._integer;
|
|
case type_real: left.cast (type_real); return left._real <= right._real;
|
|
case type_string: left.cast (type_string); return left._string <= right._string;
|
|
case type_date: left.cast (type_date); return left._date <= right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration <= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_real); return left._real <= right._real;
|
|
case type_integer: right.cast (type_real); return left._real <= right._real;
|
|
case type_real: return left._real <= right._real;
|
|
case type_string: left.cast (type_string); return left._string <= right._string;
|
|
case type_date: left.cast (type_date); return left._date <= right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration <= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_string);
|
|
return left._string <= right._string;
|
|
|
|
case type_string:
|
|
{
|
|
if (left._string == right._string)
|
|
return true;
|
|
|
|
auto order = Task::customOrder.find (left.source ());
|
|
if (order != Task::customOrder.end ())
|
|
{
|
|
// Guaranteed to be found, because of ColUDA::validate ().
|
|
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
|
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
|
return posLeft <= posRight;
|
|
}
|
|
else
|
|
{
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
return left._string <= right._string;
|
|
}
|
|
}
|
|
|
|
case type_date:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_date);
|
|
return left._date <= right._date;
|
|
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_duration);
|
|
return left._duration <= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_date);
|
|
return left._date <= right._date;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_duration);
|
|
return left._duration <= right._duration;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator> (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (left._type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: return !left._bool && right._bool;
|
|
case type_integer: left.cast (type_integer); return left._integer > right._integer;
|
|
case type_real: left.cast (type_real); return left._real > right._real;
|
|
case type_string: left.cast (type_string); return left._string > right._string;
|
|
case type_date: left.cast (type_date); return left._date > right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration > right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); return left._integer > right._integer;
|
|
case type_integer: return left._integer > right._integer;
|
|
case type_real: left.cast (type_real); return left._real > right._real;
|
|
case type_string: left.cast (type_string); return left._string > right._string;
|
|
case type_date: left.cast (type_date); return left._date > right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration > right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_real); return left._real > right._real;
|
|
case type_integer: right.cast (type_real); return left._real > right._real;
|
|
case type_real: return left._real > right._real;
|
|
case type_string: left.cast (type_string); return left._string > right._string;
|
|
case type_date: left.cast (type_date); return left._date > right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration > right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_string);
|
|
return left._string > right._string;
|
|
|
|
case type_string:
|
|
{
|
|
if (left._string == right._string)
|
|
return false;
|
|
|
|
auto order = Task::customOrder.find (left.source ());
|
|
if (order != Task::customOrder.end ())
|
|
{
|
|
// Guaranteed to be found, because of ColUDA::validate ().
|
|
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
|
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
|
return posLeft > posRight;
|
|
}
|
|
else
|
|
{
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
return left._string > right._string;
|
|
}
|
|
}
|
|
|
|
case type_date:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_date);
|
|
return left._date > right._date;
|
|
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_duration);
|
|
return left._duration > right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_date);
|
|
return left._date > right._date;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_duration);
|
|
return left._duration > right._duration;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator>= (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (left._type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: return left._bool || !right._bool;
|
|
case type_integer: left.cast (type_integer); return left._integer >= right._integer;
|
|
case type_real: left.cast (type_real); return left._real >= right._real;
|
|
case type_string: left.cast (type_string); return left._string >= right._string;
|
|
case type_date: left.cast (type_date); return left._date >= right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration >= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); return left._integer >= right._integer;
|
|
case type_integer: return left._integer >= right._integer;
|
|
case type_real: left.cast (type_real); return left._real >= right._real;
|
|
case type_string: left.cast (type_string); return left._string >= right._string;
|
|
case type_date: left.cast (type_date); return left._date >= right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration >= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_real); return left._real >= right._real;
|
|
case type_integer: right.cast (type_real); return left._real >= right._real;
|
|
case type_real: return left._real >= right._real;
|
|
case type_string: left.cast (type_string); return left._string >= right._string;
|
|
case type_date: left.cast (type_date); return left._date >= right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration >= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_string);
|
|
return left._string >= right._string;
|
|
|
|
case type_string:
|
|
{
|
|
if (left._string == right._string)
|
|
return true;
|
|
|
|
auto order = Task::customOrder.find (left.source ());
|
|
if (order != Task::customOrder.end ())
|
|
{
|
|
// Guaranteed to be found, because of ColUDA::validate ().
|
|
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
|
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
|
return posLeft >= posRight;
|
|
}
|
|
else
|
|
{
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
return left._string >= right._string;
|
|
}
|
|
}
|
|
|
|
case type_date:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_date);
|
|
return left._date >= right._date;
|
|
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_duration);
|
|
return left._duration >= right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_date);
|
|
return left._date >= right._date;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_duration);
|
|
return left._duration >= right._duration;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator== (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (left._type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: return left._bool == right._bool;
|
|
case type_integer: left.cast (type_integer); return left._integer == right._integer;
|
|
case type_real: left.cast (type_real); return left._real == right._real;
|
|
case type_string: left.cast (type_string); return left._string == right._string;
|
|
case type_date: left.cast (type_date); return left._date == right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); return left._integer == right._integer;
|
|
case type_integer: return left._integer == right._integer;
|
|
case type_real: left.cast (type_real); return left._real == right._real;
|
|
case type_string: left.cast (type_string); return left._string == right._string;
|
|
case type_date: left.cast (type_date); return left._date == right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_real); return left._real == right._real;
|
|
case type_integer: right.cast (type_real); return left._real == right._real;
|
|
case type_real: return left._real == right._real;
|
|
case type_string: left.cast (type_string); return left._string == right._string;
|
|
case type_date: left.cast (type_date); return left._date == right._date;
|
|
case type_duration: left.cast (type_duration); return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
right.cast (type_string);
|
|
|
|
// Status is always compared caseless.
|
|
if (left.source () == "status")
|
|
return compare (left._string, right._string, false);
|
|
|
|
return left._string == right._string;
|
|
|
|
case type_date:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_date);
|
|
return left._date == right._date;
|
|
|
|
case type_duration:
|
|
left.cast (type_duration);
|
|
return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
right.cast (type_date);
|
|
return left._date == right._date;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
right.cast (type_duration);
|
|
return left._duration == right._duration;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator!= (const Variant& other) const
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator_match (const Variant& other, const Task& task) const
|
|
{
|
|
// Simple matching case first.
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
left.cast (type_string);
|
|
right.cast (type_string);
|
|
|
|
std::string pattern = right._string;
|
|
Lexer::dequote (pattern);
|
|
|
|
if (searchUsingRegex)
|
|
{
|
|
RX r (pattern, searchCaseSensitive);
|
|
if (r.match (left._string))
|
|
return true;
|
|
|
|
// If the above did not match, and the left source is "description", then
|
|
// in the annotations.
|
|
if (left.source () == "description")
|
|
{
|
|
for (auto& a : task.getAnnotations ())
|
|
if (r.match (a.second))
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If pattern starts with '^', look for a leftmost compare only.
|
|
if (pattern[0] == '^' &&
|
|
find (left._string,
|
|
pattern.substr (1),
|
|
searchCaseSensitive) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// If pattern ends with '$', look for a rightmost compare only.
|
|
else if (pattern[pattern.length () - 1] == '$' &&
|
|
find (left._string,
|
|
pattern.substr (0, pattern.length () - 1),
|
|
searchCaseSensitive) == (left._string.length () - pattern.length () + 1))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
else if (find (left._string, pattern, searchCaseSensitive) != std::string::npos)
|
|
return true;
|
|
|
|
// If the above did not match, and the left source is "description", then
|
|
// in the annotations.
|
|
if (left.source () == "description")
|
|
{
|
|
for (auto& a : task.getAnnotations ())
|
|
if (find (a.second, pattern, searchCaseSensitive) != std::string::npos)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator_nomatch (const Variant& other, const Task& task) const
|
|
{
|
|
return ! operator_match (other, task);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Partial match is mostly a clone of operator==, but with some overrides:
|
|
//
|
|
// date <partial> date --> same day check
|
|
// string <partial> string --> leftmost
|
|
//
|
|
bool Variant::operator_partial (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
Variant right (other);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (left._type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: return left._bool == right._bool;
|
|
case type_integer: left.cast (type_integer); return left._integer == right._integer;
|
|
case type_real: left.cast (type_real); return left._real == right._real;
|
|
case type_string: left.cast (type_string); return left._string == right._string;
|
|
|
|
// Same-day comparison.
|
|
case type_date:
|
|
{
|
|
left.cast (type_date);
|
|
Datetime left_date (left._date);
|
|
Datetime right_date (right._date);
|
|
return left_date.sameDay (right_date);
|
|
}
|
|
|
|
case type_duration: left.cast (type_duration); return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); return left._integer == right._integer;
|
|
case type_integer: return left._integer == right._integer;
|
|
case type_real: left.cast (type_real); return left._real == right._real;
|
|
case type_string: left.cast (type_string); return left._string == right._string;
|
|
|
|
// Same-day comparison.
|
|
case type_date:
|
|
{
|
|
left.cast (type_date);
|
|
Datetime left_date (left._date);
|
|
Datetime right_date (right._date);
|
|
return left_date.sameDay (right_date);
|
|
}
|
|
|
|
case type_duration: left.cast (type_duration); return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_real);
|
|
return left._real == right._real;
|
|
|
|
case type_string:
|
|
left.cast (type_string);
|
|
return left._string == right._string;
|
|
|
|
// Same-day comparison.
|
|
case type_date:
|
|
{
|
|
left.cast (type_date);
|
|
Datetime left_date (left._date);
|
|
Datetime right_date (right._date);
|
|
return left_date.sameDay (right_date);
|
|
}
|
|
|
|
case type_duration:
|
|
left.cast (type_duration);
|
|
return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
{
|
|
right.cast (type_string);
|
|
|
|
// Status is always compared caseless.
|
|
if (left.source () == "status")
|
|
return compare (left._string, right._string, false);
|
|
|
|
int left_len = left._string.length ();
|
|
int right_len = right._string.length ();
|
|
|
|
if ((left_len == 0 && right_len != 0) ||
|
|
(left_len != 0 && right_len == 0))
|
|
return false;
|
|
|
|
// Dodgy.
|
|
if (left._string.length () < right._string.length ())
|
|
return false;
|
|
|
|
return left._string.substr (0, right._string.length ()) == right._string;
|
|
}
|
|
|
|
// Same-day comparison.
|
|
case type_date:
|
|
{
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
left.cast (type_date);
|
|
Datetime left_date (left._date);
|
|
Datetime right_date (right._date);
|
|
return left_date.sameDay (right_date);
|
|
}
|
|
|
|
case type_duration:
|
|
left.cast (type_duration);
|
|
return left._duration == right._duration;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
// Same-day comparison.
|
|
case type_string:
|
|
if (left.trivial () || right.trivial ())
|
|
return false;
|
|
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_date:
|
|
case type_duration:
|
|
{
|
|
right.cast (type_date);
|
|
Datetime left_date (left._date);
|
|
Datetime right_date (right._date);
|
|
return left_date.sameDay (right_date);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
// Same-day comparison.
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_string:
|
|
case type_date:
|
|
case type_duration:
|
|
right.cast (type_duration);
|
|
return left._duration == right._duration;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Inverse of operator_partial.
|
|
bool Variant::operator_nopartial (const Variant& other) const
|
|
{
|
|
return ! operator_partial (other);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator_hastag (const Variant& other, const Task& task) const
|
|
{
|
|
Variant right (other);
|
|
right.cast (type_string);
|
|
Lexer::dequote (right._string);
|
|
return task.hasTag (right._string);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator_notag (const Variant& other, const Task& task) const
|
|
{
|
|
return ! operator_hastag (other, task);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::operator! () const
|
|
{
|
|
Variant left (*this);
|
|
|
|
if (left._type == type_string)
|
|
Lexer::dequote (left._string);
|
|
|
|
left.cast (type_boolean);
|
|
return ! left._bool;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator^= (const Variant& other)
|
|
{
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_EXP_BOOL);
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (other._type)
|
|
{
|
|
case type_boolean: throw std::string (STRING_VARIANT_EXP_BOOL);
|
|
case type_integer: _integer = (int) pow (static_cast<double>(_integer), static_cast<double>(other._integer)); break;
|
|
case type_real: throw std::string (STRING_VARIANT_EXP_NON_INT);
|
|
case type_string: throw std::string (STRING_VARIANT_EXP_STRING);
|
|
case type_date: throw std::string (STRING_VARIANT_EXP_DATE);
|
|
case type_duration: throw std::string (STRING_VARIANT_EXP_DURATION);
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (other._type)
|
|
{
|
|
case type_boolean: throw std::string (STRING_VARIANT_EXP_BOOL);
|
|
case type_integer: _real = pow (_real, static_cast<double>(other._integer)); break;
|
|
case type_real: throw std::string (STRING_VARIANT_EXP_NON_INT);
|
|
case type_string: throw std::string (STRING_VARIANT_EXP_STRING);
|
|
case type_date: throw std::string (STRING_VARIANT_EXP_DATE);
|
|
case type_duration: throw std::string (STRING_VARIANT_EXP_DURATION);
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_EXP_STRING);
|
|
break;
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_EXP_DATE);
|
|
break;
|
|
|
|
case type_duration:
|
|
throw std::string (STRING_VARIANT_EXP_DURATION);
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant Variant::operator^ (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
left ^= other;
|
|
return left;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator-= (const Variant& other)
|
|
{
|
|
Variant right (other);
|
|
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_SUB_BOOL);
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); _integer -= right._integer; break;
|
|
case type_integer: _integer -= right._integer; break;
|
|
case type_real: cast (type_real); _real -= right._real; break;
|
|
case type_string: throw std::string (STRING_VARIANT_SUB_STRING);
|
|
case type_date: cast (type_date); _date -= right._date; break;
|
|
case type_duration: cast (type_duration); _duration -= right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_SUB_STRING);
|
|
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
case type_date:
|
|
case type_duration:
|
|
right.cast (type_real);
|
|
_real -= right._real;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_SUB_STRING);
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); _date -= right._integer; break;
|
|
case type_integer: _date -= right._integer; break;
|
|
case type_real: _date -= (int) right._real; break;
|
|
case type_string: throw std::string (STRING_VARIANT_SUB_STRING);
|
|
case type_date: cast (type_duration); _duration -= right._date; break;
|
|
case type_duration: _date -= right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); _duration -= right._integer; break;
|
|
case type_integer: _duration -= right._integer; break;
|
|
case type_real: _duration -= (int) right._real; break;
|
|
case type_string: throw std::string (STRING_VARIANT_SUB_STRING);
|
|
case type_date: throw std::string (STRING_VARIANT_SUB_DATE);
|
|
case type_duration: _duration -= right._duration; break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant Variant::operator- (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
left -= other;
|
|
return left;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator+= (const Variant& other)
|
|
{
|
|
Variant right (other);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: throw std::string (STRING_VARIANT_ADD_BOOL);
|
|
case type_integer: cast (type_integer); _integer += right._integer; break;
|
|
case type_real: cast (type_real); _real += right._real; break;
|
|
case type_string: cast (type_string); _string += right._string; break;
|
|
case type_date: cast (type_date); _date += right._date; break;
|
|
case type_duration: cast (type_duration); _duration += right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); _integer += right._integer; break;
|
|
case type_integer: _integer += right._integer; break;
|
|
case type_real: cast (type_real); _real += right._real; break;
|
|
case type_string: cast (type_string); _string += right._string; break;
|
|
case type_date: cast (type_date); _date += right._date; break;
|
|
case type_duration: cast (type_duration); _duration += right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_real);
|
|
_real += right._real;
|
|
break;
|
|
|
|
case type_string:
|
|
cast (type_string);
|
|
_string += right._string;
|
|
break;
|
|
|
|
case type_date:
|
|
_type = type_date;
|
|
_date = (unsigned) (int) _real + right._date;
|
|
break;
|
|
|
|
case type_duration:
|
|
_type = type_duration;
|
|
_duration = (unsigned) (int) _real + right._duration;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
_string += (std::string) right;
|
|
break;
|
|
|
|
case type_date:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_date); _date += right._date; break;
|
|
case type_integer: _date += right._integer; break;
|
|
case type_real: _date += (int) right._real; break;
|
|
case type_string: cast (type_string); _string += right._string; break;
|
|
case type_date: throw std::string (STRING_VARIANT_ADD_DATE);
|
|
case type_duration: _date += right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_duration); _duration += right._duration; break;
|
|
case type_integer: _duration += right._integer; break;
|
|
case type_real: _duration += (int) right._real; break;
|
|
case type_string: cast (type_string); _string += right._string; break;
|
|
case type_date: cast (type_date); _date += right._date; break;
|
|
case type_duration: _duration += right._duration; break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant Variant::operator+ (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
left += other;
|
|
return left;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator*= (const Variant& other)
|
|
{
|
|
Variant right (other);
|
|
|
|
if (right._type == type_string)
|
|
Lexer::dequote (right._string);
|
|
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: throw std::string (STRING_VARIANT_MUL_BOOL);
|
|
case type_integer: cast (type_integer); _integer *= right._integer; break;
|
|
case type_real: cast (type_real); _real *= right._real; break;
|
|
case type_string: _string = (_bool ? right._string : ""); _type = type_string; break;
|
|
case type_date: throw std::string (STRING_VARIANT_MUL_DATE);
|
|
case type_duration: cast (type_duration); _duration *= right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_integer); _integer *= right._integer; break;
|
|
case type_integer: _integer *= right._integer; break;
|
|
case type_real: cast (type_real); _real *= right._real; break;
|
|
case type_string:
|
|
{
|
|
int limit = _integer;
|
|
// assert (limit < 128);
|
|
_type = type_string;
|
|
_string = "";
|
|
while (limit--)
|
|
_string += right._string;
|
|
}
|
|
break;
|
|
case type_date: throw std::string (STRING_VARIANT_MUL_DATE);
|
|
case type_duration: cast (type_duration); _duration *= right._duration; break;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
case type_integer:
|
|
case type_real:
|
|
right.cast (type_real);
|
|
_real *= right._real;
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_MUL_REAL_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_MUL_DATE);
|
|
|
|
case type_duration:
|
|
_type = type_duration;
|
|
_duration = (time_t) (unsigned) (int) (_real * static_cast<double>(right._duration));
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: if (! right._bool) _string = ""; break;
|
|
case type_integer:
|
|
{
|
|
int limit = right._integer - 1;
|
|
// assert (limit < 128);
|
|
std::string fragment = _string;
|
|
while (limit--)
|
|
_string += fragment;
|
|
}
|
|
break;
|
|
case type_real: throw std::string (STRING_VARIANT_MUL_STR_REAL);
|
|
case type_string: throw std::string (STRING_VARIANT_MUL_STR_STR);
|
|
case type_date: throw std::string (STRING_VARIANT_MUL_STR_DATE);
|
|
case type_duration: throw std::string (STRING_VARIANT_MUL_STR_DUR);
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_MUL_DATE);
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean: right.cast (type_duration); _duration *= right._duration; break;
|
|
case type_integer: _duration *= right._integer; break;
|
|
case type_real:
|
|
_duration = (time_t) (unsigned) (int) (static_cast<double>(_duration) * right._real);
|
|
break;
|
|
case type_string: throw std::string (STRING_VARIANT_MUL_DUR_STR);
|
|
case type_date: throw std::string (STRING_VARIANT_MUL_DUR_DATE);
|
|
case type_duration: throw std::string (STRING_VARIANT_MUL_DUR_DUR);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant Variant::operator* (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
left *= other;
|
|
return left;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator/= (const Variant& other)
|
|
{
|
|
Variant right (other);
|
|
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_DIV_BOOL);
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_DIV_INT_BOOL);
|
|
|
|
case type_integer:
|
|
if (right._integer == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_integer /= right._integer;
|
|
break;
|
|
|
|
case type_real:
|
|
if (right._real == 0.0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
cast (type_real);
|
|
_real /= right._real;
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_DIV_INT_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_DIV_INT_DATE);
|
|
|
|
case type_duration:
|
|
if (right._duration == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_type = type_duration;
|
|
_duration = (time_t) (unsigned) (int) (_integer / right._duration);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_DIV_REAL_BOOL);
|
|
|
|
case type_integer:
|
|
if (right._integer == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_real /= static_cast<double>(right._integer);
|
|
break;
|
|
|
|
case type_real:
|
|
if (right._real == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_real /= right._real;
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_DIV_REAL_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_DIV_REAL_DATE);
|
|
|
|
case type_duration:
|
|
if (right._duration == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_type = type_duration;
|
|
_duration = (time_t) (unsigned) (int) (_real / right._duration);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_DIV_REAL_STR);
|
|
break;
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_DIV_REAL_DATE);
|
|
|
|
case type_duration:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_DIV_DUR_BOOL);
|
|
|
|
case type_integer:
|
|
if (right._integer == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_duration /= right._integer;
|
|
break;
|
|
|
|
case type_real:
|
|
if (right._real == 0)
|
|
throw std::string (STRING_VARIANT_DIV_ZERO);
|
|
_duration = (time_t) (unsigned) (int) (static_cast<double>(_duration) / right._real);
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_DIV_DUR_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_DIV_DUR_DATE);
|
|
|
|
case type_duration:
|
|
throw std::string (STRING_VARIANT_DIV_DUR_DUR);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant Variant::operator/ (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
left /= other;
|
|
return left;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant& Variant::operator%= (const Variant& other)
|
|
{
|
|
Variant right (other);
|
|
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_MOD_BOOL);
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_MOD_INT_BOOL);
|
|
|
|
case type_integer:
|
|
if (right._integer == 0)
|
|
throw std::string (STRING_VARIANT_MOD_ZERO);
|
|
_integer %= right._integer;
|
|
break;
|
|
|
|
case type_real:
|
|
if (right._real == 0.0)
|
|
throw std::string (STRING_VARIANT_MOD_ZERO);
|
|
cast (type_real);
|
|
_real = fmod (_real, right._real);
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_MOD_INT_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_MOD_INT_DATE);
|
|
|
|
case type_duration:
|
|
throw std::string (STRING_VARIANT_MOD_INT_DUR);
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (right._type)
|
|
{
|
|
case type_boolean:
|
|
throw std::string (STRING_VARIANT_MOD_REAL_BOOL);
|
|
|
|
case type_integer:
|
|
if (right._integer == 0)
|
|
throw std::string (STRING_VARIANT_MOD_ZERO);
|
|
_real = fmod (_real, static_cast<double>(right._integer));
|
|
break;
|
|
|
|
case type_real:
|
|
if (right._real == 0)
|
|
throw std::string (STRING_VARIANT_MOD_ZERO);
|
|
_real = fmod (_real, right._real);
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_MOD_REAL_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_MOD_REAL_DATE);
|
|
|
|
case type_duration:
|
|
throw std::string (STRING_VARIANT_MOD_REAL_DUR);
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
throw std::string (STRING_VARIANT_MOD_STR);
|
|
|
|
case type_date:
|
|
throw std::string (STRING_VARIANT_MOD_DATE);
|
|
|
|
case type_duration:
|
|
throw std::string (STRING_VARIANT_MOD_DUR);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant Variant::operator% (const Variant& other) const
|
|
{
|
|
Variant left (*this);
|
|
left %= other;
|
|
return left;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Variant::operator std::string () const
|
|
{
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
return std::string (_bool ? "true" : "false");
|
|
|
|
case type_integer:
|
|
{
|
|
std::stringstream s;
|
|
s << _integer;
|
|
return s.str ();
|
|
}
|
|
|
|
case type_real:
|
|
{
|
|
std::stringstream s;
|
|
s << _real;
|
|
return s.str ();
|
|
}
|
|
|
|
case type_string:
|
|
return _string;
|
|
|
|
case type_date:
|
|
return Datetime (_date).toISOLocalExtended ();
|
|
|
|
case type_duration:
|
|
return Duration (_duration).formatISO ();
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Variant::sqrt ()
|
|
{
|
|
if (_type == type_string)
|
|
Lexer::dequote (_string);
|
|
|
|
cast (type_real);
|
|
if (_real < 0.0)
|
|
throw std::string (STRING_VARIANT_SQRT_NEG);
|
|
_real = ::sqrt (_real);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Variant::cast (const enum type new_type)
|
|
{
|
|
// Short circuit.
|
|
if (_type == new_type)
|
|
return;
|
|
|
|
// From type_boolean
|
|
switch (_type)
|
|
{
|
|
case type_boolean:
|
|
switch (new_type)
|
|
{
|
|
case type_boolean: break;
|
|
case type_integer: _integer = _bool ? 1 : 0; break;
|
|
case type_real: _real = _bool ? 1.0 : 0.0; break;
|
|
case type_string: _string = _bool ? "true" : "false"; break;
|
|
case type_date: _date = _bool ? 1 : 0; break;
|
|
case type_duration: _duration = _bool ? 1 : 0; break;
|
|
}
|
|
break;
|
|
|
|
case type_integer:
|
|
switch (new_type)
|
|
{
|
|
case type_boolean: _bool = _integer == 0 ? false : true; break;
|
|
case type_integer: break;
|
|
case type_real: _real = static_cast<double>(_integer); break;
|
|
case type_string:
|
|
{
|
|
char temp[24];
|
|
snprintf (temp, 24, "%d", _integer);
|
|
_string = temp;
|
|
}
|
|
break;
|
|
case type_date: _date = (time_t) _integer; break;
|
|
case type_duration: _duration = (time_t) _integer; break;
|
|
}
|
|
break;
|
|
|
|
case type_real:
|
|
switch (new_type)
|
|
{
|
|
case type_boolean: _bool = _real == 0.0 ? false : true; break;
|
|
case type_integer: _integer = (int) _real; break;
|
|
case type_real: break;
|
|
case type_string:
|
|
{
|
|
char temp[24];
|
|
snprintf (temp, 24, "%g", _real);
|
|
_string = temp;
|
|
}
|
|
break;
|
|
case type_date: _date = (time_t) (int) _real; break;
|
|
case type_duration: _duration = (time_t) (int) _real; break;
|
|
}
|
|
break;
|
|
|
|
case type_string:
|
|
Lexer::dequote (_string);
|
|
switch (new_type)
|
|
{
|
|
case type_boolean:
|
|
_bool = (_string.length () == 0 ||
|
|
_string == "0" ||
|
|
_string == "0.0") ? false : true;
|
|
break;
|
|
case type_integer:
|
|
_integer = (int) strtol (_string.c_str (), NULL, (_string.substr (0, 2) == "0x" ? 16 : 10));
|
|
break;
|
|
case type_real: _real = strtod (_string.c_str (), NULL); break;
|
|
case type_string: break;
|
|
case type_date:
|
|
{
|
|
_date = 0;
|
|
Datetime iso;
|
|
std::string::size_type pos = 0;
|
|
if (iso.parse (_string, pos, dateFormat) &&
|
|
pos == _string.length ())
|
|
{
|
|
_date = iso.toEpoch ();
|
|
break;
|
|
}
|
|
|
|
pos = 0;
|
|
Duration isop;
|
|
if (isop.parse (_string, pos) &&
|
|
pos == _string.length ())
|
|
{
|
|
_date = Datetime ().toEpoch () + isop.toTime_t ();
|
|
break;
|
|
}
|
|
|
|
if (dateFormat != "")
|
|
{
|
|
_date = Datetime (_string, dateFormat).toEpoch ();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case type_duration:
|
|
{
|
|
_duration = 0;
|
|
std::string::size_type pos = 0;
|
|
Duration iso;
|
|
if (iso.parse (_string, pos) &&
|
|
pos == _string.length ())
|
|
{
|
|
_duration = iso.toTime_t ();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case type_date:
|
|
switch (new_type)
|
|
{
|
|
case type_boolean: _bool = _date != 0 ? true : false; break;
|
|
case type_integer: _integer = (int) _date; break;
|
|
case type_real: _real = static_cast<double>(_date); break;
|
|
case type_string: _string = (std::string) *this; break;
|
|
case type_date: break;
|
|
case type_duration: _duration = _date; break;
|
|
}
|
|
break;
|
|
|
|
case type_duration:
|
|
switch (new_type)
|
|
{
|
|
case type_boolean: _bool = _duration != 0 ? true : false; break;
|
|
case type_integer: _integer = (int) _duration; break;
|
|
case type_real: _real = static_cast<double>(_duration); break;
|
|
case type_string: _string = (std::string) *this; break;
|
|
case type_date: _date = _duration; break;
|
|
case type_duration: break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
_type = new_type;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
int Variant::type ()
|
|
{
|
|
return _type;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::trivial () const
|
|
{
|
|
return (_type == type_integer && _integer == 0) ||
|
|
(_type == type_real && _real == 0.0) ||
|
|
(_type == type_string && _string == "") ||
|
|
(_type == type_date && _date == 0) ||
|
|
(_type == type_duration && _duration == 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool Variant::get_bool () const
|
|
{
|
|
return _bool;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
int Variant::get_integer () const
|
|
{
|
|
return _integer;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
double Variant::get_real () const
|
|
{
|
|
return _real;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const std::string& Variant::get_string () const
|
|
{
|
|
return _string;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
time_t Variant::get_date () const
|
|
{
|
|
return _date;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
time_t Variant::get_duration () const
|
|
{
|
|
return _duration;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|