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