Qore Programming Language 2.0.0
Loading...
Searching...
No Matches
LocalVar.h
1/* -*- mode: c++; indent-tabs-mode: nil -*- */
2/*
3 LocalVar.h
4
5 Qore Programming Language
6
7 Copyright (C) 2003 - 2024 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_LOCALVAR_H
33
34#define _QORE_LOCALVAR_H
35
36#include "qore/intern/qore_thread_intern.h"
37#include "qore/intern/QoreLValue.h"
38#include "qore/intern/RSection.h"
39#include "qore/intern/RSet.h"
40#include "qore/ReferenceNode.h"
41#include "qore/intern/WeakReferenceNode.h"
42#include "qore/intern/WeakHashReferenceNode.h"
43#include "qore/intern/WeakListReferenceNode.h"
44
45#include <atomic>
46
47template <class T>
48class LocalRefHelper : public RuntimeReferenceHelper {
49protected:
50 // used to skip the var entry in case it's a recursive reference
51 bool valid;
52
53public:
54 DLLLOCAL LocalRefHelper(const T* val, ReferenceNode& ref, ExceptionSink* xsink)
55 : RuntimeReferenceHelper(ref, xsink),
56 valid(!*xsink) {
57 }
58
59 DLLLOCAL operator bool() const {
60 return valid;
61 }
62};
63
64template <class T>
65class LValueRefHelper : public LocalRefHelper<T> {
66protected:
67 LValueHelper* valp;
68
69public:
70 DLLLOCAL LValueRefHelper(T* val, ExceptionSink* xsink) : LocalRefHelper<T>(val, xsink),
71 valp(this->valid ? new LValueHelper(*((ReferenceNode*)val->v.n), xsink) : nullptr) {
72 }
73
74 DLLLOCAL ~LValueRefHelper() {
75 delete valp;
76 }
77
78 DLLLOCAL operator bool() const {
79 return valp;
80 }
81
82 DLLLOCAL LValueHelper* operator->() {
83 return valp;
84 }
85};
86
87class VarValueBase {
88protected:
89 DLLLOCAL int checkFinalized(ExceptionSink* xsink) const {
90 if (finalized) {
91 xsink->raiseException("DESTRUCTOR-ERROR", "illegal variable assignment after second phase of variable "
92 "destruction");
93 return -1;
94 }
95 return 0;
96 }
97
98public:
99 QoreLValueGeneric val;
100 const char* id;
101 bool finalized : 1;
102 bool frame_boundary : 1;
103
104 DLLLOCAL VarValueBase(const char* n_id, valtype_t t = QV_Node) : val(t), id(n_id), finalized(false), frame_boundary(false) {
105 }
106
107 DLLLOCAL VarValueBase(const char* n_id, const QoreTypeInfo* varTypeInfo) : val(varTypeInfo), id(n_id), finalized(false), frame_boundary(false) {
108 }
109
110 DLLLOCAL VarValueBase() : val(QV_Bool), id(nullptr), finalized(false), frame_boundary(false) {
111 }
112
113 DLLLOCAL void setFrameBoundary() {
114 assert(!frame_boundary);
115 frame_boundary = true;
116 }
117
118 DLLLOCAL void del(ExceptionSink* xsink) {
119 val.removeValue(true).discard(xsink);
120 }
121
122 DLLLOCAL bool isRef() const {
123 return val.getType() == NT_REFERENCE;
124 }
125
126 DLLLOCAL QoreValue finalize() {
127 if (finalized)
128 return QoreValue();
129
130 finalized = true;
131
132 return val.removeValue(true);
133 }
134};
135
136class LocalVarValue : public VarValueBase {
137public:
138 DLLLOCAL void set(const char* n_id, const QoreTypeInfo* varTypeInfo, QoreValue nval, bool assign,
139 bool static_assignment) {
140 //printd(5, "LocalVarValue::set() this: %p id: '%s' type: '%s' code: %d static_assignment: %d\n", this, n_id,
141 // QoreTypeInfo::getName(typeInfo), nval.getType(), static_assignment);
142 assert(!finalized);
143
144 id = n_id;
145
146 // try to set an optimized value type for the value holder if possible
147 val.set(varTypeInfo);
148
149 // no exception is possible here as there was no previous value
150 // also since only basic value types could be returned, no exceptions can occur with the value passed either
151 if (assign) {
152 discard(val.assignAssumeInitial(nval, static_assignment), nullptr);
153 } else {
154 assert(!val.assigned);
155 assert(!nval);
156 }
157 }
158
159 DLLLOCAL void uninstantiate(ExceptionSink* xsink) {
160 del(xsink);
161 }
162
163 DLLLOCAL void uninstantiateSelf() {
164 val.unassignIgnore();
165 }
166
167 DLLLOCAL int getLValue(LValueHelper& lvh, bool for_remove, const QoreTypeInfo* typeInfo,
168 const QoreTypeInfo* refTypeInfo) const;
169 DLLLOCAL void remove(LValueRemoveHelper& lvrh, const QoreTypeInfo* typeInfo);
170
171 DLLLOCAL QoreValue eval(bool& needs_deref, ExceptionSink* xsink) const {
172 //printd(5, "LocalVarValue::eval() this: %p '%s' type: %d '%s'\n", this, id, val.getType(),
173 // val.getTypeName());
174 if (val.getType() == NT_REFERENCE) {
175 ReferenceNode* ref = const_cast<ReferenceNode*>(val.get<ReferenceNode>());
176 LocalRefHelper<LocalVarValue> helper(this, *ref, xsink);
177 if (!helper)
178 return QoreValue();
179
180 ValueEvalOptimizedRefHolder erh(lvalue_ref::get(ref)->vexp, xsink);
181 return erh.takeValue(needs_deref);
182 }
183
184 if (val.getType() == NT_WEAKREF) {
185 needs_deref = false;
186 return val.get<WeakReferenceNode>()->get();
187 }
188
189 if (val.getType() == NT_WEAKREF_HASH) {
190 needs_deref = false;
191 return val.get<WeakHashReferenceNode>()->get();
192 }
193
194 if (val.getType() == NT_WEAKREF_LIST) {
195 needs_deref = false;
196 return val.get<WeakListReferenceNode>()->get();
197 }
198
199 return val.getReferencedValue(needs_deref);
200 }
201
202 DLLLOCAL QoreValue eval(ExceptionSink* xsink) const {
203 if (val.getType() == NT_REFERENCE) {
204 ReferenceNode* ref = const_cast<ReferenceNode*>(val.get<ReferenceNode>());
205 LocalRefHelper<LocalVarValue> helper(this, *ref, xsink);
206 if (!helper)
207 return QoreValue();
208
209 ValueEvalOptimizedRefHolder erh(lvalue_ref::get(ref)->vexp, xsink);
210 return *xsink ? QoreValue() : erh.takeReferencedValue();
211 }
212
213 if (val.getType() == NT_WEAKREF) {
214 return val.get<WeakReferenceNode>()->get()->refSelf();
215 }
216
217 if (val.getType() == NT_WEAKREF_HASH) {
218 return val.get<WeakHashReferenceNode>()->get()->refSelf();
219 }
220
221 if (val.getType() == NT_WEAKREF_LIST) {
222 return val.get<WeakListReferenceNode>()->get()->refSelf();
223 }
224
225 return val.getReferencedValue();
226 }
227};
228
229hashdecl ClosureVarValue : public VarValueBase, public RObject {
230public:
231 const QoreTypeInfo* typeInfo = nullptr; // type restriction for lvalue
232 const QoreTypeInfo* refTypeInfo;
233 // reference count; access serialized with rlck from RObject
234 mutable std::atomic_int references;
235
236 DLLLOCAL ClosureVarValue(const char* n_id, const QoreTypeInfo* varTypeInfo, QoreValue& nval, bool assign) : VarValueBase(n_id, varTypeInfo), RObject(references), typeInfo(varTypeInfo), refTypeInfo(QoreTypeInfo::getReferenceTarget(varTypeInfo)), references(1) {
237 //printd(5, "ClosureVarValue::ClosureVarValue() this: %p refs: 0 -> 1 val: %s\n", this, val.getTypeName());
238 val.setClosure();
239
240 // try to set an optimized value type for the value holder if possible
241 val.set(varTypeInfo);
242
243 //printd(5, "ClosureVarValue::ClosureVarValue() this: %p pgm: %p val: %s\n", this, getProgram(), nval.getTypeName());
244 // also since only basic value types could be returned, no exceptions can occur with the value passed either
245 if (assign)
246 discard(val.assignAssumeInitial(nval), nullptr);
247#ifdef DEBUG
248 else
249 assert(!val.assigned);
250#endif
251 }
252
253 DLLLOCAL virtual ~ClosureVarValue() {
254 //printd(5, "ClosureVarValue::~ClosureVarValue() this: %p\n", this);
255 }
256
257 DLLLOCAL void ref() const;
258
259 DLLLOCAL void deref(ExceptionSink* xsink);
260
261 DLLLOCAL const void* getLValueId() const;
262
263 // returns true if the value could contain an object or a closure
264 DLLLOCAL virtual bool needsScan(bool scan_now) {
265 return QoreTypeInfo::needsScan(typeInfo);
266 }
267
268 DLLLOCAL virtual bool scanMembers(RSetHelper& rsh);
269
270 DLLLOCAL int getLValue(LValueHelper& lvh, bool for_remove) const;
271 DLLLOCAL void remove(LValueRemoveHelper& lvrh);
272
273 DLLLOCAL ClosureVarValue* refSelf() const {
274 ref();
275 return const_cast<ClosureVarValue*>(this);
276 }
277
278 // sets the current variable to finalized, sets the value to 0, and returns the value held (for dereferencing outside the lock)
279 DLLLOCAL QoreValue finalize() {
280 QoreSafeVarRWWriteLocker sl(rml);
281 return VarValueBase::finalize();
282 }
283
284 DLLLOCAL QoreValue eval(bool& needs_deref, ExceptionSink* xsink) const {
285 QoreSafeVarRWReadLocker sl(rml);
286 if (val.getType() == NT_REFERENCE) {
288 sl.unlock();
289 LocalRefHelper<ClosureVarValue> helper(this, **ref, xsink);
290 return helper ? lvalue_ref::get(*ref)->vexp.eval(needs_deref, xsink) : QoreValue();
291 }
292
293 if (val.getType() == NT_WEAKREF) {
294 needs_deref = false;
295 return val.get<WeakReferenceNode>()->get();
296 }
297
298 if (val.getType() == NT_WEAKREF_HASH) {
299 needs_deref = false;
300 return val.get<WeakHashReferenceNode>()->get();
301 }
302
303 if (val.getType() == NT_WEAKREF_LIST) {
304 needs_deref = false;
305 return val.get<WeakListReferenceNode>()->get();
306 }
307
308 return val.getReferencedValue();
309 }
310
311 DLLLOCAL QoreValue eval(ExceptionSink* xsink) const {
312 QoreSafeVarRWReadLocker sl(rml);
313 if (val.getType() == NT_REFERENCE) {
315 sl.unlock();
316 LocalRefHelper<ClosureVarValue> helper(this, **ref, xsink);
317 return helper ? lvalue_ref::get(*ref)->vexp.eval(xsink) : QoreValue();
318 }
319
320 if (val.getType() == NT_WEAKREF) {
321 return val.get<WeakReferenceNode>()->get()->refSelf();
322 }
323
324 if (val.getType() == NT_WEAKREF_HASH) {
325 return val.get<WeakHashReferenceNode>()->get();
326 }
327
328 if (val.getType() == NT_WEAKREF_LIST) {
329 return val.get<WeakListReferenceNode>()->get();
330 }
331
332 return val.getReferencedValue();
333 }
334
335 DLLLOCAL AbstractQoreNode* getReference(const QoreProgramLocation* loc, const char* name, const void*& lvalue_id);
336
337 // deletes the object itself
338 DLLLOCAL virtual void deleteObject() {
339 delete this;
340 }
341
342 // returns the name of the object
343 DLLLOCAL virtual const char* getName() const {
344 return id;
345 }
346};
347
348// now shared between parent and child Program objects for top-level local variables with global scope
349class LocalVar {
350public:
351 DLLLOCAL LocalVar(const char* n_name, const QoreTypeInfo* ti)
352 : name(n_name), typeInfo(ti), refTypeInfo(QoreTypeInfo::getReferenceTarget(ti)) {
353 }
354
355 DLLLOCAL LocalVar(const LocalVar& old) : name(old.name), closure_use(old.closure_use),
356 parse_assigned(old.parse_assigned), is_self(old.is_self), typeInfo(old.typeInfo),
357 refTypeInfo(old.refTypeInfo) {
358 }
359
360 DLLLOCAL ~LocalVar() {
361 }
362
363 DLLLOCAL void parseAssigned() {
364 if (!parse_assigned) {
365 parse_assigned = true;
366 }
367 }
368
369 DLLLOCAL void parseUnassigned() {
370 if (parse_assigned) {
371 parse_assigned = false;
372 }
373 }
374
375 DLLLOCAL bool isAssigned() const {
376 return parse_assigned;
377 }
378
379 DLLLOCAL void instantiate(int64 parse_options) {
380 if (parse_options & PO_STRICT_TYPES) {
381 //printd(5, "LocalVar::instantiate() this: %p '%s' typeInfo: %s\n", this, name.c_str(),
382 // QoreTypeInfo::getName(typeInfo));
383 instantiateIntern(QoreTypeInfo::getDefaultQoreValue(typeInfo), true);
384 } else {
385 //printd(5, "LocalVar::instantiate() this: %p '%s' typeInfo: %s NO ASSIGNMENT\n", this, name.c_str(),
386 // QoreTypeInfo::getName(typeInfo));
387 instantiateIntern(QoreValue(), false);
388 }
389 }
390
391 DLLLOCAL void instantiate(QoreValue nval) {
392 instantiateIntern(nval, true);
393 }
394
395 DLLLOCAL void instantiateIntern(QoreValue nval, bool assign) {
396 //printd(5, "LocalVar::instantiateIntern(%s, %d) this: %p '%s' value closure_use: %s pgm: %p val: %s "
397 // "type: '%s' rti: '%s'\n", nval.getTypeName(), assign, this, name.c_str(),
398 // closure_use ? "true" : "false", getProgram(), nval.getTypeName(), QoreTypeInfo::getName(typeInfo),
399 // QoreTypeInfo::getName(refTypeInfo));
400
401 if (!closure_use) {
402 LocalVarValue* val = thread_instantiate_lvar();
403 val->set(name.c_str(), typeInfo, nval, assign, false);
404 } else {
405 thread_instantiate_closure_var(name.c_str(), typeInfo, nval, assign);
406 }
407 }
408
409 DLLLOCAL void instantiateSelf(QoreObject* value) const {
410 printd(5, "LocalVar::instantiateSelf(%p) this: %p '%s'\n", value, this, name.c_str());
411 if (!closure_use) {
412 LocalVarValue* val = thread_instantiate_lvar();
413 val->set(name.c_str(), typeInfo, value, true, true);
414 } else {
415 QoreValue val(value->refSelf());
416 thread_instantiate_closure_var(name.c_str(), typeInfo, val, true);
417 }
418 }
419
420 DLLLOCAL void uninstantiate(ExceptionSink* xsink) const {
421 //printd(5, "LocalVar::uninstantiate() this: %p '%s' closure_use: %s pgm: %p\n", this, name.c_str(),
422 // closure_use ? "true" : "false", getProgram());
423
424 if (!closure_use) {
425 thread_uninstantiate_lvar(xsink);
426 } else {
427 thread_uninstantiate_closure_var(xsink);
428 }
429 }
430
431 DLLLOCAL void uninstantiateSelf() const {
432 if (!closure_use) {
433 thread_uninstantiate_self();
434 } else { // cannot go out of scope here, so no destructor can be run, so we pass a nullptr ExceptionSink ptr
435 thread_uninstantiate_closure_var(nullptr);
436 }
437 }
438
439 DLLLOCAL QoreValue eval(bool& needs_deref, ExceptionSink* xsink) const {
440 if (!closure_use) {
441 LocalVarValue* val = get_var();
442 //printd(5, "LocalVar::eval '%s' typeInfo: %p '%s'\n", name.c_str(), typeInfo,
443 // QoreTypeInfo::getName(typeInfo));
444 return val->eval(needs_deref, xsink);
445 }
446
447 ClosureVarValue* val = thread_find_closure_var(name.c_str());
448 return val->eval(needs_deref, xsink);
449 }
450
451 // returns true if the value could contain an object or a closure
452 DLLLOCAL bool needsScan() const {
453 return QoreTypeInfo::needsScan(typeInfo);
454 }
455
456 DLLLOCAL const char* getName() const {
457 return name.c_str();
458 }
459
460 DLLLOCAL const std::string& getNameStr() const {
461 return name;
462 }
463
464 DLLLOCAL void setClosureUse() {
465 closure_use = true;
466 }
467
468 DLLLOCAL bool closureUse() const {
469 return closure_use;
470 }
471
472 DLLLOCAL bool isRef() const {
473 return !closure_use ? get_var()->isRef() : thread_find_closure_var(name.c_str())->isRef();
474 }
475
476 DLLLOCAL int getLValue(LValueHelper& lvh, bool for_remove, bool initial_assignment) const {
477 //printd(5, "LocalVar::getLValue() this: %p '%s' for_remove: %d closure_use: %d ti: '%s' rti: '%s'\n", this,
478 // getName(), for_remove, closure_use, QoreTypeInfo::getName(typeInfo), QoreTypeInfo::getName(refTypeInfo));
479 if (!closure_use) {
480 return get_var()->getLValue(lvh, for_remove, typeInfo, refTypeInfo);
481 }
482
483 return thread_find_closure_var(name.c_str())->getLValue(lvh, for_remove);
484 }
485
486 DLLLOCAL void remove(LValueRemoveHelper& lvrh) {
487 if (!closure_use) {
488 return get_var()->remove(lvrh, typeInfo);
489 }
490
491 return thread_find_closure_var(name.c_str())->remove(lvrh);
492 }
493
494 DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
495 return typeInfo;
496 }
497
498 DLLLOCAL const QoreTypeInfo* parseGetTypeInfo() const {
499 return parse_assigned && refTypeInfo ? refTypeInfo : typeInfo;
500 }
501
502 DLLLOCAL const QoreTypeInfo* parseGetTypeInfoForInitialAssignment() const {
503 return typeInfo;
504 }
505
506 DLLLOCAL qore_type_t getValueType() const {
507 return !closure_use ? get_var()->val.getType() : thread_find_closure_var(name.c_str())->val.getType();
508 }
509
510 DLLLOCAL const char* getValueTypeName() const {
511 return !closure_use ? get_var()->val.getTypeName() : thread_find_closure_var(name.c_str())->val.getTypeName();
512 }
513
514 DLLLOCAL bool isSelf() const {
515 return is_self;
516 }
517
518 DLLLOCAL void setSelf() {
519 assert(!is_self);
520 assert(name == "self");
521 is_self = true;
522 }
523
524private:
525 std::string name;
526 bool closure_use = false,
527 parse_assigned = false,
528 is_self = false;
529 const QoreTypeInfo* typeInfo = nullptr;
530 const QoreTypeInfo* refTypeInfo = nullptr;
531
532 DLLLOCAL LocalVarValue* get_var() const {
533 return thread_find_lvar(name.c_str());
534 }
535};
536
537typedef LocalVar* lvar_ptr_t;
538
539#endif
static void discard(AbstractQoreNode *n, ExceptionSink *xsink)
to deref an AbstractQoreNode (when the pointer may be 0)
Definition QoreLib.h:324
#define PO_STRICT_TYPES
enforce strict type checking and setting default values
Definition Restrictions.h:98
The base class for all value and parse types in Qore expression trees.
Definition AbstractQoreNode.h:57
DLLEXPORT AbstractQoreNode * refSelf() const
returns "this" with an incremented reference count
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition ExceptionSink.h:50
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition QoreObject.h:61
a templated class to manage a reference count of an object that can throw a Qore-language exception w...
Definition ReferenceHolder.h:52
parse type: reference to a lvalue expression
Definition ReferenceNode.h:45
DLLEXPORT ReferenceNode * refRefSelf() const
returns a reference to itself
evaluates an AbstractQoreNode and dereferences the stored value in the destructor
Definition QoreValue.h:672
int16_t qore_type_t
used to identify unique Qore data and parse types (descendents of AbstractQoreNode)
Definition common.h:76
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:266
#define QV_Node
for heap-allocated values
Definition QoreValue.h:46
#define QV_Bool
for boolean values
Definition QoreValue.h:43
const qore_type_t NT_WEAKREF_LIST
type value for WeakListReferenceNode
Definition node_types.h:91
const qore_type_t NT_WEAKREF
type value for WeakReferenceNode
Definition node_types.h:87
const qore_type_t NT_WEAKREF_HASH
type value for WeakHashReferenceNode
Definition node_types.h:90
const qore_type_t NT_REFERENCE
type value for ReferenceNode
Definition node_types.h:64
The main value class in Qore, designed to be passed by value.
Definition QoreValue.h:279