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
|