Qore Programming Language  0.9.16
QoreLValue.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  QoreLValue.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2020 Qore Technologies, s.r.o.
8 
9  Permission is hereby granted, free of charge, to any person obtaining a
10  copy of this software and associated documentation files (the "Software"),
11  to deal in the Software without restriction, including without limitation
12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  and/or sell copies of the Software, and to permit persons to whom the
14  Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26 
27  Note that the Qore library is released under a choice of three open-source
28  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29  information.
30 */
31 
32 #ifndef _QORE_INTERN_QORELVALUE_H
33 
34 #define _QORE_INTERN_QORELVALUE_H
35 
36 DLLLOCAL void check_lvalue_object_in_out(AbstractQoreNode* in, AbstractQoreNode* out);
37 
38 template <typename U = qore_value_u>
39 class QoreLValue {
40 protected:
41  // returns the old value just in case it needs to be dereferenced outside a lock
42  template <class T, typename t, int nt>
43  DLLLOCAL T* ensureUnique(AbstractQoreNode*& old) {
44  assert(type == QV_Node);
45  assert(assigned);
46  assert(!old);
47 
48  if (!v.n)
49  return reinterpret_cast<T*>(v.n = new T);
50 
51  if (v.n->getType() != nt) {
52  t i = T::getValue(v.n);
53  old = v.n;
54  return reinterpret_cast<T*>(v.n = new T(i));
55  }
56 
57  if (v.n->is_unique())
58  return reinterpret_cast<T*>(v.n);
59 
60  old = v.n;
61  return reinterpret_cast<T*>((v.n = old->realCopy()));
62  }
63 
64  DLLLOCAL void reset() {
65  assert(!assigned || type != QV_Node || !v.n);
66  if (assigned) {
67  assigned = false;
68  assert(!static_assignment);
69  }
70  }
71 
72 public:
73  U v;
74  valtype_t type : 4;
75  bool fixed_type : 1;
76  bool assigned : 1;
77 
78  // true if the assigned value was not referenced for the assignment
79  // and therefore should not be dereferenced
80  bool static_assignment : 1;
81 
82  // true if assigned to a closure
83  bool is_closure : 1;
84 
85  DLLLOCAL QoreLValue() : type(QV_Node), fixed_type(false), assigned(false), static_assignment(false), is_closure(false) {
86 #ifdef DEBUG
87  v.n = 0;
88 #endif
89  reset();
90  }
91 
92  DLLLOCAL QoreLValue(valtype_t t) : type(t), fixed_type(t != QV_Node), assigned(false), static_assignment(false), is_closure(false) {
93 #ifdef DEBUG
94  if (t == QV_Node)
95  v.n = 0;
96 #endif
97  reset();
98  }
99 
100  // fixed_type is assigned in set()
101  DLLLOCAL QoreLValue(const QoreTypeInfo* typeInfo) : assigned(false), static_assignment(false), is_closure(false) {
102 #ifdef DEBUG
103  type = QV_Bool;
104 #endif
105  set(typeInfo);
106  }
107 
108  DLLLOCAL QoreLValue(const QoreLValue<U>& old) : type(old.type), fixed_type(old.fixed_type), assigned(old.assigned), static_assignment(false), is_closure(old.is_closure) {
109  if (!assigned)
110  return;
111  switch (old.type) {
112  case QV_Bool: v.b = old.v.b; break;
113  case QV_Int: v.i = old.v.i; break;
114  case QV_Float: v.f = old.v.f; break;
115  case QV_Node:
116  v.n = old.v.n ? old.v.n->refSelf() : nullptr;
117  if (!is_closure)
118  check_lvalue_object_in_out(v.n, 0);
119  break;
120  default: assert(false);
121  // no break
122  }
123  }
124 
125 #ifdef DEBUG
126  DLLLOCAL ~QoreLValue() {
127  assert(!assigned || type != QV_Node || !v.n);
128  }
129 #endif
130 
131  DLLLOCAL void setClosure() {
132  assert(!is_closure);
133  is_closure = true;
134  }
135 
136  DLLLOCAL valtype_t getOptimizedType() const {
137  return fixed_type ? type : QV_Node;
138  }
139 
140  DLLLOCAL bool optimized() const {
141  return type != QV_Node && type != QV_Ref;
142  }
143 
145 
148  template<typename T>
149  DLLLOCAL typename detail::QoreValueCastHelper<T>::Result get() {
150  return assigned ? detail::QoreValueCastHelper<T>::cast(this, type) : nullptr;
151  }
152 
154 
157  template<typename T>
158  DLLLOCAL typename detail::QoreValueCastHelper<const T>::Result get() const {
159  return assigned ? detail::QoreValueCastHelper<const T>::cast(this, type) : nullptr;
160  }
161 
162  DLLLOCAL const char* getFixedTypeName() const {
163  if (!fixed_type)
164  return "any";
165  switch (type) {
166  case QV_Int: return "int";
167  case QV_Float: return "float";
168  case QV_Bool: return "bool";
169  default:
170  assert(false);
171  }
172  }
173 
174  DLLLOCAL bool isInt() {
175  if (!assigned) {
176  if (type != QV_Int) {
177  if (fixed_type)
178  return false;
179  type = QV_Int;
180  }
181  assigned = true;
182  v.i = 0;
183  return true;
184  }
185  if (type == QV_Int)
186  return true;
187  return false;
188  }
189 
190  DLLLOCAL bool isFloat() {
191  if (!assigned) {
192  if (type != QV_Float) {
193  if (fixed_type)
194  return false;
195  type = QV_Float;
196  }
197  assigned = true;
198  v.f = 0.0;
199  return true;
200  }
201  if (type == QV_Float)
202  return true;
203  return false;
204  }
205 
206  DLLLOCAL AbstractQoreNode* makeInt() {
207  assert(!fixed_type || type == QV_Int);
208  if (!assigned) {
209  assigned = true;
210  if (!type)
211  type = QV_Int;
212  v.i = 0;
213  return 0;
214  }
215  switch (type) {
216  case QV_Float: {
217  int64 i = (int64)v.f;
218  v.i = i;
219  type = QV_Int;
220  return 0;
221  }
222 
223  case QV_Bool: {
224  int64 i = (int64)v.b;
225  v.i = i;
226  type = QV_Int;
227  return 0;
228  }
229 
230  case QV_Node: {
231  int64 i = v.n ? v.n->getAsBigInt() : 0;
232  AbstractQoreNode* rv = v.n;
233  v.i = i;
234  type = QV_Int;
235  if (!is_closure)
236  check_lvalue_object_in_out(0, rv);
237  return rv;
238  }
239 
240  case QV_Int:
241  break;
242 
243  default:
244  assert(false);
245  }
246 
247  return 0;
248  }
249 
250  DLLLOCAL AbstractQoreNode* makeFloat() {
251  assert(!fixed_type || type == QV_Float);
252  if (!assigned) {
253  assigned = true;
254  if (!type)
255  type = QV_Float;
256  v.f = 0.0;
257  return 0;
258  }
259  switch (type) {
260  case QV_Int: {
261  double f = v.i;
262  v.f = f;
263  type = QV_Float;
264  return 0;
265  }
266 
267  case QV_Bool: {
268  double f = v.b;
269  v.f = f;
270  type = QV_Float;
271  return 0;
272  }
273 
274  case QV_Node: {
275  double f = v.n ? v.n->getAsFloat() : 0.0;
276  AbstractQoreNode* rv = v.n;
277  v.f = f;
278  type = QV_Float;
279  if (!is_closure)
280  check_lvalue_object_in_out(0, rv);
281  return rv;
282  }
283 
284  case QV_Float:
285  break;
286 
287  default:
288  assert(false);
289  }
290 
291  return 0;
292  }
293 
294  DLLLOCAL AbstractQoreNode* makeNumber() {
295  assert(!fixed_type);
296  if (!assigned) {
297  assigned = true;
298  if (!type)
299  type = QV_Node;
300  v.n = new QoreNumberNode;
301  return 0;
302  }
303  switch (type) {
304  case QV_Int: {
305  QoreNumberNode* n = new QoreNumberNode(v.i);
306  v.n = n;
307  type = QV_Node;
308  return 0;
309  }
310 
311  case QV_Float: {
312  QoreNumberNode* n = new QoreNumberNode(v.f);
313  v.n = n;
314  type = QV_Node;
315  return 0;
316  }
317 
318  case QV_Bool: {
319  QoreNumberNode* n = new QoreNumberNode((int64)v.b);
320  v.n = n;
321  type = QV_Node;
322  return 0;
323  }
324 
325  case QV_Node: {
326  if (v.n && v.n->getType() == NT_NUMBER)
327  return 0;
328  QoreNumberNode* n = new QoreNumberNode(v.n);
329  AbstractQoreNode* rv = v.n;
330  v.n = n;
331  type = QV_Node;
332  if (!is_closure)
333  check_lvalue_object_in_out(0, rv);
334  return rv;
335  }
336 
337  default:
338  assert(false);
339  }
340 
341  return 0;
342  }
343 
344  DLLLOCAL QoreValue takeValue() {
345  if (!assigned)
346  return QoreValue();
347 
348  assigned = false;
349  assert(!static_assignment);
350 
351  switch (type) {
352  case QV_Bool: return QoreValue(v.b);
353  case QV_Int: return QoreValue(v.i);
354  case QV_Float: return QoreValue(v.f);
355  case QV_Node:
356  if (!is_closure)
357  check_lvalue_object_in_out(0, v.n);
358  return QoreValue(v.n);
359  default: assert(false);
360  // no break
361  }
362  return false;
363  }
364 
365  DLLLOCAL const QoreValue getValue() const {
366  if (!assigned)
367  return QoreValue();
368 
369  switch (type) {
370  case QV_Bool: return QoreValue(v.b);
371  case QV_Int: return QoreValue(v.i);
372  case QV_Float: return QoreValue(v.f);
373  case QV_Node: return v.n;
374  default: assert(false);
375  // no break
376  }
377  return QoreValue();
378  }
379 
380  DLLLOCAL QoreValue getValue() {
381  if (!assigned)
382  return QoreValue();
383 
384  switch (type) {
385  case QV_Bool: return QoreValue(v.b);
386  case QV_Int: return QoreValue(v.i);
387  case QV_Float: return QoreValue(v.f);
388  case QV_Node: return v.n;
389  default: assert(false);
390  // no break
391  }
392  return QoreValue();
393  }
394 
395  DLLLOCAL QoreValue getReferencedValue() const {
396  return getValue().refSelf();
397  }
398 
399  DLLLOCAL bool needsScan() const {
400  if (!assigned || type != QV_Node || !v.n)
401  return false;
402 
403  return needs_scan(v.n);
404  }
405 
406  // never call when a lock is held
407  DLLLOCAL QoreValue getReferencedValue(bool& needs_deref) const {
408  if (!assigned) {
409  needs_deref = false;
410  return QoreValue();
411  }
412 
413  if (type == QV_Node) {
414  needs_deref = false;
415  return QoreValue(v.n);
416  }
417 
418  needs_deref = false;
419 
420  switch (type) {
421  case QV_Bool: return QoreValue(v.b);
422  case QV_Int: return QoreValue(v.i);
423  case QV_Float: return QoreValue(v.f);
424  default: assert(false);
425  // no break
426  }
427  return QoreValue();
428  }
429 
430  DLLLOCAL void discard(ExceptionSink* xsink) {
431  if (!assigned)
432  return;
433 
434  if (type == QV_Node && v.n) {
435  if (!is_closure)
436  check_lvalue_object_in_out(0, v.n);
437  v.n->deref(xsink);
438  }
439  }
440 
441  DLLLOCAL bool hasValue() const {
442  if (!assigned)
443  return false;
444  switch (type) {
445  case QV_Bool: return v.b;
446  case QV_Int: return (bool)v.i;
447  case QV_Float: return (bool)v.f;
448  case QV_Node: return !is_nothing(v.n);
449  default: assert(false);
450  // no break
451  }
452  return false;
453  }
454 
455  DLLLOCAL void set(const QoreTypeInfo* typeInfo) {
456  if (typeInfo == bigIntTypeInfo || typeInfo == softBigIntTypeInfo)
457  set(QV_Int);
458  else if (typeInfo == floatTypeInfo || typeInfo == softFloatTypeInfo)
459  set(QV_Float);
460  else if (typeInfo == boolTypeInfo || typeInfo == softBoolTypeInfo)
461  set(QV_Bool);
462  else
463  set(QV_Node);
464  }
465 
466  DLLLOCAL void set(valtype_t t) {
467  assert(!assigned || type != QV_Node || !v.n);
468  type = t;
469  fixed_type = (t != QV_Node);
470 #ifdef DEBUG
471  if (t == QV_Node)
472  v.n = 0;
473 #endif
474  reset();
475  }
476 
477  DLLLOCAL AbstractQoreNode* assign(bool b) {
478  if (fixed_type) {
479  if (!assigned)
480  assigned = true;
481  switch (type) {
482  case QV_Bool: v.b = false; return 0;
483  case QV_Int: v.i = (int64)b; return 0;
484  case QV_Float: v.f = (double)b; return 0;
485  default: assert(false);
486  // no break
487  }
488  }
489 
490  AbstractQoreNode* rv;
491  if (assigned) {
492  if (type == QV_Node) {
493  if (!is_closure)
494  check_lvalue_object_in_out(0, v.n);
495  rv = v.n;
496  }
497  else
498  rv = 0;
499  }
500  else {
501  assigned = true;
502  rv = 0;
503  }
504 
505  v.b = b;
506  type = QV_Bool;
507 
508  return rv;
509  }
510 
511  DLLLOCAL AbstractQoreNode* assign(int64 i) {
512  if (fixed_type) {
513  if (!assigned)
514  assigned = true;
515  switch (type) {
516  case QV_Bool: v.b = (bool)i; return 0;
517  case QV_Int: v.i = i; return 0;
518  case QV_Float: v.f = (double)i; return 0;
519  default: assert(false);
520  // no break
521  }
522  }
523 
524  AbstractQoreNode* rv;
525  if (assigned) {
526  if (type == QV_Node) {
527  if (!is_closure)
528  check_lvalue_object_in_out(0, v.n);
529  rv = v.n;
530  }
531  else
532  rv = 0;
533  }
534  else {
535  assigned = true;
536  rv = 0;
537  }
538 
539  v.i = i;
540  type = QV_Int;
541 
542  return rv;
543  }
544 
545  DLLLOCAL AbstractQoreNode* assign(double f) {
546  if (fixed_type) {
547  if (!assigned)
548  assigned = true;
549  switch (type) {
550  case QV_Bool: v.b = (bool)f; return 0;
551  case QV_Int: v.i = (int64)f; return 0;
552  case QV_Float: v.f = f; return 0;
553  default: assert(false);
554  // no break
555  }
556  }
557 
558  AbstractQoreNode* rv;
559  if (assigned) {
560  if (type == QV_Node) {
561  if (!is_closure)
562  check_lvalue_object_in_out(0, v.n);
563  rv = v.n;
564  }
565  else
566  rv = 0;
567  }
568  else {
569  assigned = true;
570  rv = 0;
571  }
572 
573  v.f = f;
574  type = QV_Float;
575 
576  return rv;
577  }
578 
580 
583  DLLLOCAL void assignSetTakeInitial(QoreLValue<U>& n, QoreValue val) {
584  assert(!assigned);
585  assigned = true;
586  type = n.type;
587  if (n.static_assignment) {
588  static_assignment = n.static_assignment;
589  n.static_assignment = false;
590  }
591  switch (n.type) {
592  case QV_Bool:
593  v.b = n.v.b;
594  assert(val.getType() == NT_BOOLEAN);
595  n.v.b = val.v.b;
596  break;
597 
598  case QV_Int:
599  v.i = n.v.i;
600  assert(val.getType() == NT_INT);
601  n.v.i = val.v.i;
602  break;
603 
604  case QV_Float:
605  v.f = n.v.f;
606  assert(val.getType() == NT_FLOAT);
607  n.v.f = val.v.f;
608  break;
609 
610  case QV_Node:
611  if (n.is_closure) {
612  assert(!is_closure);
613  is_closure = true;
614  }
615  v.n = n.v.n;
616  n.v.n = val.takeNode();
617  break;
618 
619  default:
620  assert(false);
621  // no break
622  }
623  }
624 
625  DLLLOCAL void assignSetTakeInitial(QoreLValue<U>& n) {
626  assert(!assigned);
627  if (!n.assigned)
628  return;
629  assigned = true;
630  type = n.type;
631  if (n.static_assignment) {
632  static_assignment = n.static_assignment;
633  n.static_assignment = false;
634  }
635  switch (n.type) {
636  case QV_Bool: v.b = n.v.b; n.v.b = false; break;
637  case QV_Int: v.i = n.v.i; n.v.i = 0; break;
638  case QV_Float: v.f = n.v.f; n.v.f = 0; break;
639  case QV_Node:
640  if (n.is_closure) {
641  assert(!is_closure);
642  is_closure = true;
643  }
644  v.n = n.v.n;
645  n.v.n = nullptr;
646  break;
647  default: assert(false);
648  // no break
649  }
650  n.assigned = false;
651  }
652 
653  // note: destructive for "n"
654  // returns any AbstractQoreNode no longer needed (because it was converted to a base type)
655  DLLLOCAL AbstractQoreNode* assignAssumeInitial(QoreValue& n, bool is_static_assignment = false) {
656  assert(!assigned);
657  assert(!static_assignment);
658  //printd(5, "QoreLValue::assignAssumeInitial() this: %p n: %s sa: %d\n", this, n.getTypeName(), is_static_assignment);
659  if (is_static_assignment)
660  static_assignment = true;
661  return assignAssume(n);
662  }
663 
664  DLLLOCAL void assignInitial(bool n) {
665  assert(!assigned);
666  assigned = true;
667  if (fixed_type) {
668  switch (type) {
669  case QV_Bool: v.b = n; return;
670  case QV_Int: v.i = (int64)n; return;
671  case QV_Float: v.f = (double)n; return;
672  default: assert(false);
673  // no break
674  }
675  }
676  type = QV_Bool;
677  v.b = n;
678  }
679 
680  DLLLOCAL void assignInitial(int64 n) {
681  assert(!assigned);
682  assigned = true;
683  if (fixed_type) {
684  switch (type) {
685  case QV_Bool: v.b = (bool)n; return;
686  case QV_Int: v.i = n; return;
687  case QV_Float: v.f = (double)n; return;
688  default: assert(false);
689  // no break
690  }
691  }
692  type = QV_Int;
693  v.i = n;
694  }
695 
696  DLLLOCAL void assignInitial(double n) {
697  assert(!assigned);
698  assigned = true;
699  if (fixed_type) {
700  switch (type) {
701  case QV_Bool: v.b = (bool)n; return;
702  case QV_Int: v.i = (int64)n; return;
703  case QV_Float: v.f = n; return;
704  default: assert(false);
705  // no break
706  }
707  }
708  type = QV_Float;
709  v.f = n;
710  }
711 
712  DLLLOCAL AbstractQoreNode* assignInitial(AbstractQoreNode* n) {
713  assert(!assigned);
714  assigned = true;
715  if (fixed_type) {
716  switch (type) {
717  case QV_Bool:
718  v.b = n ? n->getAsBool() : false; return n;
719  case QV_Int: v.i = n ? n->getAsBigInt() : 0; return n;
720  case QV_Float: v.f = n ? n->getAsFloat() : 0; return n;
721  default: assert(false);
722  // no break
723  }
724  }
725  type = QV_Node;
726  v.n = n;
727  if (!is_closure)
728  check_lvalue_object_in_out(v.n, 0);
729  return 0;
730  }
731 
732  DLLLOCAL AbstractQoreNode* assignInitial(QoreValue n) {
733  assert(!assigned);
734  return assignAssume(n);
735  }
736 
737  // NOTE: destructive for "val":
738  DLLLOCAL AbstractQoreNode* assignAssume(QoreValue& val) {
739  if (fixed_type) {
740  if (!assigned)
741  assigned = true;
742  switch (type) {
743  case QV_Bool: v.b = val.getAsBool(); break;
744  case QV_Int: v.i = val.getAsBigInt(); break;
745  case QV_Float: v.f = val.getAsFloat(); break;
746  default: assert(false);
747  // no break
748  }
749  return val.takeIfNode();
750  }
751 
752  AbstractQoreNode* rv;
753  if (assigned) {
754  if (type == QV_Node) {
755  if (!is_closure)
756  check_lvalue_object_in_out(0, v.n);
757  rv = v.n;
758  }
759  else
760  rv = nullptr;
761  }
762  else {
763  assigned = true;
764  rv = nullptr;
765  }
766 
767  switch (val.type) {
768  case QV_Bool: v.b = val.v.b; if (type != QV_Bool) type = QV_Bool; break;
769  case QV_Int: v.i = val.v.i; if (type != QV_Int) type = QV_Int; break;
770  case QV_Float: v.f = val.v.f; if (type != QV_Float) type = QV_Float; break;
771  case QV_Node:
772  v.n = val.takeNode();
773  if (type != QV_Node)
774  type = QV_Node;
775  if (!is_closure)
776  check_lvalue_object_in_out(v.n, 0);
777  break;
778  default: assert(false);
779  // no break
780  }
781 
782  return rv;
783  }
784 
785  // the node is already referenced for the assignment
786  DLLLOCAL AbstractQoreNode* assign(AbstractQoreNode* n) {
787  if (fixed_type) {
788  if (!assigned)
789  assigned = true;
790 
791  switch (type) {
792  case QV_Bool: {
793  if (n) {
794  v.b = n->getAsBool();
795  return n;
796  }
797  v.b = false;
798  return 0;
799  }
800  case QV_Int: {
801  if (n) {
802  v.i = n->getAsBigInt();
803  return n;
804  }
805  v.i = 0;
806  return 0;
807  }
808  case QV_Float: {
809  if (n) {
810  v.f = n->getAsFloat();
811  return n;
812  }
813  v.f = 0.0;
814  return 0;
815  }
816  case QV_Node: {
817  if (!is_closure)
818  check_lvalue_object_in_out(n, v.n);
819  AbstractQoreNode* rv = v.n;
820  v.n = n;
821  return rv;
822  }
823  default:
824  assert(false);
825  // no break
826  }
827  return 0;
828  }
829 
830  AbstractQoreNode* rv;
831  if (assigned) {
832  if (type == QV_Node) {
833  if (!is_closure)
834  check_lvalue_object_in_out(0, v.n);
835  rv = v.n;
836  }
837  else
838  rv = 0;
839  }
840  else {
841  assigned = true;
842  rv = 0;
843  }
844 
845  v.n = n;
846  if (!is_closure)
847  check_lvalue_object_in_out(v.n, 0);
848  if (type != QV_Node)
849  type = QV_Node;
850 
851  return rv;
852  }
853 
854  DLLLOCAL bool exists() const {
855  return assigned && (type != QV_Node || !is_nothing(v.n));
856  }
857 
858  DLLLOCAL bool getAsBool() const {
859  if (assigned) {
860  switch (type) {
861  case QV_Bool: return v.b;
862  case QV_Int: return (bool)v.i;
863  case QV_Float: return (bool)v.f;
864  case QV_Node: return v.n ? v.n->getAsBool() : false;
865  default: assert(false);
866  // no break
867  }
868  }
869  return false;
870  }
871 
872  DLLLOCAL int64 getAsBigInt() const {
873  if (assigned) {
874  switch (type) {
875  case QV_Bool: return (int64)v.b;
876  case QV_Int: return v.i;
877  case QV_Float: return (int64)v.f;
878  case QV_Node: return v.n ? v.n->getAsBigInt() : 0;
879  default: assert(false);
880  // no break
881  }
882  }
883  return 0;
884  }
885 
886  DLLLOCAL double getAsFloat() const {
887  if (assigned) {
888  switch (type) {
889  case QV_Bool: return (double)v.b;
890  case QV_Int: return (double)v.i;
891  case QV_Float: return v.f;
892  case QV_Node: return v.n ? v.n->getAsFloat() : 0.0;
893  default: assert(false);
894  // no break
895  }
896  }
897  return 0.0;
898  }
899 
900  DLLLOCAL AbstractQoreNode* getInternalNode() const {
901  return assigned && type == QV_Node ? v.n : nullptr;
902  }
903 
904  DLLLOCAL qore_type_t getType() const {
905  if (assigned)
906  switch (type) {
907  case QV_Bool: return NT_BOOLEAN;
908  case QV_Int: return NT_INT;
909  case QV_Float: return NT_FLOAT;
910  case QV_Node: return v.n ? v.n->getType() : NT_NOTHING;
911  default: assert(false);
912  // no break
913  }
914  return NT_NOTHING;
915  }
916 
917  DLLLOCAL const char* getTypeName() const {
918  if (assigned)
919  switch (type) {
920  case QV_Bool: return qoreBoolTypeName;
921  case QV_Int: return qoreIntTypeName;
922  case QV_Float: return qoreFloatTypeName;
923  case QV_Node: return get_type_name(v.n);
924  default: assert(false);
925  // no break
926  }
927  return "NOTHING";
928  }
929 
930  // lvalue operations
931  DLLLOCAL int64 plusEqualsBigInt(int64 i, AbstractQoreNode*& old) {
932  assert(type == QV_Int);
933 
934  switch (type) {
935  case QV_Int:
936  if (!assigned) {
937  assigned = true;
938  return v.i = i;
939  }
940  return v.i += i;
941 
942  // to avoid warnings about missing enum values
943  default:
944  assert(false);
945  // no break
946  }
947 
948  return 0;
949  }
950 
951  DLLLOCAL double plusEqualsFloat(double f, AbstractQoreNode*& old) {
952  assert(type == QV_Float);
953 
954  switch (type) {
955  case QV_Float:
956  if (!assigned) {
957  assigned = true;
958  return v.f = f;
959  }
960  return v.f += f;
961 
962  // to avoid warnings about missing enum values
963  default:
964  assert(false);
965  // no break
966  }
967 
968  return 0.0;
969  }
970 
971  DLLLOCAL int64 minusEqualsBigInt(int64 i, AbstractQoreNode*& old) {
972  assert(type == QV_Int);
973 
974  switch (type) {
975  case QV_Int:
976  if (!assigned) {
977  assigned = true;
978  return v.i = -i;
979  }
980  return v.i -= i;
981 
982  // to avoid warnings about missing enum values
983  default:
984  assert(false);
985  // no break
986  }
987 
988  return 0;
989  }
990 
991  DLLLOCAL double minusEqualsFloat(double f, AbstractQoreNode*& old) {
992  assert(type == QV_Float);
993 
994  switch (type) {
995  case QV_Float:
996  if (!assigned) {
997  assigned = true;
998  return v.f = -f;
999  }
1000  return v.f -= f;
1001 
1002  // to avoid warnings about missing enum values
1003  default:
1004  assert(false);
1005  // no break
1006  }
1007 
1008  return 0.0;
1009  }
1010 
1011  DLLLOCAL int64 orEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1012  assert(type == QV_Int);
1013 
1014  switch (type) {
1015  case QV_Int:
1016  if (!assigned) {
1017  assigned = true;
1018  return v.i = i;
1019  }
1020  return v.i |= i;
1021 
1022  // to avoid warnings about missing enum values
1023  default:
1024  assert(false);
1025  // no break
1026  }
1027 
1028  return 0;
1029  }
1030 
1031  DLLLOCAL int64 andEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1032  assert(type == QV_Int);
1033 
1034  switch (type) {
1035  case QV_Int:
1036  if (!assigned) {
1037  assigned = true;
1038  return v.i = 0;
1039  }
1040  return v.i &= i;
1041 
1042  // to avoid warnings about missing enum values
1043  default:
1044  assert(false);
1045  // no break
1046  }
1047 
1048  return 0;
1049  }
1050 
1051  DLLLOCAL int64 modulaEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1052  assert(type == QV_Int);
1053 
1054  switch (type) {
1055  case QV_Int:
1056  if (!assigned) {
1057  assigned = true;
1058  return v.i = 0;
1059  }
1060  return i ? v.i %= i : v.i = 0;
1061 
1062  // to avoid warnings about missing enum values
1063  default:
1064  assert(false);
1065  // no break
1066  }
1067 
1068  return 0;
1069  }
1070 
1071  DLLLOCAL int64 multiplyEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1072  assert(type == QV_Int);
1073 
1074  switch (type) {
1075  case QV_Int:
1076  if (!assigned) {
1077  assigned = true;
1078  return v.i = 0;
1079  }
1080  return v.i *= i;
1081 
1082  // to avoid warnings about missing enum values
1083  default:
1084  assert(false);
1085  // no break
1086  }
1087 
1088  return 0;
1089  }
1090 
1091  DLLLOCAL int64 divideEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1092  assert(type == QV_Int);
1093  assert(i);
1094 
1095  switch (type) {
1096  case QV_Int:
1097  if (!assigned) {
1098  assigned = true;
1099  return v.i = 0;
1100  }
1101  return v.i /= i;
1102 
1103  // to avoid warnings about missing enum values
1104  default:
1105  assert(false);
1106  // no break
1107  }
1108 
1109  return 0;
1110  }
1111 
1112  DLLLOCAL int64 xorEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1113  assert(type == QV_Int);
1114 
1115  switch (type) {
1116  case QV_Int:
1117  if (!assigned) {
1118  assigned = true;
1119  return v.i = i;
1120  }
1121  return v.i ^= i;
1122 
1123  // to avoid warnings about missing enum values
1124  default:
1125  assert(false);
1126  // no break
1127  }
1128 
1129  return 0;
1130  }
1131 
1132  DLLLOCAL int64 shiftLeftEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1133  assert(type == QV_Int);
1134 
1135  switch (type) {
1136  case QV_Int:
1137  if (!assigned) {
1138  assigned = true;
1139  return v.i = 0;
1140  }
1141  return v.i <<= i;
1142 
1143  // to avoid warnings about missing enum values
1144  default:
1145  assert(false);
1146  // no break
1147  }
1148 
1149  return 0;
1150  }
1151 
1152  DLLLOCAL int64 shiftRightEqualsBigInt(int64 i, AbstractQoreNode*& old) {
1153  assert(type == QV_Int);
1154 
1155  switch (type) {
1156  case QV_Int:
1157  if (!assigned) {
1158  assigned = true;
1159  return v.i = 0;
1160  }
1161  return v.i >>= i;
1162 
1163  // to avoid warnings about missing enum values
1164  default:
1165  assert(false);
1166  // no break
1167  }
1168 
1169  return 0;
1170  }
1171 
1172  DLLLOCAL int64 postIncrementBigInt(AbstractQoreNode*& old) {
1173  assert(type == QV_Int);
1174 
1175  switch (type) {
1176  case QV_Int: {
1177  if (!assigned) {
1178  assigned = true;
1179  v.i = 1;
1180  return 0;
1181  }
1182  int64 rv = (int64)v.i;
1183  ++v.i;
1184  return rv;
1185  }
1186 
1187  // to avoid warnings about missing enum values
1188  default:
1189  assert(false);
1190  // no break
1191  }
1192 
1193  return 0;
1194  }
1195 
1196  DLLLOCAL int64 preIncrementBigInt(AbstractQoreNode*& old) {
1197  assert(type == QV_Int);
1198 
1199  switch (type) {
1200  case QV_Int:
1201  if (!assigned) {
1202  assigned = true;
1203  return v.i = 1;
1204  }
1205  return ++v.i;
1206 
1207  // to avoid warnings about missing enum values
1208  default:
1209  assert(false);
1210  // no break
1211  }
1212 
1213  return 0;
1214  }
1215 
1216  DLLLOCAL int64 postDecrementBigInt(AbstractQoreNode*& old) {
1217  assert(type == QV_Int);
1218 
1219  switch (type) {
1220  case QV_Int:
1221  if (!assigned) {
1222  assigned = true;
1223  v.i = -1;
1224  return 0;
1225  }
1226  return v.i--;
1227 
1228  // to avoid warnings about missing enum values
1229  default:
1230  assert(false);
1231  // no break
1232  }
1233 
1234  return 0;
1235  }
1236 
1237  DLLLOCAL int64 preDecrementBigInt(AbstractQoreNode*& old) {
1238  assert(type == QV_Int);
1239 
1240  switch (type) {
1241  case QV_Int:
1242  if (!assigned) {
1243  assigned = true;
1244  return v.i = -1;
1245  }
1246  return --v.i;
1247 
1248  // to avoid warnings about missing enum values
1249  default:
1250  assert(false);
1251  // no break
1252  }
1253  return 0;
1254  }
1255 
1256  DLLLOCAL double postIncrementFloat(AbstractQoreNode*& old) {
1257  assert(type == QV_Float);
1258 
1259  switch (type) {
1260  case QV_Float:
1261  if (!assigned) {
1262  assigned = true;
1263  v.f = 1.0;
1264  return 0.0;
1265  }
1266  return v.f++;
1267 
1268  // to avoid warnings about missing enum values
1269  default:
1270  assert(false);
1271  // no break
1272  }
1273 
1274  return 0.0;
1275  }
1276 
1277  DLLLOCAL double preIncrementFloat(AbstractQoreNode*& old) {
1278  assert(type == QV_Float);
1279 
1280  switch (type) {
1281  case QV_Float:
1282  if (!assigned) {
1283  assigned = true;
1284  return v.f = 1.0;
1285  }
1286  return ++v.f;
1287 
1288  // to avoid warnings about missing enum values
1289  default:
1290  assert(false);
1291  // no break
1292  }
1293 
1294  return 0.0;
1295  }
1296 
1297  DLLLOCAL double postDecrementFloat(AbstractQoreNode*& old) {
1298  assert(type == QV_Float);
1299 
1300  switch (type) {
1301  case QV_Float:
1302  if (!assigned) {
1303  assigned = true;
1304  v.f = -1.0;
1305  return 0.0;
1306  }
1307  return v.f--;
1308 
1309  // to avoid warnings about missing enum values
1310  default:
1311  assert(false);
1312  // no break
1313  }
1314 
1315  return 0.0;
1316  }
1317 
1318  DLLLOCAL double preDecrementFloat(AbstractQoreNode*& old) {
1319  assert(type == QV_Float);
1320 
1321  switch (type) {
1322  case QV_Float:
1323  if (!assigned) {
1324  assigned = true;
1325  return v.f = -1.0;
1326  }
1327  return --v.f;
1328 
1329  // to avoid warnings about missing enum values
1330  default:
1331  assert(false);
1332  // no break
1333  }
1334  return 0;
1335  }
1336 
1337  DLLLOCAL double multiplyEqualsFloat(double f, AbstractQoreNode*& old) {
1338  assert(type == QV_Float);
1339 
1340  switch (type) {
1341  case QV_Float:
1342  if (!assigned) {
1343  assigned = true;
1344  return v.f = 0;
1345  }
1346  return v.f *= f;
1347 
1348  // to avoid warnings about missing enum values
1349  default:
1350  assert(false);
1351  // no break
1352  }
1353 
1354  return 0;
1355  }
1356 
1357  DLLLOCAL double divideEqualsFloat(double f, AbstractQoreNode*& old) {
1358  assert(type == QV_Float);
1359  assert(f);
1360 
1361  switch (type) {
1362  case QV_Float:
1363  if (!assigned) {
1364  assigned = true;
1365  return v.f = 0;
1366  }
1367  return v.f /= f;
1368 
1369  // to avoid warnings about missing enum values
1370  default:
1371  assert(false);
1372  // no break
1373  }
1374 
1375  return 0;
1376  }
1377 
1378  DLLLOCAL QoreValue remove(bool& was_static_assignment) {
1379  assert(!was_static_assignment);
1380 
1381  if (!assigned)
1382  return QoreValue();
1383  assigned = false;
1384  if (static_assignment) {
1385  static_assignment = false;
1386  was_static_assignment = true;
1387  }
1388 
1389  switch (type) {
1390  case QV_Bool:
1391  return v.b;
1392  case QV_Int:
1393  return v.i;
1394  case QV_Float:
1395  return v.f;
1396  case QV_Node:
1397  if (!is_closure)
1398  check_lvalue_object_in_out(0, v.n);
1399  return v.n;
1400  default:
1401  assert(false);
1402  // no break
1403  }
1404  return QoreValue();
1405  }
1406 
1407  // ignore any current value and sets the lvalue to unassigned
1408  DLLLOCAL void unassignIgnore() {
1409  if (assigned) {
1410  assigned = false;
1411  if (static_assignment)
1412  static_assignment = false;
1413  if (type == QV_Node && !is_closure)
1414  check_lvalue_object_in_out(0, v.n);
1415  }
1416  }
1417 
1418  DLLLOCAL QoreValue removeValue(bool for_del) {
1419  if (!assigned)
1420  return QoreValue();
1421  assigned = false;
1422  assert(!static_assignment);
1423 
1424  switch (type) {
1425  case QV_Bool:
1426  return for_del ? QoreValue() : QoreValue(v.b);
1427  case QV_Int:
1428  return for_del ? QoreValue() : QoreValue(v.i);
1429  case QV_Float:
1430  return for_del ? QoreValue() : QoreValue(v.f);
1431  case QV_Node:
1432  if (!is_closure)
1433  check_lvalue_object_in_out(0, v.n);
1434  return v.n;
1435  default:
1436  assert(false);
1437  // no break
1438  }
1439  return QoreValue();
1440  }
1441 };
1442 
1443 typedef QoreLValue<> QoreLValueGeneric;
1444 
1445 #endif
NT_NUMBER
const qore_type_t NT_NUMBER
type value for QoreNumberNode
Definition: node_types.h:53
detail::QoreValueCastHelper
used in QoreValue::get()
Definition: QoreValue.h:67
QoreValue
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
NT_NOTHING
const qore_type_t NT_NOTHING
type value for QoreNothingNode
Definition: node_types.h:42
NT_BOOLEAN
const qore_type_t NT_BOOLEAN
type value for bools (QoreValue only)
Definition: node_types.h:47
AbstractQoreNode::getAsBool
DLLEXPORT bool getAsBool() const
returns the boolean value of the object
QoreNumberNode
Qore's arbitrary-precision number value type, dynamically-allocated only, reference counted.
Definition: QoreNumberNode.h:51
int64
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260
NT_FLOAT
const qore_type_t NT_FLOAT
type value for floating-point values (QoreValue only)
Definition: node_types.h:44
QoreValue::refSelf
DLLEXPORT QoreValue refSelf() const
references the contained value if type == QV_Node, returns itself
NT_INT
const qore_type_t NT_INT
type value for integers (QoreValue only)
Definition: node_types.h:43
AbstractQoreNode::realCopy
virtual DLLEXPORT AbstractQoreNode * realCopy() const =0
returns a copy of the object; the caller owns the reference count
is_nothing
static bool is_nothing(const AbstractQoreNode *n)
to check if an AbstractQoreNode object is NOTHING
Definition: QoreLib.h:316
QoreValue::takeIfNode
DLLEXPORT AbstractQoreNode * takeIfNode()
returns a referenced value; leaving the "this" untouched; the caller owns the reference returned
ExceptionSink
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
AbstractQoreNode::getAsFloat
DLLEXPORT double getAsFloat() const
returns the float value of the object
AbstractQoreNode
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
qore_type_t
int16_t qore_type_t
used to identify unique Qore data and parse types (descendents of AbstractQoreNode)
Definition: common.h:70
AbstractQoreNode::getAsBigInt
DLLEXPORT int64 getAsBigInt() const
returns the 64-bit integer value of the object
discard
static void discard(AbstractQoreNode *n, ExceptionSink *xsink)
to deref an AbstractQoreNode (when the pointer may be 0)
Definition: QoreLib.h:324