Qore Programming Language  0.9.16
Variable.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  Variable.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_VARIABLE_H
33 #define _QORE_VARIABLE_H
34 
35 enum qore_var_t {
36  VT_UNRESOLVED = 1,
37  VT_LOCAL = 2,
38  VT_GLOBAL = 3,
39  VT_CLOSURE = 4,
40  VT_LOCAL_TS = 5, // thread-safe variables, not closure-bound
41  VT_IMMEDIATE = 6, // used in references with immediate variable storage
42  VT_GLOBAL_THREAD_LOCAL = 7
43 };
44 
45 #include "qore/intern/RSet.h"
46 #include "qore/intern/VRMutex.h"
47 #include "qore/intern/QoreLValue.h"
48 #include "qore/intern/qore_var_rwlock_priv.h"
49 #include "qore/vector_set"
50 
51 #include <cstdlib>
52 #include <cstring>
53 #include <memory>
54 #include <set>
55 #include <string>
56 
57 // forward references
58 class Var;
59 class ScopedObjectCallNode;
60 class QoreSquareBracketsOperatorNode;
61 class QoreSquareBracketsRangeOperatorNode;
62 class QoreHashObjectDereferenceOperatorNode;
63 
64 union qore_gvar_ref_u {
65  bool b;
66  int64 i;
67  double f;
69  // note that the "readonly" flag is stored in bit 0 of this pointer - do not read directly
70  size_t _refptr;
71 
72  DLLLOCAL void setPtr(Var* refptr, bool readonly = false) {
73  _refptr = (size_t)refptr;
74  if (readonly)
75  _refptr |= 1;
76  }
77 
78  DLLLOCAL Var* getPtr() const {
79 #ifndef HAVE_LLVM_BUG_22050
80  // there is a bug in clang++ 3.5.[0|1] where the conditional expression below is executed with the opposite expressions
81  // when compiled with -O1 or greater: http://llvm.org/bugs/show_bug.cgi?id=22050
82  return (Var*)((_refptr & 1L) ? (_refptr ^ 1L) : _refptr);
83 #else
84  return (Var*)(_refptr & (~1L));
85 #endif
86  }
87 
88  DLLLOCAL bool isReadOnly() const {
89  return _refptr & 1;
90  }
91 
92  // checks if the reference can be written to, returns -1 if an exception was thrown
93  DLLLOCAL int write(ExceptionSink* xsink) const;
94 };
95 
96 class LValueHelper;
97 class LValueRemoveHelper;
98 class RSetHelper;
99 
100 // structure for global variables
101 class Var : protected QoreReferenceCounter {
102 private:
103  const QoreProgramLocation* loc; // location of the initial definition
104  QoreLValue<qore_gvar_ref_u> val;
105  std::string name;
106  mutable QoreVarRWLock rwl;
107  QoreParseTypeInfo* parseTypeInfo;
108  const QoreTypeInfo* typeInfo;
109  const QoreTypeInfo* refTypeInfo = nullptr;
110  bool pub, // is this global var public (valid and set for modules only)
111  finalized; // has this var already been cleared during Program destruction?
112 
113  DLLLOCAL void del(ExceptionSink* xsink);
114 
115  // not implemented
116  Var(const Var&) = delete;
117 
118 protected:
119  bool builtin = false;
120 
121  DLLLOCAL ~Var() { delete parseTypeInfo; }
122 
123  DLLLOCAL int checkFinalized(ExceptionSink* xsink) const {
124  if (finalized) {
125  xsink->raiseException("DESTRUCTOR-ERROR", "illegal variable assignment after second phase of variable destruction");
126  return -1;
127  }
128  return 0;
129  }
130 
131 public:
132  DLLLOCAL Var(const QoreProgramLocation* loc, const char* n_name) : loc(loc), val(QV_Node), name(n_name), parseTypeInfo(nullptr), typeInfo(nullptr), pub(false), finalized(false) {
133  }
134 
135  DLLLOCAL Var(const QoreProgramLocation* loc, const char* n_name, QoreParseTypeInfo *n_parseTypeInfo) : loc(loc), val(QV_Node), name(n_name), parseTypeInfo(n_parseTypeInfo), typeInfo(0), pub(false), finalized(false) {
136  }
137 
138  DLLLOCAL Var(const QoreProgramLocation* loc, const char* n_name, const QoreTypeInfo *n_typeInfo, bool builtin = false) : loc(loc), val(n_typeInfo), name(n_name), parseTypeInfo(nullptr), typeInfo(n_typeInfo), pub(false), finalized(false), builtin(builtin) {
139  }
140 
141  DLLLOCAL Var(Var* ref, bool ro = false) : loc(ref->loc), val(QV_Ref), name(ref->name), parseTypeInfo(nullptr), typeInfo(ref->typeInfo), pub(false), finalized(false) {
142  ref->ROreference();
143  val.v.setPtr(ref, ro);
144  }
145 
146  DLLLOCAL const char* getName() const;
147 
148  DLLLOCAL const std::string& getNameStr() const {
149  return name;
150  }
151 
152  DLLLOCAL bool isBuiltin() const {
153  return builtin;
154  }
155 
156  DLLLOCAL int getLValue(LValueHelper& lvh, bool for_remove) const;
157  DLLLOCAL void remove(LValueRemoveHelper& lvrh);
158 
159  DLLLOCAL void clearLocal(ExceptionSink* xsink) {
160  if (val.type != QV_Ref) {
161  ValueHolder h(xsink);
162  QoreAutoVarRWWriteLocker al(rwl);
163  if (!finalized)
164  finalized = true;
165  printd(5, "Var::clearLocal() clearing '%s' %p\n", name.c_str(), this);
166  {
167  QoreProgram* pgm = getProgram();
168  // when Qore is terminating, this may be nullptr
169  if (pgm && (pgm->getParseOptions64() & PO_STRICT_TYPES)) {
170  h = val.assign(QoreTypeInfo::getDefaultQoreValue(typeInfo));
171  } else {
172  h = val.removeValue(true);
173  }
174  }
175  }
176 #ifdef DEBUG
177  else
178  printd(5, "Var::clearLocal() skipping imported var '%s' %p\n", name.c_str(), this);
179 #endif
180  }
181 
182  DLLLOCAL void setInitial(AbstractQoreNode* v) {
183  assert(val.type == QV_Node);
184  // try to set an optimized value type for the value holder if possible
185  val.set(typeInfo);
186  discard(val.assignInitial(v), nullptr);
187  }
188 
189  DLLLOCAL const Var* parseGetVar() const {
190  return (val.type == QV_Ref) ? val.v.getPtr()->parseGetVar() : this;
191  }
192 
193  DLLLOCAL bool isImported() const;
194 
195  DLLLOCAL void deref(ExceptionSink* xsink);
196 
197  DLLLOCAL QoreValue eval() const;
198 
199  DLLLOCAL void doDoubleDeclarationError(const QoreProgramLocation* loc) {
200  // make sure types are identical or throw an exception
201  if (parseTypeInfo) {
202  parse_error(*loc, "global variable '%s' previously declared with type '%s'", name.c_str(), QoreParseTypeInfo::getName(parseTypeInfo));
203  assert(!typeInfo);
204  }
205  if (typeInfo) {
206  parse_error(*loc, "global variable '%s' previously declared with type '%s'", name.c_str(), QoreTypeInfo::getName(typeInfo));
207  assert(!parseTypeInfo);
208  }
209  }
210 
211  DLLLOCAL void checkAssignType(const QoreProgramLocation* loc, const QoreTypeInfo *n_typeInfo) {
212  //printd(5, "Var::parseCheckAssignType() this=%p %s: type=%s %s new type=%s %s\n", this, name.c_str(), typeInfo->getTypeName(), typeInfo->getCID(), n_typeInfo->getTypeName(), n_typeInfo->getCID());
213  if (!QoreTypeInfo::hasType(n_typeInfo))
214  return;
215 
216  if (val.type == QV_Ref) {
217  val.v.getPtr()->checkAssignType(loc, n_typeInfo);
218  return;
219  }
220 
221  // here we know that n_typeInfo is not null
222  // if no previous type was declared, take the new type
223  if (parseTypeInfo || typeInfo) {
224  doDoubleDeclarationError(loc);
225  return;
226  }
227 
228  typeInfo = n_typeInfo;
229  refTypeInfo = QoreTypeInfo::getReferenceTarget(typeInfo);
230 
231  assert(!val.removeValue(true));
232  }
233 
234  DLLLOCAL void parseInit() {
235  if (val.type == QV_Ref)
236  return;
237 
238  if (parseTypeInfo) {
239  typeInfo = QoreParseTypeInfo::resolveAndDelete(parseTypeInfo, loc);
240  refTypeInfo = QoreTypeInfo::getReferenceTarget(typeInfo);
241  parseTypeInfo = nullptr;
242 
243  val.set(typeInfo);
244  }
245 
246  if ((getProgram()->getParseOptions64() & PO_STRICT_TYPES) && !val.hasValue()) {
247  discard(val.assignInitial(QoreTypeInfo::getDefaultQoreValue(typeInfo)), nullptr);
248  }
249  }
250 
251  DLLLOCAL QoreParseTypeInfo* copyParseTypeInfo() const {
252  return parseTypeInfo ? parseTypeInfo->copy() : nullptr;
253  }
254 
255  DLLLOCAL const QoreTypeInfo* parseGetTypeInfoForInitialAssignment() {
256  // imported variables have already been initialized
257  if (val.type == QV_Ref)
258  return val.v.getPtr()->getTypeInfo();
259 
260  parseInit();
261  return typeInfo;
262  }
263 
264  DLLLOCAL const QoreTypeInfo* parseGetTypeInfo() {
265  // imported variables have already been initialized
266  if (val.type == QV_Ref)
267  return val.v.getPtr()->getTypeInfo();
268 
269  parseInit();
270  return refTypeInfo ? refTypeInfo : typeInfo;
271  }
272 
273  DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
274  assert(!parseTypeInfo);
275  if (val.type == QV_Ref)
276  return val.v.getPtr()->getTypeInfo();
277 
278  return typeInfo;
279  }
280 
281  DLLLOCAL bool hasTypeInfo() const {
282  if (val.type == QV_Ref)
283  return val.v.getPtr()->hasTypeInfo();
284 
285  return parseTypeInfo || typeInfo;
286  }
287 
288  DLLLOCAL bool isRef() const {
289  return val.type == QV_Ref;
290  }
291 
292  // only called with a new object declaration expression (ie our <class> $x())
293  DLLLOCAL const char* getClassName() const {
294  if (val.type == QV_Ref)
295  return val.v.getPtr()->getClassName();
296 
297  if (typeInfo) {
298  assert(QoreTypeInfo::getUniqueReturnClass(typeInfo));
299  return QoreTypeInfo::getUniqueReturnClass(typeInfo)->getName();
300  }
301  assert(parseTypeInfo);
302  assert(parseTypeInfo->cscope);
303  return parseTypeInfo->cscope->getIdentifier();
304  }
305 
306  DLLLOCAL bool isPublic() const {
307  return pub;
308  }
309 
310  DLLLOCAL void setPublic() {
311  assert(!pub);
312  pub = true;
313  }
314 
315  DLLLOCAL const QoreProgramLocation* getParseLocation() const {
316  return loc;
317  }
318 };
319 
320 DLLLOCAL void delete_global_variables();
321 
322 DLLLOCAL extern QoreHashNode *ENV;
323 
324 //typedef std::set<const void*> lvid_set_t;
325 typedef vector_set_t<const void*> lvid_set_t;
326 
327 // track obj count changes
328 hashdecl ObjCountRec {
329  // container
330  const AbstractQoreNode* con;
331  // initial count (true = possible recursive cycle, false = no cycle possible)
332  bool before;
333 
334  DLLLOCAL ObjCountRec(const QoreListNode* c);
335  DLLLOCAL ObjCountRec(const QoreHashNode* c);
336  DLLLOCAL ObjCountRec(const QoreObject* c);
337  DLLLOCAL int getDifference();
338 };
339 
340 typedef std::vector<ObjCountRec> ocvec_t;
341 
342 // this class grabs global variable or object locks for the duration of the scope of the object
343 // no evaluations can be done while this object is in scope or a deadlock may result
344 class LValueHelper {
345  friend class LValueRemoveHelper;
346  friend class LValueLockHandoffHelper;
347 
348 private:
349  // not implemented
350  DLLLOCAL LValueHelper(const LValueHelper&) = delete;
351  DLLLOCAL LValueHelper& operator=(const LValueHelper&) = delete;
352 
353 protected:
354  DLLLOCAL void assignNodeIntern(AbstractQoreNode* n) {
355  //printd(5, "LValueHelper::assignNodeIntern() this: %p n: %p '%s'\n", this, n, get_type_name(n));
356 
357  assert(val || qv);
358  if (val)
359  val->assign(n);
360  else
361  *qv = n;
362  }
363 
364  DLLLOCAL int doListLValue(const QoreSquareBracketsOperatorNode* op, bool for_remove);
365  DLLLOCAL int doHashLValue(qore_type_t t, const char* mem, bool for_remove);
366  DLLLOCAL int doHashObjLValue(const QoreHashObjectDereferenceOperatorNode* op, bool for_remove);
367 
368  DLLLOCAL int makeInt(const char* desc);
369  DLLLOCAL int makeFloat(const char* desc);
370  DLLLOCAL int makeNumber(const char* desc);
371 
372  DLLLOCAL int doRecursiveException() {
373  vl.xsink->raiseException("REFERENCE-ERROR", "recursive reference detected in assignment");
374  return -1;
375  }
376 
377 public:
378  AutoVLock vl;
379  //AbstractQoreNode** v = nullptr; // ptr to ptr for lvalue expression
380 
381 private:
382  typedef std::vector<AbstractQoreNode*> nvec_t;
383  nvec_t tvec;
384  lvid_set_t* lvid_set = nullptr;
385  // to track object count changes
386  ocvec_t ocvec;
387 
388  // flag if the changed value was a container before the assignment
389  bool before = false;
390 
391  // recursive delta: change to recursive reference count
392  int rdt = 0;
393 
394  RObject* robj = nullptr;
395 
396 public:
397  QoreLValueGeneric* val = nullptr;
398  QoreValue* qv = nullptr;
399  const QoreTypeInfo* typeInfo = nullptr;
400 
401  DLLLOCAL LValueHelper(const ReferenceNode& ref, ExceptionSink* xsink, bool for_remove = false);
402  DLLLOCAL LValueHelper(QoreValue exp, ExceptionSink* xsink, bool for_remove = false);
403 
404  DLLLOCAL LValueHelper(ExceptionSink* xsink);
405 
406  DLLLOCAL LValueHelper(LValueHelper&& o);
407 
408  // to scan objects after initialization
409  DLLLOCAL LValueHelper(QoreObject& obj, ExceptionSink* xsink);
410 
411  DLLLOCAL ~LValueHelper();
412 
413  DLLLOCAL void setClosure(RObject* c) {
414  robj = c;
415  }
416 
417  DLLLOCAL void saveTemp(QoreValue n);
418 
419  DLLLOCAL AbstractQoreNode*& getTempRef() {
420  tvec.push_back(0);
421  return tvec[tvec.size() - 1];
422  }
423 
424  DLLLOCAL int doLValue(const QoreValue exp, bool for_remove);
425 
426  DLLLOCAL int doLValue(const ReferenceNode* ref, bool for_remove);
427 
428  DLLLOCAL void setAndLock(QoreVarRWLock& rwl);
429  DLLLOCAL void set(QoreVarRWLock& rwl);
430 
431  DLLLOCAL AutoVLock& getAutoVLock() {
432  return vl;
433  }
434 
435  DLLLOCAL void setTypeInfo(const QoreTypeInfo* ti) {
436  typeInfo = ti;
437  }
438 
439  DLLLOCAL void setValue(QoreLValueGeneric& nv, const QoreTypeInfo* ti = nullptr) {
440  //printd(5, "LValueHelper::setValue() this: %p new val: %p\n", this, &nv);
441 
442  assert(!val);
443  assert(!qv);
444  val = &nv;
445 
446  before = nv.assigned && nv.type == QV_Node ? needs_scan(nv.v.n) : false;
447 
448  typeInfo = ti;
449  }
450 
451  DLLLOCAL void setValue(QoreValue& nqv, const QoreTypeInfo* ti = nullptr) {
452  //printd(5, "LValueHelper::setValue() this: %p new qv: %p\n", this, &nqv);
453  assert(!val);
454  assert(!qv);
455  qv = &nqv;
456 
457  before = needs_scan(nqv);
458 
459  typeInfo = ti;
460  }
461 
462  DLLLOCAL void resetValue(QoreLValueGeneric& nv, const QoreTypeInfo* ti = nullptr) {
463  //printd(5, "LValueHelper::resetValue() this: %p new val: %p\n", this, &nv);
464  if (qv) {
465  qv = nullptr;
466  }
467  else {
468  assert(val);
469  }
470  val = &nv;
471 
472  before = nv.assigned && nv.type == QV_Node ? needs_scan(nv.v.n) : false;
473 
474  typeInfo = ti;
475  }
476 
477  DLLLOCAL void resetValue(QoreValue& nqv, const QoreTypeInfo* ti = nullptr) {
478  //printd(5, "LValueHelper::resetValue() this: %p new qv: %p\n", this, &nqv);
479  if (val) {
480  val = nullptr;
481  }
482  else {
483  assert(qv);
484  }
485  qv = &nqv;
486 
487  before = needs_scan(nqv);
488 
489  typeInfo = ti;
490  }
491 
492  DLLLOCAL void clearPtr() {
493  if (val)
494  val = nullptr;
495  else if (qv)
496  qv = nullptr;
497  typeInfo = nullptr;
498  before = false;
499  }
500 
501  DLLLOCAL operator bool() const {
502  return val || qv;
503  }
504 
505  DLLLOCAL bool isOptimized() const {
506  return val && val->optimized();
507  }
508 
509  DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
510  return typeInfo;
511  }
512 
513  DLLLOCAL qore_type_t getType() const {
514  return val ? val->getType() : qv->getType();
515  }
516 
517  DLLLOCAL const QoreValue getValue() const {
518  return val ? val->getValue() : *qv;
519  }
520 
521  DLLLOCAL QoreValue getValue() {
522  return val ? val->getValue() : *qv;
523  }
524 
525  DLLLOCAL AbstractQoreNode* getNodeValue() {
526  assert((val && val->getInternalNode()) || (qv && qv->getInternalNode()));
527  return val ? val->getInternalNode() : qv->getInternalNode();
528  }
529 
530  DLLLOCAL const char* getTypeName() const {
531  return val ? val->getTypeName() : qv->getTypeName();
532  }
533 
534  DLLLOCAL bool checkType(const qore_type_t t) const {
535  return getType() == t;
536  }
537 
538  DLLLOCAL bool isNothing() const {
539  return checkType(NT_NOTHING);
540  }
541 
542  DLLLOCAL void setObjectContext(qore_object_private* obj);
543 
544  DLLLOCAL QoreValue getReferencedValue() const;
545 
546  // only call if there is a reference-counted AbstractQoreNode value in place
547  // FIXME: port operators to LValueHelper instead and remove this function
548  DLLLOCAL void ensureUnique() {
549  AbstractQoreNode* current_value = getNodeValue();
550  assert(current_value && current_value->getType() != NT_OBJECT);
551 
552  if (!current_value->is_unique()) {
553  //printd(5, "LValueHelper::ensureUnique() this: %p saving old value: %p '%s'\n", this, current_value, get_type_name(current_value));
554  AbstractQoreNode* old = current_value;
555  assignNodeIntern(current_value->realCopy());
556  saveTemp(old);
557  }
558  }
559 
560  DLLLOCAL int64 getAsBigInt() const;
561  DLLLOCAL bool getAsBool() const;
562  DLLLOCAL double getAsFloat() const;
563 
564  DLLLOCAL int64 plusEqualsBigInt(int64 v, const char* desc = "<lvalue>");
565  DLLLOCAL int64 minusEqualsBigInt(int64 v, const char* desc = "<lvalue>");
566  DLLLOCAL int64 multiplyEqualsBigInt(int64 v, const char* desc = "<lvalue>");
567  DLLLOCAL int64 divideEqualsBigInt(int64 v, const char* desc = "<lvalue>");
568  DLLLOCAL int64 orEqualsBigInt(int64 v, const char* desc = "<lvalue>");
569  DLLLOCAL int64 andEqualsBigInt(int64 v, const char* desc = "<lvalue>");
570  DLLLOCAL int64 xorEqualsBigInt(int64 v, const char* desc = "<lvalue>");
571  DLLLOCAL int64 modulaEqualsBigInt(int64 v, const char* desc = "<lvalue>");
572  DLLLOCAL int64 shiftLeftEqualsBigInt(int64 v, const char* desc = "<lvalue>");
573  DLLLOCAL int64 shiftRightEqualsBigInt(int64 v, const char* desc = "<lvalue>");
574  DLLLOCAL int64 preIncrementBigInt(const char* desc = "<lvalue>");
575  DLLLOCAL int64 preDecrementBigInt(const char* desc = "<lvalue>");
576  DLLLOCAL int64 postIncrementBigInt(const char* desc = "<lvalue>");
577  DLLLOCAL int64 postDecrementBigInt(const char* desc = "<lvalue>");
578 
579  DLLLOCAL double plusEqualsFloat(double v, const char* desc = "<lvalue>");
580  DLLLOCAL double minusEqualsFloat(double v, const char* desc = "<lvalue>");
581  DLLLOCAL double multiplyEqualsFloat(double v, const char* desc = "<lvalue>");
582  DLLLOCAL double divideEqualsFloat(double v, const char* desc = "<lvalue>");
583  DLLLOCAL double preIncrementFloat(const char* desc = "<lvalue>");
584  DLLLOCAL double preDecrementFloat(const char* desc = "<lvalue>");
585  DLLLOCAL double postIncrementFloat(const char* desc = "<lvalue>");
586  DLLLOCAL double postDecrementFloat(const char* desc = "<lvalue>");
587 
588  DLLLOCAL void plusEqualsNumber(QoreValue r, const char* desc = "<lvalue>");
589  DLLLOCAL void minusEqualsNumber(QoreValue r, const char* desc = "<lvalue>");
590  DLLLOCAL void multiplyEqualsNumber(QoreValue r, const char* desc = "<lvalue>");
591  DLLLOCAL void divideEqualsNumber(QoreValue r, const char* desc = "<lvalue>");
592  DLLLOCAL void preIncrementNumber(const char* desc = "<lvalue>");
593  DLLLOCAL void preDecrementNumber(const char* desc = "<lvalue>");
594  DLLLOCAL QoreNumberNode* postIncrementNumber(bool ref_rv, const char* desc = "<lvalue>");
595  DLLLOCAL QoreNumberNode* postDecrementNumber(bool ref_rv, const char* desc = "<lvalue>");
596 
597  DLLLOCAL QoreNumberNode* ensureUniqueNumber(const char* desc = "<lvalue>") {
598  AbstractQoreNode** p;
599  if (val) {
600  if (makeNumber(desc))
601  return nullptr;
602  p = &val->v.n;
603  }
604  else {
605  assert(qv);
606  if (makeNumber(desc))
607  return nullptr;
608  p = &qv->v.n;
609  }
610 
611  assert(get_node_type(*p) == NT_NUMBER);
612  if (!(*p)->is_unique()) {
613  AbstractQoreNode* old = (*p);
614  (*p) = (*p)->realCopy();
615  saveTemp(old);
616  }
617  return reinterpret_cast<QoreNumberNode*>(*p);
618  }
619 
620  DLLLOCAL int assign(QoreValue val, const char* desc = "<lvalue>", bool check_types = true, bool weak_assignment = false);
621 
622  DLLLOCAL QoreValue removeValue(bool for_del);
623  DLLLOCAL QoreValue remove(bool& static_assignment);
624 
625  DLLLOCAL void setDelta(int dt) {
626  assert(!rdt);
627  rdt = dt;
628  }
629 };
630 
631 class LValueRemoveHelper {
632 private:
633  // not implemented
634  LValueRemoveHelper(const LValueRemoveHelper&) = delete;
635  LValueRemoveHelper& operator=(const LValueRemoveHelper&) = delete;
636  void* operator new(size_t) = delete;
637 
638  DLLLOCAL void doRemove(const QoreSquareBracketsOperatorNode* op);
639  DLLLOCAL void doRemove(const QoreSquareBracketsOperatorNode* op, const QoreParseListNode* l);
640  DLLLOCAL void doRemove(const QoreSquareBracketsRangeOperatorNode* op);
641 
642 protected:
643  ExceptionSink* xsink;
644  QoreLValueGeneric rv;
645  bool for_del,
646  direct_list = false;
647 
648 public:
649  DLLLOCAL LValueRemoveHelper(const ReferenceNode& ref, ExceptionSink* n_xsink, bool fd);
650  DLLLOCAL LValueRemoveHelper(const QoreValue exp, ExceptionSink* n_xsink, bool fd);
651 
652  DLLLOCAL void doRemove(QoreValue exp);
653 
654  DLLLOCAL operator bool() const {
655  return !*xsink;
656  }
657 
658  DLLLOCAL ExceptionSink* getExceptionSink() const {
659  return xsink;
660  }
661 
662  DLLLOCAL bool forDel() const {
663  return for_del;
664  }
665 
666  DLLLOCAL void doRemove(QoreLValueGeneric& qv, const QoreTypeInfo* ti) {
667  QoreProgram* pgm = getProgram();
668  // when Qore is terminating, this may be nullptr
669  if (pgm && (pgm->getParseOptions64() & PO_STRICT_TYPES)) {
670  rv.assignSetTakeInitial(qv, QoreTypeInfo::getDefaultQoreValue(ti));
671  } else {
672  rv.assignSetTakeInitial(qv);
673  }
674  }
675 
676  DLLLOCAL QoreValue removeValue();
677  DLLLOCAL QoreValue remove(bool& static_assignment);
678 
679  DLLLOCAL void deleteLValue();
680 };
681 
682 #endif // _QORE_VARIABLE_H
NT_NUMBER
const qore_type_t NT_NUMBER
type value for QoreNumberNode
Definition: node_types.h:53
NT_OBJECT
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
QoreProgram
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only
Definition: QoreProgram.h:126
QoreValue
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
QoreHashNode
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
NT_NOTHING
const qore_type_t NT_NOTHING
type value for QoreNothingNode
Definition: node_types.h:42
AbstractQoreNode::getType
DLLLOCAL qore_type_t getType() const
returns the data type
Definition: AbstractQoreNode.h:172
QoreListNode
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
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
PO_STRICT_TYPES
#define PO_STRICT_TYPES
enforce strict type checking and setting default values
Definition: Restrictions.h:98
QoreProgram::getParseOptions64
DLLEXPORT int64 getParseOptions64() const
returns the parse options currently set for this program
ExceptionSink::raiseException
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
AbstractQoreNode::realCopy
virtual DLLEXPORT AbstractQoreNode * realCopy() const =0
returns a copy of the object; the caller owns the reference count
ReferenceNode
parse type: reference to a lvalue expression
Definition: ReferenceNode.h:45
QoreObject
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:61
ExceptionSink
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
QoreReferenceCounter
provides atomic reference counting to Qore objects
Definition: QoreReferenceCounter.h:44
QoreReferenceCounter::is_unique
DLLEXPORT bool is_unique() const
returns true if the reference count is 1
ValueHolder
holds an object and dereferences it in the destructor
Definition: QoreValue.h:452
getProgram
DLLEXPORT QoreProgram * getProgram()
returns the current QoreProgram
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
discard
static void discard(AbstractQoreNode *n, ExceptionSink *xsink)
to deref an AbstractQoreNode (when the pointer may be 0)
Definition: QoreLib.h:324
AutoVLock
AutoVLock is a container for safely managing global variable and object lock handovers,...
Definition: AutoVLock.h:80