LCOV - code coverage report
Current view: top level - snapwebsites - snap_expr.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 158 2046 7.7 %
Date: 2019-12-15 17:13:15 Functions: 15 240 6.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Server -- C-like expression scripting support
       2             : // Copyright (c) 2014-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : //#define SHOW_COMMANDS
      19             : 
      20             : 
      21             : // self
      22             : //
      23             : #include "snapwebsites/snap_expr.h"
      24             : 
      25             : 
      26             : // snapwebsites
      27             : //
      28             : #include "snapwebsites/snapwebsites.h"
      29             : #include "snapwebsites/log.h"
      30             : 
      31             : 
      32             : // snapdev lib
      33             : //
      34             : #include <snapdev/not_reached.h>
      35             : #include <snapdev/not_used.h>
      36             : 
      37             : 
      38             : // QtSerialization lib
      39             : //
      40             : #include <QtSerialization/QSerializationComposite.h>
      41             : #include <QtSerialization/QSerializationFieldString.h>
      42             : #include <QtSerialization/QSerializationFieldBasicTypes.h>
      43             : 
      44             : 
      45             : // last include
      46             : //
      47             : #include <snapdev/poison.h>
      48             : 
      49             : 
      50             : 
      51             : namespace snap
      52             : {
      53             : namespace snap_expr
      54             : {
      55             : 
      56             : 
      57             : 
      58             : namespace
      59             : {
      60             : /** \brief Context to access the database.
      61             :  *
      62             :  * Different functions available in this expression handling program let
      63             :  * you access the database. For example, the cell() function let you
      64             :  * read the content of a cell and save it in a variable, or compare
      65             :  * to a specific value, or use it as part of some key.
      66             :  *
      67             :  * The pointer is set using the set_cassandra_context() which is a
      68             :  * static function and should only be called once.
      69             :  */
      70           2 : libdbproxy::context::pointer_t   g_context;
      71             : } // no name namespace
      72             : 
      73             : 
      74             : 
      75             : 
      76           3 : variable_t::variable_t(QString const& name)
      77           3 :     : f_name(name)
      78             :     //, f_type(variable_type_t::EXPR_VARIABLE_TYPE_NULL) -- auto-init
      79             :     //, f_value() -- auto-init (empty, a.k.a. NULL)
      80             : {
      81           3 : }
      82             : 
      83             : 
      84           0 : QString variable_t::get_name() const
      85             : {
      86           0 :     return f_name;
      87             : }
      88             : 
      89             : 
      90           0 : variable_t::variable_type_t variable_t::get_type() const
      91             : {
      92           0 :     return f_type;
      93             : }
      94             : 
      95             : 
      96           0 : libdbproxy::value const& variable_t::get_value() const
      97             : {
      98           0 :     return f_value;
      99             : }
     100             : 
     101             : 
     102           0 : void variable_t::set_value(variable_type_t type, libdbproxy::value const & value)
     103             : {
     104           0 :     f_type = type;
     105           0 :     f_value = value;
     106           0 : }
     107             : 
     108             : 
     109           0 : void variable_t::set_value()
     110             : {
     111           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_NULL;
     112           0 :     f_value.setNullValue();
     113           0 : }
     114             : 
     115             : 
     116           0 : void variable_t::set_value(bool value)
     117             : {
     118           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_BOOL;
     119           0 :     f_value = value;
     120           0 : }
     121             : 
     122             : 
     123           0 : void variable_t::set_value(char value)
     124             : {
     125             :     // with g++ this is unsigned...
     126           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_UINT8;
     127           0 :     f_value = value;
     128           0 : }
     129             : 
     130             : 
     131           0 : void variable_t::set_value(signed char value)
     132             : {
     133           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_INT8;
     134           0 :     f_value = value;
     135           0 : }
     136             : 
     137             : 
     138           0 : void variable_t::set_value(unsigned char value)
     139             : {
     140           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_UINT8;
     141           0 :     f_value = value;
     142           0 : }
     143             : 
     144             : 
     145           0 : void variable_t::set_value(int16_t value)
     146             : {
     147           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_INT16;
     148           0 :     f_value = value;
     149           0 : }
     150             : 
     151             : 
     152           0 : void variable_t::set_value(uint16_t value)
     153             : {
     154           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_UINT16;
     155           0 :     f_value = value;
     156           0 : }
     157             : 
     158             : 
     159           0 : void variable_t::set_value(int32_t value)
     160             : {
     161           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_INT32;
     162           0 :     f_value = value;
     163           0 : }
     164             : 
     165             : 
     166           0 : void variable_t::set_value(uint32_t value)
     167             : {
     168           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_UINT32;
     169           0 :     f_value = value;
     170           0 : }
     171             : 
     172             : 
     173           0 : void variable_t::set_value(int64_t value)
     174             : {
     175           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_INT64;
     176           0 :     f_value = value;
     177           0 : }
     178             : 
     179             : 
     180           0 : void variable_t::set_value(uint64_t value)
     181             : {
     182           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_UINT64;
     183           0 :     f_value = value;
     184           0 : }
     185             : 
     186             : 
     187           0 : void variable_t::set_value(float value)
     188             : {
     189           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_FLOAT;
     190           0 :     f_value = value;
     191           0 : }
     192             : 
     193             : 
     194           0 : void variable_t::set_value(double value)
     195             : {
     196           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE;
     197           0 :     f_value = value;
     198           0 : }
     199             : 
     200             : 
     201           0 : void variable_t::set_value(char const * value)
     202             : {
     203           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_STRING;
     204           0 :     f_value.setStringValue(QString::fromUtf8(value));
     205           0 : }
     206             : 
     207             : 
     208           0 : void variable_t::set_value(wchar_t const * value)
     209             : {
     210           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_STRING;
     211           0 :     f_value.setStringValue(QString::fromWCharArray(value));
     212           0 : }
     213             : 
     214             : 
     215           0 : void variable_t::set_value(QString const & value)
     216             : {
     217           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_STRING;
     218           0 :     f_value.setStringValue(value);
     219           0 : }
     220             : 
     221             : 
     222           0 : void variable_t::set_value(QByteArray const & value)
     223             : {
     224           0 :     f_type = variable_type_t::EXPR_VARIABLE_TYPE_BINARY;
     225           0 :     f_value = value;
     226           0 : }
     227             : 
     228             : 
     229           0 : bool variable_t::is_true() const
     230             : {
     231           0 :     switch(f_type)
     232             :     {
     233           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_NULL:
     234           0 :         return false;
     235             : 
     236           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
     237           0 :         return f_value.safeBoolValue();
     238             : 
     239           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT8:
     240             :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
     241           0 :         return f_value.safeSignedCharValue() != 0;
     242             : 
     243           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT16:
     244             :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
     245           0 :         return f_value.safeInt16Value() != 0;
     246             : 
     247           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT32:
     248             :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
     249           0 :         return f_value.safeInt32Value() != 0;
     250             : 
     251           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT64:
     252             :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
     253           0 :         return f_value.safeInt32Value() != 0;
     254             : 
     255           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
     256             : #pragma GCC diagnostic push
     257             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     258           0 :         return f_value.safeFloatValue() != 0.0f;
     259             : #pragma GCC diagnostic pop
     260             : 
     261           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
     262             : #pragma GCC diagnostic push
     263             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     264           0 :         return f_value.safeDoubleValue() != 0.0;
     265             : #pragma GCC diagnostic pop
     266             : 
     267           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_STRING:
     268             :     case variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
     269           0 :         return !f_value.nullValue();
     270             : 
     271             :     }
     272           0 :     NOTREACHED();
     273             : }
     274             : 
     275             : 
     276           0 : bool variable_t::get_bool(QString const& name) const
     277             : {
     278           0 :     switch(get_type())
     279             :     {
     280           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
     281           0 :         return get_value().safeBoolValue();
     282             : 
     283           0 :     default:
     284           0 :         throw snap_expr_exception_invalid_parameter_type(QString("parameter for %1 must be a Boolean").arg(name));
     285             : 
     286             :     }
     287             :     NOTREACHED();
     288             : }
     289             : 
     290             : 
     291           0 : int64_t variable_t::get_integer(QString const& name) const
     292             : {
     293           0 :     switch(get_type())
     294             :     {
     295           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT8:
     296           0 :         return get_value().safeSignedCharValue();
     297             : 
     298           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
     299           0 :         return get_value().safeUnsignedCharValue();
     300             : 
     301           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT16:
     302           0 :         return get_value().safeInt16Value();
     303             : 
     304           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
     305           0 :         return get_value().safeUInt16Value();
     306             : 
     307           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT32:
     308           0 :         return get_value().safeInt32Value();
     309             : 
     310           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
     311           0 :         return get_value().safeUInt32Value();
     312             : 
     313           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT64:
     314           0 :         return get_value().safeInt64Value();
     315             : 
     316           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
     317           0 :         return get_value().safeUInt64Value();
     318             : 
     319           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
     320           0 :         return static_cast<int64_t>(get_value().safeFloatValue());
     321             : 
     322           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
     323           0 :         return static_cast<int64_t>(get_value().safeDoubleValue());
     324             : 
     325           0 :     default:
     326             :         // although we allow floating point too...
     327           0 :         throw snap_expr_exception_invalid_parameter_type(QString("parameter for %1 must be an integer").arg(name));
     328             : 
     329             :     }
     330             :     NOTREACHED();
     331             : }
     332             : 
     333             : 
     334           0 : double variable_t::get_floating_point(QString const& name) const
     335             : {
     336           0 :     switch(get_type())
     337             :     {
     338           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT8:
     339           0 :         return get_value().safeSignedCharValue();
     340             : 
     341           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
     342           0 :         return get_value().safeUnsignedCharValue();
     343             : 
     344           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT16:
     345           0 :         return get_value().safeInt16Value();
     346             : 
     347           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
     348           0 :         return get_value().safeUInt16Value();
     349             : 
     350           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT32:
     351           0 :         return get_value().safeInt32Value();
     352             : 
     353           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
     354           0 :         return get_value().safeUInt32Value();
     355             : 
     356           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT64:
     357           0 :         return get_value().safeInt64Value();
     358             : 
     359           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
     360           0 :         return get_value().safeUInt64Value();
     361             : 
     362           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
     363           0 :         return static_cast<int64_t>(get_value().safeFloatValue());
     364             : 
     365           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
     366           0 :         return static_cast<int64_t>(get_value().safeDoubleValue());
     367             : 
     368           0 :     default:
     369             :         // although we auto-convert integers too
     370           0 :         throw snap_expr_exception_invalid_parameter_type(QString("parameter for %1 must be a floating point").arg(name));
     371             : 
     372             :     }
     373             :     NOTREACHED();
     374             : }
     375             : 
     376             : 
     377           0 : QString variable_t::get_string(QString const & name) const
     378             : {
     379           0 :     switch(get_type())
     380             :     {
     381           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_STRING:
     382           0 :         return get_value().stringValue();
     383             : 
     384           0 :     default:
     385           0 :         throw snap_expr_exception_invalid_parameter_type(QString("parameter for %1 must be a string (got type %2 instead)")
     386           0 :                             .arg(name)
     387           0 :                             .arg(static_cast<int>(get_type())));
     388             : 
     389             :     }
     390             :     NOTREACHED();
     391             : }
     392             : 
     393             : 
     394           0 : QString variable_t::to_string() const
     395             : {
     396           0 :     switch(f_type)
     397             :     {
     398           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_NULL:
     399           0 :         return "(null)";
     400             : 
     401           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
     402           0 :         return f_value.safeBoolValue() ? "true" : "false";
     403             : 
     404           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT8:
     405           0 :         return QString("%1").arg(f_value.safeSignedCharValue());
     406             : 
     407           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
     408           0 :         return QString("%1").arg(static_cast<int>(f_value.safeUnsignedCharValue()));
     409             : 
     410           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT16:
     411           0 :         return QString("%1").arg(f_value.safeInt16Value());
     412             : 
     413           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
     414           0 :         return QString("%1").arg(f_value.safeUInt16Value());
     415             : 
     416           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT32:
     417           0 :         return QString("%1").arg(f_value.safeInt32Value());
     418             : 
     419           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
     420           0 :         return QString("%1").arg(f_value.safeUInt32Value());
     421             : 
     422           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_INT64:
     423           0 :         return QString("%1").arg(f_value.safeInt64Value());
     424             : 
     425           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
     426           0 :         return QString("%1").arg(f_value.safeUInt64Value());
     427             : 
     428           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
     429           0 :         return QString("%1").arg(f_value.safeFloatValue());
     430             : 
     431           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
     432           0 :         return QString("%1").arg(f_value.safeDoubleValue());
     433             : 
     434           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_STRING:
     435           0 :         return QString("\"%1\"").arg(f_value.stringValue());
     436             : 
     437           0 :     case variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
     438           0 :         return "#...TODO: binary...#";
     439             : 
     440             :     }
     441           0 :     NOTREACHED();
     442             : }
     443             : 
     444             : 
     445             : 
     446             : 
     447             : 
     448             : 
     449             : 
     450             : using namespace parser;
     451             : 
     452             : 
     453             : class expr_node
     454             :         : public expr_node_base
     455             :         , public parser_user_data
     456             :         , public QtSerialization::QSerializationObject
     457             : {
     458             : public:
     459             :     static int const LIST_TEST_NODE_MAJOR_VERSION = 1;
     460             :     static int const LIST_TEST_NODE_MINOR_VERSION = 0;
     461             : 
     462             :     typedef QSharedPointer<expr_node>           expr_node_pointer_t;
     463             :     typedef QVector<expr_node_pointer_t>        expr_node_vector_t;
     464             :     typedef QMap<QString, expr_node_pointer_t>  expr_node_map_t;
     465             : 
     466             :     static functions_t::function_call_table_t const internal_functions[];
     467             : 
     468             :     enum class node_type_t
     469             :     {
     470             :         NODE_TYPE_UNKNOWN, // used when creating a node without a type
     471             :         NODE_TYPE_LOADING, // used when loading
     472             : 
     473             :         // Operations
     474             :         NODE_TYPE_OPERATION_LIST, // comma operator
     475             :         NODE_TYPE_OPERATION_LOGICAL_NOT,
     476             :         NODE_TYPE_OPERATION_BITWISE_NOT,
     477             :         NODE_TYPE_OPERATION_NEGATE,
     478             :         NODE_TYPE_OPERATION_FUNCTION,
     479             :         NODE_TYPE_OPERATION_MULTIPLY,
     480             :         NODE_TYPE_OPERATION_DIVIDE,
     481             :         NODE_TYPE_OPERATION_MODULO,
     482             :         NODE_TYPE_OPERATION_ADD,
     483             :         NODE_TYPE_OPERATION_SUBTRACT,
     484             :         NODE_TYPE_OPERATION_SHIFT_LEFT,
     485             :         NODE_TYPE_OPERATION_SHIFT_RIGHT,
     486             :         NODE_TYPE_OPERATION_LESS,
     487             :         NODE_TYPE_OPERATION_LESS_OR_EQUAL,
     488             :         NODE_TYPE_OPERATION_GREATER,
     489             :         NODE_TYPE_OPERATION_GREATER_OR_EQUAL,
     490             :         NODE_TYPE_OPERATION_MINIMUM,
     491             :         NODE_TYPE_OPERATION_MAXIMUM,
     492             :         NODE_TYPE_OPERATION_EQUAL,
     493             :         NODE_TYPE_OPERATION_NOT_EQUAL,
     494             :         NODE_TYPE_OPERATION_BITWISE_AND,
     495             :         NODE_TYPE_OPERATION_BITWISE_XOR,
     496             :         NODE_TYPE_OPERATION_BITWISE_OR,
     497             :         NODE_TYPE_OPERATION_LOGICAL_AND,
     498             :         NODE_TYPE_OPERATION_LOGICAL_XOR,
     499             :         NODE_TYPE_OPERATION_LOGICAL_OR,
     500             :         NODE_TYPE_OPERATION_CONDITIONAL,
     501             :         NODE_TYPE_OPERATION_ASSIGNMENT, // save to variable
     502             :         NODE_TYPE_OPERATION_VARIABLE, // load from variable
     503             : 
     504             :         // Literals
     505             :         NODE_TYPE_LITERAL_BOOLEAN,
     506             :         NODE_TYPE_LITERAL_INTEGER,
     507             :         NODE_TYPE_LITERAL_FLOATING_POINT,
     508             :         NODE_TYPE_LITERAL_STRING,
     509             : 
     510             :         // Variable
     511             :         NODE_TYPE_VARIABLE
     512             :     };
     513             : 
     514             :     static char const * type_names[static_cast<size_t>(node_type_t::NODE_TYPE_VARIABLE) + 1];
     515             : 
     516           3 :     expr_node(node_type_t type)
     517           3 :         : f_type(type)
     518           3 :         , f_variable("")
     519             :     {
     520           3 :     }
     521             : 
     522           0 :     virtual ~expr_node()
     523           0 :     {
     524           0 :     }
     525             : 
     526           0 :     node_type_t get_type() const
     527             :     {
     528           0 :         return f_type;
     529             :     }
     530             : 
     531           2 :     void set_name(QString const& name)
     532             :     {
     533           2 :         f_name = name;
     534           2 :     }
     535             : 
     536             :     QString get_name() const
     537             :     {
     538             :         return f_name;
     539             :     }
     540             : 
     541             :     variable_t const& get_variable() const
     542             :     {
     543             :         verify_variable();
     544             :         return f_variable;
     545             :     }
     546             : 
     547           0 :     void set_variable(variable_t const& variable)
     548             :     {
     549           0 :         verify_variable();
     550           0 :         f_variable = variable;
     551           0 :     }
     552             : 
     553           2 :     void add_child(expr_node_pointer_t child)
     554             :     {
     555           2 :         verify_children(-1);
     556           2 :         f_children.push_back(child);
     557           2 :     }
     558             : 
     559           0 :     void remove_child(int idx)
     560             :     {
     561           0 :         verify_children(idx);
     562           0 :         f_children.remove(idx);
     563           0 :     }
     564             : 
     565           0 :     void insert_child(int idx, expr_node_pointer_t child)
     566             :     {
     567           0 :         verify_children(idx, true);
     568           0 :         f_children.insert(idx, child);
     569           0 :     }
     570             : 
     571           0 :     int children_size() const
     572             :     {
     573           0 :         verify_children(-1);
     574           0 :         return f_children.size();
     575             :     }
     576             : 
     577           0 :     expr_node_pointer_t get_child(int idx)
     578             :     {
     579           0 :         verify_children(idx);
     580           0 :         return f_children[idx];
     581             :     }
     582             : 
     583           0 :     static QSharedPointer<expr_node> load(QtSerialization::QReader& r)
     584             :     {
     585             :         // create a "root" used only to load the data
     586           0 :         expr_node_pointer_t root(new expr_node(node_type_t::NODE_TYPE_LOADING));
     587           0 :         root->read(r);
     588             : #ifdef DEBUG
     589           0 :         if(root->children_size() != 1)
     590             :         {
     591           0 :             throw snap_logic_exception(QString("expr_node::load() did not return exactly one child in the root node"));
     592             :         }
     593             : //std::cout << "--- Loaded result:\n" << root->get_child(0)->toString() << "---\n";
     594             : #endif
     595           0 :         return root->get_child(0);
     596             :     }
     597             : 
     598           0 :     void read(QtSerialization::QReader& r)
     599             :     {
     600             :         // read the data from the reader
     601           0 :         QtSerialization::QComposite comp;
     602           0 :         qint32 type(static_cast<qint32>(static_cast<node_type_t>(node_type_t::NODE_TYPE_LOADING)));
     603           0 :         QtSerialization::QFieldInt32 node_type(comp, "type", type); // f_type is an enum...
     604           0 :         QtSerialization::QFieldString node_name(comp, "name", f_name);
     605           0 :         qint64 value_int(0);
     606           0 :         QtSerialization::QFieldInt64 node_int(comp, "int", value_int);
     607           0 :         double value_dbl(0.0);
     608           0 :         QtSerialization::QFieldDouble node_flt(comp, "flt", value_dbl);
     609           0 :         QString value_str; // ("") -- default value
     610           0 :         QtSerialization::QFieldString node_str(comp, "str", value_str);
     611           0 :         QtSerialization::QFieldTag vars(comp, "node", this);
     612           0 :         r.read(comp);
     613           0 :         f_type = static_cast<node_type_t>(type);
     614           0 :         switch(f_type)
     615             :         {
     616           0 :         case node_type_t::NODE_TYPE_UNKNOWN:
     617           0 :             throw snap_logic_exception("expr_node::read() loaded a node of type: node_type_t::NODE_TYPE_UNKNOWN");
     618             : 
     619           0 :         case node_type_t::NODE_TYPE_LITERAL_BOOLEAN:
     620           0 :             f_variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, static_cast<bool>(value_int));
     621           0 :             break;
     622             : 
     623           0 :         case node_type_t::NODE_TYPE_LITERAL_INTEGER:
     624           0 :             f_variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64, static_cast<int64_t>(value_int));
     625           0 :             break;
     626             : 
     627           0 :         case node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT:
     628           0 :             f_variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE, value_dbl);
     629           0 :             break;
     630             : 
     631           0 :         case node_type_t::NODE_TYPE_LITERAL_STRING:
     632           0 :             f_variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value_str);
     633           0 :             break;
     634             : 
     635           0 :         default:
     636             :             // only literals have a value when serializing
     637           0 :             break;
     638             : 
     639             :         }
     640           0 :     }
     641             : 
     642           0 :     virtual void readTag(QString const& name, QtSerialization::QReader& r)
     643             :     {
     644           0 :         if(name == "node")
     645             :         {
     646             :             // create a node
     647           0 :             expr_node_pointer_t child(new expr_node(node_type_t::NODE_TYPE_LOADING));
     648             :             // read the data from the reader
     649           0 :             child->read(r);
     650             :             // add to the vector
     651           0 :             add_child(child);
     652             :         }
     653           0 :     }
     654             : 
     655           3 :     void write(QtSerialization::QWriter& w) const
     656             :     {
     657           6 :         QtSerialization::QWriter::QTag tag(w, "node");
     658             : 
     659           3 :         QtSerialization::writeTag(w, "type", static_cast<qint32>(static_cast<node_type_t>(f_type)));
     660             : 
     661           3 :         if(!f_name.isEmpty())
     662             :         {
     663           2 :             QtSerialization::writeTag(w, "name", f_name);
     664             :         }
     665             : 
     666           3 :         switch(f_type)
     667             :         {
     668           0 :         case node_type_t::NODE_TYPE_LITERAL_BOOLEAN:
     669           0 :             QtSerialization::writeTag(w, "int", static_cast<qint64>(f_variable.get_value().safeBoolValue()));
     670           0 :             break;
     671             : 
     672           0 :         case node_type_t::NODE_TYPE_LITERAL_INTEGER:
     673           0 :             QtSerialization::writeTag(w, "int", static_cast<qint64>(f_variable.get_value().safeInt64Value()));
     674           0 :             break;
     675             : 
     676           0 :         case node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT:
     677           0 :             QtSerialization::writeTag(w, "flt", f_variable.get_value().safeDoubleValue());
     678           0 :             break;
     679             : 
     680           0 :         case node_type_t::NODE_TYPE_LITERAL_STRING:
     681           0 :             QtSerialization::writeTag(w, "str", f_variable.get_value().stringValue());
     682           0 :             break;
     683             : 
     684           3 :         default:
     685             :             // only literals have a value when serializing
     686           3 :             break;
     687             : 
     688             :         }
     689             : 
     690           3 :         int const max_children(f_children.size());
     691           5 :         for(int i(0); i < max_children; ++i)
     692             :         {
     693           2 :             f_children[i]->write(w);
     694             :         }
     695           3 :     }
     696             : 
     697             :     // SFINAE test
     698             :     // Source: http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
     699             : #pragma GCC diagnostic push
     700             : #pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
     701             :     template<typename T>
     702             :     class has_function
     703             :     {
     704             :     private:
     705             :         typedef char yes[1];
     706             :         typedef char no [2];
     707             : 
     708             :         template <typename U, U> struct type_check;
     709             : 
     710             :         // integers() is always available at this point
     711             :         //template <typename C> static yes &test_integers(type_check<int64_t(&)(int64_t, int64_t), C::integers> *);
     712             :         //template <typename C> static no  &test_integers(...);
     713             : 
     714             :         template <typename C> static yes &test_floating_points(type_check<double(&)(double, double), C::floating_points> *);
     715             :         template <typename C> static no  &test_floating_points(...);
     716             : 
     717             :         template <typename C> static yes &test_string_integer(type_check<QString(&)(QString const&, int64_t), C::string_integer> *);
     718             :         template <typename C> static no  &test_string_integer(...);
     719             : 
     720             :         template <typename C> static yes &test_strings(type_check<QString(&)(QString const&, QString const&), C::strings> *);
     721             :         template <typename C> static no  &test_strings(...);
     722             : 
     723             :         // integers() is always available at this point
     724             :         //template <typename C> static yes &test_bool_integers(type_check<bool(&)(int64_t, int64_t), C::integers> *);
     725             :         //template <typename C> static no  &test_bool_integers(...);
     726             : 
     727             :         template <typename C> static yes &test_bool_floating_points(type_check<bool(&)(double, double), C::floating_points> *);
     728             :         template <typename C> static no  &test_bool_floating_points(...);
     729             : 
     730             :         template <typename C> static yes &test_bool_string_integer(type_check<bool(&)(QString const&, int64_t), C::string_integer> *);
     731             :         template <typename C> static no  &test_bool_string_integer(...);
     732             : 
     733             :         template <typename C> static yes &test_bool_strings(type_check<bool(&)(QString const&, QString const&), C::strings> *);
     734             :         template <typename C> static no  &test_bool_strings(...);
     735             : 
     736             :     public:
     737             :         //static bool const has_integers        = sizeof(test_integers       <T>(nullptr)) == sizeof(yes);
     738             :         static bool const has_floating_points = sizeof(test_floating_points<T>(nullptr)) == sizeof(yes);
     739             :         static bool const has_string_integer  = sizeof(test_string_integer <T>(nullptr)) == sizeof(yes);
     740             :         static bool const has_strings         = sizeof(test_strings        <T>(nullptr)) == sizeof(yes);
     741             :         //static bool const has_bool_integers        = sizeof(test_bool_integers       <T>(nullptr)) == sizeof(yes);
     742             :         static bool const has_bool_floating_points = sizeof(test_bool_floating_points<T>(nullptr)) == sizeof(yes);
     743             :         static bool const has_bool_string_integer  = sizeof(test_bool_string_integer <T>(nullptr)) == sizeof(yes);
     744             :         static bool const has_bool_strings         = sizeof(test_bool_strings        <T>(nullptr)) == sizeof(yes);
     745             :     };
     746             : #pragma GCC diagnostic pop
     747             : 
     748             :     // select structure depending on bool
     749             :     template<bool C, typename T = void>
     750             :     struct enable_if
     751             :     {
     752             :         typedef T type;
     753             :     };
     754             : 
     755             :     // if false, do nothing, whatever T
     756             :     template<typename T>
     757             :     struct enable_if<false, T>
     758             :     {
     759             :     };
     760             : 
     761             :     template<typename F>
     762           0 :     typename enable_if<has_function<F>::has_floating_points>::type do_float(variable_t & result, double a, double b)
     763             :     {
     764           0 :         libdbproxy::value value;
     765           0 :         value.setFloatValue(static_cast<float>(F::floating_points(a, b)));
     766           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT, value);
     767           0 :     }
     768             : 
     769             : #pragma GCC diagnostic push
     770             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     771             :     template<typename F>
     772             :     typename enable_if<!has_function<F>::has_floating_points>::type do_float(variable_t & result, double a, double b)
     773             :     {
     774             :     }
     775             : #pragma GCC diagnostic pop
     776             : 
     777             :     template<typename F>
     778           0 :     typename enable_if<has_function<F>::has_bool_floating_points>::type do_float_to_bool(variable_t& result, double a, double b)
     779             :     {
     780           0 :         libdbproxy::value value;
     781           0 :         value.setBoolValue(F::floating_points(a, b));
     782           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
     783           0 :     }
     784             : 
     785             : #pragma GCC diagnostic push
     786             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     787             :     template<typename F>
     788             :     typename enable_if<!has_function<F>::has_bool_floating_points>::type do_float_to_bool(variable_t& result, double a, double b)
     789             :     {
     790             :     }
     791             : #pragma GCC diagnostic pop
     792             : 
     793             :     template<typename F>
     794           0 :     typename enable_if<has_function<F>::has_floating_points>::type do_double(variable_t& result, double a, double b)
     795             :     {
     796           0 :         libdbproxy::value value;
     797           0 :         value.setDoubleValue(F::floating_points(a, b));
     798           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE, value);
     799           0 :     }
     800             : 
     801             : #pragma GCC diagnostic push
     802             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     803             :     template<typename F>
     804             :     typename enable_if<!has_function<F>::has_floating_points>::type do_double(variable_t& result, double a, double b)
     805             :     {
     806             :     }
     807             : #pragma GCC diagnostic pop
     808             : 
     809             :     template<typename F>
     810           0 :     typename enable_if<has_function<F>::has_bool_floating_points>::type do_double_to_bool(variable_t & result, double a, double b)
     811             :     {
     812           0 :         libdbproxy::value value;
     813           0 :         value.setBoolValue(F::floating_points(a, b));
     814           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
     815           0 :     }
     816             : 
     817             : #pragma GCC diagnostic push
     818             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     819             :     template<typename F>
     820             :     typename enable_if<!has_function<F>::has_bool_floating_points>::type do_double_to_bool(variable_t & result, double a, double b)
     821             :     {
     822             :     }
     823             : #pragma GCC diagnostic pop
     824             : 
     825             :     template<typename F>
     826           0 :     typename enable_if<has_function<F>::has_string_integer>::type do_string_integer(variable_t & result, QString const & a, int64_t b)
     827             :     {
     828           0 :         libdbproxy::value value;
     829           0 :         value.setStringValue(F::string_integer(a, b));
     830           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
     831           0 :     }
     832             : 
     833             : #pragma GCC diagnostic push
     834             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     835             :     template<typename F>
     836             :     typename enable_if<!has_function<F>::has_string_integer>::type do_string_integer(variable_t & result, QString const & a, int64_t b)
     837             :     {
     838             :     }
     839             : #pragma GCC diagnostic pop
     840             : 
     841             :     template<typename F>
     842             :     typename enable_if<has_function<F>::has_bool_string_integer>::type do_string_integer_to_bool(variable_t & result, QString const & a, int64_t b)
     843             :     {
     844             :         libdbproxy::value value;
     845             :         value.setBoolValue(F::string_integer(a, b));
     846             :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
     847             :     }
     848             : 
     849             : #pragma GCC diagnostic push
     850             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     851             :     template<typename F>
     852             :     typename enable_if<!has_function<F>::has_bool_string_integer>::type do_string_integer_to_bool(variable_t & result, QString const & a, int64_t b)
     853             :     {
     854             :     }
     855             : #pragma GCC diagnostic pop
     856             : 
     857             :     template<typename F>
     858           0 :     typename enable_if<has_function<F>::has_strings>::type do_strings(variable_t & result, QString const & a, QString const & b)
     859             :     {
     860           0 :         libdbproxy::value value;
     861           0 :         value.setStringValue(F::strings(a, b));
     862           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
     863           0 :     }
     864             : 
     865             : #pragma GCC diagnostic push
     866             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     867             :     template<typename F>
     868             :     typename enable_if<!has_function<F>::has_strings>::type do_strings(variable_t& result, QString const& a, QString const& b)
     869             :     {
     870             :     }
     871             : #pragma GCC diagnostic pop
     872             : 
     873             :     template<typename F>
     874           0 :     typename enable_if<has_function<F>::has_bool_strings>::type do_strings_to_bool(variable_t & result, QString const & a, QString const & b)
     875             :     {
     876           0 :         libdbproxy::value value;
     877           0 :         value.setBoolValue(F::strings(a, b));
     878           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
     879           0 :     }
     880             : 
     881             : #pragma GCC diagnostic push
     882             : #pragma GCC diagnostic ignored "-Wunused-parameter"
     883             :     template<typename F>
     884             :     typename enable_if<!has_function<F>::has_bool_strings>::type do_strings_to_bool(variable_t & result, QString const & a, QString const & b)
     885             :     {
     886             :     }
     887             : #pragma GCC diagnostic pop
     888             : 
     889             :     class op_multiply
     890             :     {
     891             :     public:
     892           0 :         static int64_t integers(int64_t a, int64_t b) { return a * b; }
     893           0 :         static double floating_points(double a, double b) { return a * b; }
     894           0 :         static QString string_integer(QString const& a, int64_t b) { return a.repeated(static_cast<int>(b)); }
     895             :     };
     896             : 
     897             :     class op_divide
     898             :     {
     899             :     public:
     900           0 :         static int64_t integers(int64_t a, int64_t b)
     901             :         {
     902           0 :             if(b == 0)
     903             :             {
     904           0 :                 throw snap_expr_exception_division_by_zero("expr_node::op_divide() called with integers and a denominator set to zero");
     905             :             }
     906           0 :             return a / b;
     907             :         }
     908           0 :         static double floating_points(double a, double b)
     909             :         {
     910             :             // in this case division by zero is well defined!
     911           0 :             return a / b;
     912             :         }
     913             :     };
     914             : 
     915             :     class op_modulo
     916             :     {
     917             :     public:
     918           0 :         static int64_t integers(int64_t a, int64_t b)
     919             :         {
     920           0 :             if(b == 0)
     921             :             {
     922           0 :                 throw snap_expr_exception_division_by_zero("expr_node::op_modulo() called with integers and a denominator set to zero");
     923             :             }
     924           0 :             return a % b;
     925             :         }
     926             :     };
     927             : 
     928             :     class op_add
     929             :     {
     930             :     public:
     931           0 :         static int64_t integers(int64_t a, int64_t b) { return a + b; }
     932           0 :         static double floating_points(double a, double b) { return a + b; }
     933           0 :         static QString strings(QString const & a, QString const & b) { return a + b; }
     934             :     };
     935             : 
     936             :     class op_subtract
     937             :     {
     938             :     public:
     939           0 :         static int64_t integers(int64_t a, int64_t b) { return a - b; }
     940           0 :         static double floating_points(double a, double b) { return a - b; }
     941             :     };
     942             : 
     943             :     class op_shift_left
     944             :     {
     945             :     public:
     946           0 :         static int64_t integers(int64_t a, int64_t b) { return a << b; }
     947             :     };
     948             : 
     949             :     class op_shift_right
     950             :     {
     951             :     public:
     952           0 :         static int64_t integers(int64_t a, int64_t b) { return a >> b; }
     953             :         static int64_t integers(uint64_t a, int64_t b) { return a >> b; }
     954             :         static int64_t integers(int64_t a, uint64_t b) { return a >> b; }
     955             :         static int64_t integers(uint64_t a, uint64_t b) { return a >> b; }
     956             :     };
     957             : 
     958             :     class op_less
     959             :     {
     960             :     public:
     961           0 :         static bool integers(int64_t a, int64_t b) { return a < b; }
     962           0 :         static bool floating_points(double a, double b) { return a < b; }
     963           0 :         static bool strings(QString const& a, QString const& b) { return a < b; }
     964             :     };
     965             : 
     966             :     class op_less_or_equal
     967             :     {
     968             :     public:
     969           0 :         static bool integers(int64_t a, int64_t b) { return a <= b; }
     970           0 :         static bool floating_points(double a, double b) { return a <= b; }
     971           0 :         static bool strings(QString const& a, QString const& b) { return a <= b; }
     972             :     };
     973             : 
     974             :     class op_greater
     975             :     {
     976             :     public:
     977           0 :         static bool integers(int64_t a, int64_t b) { return a > b; }
     978           0 :         static bool floating_points(double a, double b) { return a > b; }
     979           0 :         static bool strings(QString const& a, QString const& b) { return a > b; }
     980             :     };
     981             : 
     982             :     class op_greater_or_equal
     983             :     {
     984             :     public:
     985           0 :         static bool integers(int64_t a, int64_t b) { return a >= b; }
     986           0 :         static bool floating_points(double a, double b) { return a >= b; }
     987           0 :         static bool strings(QString const& a, QString const& b) { return a >= b; }
     988             :     };
     989             : 
     990             :     class op_minimum
     991             :     {
     992             :     public:
     993           0 :         static int64_t integers(int64_t a, int64_t b) { return a < b ? a : b; }
     994           0 :         static double floating_points(double a, double b) { return a < b ? a : b; }
     995           0 :         static QString strings(QString const& a, QString const& b) { return a < b ? a : b; }
     996             :     };
     997             : 
     998             :     class op_maximum
     999             :     {
    1000             :     public:
    1001           0 :         static int64_t integers(int64_t a, int64_t b) { return a > b ? a : b; }
    1002           0 :         static double floating_points(double a, double b) { return a > b ? a : b; }
    1003           0 :         static QString strings(QString const& a, QString const& b) { return a > b ? a : b; }
    1004             :     };
    1005             : 
    1006             :     class op_equal
    1007             :     {
    1008             :     public:
    1009           0 :         static bool integers(int64_t a, int64_t b) { return a == b; }
    1010             : #pragma GCC diagnostic push
    1011             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1012             :         // TBD -- users should not compare floating points with == and !=
    1013             :         //        can we do something about it here? (i.e. emit a warning
    1014             :         //        in debug mode?)
    1015           0 :         static bool floating_points(double a, double b) { return a == b; }
    1016           0 :         static bool strings(QString const& a, QString const& b) { return a == b; }
    1017             : #pragma GCC diagnostic pop
    1018             :     };
    1019             : 
    1020             :     class op_not_equal
    1021             :     {
    1022             :     public:
    1023           0 :         static bool integers(int64_t a, int64_t b) { return a != b; }
    1024             : #pragma GCC diagnostic push
    1025             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1026             :         // TBD -- users should not compare floating points with == and !=
    1027             :         //        can we do something about it here? (i.e. emit a warning
    1028             :         //        in debug mode?)
    1029           0 :         static bool floating_points(double a, double b) { return a != b; }
    1030           0 :         static bool strings(QString const& a, QString const& b) { return a != b; }
    1031             : #pragma GCC diagnostic pop
    1032             :     };
    1033             : 
    1034             :     class op_bitwise_and
    1035             :     {
    1036             :     public:
    1037           0 :         static int64_t integers(int64_t a, int64_t b) { return a & b; }
    1038             :     };
    1039             : 
    1040             :     class op_bitwise_xor
    1041             :     {
    1042             :     public:
    1043           0 :         static int64_t integers(int64_t a, int64_t b) { return a ^ b; }
    1044             :     };
    1045             : 
    1046             :     class op_bitwise_or
    1047             :     {
    1048             :     public:
    1049           0 :         static int64_t integers(int64_t a, int64_t b) { return a | b; }
    1050             :     };
    1051             : 
    1052             :     class op_logical_and
    1053             :     {
    1054             :     public:
    1055           0 :         static bool integers(int64_t a, int64_t b) { return a && b; }
    1056             :     };
    1057             : 
    1058             :     class op_logical_xor
    1059             :     {
    1060             :     public:
    1061           0 :         static bool integers(int64_t a, int64_t b) { return (a != 0) ^ (b != 0); }
    1062             :     };
    1063             : 
    1064             :     class op_logical_or
    1065             :     {
    1066             :     public:
    1067           0 :         static bool integers(int64_t a, int64_t b) { return a || b; }
    1068             :     };
    1069             : 
    1070           0 :     void execute(variable_t & result, variable_t::variable_map_t & variables, functions_t & functions)
    1071             :     {
    1072             : #ifdef SHOW_COMMANDS
    1073             :         switch(f_type)
    1074             :         {
    1075             :         case node_type_t::NODE_TYPE_UNKNOWN:
    1076             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_UNKNOWN";
    1077             :             break;
    1078             : 
    1079             :         case node_type_t::NODE_TYPE_LOADING:
    1080             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_LOADING";
    1081             :             break;
    1082             : 
    1083             :         case node_type_t::NODE_TYPE_OPERATION_LIST:
    1084             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LIST";
    1085             :             break;
    1086             : 
    1087             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_NOT:
    1088             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LOGICAL_NOT";
    1089             :             break;
    1090             : 
    1091             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_NOT:
    1092             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_BITWISE_NOT";
    1093             :             break;
    1094             : 
    1095             :         case node_type_t::NODE_TYPE_OPERATION_NEGATE:
    1096             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_NEGATE";
    1097             :             break;
    1098             : 
    1099             :         case node_type_t::NODE_TYPE_OPERATION_FUNCTION:
    1100             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_FUNCTION -- " << f_name << "()";
    1101             :             break;
    1102             : 
    1103             :         case node_type_t::NODE_TYPE_OPERATION_MULTIPLY:
    1104             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_MULTIPLY (*)";
    1105             :             break;
    1106             : 
    1107             :         case node_type_t::NODE_TYPE_OPERATION_DIVIDE:
    1108             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_DIVIDE (/)";
    1109             :             break;
    1110             : 
    1111             :         case node_type_t::NODE_TYPE_OPERATION_MODULO:
    1112             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_MODULO (%)";
    1113             :             break;
    1114             : 
    1115             :         case node_type_t::NODE_TYPE_OPERATION_ADD:
    1116             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_ADD (+)";
    1117             :             break;
    1118             : 
    1119             :         case node_type_t::NODE_TYPE_OPERATION_SUBTRACT:
    1120             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_SUBTRACT (-)";
    1121             :             break;
    1122             : 
    1123             :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_LEFT:
    1124             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_SHIFT_LEFT (<<)";
    1125             :             break;
    1126             : 
    1127             :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_RIGHT:
    1128             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_SHIFT_RIGHT (>>)";
    1129             :             break;
    1130             : 
    1131             :         case node_type_t::NODE_TYPE_OPERATION_LESS:
    1132             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LESS (<)";
    1133             :             break;
    1134             : 
    1135             :         case node_type_t::NODE_TYPE_OPERATION_LESS_OR_EQUAL:
    1136             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LESS_OR_EQUAL (<=)";
    1137             :             break;
    1138             : 
    1139             :         case node_type_t::NODE_TYPE_OPERATION_GREATER:
    1140             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_GREATER (>)";
    1141             :             break;
    1142             : 
    1143             :         case node_type_t::NODE_TYPE_OPERATION_GREATER_OR_EQUAL:
    1144             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_GREATER_OR_EQUAL (>=)";
    1145             :             break;
    1146             : 
    1147             :         case node_type_t::NODE_TYPE_OPERATION_MINIMUM:
    1148             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_MINIMUM (<?)";
    1149             :             break;
    1150             : 
    1151             :         case node_type_t::NODE_TYPE_OPERATION_MAXIMUM:
    1152             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_MAXIMUM (>?)";
    1153             :             break;
    1154             : 
    1155             :         case node_type_t::NODE_TYPE_OPERATION_EQUAL:
    1156             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_EQUAL (==)";
    1157             :             break;
    1158             : 
    1159             :         case node_type_t::NODE_TYPE_OPERATION_NOT_EQUAL:
    1160             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_NOT_EQUAL (!=)";
    1161             :             break;
    1162             : 
    1163             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_AND:
    1164             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_BITWISE_AND (&)";
    1165             :             break;
    1166             : 
    1167             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_XOR:
    1168             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_BITWISE_XOR (^)";
    1169             :             break;
    1170             : 
    1171             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_OR:
    1172             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_BITWISE_OR (|)";
    1173             :             break;
    1174             : 
    1175             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_AND:
    1176             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LOGICAL_AND (&&)";
    1177             :             break;
    1178             : 
    1179             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_XOR:
    1180             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LOGICAL_XOR (^^)";
    1181             :             break;
    1182             : 
    1183             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_OR:
    1184             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_LOGICAL_OR (||)";
    1185             :             break;
    1186             : 
    1187             :         case node_type_t::NODE_TYPE_OPERATION_CONDITIONAL:
    1188             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_CONDITIONAL (?:)";
    1189             :             break;
    1190             : 
    1191             :         case node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT:
    1192             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT (" << f_name << ":= ...)";
    1193             :             break;
    1194             : 
    1195             :         case node_type_t::NODE_TYPE_OPERATION_VARIABLE:
    1196             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_OPERATION_VARIABLE (" << f_name
    1197             :                 << (variables.contains(f_name) ? " = " : "")
    1198             :                 << (variables.contains(f_name) ? variables[f_name].to_string() : "")
    1199             :                 << ")";
    1200             :             break;
    1201             : 
    1202             :         case node_type_t::NODE_TYPE_LITERAL_BOOLEAN:
    1203             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_LITERAL_BOOLEAN (" << (f_variable.get_bool(f_name) ? "true" : "false") << ")";
    1204             :             break;
    1205             : 
    1206             :         case node_type_t::NODE_TYPE_LITERAL_INTEGER:
    1207             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_LITERAL_INTEGER (" << f_variable.get_integer(f_name) << ")";
    1208             :             break;
    1209             : 
    1210             :         case node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT:
    1211             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT (" << f_variable.get_value().safeDoubleValue() << ")";
    1212             :             break;
    1213             : 
    1214             :         case node_type_t::NODE_TYPE_LITERAL_STRING:
    1215             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_LITERAL_STRING (" << f_variable.get_string(f_name) << ")";
    1216             :             break;
    1217             : 
    1218             :         case node_type_t::NODE_TYPE_VARIABLE:
    1219             :             SNAP_LOG_TRACE() << "execute: node_type_t::NODE_TYPE_VARIABLE";
    1220             :             break;
    1221             : 
    1222             :         }
    1223             : #endif
    1224             : 
    1225           0 :         variable_t::variable_vector_t sub_results;
    1226           0 :         if(node_type_t::NODE_TYPE_OPERATION_CONDITIONAL != f_type)
    1227             :         {
    1228             :             // we don't do that for conditionals because only the left
    1229             :             // or only the right shall be computed!
    1230           0 :             int const max_children(f_children.size());
    1231           0 :             for(int i(0); i < max_children; ++i)
    1232             :             {
    1233           0 :                 variable_t cr;
    1234           0 :                 f_children[i]->execute(cr, variables, functions);
    1235           0 :                 sub_results.push_back(cr);
    1236             :             }
    1237             :         }
    1238             : 
    1239           0 :         switch(f_type)
    1240             :         {
    1241           0 :         case node_type_t::NODE_TYPE_UNKNOWN:
    1242             :         case node_type_t::NODE_TYPE_LOADING:
    1243           0 :             throw snap_logic_exception("expr_node::execute() called with an incompatible result type: node_type_t::NODE_TYPE_UNKNOWN or node_type_t::NODE_TYPE_LOADING");
    1244             : 
    1245           0 :         case node_type_t::NODE_TYPE_OPERATION_LIST:
    1246           0 :             result = sub_results.last();
    1247           0 :             break;
    1248             : 
    1249           0 :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_NOT:
    1250           0 :             logical_not(result, sub_results);
    1251           0 :             break;
    1252             : 
    1253           0 :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_NOT:
    1254           0 :             bitwise_not(result, sub_results);
    1255           0 :             break;
    1256             : 
    1257           0 :         case node_type_t::NODE_TYPE_OPERATION_NEGATE:
    1258           0 :             negate(result, sub_results);
    1259           0 :             break;
    1260             : 
    1261           0 :         case node_type_t::NODE_TYPE_OPERATION_FUNCTION:
    1262           0 :             call_function(result, sub_results, functions);
    1263           0 :             break;
    1264             : 
    1265           0 :         case node_type_t::NODE_TYPE_OPERATION_MULTIPLY:
    1266           0 :             binary_operation<op_multiply>("*", result, sub_results);
    1267           0 :             break;
    1268             : 
    1269           0 :         case node_type_t::NODE_TYPE_OPERATION_DIVIDE:
    1270           0 :             binary_operation<op_divide>("/", result, sub_results);
    1271           0 :             break;
    1272             : 
    1273           0 :         case node_type_t::NODE_TYPE_OPERATION_MODULO:
    1274           0 :             binary_operation<op_modulo>("%", result, sub_results);
    1275           0 :             break;
    1276             : 
    1277           0 :         case node_type_t::NODE_TYPE_OPERATION_ADD:
    1278           0 :             binary_operation<op_add>("+", result, sub_results);
    1279           0 :             break;
    1280             : 
    1281           0 :         case node_type_t::NODE_TYPE_OPERATION_SUBTRACT:
    1282           0 :             binary_operation<op_subtract>("-", result, sub_results);
    1283           0 :             break;
    1284             : 
    1285           0 :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_LEFT:
    1286           0 :             binary_operation<op_shift_left>("<<", result, sub_results);
    1287           0 :             break;
    1288             : 
    1289           0 :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_RIGHT:
    1290           0 :             binary_operation<op_shift_right>(">>", result, sub_results);
    1291           0 :             break;
    1292             : 
    1293           0 :         case node_type_t::NODE_TYPE_OPERATION_LESS:
    1294           0 :             bool_binary_operation<op_less>("<", result, sub_results);
    1295           0 :             break;
    1296             : 
    1297           0 :         case node_type_t::NODE_TYPE_OPERATION_LESS_OR_EQUAL:
    1298           0 :             bool_binary_operation<op_less_or_equal>("<=", result, sub_results);
    1299           0 :             break;
    1300             : 
    1301           0 :         case node_type_t::NODE_TYPE_OPERATION_GREATER:
    1302           0 :             bool_binary_operation<op_greater>(">", result, sub_results);
    1303           0 :             break;
    1304             : 
    1305           0 :         case node_type_t::NODE_TYPE_OPERATION_GREATER_OR_EQUAL:
    1306           0 :             bool_binary_operation<op_greater_or_equal>(">=", result, sub_results);
    1307           0 :             break;
    1308             : 
    1309           0 :         case node_type_t::NODE_TYPE_OPERATION_MINIMUM:
    1310           0 :             binary_operation<op_minimum>("<?", result, sub_results);
    1311           0 :             break;
    1312             : 
    1313           0 :         case node_type_t::NODE_TYPE_OPERATION_MAXIMUM:
    1314           0 :             binary_operation<op_maximum>(">?", result, sub_results);
    1315           0 :             break;
    1316             : 
    1317           0 :         case node_type_t::NODE_TYPE_OPERATION_EQUAL:
    1318           0 :             bool_binary_operation<op_equal>("==", result, sub_results);
    1319           0 :             break;
    1320             : 
    1321           0 :         case node_type_t::NODE_TYPE_OPERATION_NOT_EQUAL:
    1322           0 :             bool_binary_operation<op_not_equal>("!=", result, sub_results);
    1323           0 :             break;
    1324             : 
    1325           0 :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_AND:
    1326           0 :             binary_operation<op_bitwise_and>("&", result, sub_results);
    1327           0 :             break;
    1328             : 
    1329           0 :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_XOR:
    1330           0 :             binary_operation<op_bitwise_xor>("^", result, sub_results);
    1331           0 :             break;
    1332             : 
    1333           0 :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_OR:
    1334           0 :             binary_operation<op_bitwise_or>("|", result, sub_results);
    1335           0 :             break;
    1336             : 
    1337           0 :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_AND:
    1338           0 :             bool_binary_operation<op_logical_and>("&&", result, sub_results);
    1339           0 :             break;
    1340             : 
    1341           0 :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_XOR:
    1342           0 :             bool_binary_operation<op_logical_xor>("^^", result, sub_results);
    1343           0 :             break;
    1344             : 
    1345           0 :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_OR:
    1346           0 :             bool_binary_operation<op_logical_or>("||", result, sub_results);
    1347           0 :             break;
    1348             : 
    1349           0 :         case node_type_t::NODE_TYPE_OPERATION_CONDITIONAL:
    1350           0 :             conditional(result, variables, functions);
    1351           0 :             break;
    1352             : 
    1353           0 :         case node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT:
    1354           0 :             assignment(result, sub_results, variables);
    1355           0 :             break;
    1356             : 
    1357           0 :         case node_type_t::NODE_TYPE_OPERATION_VARIABLE:
    1358           0 :             load_variable(result, variables);
    1359           0 :             break;
    1360             : 
    1361           0 :         case node_type_t::NODE_TYPE_LITERAL_BOOLEAN:
    1362           0 :             result = f_variable;
    1363           0 :             break;
    1364             : 
    1365           0 :         case node_type_t::NODE_TYPE_LITERAL_INTEGER:
    1366           0 :             result = f_variable;
    1367           0 :             break;
    1368             : 
    1369           0 :         case node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT:
    1370           0 :             result = f_variable;
    1371           0 :             break;
    1372             : 
    1373           0 :         case node_type_t::NODE_TYPE_LITERAL_STRING:
    1374           0 :             result = f_variable;
    1375           0 :             break;
    1376             : 
    1377           0 :         case node_type_t::NODE_TYPE_VARIABLE:
    1378             :             // a program cannot include variables as instructions
    1379           0 :             throw snap_logic_exception(QString("expr_node::execute() called with an incompatible type: %1").arg(static_cast<int>(static_cast<node_type_t>(f_type))));
    1380             : 
    1381             :         }
    1382           0 :     }
    1383             : 
    1384           0 :     void logical_not(variable_t& result, variable_t::variable_vector_t const& sub_results)
    1385             :     {
    1386           0 :         verify_unary(sub_results);
    1387           0 :         libdbproxy::value value;
    1388           0 :         switch(sub_results[0].get_type())
    1389             :         {
    1390           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    1391           0 :             value.setBoolValue(!sub_results[0].get_value().safeBoolValue());
    1392           0 :             break;
    1393             : 
    1394           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    1395           0 :             value.setBoolValue(sub_results[0].get_value().safeSignedCharValue() == 0);
    1396           0 :             break;
    1397             : 
    1398           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    1399           0 :             value.setBoolValue(sub_results[0].get_value().safeUnsignedCharValue() == 0);
    1400           0 :             break;
    1401             : 
    1402           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    1403           0 :             value.setBoolValue(sub_results[0].get_value().safeInt16Value() == 0);
    1404           0 :             break;
    1405             : 
    1406           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    1407           0 :             value.setBoolValue(sub_results[0].get_value().safeUInt16Value() == 0);
    1408           0 :             break;
    1409             : 
    1410           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    1411           0 :             value.setBoolValue(sub_results[0].get_value().safeInt32Value() == 0);
    1412           0 :             break;
    1413             : 
    1414           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    1415           0 :             value.setBoolValue(sub_results[0].get_value().safeUInt32Value() == 0);
    1416           0 :             break;
    1417             : 
    1418           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    1419           0 :             value.setBoolValue(sub_results[0].get_value().safeInt64Value() == 0);
    1420           0 :             break;
    1421             : 
    1422           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    1423           0 :             value.setBoolValue(sub_results[0].get_value().safeUInt64Value() == 0);
    1424           0 :             break;
    1425             : 
    1426           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    1427             : #pragma GCC diagnostic push
    1428             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1429           0 :             value.setBoolValue(sub_results[0].get_value().safeFloatValue() == 0.0f);
    1430             : #pragma GCC diagnostic pop
    1431           0 :             break;
    1432             : 
    1433           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    1434             : #pragma GCC diagnostic push
    1435             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    1436           0 :             value.setBoolValue(sub_results[0].get_value().safeDoubleValue() == 0.0);
    1437             : #pragma GCC diagnostic pop
    1438           0 :             break;
    1439             : 
    1440           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    1441           0 :             value.setBoolValue(sub_results[0].get_value().stringValue().length() == 0);
    1442           0 :             break;
    1443             : 
    1444           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    1445           0 :             value.setBoolValue(sub_results[0].get_value().binaryValue().size() == 0);
    1446           0 :             break;
    1447             : 
    1448           0 :         default:
    1449           0 :             throw snap_logic_exception(QString("expr_node::logical_not() called with an incompatible sub_result type: %1").arg(static_cast<int>(sub_results[0].get_type())));
    1450             : 
    1451             :         }
    1452           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    1453           0 :     }
    1454             : 
    1455           0 :     void bitwise_not(variable_t& result, variable_t::variable_vector_t const& sub_results)
    1456             :     {
    1457           0 :         verify_unary(sub_results);
    1458           0 :         libdbproxy::value value;
    1459           0 :         switch(sub_results[0].get_type())
    1460             :         {
    1461           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    1462             :             // this is balently "wrong" as far as the source is concerned
    1463             :             // and maybe we should throw instead of accepting such bad code?
    1464             :             // (i.e. g++ and Coverity do not like it without the casts so
    1465             :             // maybe we ought to throw on such and have the programmer fix
    1466             :             // their source) CID 30192
    1467             :             //
    1468           0 :             value.setBoolValue(static_cast<bool>(~static_cast<int>(sub_results[0].get_value().safeBoolValue())));
    1469           0 :             break;
    1470             : 
    1471           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    1472           0 :             value.setSignedCharValue(static_cast<signed char>(~sub_results[0].get_value().safeSignedCharValue()));
    1473           0 :             break;
    1474             : 
    1475           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    1476           0 :             value.setUnsignedCharValue(static_cast<unsigned char>(~sub_results[0].get_value().safeUnsignedCharValue()));
    1477           0 :             break;
    1478             : 
    1479           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    1480           0 :             value.setInt16Value(static_cast<int16_t>(~sub_results[0].get_value().safeInt16Value()));
    1481           0 :             break;
    1482             : 
    1483           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    1484           0 :             value.setUInt16Value(static_cast<uint16_t>(~sub_results[0].get_value().safeUInt16Value()));
    1485           0 :             break;
    1486             : 
    1487           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    1488           0 :             value.setInt32Value(~sub_results[0].get_value().safeInt32Value());
    1489           0 :             break;
    1490             : 
    1491           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    1492           0 :             value.setUInt32Value(~sub_results[0].get_value().safeUInt32Value());
    1493           0 :             break;
    1494             : 
    1495           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    1496           0 :             value.setInt64Value(~sub_results[0].get_value().safeInt64Value());
    1497           0 :             break;
    1498             : 
    1499           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    1500           0 :             value.setUInt64Value(~sub_results[0].get_value().safeUInt64Value());
    1501           0 :             break;
    1502             : 
    1503             :         //case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    1504             :             // TODO:
    1505             :             // swap case (A -> a and A -> a)
    1506           0 :         default:
    1507           0 :             throw snap_logic_exception(QString("expr_node::bitwise_not() called with an incompatible sub_result type: %1").arg(static_cast<int>(sub_results[0].get_type())));
    1508             : 
    1509             :         }
    1510           0 :         result.set_value(sub_results[0].get_type(), value);
    1511           0 :     }
    1512             : 
    1513           0 :     void negate(variable_t& result, variable_t::variable_vector_t const& sub_results)
    1514             :     {
    1515           0 :         verify_unary(sub_results);
    1516           0 :         libdbproxy::value value;
    1517           0 :         switch(sub_results[0].get_type())
    1518             :         {
    1519           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    1520           0 :             value.setSignedCharValue(static_cast<signed char>(-sub_results[0].get_value().safeSignedCharValue()));
    1521           0 :             break;
    1522             : 
    1523           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    1524           0 :             value.setUnsignedCharValue(static_cast<unsigned char>(-sub_results[0].get_value().safeUnsignedCharValue()));
    1525           0 :             break;
    1526             : 
    1527           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    1528           0 :             value.setInt16Value(static_cast<int16_t>(-sub_results[0].get_value().safeInt16Value()));
    1529           0 :             break;
    1530             : 
    1531           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    1532           0 :             value.setUInt16Value(static_cast<uint16_t>(-sub_results[0].get_value().safeUInt16Value()));
    1533           0 :             break;
    1534             : 
    1535           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    1536           0 :             value.setInt32Value(-sub_results[0].get_value().safeInt32Value());
    1537           0 :             break;
    1538             : 
    1539           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    1540           0 :             value.setUInt32Value(-sub_results[0].get_value().safeUInt32Value());
    1541           0 :             break;
    1542             : 
    1543           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    1544           0 :             value.setInt64Value(-sub_results[0].get_value().safeInt64Value());
    1545           0 :             break;
    1546             : 
    1547           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    1548           0 :             value.setUInt64Value(-sub_results[0].get_value().safeUInt64Value());
    1549           0 :             break;
    1550             : 
    1551           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    1552           0 :             value.setFloatValue(-sub_results[0].get_value().safeFloatValue());
    1553           0 :             break;
    1554             : 
    1555           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    1556           0 :             value.setDoubleValue(-sub_results[0].get_value().safeDoubleValue());
    1557           0 :             break;
    1558             : 
    1559           0 :         default:
    1560           0 :             throw snap_logic_exception(QString("expr_node::negate() called with an incompatible sub_result type: %1").arg(static_cast<int>(sub_results[0].get_type())));
    1561             : 
    1562             :         }
    1563           0 :         result.set_value(sub_results[0].get_type(), value);
    1564           0 :     }
    1565             : 
    1566           0 :     static void call_cell(variable_t& result, variable_t::variable_vector_t const& sub_results)
    1567             :     {
    1568           0 :         if(!g_context)
    1569             :         {
    1570           0 :             throw snap_expr_exception_not_ready("cell() function not available, g_context is NULL.");
    1571             :         }
    1572           0 :         if(sub_results.size() != 3)
    1573             :         {
    1574           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call cell() expected exactly 3.");
    1575             :         }
    1576           0 :         QString const table_name(sub_results[0].get_string("cell(1)"));
    1577           0 :         QString const row_name(sub_results[1].get_string("cell(2)"));
    1578           0 :         QString const cell_name(sub_results[2].get_string("cell(3)"));
    1579             : //SNAP_LOG_WARNING("cell(")(table_name)(", ")(row_name)(", ")(cell_name)(") -> ...");
    1580             : 
    1581             :         // verify whether reading the content is considered secure
    1582           0 :         server::accessible_flag_t accessible;
    1583           0 :         server::instance()->table_is_accessible(table_name, accessible);
    1584           0 :         if(!accessible.is_accessible())
    1585             :         {
    1586             :             // TBD: should we just return a string with an error in it
    1587             :             //      instead of throwing?
    1588             :             //
    1589             :             throw snap_expr_exception_not_accessible(
    1590           0 :                     QString("cell() called with a set of parameters specifying access to a secure table (table \"%1\", row \"%2\", cell \"%3\"); no data will be returned.")
    1591           0 :                             .arg(table_name).arg(row_name).arg(cell_name));
    1592             :         }
    1593             : 
    1594           0 :         libdbproxy::value value(g_context->getTable(table_name)->getRow(row_name)->getCell(cell_name)->getValue());
    1595             : //std::cerr << "  -> value size: " << value.size() << "\n";
    1596           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY, value);
    1597           0 :     }
    1598             : 
    1599           0 :     static void call_cell_exists(variable_t & result, variable_t::variable_vector_t const & sub_results)
    1600             :     {
    1601           0 :         if(!g_context)
    1602             :         {
    1603           0 :             throw snap_expr_exception_not_ready("cell_exists() function not available, g_context is NULL");
    1604             :         }
    1605           0 :         if(sub_results.size() != 3)
    1606             :         {
    1607           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call cell_exists(), expected exactly 3");
    1608             :         }
    1609           0 :         QString const table_name(sub_results[0].get_string("cell_exist(1)"));
    1610           0 :         QString const row_name(sub_results[1].get_string("cell_exist(2)"));
    1611           0 :         QString const cell_name(sub_results[2].get_string("cell_exist(3)"));
    1612           0 :         libdbproxy::value value;
    1613           0 :         value.setBoolValue(g_context->getTable(table_name)->getRow(row_name)->exists(cell_name));
    1614             : //SNAP_LOG_WARNING("cell_exists(")(table_name)(", ")(row_name)(", ")(cell_name)(") -> ")(value.boolValue() ? "true" : "false");
    1615           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    1616           0 :     }
    1617             : 
    1618           0 :     static void call_child(variable_t & result, variable_t::variable_vector_t const & sub_results)
    1619             :     {
    1620           0 :         if(sub_results.size() != 2)
    1621             :         {
    1622           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call child() expected exactly 2");
    1623             :         }
    1624           0 :         QString path(sub_results[0].get_string("child(1)"));
    1625           0 :         QString child(sub_results[1].get_string("child(2)"));
    1626           0 :         while(path.endsWith("/"))
    1627             :         {
    1628           0 :             path = path.left(path.length() - 1);
    1629             :         }
    1630           0 :         while(child.startsWith("/"))
    1631             :         {
    1632           0 :             child = child.right(child.length() - 1);
    1633             :         }
    1634           0 :         if(!child.isEmpty()
    1635           0 :         && !path.isEmpty())
    1636             :         {
    1637           0 :             path = path + "/" + child;
    1638             :         }
    1639           0 :         libdbproxy::value value;
    1640           0 :         value.setStringValue(path);
    1641           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    1642           0 :     }
    1643             : 
    1644             :     // This cannot work right in an international website
    1645             :     // The dates should be saved as int64_t values in the database instead
    1646             :     //static void call_date_to_us(variable_t & result, variable_t::variable_vector_t const & sub_results)
    1647             :     //{
    1648             :     //    if(!g_context)
    1649             :     //    {
    1650             :     //        throw snap_expr_exception_not_ready("date_to_us() function not available, g_context is NULL");
    1651             :     //    }
    1652             :     //    if(sub_results.size() != 1)
    1653             :     //    {
    1654             :     //        throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call date_to_us(), expected exactly 1");
    1655             :     //    }
    1656             :     //    QString const date_str(sub_results[0].get_string("date_to_us(1)"));
    1657             : 
    1658             :     //    // we only support MM/DD/YYYY
    1659             :     //    struct tm time_info;
    1660             :     //    memset(&time_info, 0, sizeof(time_info));
    1661             :     //    time_info.tm_mon = date_str.mid(0, 2).toInt() - 1;
    1662             :     //    time_info.tm_mday = date_str.mid(3, 2).toInt();
    1663             :     //    time_info.tm_year = date_str.mid(6, 4).toInt() - 1900;
    1664             :     //    time_t t(mkgmtime(&time_info));
    1665             : 
    1666             :     //    libdbproxy::value value;
    1667             :     //    value.setInt64Value(t * 1000000);
    1668             :     //    result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    1669             :     //}
    1670             : 
    1671           0 :     static void call_format(variable_t & result, variable_t::variable_vector_t const & sub_results)
    1672             :     {
    1673           0 :         if(sub_results.size() < 1)
    1674             :         {
    1675           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call format() expected at least 1, the format");
    1676             :         }
    1677             : 
    1678           0 :         struct input
    1679             :         {
    1680             :             int const INPUT_LEFT_ALIGN = 0x0001;
    1681             :             int const INPUT_ZERO_PAD   = 0x0002;
    1682             :             int const INPUT_BLANK      = 0x0004;
    1683             :             int const INPUT_SIGN       = 0x0008;
    1684             :             int const INPUT_THOUSANDS  = 0x0010;
    1685             : 
    1686           0 :             input(variable_t::variable_vector_t const& sub_results)
    1687           0 :                 : f_sub_results(sub_results)
    1688             :             {
    1689           0 :                 f_format = sub_results[0].get_string("format() function format string");
    1690           0 :             }
    1691             : 
    1692           0 :             int getc()
    1693             :             {
    1694           0 :                 if(f_position >= f_format.length())
    1695             :                 {
    1696           0 :                     f_last = EOF;
    1697             :                 }
    1698             :                 else
    1699             :                 {
    1700           0 :                     f_last = f_format[f_position].unicode();
    1701           0 :                     ++f_position;
    1702             :                 }
    1703           0 :                 return f_last;
    1704             :             }
    1705             : 
    1706           0 :             int get_flags()
    1707             :             {
    1708           0 :                 int flags(0);
    1709           0 :                 for(int old_flags(-1); flags != old_flags; )
    1710             :                 {
    1711           0 :                     old_flags = flags;
    1712           0 :                     if(f_last == '\'')
    1713             :                     {
    1714           0 :                         flags |= INPUT_THOUSANDS;
    1715           0 :                         getc();
    1716             :                     }
    1717           0 :                     if(f_last == ' ')
    1718             :                     {
    1719           0 :                         flags |= INPUT_BLANK;
    1720           0 :                         getc();
    1721             :                     }
    1722           0 :                     if(f_last == '+')
    1723             :                     {
    1724           0 :                         flags |= INPUT_SIGN;
    1725           0 :                         getc();
    1726             :                     }
    1727           0 :                     if(f_last == '-')
    1728             :                     {
    1729           0 :                         flags |= INPUT_LEFT_ALIGN;
    1730           0 :                         getc();
    1731             :                     }
    1732           0 :                     if(f_last == '0')
    1733             :                     {
    1734           0 :                         flags |= INPUT_ZERO_PAD;
    1735           0 :                         getc();
    1736             :                     }
    1737             :                 }
    1738             : 
    1739             :                 // mutually exclusive flags
    1740           0 :                 if(flags & INPUT_LEFT_ALIGN)
    1741             :                 {
    1742           0 :                     flags &= ~INPUT_ZERO_PAD;
    1743             :                 }
    1744           0 :                 if(flags & INPUT_SIGN)
    1745             :                 {
    1746           0 :                     flags &= ~INPUT_BLANK;
    1747             :                 }
    1748             : 
    1749           0 :                 return flags;
    1750             :             }
    1751             : 
    1752           0 :             int get_number()
    1753             :             {
    1754           0 :                 int number(0);
    1755           0 :                 for(; f_last >= '0' && f_last <= '9'; getc())
    1756             :                 {
    1757           0 :                     number = number * 10 + f_last - '0';
    1758             :                 }
    1759           0 :                 return number;
    1760             :             }
    1761             : 
    1762           0 :             variable_t const & get_next_variable()
    1763             :             {
    1764           0 :                 if(f_index >= f_sub_results.size())
    1765             :                 {
    1766           0 :                     throw snap_expr_exception_invalid_data("invalid number of parameters to call format(), your format requires more parameters than is currently allowed");
    1767             :                 }
    1768           0 :                 variable_t const & r(f_sub_results[f_index]);
    1769           0 :                 ++f_index;
    1770           0 :                 return r;
    1771             :             }
    1772             : 
    1773           0 :             QString get_integer()
    1774             :             {
    1775           0 :                 int64_t v(get_next_variable().get_integer("format.get_integer()"));
    1776           0 :                 QString r(QString("%1").arg(v));
    1777           0 :                 if(f_flags & INPUT_THOUSANDS)
    1778             :                 {
    1779           0 :                     int stop(0);
    1780           0 :                     if(r[0] == '-')
    1781             :                     {
    1782           0 :                         stop = 1;
    1783             :                     }
    1784           0 :                     for(int p(r.length() - 3); p > stop; p -= 3)
    1785             :                     {
    1786             :                         // TODO: need to be able to specify the separator
    1787             :                         //       (',', or '.', or ' ', or '_', ...)
    1788             :                         //
    1789           0 :                         r.insert(p, ',');
    1790             :                     }
    1791             :                 }
    1792           0 :                 if((f_flags & INPUT_SIGN) && v >= 0)
    1793             :                 {
    1794           0 :                     r = "+" + r;
    1795             :                 }
    1796           0 :                 else if((f_flags & INPUT_BLANK) && v >= 0)
    1797             :                 {
    1798           0 :                     r = " " + r;
    1799             :                 }
    1800           0 :                 return r;
    1801             :             }
    1802             : 
    1803           0 :             QString get_floating_point()
    1804             :             {
    1805             :                 // TODO: floating points need to be properly formatted here
    1806             :                 //       (i.e. width and precision...)
    1807           0 :                 double v(get_next_variable().get_floating_point("format.get_floating_point()"));
    1808           0 :                 QString r(QString("%1").arg(v));
    1809           0 :                 if(f_flags & INPUT_THOUSANDS)
    1810             :                 {
    1811           0 :                     int stop(0);
    1812           0 :                     if(r[0] == '-')
    1813             :                     {
    1814           0 :                         stop = 1;
    1815             :                     }
    1816           0 :                     int p(r.indexOf('.'));
    1817           0 :                     if(p == -1)
    1818             :                     {
    1819           0 :                         p = r.length() - 3;
    1820             :                     }
    1821           0 :                     for(; p > stop; p -= 3)
    1822             :                     {
    1823             :                         // TODO: need to be able to specify the separator
    1824             :                         //       (',', or '.', or ' ', or '_', ...)
    1825             :                         //
    1826           0 :                         r.insert(p, ',');
    1827             :                     }
    1828             :                     // TBD: add thousand markers in the decimal part?
    1829             :                 }
    1830           0 :                 if((f_flags & INPUT_SIGN) && v >= 0)
    1831             :                 {
    1832           0 :                     r = "+" + r;
    1833             :                 }
    1834           0 :                 else if((f_flags & INPUT_BLANK) && v >= 0)
    1835             :                 {
    1836           0 :                     r = " " + r;
    1837             :                 }
    1838           0 :                 return r;
    1839             :             }
    1840             : 
    1841           0 :             QString get_character()
    1842             :             {
    1843             :                 // TODO: verify that the integer is a valid code point
    1844           0 :                 int64_t code(get_next_variable().get_integer("format.get_character()"));
    1845           0 :                 if(code < 0 || code > 0x110000
    1846           0 :                 || (code >= 0xD800 && code <= 0xDFFF))
    1847             :                 {
    1848           0 :                     throw snap_expr_exception_invalid_data("invalid character code in format(), only valid Unicode characters are allowed");
    1849             :                 }
    1850           0 :                 if(QChar::requiresSurrogates(code))
    1851             :                 {
    1852             :                     // this uses the old Unicode terminology
    1853           0 :                     QChar high(QChar::highSurrogate(code));
    1854           0 :                     QChar low(QChar::lowSurrogate(code));
    1855           0 :                     return QString(high) + QString(low);
    1856             :                 }
    1857             :                 else
    1858             :                 {
    1859             :                     // small characters can be used as is
    1860           0 :                     QChar c(static_cast<uint>(code));
    1861           0 :                     return QString(c);
    1862             :                 }
    1863             :             }
    1864             : 
    1865           0 :             QString get_string()
    1866             :             {
    1867           0 :                 QString r(QString("%1").arg(get_next_variable().get_string("format.get_string()")));
    1868           0 :                 if(r.isEmpty() && (f_flags & INPUT_BLANK))
    1869             :                 {
    1870             :                     // blank against empty strings...
    1871           0 :                     r = " ";
    1872             :                 }
    1873           0 :                 if(f_precision > 0)
    1874             :                 {
    1875             :                     // truncate
    1876             :                     // TODO: truncating a QString is wrong if it includes
    1877             :                     //       UTF-16 surrogate characters!
    1878           0 :                     r = r.left(f_precision);
    1879             :                 }
    1880           0 :                 f_flags &= ~INPUT_ZERO_PAD;
    1881           0 :                 return r;
    1882             :             }
    1883             : 
    1884           0 :             QString format(QString value)
    1885             :             {
    1886           0 :                 int align(f_width - value.length());
    1887           0 :                 if(align > 0)
    1888             :                 {
    1889             :                     // need padding
    1890           0 :                     if(f_flags & INPUT_LEFT_ALIGN)
    1891             :                     {
    1892             :                         // add padding to the right side
    1893           0 :                         value += QString(" ").repeated(align);
    1894             :                     }
    1895           0 :                     else if(f_flags & INPUT_ZERO_PAD)
    1896             :                     {
    1897           0 :                         QChar c(value[0]);
    1898           0 :                         QString const pad("0");
    1899           0 :                         switch(c.unicode())
    1900             :                         {
    1901           0 :                         case '+':
    1902             :                         case '-':
    1903           0 :                             value = c + pad.repeated(align) + value.mid(1);
    1904           0 :                             break;
    1905             : 
    1906           0 :                         case ' ':
    1907           0 :                             if(f_flags & INPUT_BLANK)
    1908             :                             {
    1909             :                                 // special case if we had the blank flag
    1910           0 :                                 value = c + pad.repeated(align) + value.mid(1);
    1911           0 :                                 break;
    1912             :                             }
    1913             : #if __cplusplus >= 201700
    1914             :                             [[fallthrough]];
    1915             : #endif
    1916             :                         default:
    1917           0 :                             value = pad.repeated(align) + value;
    1918           0 :                             break;
    1919             : 
    1920             :                         }
    1921             :                     }
    1922             :                     else
    1923             :                     {
    1924           0 :                         value = QString(" ").repeated(align) + value;
    1925             :                     }
    1926             :                 }
    1927           0 :                 return value;
    1928             :             }
    1929             : 
    1930           0 :             void parse()
    1931             :             {
    1932           0 :                 while(getc() != EOF)
    1933             :                 {
    1934           0 :                     if(f_last == '%')
    1935             :                     {
    1936             :                         // skip the '%'
    1937           0 :                         if(getc() == EOF)
    1938             :                         {
    1939           0 :                             return;
    1940             :                         }
    1941           0 :                         if(f_last == '%')
    1942             :                         {
    1943             :                             // literal percent
    1944           0 :                             f_result += '%';
    1945             :                         }
    1946             :                         else
    1947             :                         {
    1948           0 :                             f_flags = get_flags();
    1949           0 :                             if(f_last >= '1' && f_last <= '9')
    1950             :                             {
    1951           0 :                                 f_width = get_number();
    1952             :                             }
    1953             :                             else
    1954             :                             {
    1955           0 :                                 f_width = 0;
    1956             :                             }
    1957           0 :                             if(f_last == '.')
    1958             :                             {
    1959           0 :                                 getc();
    1960           0 :                                 f_precision = get_number();
    1961             :                             }
    1962             :                             else
    1963             :                             {
    1964             :                                 // default precision is 1, but we need to
    1965             :                                 // have -1 to distinguish in the case of
    1966             :                                 // a string
    1967           0 :                                 f_precision = -1;
    1968             :                             }
    1969           0 :                             switch(f_last)
    1970             :                             {
    1971           0 :                             case 'd': // integer formatting
    1972             :                             case 'i':
    1973           0 :                                 f_result += format(get_integer());
    1974           0 :                                 break;
    1975             : 
    1976           0 :                             case 'f': // floating point formatting
    1977             :                             case 'g':
    1978           0 :                                 f_result += format(get_floating_point());
    1979           0 :                                 break;
    1980             : 
    1981           0 :                             case 'c': // character formatting
    1982             :                             case 'C':
    1983           0 :                                 f_result += format(get_character());
    1984           0 :                                 break;
    1985             : 
    1986           0 :                             case 's': // string formatting
    1987             :                             case 'S':
    1988           0 :                                 f_result += format(get_string());
    1989           0 :                                 break;
    1990             : 
    1991             :                             }
    1992             :                         }
    1993             :                     }
    1994             :                     else
    1995             :                     {
    1996           0 :                         f_result += f_last;
    1997             :                     }
    1998             :                 }
    1999             :             }
    2000             : 
    2001             :             variable_t::variable_vector_t const &   f_sub_results;
    2002             :             QString                                 f_format = QString();
    2003             :             int32_t                                 f_position = 0;
    2004             :             int32_t                                 f_index = 1;
    2005             :             QString                                 f_result = QString();
    2006             :             int                                     f_last = EOF;
    2007             :             int                                     f_flags = 0;
    2008             :             int32_t                                 f_width = 0;
    2009             :             int32_t                                 f_precision = 0;
    2010             :         };
    2011           0 :         input in(sub_results);
    2012           0 :         in.parse();
    2013           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, in.f_result);
    2014           0 :     }
    2015             : 
    2016           0 :     static void call_int16(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2017             :     {
    2018           0 :         if(sub_results.size() != 1)
    2019             :         {
    2020           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call int16() expected exactly 1");
    2021             :         }
    2022           0 :         int16_t r(0);
    2023           0 :         libdbproxy::value const& v(sub_results[0].get_value());
    2024           0 :         switch(sub_results[0].get_type())
    2025             :         {
    2026           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2027             :             //r = 0; -- an "empty" number...
    2028           0 :             break;
    2029             : 
    2030           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2031           0 :             r = v.safeBoolValue() ? 1 : 0;
    2032           0 :             break;
    2033             : 
    2034           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2035           0 :             r = v.safeSignedCharValue();
    2036           0 :             break;
    2037             : 
    2038           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2039           0 :             r = v.safeUnsignedCharValue();
    2040           0 :             break;
    2041             : 
    2042           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2043           0 :             r = v.safeInt16Value();
    2044           0 :             break;
    2045             : 
    2046           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2047           0 :             r = v.safeUInt16Value();
    2048           0 :             break;
    2049             : 
    2050           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2051           0 :             r = static_cast<int16_t>(v.safeInt32Value());
    2052           0 :             break;
    2053             : 
    2054           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2055           0 :             r = static_cast<int16_t>(v.safeUInt32Value());
    2056           0 :             break;
    2057             : 
    2058           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2059           0 :             r = static_cast<int16_t>(v.safeInt64Value());
    2060           0 :             break;
    2061             : 
    2062           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2063           0 :             r = static_cast<int16_t>(v.safeUInt64Value());
    2064           0 :             break;
    2065             : 
    2066           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2067           0 :             r = static_cast<int16_t>(v.safeFloatValue());
    2068           0 :             break;
    2069             : 
    2070           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2071           0 :             r = static_cast<int16_t>(v.safeDoubleValue());
    2072           0 :             break;
    2073             : 
    2074           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2075           0 :             r = static_cast<int16_t>(v.stringValue().toLongLong());
    2076           0 :             break;
    2077             : 
    2078           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2079           0 :             r = v.safeInt16Value();
    2080           0 :             break;
    2081             : 
    2082             :         }
    2083           0 :         libdbproxy::value value;
    2084           0 :         value.setInt16Value(r);
    2085           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16, value);
    2086           0 :     }
    2087             : 
    2088           0 :     static void call_int32(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2089             :     {
    2090           0 :         if(sub_results.size() != 1)
    2091             :         {
    2092           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call int32() expected exactly 1");
    2093             :         }
    2094           0 :         int32_t r(0);
    2095           0 :         libdbproxy::value const& v(sub_results[0].get_value());
    2096           0 :         switch(sub_results[0].get_type())
    2097             :         {
    2098           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2099             :             //r = 0; -- an "empty" number...
    2100           0 :             break;
    2101             : 
    2102           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2103           0 :             r = v.safeBoolValue() ? 1 : 0;
    2104           0 :             break;
    2105             : 
    2106           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2107           0 :             r = v.safeSignedCharValue();
    2108           0 :             break;
    2109             : 
    2110           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2111           0 :             r = v.safeUnsignedCharValue();
    2112           0 :             break;
    2113             : 
    2114           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2115           0 :             r = v.safeInt16Value();
    2116           0 :             break;
    2117             : 
    2118           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2119           0 :             r = v.safeUInt16Value();
    2120           0 :             break;
    2121             : 
    2122           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2123           0 :             r = v.safeInt32Value();
    2124           0 :             break;
    2125             : 
    2126           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2127           0 :             r = v.safeUInt32Value();
    2128           0 :             break;
    2129             : 
    2130           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2131           0 :             r = static_cast<int32_t>(v.safeInt64Value());
    2132           0 :             break;
    2133             : 
    2134           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2135           0 :             r = static_cast<int32_t>(v.safeUInt64Value());
    2136           0 :             break;
    2137             : 
    2138           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2139           0 :             r = static_cast<int32_t>(v.safeFloatValue());
    2140           0 :             break;
    2141             : 
    2142           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2143           0 :             r = static_cast<int32_t>(v.safeDoubleValue());
    2144           0 :             break;
    2145             : 
    2146           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2147           0 :             r = static_cast<int32_t>(v.stringValue().toLongLong());
    2148           0 :             break;
    2149             : 
    2150           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2151           0 :             r = v.safeInt32Value();
    2152           0 :             break;
    2153             : 
    2154             :         }
    2155           0 :         libdbproxy::value value;
    2156           0 :         value.setInt32Value(r);
    2157           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32, value);
    2158           0 :     }
    2159             : 
    2160           0 :     static void call_int64(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2161             :     {
    2162           0 :         if(sub_results.size() != 1)
    2163             :         {
    2164           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call int64() expected exactly 1");
    2165             :         }
    2166           0 :         int64_t r(0);
    2167           0 :         libdbproxy::value const& v(sub_results[0].get_value());
    2168           0 :         switch(sub_results[0].get_type())
    2169             :         {
    2170           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2171             :             //r = 0; -- an "empty" number...
    2172           0 :             break;
    2173             : 
    2174           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2175           0 :             r = v.safeBoolValue() ? 1 : 0;
    2176           0 :             break;
    2177             : 
    2178           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2179           0 :             r = v.safeSignedCharValue();
    2180           0 :             break;
    2181             : 
    2182           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2183           0 :             r = v.safeUnsignedCharValue();
    2184           0 :             break;
    2185             : 
    2186           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2187           0 :             r = v.safeInt16Value();
    2188           0 :             break;
    2189             : 
    2190           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2191           0 :             r = v.safeUInt16Value();
    2192           0 :             break;
    2193             : 
    2194           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2195           0 :             r = v.safeInt32Value();
    2196           0 :             break;
    2197             : 
    2198           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2199           0 :             r = v.safeUInt32Value();
    2200           0 :             break;
    2201             : 
    2202           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2203           0 :             r = v.safeInt64Value();
    2204           0 :             break;
    2205             : 
    2206           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2207           0 :             r = v.safeUInt64Value();
    2208           0 :             break;
    2209             : 
    2210           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2211           0 :             r = static_cast<int64_t>(v.safeFloatValue());
    2212           0 :             break;
    2213             : 
    2214           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2215           0 :             r = static_cast<int64_t>(v.safeDoubleValue());
    2216           0 :             break;
    2217             : 
    2218           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2219           0 :             r = v.stringValue().toLongLong();
    2220           0 :             break;
    2221             : 
    2222           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2223           0 :             r = v.safeInt64Value();
    2224           0 :             break;
    2225             : 
    2226             :         }
    2227           0 :         libdbproxy::value value;
    2228           0 :         value.setInt64Value(r);
    2229           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64, value);
    2230           0 :     }
    2231             : 
    2232           0 :     static void call_int8(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2233             :     {
    2234           0 :         if(sub_results.size() != 1)
    2235             :         {
    2236           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call int8() expected exactly 1");
    2237             :         }
    2238           0 :         int8_t r(0);
    2239           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2240           0 :         switch(sub_results[0].get_type())
    2241             :         {
    2242           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2243             :             //r = 0; -- an "empty" number...
    2244           0 :             break;
    2245             : 
    2246           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2247           0 :             r = v.safeBoolValue() ? 1 : 0;
    2248           0 :             break;
    2249             : 
    2250           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2251           0 :             r = v.safeSignedCharValue();
    2252           0 :             break;
    2253             : 
    2254           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2255           0 :             r = static_cast<int8_t>(v.safeUnsignedCharValue());
    2256           0 :             break;
    2257             : 
    2258           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2259           0 :             r = static_cast<int8_t>(v.safeInt16Value());
    2260           0 :             break;
    2261             : 
    2262           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2263           0 :             r = static_cast<int8_t>(v.safeUInt16Value());
    2264           0 :             break;
    2265             : 
    2266           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2267           0 :             r = static_cast<int8_t>(v.safeInt32Value());
    2268           0 :             break;
    2269             : 
    2270           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2271           0 :             r = static_cast<int8_t>(v.safeUInt32Value());
    2272           0 :             break;
    2273             : 
    2274           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2275           0 :             r = static_cast<int8_t>(v.safeInt64Value());
    2276           0 :             break;
    2277             : 
    2278           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2279           0 :             r = static_cast<int8_t>(v.safeUInt64Value());
    2280           0 :             break;
    2281             : 
    2282           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2283           0 :             r = static_cast<int8_t>(v.safeFloatValue());
    2284           0 :             break;
    2285             : 
    2286           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2287           0 :             r = static_cast<int8_t>(v.safeDoubleValue());
    2288           0 :             break;
    2289             : 
    2290           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2291           0 :             r = static_cast<int8_t>(v.stringValue().toLongLong());
    2292           0 :             break;
    2293             : 
    2294           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2295           0 :             r = v.safeSignedCharValue();
    2296           0 :             break;
    2297             : 
    2298             :         }
    2299           0 :         libdbproxy::value value;
    2300           0 :         value.setSignedCharValue(r);
    2301           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8, value);
    2302           0 :     }
    2303             : 
    2304           0 :     static void call_is_integer(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2305             :     {
    2306           0 :         if(sub_results.size() != 1)
    2307             :         {
    2308           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call is_integer() expected exactly 1");
    2309             :         }
    2310           0 :         bool r(false);
    2311           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2312           0 :         switch(sub_results[0].get_type())
    2313             :         {
    2314           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2315             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2316             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2317             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2318             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2319           0 :             break;
    2320             : 
    2321           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2322             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2323             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2324             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2325             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2326             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2327             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2328             :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2329           0 :             r = true;
    2330           0 :             break;
    2331             : 
    2332           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2333             :             // make sure it is a valid integer
    2334           0 :             v.stringValue().toLongLong(&r, 10);
    2335           0 :             break;
    2336             : 
    2337             :         }
    2338           0 :         libdbproxy::value value;
    2339           0 :         value.setBoolValue(r);
    2340           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    2341           0 :     }
    2342             : 
    2343           0 :     static void call_parent(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2344             :     {
    2345           0 :         if(sub_results.size() != 1)
    2346             :         {
    2347           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call parent() expected exactly 1");
    2348             :         }
    2349           0 :         QString path(sub_results[0].get_string("parent(1)"));
    2350           0 :         if(path.endsWith("/"))
    2351             :         {
    2352           0 :             path = path.left(path.length() - 1);
    2353             :         }
    2354           0 :         int pos(path.lastIndexOf('/'));
    2355           0 :         if(pos == -1)
    2356             :         {
    2357           0 :             path.clear();
    2358             :         }
    2359             :         else
    2360             :         {
    2361           0 :             path = path.mid(0, pos);
    2362             :         }
    2363           0 :         libdbproxy::value value;
    2364           0 :         value.setStringValue(path);
    2365           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    2366           0 :     }
    2367             : 
    2368           0 :     static void call_preg_replace(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2369             :     {
    2370           0 :         int const size(sub_results.size());
    2371           0 :         if(size != 3)
    2372             :         {
    2373           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call preg_replace() expected exactly 3");
    2374             :         }
    2375           0 :         QString pattern(sub_results[0].get_string("preg_replace(1)"));
    2376           0 :         QString const replacement(sub_results[1].get_string("preg_replace(2)"));
    2377           0 :         QString str(sub_results[2].get_string("preg_replace(3)"));
    2378           0 :         QString flags;
    2379             : 
    2380             :         // pattern may include a set of flags after the ending '/'
    2381           0 :         Qt::CaseSensitivity cs(Qt::CaseSensitive);
    2382           0 :         if(pattern.length() >= 2
    2383           0 :         && pattern[0] == '/')
    2384             :         {
    2385           0 :             int const end(pattern.lastIndexOf('/'));
    2386           0 :             if(end <= 0)
    2387             :             {
    2388           0 :                 throw snap_expr_exception_invalid_number_of_parameters("invalid pattern for preg_replace() if it starts with a '/' it must end with another '/'");
    2389             :             }
    2390           0 :             flags = pattern.mid(end + 1);
    2391           0 :             pattern = pattern.mid(1, end - 2);
    2392             :         }
    2393           0 :         if(flags.contains("i"))
    2394             :         {
    2395           0 :             cs = Qt::CaseInsensitive;
    2396             :         }
    2397           0 :         QRegExp re(pattern, cs, QRegExp::RegExp2);
    2398           0 :         str.replace(re, replacement); // this does the replacement in place
    2399           0 :         libdbproxy::value value;
    2400           0 :         value.setStringValue(str);
    2401           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    2402           0 :     }
    2403             : 
    2404           0 :     static void call_row_exists(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2405             :     {
    2406           0 :         if(!g_context)
    2407             :         {
    2408           0 :             throw snap_expr_exception_not_ready("row_exists() function not available, g_context is NULL");
    2409             :         }
    2410           0 :         if(sub_results.size() != 2)
    2411             :         {
    2412           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call row_exists() expected exactly 2");
    2413             :         }
    2414           0 :         QString const table_name(sub_results[0].get_string("row_exists(1)"));
    2415           0 :         QString const row_name(sub_results[1].get_string("row_exists(2)"));
    2416           0 :         libdbproxy::value value;
    2417           0 :         value.setBoolValue(g_context->getTable(table_name)->exists(row_name));
    2418           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    2419           0 :     }
    2420             : 
    2421           0 :     static void call_segment(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2422             :     {
    2423           0 :         if(sub_results.size() != 3)
    2424             :         {
    2425           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call segment() expected exactly 3");
    2426             :         }
    2427           0 :         QString const str(sub_results[0].get_string("segment(1)"));
    2428           0 :         QString const sep(sub_results[1].get_string("segment(2)"));
    2429           0 :         int64_t const idx(sub_results[2].get_integer("segment(3)"));
    2430           0 :         snap_string_list list(str.split(sep));
    2431           0 :         if(idx >= 0 && idx < list.size())
    2432             :         {
    2433           0 :             result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, list[idx]);
    2434             :         }
    2435             :         else
    2436             :         {
    2437           0 :             result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, QString(""));
    2438             :         }
    2439           0 :     }
    2440             : 
    2441           0 :     static void call_string(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2442             :     {
    2443           0 :         if(sub_results.size() != 1)
    2444             :         {
    2445           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call string() expected exactly 1");
    2446             :         }
    2447           0 :         QString str;
    2448           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2449           0 :         switch(sub_results[0].get_type())
    2450             :         {
    2451           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2452             :             //str = ""; -- an empty string is the default
    2453           0 :             break;
    2454             : 
    2455           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2456           0 :             str = v.safeBoolValue() ? "true" : "false";
    2457           0 :             break;
    2458             : 
    2459           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2460           0 :             str = QString("%1").arg(static_cast<int>(v.safeSignedCharValue()));
    2461           0 :             break;
    2462             : 
    2463           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2464           0 :             str = QString("%1").arg(static_cast<int>(v.safeUnsignedCharValue()));
    2465           0 :             break;
    2466             : 
    2467           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2468           0 :             str = QString("%1").arg(v.safeInt16Value());
    2469           0 :             break;
    2470             : 
    2471           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2472           0 :             str = QString("%1").arg(v.safeUInt16Value());
    2473           0 :             break;
    2474             : 
    2475           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2476           0 :             str = QString("%1").arg(v.safeInt32Value());
    2477           0 :             break;
    2478             : 
    2479           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2480           0 :             str = QString("%1").arg(v.safeUInt32Value());
    2481           0 :             break;
    2482             : 
    2483           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2484           0 :             str = QString("%1").arg(v.safeInt64Value());
    2485           0 :             break;
    2486             : 
    2487           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2488           0 :             str = QString("%1").arg(v.safeUInt64Value());
    2489           0 :             break;
    2490             : 
    2491           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2492           0 :             str = QString("%1").arg(v.safeFloatValue());
    2493           0 :             break;
    2494             : 
    2495           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2496           0 :             str = QString("%1").arg(v.safeDoubleValue());
    2497           0 :             break;
    2498             : 
    2499           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2500           0 :             str = v.stringValue();
    2501           0 :             break;
    2502             : 
    2503           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2504           0 :             str = v.stringValue();
    2505           0 :             break;
    2506             : 
    2507             :         }
    2508           0 :         libdbproxy::value value;
    2509           0 :         value.setStringValue(str);
    2510           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    2511           0 :     }
    2512             : 
    2513           0 :     static void call_strlen(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2514             :     {
    2515           0 :         if(sub_results.size() != 1)
    2516             :         {
    2517           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call strlen() expected exactly 1");
    2518             :         }
    2519           0 :         QString const str(sub_results[0].get_string("strlen(1)"));
    2520           0 :         libdbproxy::value value;
    2521           0 :         value.setInt64Value(str.length());
    2522           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64, value);
    2523           0 :     }
    2524             : 
    2525           0 :     static void call_strmatch(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2526             :     {
    2527           0 :         int const size(sub_results.size());
    2528           0 :         if(size < 2 || size > 3)
    2529             :         {
    2530           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call strmatch() expected 2 or 3");
    2531             :         }
    2532           0 :         QString const pattern(sub_results[0].get_string("submatch(1)"));
    2533           0 :         QString const str(sub_results[1].get_string("submatch(2)"));
    2534           0 :         QString flags;
    2535           0 :         if(size == 3)
    2536             :         {
    2537           0 :             flags = sub_results[2].get_string("submatch(3)");
    2538             :         }
    2539           0 :         Qt::CaseSensitivity cs(Qt::CaseSensitive);
    2540           0 :         if(flags.contains("i"))
    2541             :         {
    2542           0 :             cs = Qt::CaseInsensitive;
    2543             :         }
    2544           0 :         QRegExp re(pattern, cs, QRegExp::RegExp2);
    2545           0 :         libdbproxy::value value;
    2546             : //SNAP_LOG_WARNING("exact match pattern: \"")(pattern)("\", str \"")(str)("\".");
    2547           0 :         value.setBoolValue(re.exactMatch(str));
    2548           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    2549           0 :     }
    2550             : 
    2551           0 :     static void call_substr(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2552             :     {
    2553           0 :         int const size(sub_results.size());
    2554           0 :         if(size < 2 || size > 3)
    2555             :         {
    2556           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call substr() expected 2 or 3");
    2557             :         }
    2558           0 :         QString const str(sub_results[0].get_string("substr(1)"));
    2559           0 :         int const start(static_cast<int>(sub_results[1].get_integer("substr(2)")));
    2560           0 :         libdbproxy::value value;
    2561           0 :         if(size == 3)
    2562             :         {
    2563           0 :             int const end(static_cast<int>(sub_results[2].get_integer("substr(3)")));
    2564           0 :             value.setStringValue(str.mid(start, end));
    2565             :         }
    2566             :         else
    2567             :         {
    2568           0 :             value.setStringValue(str.mid(start));
    2569             :         }
    2570           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    2571           0 :     }
    2572             : 
    2573           0 :     static void call_table_exists(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2574             :     {
    2575           0 :         if(!g_context)
    2576             :         {
    2577           0 :             throw snap_expr_exception_not_ready("table_exists() function not available, g_context is NULL");
    2578             :         }
    2579           0 :         if(sub_results.size() != 1)
    2580             :         {
    2581           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call table_exists() expected exactly 1");
    2582             :         }
    2583           0 :         QString const table_name(sub_results[0].get_string("table_exists(1)"));
    2584           0 :         libdbproxy::value value;
    2585           0 :         value.setBoolValue(g_context->findTable(table_name) != nullptr);
    2586           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    2587           0 :     }
    2588             : 
    2589           0 :     static void call_tolower(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2590             :     {
    2591           0 :         if(sub_results.size() != 1)
    2592             :         {
    2593           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call tolower() expected exactly 1");
    2594             :         }
    2595           0 :         QString const str(sub_results[0].get_string("tolower(1)"));
    2596           0 :         libdbproxy::value value;
    2597           0 :         value.setStringValue(str.toLower());
    2598           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    2599           0 :     }
    2600             : 
    2601           0 :     static void call_toupper(variable_t & result, variable_t::variable_vector_t const & sub_results)
    2602             :     {
    2603           0 :         if(sub_results.size() != 1)
    2604             :         {
    2605           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call toupper() expected exactly 1");
    2606             :         }
    2607           0 :         QString const str(sub_results[0].get_string("toupper(1)"));
    2608           0 :         libdbproxy::value value;
    2609           0 :         value.setStringValue(str.toUpper());
    2610           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    2611           0 :     }
    2612             : 
    2613           0 :     static void call_uint16(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2614             :     {
    2615           0 :         if(sub_results.size() != 1)
    2616             :         {
    2617           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call uint16() expected exactly 1");
    2618             :         }
    2619           0 :         uint16_t r(0);
    2620           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2621           0 :         switch(sub_results[0].get_type())
    2622             :         {
    2623           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2624             :             //r = 0; -- an "empty" number...
    2625           0 :             break;
    2626             : 
    2627           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2628           0 :             r = v.safeBoolValue() ? 1 : 0;
    2629           0 :             break;
    2630             : 
    2631           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2632           0 :             r = v.safeSignedCharValue();
    2633           0 :             break;
    2634             : 
    2635           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2636           0 :             r = v.safeUnsignedCharValue();
    2637           0 :             break;
    2638             : 
    2639           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2640           0 :             r = v.safeInt16Value();
    2641           0 :             break;
    2642             : 
    2643           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2644           0 :             r = v.safeUInt16Value();
    2645           0 :             break;
    2646             : 
    2647           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2648           0 :             r = static_cast<uint16_t>(v.safeInt32Value());
    2649           0 :             break;
    2650             : 
    2651           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2652           0 :             r = static_cast<uint16_t>(v.safeUInt32Value());
    2653           0 :             break;
    2654             : 
    2655           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2656           0 :             r = static_cast<uint16_t>(v.safeInt64Value());
    2657           0 :             break;
    2658             : 
    2659           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2660           0 :             r = static_cast<uint16_t>(v.safeUInt64Value());
    2661           0 :             break;
    2662             : 
    2663           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2664           0 :             r = static_cast<uint16_t>(v.safeFloatValue());
    2665           0 :             break;
    2666             : 
    2667           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2668           0 :             r = static_cast<uint16_t>(v.safeDoubleValue());
    2669           0 :             break;
    2670             : 
    2671           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2672           0 :             r = static_cast<uint16_t>(v.stringValue().toLongLong());
    2673           0 :             break;
    2674             : 
    2675           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2676           0 :             r = v.safeUInt16Value();
    2677           0 :             break;
    2678             : 
    2679             :         }
    2680           0 :         libdbproxy::value value;
    2681           0 :         value.setUInt16Value(r);
    2682           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16, value);
    2683           0 :     }
    2684             : 
    2685           0 :     static void call_uint32(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2686             :     {
    2687           0 :         if(sub_results.size() != 1)
    2688             :         {
    2689           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call uint32() expected exactly 1");
    2690             :         }
    2691           0 :         uint32_t r(0);
    2692           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2693           0 :         switch(sub_results[0].get_type())
    2694             :         {
    2695           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2696             :             //r = 0; -- an "empty" number...
    2697           0 :             break;
    2698             : 
    2699           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2700           0 :             r = v.safeBoolValue() ? 1 : 0;
    2701           0 :             break;
    2702             : 
    2703           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2704           0 :             r = v.safeSignedCharValue();
    2705           0 :             break;
    2706             : 
    2707           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2708           0 :             r = v.safeUnsignedCharValue();
    2709           0 :             break;
    2710             : 
    2711           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2712           0 :             r = v.safeInt16Value();
    2713           0 :             break;
    2714             : 
    2715           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2716           0 :             r = v.safeUInt16Value();
    2717           0 :             break;
    2718             : 
    2719           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2720           0 :             r = v.safeInt32Value();
    2721           0 :             break;
    2722             : 
    2723           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2724           0 :             r = v.safeUInt32Value();
    2725           0 :             break;
    2726             : 
    2727           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2728           0 :             r = static_cast<uint32_t>(v.safeInt64Value());
    2729           0 :             break;
    2730             : 
    2731           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2732           0 :             r = static_cast<uint32_t>(v.safeUInt64Value());
    2733           0 :             break;
    2734             : 
    2735           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2736           0 :             r = static_cast<uint32_t>(v.safeFloatValue());
    2737           0 :             break;
    2738             : 
    2739           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2740           0 :             r = static_cast<uint32_t>(v.safeDoubleValue());
    2741           0 :             break;
    2742             : 
    2743           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2744           0 :             r = static_cast<uint32_t>(v.stringValue().toLongLong());
    2745           0 :             break;
    2746             : 
    2747           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2748           0 :             r = v.safeUInt32Value();
    2749           0 :             break;
    2750             : 
    2751             :         }
    2752           0 :         libdbproxy::value value;
    2753           0 :         value.setUInt32Value(r);
    2754           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32, value);
    2755           0 :     }
    2756             : 
    2757           0 :     static void call_uint64(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2758             :     {
    2759           0 :         if(sub_results.size() != 1)
    2760             :         {
    2761           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call uint64() expected exactly 1");
    2762             :         }
    2763           0 :         uint64_t r(0);
    2764           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2765           0 :         switch(sub_results[0].get_type())
    2766             :         {
    2767           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2768             :             //r = 0; -- an "empty" number...
    2769           0 :             break;
    2770             : 
    2771           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2772           0 :             r = v.safeBoolValue() ? 1 : 0;
    2773           0 :             break;
    2774             : 
    2775           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2776           0 :             r = v.safeSignedCharValue();
    2777           0 :             break;
    2778             : 
    2779           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2780           0 :             r = v.safeUnsignedCharValue();
    2781           0 :             break;
    2782             : 
    2783           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2784           0 :             r = v.safeInt16Value();
    2785           0 :             break;
    2786             : 
    2787           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2788           0 :             r = v.safeUInt16Value();
    2789           0 :             break;
    2790             : 
    2791           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2792           0 :             r = v.safeInt32Value();
    2793           0 :             break;
    2794             : 
    2795           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2796           0 :             r = v.safeUInt32Value();
    2797           0 :             break;
    2798             : 
    2799           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2800           0 :             r = v.safeInt64Value();
    2801           0 :             break;
    2802             : 
    2803           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2804           0 :             r = v.safeUInt64Value();
    2805           0 :             break;
    2806             : 
    2807           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2808           0 :             r = static_cast<int64_t>(v.safeFloatValue());
    2809           0 :             break;
    2810             : 
    2811           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2812           0 :             r = static_cast<int64_t>(v.safeDoubleValue());
    2813           0 :             break;
    2814             : 
    2815           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2816           0 :             r = v.stringValue().toLongLong();
    2817           0 :             break;
    2818             : 
    2819           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2820           0 :             r = v.safeInt64Value();
    2821           0 :             break;
    2822             : 
    2823             :         }
    2824           0 :         libdbproxy::value value;
    2825           0 :         value.setUInt64Value(r);
    2826           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64, value);
    2827           0 :     }
    2828             : 
    2829           0 :     static void call_uint8(variable_t& result, variable_t::variable_vector_t const& sub_results)
    2830             :     {
    2831           0 :         if(sub_results.size() != 1)
    2832             :         {
    2833           0 :             throw snap_expr_exception_invalid_number_of_parameters("invalid number of parameters to call uint8() expected exactly 1");
    2834             :         }
    2835           0 :         uint8_t r(0);
    2836           0 :         libdbproxy::value const & v(sub_results[0].get_value());
    2837           0 :         switch(sub_results[0].get_type())
    2838             :         {
    2839           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_NULL:
    2840             :             //r = 0; -- an "empty" number...
    2841           0 :             break;
    2842             : 
    2843           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2844           0 :             r = v.safeBoolValue() ? 1 : 0;
    2845           0 :             break;
    2846             : 
    2847           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2848           0 :             r = v.safeSignedCharValue();
    2849           0 :             break;
    2850             : 
    2851           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2852           0 :             r = static_cast<uint8_t>(v.safeUnsignedCharValue());
    2853           0 :             break;
    2854             : 
    2855           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2856           0 :             r = static_cast<uint8_t>(v.safeInt16Value());
    2857           0 :             break;
    2858             : 
    2859           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2860           0 :             r = static_cast<uint8_t>(v.safeUInt16Value());
    2861           0 :             break;
    2862             : 
    2863           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2864           0 :             r = static_cast<uint8_t>(v.safeInt32Value());
    2865           0 :             break;
    2866             : 
    2867           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2868           0 :             r = static_cast<uint8_t>(v.safeUInt32Value());
    2869           0 :             break;
    2870             : 
    2871           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2872           0 :             r = static_cast<uint8_t>(v.safeInt64Value());
    2873           0 :             break;
    2874             : 
    2875           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2876           0 :             r = static_cast<uint8_t>(v.safeUInt64Value());
    2877           0 :             break;
    2878             : 
    2879           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    2880           0 :             r = static_cast<uint8_t>(v.safeFloatValue());
    2881           0 :             break;
    2882             : 
    2883           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2884           0 :             r = static_cast<uint8_t>(v.safeDoubleValue());
    2885           0 :             break;
    2886             : 
    2887           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2888           0 :             r = static_cast<uint8_t>(v.stringValue().toLongLong());
    2889           0 :             break;
    2890             : 
    2891           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    2892           0 :             r = v.safeUnsignedCharValue();
    2893           0 :             break;
    2894             : 
    2895             :         }
    2896           0 :         libdbproxy::value value;
    2897           0 :         value.setUnsignedCharValue(r);
    2898           0 :         result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8, value);
    2899           0 :     }
    2900             : 
    2901           0 :     void call_function(variable_t & result, variable_t::variable_vector_t const & sub_results, functions_t & functions)
    2902             :     {
    2903           0 :         functions_t::function_call_t f(functions.get_function(f_name));
    2904           0 :         if(f == nullptr)
    2905             :         {
    2906             :             // if we already initialized the internal functions,
    2907             :             // there is nothing more to do here
    2908           0 :             if(!functions.get_has_internal_functions())
    2909             :             {
    2910             :                 // avoid recursivity (you never know!)
    2911           0 :                 functions.set_has_internal_functions();
    2912           0 :                 functions.add_functions(internal_functions);
    2913             :                 // also give a chance to plugins and other listeners to
    2914             :                 // register functions
    2915           0 :                 server::instance()->add_snap_expr_functions(functions);
    2916           0 :                 f = functions.get_function(f_name);
    2917             :             }
    2918           0 :             if(f == nullptr)
    2919             :             {
    2920           0 :                 throw snap_expr_exception_unknown_function(QString("unknown function \"%1\" in list execution environment").arg(f_name));
    2921             :             }
    2922             :         }
    2923           0 :         f(result, sub_results);
    2924           0 :     }
    2925             : 
    2926           0 :     bool get_variable_value(variable_t const & var, int64_t & integer, double & floating_point, QString & string, bool & signed_integer, bool & is_floating_point, bool & is_string_type)
    2927             :     {
    2928           0 :         switch(var.get_type())
    2929             :         {
    2930           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    2931           0 :             integer = static_cast<int64_t>(var.get_value().safeBoolValue() != 0);
    2932           0 :             break;
    2933             : 
    2934           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    2935           0 :             integer = static_cast<int64_t>(var.get_value().safeSignedCharValue());
    2936           0 :             break;
    2937             : 
    2938           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    2939           0 :             signed_integer = false;
    2940           0 :             integer = static_cast<int64_t>(var.get_value().safeUnsignedCharValue());
    2941           0 :             break;
    2942             : 
    2943           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    2944           0 :             integer = static_cast<int64_t>(var.get_value().safeInt16Value());
    2945           0 :             break;
    2946             : 
    2947           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    2948           0 :             signed_integer = false;
    2949           0 :             integer = static_cast<int64_t>(var.get_value().safeUInt16Value());
    2950           0 :             break;
    2951             : 
    2952           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    2953           0 :             integer = static_cast<int64_t>(var.get_value().safeInt32Value());
    2954           0 :             break;
    2955             : 
    2956           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    2957           0 :             signed_integer = false;
    2958           0 :             integer = static_cast<int64_t>(var.get_value().safeUInt32Value());
    2959           0 :             break;
    2960             : 
    2961           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    2962           0 :             integer = static_cast<int64_t>(var.get_value().safeInt64Value());
    2963           0 :             break;
    2964             : 
    2965           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    2966           0 :             signed_integer = false;
    2967           0 :             integer = static_cast<int64_t>(var.get_value().safeUInt64Value());
    2968           0 :             break;
    2969             : 
    2970           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    2971           0 :             is_floating_point = true;
    2972           0 :             floating_point = var.get_value().safeDoubleValue();
    2973           0 :             break;
    2974             : 
    2975           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    2976           0 :             is_string_type = true;
    2977           0 :             string = var.get_value().stringValue();
    2978           0 :             break;
    2979             : 
    2980           0 :         default:
    2981           0 :             return false;
    2982             : 
    2983             :         }
    2984             : 
    2985           0 :         return true;
    2986             :     }
    2987             : 
    2988             :     template<typename F>
    2989           0 :     void binary_operation(char const * op, variable_t & result, variable_t::variable_vector_t const & sub_results)
    2990             :     {
    2991           0 :         verify_binary(sub_results);
    2992             : 
    2993           0 :         variable_t::variable_type_t type(std::max(sub_results[0].get_type(), sub_results[1].get_type()));
    2994             : 
    2995           0 :         bool lstring_type(false), rstring_type(false);
    2996           0 :         bool lfloating_point(false), rfloating_point(false);
    2997           0 :         bool lsigned_value(true), rsigned_value(true);
    2998           0 :         QString ls, rs;
    2999           0 :         double lf(0.0), rf(0.0);
    3000           0 :         int64_t li(0), ri(0);
    3001             : 
    3002           0 :         bool valid(get_variable_value(sub_results[0], li, lf, ls, lsigned_value, lfloating_point, lstring_type));
    3003           0 :         valid = valid && get_variable_value(sub_results[1], ri, rf, rs, rsigned_value, rfloating_point, rstring_type);
    3004             : 
    3005           0 :         if(valid)
    3006             :         {
    3007           0 :             libdbproxy::value value;
    3008           0 :             switch(type)
    3009             :             {
    3010           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    3011           0 :                 value.setBoolValue(F::integers(li, ri));
    3012           0 :                 result.set_value(type, value);
    3013           0 :                 return;
    3014             : 
    3015           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    3016           0 :                 value.setSignedCharValue(static_cast<signed char>(F::integers(li, ri)));
    3017           0 :                 result.set_value(type, value);
    3018           0 :                 return;
    3019             : 
    3020           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    3021           0 :                 value.setUnsignedCharValue(static_cast<unsigned char>(F::integers(li, ri)));
    3022           0 :                 result.set_value(type, value);
    3023           0 :                 return;
    3024             : 
    3025           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    3026           0 :                 value.setInt16Value(static_cast<int16_t>(F::integers(li, ri)));
    3027           0 :                 result.set_value(type, value);
    3028           0 :                 return;
    3029             : 
    3030           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    3031           0 :                 value.setUInt16Value(static_cast<uint16_t>(F::integers(li, ri)));
    3032           0 :                 result.set_value(type, value);
    3033           0 :                 return;
    3034             : 
    3035           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    3036           0 :                 value.setInt32Value(static_cast<int32_t>(F::integers(li, ri)));
    3037           0 :                 result.set_value(type, value);
    3038           0 :                 return;
    3039             : 
    3040           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    3041           0 :                 value.setUInt32Value(static_cast<uint32_t>(F::integers(li, ri)));
    3042           0 :                 result.set_value(type, value);
    3043           0 :                 return;
    3044             : 
    3045           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    3046           0 :                 value.setInt64Value(F::integers(li, ri));
    3047           0 :                 result.set_value(type, value);
    3048           0 :                 return;
    3049             : 
    3050           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    3051           0 :                 value.setUInt64Value(F::integers(li, ri));
    3052           0 :                 result.set_value(type, value);
    3053           0 :                 return;
    3054             : 
    3055           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    3056             :                 if(has_function<F>::has_floating_points)
    3057             :                 {
    3058           0 :                     if(!lfloating_point)
    3059             :                     {
    3060           0 :                         lf = static_cast<double>(lsigned_value ? li : static_cast<uint64_t>(li));
    3061             :                     }
    3062           0 :                     if(!rfloating_point)
    3063             :                     {
    3064           0 :                         rf = static_cast<double>(rsigned_value ? ri : static_cast<uint64_t>(ri));
    3065             :                     }
    3066           0 :                     do_float<F>(result, lf, rf);
    3067           0 :                     return;
    3068             :                 }
    3069           0 :                 break;
    3070             : 
    3071           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    3072             :                 if(has_function<F>::has_floating_points)
    3073             :                 {
    3074           0 :                     if(!lfloating_point)
    3075             :                     {
    3076           0 :                         lf = static_cast<double>(lsigned_value ? li : static_cast<uint64_t>(li));
    3077             :                     }
    3078           0 :                     if(!rfloating_point)
    3079             :                     {
    3080           0 :                         rf = static_cast<double>(rsigned_value ? ri : static_cast<uint64_t>(ri));
    3081             :                     }
    3082           0 :                     do_double<F>(result, lf, rf);
    3083           0 :                     return;
    3084             :                 }
    3085           0 :                 break;
    3086             : 
    3087           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    3088             :                 if(has_function<F>::has_strings)
    3089             :                 {
    3090           0 :                     if(!lstring_type)
    3091             :                     {
    3092           0 :                         ls = QString("%1").arg(lfloating_point ? lf : static_cast<double>(lsigned_value ? li : static_cast<uint64_t>(li)));
    3093             :                     }
    3094           0 :                     if(!rstring_type)
    3095             :                     {
    3096           0 :                         rs = QString("%1").arg(rfloating_point ? rf : static_cast<double>(rsigned_value ? ri : static_cast<uint64_t>(ri)));
    3097             :                     }
    3098             :                     // do "string" + "string"
    3099           0 :                     do_strings<F>(result, ls, rs);
    3100           0 :                     return;
    3101             :                 }
    3102           0 :                 else if(has_function<F>::has_string_integer
    3103           0 :                      && variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING == sub_results[0].get_type()
    3104           0 :                      && !rfloating_point && !rstring_type)
    3105             :                 {
    3106             :                     // very special case to support: "string" * 123
    3107           0 :                     do_string_integer<F>(result, ls, ri);
    3108           0 :                     return;
    3109             :                 }
    3110           0 :                 break;
    3111             : 
    3112           0 :             default:
    3113             :                 // anything else is invalid at this point
    3114           0 :                 break;
    3115             : 
    3116             :             }
    3117             :         }
    3118             : 
    3119             :         throw snap_logic_exception(QString("expr_node::binary_operation(\"%3\") called with incompatible sub_result types: %1 x %2")
    3120           0 :                             .arg(static_cast<int>(sub_results[0].get_type()))
    3121           0 :                             .arg(static_cast<int>(sub_results[1].get_type()))
    3122           0 :                             .arg(op));
    3123             :     }
    3124             : 
    3125             :     template<typename F>
    3126           0 :     void bool_binary_operation(char const * op, variable_t & result, variable_t::variable_vector_t const & sub_results)
    3127             :     {
    3128           0 :         verify_binary(sub_results);
    3129             : 
    3130           0 :         variable_t::variable_type_t type(std::max(sub_results[0].get_type(), sub_results[1].get_type()));
    3131             : 
    3132           0 :         bool lstring_type(false), rstring_type(false);
    3133           0 :         bool lfloating_point(false), rfloating_point(false);
    3134           0 :         bool lsigned_value(true), rsigned_value(true);
    3135           0 :         QString ls, rs;
    3136           0 :         double lf(0.0), rf(0.0);
    3137           0 :         int64_t li(0), ri(0);
    3138             : 
    3139           0 :         bool valid(get_variable_value(sub_results[0], li, lf, ls, lsigned_value, lfloating_point, lstring_type));
    3140           0 :         valid = valid && get_variable_value(sub_results[1], ri, rf, rs, rsigned_value, rfloating_point, rstring_type);
    3141             : 
    3142           0 :         if(valid)
    3143             :         {
    3144           0 :             libdbproxy::value value;
    3145           0 :             switch(type)
    3146             :             {
    3147           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    3148           0 :                 value.setBoolValue(F::integers(li, ri));
    3149           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3150           0 :                 return;
    3151             : 
    3152           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    3153           0 :                 value.setBoolValue(F::integers(li, ri));
    3154           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3155           0 :                 return;
    3156             : 
    3157           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    3158           0 :                 value.setBoolValue(F::integers(li, ri));
    3159           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3160           0 :                 return;
    3161             : 
    3162           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    3163           0 :                 value.setBoolValue(F::integers(li, ri));
    3164           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3165           0 :                 return;
    3166             : 
    3167           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    3168           0 :                 value.setBoolValue(F::integers(li, ri));
    3169           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3170           0 :                 return;
    3171             : 
    3172           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    3173           0 :                 value.setBoolValue(F::integers(li, ri));
    3174           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3175           0 :                 return;
    3176             : 
    3177           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    3178           0 :                 value.setBoolValue(F::integers(li, ri));
    3179           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3180           0 :                 return;
    3181             : 
    3182           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    3183           0 :                 value.setBoolValue(F::integers(li, ri));
    3184           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3185           0 :                 return;
    3186             : 
    3187           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    3188           0 :                 value.setBoolValue(F::integers(li, ri));
    3189           0 :                 result.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3190           0 :                 return;
    3191             : 
    3192           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    3193             :                 if(has_function<F>::has_bool_floating_points)
    3194             :                 {
    3195           0 :                     if(!lfloating_point)
    3196             :                     {
    3197           0 :                         lf = static_cast<double>(lsigned_value ? li : static_cast<uint64_t>(li));
    3198             :                     }
    3199           0 :                     if(!rfloating_point)
    3200             :                     {
    3201           0 :                         rf = static_cast<double>(rsigned_value ? ri : static_cast<uint64_t>(ri));
    3202             :                     }
    3203           0 :                     do_float_to_bool<F>(result, lf, rf);
    3204           0 :                     return;
    3205             :                 }
    3206           0 :                 break;
    3207             : 
    3208           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    3209             :                 if(has_function<F>::has_bool_floating_points)
    3210             :                 {
    3211           0 :                     if(!lfloating_point)
    3212             :                     {
    3213           0 :                         lf = static_cast<double>(lsigned_value ? li : static_cast<uint64_t>(li));
    3214             :                     }
    3215           0 :                     if(!rfloating_point)
    3216             :                     {
    3217           0 :                         rf = static_cast<double>(rsigned_value ? ri : static_cast<uint64_t>(ri));
    3218             :                     }
    3219           0 :                     do_double_to_bool<F>(result, lf, rf);
    3220           0 :                     return;
    3221             :                 }
    3222           0 :                 break;
    3223             : 
    3224           0 :             case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    3225             :                 if(has_function<F>::has_bool_strings)
    3226             :                 {
    3227           0 :                     if(!lstring_type)
    3228             :                     {
    3229           0 :                         ls = QString("%1").arg(lfloating_point ? lf : static_cast<double>(lsigned_value ? li : static_cast<uint64_t>(li)));
    3230             :                     }
    3231           0 :                     if(!rstring_type)
    3232             :                     {
    3233           0 :                         rs = QString("%1").arg(rfloating_point ? rf : static_cast<double>(rsigned_value ? ri : static_cast<uint64_t>(ri)));
    3234             :                     }
    3235             :                     // do "string" + "string"
    3236           0 :                     do_strings_to_bool<F>(result, ls, rs);
    3237           0 :                     return;
    3238             :                 }
    3239             :                 else if(has_function<F>::has_bool_string_integer
    3240             :                      && variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING == sub_results[0].get_type()
    3241             :                      && !rfloating_point && !rstring_type)
    3242             :                 {
    3243             :                     // very special case to support: "string" * 123
    3244             :                     do_string_integer_to_bool<F>(result, ls, ri);
    3245             :                     return;
    3246             :                 }
    3247           0 :                 break;
    3248             : 
    3249           0 :             default:
    3250             :                 // anything else is invalid at this point
    3251           0 :                 break;
    3252             : 
    3253             :             }
    3254             :         }
    3255             : 
    3256             :         throw snap_logic_exception(QString("expr_node::binary_operation(\"%3\") called with incompatible sub_result types: %1 x %2")
    3257           0 :                             .arg(static_cast<int>(sub_results[0].get_type()))
    3258           0 :                             .arg(static_cast<int>(sub_results[1].get_type()))
    3259           0 :                             .arg(op));
    3260             :     }
    3261             : 
    3262           0 :     void conditional(variable_t& result, variable_t::variable_map_t& variables, functions_t& functions)
    3263             :     {
    3264             :         // IMPORTANT NOTE
    3265             :         //   we compute the results directly in conditional() to
    3266             :         //   avoid calculating f_children[1] and f_children[2]
    3267             : #ifdef DEBUG
    3268           0 :         if(f_children.size() != 3)
    3269             :         {
    3270           0 :             throw snap_logic_exception("expr_node::conditional() found a conditional operator with a number of results which is not 3");
    3271             :         }
    3272             : #endif
    3273             :         // Note:
    3274             :         // we put the result of f_children[0] in 'result' even though this
    3275             :         // is not the result of the function, but it shouldn't matter, we'll
    3276             :         // either throw or compute f_children[1] or f_children[2] as required
    3277           0 :         f_children[0]->execute(result, variables, functions);
    3278           0 :         bool r(false);
    3279           0 :         switch(result.get_type())
    3280             :         {
    3281           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL:
    3282             :             // using the following to force the value ot 0 or 1
    3283           0 :             r = result.get_value().safeSignedCharValue() != 0;
    3284           0 :             break;
    3285             : 
    3286           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT8:
    3287           0 :             r = result.get_value().safeSignedCharValue() != 0;
    3288           0 :             break;
    3289             : 
    3290           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT8:
    3291           0 :             r = result.get_value().safeUnsignedCharValue() != 0;
    3292           0 :             break;
    3293             : 
    3294           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT16:
    3295           0 :             r = result.get_value().safeInt16Value() != 0;
    3296           0 :             break;
    3297             : 
    3298           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT16:
    3299           0 :             r = result.get_value().safeUInt16Value() != 0;
    3300           0 :             break;
    3301             : 
    3302           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT32:
    3303           0 :             r = result.get_value().safeInt32Value() != 0;
    3304           0 :             break;
    3305             : 
    3306           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT32:
    3307           0 :             r = result.get_value().safeUInt32Value() != 0;
    3308           0 :             break;
    3309             : 
    3310           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64:
    3311           0 :             r = result.get_value().safeInt64Value() != 0;
    3312           0 :             break;
    3313             : 
    3314           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_UINT64:
    3315           0 :             r = result.get_value().safeUInt64Value() != 0;
    3316           0 :             break;
    3317             : 
    3318           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_FLOAT:
    3319             : #pragma GCC diagnostic push
    3320             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    3321           0 :             r = result.get_value().safeFloatValue() != 0.0f;
    3322             : #pragma GCC diagnostic pop
    3323           0 :             break;
    3324             : 
    3325           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE:
    3326             : #pragma GCC diagnostic push
    3327             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    3328           0 :             r = result.get_value().safeDoubleValue() != 0.0;
    3329             : #pragma GCC diagnostic pop
    3330           0 :             break;
    3331             : 
    3332           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING:
    3333           0 :             r = result.get_value().stringValue().length() != 0;
    3334           0 :             break;
    3335             : 
    3336           0 :         case variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BINARY:
    3337           0 :             r = result.get_value().binaryValue().size() != 0;
    3338           0 :             break;
    3339             : 
    3340           0 :         default:
    3341           0 :             throw snap_logic_exception(QString("expr_node::logical_not() called with an incompatible sub_result type: %1")
    3342           0 :                         .arg(static_cast<int>(result.get_type())));
    3343             : 
    3344             :         }
    3345           0 :         if(r)
    3346             :         {
    3347           0 :             f_children[1]->execute(result, variables, functions);
    3348             :         }
    3349             :         else
    3350             :         {
    3351           0 :             f_children[2]->execute(result, variables, functions);
    3352             :         }
    3353           0 :     }
    3354             : 
    3355           0 :     void assignment(variable_t & result, variable_t::variable_vector_t const & sub_results, variable_t::variable_map_t & variables)
    3356             :     {
    3357             : #ifdef DEBUG
    3358           0 :         if(sub_results.size() != 1)
    3359             :         {
    3360           0 :             throw snap_logic_exception("expr_node::execute() found an assignment operator with a number of results which is not 1");
    3361             :         }
    3362             : #endif
    3363           0 :         variables[f_name] = sub_results[0];
    3364             :         // result is a copy of the variable contents
    3365           0 :         result = variables[f_name];
    3366           0 :     }
    3367             : 
    3368           0 :     void load_variable(variable_t & result, variable_t::variable_map_t & variables)
    3369             :     {
    3370           0 :         if(variables.contains(f_name))
    3371             :         {
    3372           0 :             result = variables[f_name];
    3373             :         }
    3374           0 :     }
    3375             : 
    3376             : 
    3377             :     QString toString()
    3378             :     {
    3379             :         return internal_toString("");
    3380             :     }
    3381             : 
    3382             : 
    3383             : private:
    3384             :     QString internal_toString(QString indent)
    3385             :     {
    3386             :         // start with the type
    3387             :         QString result(QString("%1%2").arg(indent).arg(type_names[static_cast<int>(static_cast<node_type_t>(f_type))]));
    3388             : 
    3389             :         // add type specific data
    3390             :         switch(f_type)
    3391             :         {
    3392             :         case node_type_t::NODE_TYPE_UNKNOWN:
    3393             :         case node_type_t::NODE_TYPE_LOADING:
    3394             :         case node_type_t::NODE_TYPE_OPERATION_LIST:
    3395             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_NOT:
    3396             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_NOT:
    3397             :         case node_type_t::NODE_TYPE_OPERATION_NEGATE:
    3398             :         case node_type_t::NODE_TYPE_OPERATION_MULTIPLY:
    3399             :         case node_type_t::NODE_TYPE_OPERATION_DIVIDE:
    3400             :         case node_type_t::NODE_TYPE_OPERATION_MODULO:
    3401             :         case node_type_t::NODE_TYPE_OPERATION_ADD:
    3402             :         case node_type_t::NODE_TYPE_OPERATION_SUBTRACT:
    3403             :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_LEFT:
    3404             :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_RIGHT:
    3405             :         case node_type_t::NODE_TYPE_OPERATION_LESS:
    3406             :         case node_type_t::NODE_TYPE_OPERATION_LESS_OR_EQUAL:
    3407             :         case node_type_t::NODE_TYPE_OPERATION_GREATER:
    3408             :         case node_type_t::NODE_TYPE_OPERATION_GREATER_OR_EQUAL:
    3409             :         case node_type_t::NODE_TYPE_OPERATION_MINIMUM:
    3410             :         case node_type_t::NODE_TYPE_OPERATION_MAXIMUM:
    3411             :         case node_type_t::NODE_TYPE_OPERATION_EQUAL:
    3412             :         case node_type_t::NODE_TYPE_OPERATION_NOT_EQUAL:
    3413             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_AND:
    3414             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_XOR:
    3415             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_OR:
    3416             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_AND:
    3417             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_XOR:
    3418             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_OR:
    3419             :         case node_type_t::NODE_TYPE_OPERATION_CONDITIONAL:
    3420             :             break;
    3421             : 
    3422             :         case node_type_t::NODE_TYPE_OPERATION_FUNCTION:
    3423             :             result += QString(" (function name: %1)").arg(f_name);
    3424             :             break;
    3425             : 
    3426             :         case node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT:
    3427             :         case node_type_t::NODE_TYPE_OPERATION_VARIABLE:
    3428             :             result += QString(" (variable name: %1)").arg(f_name);
    3429             :             break;
    3430             : 
    3431             :         case node_type_t::NODE_TYPE_LITERAL_BOOLEAN:
    3432             :             result += QString(" (%1)").arg(f_variable.get_value().safeBoolValue() ? "true" : "false");
    3433             :             break;
    3434             : 
    3435             :         case node_type_t::NODE_TYPE_LITERAL_INTEGER:
    3436             :             result += QString(" (%1)").arg(f_variable.get_value().safeInt64Value());
    3437             :             break;
    3438             : 
    3439             :         case node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT:
    3440             :             result += QString(" (%1)").arg(f_variable.get_value().safeDoubleValue());
    3441             :             break;
    3442             : 
    3443             :         case node_type_t::NODE_TYPE_LITERAL_STRING:
    3444             :             result += QString(" (%1)").arg(f_variable.get_value().stringValue());
    3445             :             break;
    3446             : 
    3447             :         case node_type_t::NODE_TYPE_VARIABLE:
    3448             :             result += "a program cannot include variables";
    3449             :             break;
    3450             : 
    3451             :         }
    3452             :         result += "\n";
    3453             : 
    3454             :         // add the children
    3455             :         int const max_children(f_children.size());
    3456             :         for(int i(0); i < max_children; ++i)
    3457             :         {
    3458             :             result += f_children[i]->internal_toString(indent + "  ");
    3459             :         }
    3460             : 
    3461             :         return result;
    3462             :     }
    3463             : 
    3464           0 :     void verify_variable() const
    3465             :     {
    3466             : #ifdef DEBUG
    3467           0 :         switch(f_type)
    3468             :         {
    3469           0 :         case node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT:
    3470             :         case node_type_t::NODE_TYPE_LITERAL_BOOLEAN:
    3471             :         case node_type_t::NODE_TYPE_LITERAL_INTEGER:
    3472             :         case node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT:
    3473             :         case node_type_t::NODE_TYPE_LITERAL_STRING:
    3474             :         case node_type_t::NODE_TYPE_OPERATION_VARIABLE:
    3475           0 :             break;
    3476             : 
    3477           0 :         default:
    3478           0 :             throw snap_logic_exception(QString("expr_node::[gs]et_name(\"...\") called on a node which does not support a name... (type: %1)").arg(static_cast<int>(static_cast<node_type_t>(f_type))));
    3479             : 
    3480             :         }
    3481             : #endif
    3482           0 :     }
    3483             : 
    3484           2 :     void verify_children(int idx, bool size_is_legal = false) const
    3485             :     {
    3486             : #ifdef DEBUG
    3487           2 :         switch(f_type)
    3488             :         {
    3489           2 :         case node_type_t::NODE_TYPE_LOADING: // this happens while loading; the type is set afterward because of the recursion mechanism...
    3490             :         case node_type_t::NODE_TYPE_OPERATION_LIST:
    3491             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_NOT:
    3492             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_NOT:
    3493             :         case node_type_t::NODE_TYPE_OPERATION_NEGATE:
    3494             :         case node_type_t::NODE_TYPE_OPERATION_FUNCTION:
    3495             :         case node_type_t::NODE_TYPE_OPERATION_MULTIPLY:
    3496             :         case node_type_t::NODE_TYPE_OPERATION_DIVIDE:
    3497             :         case node_type_t::NODE_TYPE_OPERATION_MODULO:
    3498             :         case node_type_t::NODE_TYPE_OPERATION_ADD:
    3499             :         case node_type_t::NODE_TYPE_OPERATION_SUBTRACT:
    3500             :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_LEFT:
    3501             :         case node_type_t::NODE_TYPE_OPERATION_SHIFT_RIGHT:
    3502             :         case node_type_t::NODE_TYPE_OPERATION_LESS:
    3503             :         case node_type_t::NODE_TYPE_OPERATION_LESS_OR_EQUAL:
    3504             :         case node_type_t::NODE_TYPE_OPERATION_GREATER:
    3505             :         case node_type_t::NODE_TYPE_OPERATION_GREATER_OR_EQUAL:
    3506             :         case node_type_t::NODE_TYPE_OPERATION_MINIMUM:
    3507             :         case node_type_t::NODE_TYPE_OPERATION_MAXIMUM:
    3508             :         case node_type_t::NODE_TYPE_OPERATION_EQUAL:
    3509             :         case node_type_t::NODE_TYPE_OPERATION_NOT_EQUAL:
    3510             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_AND:
    3511             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_XOR:
    3512             :         case node_type_t::NODE_TYPE_OPERATION_BITWISE_OR:
    3513             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_AND:
    3514             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_XOR:
    3515             :         case node_type_t::NODE_TYPE_OPERATION_LOGICAL_OR:
    3516             :         case node_type_t::NODE_TYPE_OPERATION_CONDITIONAL:
    3517             :         case node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT:
    3518           2 :             break;
    3519             : 
    3520           0 :         default:
    3521           0 :             throw snap_logic_exception(QString("expr_node::add_child/children_size/get_child() called on a node which does not support children... (type: %1)")
    3522           0 :                     .arg(static_cast<int>(static_cast<node_type_t>(f_type))));
    3523             : 
    3524             :         }
    3525             : #endif
    3526             : #pragma GCC diagnostic push
    3527             : #pragma GCC diagnostic ignored "-Wstrict-overflow"
    3528           2 :         if(idx >= 0)
    3529             :         {
    3530             : #pragma GCC diagnostic pop
    3531           0 :             if(static_cast<uint32_t>(idx) >= static_cast<uint32_t>(f_children.size()))
    3532             :             {
    3533           0 :                 if(static_cast<uint32_t>(idx) != static_cast<uint32_t>(f_children.size())
    3534           0 :                 || !size_is_legal)
    3535             :                 {
    3536           0 :                     throw snap_logic_exception(QString("expr_node::get_child(%1) called with an out of bounds index (max: %2)")
    3537           0 :                                             .arg(idx).arg(f_children.size()));
    3538             :                 }
    3539             :             }
    3540             :         }
    3541           2 :     }
    3542             : 
    3543           0 :     void verify_unary(variable_t::variable_vector_t const& sub_results)
    3544             :     {
    3545             : #ifdef DEBUG
    3546           0 :         if(sub_results.size() != 1)
    3547             :         {
    3548           0 :             throw snap_logic_exception(QString("expr_node::execute() found an unary operator (%1) with a number of results which is not 1")
    3549           0 :                     .arg(static_cast<int>(static_cast<node_type_t>(f_type))).arg(sub_results.size()));
    3550             :         }
    3551             : #else
    3552             :         NOTUSED(sub_results);
    3553             : #endif
    3554           0 :     }
    3555             : 
    3556           0 :     void verify_binary(variable_t::variable_vector_t const& sub_results)
    3557             :     {
    3558             : #ifdef DEBUG
    3559           0 :         if(sub_results.size() != 2)
    3560             :         {
    3561           0 :             throw snap_logic_exception(QString("expr_node::execute() found a binary operator (%1) with %2 results, expected exactly 2")
    3562           0 :                     .arg(static_cast<int>(static_cast<node_type_t>(f_type))).arg(sub_results.size()));
    3563             :         }
    3564             : #else
    3565             :         NOTUSED(sub_results);
    3566             : #endif
    3567           0 :     }
    3568             : 
    3569             :     node_type_t             f_type = node_type_t::NODE_TYPE_VARIABLE;
    3570             : 
    3571             :     QString                 f_name = QString();
    3572             :     variable_t              f_variable = variable_t();
    3573             : 
    3574             :     expr_node_vector_t      f_children = expr_node_vector_t();
    3575             : };
    3576             : 
    3577             : 
    3578             : functions_t::function_call_table_t const expr_node::internal_functions[] =
    3579             : {
    3580             :     { // read the content of a cell
    3581             :         "cell",
    3582             :         expr_node::call_cell
    3583             :     },
    3584             :     { // check whether a cell exists in a table and row
    3585             :         "cell_exists",
    3586             :         expr_node::call_cell_exists
    3587             :     },
    3588             :     { // concatenate a child to a path (add "foo" or "/foo" as required)
    3589             :         "child",
    3590             :         expr_node::call_child
    3591             :     },
    3592             :     //{ // converts a date to microseconds
    3593             :     //    "date_to_us",
    3594             :     //    expr_node::call_date_to_us
    3595             :     //},
    3596             :     { // cast to format
    3597             :         "format",
    3598             :         expr_node::call_format
    3599             :     },
    3600             :     { // cast to int16
    3601             :         "int16",
    3602             :         expr_node::call_int16
    3603             :     },
    3604             :     { // cast to int32
    3605             :         "int32",
    3606             :         expr_node::call_int32
    3607             :     },
    3608             :     { // cast to int64
    3609             :         "int64",
    3610             :         expr_node::call_int64
    3611             :     },
    3612             :     { // cast to int8
    3613             :         "int8",
    3614             :         expr_node::call_int8
    3615             :     },
    3616             :     { // check whether parameter is an integer
    3617             :         "is_integer",
    3618             :         expr_node::call_is_integer
    3619             :     },
    3620             :     { // retrieve the parent of a path (remove the last /foo name)
    3621             :         "parent",
    3622             :         expr_node::call_parent
    3623             :     },
    3624             :     { // replace parts of a string
    3625             :         "preg_replace",
    3626             :         expr_node::call_preg_replace
    3627             :     },
    3628             :     { // check whether a row exists in a table
    3629             :         "row_exists",
    3630             :         expr_node::call_row_exists
    3631             :     },
    3632             :     { // retrieve a segment
    3633             :         "segment",
    3634             :         expr_node::call_segment
    3635             :     },
    3636             :     { // convert the parameter to a string
    3637             :         "string",
    3638             :         expr_node::call_string
    3639             :     },
    3640             :     { // return length of a string
    3641             :         "strlen",
    3642             :         expr_node::call_strlen
    3643             :     },
    3644             :     { // return true if the string matches the regular expression
    3645             :         "strmatch",
    3646             :         expr_node::call_strmatch
    3647             :     },
    3648             :     { // retrieve part of a string
    3649             :         "substr",
    3650             :         expr_node::call_substr
    3651             :     },
    3652             :     { // check whether a named table exists
    3653             :         "table_exists",
    3654             :         expr_node::call_table_exists
    3655             :     },
    3656             :     { // convert string to lowercase
    3657             :         "tolower",
    3658             :         expr_node::call_tolower
    3659             :     },
    3660             :     { // convert string to uppercase
    3661             :         "toupper",
    3662             :         expr_node::call_toupper
    3663             :     },
    3664             :     { // cast to uint16
    3665             :         "uint16",
    3666             :         expr_node::call_uint16
    3667             :     },
    3668             :     { // cast to uint32
    3669             :         "uint32",
    3670             :         expr_node::call_uint32
    3671             :     },
    3672             :     { // cast to uint64
    3673             :         "uint64",
    3674             :         expr_node::call_uint64
    3675             :     },
    3676             :     { // cast to uint8
    3677             :         "uint8",
    3678             :         expr_node::call_uint8
    3679             :     },
    3680             :     {
    3681             :         nullptr,
    3682             :         nullptr
    3683             :     }
    3684             : };
    3685             : 
    3686             : 
    3687             : char const *expr_node::type_names[static_cast<size_t>(node_type_t::NODE_TYPE_VARIABLE) + 1] =
    3688             : {
    3689             :     /* NODE_TYPE_UNKNOWN */ "Unknown",
    3690             :     /* NODE_TYPE_LOADING */ "Loading",
    3691             :     /* NODE_TYPE_OPERATION_LIST */ "Operator: ,",
    3692             :     /* NODE_TYPE_OPERATION_LOGICAL_NOT */ "Operator: !",
    3693             :     /* NODE_TYPE_OPERATION_BITWISE_NOT */ "Operator: ~",
    3694             :     /* NODE_TYPE_OPERATION_NEGATE */ "Operator: - (negate)",
    3695             :     /* NODE_TYPE_OPERATION_FUNCTION */ "Operator: function()",
    3696             :     /* NODE_TYPE_OPERATION_MULTIPLY */ "Operator: *",
    3697             :     /* NODE_TYPE_OPERATION_DIVIDE */ "Operator: /",
    3698             :     /* NODE_TYPE_OPERATION_MODULO */ "Operator: %",
    3699             :     /* NODE_TYPE_OPERATION_ADD */ "Operator: +",
    3700             :     /* NODE_TYPE_OPERATION_SUBTRACT */ "Operator: - (subtract)",
    3701             :     /* NODE_TYPE_OPERATION_SHIFT_LEFT */ "Operator: <<",
    3702             :     /* NODE_TYPE_OPERATION_SHIFT_RIGHT */ "Operator: >>",
    3703             :     /* NODE_TYPE_OPERATION_LESS */ "Operator: <",
    3704             :     /* NODE_TYPE_OPERATION_LESS_OR_EQUAL */ "Operator: <=",
    3705             :     /* NODE_TYPE_OPERATION_GREATER */ "Operator: >",
    3706             :     /* NODE_TYPE_OPERATION_GREATER_OR_EQUAL */ "Operator: >=",
    3707             :     /* NODE_TYPE_OPERATION_MINIMUM */ "Operator: <?",
    3708             :     /* NODE_TYPE_OPERATION_MAXIMUM */ "Operator: >?",
    3709             :     /* NODE_TYPE_OPERATION_EQUAL */ "Operator: ==",
    3710             :     /* NODE_TYPE_OPERATION_NOT_EQUAL */ "Operator: !=",
    3711             :     /* NODE_TYPE_OPERATION_BITWISE_AND */ "Operator: &",
    3712             :     /* NODE_TYPE_OPERATION_BITWISE_XOR */ "Operator: ^",
    3713             :     /* NODE_TYPE_OPERATION_BITWISE_OR */ "Operator: |",
    3714             :     /* NODE_TYPE_OPERATION_LOGICAL_AND */ "Operator: &&",
    3715             :     /* NODE_TYPE_OPERATION_LOGICAL_XOR */ "Operator: ^^",
    3716             :     /* NODE_TYPE_OPERATION_LOGICAL_OR */ "Operator: ||",
    3717             :     /* NODE_TYPE_OPERATION_CONDITIONAL */ "Operator: ?:",
    3718             :     /* NODE_TYPE_OPERATION_ASSIGNMENT */ "Operator: :=",
    3719             :     /* NODE_TYPE_OPERATION_VARIABLE */ "Operator: variable-name",
    3720             :     /* NODE_TYPE_LITERAL_BOOLEAN */ "Boolean",
    3721             :     /* NODE_TYPE_LITERAL_INTEGER */ "Integer",
    3722             :     /* NODE_TYPE_LITERAL_FLOATING_POINT */ "Floating Point",
    3723             :     /* NODE_TYPE_LITERAL_STRING */ "String",
    3724             :     /* NODE_TYPE_VARIABLE */ "Variable"
    3725             : };
    3726             : 
    3727             : 
    3728             : 
    3729             : /** \brief Merge qualified names in one single identifier.
    3730             :  *
    3731             :  * This function is used to transform qualified names in one single long
    3732             :  * identifier. So
    3733             :  *
    3734             :  * \code
    3735             :  * a :: b
    3736             :  *   :: c
    3737             :  * \endcode
    3738             :  *
    3739             :  * will result in "a::b::c" as one long identifier.
    3740             :  *
    3741             :  * \param[in] r  The rule calling this function.
    3742             :  * \param[in,out] t  The token tree to be tweaked.
    3743             :  */
    3744           0 : void list_qualified_name(rule const& r, QSharedPointer<token_node>& t)
    3745             : {
    3746           0 :     NOTUSED(r);
    3747             : 
    3748           0 :     QSharedPointer<parser::token_node> n(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    3749           0 :     (*t)[0]->set_value((*n)[0]->get_value().toString() + "::" + (*t)[2]->get_value().toString());
    3750           0 : }
    3751             : 
    3752             : 
    3753           1 : void list_expr_binary_operation(QSharedPointer<token_node>& t, expr_node::node_type_t operation)
    3754             : {
    3755           2 :     QSharedPointer<token_node> n0(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    3756           2 :     expr_node::expr_node_pointer_t l(qSharedPointerDynamicCast<expr_node, parser_user_data>(n0->get_user_data()));
    3757             : 
    3758           2 :     QSharedPointer<token_node> n2(qSharedPointerDynamicCast<token_node, token>((*t)[2]));
    3759           2 :     expr_node::expr_node_pointer_t r(qSharedPointerDynamicCast<expr_node, parser_user_data>(n2->get_user_data()));
    3760             : 
    3761           2 :     QSharedPointer<expr_node> v(new expr_node(operation));
    3762           1 :     v->add_child(l);
    3763           1 :     v->add_child(r);
    3764           1 :     t->set_user_data(v);
    3765           1 : }
    3766             : 
    3767             : #define LIST_EXPR_BINARY_OPERATION(a, b) \
    3768             :     void list_expr_##a(rule const& r, QSharedPointer<token_node>& t) \
    3769             :     { \
    3770             :         NOTUSED(r); \
    3771             :         list_expr_binary_operation(t, expr_node::node_type_t::NODE_TYPE_OPERATION_##b); \
    3772             :     }
    3773             : 
    3774           0 : LIST_EXPR_BINARY_OPERATION(multiplicative_multiply, MULTIPLY)
    3775           0 : LIST_EXPR_BINARY_OPERATION(multiplicative_divide, DIVIDE)
    3776           0 : LIST_EXPR_BINARY_OPERATION(multiplicative_modulo, MODULO)
    3777           0 : LIST_EXPR_BINARY_OPERATION(additive_add, ADD)
    3778           0 : LIST_EXPR_BINARY_OPERATION(additive_subtract, SUBTRACT)
    3779           0 : LIST_EXPR_BINARY_OPERATION(shift_left, SHIFT_LEFT)
    3780           0 : LIST_EXPR_BINARY_OPERATION(shift_right, SHIFT_RIGHT)
    3781           0 : LIST_EXPR_BINARY_OPERATION(relational_less, LESS)
    3782           0 : LIST_EXPR_BINARY_OPERATION(relational_less_or_equal, LESS_OR_EQUAL)
    3783           1 : LIST_EXPR_BINARY_OPERATION(relational_greater, GREATER)
    3784           0 : LIST_EXPR_BINARY_OPERATION(relational_greater_or_equal, GREATER_OR_EQUAL)
    3785           0 : LIST_EXPR_BINARY_OPERATION(relational_minimum, MINIMUM)
    3786           0 : LIST_EXPR_BINARY_OPERATION(relational_maximum, MAXIMUM)
    3787           0 : LIST_EXPR_BINARY_OPERATION(equality_equal, EQUAL)
    3788           0 : LIST_EXPR_BINARY_OPERATION(equality_not_equal, NOT_EQUAL)
    3789           0 : LIST_EXPR_BINARY_OPERATION(bitwise_and, BITWISE_AND)
    3790           0 : LIST_EXPR_BINARY_OPERATION(bitwise_xor, BITWISE_XOR)
    3791           0 : LIST_EXPR_BINARY_OPERATION(bitwise_or, BITWISE_OR)
    3792           0 : LIST_EXPR_BINARY_OPERATION(logical_and, LOGICAL_AND)
    3793           0 : LIST_EXPR_BINARY_OPERATION(logical_xor, LOGICAL_XOR)
    3794           0 : LIST_EXPR_BINARY_OPERATION(logical_or, LOGICAL_OR)
    3795             : 
    3796             : 
    3797             : 
    3798           0 : void list_expr_unary_operation(QSharedPointer<token_node>& t, expr_node::node_type_t operation)
    3799             : {
    3800           0 :     QSharedPointer<token_node> n(qSharedPointerDynamicCast<token_node, token>((*t)[1]));
    3801           0 :     expr_node::expr_node_pointer_t i(qSharedPointerDynamicCast<expr_node, parser_user_data>(n->get_user_data()));
    3802             : 
    3803           0 :     expr_node::expr_node_pointer_t v(new expr_node(operation));
    3804           0 :     v->add_child(i);
    3805           0 :     t->set_user_data(v);
    3806           0 : }
    3807             : 
    3808             : #define LIST_EXPR_UNARY_OPERATION(a, b) \
    3809             :     void list_expr_##a(rule const& r, QSharedPointer<token_node>& t) \
    3810             :     { \
    3811             :         NOTUSED(r); \
    3812             :         list_expr_unary_operation(t, expr_node::node_type_t::NODE_TYPE_OPERATION_##b); \
    3813             :     }
    3814             : 
    3815           0 : LIST_EXPR_UNARY_OPERATION(logical_not, LOGICAL_NOT)
    3816           0 : LIST_EXPR_UNARY_OPERATION(bitwise_not, BITWISE_NOT)
    3817           0 : LIST_EXPR_UNARY_OPERATION(negate, NEGATE)
    3818             : 
    3819             : 
    3820           0 : void list_expr_conditional(rule const& r, QSharedPointer<token_node>& t)
    3821             : {
    3822           0 :     NOTUSED(r);
    3823             : 
    3824           0 :     QSharedPointer<token_node> n0(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    3825           0 :     expr_node::expr_node_pointer_t c(qSharedPointerDynamicCast<expr_node, parser_user_data>(n0->get_user_data()));
    3826             : 
    3827           0 :     QSharedPointer<token_node> n2(qSharedPointerDynamicCast<token_node, token>((*t)[2]));
    3828           0 :     expr_node::expr_node_pointer_t at(qSharedPointerDynamicCast<expr_node, parser_user_data>(n2->get_user_data()));
    3829             : 
    3830           0 :     QSharedPointer<token_node> n4(qSharedPointerDynamicCast<token_node, token>((*t)[4]));
    3831           0 :     expr_node::expr_node_pointer_t af(qSharedPointerDynamicCast<expr_node, parser_user_data>(n4->get_user_data()));
    3832             : 
    3833           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_OPERATION_CONDITIONAL));
    3834           0 :     v->add_child(c);
    3835           0 :     v->add_child(at);
    3836           0 :     v->add_child(af);
    3837           0 :     t->set_user_data(v);
    3838           0 : }
    3839             : 
    3840             : 
    3841           0 : void list_expr_level_child(expr_node::expr_node_pointer_t n)
    3842             : {
    3843           0 :     int max_children(n->children_size());
    3844           0 :     for(int i(0); i < max_children; ++i)
    3845             :     {
    3846           0 :         expr_node::expr_node_pointer_t child(n->get_child(i));
    3847           0 :         if(child->get_type() == expr_node::node_type_t::NODE_TYPE_OPERATION_LIST)
    3848             :         {
    3849           0 :             n->remove_child(i);
    3850             : 
    3851             :             // if the child is a list, first reduce it
    3852           0 :             list_expr_level_child(child);
    3853             : 
    3854             :             // now add its children to use at this curent location
    3855           0 :             int const max_child_children(child->children_size());
    3856           0 :             for(int j(0); j < max_child_children; ++j, ++i)
    3857             :             {
    3858           0 :                 n->insert_child(i, child->get_child(j));
    3859             :             }
    3860           0 :             max_children = n->children_size();
    3861           0 :             --i; // we're going to do ++i in the for()
    3862             :         }
    3863             :     }
    3864           0 : }
    3865             : 
    3866             : 
    3867           0 : void list_expr_list(rule const& r, QSharedPointer<token_node>& t)
    3868             : {
    3869           0 :     NOTUSED(r);
    3870             : 
    3871           0 :     QSharedPointer<token_node> n0(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    3872           0 :     expr_node::expr_node_pointer_t l(qSharedPointerDynamicCast<expr_node, parser_user_data>(n0->get_user_data()));
    3873             : 
    3874           0 :     QSharedPointer<token_node> n2(qSharedPointerDynamicCast<token_node, token>((*t)[2]));
    3875           0 :     expr_node::expr_node_pointer_t i(qSharedPointerDynamicCast<expr_node, parser_user_data>(n2->get_user_data()));
    3876             : 
    3877             :     // This is very premature optimization and it is WRONG
    3878             :     // DO NOT OPTIMIZE HERE -- instead we have to optimize when
    3879             :     // expr_list is being reduced (in the unary and function expressions.)
    3880             :     // see the list_expr_level_child() function
    3881             :     //if(l->get_type() == expr_node::node_type_t::NODE_TYPE_OPERATION_LIST)
    3882             :     //{
    3883             :     //    // just add to the existing list
    3884             :     //    l->add_child(i);
    3885             :     //    t->set_user_data(l);
    3886             :     //}
    3887             :     //else
    3888             :     {
    3889             :         // not a list yet, create it
    3890           0 :         expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_OPERATION_LIST));
    3891           0 :         v->add_child(l);
    3892           0 :         v->add_child(i);
    3893           0 :         t->set_user_data(v);
    3894             :     }
    3895           0 : }
    3896             : 
    3897             : 
    3898           0 : void list_expr_identity(rule const& r, QSharedPointer<token_node>& t)
    3899             : {
    3900           0 :     NOTUSED(r);
    3901             : 
    3902           0 :     QSharedPointer<token_node> n(qSharedPointerDynamicCast<token_node, token>((*t)[1]));
    3903           0 :     expr_node::expr_node_pointer_t i(qSharedPointerDynamicCast<expr_node, parser_user_data>(n->get_user_data()));
    3904             : 
    3905             :     // we completely ignore the + and (...) they served there purpose already
    3906           0 :     t->set_user_data(i);
    3907           0 : }
    3908             : 
    3909             : 
    3910           0 : void list_expr_function(rule const& r, QSharedPointer<token_node>& t)
    3911             : {
    3912           0 :     NOTUSED(r);
    3913             : 
    3914             :     // the function name is a string
    3915           0 :     QSharedPointer<token_node> n0(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    3916           0 :     QString const func_name((*n0)[0]->get_value().toString());
    3917             : 
    3918             :     // at this point this node is an expr_list which only returns the
    3919             :     // last item as a result, we want all the parameters when calling a
    3920             :     // function so we remove the parent node below (see loop)
    3921           0 :     QSharedPointer<token_node> n2(qSharedPointerDynamicCast<token_node, token>((*t)[2]));
    3922           0 :     expr_node::expr_node_pointer_t l(qSharedPointerDynamicCast<expr_node, parser_user_data>(n2->get_user_data()));
    3923             : 
    3924           0 :     QSharedPointer<expr_node> v(new expr_node(expr_node::node_type_t::NODE_TYPE_OPERATION_FUNCTION));
    3925           0 :     v->set_name(func_name);
    3926             : 
    3927           0 :     if(l->get_type() == expr_node::node_type_t::NODE_TYPE_OPERATION_LIST)
    3928             :     {
    3929           0 :         list_expr_level_child(l);
    3930           0 :         int const max_children(l->children_size());
    3931           0 :         for(int i(0); i < max_children; ++i)
    3932             :         {
    3933           0 :             v->add_child(l->get_child(i));
    3934             :         }
    3935             :     }
    3936             :     else
    3937             :     {
    3938           0 :         v->add_child(l);
    3939             :     }
    3940             : 
    3941           0 :     t->set_user_data(v);
    3942           0 : }
    3943             : 
    3944             : 
    3945           0 : void list_expr_function_no_param(rule const & r, QSharedPointer<token_node> & t)
    3946             : {
    3947           0 :     NOTUSED(r);
    3948             : 
    3949             :     // the function name is a string
    3950           0 :     QSharedPointer<token_node> n0(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    3951           0 :     QString const func_name((*n0)[0]->get_value().toString());
    3952             : 
    3953           0 :     QSharedPointer<expr_node> v(new expr_node(expr_node::node_type_t::NODE_TYPE_OPERATION_FUNCTION));
    3954           0 :     v->set_name(func_name);
    3955             : 
    3956           0 :     t->set_user_data(v);
    3957           0 : }
    3958             : 
    3959             : 
    3960           0 : void list_expr_true(rule const& r, QSharedPointer<token_node>& t)
    3961             : {
    3962           0 :     NOTUSED(r);
    3963             : 
    3964           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_LITERAL_BOOLEAN));
    3965           0 :     libdbproxy::value value;
    3966           0 :     value.setBoolValue(true);
    3967           0 :     variable_t variable;
    3968           0 :     variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3969           0 :     v->set_variable(variable);
    3970           0 :     t->set_user_data(v);
    3971           0 : }
    3972             : 
    3973             : 
    3974           0 : void list_expr_false(rule const& r, QSharedPointer<token_node>& t)
    3975             : {
    3976           0 :     NOTUSED(r);
    3977             : 
    3978           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_LITERAL_BOOLEAN));
    3979           0 :     libdbproxy::value value;
    3980           0 :     value.setBoolValue(false);
    3981           0 :     variable_t variable;
    3982           0 :     variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_BOOL, value);
    3983           0 :     v->set_variable(variable);
    3984           0 :     t->set_user_data(v);
    3985           0 : }
    3986             : 
    3987             : 
    3988           0 : void list_expr_string(rule const& r, QSharedPointer<token_node>& t)
    3989             : {
    3990           0 :     NOTUSED(r);
    3991             : 
    3992           0 :     QString const str((*t)[0]->get_value().toString());
    3993             : 
    3994           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_LITERAL_STRING));
    3995           0 :     libdbproxy::value value;
    3996           0 :     value.setStringValue(str);
    3997           0 :     variable_t variable;
    3998           0 :     variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_STRING, value);
    3999           0 :     v->set_variable(variable);
    4000           0 :     t->set_user_data(v);
    4001           0 : }
    4002             : 
    4003             : 
    4004           0 : void list_expr_integer(rule const& r, QSharedPointer<token_node>& t)
    4005             : {
    4006           0 :     NOTUSED(r);
    4007             : 
    4008           0 :     int64_t const integer((*t)[0]->get_value().toLongLong());
    4009             : 
    4010           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_LITERAL_INTEGER));
    4011           0 :     libdbproxy::value value;
    4012           0 :     value.setInt64Value(integer);
    4013           0 :     variable_t variable;
    4014           0 :     variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_INT64, value);
    4015           0 :     v->set_variable(variable);
    4016           0 :     t->set_user_data(v);
    4017           0 : }
    4018             : 
    4019             : 
    4020           0 : void list_expr_float(rule const& r, QSharedPointer<token_node>& t)
    4021             : {
    4022           0 :     NOTUSED(r);
    4023             : 
    4024           0 :     double const floating_point((*t)[0]->get_value().toDouble());
    4025             : 
    4026           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_LITERAL_FLOATING_POINT));
    4027           0 :     libdbproxy::value value;
    4028           0 :     value.setDoubleValue(floating_point);
    4029           0 :     variable_t variable;
    4030           0 :     variable.set_value(variable_t::variable_type_t::EXPR_VARIABLE_TYPE_DOUBLE, value);
    4031           0 :     v->set_variable(variable);
    4032           0 :     t->set_user_data(v);
    4033           0 : }
    4034             : 
    4035             : 
    4036           0 : void list_expr_level_list(rule const& r, QSharedPointer<token_node>& t)
    4037             : {
    4038           0 :     NOTUSED(r);
    4039             : 
    4040           0 :     QSharedPointer<token_node> n0(qSharedPointerDynamicCast<token_node, token>((*t)[1]));
    4041           0 :     expr_node::expr_node_pointer_t n(qSharedPointerDynamicCast<expr_node, parser_user_data>(n0->get_user_data()));
    4042             : 
    4043           0 :     list_expr_level_child(n);
    4044             : 
    4045             :     // we completely ignore the + and (...) they served there purpose already
    4046           0 :     t->set_user_data(n);
    4047           0 : }
    4048             : 
    4049             : 
    4050           2 : void list_expr_variable(rule const& r, QSharedPointer<token_node>& t)
    4051             : {
    4052           2 :     NOTUSED(r);
    4053             : 
    4054           4 :     QString const name((*t)[0]->get_value().toString());
    4055             : 
    4056           4 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_OPERATION_VARIABLE));
    4057           2 :     v->set_name(name);
    4058           2 :     t->set_user_data(v);
    4059           2 : }
    4060             : 
    4061             : 
    4062           0 : void list_expr_assignment(rule const& r, QSharedPointer<token_node>& t)
    4063             : {
    4064           0 :     NOTUSED(r);
    4065             : 
    4066           0 :     QString const name((*t)[0]->get_value().toString());
    4067             : 
    4068           0 :     QSharedPointer<token_node> n2(qSharedPointerDynamicCast<token_node, token>((*t)[2]));
    4069           0 :     expr_node::expr_node_pointer_t i(qSharedPointerDynamicCast<expr_node, parser_user_data>(n2->get_user_data()));
    4070             : 
    4071           0 :     expr_node::expr_node_pointer_t v(new expr_node(expr_node::node_type_t::NODE_TYPE_OPERATION_ASSIGNMENT));
    4072           0 :     v->set_name(name);
    4073           0 :     v->add_child(i);
    4074           0 :     t->set_user_data(v);
    4075           0 : }
    4076             : 
    4077             : 
    4078          27 : void list_expr_copy_result(const rule& r, QSharedPointer<token_node>& t)
    4079             : {
    4080          27 :     NOTUSED(r);
    4081             : 
    4082          54 :     QSharedPointer<token_node> n(qSharedPointerDynamicCast<token_node, token>((*t)[0]));
    4083             :     // we don't need the dynamic cast since we don't need to access the data
    4084          27 :     t->set_user_data(n->get_user_data());
    4085          27 : }
    4086             : 
    4087             : 
    4088             : 
    4089             : /** \brief Compile a list test to binary.
    4090             :  *
    4091             :  * This function transforms a "list test" to byte code (similar to
    4092             :  * Java byte code if you wish, althgouh really our result is an XML
    4093             :  * string.) A list test is used to test whether a page is part of a
    4094             :  * list or not.
    4095             :  *
    4096             :  * The \p script parameter is the C-like expression to be transformed.
    4097             :  *
    4098             :  * If the script is invalid, the function returns false and the \p program
    4099             :  * parameter is left untouched.
    4100             :  *
    4101             :  * The script is actually a C-like expression.
    4102             :  *
    4103             :  * The following defines what is supported in the script (note that this
    4104             :  * simplified yacc does not show you the priority of the binary operator;
    4105             :  * we use the C order to the letter):
    4106             :  *
    4107             :  * \code
    4108             :  * // start the parser here
    4109             :  * start: expr_list
    4110             :  *
    4111             :  * // expression
    4112             :  * expr: '(' expr_list ')'
    4113             :  *     | expr binary_operator expr
    4114             :  *     | unary_operator expr
    4115             :  *     | expr '?' expr ':' expr
    4116             :  *     | qualified_name '(' expr_list ')'
    4117             :  *     | TOKEN_ID_IDENTIFIER
    4118             :  *     | TOKEN_ID_STRING
    4119             :  *     | TOKEN_ID_INTEGER
    4120             :  *     | TOKEN_ID_FLOAT
    4121             :  *     | 'true'
    4122             :  *     | 'false'
    4123             :  *
    4124             :  * qualified_name: TOKEN_ID_IDENTIFIER
    4125             :  *                     | qualified_name '::' TOKEN_ID_IDENTIFIER
    4126             :  *
    4127             :  * expr_list: expr
    4128             :  *          | expr_list ',' expr
    4129             :  *
    4130             :  * // operators
    4131             :  * unary_operator: '!' | '~' | '+' | '-'
    4132             :  *
    4133             :  * binary_operator: '*' | '/' | '%'
    4134             :  *                | '+' | '-'
    4135             :  *                | '<<' | '>>'
    4136             :  *                | '<' | '>' | '<=' | '>=' | '~=' | '<?' | '>?'
    4137             :  *                | '==' | '!='
    4138             :  *                | '&'
    4139             :  *                | '^'
    4140             :  *                | '|'
    4141             :  *                | '&&'
    4142             :  *                | '^^'
    4143             :  *                | '||'
    4144             :  *                | ':='
    4145             :  * \endcode
    4146             :  *
    4147             :  * Functions we support:
    4148             :  *
    4149             :  * \li cell( \<table>, \<row>, \<cell> )
    4150             :  *
    4151             :  * Read the content of a cell named \<cell> from table \<table>
    4152             :  * in row \<row>. The function always returns a binary piece of
    4153             :  * content (i.e. the raw data from the cell). It can be converted using
    4154             :  * a cast:
    4155             :  *
    4156             :  * \code
    4157             :  * int32(cell("content", website_uri() + "path/to/data", "stats::counter"));
    4158             :  * \endcode
    4159             :  *
    4160             :  * Note that a missing cell returns an empty buffer which represents zero or
    4161             :  * an empty string, although you may use `cell_exists()` first to know
    4162             :  * whether the cell exists or is just empty.
    4163             :  *
    4164             :  * \li cell_exists( \<table>, \<row>, \<cell> )
    4165             :  *
    4166             :  * Check whether the specified cell exists in the specified row of the
    4167             :  * specified table.
    4168             :  *
    4169             :  * \li int16( \<any> )
    4170             :  *
    4171             :  * Transform \<any> in a signed integer of 16 bits.
    4172             :  *
    4173             :  * \li int32( \<any> )
    4174             :  *
    4175             :  * Transform \<any> in a signed integer of 32 bits.
    4176             :  *
    4177             :  * \li int64( \<any> )
    4178             :  *
    4179             :  * Transform \<any> in a signed integer of 64 bits.
    4180             :  *
    4181             :  * \li int8( \<any> )
    4182             :  *
    4183             :  * Transform \<any> in a signed integer of 8 bits (-128 to +127).
    4184             :  *
    4185             :  * \li parent( \<path> )
    4186             :  *
    4187             :  * Compute the parent path of \<path>. (i.e. remove the last name on the
    4188             :  * path.) If the path ends with a slash, the slash is first removed, the
    4189             :  * the last name.
    4190             :  *
    4191             :  * \li row_exists( \<table>, \<row> )
    4192             :  *
    4193             :  * Check whether \<row> exists in \<table>.
    4194             :  *
    4195             :  * \li string( \<any> )
    4196             :  *
    4197             :  * Return \<any> converted to a string.
    4198             :  *
    4199             :  * \li strlen( \<string> )
    4200             :  *
    4201             :  * Return the length of the \<string>.
    4202             :  *
    4203             :  * \li substr( \<string>, \<start>, \<length> )
    4204             :  *
    4205             :  * Return the portion of the \<string> starting at \<start> and with at
    4206             :  * most \<length> characters.
    4207             :  *
    4208             :  * \li table_exists( \<table> )
    4209             :  *
    4210             :  * Check wether the named table exists, if so return true.
    4211             :  *
    4212             :  * \li uint16( \<any> )
    4213             :  *
    4214             :  * Transform the parameter to an integer of 16 bit, unsigned.
    4215             :  *
    4216             :  * \li uint32( \<any> )
    4217             :  *
    4218             :  * Transform the parameter to an integer of 32 bit, unsigned.
    4219             :  *
    4220             :  * \li uint64( \<any> )
    4221             :  *
    4222             :  * Transform the parameter to an integer of 64 bit, unsigned.
    4223             :  *
    4224             :  * \li uint8( \<any> )
    4225             :  *
    4226             :  * Transform the parameter to an integer of 8 bits, unsigned (from 0 to 255).
    4227             :  *
    4228             :  * \param[in] script  The script to be compiled to binary code bytes.
    4229             :  *
    4230             :  * \return A pointer to the program tree or nullptr.
    4231             :  */
    4232           1 : expr_node::expr_node_pointer_t compile_expression(QString const& script)
    4233             : {
    4234             :     // LEXER
    4235             : 
    4236             :     // lexer object
    4237           2 :     parser::lexer lexer;
    4238           1 :     lexer.set_input(script);
    4239           2 :     parser::keyword keyword_true(lexer, "true");
    4240           2 :     parser::keyword keyword_false(lexer, "false");
    4241             : 
    4242             :     // GRAMMAR
    4243           2 :     parser::grammar g;
    4244             : 
    4245             :     // qualified_name
    4246           2 :     choices qualified_name(&g, "qualified_name");
    4247           1 :     qualified_name >>= TOKEN_ID_IDENTIFIER // keep identifier as is
    4248           2 :                      | qualified_name >> "::" >> TOKEN_ID_IDENTIFIER
    4249           1 :                                                          >= list_qualified_name
    4250             :     ;
    4251             : 
    4252             :     // forward definitions
    4253           2 :     choices expr(&g, "expr");
    4254             : 
    4255             :     // expr_list
    4256           2 :     choices expr_list(&g, "expr_list");
    4257           1 :     expr_list >>= expr
    4258             :                                                     >= list_expr_copy_result
    4259           2 :                 | expr_list >> "," >> expr
    4260           1 :                                                     >= list_expr_list
    4261             :     ;
    4262             : 
    4263             :     // unary_expr
    4264           2 :     choices unary_expr(&g, "unary_expr");
    4265           2 :     unary_expr >>= "!" >> unary_expr
    4266             :                                                     >= list_expr_logical_not
    4267           1 :                  | "~" >> unary_expr
    4268             :                                                     >= list_expr_bitwise_not
    4269           1 :                  | "+" >> unary_expr
    4270             :                                                     >= list_expr_identity
    4271           1 :                  | "-" >> unary_expr
    4272             :                                                     >= list_expr_negate
    4273           1 :                  | "(" >> expr_list >> ")"
    4274             :                                                     >= list_expr_level_list
    4275           2 :                  | qualified_name >> "(" >> ")"
    4276             :                                                     >= list_expr_function_no_param
    4277           2 :                  | qualified_name >> "(" >> expr_list >> ")"
    4278             :                                                     >= list_expr_function
    4279             :                  | TOKEN_ID_IDENTIFIER
    4280             :                                                     >= list_expr_variable
    4281             :                  | keyword_true
    4282             :                                                     >= list_expr_true
    4283             :                  | keyword_false
    4284             :                                                     >= list_expr_false
    4285             :                  | TOKEN_ID_STRING
    4286             :                                                     >= list_expr_string
    4287             :                  | TOKEN_ID_INTEGER
    4288             :                                                     >= list_expr_integer
    4289             :                  | TOKEN_ID_FLOAT
    4290           8 :                                                     >= list_expr_float
    4291             :     ;
    4292             : 
    4293             :     // multiplicative_expr
    4294           2 :     choices multiplicative_expr(&g, "multiplicative_expr");
    4295           1 :     multiplicative_expr >>= unary_expr
    4296             :                                                     >= list_expr_copy_result
    4297           2 :                           | multiplicative_expr >> "*" >> unary_expr
    4298             :                                                     >= list_expr_multiplicative_multiply
    4299           2 :                           | multiplicative_expr >> "/" >> unary_expr
    4300             :                                                     >= list_expr_multiplicative_divide
    4301           2 :                           | multiplicative_expr >> "%" >> unary_expr
    4302           3 :                                                     >= list_expr_multiplicative_modulo
    4303             :     ;
    4304             : 
    4305             :     // additive_expr
    4306           2 :     choices additive_expr(&g, "additive_expr");
    4307           1 :     additive_expr >>= multiplicative_expr
    4308             :                                                     >= list_expr_copy_result
    4309           2 :                     | additive_expr >> "+" >> multiplicative_expr
    4310             :                                                     >= list_expr_additive_add
    4311           2 :                     | additive_expr >> "-" >> multiplicative_expr
    4312           2 :                                                     >= list_expr_additive_subtract
    4313             :     ;
    4314             : 
    4315             :     // shift_expr
    4316           2 :     choices shift_expr(&g, "shift_expr");
    4317           1 :     shift_expr >>= additive_expr
    4318             :                                                     >= list_expr_copy_result
    4319           2 :                  | shift_expr >> "<<" >> additive_expr
    4320             :                                                     >= list_expr_shift_left
    4321           2 :                  | shift_expr >> ">>" >> additive_expr
    4322           2 :                                                     >= list_expr_shift_right
    4323             :     ;
    4324             : 
    4325             :     // relational_expr
    4326           2 :     choices relational_expr(&g, "relational_expr");
    4327           1 :     relational_expr >>= shift_expr
    4328             :                                                     >= list_expr_copy_result
    4329           2 :                       | relational_expr >> "<" >> shift_expr
    4330             :                                                     >= list_expr_relational_less
    4331           2 :                       | relational_expr >> "<=" >> shift_expr
    4332             :                                                     >= list_expr_relational_less_or_equal
    4333           2 :                       | relational_expr >> ">" >> shift_expr
    4334             :                                                     >= list_expr_relational_greater
    4335           2 :                       | relational_expr >> ">=" >> shift_expr
    4336             :                                                     >= list_expr_relational_greater_or_equal
    4337           2 :                       | relational_expr >> "<?" >> shift_expr
    4338             :                                                     >= list_expr_relational_minimum
    4339           2 :                       | relational_expr >> ">?" >> shift_expr
    4340           6 :                                                     >= list_expr_relational_maximum
    4341             :     ;
    4342             : 
    4343             :     // equality_expr
    4344           2 :     choices equality_expr(&g, "equality_expr");
    4345           1 :     equality_expr >>= relational_expr
    4346             :                                                     >= list_expr_copy_result
    4347           2 :                     | equality_expr >> "==" >> relational_expr
    4348             :                                                     >= list_expr_equality_equal
    4349           2 :                     | equality_expr >> "!=" >> relational_expr
    4350           2 :                                                     >= list_expr_equality_not_equal
    4351             :     ;
    4352             : 
    4353             :     // bitwise_and_expr
    4354           2 :     choices bitwise_and_expr(&g, "bitwise_and_expr");
    4355           1 :     bitwise_and_expr >>= equality_expr
    4356             :                                                     >= list_expr_copy_result
    4357           2 :                        | bitwise_and_expr >> "&" >> equality_expr
    4358           1 :                                                     >= list_expr_bitwise_and
    4359             :     ;
    4360             : 
    4361             :     // bitwise_xor_expr
    4362           2 :     choices bitwise_xor_expr(&g, "bitwise_xor_expr");
    4363           1 :     bitwise_xor_expr >>= bitwise_and_expr
    4364             :                                                     >= list_expr_copy_result
    4365           2 :                        | bitwise_xor_expr >> "^" >> bitwise_and_expr
    4366           1 :                                                     >= list_expr_bitwise_xor
    4367             :     ;
    4368             : 
    4369             :     // bitwise_or_expr
    4370           2 :     choices bitwise_or_expr(&g, "bitwise_or_expr");
    4371           1 :     bitwise_or_expr >>= bitwise_xor_expr
    4372             :                                                     >= list_expr_copy_result
    4373           2 :                       | bitwise_or_expr >> "|" >> bitwise_xor_expr
    4374           1 :                                                     >= list_expr_bitwise_or
    4375             :     ;
    4376             : 
    4377             :     // logical_and_expr
    4378           2 :     choices logical_and_expr(&g, "logical_and_expr");
    4379           1 :     logical_and_expr >>= bitwise_or_expr
    4380             :                                                     >= list_expr_copy_result
    4381           2 :                        | logical_and_expr >> "&&" >> bitwise_or_expr
    4382           1 :                                                     >= list_expr_logical_and
    4383             :     ;
    4384             : 
    4385             :     // logical_xor_expr
    4386           2 :     choices logical_xor_expr(&g, "logical_xor_expr");
    4387           1 :     logical_xor_expr >>= logical_and_expr
    4388             :                                                     >= list_expr_copy_result
    4389           2 :                        | logical_xor_expr >> "^^" >> logical_and_expr
    4390           1 :                                                     >= list_expr_logical_xor
    4391             :     ;
    4392             : 
    4393             :     // logical_or_expr
    4394           2 :     choices logical_or_expr(&g, "logical_or_expr");
    4395           1 :     logical_or_expr >>= logical_xor_expr
    4396             :                                                     >= list_expr_copy_result
    4397           2 :                       | logical_or_expr >> "||" >> logical_xor_expr
    4398           1 :                                                     >= list_expr_logical_or
    4399             :     ;
    4400             : 
    4401             :     // conditional_expr
    4402             :     // The C/C++ definition is somewhat different:
    4403             :     // logical-OR-expression ? expression : conditional-expression
    4404           2 :     choices conditional_expr(&g, "conditional_expr");
    4405           1 :     conditional_expr >>= logical_or_expr
    4406             :                                                     >= list_expr_copy_result
    4407           2 :                        | conditional_expr >> "?" >> expr >> ":" >> logical_or_expr
    4408           1 :                                                     >= list_expr_conditional
    4409             :     ;
    4410             : 
    4411             :     // assignment
    4412             :     // (this is NOT a C compatible assignment, hence I used ":=")
    4413           2 :     choices assignment(&g, "assignment");
    4414           1 :     assignment >>= conditional_expr
    4415             :                                                     >= list_expr_copy_result
    4416           1 :                  | TOKEN_ID_IDENTIFIER >> ":=" >> conditional_expr
    4417           1 :                                                     >= list_expr_assignment
    4418             :     ;
    4419             : 
    4420             :     // expr
    4421           1 :     expr >>= assignment
    4422           1 :                                                     >= list_expr_copy_result
    4423             :     ;
    4424             : 
    4425             : //std::cerr << expr.to_string() << "\n";
    4426             : //std::cerr << expr_list.to_string() << "\n";
    4427             : //std::cerr << unary_expr.to_string() << "\n";
    4428             : 
    4429           1 :     if(!g.parse(lexer, expr))
    4430             :     {
    4431           0 :         SNAP_LOG_ERROR() << "error #" << static_cast<int>(lexer.get_error_code())
    4432           0 :                   << " on line " << lexer.get_error_line()
    4433           0 :                   << ": " << lexer.get_error_message();
    4434             : 
    4435           0 :         expr_node::expr_node_pointer_t null;
    4436           0 :         return null;
    4437             :     }
    4438             : 
    4439           2 :     QSharedPointer<token_node> r(g.get_result());
    4440           1 :     return qSharedPointerDynamicCast<expr_node, parser_user_data>(r->get_user_data());
    4441             : }
    4442             : 
    4443             : 
    4444             : 
    4445           1 : bool expr::compile(QString const& expression)
    4446             : {
    4447           1 :     f_program_tree = compile_expression(expression);
    4448           1 :     return f_program_tree;
    4449             : }
    4450             : 
    4451             : 
    4452           1 : QByteArray expr::serialize() const
    4453             : {
    4454           1 :     QByteArray result;
    4455             : 
    4456           2 :     QBuffer archive(&result);
    4457           1 :     archive.open(QIODevice::WriteOnly);
    4458           2 :     QtSerialization::QWriter w(archive, "expr", expr_node::LIST_TEST_NODE_MAJOR_VERSION, expr_node::LIST_TEST_NODE_MINOR_VERSION);
    4459           1 :     static_cast<expr_node *>(&*f_program_tree)->write(w);
    4460             : 
    4461           2 :     return result;
    4462             : }
    4463             : 
    4464             : 
    4465           0 : void expr::unserialize(QByteArray const& serialized_code)
    4466             : {
    4467           0 :     QByteArray non_const(serialized_code);
    4468           0 :     QBuffer archive(&non_const);
    4469           0 :     archive.open(QIODevice::ReadOnly);
    4470           0 :     QtSerialization::QReader r(archive);
    4471           0 :     f_program_tree = expr_node::load(r);
    4472           0 : }
    4473             : 
    4474             : 
    4475           0 : void expr::execute(variable_t& result, variable_t::variable_map_t& variables, functions_t& functions)
    4476             : {
    4477           0 :     if(!f_program_tree)
    4478             :     {
    4479           0 :         throw snap_expr_exception_unknown_function("cannot execute an empty program");
    4480             :     }
    4481             : 
    4482             :     // an internal variable
    4483           0 :     variable_t pi("pi");
    4484           0 :     pi.set_value(pi_number());
    4485           0 :     variables["pi"] = pi;
    4486             : 
    4487           0 :     static_cast<expr_node *>(&*f_program_tree)->execute(result, variables, functions);
    4488           0 : }
    4489             : 
    4490             : 
    4491           0 : void expr::set_cassandra_context(libdbproxy::context::pointer_t context)
    4492             : {
    4493           0 :     g_context = context;
    4494           0 : }
    4495             : 
    4496             : 
    4497             : } // namespace snap_expr
    4498           6 : } // snap
    4499             : 
    4500             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13