Qore Programming Language 1.19.2
Loading...
Searching...
No Matches
QoreClassIntern.h
1/* -*- mode: c++; indent-tabs-mode: nil -*- */
2/*
3 QoreClassIntern.h
4
5 Qore Programming Language
6
7 Copyright (C) 2003 - 2023 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_QORECLASSINTERN_H
33
34#define _QORE_QORECLASSINTERN_H
35
36#include "qore/safe_dslist"
37#include "qore/intern/ConstantList.h"
38#include "qore/intern/QoreLValue.h"
39#include "qore/intern/qore_var_rwlock_priv.h"
40#include "qore/intern/VRMutex.h"
41#include "qore/vector_map"
42#include "qore/vector_set"
43
44#include <algorithm>
45#include <cstring>
46#include <deque>
47#include <list>
48#include <map>
49#include <memory>
50#include <set>
51#include <string>
52#include <vector>
53
54#define OTF_USER CT_USER
55#define OTF_BUILTIN CT_BUILTIN
56
57// cannot use vector_map here for performance reasons with method lookups
58#ifdef HAVE_QORE_HASH_MAP
59#include <qore/hash_map_include.h>
60#include "qore/intern/xxhash.h"
61
62typedef HASH_MAP<std::string, QoreMethod*> hm_method_t;
63#else
64typedef std::map<std::string, QoreMethod*> hm_method_t;
65#endif
66
67// forward reference to private class implementation
68class qore_class_private;
69
70// map from abstract signature to variant for fast tracking of abstract variants
71//typedef vector_map_t<const char*, MethodVariantBase*> vmap_t;
72// must be a map to support deletion while iterating
73typedef std::map<const char*, MethodVariantBase*, ltstr> vmap_t;
74
75hashdecl AbstractMethod {
76 // committed abstract methods from this class and parent classes
77 vmap_t vlist;
78 // abstract methods to be removed
79 vmap_t pending_save;
80 // flag if there are new entries in vlist to check
81 bool check_parse = false;
82 // use relaxed method signature matching
83 bool relaxed_match;
84
85 DLLLOCAL AbstractMethod(bool relaxed_match) : relaxed_match(relaxed_match) {
86 }
87
88 DLLLOCAL AbstractMethod(const AbstractMethod& old);
89
90 DLLLOCAL ~AbstractMethod();
91
92 // merge changes from parent class method of the same name during parse initialization
93 DLLLOCAL void parseMergeBase(AbstractMethod& m, bool committed = false);
94
95 // merge changes from parent class method of the same name during parse initialization
96 DLLLOCAL void parseMergeBase(AbstractMethod& m, MethodFunctionBase* f, bool committed = false);
97
98 DLLLOCAL void parseAdd(MethodVariantBase* v);
99
100 DLLLOCAL void parseOverride(MethodVariantBase* v);
101
102 // delete/purge all saved variants in the pending_save list, returns 0 if the AbstractMethod still has abstract
103 // variants, -1 if not and therefore can be removed from the map
104 DLLLOCAL int parseCommit();
105
106 // noop: parsing can happen once and either succeeds or fails
107 DLLLOCAL void parseRollback() {
108 }
109
110 DLLLOCAL static void checkAbstract(const char* cname, const char* mname, vmap_t& vlist, QoreStringNode*& desc);
111
112 DLLLOCAL void add(MethodVariantBase* v);
113 DLLLOCAL void override(MethodVariantBase* v);
114
115 DLLLOCAL bool empty() const {
116 return vlist.empty();
117 }
118};
119
120// cannot be a vector map to support deletion while iterating with the map API
121#ifdef HAVE_QORE_HASH_MAP
122typedef HASH_MAP<std::string, AbstractMethod*> amap_t;
123#else
124typedef std::map<std::string, AbstractMethod*> amap_t;
125#endif
126
127hashdecl AbstractMethodMap : amap_t {
128 DLLLOCAL AbstractMethodMap(const AbstractMethodMap& old) : relaxed_match(old.relaxed_match) {
129 for (auto& i : old) {
130 assert(!i.second->vlist.empty());
131 insert(amap_t::value_type(i.first, new AbstractMethod(*(i.second))));
132 }
133 }
134
135 DLLLOCAL AbstractMethodMap() {
136 }
137
138 DLLLOCAL ~AbstractMethodMap() {
139 for (auto& i : *this) {
140 delete i.second;
141 }
142 }
143
144 DLLLOCAL AbstractMethod* findMethod(const std::string& name) {
145 amap_t::iterator i = find(name);
146 return i == end() ? nullptr : i->second;
147 }
148
149 // adds a pending abstract variant if it doesn't already exist
150 DLLLOCAL void parseAddAbstractVariant(const char* name, MethodVariantBase* f);
151
152 DLLLOCAL void parseOverrideAbstractVariant(const char* name, MethodVariantBase* f);
153
154 // adds a committed abstract variant if it doesn't already exist
155 DLLLOCAL void addAbstractVariant(const char* name, MethodVariantBase* f);
156
157 // adds a committed non-abstract variant
158 DLLLOCAL void overrideAbstractVariant(const char* name, MethodVariantBase* f);
159
160 DLLLOCAL void parseCommit() {
161 for (amap_t::iterator i = begin(), e = end(); i != e;) {
162 if (i->second->parseCommit()) {
163 //printd(5, "AbstractMethodMap::parseCommit() removing abstract ???::%s()\n", i->first.c_str());
164 delete i->second;
165 erase(i++);
166 continue;
167 }
168 ++i;
169 }
170 }
171
172 DLLLOCAL void parseRollback() {
173 for (auto& i : *this)
174 i.second->parseRollback();
175 }
176
177 DLLLOCAL void parseInit(qore_class_private& qc, BCList* scl);
178
179 DLLLOCAL QoreStringNode* checkAbstract(const char* cname) const;
180
181 // we check if there are any abstract method variants still in the committed lists
182 DLLLOCAL void parseCheckAbstractNew(const QoreProgramLocation* loc, const char* name) const;
183
184 // we check if there are any abstract method variants in the class at runtime (for use with exec-class)
185 DLLLOCAL int runtimeCheckInstantiateClass(const char* name, ExceptionSink* xsink) const;
186
187 // use relaxed matching
188 bool relaxed_match = false;
189};
190
191class SignatureHash;
192
193static inline const char* privpub(ClassAccess access) {
194 return access == Public
195 ? "public"
196 : (access == Private
197 ? "private"
198 : (access == Internal ? "private:internal" : "inaccessible"));
199}
200
201// forward reference for base class (constructor) argument list
202class BCAList;
203// forward reference for base class list
204class BCList;
205// forward reference for base class (constructor) evaluated argument list
206class BCEAList;
207
208class MethodVariantBase : public AbstractQoreFunctionVariant {
209protected:
210 const QoreMethod* qmethod = nullptr; // pointer to method that owns the variant
211 ClassAccess access; // variant access code
212 bool final; // is the variant final or not
213 bool abstract; // is the variant abstract or not
214 std::string asig; // abstract signature, only set for abstract method variants
215
216public:
217 // if %broken-varargs is set, add QCF_USES_EXTRA_ARGS to abstract methods by default as derived methods could use
218 // extra arguments
219 DLLLOCAL MethodVariantBase(ClassAccess n_access, bool n_final, int64 n_flags, bool n_is_user = false,
220 bool n_is_abstract = false) :
221 AbstractQoreFunctionVariant(n_flags |
222 (n_is_abstract && (getProgram()->getParseOptions64() & PO_BROKEN_VARARGS)
223 ? QCF_USES_EXTRA_ARGS
224 : 0
225 ), n_is_user), access(n_access), final(n_final), abstract(n_is_abstract) {
226 }
227
228 DLLLOCAL bool isAbstract() const {
229 return abstract;
230 }
231
232 DLLLOCAL bool isPrivate() const {
233 return access > Public;
234 }
235
236 DLLLOCAL ClassAccess getAccess() const {
237 return access;
238 }
239
240 DLLLOCAL bool isFinal() const {
241 return final;
242 }
243
244 DLLLOCAL void clearAbstract() {
245 assert(abstract);
246 abstract = false;
247 }
248
249 DLLLOCAL void setMethod(QoreMethod* n_qm) {
250 qmethod = n_qm;
251 }
252
253 DLLLOCAL void setNormalUserMethod(QoreMethod* n_qm, LocalVar* selfid) {
254 setMethod(n_qm);
255 getUserVariantBase()->setSelfId(selfid);
256 assert(selfid);
257 assert(selfid->getTypeInfo());
258 assert(QoreTypeInfo::getUniqueReturnClass(selfid->getTypeInfo()));
259 }
260
261 DLLLOCAL const QoreMethod* method() const {
262 assert(qmethod);
263 return qmethod;
264 }
265
266 DLLLOCAL const QoreClass* getClass() const {
267 return qmethod->getClass();
268 }
269
270 DLLLOCAL const char* getAbstractSignature();
271
272 DLLLOCAL const qore_class_private* getClassPriv() const;
273
274 DLLLOCAL MethodVariantBase* ref() {
275 ROreference();
276 return this;
277 }
278
279 DLLLOCAL void deref() {
280 if (ROdereference()) {
281 delete this;
282 }
283 }
284};
285
286#define METHVB(f) (reinterpret_cast<MethodVariantBase*>(f))
287#define METHVB_const(f) (reinterpret_cast<const MethodVariantBase*>(f))
288
289class MethodVariant : public MethodVariantBase {
290public:
291 DLLLOCAL MethodVariant(ClassAccess n_access, bool n_final, int64 n_flags, bool n_is_user = false,
292 bool is_abstract = false) : MethodVariantBase(n_access, n_final, n_flags, n_is_user, is_abstract) {
293 }
294 DLLLOCAL virtual QoreValue evalMethod(QoreObject* self, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const = 0;
295 DLLLOCAL virtual QoreValue evalPseudoMethod(const QoreValue n, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const {
296 assert(false);
297 return QoreValue();
298 }
299};
300
301#define METHV(f) (reinterpret_cast<MethodVariant*>(f))
302#define METHV_const(f) (reinterpret_cast<const MethodVariant*>(f))
303
304class ConstructorMethodVariant : public MethodVariantBase {
305protected:
306 // evaluates base class constructors and initializes members
307 DLLLOCAL int constructorPrelude(const QoreClass &thisclass, CodeEvaluationHelper& ceh, QoreObject* self, BCList* bcl, BCEAList* bceal, ExceptionSink* xsink) const;
308
309public:
310 DLLLOCAL ConstructorMethodVariant(ClassAccess n_access, int64 n_flags, bool n_is_user = false) : MethodVariantBase(n_access, false, n_flags, n_is_user) {
311 }
312 DLLLOCAL virtual const BCAList* getBaseClassArgumentList() const = 0;
313 DLLLOCAL virtual void evalConstructor(const QoreClass &thisclass, QoreObject* self, CodeEvaluationHelper& ceh, BCList* bcl, BCEAList* bceal, ExceptionSink* xsink) const = 0;
314};
315
316#define CONMV(f) (reinterpret_cast<ConstructorMethodVariant*>(f))
317#define CONMV_const(f) (reinterpret_cast<const ConstructorMethodVariant*>(f))
318
319class DestructorMethodVariant : public MethodVariantBase {
320protected:
321public:
322 DLLLOCAL DestructorMethodVariant(bool n_is_user = false) : MethodVariantBase(Public, false, QCF_NO_FLAGS, n_is_user) {
323 }
324
325 DLLLOCAL virtual void evalDestructor(const QoreClass &thisclass, QoreObject* self, ExceptionSink* xsink) const = 0;
326};
327
328#define DESMV(f) (reinterpret_cast<DestructorMethodVariant*>(f))
329#define DESMV_const(f) (reinterpret_cast<const DestructorMethodVariant*>(f))
330
331class CopyMethodVariant : public MethodVariantBase {
332protected:
333public:
334 DLLLOCAL CopyMethodVariant(ClassAccess n_access, bool n_is_user = false)
335 : MethodVariantBase(n_access, false, QCF_NO_FLAGS, n_is_user) {
336 }
337
338 DLLLOCAL virtual void evalCopy(const QoreClass &thisclass, QoreObject* self, QoreObject* old,
339 CodeEvaluationHelper& ceh, BCList* scl, ExceptionSink* xsink) const = 0;
340};
341
342#define COPYMV(f) (reinterpret_cast<CopyMethodVariant*>(f))
343#define COPYMV_const(f) (reinterpret_cast<const CopyMethodVariant*>(f))
344
345class UserMethodVariant : public MethodVariant, public UserVariantBase {
346protected:
347 bool synchronized;
348
349public:
350 DLLLOCAL UserMethodVariant(ClassAccess n_access, bool n_final, StatementBlock* b, int n_sig_first_line,
351 int n_sig_last_line, QoreValue params, RetTypeInfo* rv, bool synced, int64 n_flags, bool is_abstract)
352 : MethodVariant(n_access, n_final, n_flags, true, is_abstract),
353 UserVariantBase(b, n_sig_first_line, n_sig_last_line, params, rv, false), synchronized(synced) {
354 if (signature.hasVarargs()) {
355 flags |= QCF_USES_EXTRA_ARGS;
356 }
357 }
358
359 DLLLOCAL ~UserMethodVariant() {
360 }
361
362 // the following defines the pure virtual functions that are common to all user variants
363 COMMON_USER_VARIANT_FUNCTIONS
364
365 DLLLOCAL virtual int parseInit(QoreFunction* f) {
366 MethodFunctionBase* mf = static_cast<MethodFunctionBase*>(f);
367
368 signature.resolve();
369 // parseResolve and push current return type on stack
370 ParseCodeInfoHelper rtih(mf->getName(), signature.getReturnTypeInfo());
371
372 int err = 0;
373
374 // must be called even if "statements" is NULL
375 if (!mf->isStatic()) {
376 if (!isAbstract()) {
377 err = statements->parseInitMethod(mf->MethodFunctionBase::getClass()->getTypeInfo(), this);
378 }
379 } else {
380 err = statements->parseInit(this);
381 }
382
383 // recheck types against committed types if necessary
384 if (recheck) {
385 f->parseCheckDuplicateSignatureCommitted(&signature);
386 }
387
388 return err;
389 }
390
391 DLLLOCAL virtual QoreValue evalMethod(QoreObject* self, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const;
392};
393
394#define UMV(f) (reinterpret_cast<UserMethodVariant*>(f))
395#define UMV_const(f) (reinterpret_cast<const UserMethodVariant*>(f))
396
397class UserConstructorVariant : public ConstructorMethodVariant, public UserVariantBase {
398protected:
399 // base class argument list for constructors
400 BCAList* bcal;
401
402 DLLLOCAL virtual ~UserConstructorVariant();
403
404public:
405 DLLLOCAL UserConstructorVariant(ClassAccess n_access, StatementBlock* b, int n_sig_first_line, int n_sig_last_line,
406 QoreValue params, BCAList* n_bcal, int64 n_flags = QCF_NO_FLAGS)
407 : ConstructorMethodVariant(n_access, n_flags, true), UserVariantBase(b, n_sig_first_line, n_sig_last_line,
408 params, nullptr, false), bcal(n_bcal) {
409 if (signature.hasVarargs()) {
410 flags |= QCF_USES_EXTRA_ARGS;
411 }
412 }
413
414 // the following defines the pure virtual functions that are common to all user variants
415 COMMON_USER_VARIANT_FUNCTIONS
416
417 DLLLOCAL virtual const BCAList* getBaseClassArgumentList() const {
418 return bcal;
419 }
420
421 DLLLOCAL virtual void evalConstructor(const QoreClass& thisclass, QoreObject* self, CodeEvaluationHelper& ceh,
422 BCList* bcl, BCEAList* bceal, ExceptionSink* xsink) const;
423
424 DLLLOCAL virtual int parseInit(QoreFunction* f);
425};
426
427#define UCONV(f) (reinterpret_cast<UserConstructorVariant*>(f))
428#define UCONV_const(f) (reinterpret_cast<const UserConstructorVariant*>(f))
429
430class UserDestructorVariant : public DestructorMethodVariant, public UserVariantBase {
431protected:
432public:
433 DLLLOCAL UserDestructorVariant(StatementBlock* b, int n_sig_first_line, int n_sig_last_line)
434 : DestructorMethodVariant(true), UserVariantBase(b, n_sig_first_line, n_sig_last_line, QoreValue(),
435 nullptr, false) {
436 }
437
438 // the following defines the pure virtual functions that are common to all user variants
439 COMMON_USER_VARIANT_FUNCTIONS
440
441 DLLLOCAL virtual int parseInit(QoreFunction* f) {
442 MethodFunctionBase* mf = static_cast<MethodFunctionBase*>(f);
443
444 int err = signature.resolve();
445 assert(!signature.getReturnTypeInfo() || signature.getReturnTypeInfo() == nothingTypeInfo);
446
447 // push return type on stack (no return value can be used)
448 ParseCodeInfoHelper rtih("destructor", nothingTypeInfo);
449
450 // must be called even if statements is NULL
451 if (statements->parseInitMethod(mf->MethodFunctionBase::getClass()->getTypeInfo(), this) && !err) {
452 err = -1;
453 }
454
455 // only 1 variant is possible, no need to recheck types
456 return err;
457 }
458
459 DLLLOCAL virtual void evalDestructor(const QoreClass &thisclass, QoreObject* self, ExceptionSink* xsink) const {
460 // there cannot be any params
461 assert(!signature.numParams());
462 assert(!signature.getReturnTypeInfo() || signature.getReturnTypeInfo() == nothingTypeInfo);
463 eval("destructor", 0, self, xsink, getClassPriv()).discard(xsink);
464 }
465};
466
467#define UDESV(f) (reinterpret_cast<UserDestructorVariant*>(f))
468#define UDESV_const(f) (reinterpret_cast<const UserDestructorVariant*>(f))
469
470class UserCopyVariant : public CopyMethodVariant, public UserVariantBase {
471protected:
472public:
473 DLLLOCAL UserCopyVariant(ClassAccess n_access, StatementBlock* b, int n_sig_first_line, int n_sig_last_line, QoreValue params, RetTypeInfo* rv, bool synced) : CopyMethodVariant(n_access, true), UserVariantBase(b, n_sig_first_line, n_sig_last_line, params, rv, synced) {
474 }
475
476 // the following defines the pure virtual functions that are common to all user variants
477 COMMON_USER_VARIANT_FUNCTIONS
478
479 DLLLOCAL virtual int parseInit(QoreFunction* f);
480
481 DLLLOCAL virtual void evalCopy(const QoreClass &thisclass, QoreObject* self, QoreObject* old, CodeEvaluationHelper& ceh, BCList* scl, ExceptionSink* xsink) const;
482};
483
484#define UCOPYV(f) (reinterpret_cast<UserCopyVariant*>(f))
485
486class BuiltinMethodVariant : public MethodVariant, public BuiltinFunctionVariantBase {
487public:
488 DLLLOCAL BuiltinMethodVariant(ClassAccess n_access, bool n_final, int64 n_flags, int64 n_functionality,
489 const QoreTypeInfo* n_returnTypeInfo, const type_vec_t &n_typeList = type_vec_t(),
490 const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t())
491 : MethodVariant(n_access, n_final, n_flags),
492 BuiltinFunctionVariantBase(n_flags, n_functionality, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names) {}
493
494 // the following defines the pure virtual functions that are common to all builtin variants
495 COMMON_BUILTIN_VARIANT_FUNCTIONS
496};
497
498class BuiltinAbstractMethodVariant : public BuiltinMethodVariant {
499public:
500 DLLLOCAL BuiltinAbstractMethodVariant(ClassAccess n_access, int64 n_flags, const QoreTypeInfo* n_returnTypeInfo, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinMethodVariant(n_access, false, n_flags, QDOM_DEFAULT, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names) {
501 abstract = true;
502 }
503
504 DLLLOCAL virtual QoreValue evalMethod(QoreObject* self, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const {
505 assert(false);
506 return QoreValue();
507 }
508};
509
510class BuiltinNormalMethodVariantBase : public BuiltinMethodVariant {
511public:
512 DLLLOCAL BuiltinNormalMethodVariantBase(ClassAccess n_access, bool n_final, int64 n_flags, int64 n_functionality, const QoreTypeInfo* n_returnTypeInfo, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinMethodVariant(n_access, n_final, n_flags, n_functionality, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names) {}
513
514 DLLLOCAL virtual QoreValue evalMethod(QoreObject* self, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const;
515
516 DLLLOCAL virtual QoreValue evalPseudoMethod(const QoreValue n, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const;
517
518 DLLLOCAL virtual QoreValue evalImpl(QoreObject* self, AbstractPrivateData* private_data, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) const = 0;
519};
520
521class BuiltinNormalMethodValueVariant : public BuiltinNormalMethodVariantBase {
522protected:
523 q_method_n_t method;
524
525public:
526 DLLLOCAL BuiltinNormalMethodValueVariant(q_method_n_t m, ClassAccess n_access, bool n_final = false, int64 n_flags = QCF_USES_EXTRA_ARGS, int64 n_functionality = QDOM_DEFAULT, const QoreTypeInfo* n_returnTypeInfo = 0, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinNormalMethodVariantBase(n_access, n_final, n_flags, n_functionality, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names), method(m) {
527 }
528 DLLLOCAL virtual QoreValue evalImpl(QoreObject* self, AbstractPrivateData* private_data, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) const {
529 return method(self, private_data, args, rtflags, xsink);
530 }
531};
532
533class BuiltinExternalNormalMethodValueVariant : public BuiltinNormalMethodVariantBase {
534protected:
535 q_external_method_t method;
536 const void* ptr;
537
538public:
539 DLLLOCAL BuiltinExternalNormalMethodValueVariant(const void* n_ptr, q_external_method_t m, ClassAccess n_access, bool n_final = false, int64 n_flags = QCF_USES_EXTRA_ARGS, int64 n_functionality = QDOM_DEFAULT, const QoreTypeInfo* n_returnTypeInfo = 0, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinNormalMethodVariantBase(n_access, n_final, n_flags, n_functionality, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names), method(m), ptr(n_ptr) {
540 }
541 DLLLOCAL virtual QoreValue evalImpl(QoreObject* self, AbstractPrivateData* private_data, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) const {
542 return method(*qmethod, ptr, self, private_data, args, rtflags, xsink);
543 }
544};
545
546class BuiltinStaticMethodValueVariant : public BuiltinMethodVariant {
547protected:
548 q_func_n_t static_method;
549
550public:
551 DLLLOCAL BuiltinStaticMethodValueVariant(q_func_n_t m, ClassAccess n_access, bool n_final = false, int64 n_flags = QCF_USES_EXTRA_ARGS, int64 n_functionality = QDOM_DEFAULT, const QoreTypeInfo* n_returnTypeInfo = 0, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinMethodVariant(n_access, n_final, n_flags, n_functionality, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names), static_method(m) {
552 }
553
554 DLLLOCAL virtual QoreValue evalMethod(QoreObject* self, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const {
555 CodeContextHelper cch(xsink, CT_BUILTIN, qmethod->getName(), 0, getClassPriv());
556
557 return static_method(ceh.getArgs(), ceh.getRuntimeFlags(), xsink);
558 }
559};
560
561class BuiltinExternalStaticMethodValueVariant : public BuiltinMethodVariant {
562protected:
563 q_external_static_method_t static_method;
564 const void* ptr;
565
566public:
567 DLLLOCAL BuiltinExternalStaticMethodValueVariant(const void* n_ptr, q_external_static_method_t m, ClassAccess n_access, bool n_final = false, int64 n_flags = QCF_USES_EXTRA_ARGS, int64 n_functionality = QDOM_DEFAULT, const QoreTypeInfo* n_returnTypeInfo = 0, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinMethodVariant(n_access, n_final, n_flags, n_functionality, n_returnTypeInfo, n_typeList, n_defaultArgList, n_names), static_method(m), ptr(n_ptr) {
568 }
569
570 DLLLOCAL virtual QoreValue evalMethod(QoreObject* self, CodeEvaluationHelper& ceh, ExceptionSink* xsink) const {
571 CodeContextHelper cch(xsink, CT_BUILTIN, qmethod->getName(), 0, getClassPriv());
572
573 return static_method(*qmethod, ptr, ceh.getArgs(), ceh.getRuntimeFlags(), xsink);
574 }
575};
576
577class BuiltinConstructorVariantBase : public ConstructorMethodVariant, public BuiltinFunctionVariantBase {
578public:
579 // return type info is set to 0 because the new operator actually returns the new object, not the constructor
580 DLLLOCAL BuiltinConstructorVariantBase(ClassAccess n_access, int64 n_flags = QCF_USES_EXTRA_ARGS,
581 int64 n_functionality = QDOM_DEFAULT, const type_vec_t &n_typeList = type_vec_t(),
582 const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t())
583 : ConstructorMethodVariant(n_access, n_flags),
584 BuiltinFunctionVariantBase(n_flags, n_functionality, 0, n_typeList, n_defaultArgList, n_names) {
585 }
586
587 // the following defines the pure virtual functions that are common to all builtin variants
588 COMMON_BUILTIN_VARIANT_FUNCTIONS
589
590 DLLLOCAL virtual const BCAList* getBaseClassArgumentList() const {
591 return nullptr;
592 }
593};
594
595class BuiltinConstructorValueVariant : public BuiltinConstructorVariantBase {
596protected:
597 q_constructor_n_t constructor;
598
599public:
600 DLLLOCAL BuiltinConstructorValueVariant(q_constructor_n_t m, ClassAccess n_access, int64 n_flags = QCF_USES_EXTRA_ARGS, int64 n_functionality = QDOM_DEFAULT, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinConstructorVariantBase(n_access, n_flags, n_functionality, n_typeList, n_defaultArgList, n_names), constructor(m) {
601 }
602
603 DLLLOCAL virtual void evalConstructor(const QoreClass& thisclass, QoreObject* self, CodeEvaluationHelper& ceh, BCList* bcl, BCEAList* bceal, ExceptionSink* xsink) const;
604};
605
606class BuiltinExternalConstructorValueVariant : public BuiltinConstructorVariantBase {
607protected:
608 q_external_constructor_t constructor;
609 const void* ptr;
610
611public:
612 DLLLOCAL BuiltinExternalConstructorValueVariant(const void* n_ptr, q_external_constructor_t m, ClassAccess n_access, int64 n_flags = QCF_USES_EXTRA_ARGS, int64 n_functionality = QDOM_DEFAULT, const type_vec_t &n_typeList = type_vec_t(), const arg_vec_t &n_defaultArgList = arg_vec_t(), const name_vec_t& n_names = name_vec_t()) : BuiltinConstructorVariantBase(n_access, n_flags, n_functionality, n_typeList, n_defaultArgList, n_names), constructor(m), ptr(n_ptr) {
613 }
614
615 DLLLOCAL virtual void evalConstructor(const QoreClass& thisclass, QoreObject* self, CodeEvaluationHelper& ceh, BCList* bcl, BCEAList* bceal, ExceptionSink* xsink) const;
616};
617
618class BuiltinDestructorVariantBase : public DestructorMethodVariant, public BuiltinFunctionVariantBase {
619public:
620 // the following defines the pure virtual functions that are common to all builtin variants
621 COMMON_BUILTIN_VARIANT_FUNCTIONS
622};
623
624class BuiltinDestructorVariant : public BuiltinDestructorVariantBase {
625protected:
626 q_destructor_t destructor;
627
628public:
629 DLLLOCAL BuiltinDestructorVariant(q_destructor_t n_destructor) : destructor(n_destructor) {
630 }
631
632 DLLLOCAL virtual void evalDestructor(const QoreClass &thisclass, QoreObject* self, ExceptionSink* xsink) const;
633};
634
635class BuiltinExternalDestructorVariant : public BuiltinDestructorVariantBase {
636protected:
637 q_external_destructor_t destructor;
638 const void* ptr;
639
640public:
641 DLLLOCAL BuiltinExternalDestructorVariant(const void* ptr, q_external_destructor_t destructor) : destructor(destructor), ptr(ptr) {
642 }
643
644 DLLLOCAL virtual void evalDestructor(const QoreClass &thisclass, QoreObject* self, ExceptionSink* xsink) const;
645};
646
647class BuiltinCopyVariantBase : public CopyMethodVariant, public BuiltinFunctionVariantBase {
648protected:
649public:
650 DLLLOCAL BuiltinCopyVariantBase(const QoreClass* c)
651 : CopyMethodVariant(Public),
652 BuiltinFunctionVariantBase(0, QDOM_DEFAULT, c->getTypeInfo()) {
653 }
654
655 // the following defines the pure virtual functions that are common to all builtin variants
656 COMMON_BUILTIN_VARIANT_FUNCTIONS
657
658 DLLLOCAL virtual void evalCopy(const QoreClass &thisclass, QoreObject* self, QoreObject* old, CodeEvaluationHelper& ceh, BCList* scl, ExceptionSink* xsink) const;
659 DLLLOCAL virtual void evalImpl(const QoreClass &thisclass, QoreObject* self, QoreObject* old, AbstractPrivateData* private_data, ExceptionSink* xsink) const = 0;
660};
661
662class BuiltinCopyVariant : public BuiltinCopyVariantBase {
663protected:
664 q_copy_t copy;
665
666public:
667 DLLLOCAL BuiltinCopyVariant(QoreClass* c, q_copy_t m) : BuiltinCopyVariantBase(c), copy(m) {
668 }
669 DLLLOCAL virtual void evalImpl(const QoreClass &thisclass, QoreObject* self, QoreObject* old, AbstractPrivateData* private_data, ExceptionSink* xsink) const {
670 copy(self, old, private_data, xsink);
671 }
672};
673
674class BuiltinExternalCopyVariant : public BuiltinCopyVariantBase {
675protected:
677 const void* ptr;
678
679public:
680 DLLLOCAL BuiltinExternalCopyVariant(const void* n_ptr, QoreClass* c, q_external_copy_t m) : BuiltinCopyVariantBase(c), copy(m), ptr(n_ptr) {
681 }
682
683 DLLLOCAL virtual void evalImpl(const QoreClass &thisclass, QoreObject* self, QoreObject* old, AbstractPrivateData* private_data, ExceptionSink* xsink) const {
684 copy(thisclass, ptr, self, old, private_data, xsink);
685 }
686};
687
688// abstract class for method functions (static and non-static)
689class NormalMethodFunction : public MethodFunctionBase {
690public:
691 DLLLOCAL NormalMethodFunction(const char* nme, const QoreClass* n_qc) : MethodFunctionBase(nme, n_qc, false) {
692 }
693
694 DLLLOCAL NormalMethodFunction(const NormalMethodFunction &old, const QoreClass* n_qc) : MethodFunctionBase(old, n_qc) {
695 }
696
697 DLLLOCAL virtual ~NormalMethodFunction() {
698 }
699
700 // if the variant was identified at parse time, then variant will not be NULL, otherwise if NULL then it is identified at run time
701 DLLLOCAL QoreValue evalMethod(ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant, QoreObject* self, const QoreListNode* args, const qore_class_private* cctx = nullptr) const;
702
703 // if the variant was identified at parse time, then variant will not be NULL, otherwise if NULL then it is identified at run time
704 DLLLOCAL QoreValue evalMethodTmpArgs(ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant, QoreObject* self, QoreListNode* args, const qore_class_private* cctx = nullptr) const;
705
706 // if the variant was identified at parse time, then variant will not be NULL, otherwise if NULL then it is identified at run time
707 DLLLOCAL QoreValue evalPseudoMethod(ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant,
708 const QoreValue n, const QoreListNode* args, const qore_class_private* cctx = runtime_get_class()) const;
709};
710
711#define NMETHF(f) (reinterpret_cast<NormalMethodFunction*>(f))
712
713// abstract class for method functions (static and non-static)
714class StaticMethodFunction : public MethodFunctionBase {
715public:
716 DLLLOCAL StaticMethodFunction(const char* nme, const QoreClass* n_qc) : MethodFunctionBase(nme, n_qc, true) {
717 }
718 DLLLOCAL StaticMethodFunction(const StaticMethodFunction &old, const QoreClass* n_qc) : MethodFunctionBase(old, n_qc) {
719 }
720 DLLLOCAL virtual ~StaticMethodFunction() {
721 }
722
723 // if the variant was identified at parse time, then variant will not be NULL, otherwise if NULL then it is identified at run time
724 DLLLOCAL QoreValue evalMethod(ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant, const QoreListNode* args, const qore_class_private* cctx = nullptr) const;
725
726 // if the variant was identified at parse time, then variant will not be NULL, otherwise if NULL then it is identified at run time
727 DLLLOCAL QoreValue evalMethodTmpArgs(ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant, QoreListNode* args, const qore_class_private* cctx = nullptr) const;
728};
729
730#define SMETHF(f) (reinterpret_cast<StaticMethodFunction*>(f))
731
732// abstract class for constructor method functions
733class ConstructorMethodFunction : public MethodFunctionBase {
734public:
735 DLLLOCAL ConstructorMethodFunction(const QoreClass* n_qc) : MethodFunctionBase("constructor", n_qc, false) {
736 }
737 DLLLOCAL ConstructorMethodFunction(const ConstructorMethodFunction &old, const QoreClass* n_qc) : MethodFunctionBase(old, n_qc) {
738 }
739
740 // if the variant was identified at parse time, then variant will not be NULL, otherwise if NULL then it is identified at run time
741 DLLLOCAL void evalConstructor(const AbstractQoreFunctionVariant* variant, const QoreClass &thisclass, QoreObject* self, const QoreListNode* args, BCList* bcl, BCEAList* bceal, ExceptionSink* xsink) const;
742
743 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
744 return new ConstructorMethodFunction(*this, n_qc);
745 }
746};
747
748#define CONMF(f) (reinterpret_cast<ConstructorMethodFunction*>(f))
749
750// abstract class for destructor method functions
751class DestructorMethodFunction : public MethodFunctionBase {
752public:
753 DLLLOCAL DestructorMethodFunction(const QoreClass* n_qc) : MethodFunctionBase("destructor", n_qc, false) {
754 }
755 DLLLOCAL DestructorMethodFunction(const DestructorMethodFunction &old, const QoreClass* n_qc) : MethodFunctionBase(old, n_qc) {
756 }
757 DLLLOCAL void evalDestructor(const QoreClass &thisclass, QoreObject* self, ExceptionSink* xsink) const;
758
759 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
760 return new DestructorMethodFunction(*this, n_qc);
761 }
762};
763
764#define DESMF(f) (reinterpret_cast<DestructorMethodFunction*>(f))
765
766// abstract class for copy method functions
767class CopyMethodFunction : public MethodFunctionBase {
768public:
769 DLLLOCAL CopyMethodFunction(const QoreClass* n_qc) : MethodFunctionBase("copy", n_qc, false) {
770 }
771 DLLLOCAL CopyMethodFunction(const CopyMethodFunction &old, const QoreClass* n_qc) : MethodFunctionBase(old, n_qc) {
772 }
773 DLLLOCAL void evalCopy(const QoreClass &thisclass, QoreObject* self, QoreObject* old, BCList* scl, ExceptionSink* xsink) const;
774
775 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
776 return new CopyMethodFunction(*this, n_qc);
777 }
778};
779
780#define COPYMF(f) (reinterpret_cast<CopyMethodFunction*>(f))
781
782class BuiltinSystemConstructorBase : public MethodFunctionBase {
783public:
784 DLLLOCAL BuiltinSystemConstructorBase(const QoreClass* n_qc) : MethodFunctionBase("constructor", n_qc, false) {
785 }
786 DLLLOCAL BuiltinSystemConstructorBase(const BuiltinSystemConstructorBase &old, const QoreClass* n_qc) : MethodFunctionBase(old, n_qc) {
787 }
788 DLLLOCAL virtual void eval(const QoreClass &thisclass, QoreObject* self, int code, va_list args) const = 0;
789
790 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const = 0;
791};
792
793#define BSYSCONB(f) (reinterpret_cast<BuiltinSystemConstructorBase* >(f))
794
795// system constructors are not accessed from userspace so we don't need to conform
796// to the abstract class structure
797class BuiltinSystemConstructor : public BuiltinSystemConstructorBase {
798protected:
799 q_system_constructor_t system_constructor;
800
801public:
802 DLLLOCAL BuiltinSystemConstructor(const QoreClass* n_qc, q_system_constructor_t m) : BuiltinSystemConstructorBase(n_qc), system_constructor(m) {
803 }
804
805 DLLLOCAL BuiltinSystemConstructor(const BuiltinSystemConstructor &old, const QoreClass* n_qc) : BuiltinSystemConstructorBase(old, n_qc), system_constructor(old.system_constructor) {
806 }
807
808 DLLLOCAL virtual void eval(const QoreClass &thisclass, QoreObject* self, int code, va_list args) const {
809 system_constructor(self, code, args);
810 }
811
812 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
813 return new BuiltinSystemConstructor(*this, n_qc);
814 }
815};
816
817class BuiltinNormalMethod : public NormalMethodFunction {
818public:
819 DLLLOCAL BuiltinNormalMethod(const QoreClass* n_qc, const char* mname) : NormalMethodFunction(mname, n_qc) {
820 }
821
822 DLLLOCAL BuiltinNormalMethod(const BuiltinNormalMethod &old, const QoreClass* n_qc) : NormalMethodFunction(old, n_qc) {
823 }
824
825 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
826 return new BuiltinNormalMethod(*this, n_qc);
827 }
828};
829
830class BuiltinStaticMethod : public StaticMethodFunction {
831public:
832 DLLLOCAL BuiltinStaticMethod(const QoreClass* n_qc, const char* mname) : StaticMethodFunction(mname, n_qc) {
833 }
834
835 DLLLOCAL BuiltinStaticMethod(const BuiltinStaticMethod &old, const QoreClass* n_qc) : StaticMethodFunction(old, n_qc) {
836 }
837
838 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
839 return new BuiltinStaticMethod(*this, n_qc);
840 }
841};
842
843class NormalUserMethod : public NormalMethodFunction {
844public:
845 DLLLOCAL NormalUserMethod(const QoreClass* n_qc, const char* mname) : NormalMethodFunction(mname, n_qc) {
846 }
847 DLLLOCAL NormalUserMethod(const NormalUserMethod &old, const QoreClass* n_qc) : NormalMethodFunction(old, n_qc) {
848 }
849 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
850 return new NormalUserMethod(*this, n_qc);
851 }
852};
853
854class StaticUserMethod : public StaticMethodFunction {
855public:
856 DLLLOCAL StaticUserMethod(const QoreClass* n_qc, const char* mname) : StaticMethodFunction(mname, n_qc) {
857 }
858 DLLLOCAL StaticUserMethod(const StaticUserMethod &old, const QoreClass* n_qc) : StaticMethodFunction(old, n_qc) {
859 }
860 DLLLOCAL virtual MethodFunctionBase* copy(const QoreClass* n_qc) const {
861 return new StaticUserMethod(*this, n_qc);
862 }
863};
864
865class QoreMemberInfoBase {
866protected:
867 const QoreTypeInfo* typeInfo;
868
869 DLLLOCAL QoreMemberInfoBase(const QoreMemberInfoBase& old) : typeInfo(old.typeInfo), exp(old.exp.refSelf()),
870 loc(old.loc), parseTypeInfo(old.parseTypeInfo ? new QoreParseTypeInfo(*old.parseTypeInfo) : nullptr) {
871 }
872
873public:
874 // initialization expression
875 QoreValue exp;
876
877 // store parse location in case of errors
878 const QoreProgramLocation* loc;
879 QoreParseTypeInfo* parseTypeInfo;
880
881 DLLLOCAL QoreMemberInfoBase(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeinfo = nullptr,
882 QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue())
883 : typeInfo(n_typeinfo), exp(e), loc(loc), parseTypeInfo(n_parseTypeInfo) {
884 }
885
886 DLLLOCAL ~QoreMemberInfoBase() {
887 del();
888 }
889
890 DLLLOCAL void del() {
891 exp.discard(nullptr);
892 if (parseTypeInfo) {
893 delete parseTypeInfo;
894 parseTypeInfo = nullptr;
895 }
896 }
897
898 DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
899 return typeInfo;
900 }
901
902 DLLLOCAL const QoreTypeInfo* parseGetTypeInfo() const {
903 // we cannot tell if the member has been initialized, so we return anyTypeInfo here for potential references
904 return QoreTypeInfo::isReference(typeInfo) ? anyTypeInfo : typeInfo;
905 //return typeInfo;
906 }
907
908 DLLLOCAL bool parseHasTypeInfo() const {
909 return (typeInfo || parseTypeInfo);
910 }
911};
912
913class QoreMemberInfoBaseAccess : public QoreMemberInfoBase {
914public:
915 ClassAccess access;
916
917 DLLLOCAL QoreMemberInfoBaseAccess(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeinfo = nullptr,
918 QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue(), ClassAccess n_access = Public) :
919 QoreMemberInfoBase(loc, n_typeinfo, n_parseTypeInfo, e), access(n_access) {
920 }
921
922 DLLLOCAL ClassAccess getAccess() const {
923 return access;
924 }
925
926protected:
927 DLLLOCAL QoreMemberInfoBaseAccess(const QoreMemberInfoBaseAccess& old, ClassAccess n_access)
928 : QoreMemberInfoBase(old), access(old.access >= n_access ? old.access : n_access), init(old.init) {
929 }
930
931 bool init = false;
932};
933
934// for the inheritance list for each member
935typedef std::vector<const qore_class_private*> cls_vec_t;
936
937// maps from an accessing context to the object storage context
938typedef std::map<const qore_class_private*, const qore_class_private*> cls_context_map_t;
939
940// list of inherited member info dsta structures for initialization
941typedef std::deque<const QoreMemberInfo*> member_info_list_t;
942
943// the access stored here is a composite access for the member; the maximum of the class inheritance access
944// (for accessible members imported from base classes) and the member's access in the class where it's
945// defined
946class QoreMemberInfo : public QoreMemberInfoBaseAccess {
947 friend class qore_class_private;
948public:
949 DLLLOCAL QoreMemberInfo(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeInfo = nullptr,
950 QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue(), ClassAccess n_access = Public,
951 const qore_class_private* qc = nullptr)
952 : QoreMemberInfoBaseAccess(loc, n_typeInfo, n_parseTypeInfo, e, n_access), is_local(true) {
953 if (qc) {
954 cls_vec.push_back(qc);
955 }
956 }
957
958 // copy to a new class - same member, new class
959 DLLLOCAL QoreMemberInfo(const QoreMemberInfo& old, const qore_class_private* cls);
960
961 DLLLOCAL ~QoreMemberInfo() {
962 delete cls_context_map;
963 delete member_info_list;
964 }
965
966 DLLLOCAL void setDeclaringClass(const qore_class_private* qc) {
967 assert(cls_vec.empty());
968 cls_vec.push_back(qc);
969 assert(is_local);
970 }
971
972 // returns true if the member is a locally-defined member with private:internal member access
973 DLLLOCAL bool isLocalInternal() const {
974 return is_local && access == Internal;
975 }
976
977 // returns true if the member is locally defined
978 DLLLOCAL bool local() const {
979 return is_local;
980 }
981
982 // returns the class where the member was declared
983 DLLLOCAL const qore_class_private* getClass() const {
984 return cls_vec[0];
985 }
986
987 // issue #2970: returns the class ptr to be used to access the member data in the object; nullptr means to access in the standard object hash
988 DLLLOCAL const qore_class_private* getClassContext(const qore_class_private* class_ctx) const {
989 if (local() && class_ctx == getClass()) {
990 if (access == Internal) {
991 return class_ctx;
992 }
993 return nullptr;
994 }
995 if (cls_context_map) {
996 cls_context_map_t::const_iterator i = cls_context_map->find(class_ctx);
997 if (i != cls_context_map->end()) {
998 return i->second;
999 }
1000 }
1001
1002 return nullptr;
1003 }
1004
1005 DLLLOCAL size_t getContextSize() const {
1006 return cls_context_map ? cls_context_map->size() : 0;
1007 }
1008
1009 // issue #2970: marks the member to be accessed with the classes in the argument when
1010 // accessing the object's data
1011 DLLLOCAL void addContextAccess(const QoreMemberInfo& mi);
1012
1013 // issue #2970: marks the member to be accessed with the classes in the argument when
1014 // accessing the object's data
1015 DLLLOCAL void addContextAccess(const QoreMemberInfo& mi, const qore_class_private* qc);
1016
1017 // issue #2970: returns the number of parent class members to initialize
1018 DLLLOCAL size_t numParentMembers() const {
1019 return member_info_list ? member_info_list->size() : 0;
1020 }
1021
1022 // issue #2970: initialization begin
1023 DLLLOCAL member_info_list_t::const_iterator initializationBegin() const {
1024 assert(member_info_list);
1025 return member_info_list->begin();
1026 }
1027
1028 // issue #2970: initialization end
1029 DLLLOCAL member_info_list_t::const_iterator initializationEnd() const {
1030 assert(member_info_list);
1031 return member_info_list->end();
1032 }
1033
1034 // initializes the member
1035 DLLLOCAL int parseInit(const char* name, LocalVar& selfid);
1036
1037 // sets the transient flag
1038 DLLLOCAL void setTransient() {
1039 assert(!is_transient);
1040 is_transient = true;
1041 }
1042
1043 // returns the transient flag
1044 DLLLOCAL bool getTransient() const {
1045 return is_transient;
1046 }
1047
1048private:
1049 // the classes where this member is accessible; the first class is the class where the member was defined
1050 cls_vec_t cls_vec;
1051 // maps class contexts to class pointers in object storage for private members
1052 cls_context_map_t* cls_context_map = nullptr;
1053 // list of inherited members for initialization
1054 member_info_list_t* member_info_list = nullptr;
1055
1056 // local flag
1057 bool is_local,
1058 // transient flag
1059 is_transient = false;
1060
1071 DLLLOCAL QoreMemberInfo(const QoreMemberInfo& old, const qore_class_private* cls, ClassAccess cls_access);
1072};
1073
1074class QoreVarInfo : public QoreMemberInfoBaseAccess {
1075public:
1076 mutable QoreVarRWLock rwl;
1077 QoreLValueGeneric val;
1078 bool finalized;
1079 // flag telling if the static var has been evaluated
1080 bool eval_init = false;
1081
1082 DLLLOCAL QoreVarInfo(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeinfo = nullptr,
1083 QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue(), ClassAccess n_access = Public) :
1084 QoreMemberInfoBaseAccess(loc, n_typeinfo, n_parseTypeInfo, e, n_access), finalized(false) {
1085 }
1086
1087 DLLLOCAL QoreVarInfo(const QoreVarInfo& old, ClassAccess n_access = Public)
1088 : QoreMemberInfoBaseAccess(old, n_access), val(old.val), finalized(old.finalized), eval_init(old.eval_init) {
1089 }
1090
1091 DLLLOCAL ~QoreVarInfo() {
1092 assert(!val.hasValue());
1093 }
1094
1095 DLLLOCAL int evalInit(const char* name, ExceptionSink* xsink);
1096
1097#ifdef DEBUG
1098 DLLLOCAL void del() {
1099 assert(!val.hasValue());
1100 QoreMemberInfoBaseAccess::del();
1101 }
1102#endif
1103
1104 DLLLOCAL void clear(ExceptionSink* xsink) {
1105 ValueHolder tmp(xsink);
1106 QoreAutoVarRWWriteLocker al(rwl);
1107 if (!finalized)
1108 finalized = true;
1109 tmp = val.removeValue(true);
1110 }
1111
1112 DLLLOCAL void delVar(ExceptionSink* xsink) {
1113#ifdef DEBUG
1114 QoreMemberInfoBaseAccess::del();
1115#else
1116 del();
1117#endif
1118 val.removeValue(true).discard(xsink);
1119 }
1120
1121 DLLLOCAL AbstractQoreNode* assignInit(QoreValue v) {
1122 // try to set an optimized value type for the value holder if possible
1123 val.set(getTypeInfo());
1124 return val.assignInitial(v);
1125 }
1126
1127 DLLLOCAL void getLValue(LValueHelper& lvh) {
1128 lvh.setAndLock(rwl);
1129 if (checkFinalized(lvh.vl.xsink))
1130 return;
1131 lvh.setValue(val, getTypeInfo());
1132 }
1133
1134 DLLLOCAL void init() {
1135 val.set(getTypeInfo());
1136 if (getProgram()->getParseOptions64() & PO_STRICT_TYPES) {
1137 // try to set an optimized value type for the value holder if possible
1138 discard(val.assignInitial(QoreTypeInfo::getDefaultQoreValue(typeInfo)), nullptr);
1139 }
1140 }
1141
1142 // can be called during parse initialization, in which case the variable must be initialized first
1143 DLLLOCAL QoreValue getReferencedValue(const char* name, ExceptionSink* xsink) {
1144 if (!eval_init && evalInit(name, xsink)) {
1145 return QoreValue();
1146 }
1147 return getRuntimeReferencedValue();
1148 }
1149
1150 DLLLOCAL QoreValue getRuntimeReferencedValue() const {
1151 QoreAutoVarRWReadLocker al(rwl);
1152 return val.getReferencedValue();
1153 }
1154
1155 DLLLOCAL int64 getAsBigInt() const {
1156 QoreAutoVarRWReadLocker al(rwl);
1157 return val.getAsBigInt();
1158 }
1159
1160 DLLLOCAL double getAsFloat() const {
1161 QoreAutoVarRWReadLocker al(rwl);
1162 return val.getAsFloat();
1163 }
1164
1165 DLLLOCAL bool getAsBool() const {
1166 QoreAutoVarRWReadLocker al(rwl);
1167 return val.getAsBool();
1168 }
1169
1170 DLLLOCAL int parseInit(const char* name);
1171
1172protected:
1173 DLLLOCAL int checkFinalized(ExceptionSink* xsink) const {
1174 if (finalized) {
1175 xsink->raiseException("DESTRUCTOR-ERROR", "illegal class static variable assignment after second phase "
1176 "of variable destruction");
1177 return -1;
1178 }
1179 return 0;
1180 }
1181};
1182
1183template <typename T>
1184class QoreMemberMapBase {
1185public:
1186 typedef std::pair<char*, std::unique_ptr<T>> member_list_element_t;
1187 typedef std::deque<member_list_element_t> member_list_t;
1188 typedef typename member_list_t::iterator iterator;
1189 typedef typename member_list_t::const_iterator const_iterator;
1190 member_list_t member_list;
1191
1192 DLLLOCAL ~QoreMemberMapBase() {
1193 for (auto& i : member_list) {
1194 //printd(5, "QoreMemberMap::~QoreMemberMap() this: %p freeing member %p '%s'\n", this, i->second, i->first);
1195 // the key is allocated normally in the scanner, and must be freed manually here
1196 free(i.first);
1197 }
1198 member_list.clear();
1199 }
1200
1201 DLLLOCAL bool inList(const char* name) const {
1202 return (bool)find(name);
1203 }
1204
1205 DLLLOCAL T* find(const char* name) const {
1206 typename member_list_t::const_iterator i =
1207 std::find_if(member_list.begin(), member_list.end(), [name](const member_list_element_t& e)
1208 -> bool {return !strcmp(e.first, name); });
1209 return i == member_list.end() ? nullptr : i->second.get();
1210 }
1211
1212 DLLLOCAL T* replace(const char* name, T* info) {
1213 typename member_list_t::iterator i =
1214 std::find_if(member_list.begin(), member_list.end(), [name](const member_list_element_t& e)
1215 -> bool {return !strcmp(e.first, name); });
1216 assert(i != member_list.end());
1217 T* rv = i->second.release();
1218 i->second = std::unique_ptr<T>(info);
1219 return rv;
1220 }
1221
1222 DLLLOCAL bool empty() const {
1223 return member_list.empty();
1224 }
1225
1226 DLLLOCAL void addNoCheck(char* name, T* info) {
1227 assert(name);
1228 assert(info);
1229 assert(!inList(name));
1230 member_list.push_back(std::make_pair(name, std::unique_ptr<T>(info)));
1231 }
1232
1233 DLLLOCAL void addNoCheck(std::pair<char*, T*> pair) {
1234 addNoCheck(pair.first, pair.second);
1235 }
1236
1237 DLLLOCAL void moveAllTo(QoreMemberMapBase<T>& dest) {
1238 dest.member_list.insert(dest.member_list.end(), member_list.begin(), member_list.end());
1239 member_list.clear();
1240 }
1241
1242 DLLLOCAL size_t size() const {
1243 return member_list.size();
1244 }
1245};
1246
1247class QoreMemberMap : public QoreMemberMapBase<QoreMemberInfo> {
1248public:
1249 using QoreMemberMapBase<QoreMemberInfo>::moveAllTo;
1250 DLLLOCAL void moveAllTo(QoreClass* qc, ClassAccess access);
1251
1252 using QoreMemberMapBase<QoreMemberInfo>::addNoCheck;
1253 DLLLOCAL void addNoCheck(char* name, QoreMemberInfo* info) {
1254 assert(info->getClass());
1255 QoreMemberMapBase<QoreMemberInfo>::addNoCheck(name, info);
1256 }
1257
1258 DLLLOCAL void addInheritedNoCheck(char* name, QoreMemberInfo* info) {
1259 assert(name);
1260 assert(info);
1261 assert(!inList(name));
1262 member_list.insert(member_list.begin(), std::make_pair(name, std::unique_ptr<QoreMemberInfo>(info)));
1263 }
1264
1265 DLLLOCAL int parseInit(LocalVar& selfid);
1266
1267private:
1268 bool init = false;
1269};
1270
1271class QoreVarMap : public QoreMemberMapBase<QoreVarInfo> {
1272public:
1273 DLLLOCAL void clear(ExceptionSink* xsink) {
1274 for (member_list_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
1275 i->second->clear(xsink);
1276 }
1277 }
1278
1279 DLLLOCAL void del(ExceptionSink* xsink) {
1280 for (member_list_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
1281 i->second->delVar(xsink);
1282 // the key is allocated normally in the scanner, and must be freed manually here
1283 free(i->first);
1284 }
1285 member_list.clear();
1286 }
1287
1288 DLLLOCAL void del() {
1289 for (member_list_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
1290 assert(!i->second->val.hasValue());
1291 /*
1292 // when rolling back a failed parse, vars may have values, but no exception can happen, so xsink can be nullptr
1293 i->second->delVar(nullptr);
1294 */
1295 // the key is allocated normally in the scanner, and must be freed manually here
1296 free(i->first);
1297 }
1298 member_list.clear();
1299 }
1300
1301 DLLLOCAL void clearNoFree() {
1302 member_list.clear();
1303 }
1304
1305 DLLLOCAL void moveAllTo(QoreClass* qc, ClassAccess access);
1306
1307 DLLLOCAL void parseCommitRuntimeInit(ExceptionSink* xsink);
1308
1309private:
1310 bool init = false;
1311};
1312
1313/*
1314 BCANode
1315 base class constructor argument node
1316*/
1317class BCANode : public FunctionCallBase {
1318public:
1319 // set automatically when created
1320 const QoreProgramLocation* loc;
1321 qore_classid_t classid = 0;
1322 //QoreClass* sclass;
1323 NamedScope* ns;
1324 char* name;
1325
1326 // this function takes ownership of n and arg
1327 DLLLOCAL BCANode(NamedScope* n, QoreParseListNode* n_args, const QoreProgramLocation* loc)
1328 : FunctionCallBase(n_args), loc(loc), ns(n), name(nullptr) {
1329 assert(loc->start_line > 0);
1330 }
1331
1332 // this function takes ownership of n and arg
1333 DLLLOCAL BCANode(char* n, QoreParseListNode* n_args, const QoreProgramLocation* loc)
1334 : FunctionCallBase(n_args), loc(loc), ns(nullptr), name(n) {
1335 assert(loc->start_line > 0);
1336 }
1337
1338 DLLLOCAL ~BCANode() {
1339 delete ns;
1340 if (name)
1341 free(name);
1342 }
1343
1344 // resolves classes, parses arguments, and attempts to find constructor variant
1345 DLLLOCAL int parseInit(BCList* bcl, const char* classname);
1346};
1347
1348typedef std::vector<BCANode*> bcalist_t;
1349
1350// BCAList
1351// base class constructor argument list
1352// this data structure will not be modified even if the class is copied
1353// to a subprogram object
1354class BCAList : public bcalist_t {
1355public:
1356 DLLLOCAL BCAList(BCANode* n) {
1357 push_back(n);
1358 }
1359
1360 DLLLOCAL ~BCAList() {
1361 for (bcalist_t::iterator i = begin(), e = end(); i != e; ++i)
1362 delete *i;
1363 }
1364
1365 // returns 0 for no errors, -1 for exception raised
1366 DLLLOCAL int execBaseClassConstructorArgs(BCEAList* bceal, ExceptionSink* xsink) const;
1367};
1368
1369typedef std::pair<QoreClass*, bool> class_virt_pair_t;
1370//typedef std::list<class_virt_pair_t> class_list_t;
1371typedef std::vector<class_virt_pair_t> class_list_t;
1372
1373// member initialization list entry
1374hashdecl member_init_entry_t {
1375 const char* name;
1376 const QoreMemberInfo* info;
1377 const qore_class_private* member_class_ctx;
1378
1379 DLLLOCAL member_init_entry_t(const char* name, const QoreMemberInfo* info, const qore_class_private* member_class_ctx) :
1380 name(name), info(info), member_class_ctx(member_class_ctx) {
1381 }
1382};
1383
1384// list of members in initialization order
1385typedef std::vector<member_init_entry_t> member_init_list_t;
1386
1387// BCSMList: Base Class Special Method List
1388// unique list of base classes for a class hierarchy to ensure that "special" methods, constructor(), destructor(), copy() - are executed only once
1389// this class also tracks virtual classes to ensure that they are not inserted into the list in a complex tree and executed here
1390class BCSMList : public class_list_t {
1391public:
1392 DLLLOCAL BCSMList() {
1393 }
1394
1395 DLLLOCAL BCSMList(const BCSMList &old);
1396
1397 DLLLOCAL ~BCSMList();
1398
1399 DLLLOCAL void processMemberInitializationList(const QoreMemberMap& members, member_init_list_t& member_init_list);
1400
1401 DLLLOCAL int add(QoreClass* thisclass, QoreClass* qc, bool is_virtual);
1402 DLLLOCAL int addBaseClassesToSubclass(QoreClass* thisclass, QoreClass* sc, bool is_virtual);
1403
1404 DLLLOCAL void alignBaseClassesInSubclass(QoreClass* thisclass, QoreClass* child, bool is_virtual);
1405
1406 // returns 0 = can add, non-0 = cannot add
1407 DLLLOCAL void align(QoreClass* thisclass, QoreClass* qc, bool is_virtual);
1408
1409 DLLLOCAL const QoreClass* getClass(qore_classid_t cid) const;
1410 //DLLLOCAL void execConstructors(QoreObject* o, BCEAList* bceal, ExceptionSink* xsink) const;
1411 DLLLOCAL void execDestructors(QoreObject* o, ExceptionSink* xsink) const;
1412 DLLLOCAL void execSystemDestructors(QoreObject* o, ExceptionSink* xsink) const;
1413 DLLLOCAL void execCopyMethods(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const;
1414
1415 // parseResolve classes to the new class pointer after all namespaces and classes have been copied
1416 DLLLOCAL void resolveCopy();
1417};
1418
1419// set of private class pointers; used when checking for recursive class inheritance lists
1420typedef vector_set_t<qore_class_private*> qcp_set_t;
1421//typedef std::set<qore_class_private*> qcp_set_t;
1422
1423// BCNode
1424// base class pointer
1425class BCNode {
1426public:
1427 // populated automatically on creation
1428 const QoreProgramLocation* loc;
1429 NamedScope* cname = nullptr;
1430 char* cstr = nullptr;
1431 QoreClass* sclass = nullptr;
1432 ClassAccess access;
1433 bool is_virtual : 1;
1434
1435 DLLLOCAL BCNode(const QoreProgramLocation* loc, NamedScope* c, ClassAccess a) : loc(loc), cname(c), access(a),
1436 is_virtual(false) {
1437 }
1438
1439 // this method takes ownership of *str
1440 DLLLOCAL BCNode(const QoreProgramLocation* loc, char* str, ClassAccess a) : loc(loc), cstr(str), access(a),
1441 is_virtual(false) {
1442 }
1443
1444 // for builtin base classes
1445 DLLLOCAL BCNode(const QoreProgramLocation* loc, QoreClass* qc, bool n_virtual = false) : loc(loc), sclass(qc),
1446 access(Public), is_virtual(n_virtual) {
1447 }
1448
1449 // called at runtime with committed classes
1450 DLLLOCAL BCNode(const BCNode &old) : loc(old.loc), sclass(old.sclass), access(old.access),
1451 is_virtual(old.is_virtual) {
1452 assert(!old.cname);
1453 assert(!old.cstr);
1454 assert(old.sclass);
1455 }
1456
1457 DLLLOCAL ~BCNode() {
1458 delete cname;
1459 if (cstr)
1460 free(cstr);
1461 }
1462
1463 DLLLOCAL int tryResolveClass(QoreClass* cls, bool raise_error);
1464
1465 DLLLOCAL ClassAccess getAccess() const { return access; }
1466
1467 // returns -1 if a recursive reference is found, 0 if not
1468 DLLLOCAL int initializeHierarchy(QoreClass* cls, qcp_set_t& qcp_set);
1469
1470 DLLLOCAL int initializeMembers(QoreClass* cls);
1471
1472 // returns -1 if a recursive reference is found, 0 if not
1473 DLLLOCAL int initialize(QoreClass* cls);
1474
1475 DLLLOCAL bool isBaseClass(QoreClass* qc, bool toplevel) const;
1476
1477 DLLLOCAL const QoreMethod* runtimeFindCommittedMethod(const char* name, ClassAccess& n_access,
1478 const qore_class_private* class_ctx, bool allow_internal) const;
1479 DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethod(const char* name, ClassAccess& n_access,
1480 const qore_class_private* class_ctx, bool allow_internal) const;
1481
1482 DLLLOCAL bool runtimeIsPrivateMember(const char* str, bool toplevel) const;
1483
1484 DLLLOCAL void execConstructors(QoreObject* o, BCEAList* bceal, ExceptionSink* xsink) const;
1485
1486 DLLLOCAL const QoreMemberInfo* parseFindMember(const char* mem, const qore_class_private*& qc,
1487 ClassAccess& n_access, bool toplevel) const;
1488 DLLLOCAL const QoreVarInfo* parseFindVar(const char* name, const qore_class_private*& qc, ClassAccess& n_access,
1489 bool toplevel) const;
1490
1491 DLLLOCAL const QoreClass* findInHierarchy(const qore_class_private& qc);
1492
1493 DLLLOCAL const QoreClass* getClass(qore_classid_t cid, ClassAccess& n_access, bool toplevel) const;
1494 DLLLOCAL const QoreClass* getClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1495 DLLLOCAL const QoreClass* parseGetClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1496 DLLLOCAL bool inHierarchy(const qore_class_private& qc, ClassAccess& n_access) const;
1497 DLLLOCAL bool inHierarchyStrict(const qore_class_private& qc, ClassAccess& n_access) const;
1498
1499 // inaccessible methods are ignored
1500 DLLLOCAL const QoreMethod* parseFindNormalMethod(const char* name, const qore_class_private* class_ctx,
1501 bool allow_internal) const;
1502
1503 // inaccessible methods are ignored
1504 DLLLOCAL const QoreMethod* parseFindStaticMethod(const char* name, const qore_class_private* class_ctx,
1505 bool allow_internal) const;
1506
1507 // inaccessible methods are ignored
1508 DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, const char* name,
1509 const qore_class_private* class_ctx, bool allow_internal) const;
1510
1511 DLLLOCAL bool parseCheckHierarchy(const QoreClass* cls, ClassAccess& n_access, bool toplevel) const;
1512
1513 DLLLOCAL QoreVarInfo* parseFindStaticVar(const char* vname, const QoreClass*& qc, ClassAccess& n_access,
1514 bool check, bool toplevel) const;
1515
1516 DLLLOCAL QoreValue parseFindConstantValue(const char* cname, const QoreTypeInfo*& typeInfo, bool &found,
1517 const qore_class_private* class_ctx, bool allow_internal) const;
1518
1519 DLLLOCAL int addBaseClassesToSubclass(QoreClass* child, bool is_virtual);
1520
1521 DLLLOCAL void initializeBuiltin();
1522};
1523
1524typedef std::vector<BCNode*> bclist_t;
1525
1526// BCList
1527// linked list of base classes, constructors called head->tail,
1528// destructors called in reverse order (tail->head) (stored in BCSMList)
1529// note that this data structure cannot be modified even if the class is
1530// copied to a subprogram object and extended
1531// this class is a QoreReferenceCounter so it won't be copied when the class is copied
1532class BCList : public bclist_t {
1533protected:
1534public:
1535 // special method (constructor, destructor, copy) list for superclasses
1536 BCSMList sml;
1537 bool valid = true;
1538 bool rescanned = false;
1539
1540 DLLLOCAL BCList(BCNode* n) {
1541 push_back(n);
1542 }
1543
1544 DLLLOCAL BCList() {
1545 }
1546
1547 DLLLOCAL BCList(const BCList& old) : sml(old.sml) {
1548 assert(old.valid);
1549 reserve(old.size());
1550 for (bclist_t::const_iterator i = old.begin(), e = old.end(); i != e; ++i)
1551 push_back(new BCNode(*(*i)));
1552 }
1553
1554 DLLLOCAL ~BCList() {
1555 for (bclist_t::iterator i = begin(), e = end(); i != e; ++i)
1556 delete *i;
1557 }
1558
1559 DLLLOCAL int initializeHierarchy(QoreClass* thisclass, qcp_set_t& qcp_set);
1560
1561 DLLLOCAL int initializeMembers(QoreClass* thisclass);
1562
1563 DLLLOCAL int initialize(QoreClass* thisclass);
1564
1565 // inaccessible methods are ignored
1566 DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, const char* name,
1567 const qore_class_private* class_ctx, bool allow_internal);
1568
1569 // inaccessible methods are ignored
1570 DLLLOCAL const QoreMethod* parseFindNormalMethod(const char* name, const qore_class_private* class_ctx,
1571 bool allow_internal);
1572 // inaccessible methods are ignored
1573 DLLLOCAL const QoreMethod* parseFindStaticMethod(const char* name, const qore_class_private* class_ctx,
1574 bool allow_internal);
1575
1576 DLLLOCAL const QoreMethod* runtimeFindCommittedMethod(const char* name, ClassAccess& access,
1577 const qore_class_private* class_ctx, bool allow_internal) const;
1578 DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethod(const char* name, ClassAccess& access,
1579 const qore_class_private* class_ctx, bool allow_internal) const;
1580
1581 DLLLOCAL bool match(const QoreClass* cls);
1582 DLLLOCAL void execConstructors(QoreObject* o, BCEAList* bceal, ExceptionSink* xsink) const;
1583
1584 DLLLOCAL bool runtimeIsPrivateMember(const char* str, bool toplevel) const;
1585
1586 DLLLOCAL bool parseCheckHierarchy(const QoreClass* cls, ClassAccess& access, bool toplevel) const;
1587
1588 DLLLOCAL const QoreMemberInfo* parseFindMember(const char* mem, const qore_class_private*& qc,
1589 ClassAccess& n_access, bool toplevel) const;
1590
1591 DLLLOCAL const QoreVarInfo* parseFindVar(const char* vname, const qore_class_private*& qc, ClassAccess& access,
1592 bool toplevel) const;
1593
1594 DLLLOCAL bool parseHasPublicMembersInHierarchy() const;
1595
1596 DLLLOCAL const QoreClass* findInHierarchy(const qore_class_private& qc);
1597
1598 DLLLOCAL const QoreClass* getClass(qore_classid_t cid, ClassAccess& n_access, bool toplevel) const;
1599 DLLLOCAL const QoreClass* getClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1600
1601 DLLLOCAL const QoreClass* parseGetClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1602 DLLLOCAL bool inHierarchy(const qore_class_private& qc, ClassAccess& n_access) const;
1603 DLLLOCAL bool inHierarchyStrict(const qore_class_private& qc, ClassAccess& n_access) const;
1604
1605 DLLLOCAL void addNewAncestors(QoreMethod* m);
1606 DLLLOCAL void addAncestors(QoreMethod* m);
1607 DLLLOCAL void addNewStaticAncestors(QoreMethod* m);
1608 DLLLOCAL void addStaticAncestors(QoreMethod* m);
1609 DLLLOCAL void parseAddAncestors(QoreMethod* m);
1610 DLLLOCAL void parseAddStaticAncestors(QoreMethod* m);
1611
1612 DLLLOCAL void parseResolveAbstract();
1613
1614 DLLLOCAL QoreValue parseFindConstantValue(const char* cname, const QoreTypeInfo*& typeInfo, bool& found,
1615 const qore_class_private* class_ctx, bool allow_internal) const;
1616
1617 DLLLOCAL QoreVarInfo* parseFindStaticVar(const char* vname, const QoreClass*& qc, ClassAccess& access, bool check,
1618 bool toplevel) const;
1619
1620 DLLLOCAL void resolveCopy();
1621
1622 DLLLOCAL MethodVariantBase* matchNonAbstractVariant(const std::string& name, MethodVariantBase* v) const;
1623
1624 DLLLOCAL bool isBaseClass(QoreClass* qc, bool toplevel) const;
1625
1626 DLLLOCAL int addBaseClassesToSubclass(QoreClass* thisparent, QoreClass* child, bool is_virtual) {
1627 for (auto& i : *this) {
1628 if ((*i).addBaseClassesToSubclass(child, is_virtual))
1629 return -1;
1630 }
1631 return sml.addBaseClassesToSubclass(thisparent, child, is_virtual);
1632 }
1633
1634 DLLLOCAL void rescanParents(QoreClass* cls);
1635
1636 DLLLOCAL void initializeBuiltin() {
1637 for (auto& i : *this) {
1638 (*i).initializeBuiltin();
1639 }
1640 }
1641};
1642
1643// BCEANode
1644// base constructor evaluated argument node; created locally at run time
1645class BCEANode {
1646public:
1647 const QoreProgramLocation* loc;
1648 QoreListNode* args = nullptr;
1649 const AbstractQoreFunctionVariant* variant = nullptr;
1650 bool execed = false;
1651 bool member_init_done = false;
1652
1653 DLLLOCAL BCEANode(const QoreProgramLocation* loc, QoreListNode* args, const AbstractQoreFunctionVariant* variant) : loc(loc), args(args), variant(reinterpret_cast<const MethodVariant*>(variant)) {
1654 }
1655
1656 DLLLOCAL BCEANode(bool n_execed = true, bool mid = true) : execed(n_execed), member_init_done(mid) {
1657 }
1658};
1659
1660/*
1661hashdecl ltqc {
1662 bool operator()(const QoreClass* qc1, const QoreClass* qc2) const {
1663 return qc1 < qc2;
1664 }
1665};
1666*/
1667
1668//typedef std::map<qore_classid_t, BCEANode*> bceamap_t;
1669typedef vector_map_t<qore_classid_t, BCEANode*> bceamap_t;
1670
1671/*
1672 BCEAList
1673 base constructor evaluated argument list
1674*/
1675class BCEAList : public bceamap_t {
1676protected:
1677 DLLLOCAL ~BCEAList() {
1678 assert(empty());
1679 }
1680
1681public:
1682 DLLLOCAL void deref(ExceptionSink* xsink);
1683 // evaluates arguments, returns -1 if an exception was thrown
1684 DLLLOCAL int add(qore_classid_t classid, const QoreListNode* arg, const AbstractQoreFunctionVariant* variant, const QoreProgramLocation* loc, ExceptionSink* xsink);
1685 DLLLOCAL QoreListNode* findArgs(qore_classid_t classid, bool* aexeced, const AbstractQoreFunctionVariant*& variant, const QoreProgramLocation*& loc);
1686 /*
1687 DLLLOCAL bool initMembers(qore_classid_t classid) {
1688 bceamap_t::iterator i = lower_bound(classid);
1689 if (i == end() || i->first != classid) {
1690 insert(i, bceamap_t::value_type(classid, new BCEANode(false, true)));
1691 return false;
1692 }
1693 if (!i->second->member_init_done) {
1694 i->second->member_init_done = true;
1695 return false;
1696 }
1697 return true;
1698 }
1699 */
1700};
1701
1702hashdecl SelfInstantiatorHelper {
1703 LocalVar* selfid;
1704 DLLLOCAL SelfInstantiatorHelper(LocalVar* n_selfid, QoreObject* self) : selfid(n_selfid) {
1705 selfid->instantiateSelf(self);
1706 }
1707 DLLLOCAL ~SelfInstantiatorHelper() {
1708 selfid->uninstantiateSelf();
1709 }
1710};
1711
1712// signature hash size - we use SHA1 for performance reasons (and because we don't necessarily need the best cryptographic security)
1713#define SH_SIZE 20
1714
1715// class "signature" hash for comparing classes with the same name from different program objects at runtime
1716class SignatureHash {
1717protected:
1718 unsigned char buf[SH_SIZE];
1719 bool is_set;
1720
1721 DLLLOCAL void set(const QoreString& str);
1722
1723 DLLLOCAL void clearHash() {
1724 memset(buf, 0, SH_SIZE);
1725 }
1726
1727 DLLLOCAL void copyHash(const SignatureHash& other) {
1728 memcpy(buf, other.buf, SH_SIZE);
1729 }
1730
1731public:
1732 DLLLOCAL SignatureHash() : is_set(false) {
1733 clearHash();
1734 }
1735
1736 DLLLOCAL SignatureHash(const SignatureHash& old) : is_set(old.is_set) {
1737 if (is_set)
1738 copyHash(old);
1739 }
1740
1741 DLLLOCAL void update(const QoreString& str);
1742
1743 DLLLOCAL void updateEmpty() {
1744 assert(!is_set);
1745 clearHash();
1746 is_set = true;
1747 }
1748
1749 DLLLOCAL bool operator==(const SignatureHash& other) const {
1750 // if either one of the hashes is not set, then the comparison always fails
1751 if (!is_set || !other.is_set)
1752 return false;
1753 return !memcmp(buf, other.buf, SH_SIZE);
1754 }
1755
1756 DLLLOCAL SignatureHash& operator=(const SignatureHash& other) {
1757 if (!other.is_set) {
1758 assert(false);
1759 clear();
1760 } else {
1761 if (!is_set)
1762 is_set = true;
1763 copyHash(other);
1764 }
1765 return *this;
1766 }
1767
1768 DLLLOCAL operator bool() const {
1769 return is_set;
1770 }
1771
1772 // appends the hash to the string
1773 DLLLOCAL void toString(QoreString& str) const {
1774 for (unsigned i = 0; i < SH_SIZE; ++i) {
1775 str.sprintf("%02x", buf[i]);
1776 }
1777 }
1778
1779#ifdef DEBUG
1780 // for debugging only; uses a static buffer
1781 DLLLOCAL const char* debugToString() const {
1782 static QoreString str;
1783 str.clear();
1784 for (unsigned i = 0; i < SH_SIZE; ++i) {
1785 str.sprintf("%02x", buf[i]);
1786 }
1787 return str.c_str();
1788 }
1789#endif
1790
1791 DLLLOCAL char* getHash() const {
1792 assert(is_set);
1793 return (char*)buf;
1794 }
1795
1796 DLLLOCAL void clear() {
1797 if (is_set) {
1798 is_set = false;
1799 clearHash();
1800 }
1801 }
1802};
1803
1804#define QCCM_NORMAL (1 << 0)
1805#define QCCM_STATIC (1 << 1)
1806
1807// set of QoreClass pointers associated to a qore_class_private object
1808typedef vector_set_t<QoreClass*> qc_set_t;
1809//typedef std::set<QoreClass*> qc_set_t;
1810
1811// private QoreClass implementation
1812// only dynamically allocated; reference counter managed in "refs"
1813class qore_class_private {
1814public:
1815 const QoreProgramLocation* loc; // location of declaration
1816 std::string name; // the name of the class
1817 std::string path; // the full namespace path for the class
1818 QoreClass* cls; // parent class
1819 qore_ns_private* ns = nullptr; // parent namespace
1820 BCList* scl = nullptr; // base class list
1821 qc_set_t qcset; // set of QoreClass pointers associated with this private object (besides cls)
1822
1823 mutable VRMutex gate; // for synchronized static methods
1824
1825 hm_method_t hm, // "normal" (non-static) method map
1826 shm; // static method map
1827
1828 AbstractMethodMap ahm; // holds abstract variants with no implementation in the current class
1829
1830 ConstantList constlist; // class constants
1831
1832 // member list (map)
1833 QoreMemberMap members;
1834 // member initialization list in hierarchy nitialization order
1835 member_init_list_t member_init_list;
1836
1837 // static var list (map)
1838 QoreVarMap vars;
1839
1840 const QoreMethod* system_constructor = nullptr,
1841 * constructor = nullptr,
1842 * destructor = nullptr,
1843 * copyMethod = nullptr,
1844 * methodGate = nullptr,
1845 * memberGate = nullptr,
1846 * memberNotification = nullptr;
1847
1848 q_serializer_t serializer = nullptr;
1849 q_deserializer_t deserializer = nullptr;
1850
1851 qore_classid_t classID, // class ID
1852 methodID; // for subclasses of builtin classes that will not have their own private data,
1853 // instead they will get the private data from this class
1854
1855 bool sys : 1, // system/builtin class?
1856 initialized : 1, // is initialized? (only performed once)
1857 static_init : 1, // has static initialization been called for the class?
1858 parse_init_called : 1, // has parseInit() been called? (performed once for each parseCommit())
1859 parse_init_partial_called : 1, // has parseInitPartial() been called? (performed once for each parseCommit())
1860 has_public_memdecl : 1, // has a public member declaration somewhere in the hierarchy?
1861 pending_has_public_memdecl : 1, // has a pending public member declaration in this class?
1862 owns_typeinfo : 1, // do we own the typeInfo data or not?
1863 resolve_copy_done : 1, // has the copy already been resolved
1864 has_new_user_changes : 1, // does the class have new user code that needs to be processed?
1865 has_sig_changes : 1, // does the class have code affecting the signature to be processed?
1866 owns_ornothingtypeinfo : 1, // do we own the "or nothing" type info
1867 pub : 1, // is a public class (modules only)
1868 final : 1, // is the class "final" (cannot be inherited)
1869 inject : 1, // has the class been injected
1870 gate_access : 1, // if the methodGate and memberGate methods should be called with a class access boolean
1871 committed : 1, // can only parse to a class once
1872 parse_resolve_hierarchy : 1, // class hierarchy resolved
1873 parse_resolve_class_members : 1, // class members resolved
1874 parse_resolve_abstract : 1, // abstract methods resolved
1875 has_transient_member : 1 // has at least one transient member
1876 ;
1877
1878 int64 domain; // capabilities of builtin class to use in the context of parse restrictions
1879 mutable QoreReferenceCounter refs; // existence references
1880 mutable QoreReferenceCounter const_refs; // constant references
1881 mutable QoreReferenceCounter var_refs; // static var references
1882
1883 unsigned num_methods, num_user_methods, num_static_methods, num_static_user_methods;
1884
1885 // type information for the class, may not have a pointer to the same QoreClass
1886 // as the actual owning class in case of a copy
1887 QoreClassTypeInfo* typeInfo = nullptr;
1888 QoreClassOrNothingTypeInfo* orNothingTypeInfo = nullptr;
1889
1890 const qore_class_private* injectedClass = nullptr;
1891
1892 // common "self" local variable for all constructors
1893 mutable LocalVar selfid;
1894
1895 // class "signature" hash for comparing classes with the same name from different program objects at runtime
1896 SignatureHash hash;
1897
1898 // user-specific data
1899 const void* ptr = nullptr;
1900
1901 // managed user-specific data
1902 AbstractQoreClassUserData* mud = nullptr;
1903
1904 // pointer to new class when copying
1905 mutable QoreClass* new_copy = nullptr;
1906
1907 // pointer to owning program for imported classes
1908 QoreProgram* spgm = nullptr;
1909
1910 // if the souorce program should be dereference when the class is destroyed
1911 bool deref_source_program = true;
1912
1913 // the module that defined this class, if any
1914 std::string from_module;
1915
1916 // class language
1917 std::string lang = "Qore";
1918
1919 // class key-value store
1920 typedef std::map<std::string, QoreValue> kvmap_t;
1921 kvmap_t kvmap;
1922
1923 DLLLOCAL qore_class_private(QoreClass* n_cls, std::string&& nme, std::string&& path, int64 dom = QDOM_DEFAULT,
1924 QoreClassTypeInfo* n_typeinfo = nullptr);
1925
1926 // only called while the parse lock for the QoreProgram owning "old" is held
1927 // called for injected classes only
1928 DLLLOCAL qore_class_private(const qore_class_private& old, qore_ns_private* ns, QoreProgram* spgm,
1929 const char* nme, bool inject, const qore_class_private* injectedClass, q_setpub_t set_pub);
1930
1932
1939 DLLLOCAL QoreValue setKeyValue(const std::string& key, QoreValue val);
1940
1942
1951 DLLLOCAL QoreValue setKeyValueIfNotSet(const std::string& key, QoreValue val);
1952
1954
1963 DLLLOCAL bool setKeyValueIfNotSet(const std::string& key, const char* str);
1964
1966
1972 DLLLOCAL QoreValue getReferencedKeyValue(const std::string& key) const;
1973
1975
1981 DLLLOCAL QoreValue getReferencedKeyValue(const char* key) const;
1982
1983 // add a base class to this class
1984 DLLLOCAL void addBaseClass(QoreClass* qc, bool virt);
1985
1986 // This function must only be called from QoreObject
1987 DLLLOCAL QoreValue evalMemberGate(QoreObject* self, const char* nme, ExceptionSink* xsink) const;
1988
1989 DLLLOCAL const char* getModuleName() const {
1990 return from_module.empty() ? nullptr : from_module.c_str();
1991 }
1992
1993 // get base class list to add virtual class indexes for private data
1994 DLLLOCAL BCSMList* getBCSMList() const {
1995 return scl ? &scl->sml : nullptr;
1996 }
1997
1998 DLLLOCAL void pgmRef() const {
1999 refs.ROreference();
2000 var_refs.ROreference();
2001 const_refs.ROreference();
2002 }
2003
2004 DLLLOCAL void ref() const {
2005 refs.ROreference();
2006 }
2007
2008 DLLLOCAL bool deref(bool ns_const, bool ns_vars, bool in_del = false) {
2009 if (ns_const && const_refs.ROdereference()) {
2010 // constants may not be empty when deleting an uninitialized user class
2011 if (!constlist.empty()) {
2012 constlist.deleteAll(nullptr);
2013 }
2014 }
2015 if (ns_vars && var_refs.ROdereference()) {
2016 // vars may not be empty when deleting an uninitialized user class
2017 if (!vars.empty()) {
2018 vars.del(nullptr);
2019 }
2020 }
2021
2022 if (refs.ROdereference()) {
2023 // remove the private data pointer, delete the class object, then delete ourselves
2024 cls->priv = nullptr;
2025 if (!in_del) {
2026 delete cls;
2027 }
2028
2029 // delete all linked QoreClass objects
2030 for (auto& i : qcset) {
2031 i->priv = nullptr;
2032 delete i;
2033 }
2034
2035 delete this;
2036 return true;
2037 }
2038 return false;
2039 }
2040
2041 DLLLOCAL bool hasAbstract() const {
2042 return !ahm.empty();
2043 }
2044
2045 DLLLOCAL void parseSetEmptyPublicMemberDeclaration() {
2046 pending_has_public_memdecl = true;
2047 if (!has_new_user_changes) {
2048 has_new_user_changes = true;
2049 }
2050 }
2051
2052 DLLLOCAL int runtimeCheckInstantiateClass(ExceptionSink* xsink) const {
2053 return ahm.runtimeCheckInstantiateClass(name.c_str(), xsink);
2054 }
2055
2056 DLLLOCAL void parseCheckAbstractNew(const QoreProgramLocation* loc) const;
2057
2058 DLLLOCAL void parseDoCheckAbstractNew(const QoreProgramLocation* loc) const;
2059
2060 DLLLOCAL void setNamespace(qore_ns_private* n) {
2061 assert(!ns);
2062 ns = n;
2063 }
2064
2065 // returns true if the namespace was assigned
2066 DLLLOCAL bool setNamespaceConditional(qore_ns_private* n) {
2067 // only assign the namespace if it hasn't already been assiogned
2068 if (!ns) {
2069 ns = n;
2070 return true;
2071 }
2072 return false;
2073 }
2074
2075 // used when assimilating a namespace at parse time
2076 DLLLOCAL void updateNamespace(qore_ns_private* n) {
2077 assert(ns);
2078 assert(ns != n);
2079 ns = n;
2080 }
2081
2082 DLLLOCAL void resolveCopy();
2083
2084 DLLLOCAL void setUserData(const void* n_ptr) {
2085 assert(!ptr);
2086 ptr = n_ptr;
2087 }
2088
2089 DLLLOCAL const void* getUserData() const {
2090 return ptr;
2091 }
2092
2093 DLLLOCAL void setManagedUserData(AbstractQoreClassUserData* n_mud) {
2094 assert(!mud);
2095 mud = n_mud;
2096 }
2097
2098 DLLLOCAL AbstractQoreClassUserData* getManagedUserData() const {
2099 return mud;
2100 }
2101
2102 DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
2103 return typeInfo;
2104 }
2105
2106 DLLLOCAL const QoreTypeInfo* getOrNothingTypeInfo() const {
2107 return orNothingTypeInfo;
2108 }
2109
2110 DLLLOCAL bool runtimeIsPrivateMemberIntern(const char* str, bool toplevel) const;
2111
2112 DLLLOCAL void parseImportMembers(qore_class_private& qc, ClassAccess access);
2113
2114 DLLLOCAL bool parseHasMemberGate() const {
2115 return memberGate || hm.find("memberGate") != hm.end() || ahm.find("memberGate") != ahm.end();
2116 }
2117
2118 DLLLOCAL bool parseHasMethodGate() const {
2119 return methodGate || hm.find("methodGate") != hm.end() || ahm.find("methodGate") != ahm.end();
2120 }
2121
2122 // checks for all special methods except constructor & destructor
2123 DLLLOCAL bool checkAssignSpecialIntern(const QoreMethod* m) {
2124 // set quick pointers
2125 if (!methodGate && !strcmp(m->getName(), "methodGate")) {
2126 methodGate = m;
2127 return true;
2128 }
2129
2130 if (!memberGate && !strcmp(m->getName(), "memberGate")) {
2131 memberGate = m;
2132 //printd(5, "qore_class_private::checkAssignSpecialIntern() this: %p got %s::%s()\n", this, name.c_str(), m->getName());
2133 return true;
2134 }
2135
2136 if (!memberNotification && !strcmp(m->getName(), "memberNotification")) {
2137 memberNotification = m;
2138 return true;
2139 }
2140
2141 return false;
2142 }
2143
2144 // checks for all special methods except constructor, destructor, and copy
2145 DLLLOCAL bool checkSpecialStaticIntern(const char* mname) {
2146 // set quick pointers
2147 if ((!methodGate && !strcmp(mname, "methodGate"))
2148 || (!memberGate && !strcmp(mname, "memberGate"))
2149 || (!memberNotification && !strcmp(mname, "memberNotification")))
2150 return true;
2151 return false;
2152 }
2153
2154 // checks for all special methods
2155 DLLLOCAL bool checkSpecial(const char* mname) {
2156 // set quick pointers
2157 if ((!methodGate && !strcmp(mname, "methodGate"))
2158 || (!memberGate && !strcmp(mname, "memberGate"))
2159 || (!memberNotification && !strcmp(mname, "memberNotification"))
2160 || (!constructor && !strcmp(mname, "constructor"))
2161 || (!destructor && !strcmp(mname, "destructor"))
2162 || (!copyMethod && !strcmp(mname, "copy")))
2163 return true;
2164 return false;
2165 }
2166
2167 // checks for all special methods
2168 DLLLOCAL bool checkAssignSpecial(const QoreMethod* m) {
2169 // set quick pointers
2170 if (!constructor && !strcmp(m->getName(), "constructor")) {
2171 constructor = m;
2172 return true;
2173 }
2174
2175 if (!destructor && !strcmp(m->getName(), "destructor")) {
2176 destructor = m;
2177 return true;
2178 }
2179
2180 if (!copyMethod && !strcmp(m->getName(), "copy")) {
2181 copyMethod = m;
2182 return true;
2183 }
2184
2185 return checkAssignSpecialIntern(m);
2186 }
2187
2188 // merge abstract variants from base classes to child class
2189 DLLLOCAL void mergeAbstract();
2190
2191 // returns -1 if a recursive inheritance list was found, 0 if not
2192 DLLLOCAL int initializeIntern();
2193 DLLLOCAL int initializeHierarchy(qcp_set_t& qcp_set);
2194 DLLLOCAL int initializeMembers();
2195 DLLLOCAL int initialize();
2196
2197 DLLLOCAL int parseInitPartial();
2198 DLLLOCAL int parseInitPartialIntern();
2199
2200 DLLLOCAL int parseCheckMemberAccess(const QoreProgramLocation* loc, const char* mem,
2201 const QoreTypeInfo*& memberTypeInfo, int pflag) const {
2202 const_cast<qore_class_private*>(this)->parseInitPartial();
2203
2204 const qore_class_private* qc = nullptr;
2205 ClassAccess access;
2206 const QoreMemberInfo* omi = parseFindMember(mem, qc, access);
2207
2208 if (!omi) {
2209 int rc = 0;
2210 if (!parseHasMemberGate() || (pflag & PF_FOR_ASSIGNMENT)) {
2211 if (parse_check_parse_option(PO_REQUIRE_TYPES)) {
2212 parse_error(*loc, "member '%s' of class '%s' referenced has no type information because it was " \
2213 "not declared in a public or private member list, but parse options require type " \
2214 "information for all declarations",
2215 mem, name.c_str());
2216 rc = -1;
2217 }
2218 if (parseHasPublicMembersInHierarchy()) {
2219 //printd(5, "qore_class_private::parseCheckMemberAccess() %s %%.%s memberGate: %d pflag: %d\n",
2220 // name.c_str(), mem, parseHasMemberGate(), pflag);
2221 parse_error(*loc, "illegal access to unknown member '%s' in class '%s' which has a public " \
2222 "member list (or inherited public member list)", mem, name.c_str());
2223 rc = -1;
2224 }
2225 }
2226 return rc;
2227 }
2228
2229 memberTypeInfo = omi->getTypeInfo();
2230
2231 // only raise a parse error for illegal access to private members if there is not memberGate function
2232 if ((access > Public) && !parseHasMemberGate() && !parseCheckPrivateClassAccess()) {
2233 memberTypeInfo = nullptr;
2234 parse_error(*loc, "illegal access to private member '%s' of class '%s'", mem, name.c_str());
2235 return -1;
2236 }
2237 return 0;
2238 }
2239
2240 DLLLOCAL int parseResolveInternalMemberAccess(const char* mem, const QoreTypeInfo*& memberTypeInfo) const {
2241 const_cast<qore_class_private*>(this)->parseInitPartial();
2242
2243 const qore_class_private* qc = nullptr;
2244 ClassAccess access;
2245 const QoreMemberInfo* omi = parseFindMember(mem, qc, access);
2246 if (omi) {
2247 memberTypeInfo = omi->getTypeInfo();
2248 }
2249
2250 return omi ? 0 : -1;
2251 }
2252
2253 DLLLOCAL int parseCheckInternalMemberAccess(const char* mem, const QoreTypeInfo*& memberTypeInfo,
2254 const QoreProgramLocation* loc) const {
2255 const_cast<qore_class_private*>(this)->parseInitPartial();
2256
2257 // throws a parse exception if there are public members and the name is not valid
2258 const qore_class_private* qc = nullptr;
2259 ClassAccess access;
2260 const QoreMemberInfo* omi = parseFindMember(mem, qc, access);
2261 int rc = 0;
2262 if (omi) {
2263 // issue #3355: to handle out of order initialization properly, we need to ensure that the member is
2264 // initialized before accessing its type. We cannot rely on calling members.parseInit() here because
2265 // we may have already been called by this call
2266 rc = const_cast<QoreMemberInfo*>(omi)->parseInit(mem, selfid);
2267 memberTypeInfo = omi->parseGetTypeInfo();
2268 }
2269
2270 if (!omi) {
2271 if (parse_check_parse_option(PO_REQUIRE_TYPES)) {
2272 parse_error(*loc, "member '%s' of class '%s' referenced has no type information because it was not " \
2273 "declared in a public or private member list, but parse options require type information for " \
2274 "all declarations", mem, name.c_str());
2275 if (!rc) {
2276 rc = -1;
2277 }
2278 }
2279 if (parseHasPublicMembersInHierarchy()) {
2280 parse_error(*loc, "illegal access to unknown member '%s' in class '%s' which has a public member " \
2281 "list (or inherited public member list)", mem, name.c_str());
2282 if (!rc) {
2283 rc = -1;
2284 }
2285 }
2286 }
2287 return rc;
2288 }
2289
2290 DLLLOCAL bool parseHasPublicMembersInHierarchy() const {
2291 if (has_public_memdecl || pending_has_public_memdecl)
2292 return true;
2293
2294 return scl ? scl->parseHasPublicMembersInHierarchy() : false;
2295 }
2296
2304 DLLLOCAL const qore_class_private* runtimeGetMemberContext(const char* mem, const qore_class_private* class_ctx) const {
2305 const QoreMemberInfo* info = runtimeGetMemberInfo(mem, class_ctx);
2306 //printd(5, "qore_class_private::runtimeGetMemberContext() this: %p '%s' mem: '%s' info: %p member class: %p '%s' ctx(%p): %p (size: %d)\n", this, name.c_str(), mem, info, info ? info->getClass() : nullptr, info ? info->getClass()->name.c_str() : "n/a", class_ctx, info ? info->getClassContext(class_ctx) : nullptr, info ? info->getContextSize() : 0);
2307 return info ? info->getClassContext(class_ctx) : nullptr;
2308 }
2309
2310 DLLLOCAL bool runtimeIsMemberInternal(const char* mem) const {
2311 QoreMemberInfo* info = members.find(mem);
2312 return info && info->isLocalInternal() ? true : false;
2313 }
2314
2324 DLLLOCAL const QoreMemberInfo* runtimeGetMemberInfo(const char* mem, const qore_class_private* class_ctx) const {
2325 QoreMemberInfo* info;
2326 if (class_ctx) {
2327 info = class_ctx->members.find(mem);
2328 if (info && info->isLocalInternal()) {
2329 return info;
2330 }
2331 } else {
2332 info = nullptr;
2333 }
2334
2335 if (class_ctx != this) {
2336 info = members.find(mem);
2337 }
2338
2339 if (info && info->access == Inaccessible && !info->getClassContext(class_ctx)) {
2340 info = nullptr;
2341 }
2342
2343 return info;
2344 }
2345
2346 DLLLOCAL const QoreMemberInfo* parseFindMember(const char* mem, const qore_class_private*& qc, ClassAccess& access) const {
2347 access = Public;
2348 const_cast<qore_class_private*>(this)->initialize();
2349 return parseFindMemberNoInit(mem, qc, access, true);
2350 }
2351
2352 // returns the member if it's defined and reachable from the class and cannot be declared again in the top-level class
2355 DLLLOCAL const QoreMemberInfo* parseFindMemberNoInit(const char* mem, const qore_class_private*& qc, ClassAccess& access, bool toplevel) const {
2356 const QoreMemberInfo* mi = members.find(mem);
2357 if (mi) {
2358 ClassAccess ma = mi->getAccess();
2359 if (toplevel || ma < Internal) {
2360 if (access < ma) {
2361 access = ma;
2362 }
2363 qc = mi->getClass();
2364 return mi;
2365 }
2366 }
2367
2368 return scl ? scl->parseFindMember(mem, qc, access, true) : 0;
2369 }
2370
2371 DLLLOCAL const QoreVarInfo* parseFindVar(const char* vname, const qore_class_private*& qc, ClassAccess& access, bool toplevel) const {
2372 //printd(5, "parseFindVar() this: %p cls: %p (%s) scl: %p\n", this, cls, cls->getName(), scl);
2373
2374 QoreVarInfo* vi = vars.find(const_cast<char*>(vname));
2375
2376 if (vi) {
2377 qc = this;
2378 access = vi->getAccess();
2379 return vi;
2380 }
2381
2382 return scl ? scl->parseFindVar(vname, qc, access, toplevel) : nullptr;
2383 }
2384
2385 DLLLOCAL int parseCheckClassHierarchyMembers(const char* mname, const QoreMemberInfo& l_mi, const QoreMemberInfo& b_mi) const;
2386
2387 DLLLOCAL int checkExistingVarMember(const char* dname, const QoreMemberInfoBaseAccess* mi, const QoreMemberInfoBaseAccess* omi, const qore_class_private* qc, ClassAccess oaccess, bool var = false) const;
2388
2389 DLLLOCAL int parseCheckVar(const char* dname, const QoreVarInfo* vi) const {
2390 const qore_class_private* qc = 0;
2391 ClassAccess access;
2392 const QoreVarInfo* ovi = parseFindVar(dname, qc, access, true);
2393 //printd(5, "parseCheckVar() %s cls: %p (%s)\n", dname, sclass, sclass ? sclass->getName() : "n/a");
2394 if (!ovi) {
2395 if (parseHasConstant(dname)) {
2396 parse_error(*vi->loc, "'%s' has already been declared as a constant in class '%s' and therefore cannot be also declared as a static class variable in the same class with the same name", dname, name.c_str());
2397 return -1;
2398 }
2399 return 0;
2400 }
2401
2402 return checkExistingVarMember(dname, vi, ovi, qc, access, true);
2403 }
2404
2405 DLLLOCAL int parseCheckMember(const char* mem, const QoreMemberInfo* mi) const {
2406 const qore_class_private* qc = nullptr;
2407 ClassAccess access = Public;
2408 const QoreMemberInfo* omi = parseFindMemberNoInit(mem, qc, access, true);
2409 if (!omi) {
2410 return 0;
2411 }
2412
2413 return checkExistingVarMember(mem, mi, omi, qc, omi->access);
2414 }
2415
2416 DLLLOCAL int parseCheckMemberInBaseClasses(const char* mem, const QoreMemberInfo* mi) const {
2417 const qore_class_private* qc = nullptr;
2418 ClassAccess access = Public;
2419 // issue #2970: do not check classes inherited by direct parents with private:internal inheritance
2420 // as these members cannot cause a conflict
2421 const QoreMemberInfo* omi = scl ? scl->parseFindMember(mem, qc, access, false) : nullptr;
2422 if (!omi || (omi->getClass() == mi->getClass())) {
2423 return 0;
2424 }
2425
2426 return checkExistingVarMember(mem, mi, omi, qc, omi->access);
2427 }
2428
2429 DLLLOCAL int parseCheckSystemCommitted(const QoreProgramLocation* loc) {
2430 if (sys) {
2431 parse_error(*loc, "cannot modify system class '%s'", name.c_str());
2432 return -1;
2433 }
2434 if (committed) {
2435 parse_error(*loc, "cannot modify user class '%s' once it's been committed", name.c_str());
2436 return -1;
2437 }
2438 return 0;
2439 }
2440
2441 DLLLOCAL void parseAddMember(char* mem, ClassAccess access, QoreMemberInfo* memberInfo) {
2442 memberInfo->access = access;
2443 if (!parseCheckSystemCommitted(memberInfo->loc) && !parseCheckMember(mem, memberInfo)) {
2444 if (!has_new_user_changes) {
2445 has_new_user_changes = true;
2446 }
2447 if (!has_sig_changes) {
2448 has_sig_changes = true;
2449 }
2450 memberInfo->setDeclaringClass(this);
2451 if (!has_transient_member && memberInfo->getTransient()) {
2452 has_transient_member = true;
2453 }
2454 //printd(5, "qore_class_private::parseAddMember() this: %p %s adding %s %p %s\n", this, name.c_str(), privpub(access), mem, mem);
2455 members.addNoCheck(mem, memberInfo);
2456 return;
2457 }
2458
2459 free(mem);
2460 delete memberInfo;
2461 }
2462
2463 DLLLOCAL void parseAddStaticVar(char* dname, ClassAccess access, QoreVarInfo* VarInfo) {
2464 VarInfo->access = access;
2465 if (!parseCheckSystemCommitted(VarInfo->loc) && !parseCheckVar(dname, VarInfo)) {
2466 if (!has_new_user_changes) {
2467 has_new_user_changes = true;
2468 }
2469 if (!has_sig_changes) {
2470 has_sig_changes = true;
2471 }
2472
2473 //printd(5, "qore_class_private::parseAddStaticVar() this: %p %s adding %p %s\n", this, name.c_str(), mem, mem);
2474 vars.addNoCheck(dname, VarInfo);
2475 return;
2476 }
2477
2478 free(dname);
2479 delete VarInfo;
2480 }
2481
2482 DLLLOCAL void addBuiltinConstant(const char* cname, QoreValue value, ClassAccess access = Public, const QoreTypeInfo* cTypeInfo = nullptr) {
2483 assert(!constlist.inList(cname));
2484 if (!sys) {
2485 sys = committed = true;
2486 }
2487 constlist.add(cname, value, cTypeInfo, access);
2488 }
2489
2490 DLLLOCAL void addBuiltinStaticVar(const char* vname, QoreValue value, ClassAccess access = Public, const QoreTypeInfo* vTypeInfo = nullptr);
2491
2492 DLLLOCAL void parseAssimilateConstants(ConstantList &cmap, ClassAccess access) {
2493 assert(!sys && !committed);
2494 if (!has_new_user_changes)
2495 has_new_user_changes = true;
2496 if (!has_sig_changes)
2497 has_sig_changes = true;
2498
2499 // set access if necessary
2500 cmap.setAccess(access);
2501 constlist.assimilate(cmap, "class", name.c_str());
2502 }
2503
2504 DLLLOCAL void parseAddConstant(const QoreProgramLocation* loc, const std::string &cname, QoreValue val, ClassAccess access) {
2505 ValueHolder val_holder(val, nullptr);
2506 if (parseCheckSystemCommitted(loc)) {
2507 return;
2508 }
2509 if (parseHasVar(cname.c_str())) {
2510 parse_error(*loc, "'%s' has already been declared as a static variable in class '%s' and therefore cannot be also declared as a constant in the same class with the same name", cname.c_str(), name.c_str());
2511 return;
2512 }
2513 if (!has_new_user_changes)
2514 has_new_user_changes = true;
2515 if (!has_sig_changes)
2516 has_sig_changes = true;
2517
2518 //printd(5, "parseAddConstant() this: %p cls: %p const: %s access: %d\n", this, cls, cname.c_str(), access);
2519
2520 constlist.parseAdd(loc, cname, val_holder.release(), access, name.c_str());
2521 }
2522
2523 DLLLOCAL bool parseHasVar(const char* vn) {
2524 return vars.inList(vn);
2525 }
2526
2527 DLLLOCAL bool parseHasConstant(const std::string &cname) const {
2528 return constlist.inList(cname);
2529 }
2530
2531 DLLLOCAL QoreValue parseFindLocalConstantValue(const char* cname, const QoreTypeInfo*& cTypeInfo, bool& found) {
2532 parseInitPartial();
2533
2534 // first check committed constants
2535 ClassAccess access = Public;
2536 QoreValue rv = constlist.find(cname, cTypeInfo, access, found);
2537
2538 // check for accessibility to private constants
2539 if (found && (access > Public)) {
2540 qore_class_private* class_ctx = parse_get_class_priv();
2541 if ((access >= Internal && class_ctx != this) || !parseCheckPrivateClassAccess(class_ctx)) {
2542 rv.clear();
2543 cTypeInfo = nullptr;
2544 found = false;
2545 }
2546 }
2547
2548 //printd(5, "qore_class_private::parseFindLocalConstantValue(%s) this: %p (cls: %p %s) rv: %p\n", cname, this,
2549 // cls, name.c_str(), rv);
2550 return rv;
2551 }
2552
2553 DLLLOCAL QoreValue parseFindConstantValue(const char* cname, const QoreTypeInfo*& cTypeInfo, bool& found,
2554 const qore_class_private* class_ctx) {
2555 found = false;
2556 return parseFindConstantValueIntern(cname, cTypeInfo, found, class_ctx);
2557 }
2558
2559 DLLLOCAL QoreValue parseFindConstantValueIntern(const char* cname, const QoreTypeInfo*& cTypeInfo, bool& found,
2560 const qore_class_private* class_ctx) {
2561 parseInitPartial();
2562
2563 // check constant list
2564 ClassAccess access = Public;
2565 QoreValue rv = constlist.find(cname, cTypeInfo, access, found);
2566
2567 // check for accessibility to private constants
2568 if (found) {
2569 if (access == Internal) {
2570 if (class_ctx == this)
2571 return rv;
2572 else {
2573 cTypeInfo = nullptr;
2574 found = false;
2575 }
2576 } else if (access == Private && !parseCheckPrivateClassAccess(class_ctx)) {
2577 cTypeInfo = nullptr;
2578 found = false;
2579 } else {
2580 return rv;
2581 }
2582 }
2583
2584 return scl ? scl->parseFindConstantValue(cname, cTypeInfo, found, class_ctx, class_ctx == this) : QoreValue();
2585 }
2586
2587 DLLLOCAL QoreVarInfo* parseFindLocalStaticVar(const char* vname) const {
2588 QoreVarInfo* vi = vars.find(vname);
2589
2590 if (vi && (vi->access > Public) && !parseCheckPrivateClassAccess())
2591 vi = nullptr;
2592
2593 return vi;
2594 }
2595
2596 DLLLOCAL QoreVarInfo* parseFindStaticVar(const char* vname, const QoreClass*& qc, ClassAccess& access, bool check = false) const {
2597 access = Public;
2598 return parseFindStaticVarIntern(vname, qc, access, check, true);
2599 }
2600
2601 DLLLOCAL QoreVarInfo* parseFindStaticVarIntern(const char* vname, const QoreClass*& qc, ClassAccess& access, bool check, bool toplevel) const {
2602 QoreVarInfo* vi = vars.find(vname);
2603
2604 if (vi) {
2605 ClassAccess va = vi->getAccess();
2606 if (toplevel || va != Internal) {
2607 if (access < va) {
2608 access = va;
2609 }
2610
2611 // return null and stop searching in this class if we should verify access, and the var is not accessible
2612 if (check && (access > Public) && !parseCheckPrivateClassAccess()) {
2613 return nullptr;
2614 }
2615
2616 qc = cls;
2617 return vi;
2618 }
2619 }
2620
2621 return scl ? scl->parseFindStaticVar(vname, qc, access, check, toplevel) : nullptr;
2622 }
2623
2624 DLLLOCAL void addMember(const char* mem, ClassAccess access, const QoreTypeInfo* n_typeinfo, QoreValue initial_value) {
2625 assert(!members.inList(mem));
2626 if (!has_sig_changes) {
2627 has_sig_changes = true;
2628 }
2629 members.addNoCheck(strdup(mem), new QoreMemberInfo(&loc_builtin, n_typeinfo, nullptr, initial_value, access, this));
2630 if (access == Public && !has_public_memdecl) {
2631 has_public_memdecl = true;
2632 }
2633 }
2634
2635 DLLLOCAL void insertBuiltinStaticMethod(QoreMethod* m) {
2636 assert(m->isStatic());
2637 //printd(5, "QoreClass::insertBuiltinStaticMethod() %s::%s() size: %d\n", name.c_str(), m->getName(), numMethods());
2638 shm[m->getName()] = m;
2639 // maintain method counts (safely inside parse lock)
2640 ++num_static_methods;
2641 if (!sys) {
2642 sys = committed = true;
2643 }
2644 // check for special methods (except constructor and destructor) and abort if found
2645 assert(!checkSpecialStaticIntern(m->getName()));
2646 // add ancestors
2647 addStaticAncestors(m);
2648 }
2649
2650 DLLLOCAL void insertBuiltinMethod(QoreMethod* m, bool special_method = false) {
2651 assert(!m->isStatic());
2652 //printd(5, "QoreClass::insertBuiltinMethod() %s::%s() size: %d\n", name.c_str(), m->getName(), numMethods());
2653 hm[m->getName()] = m;
2654 // maintain method counts (safely inside parse lock)
2655 ++num_methods;
2656 if (!sys) {
2657 sys = committed = true;
2658 }
2659 // check for special methods (except constructor and destructor)
2660 if (!special_method && !checkAssignSpecialIntern(m))
2661 // add ancestors
2662 addAncestors(m);
2663 }
2664
2665 DLLLOCAL void recheckBuiltinMethodHierarchy();
2666
2667 DLLLOCAL void addNewAncestors(QoreMethod* m) {
2668 if (!scl) {
2669 return;
2670 }
2671
2672 scl->addNewAncestors(m);
2673 }
2674
2675 DLLLOCAL void addNewStaticAncestors(QoreMethod* m) {
2676 if (!scl) {
2677 return;
2678 }
2679
2680 scl->addNewStaticAncestors(m);
2681 }
2682
2683 DLLLOCAL void addStaticAncestors(QoreMethod* m) {
2684 if (!scl) {
2685 return;
2686 }
2687
2688 scl->addStaticAncestors(m);
2689 }
2690
2691 DLLLOCAL void addAncestors(QoreMethod* m) {
2692 assert(strcmp(m->getName(), "constructor"));
2693
2694 if (!scl) {
2695 return;
2696 }
2697
2698 scl->addAncestors(m);
2699 }
2700
2701 DLLLOCAL void parseAddStaticAncestors(QoreMethod* m) {
2702 if (!scl) {
2703 return;
2704 }
2705
2706 scl->parseAddStaticAncestors(m);
2707 }
2708
2709 DLLLOCAL void parseAddAncestors(QoreMethod* m) {
2710 //printd(5, "qore_class_private::parseAddAncestors(%p %s) this: %p cls: %p %s scl: %p\n", m, m->getName(), this, cls, name.c_str(), scl);
2711 assert(strcmp(m->getName(), "constructor"));
2712
2713 if (!scl)
2714 return;
2715
2716 scl->parseAddAncestors(m);
2717 }
2718
2719 DLLLOCAL int initMembers(QoreObject& o, bool& need_scan, ExceptionSink* xsink) const;
2720
2721 DLLLOCAL int initMember(QoreObject& o, bool& need_scan, const char* member_name, const QoreMemberInfo& info, const qore_class_private* member_class_ctx, ExceptionSink* xsink) const;
2722
2723 DLLLOCAL void clearConstants(QoreListNode& l) {
2724 if (const_refs.ROdereference()) {
2725 constlist.clear(l);
2726 }
2727 }
2728
2729 DLLLOCAL void clearConstants(ExceptionSink* xsink) {
2730 if (const_refs.ROdereference()) {
2731 constlist.deleteAll(xsink);
2732 }
2733 }
2734
2735 DLLLOCAL void clear(ExceptionSink* xsink) {
2736 //printd(5, "qore_class_private::clear() this: %p '%s' %d -> %d\n", this, name.c_str(), var_refs.reference_count(), var_refs.reference_count() - 1);
2737
2738 if (var_refs.ROdereference()) {
2739 // issue #3521: only clear vars here; do not delete
2740 vars.clear(xsink);
2741 }
2742 }
2743
2744 DLLLOCAL void deleteClassData(bool deref_vars, ExceptionSink* xsink) {
2745 if (deref_vars && var_refs.ROdereference()) {
2746 vars.clear(xsink);
2747 vars.del(xsink);
2748 } else if (!var_refs.reference_count()) {
2749 // delete vars again if possible
2750 vars.del(xsink);
2751 }
2752
2753 // delete key-value data
2754 for (auto& i : kvmap) {
2755 i.second.discard(xsink);
2756 }
2757 kvmap.clear();
2758
2759 /*
2760 if (!const_refs.reference_count()) {
2761 constlist.deleteAll(xsink);
2762 }
2763 */
2764 if (spgm) {
2765 if (deref_source_program) {
2766 spgm->deref(xsink);
2767 }
2768 spgm = nullptr;
2769 }
2770 }
2771
2772 /*
2773 DLLLOCAL int initMembers(QoreObject& o, BCEAList* bceal, ExceptionSink* xsink) const {
2774 if (scl && scl->initMembers(o, bceal, xsink))
2775 return -1;
2776
2777 if (members.empty())
2778 return 0;
2779
2780 // ensure class is only initialized once
2781 if (bceal && bceal->initMembers(cls->getID()))
2782 return 0;
2783
2784 SelfInstantiatorHelper sih(&selfid, &o, xsink);
2785
2786 if (initMembers(o, members.begin(), members.end(), xsink))
2787 return -1;
2788 return 0;
2789 }
2790 */
2791
2792 DLLLOCAL const QoreMethod* getMethodForEval(const char* nme, QoreProgram* pgm,
2793 const qore_class_private* class_ctx, ExceptionSink* xsink) const;
2794
2795 // allow_abstract = true if only for other languages that have inherited this class and have implemented
2796 // the abstract methods
2797 DLLLOCAL QoreObject* execConstructor(ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant,
2798 const QoreListNode* args, const QoreClass* obj_cls = nullptr, bool allow_abstract = false) const;
2799
2800 DLLLOCAL void addBuiltinMethod(const char* mname, MethodVariantBase* variant);
2801 DLLLOCAL void addBuiltinStaticMethod(const char* mname, MethodVariantBase* variant);
2802 DLLLOCAL void addBuiltinConstructor(BuiltinConstructorVariantBase* variant);
2803 DLLLOCAL void addBuiltinDestructor(BuiltinDestructorVariantBase* variant);
2804 DLLLOCAL void addBuiltinCopyMethod(BuiltinCopyVariantBase* variant);
2805 DLLLOCAL void setBuiltinSystemConstructor(BuiltinSystemConstructorBase* m);
2806
2807 DLLLOCAL void execBaseClassConstructor(QoreObject* self, BCEAList* bceal, ExceptionSink* xsink) const;
2808 DLLLOCAL QoreObject* execSystemConstructor(QoreObject* self, int code, va_list args) const;
2809 DLLLOCAL QoreObject* execCopy(QoreObject* old, ExceptionSink* xsink) const;
2810
2811 // returns a non-static method if it exists in the local class
2812 DLLLOCAL QoreMethod* parseFindLocalMethod(const char* nme) {
2813 hm_method_t::iterator i = hm.find(nme);
2814 return (i != hm.end()) ? i->second : nullptr;
2815 }
2816 // returns a non-static method if it exists in the local class
2817 DLLLOCAL const QoreMethod* parseFindLocalMethod(const char* nme) const {
2818 hm_method_t::const_iterator i = hm.find(nme);
2819 return (i != hm.end()) ? i->second : nullptr;
2820 }
2821
2822 DLLLOCAL QoreMethod* parseFindLocalMethod(const std::string& nme) {
2823 hm_method_t::iterator i = hm.find(nme);
2824 return (i != hm.end()) ? i->second : nullptr;
2825 }
2826 // returns a non-static method if it exists in the local class
2827 DLLLOCAL const QoreMethod* parseFindLocalMethod(const std::string& nme) const {
2828 hm_method_t::const_iterator i = hm.find(nme);
2829 return (i != hm.end()) ? i->second : nullptr;
2830 }
2831
2832 // returns any method if it exists in the local class
2833 DLLLOCAL const QoreMethod* parseFindAnyLocalMethod(const char* nme) const {
2834 const QoreMethod* m = parseFindLocalMethod(nme);
2835 return m ? m : parseFindLocalStaticMethod(nme);
2836 }
2837
2838 // returns a static method if it exists in the local class
2839 DLLLOCAL QoreMethod* parseFindLocalStaticMethod(const char* nme) {
2840 hm_method_t::iterator i = shm.find(nme);
2841 return (i != shm.end()) ? i->second : nullptr;
2842 }
2843 // returns a static method if it exists in the local class
2844 DLLLOCAL const QoreMethod* parseFindLocalStaticMethod(const char* nme) const {
2845 hm_method_t::const_iterator i = shm.find(nme);
2846 return (i != shm.end()) ? i->second : nullptr;
2847 }
2848
2849 DLLLOCAL const QoreMethod* parseGetConstructor() const {
2850 const_cast<qore_class_private*>(this)->initialize();
2851 if (constructor) {
2852 return constructor;
2853 }
2854 return parseFindLocalMethod("constructor");
2855 }
2856
2857 DLLLOCAL void unsetPublicMemberFlag() {
2858 assert(has_public_memdecl);
2859 has_public_memdecl = false;
2860 }
2861
2862 // This function must only be called from QoreObject
2863 DLLLOCAL void execMemberNotification(QoreObject* self, const char* mem, ExceptionSink* xsink) const;
2864
2865 // returns a non-static method if it exists in the local class and has been committed to the class
2866 DLLLOCAL QoreMethod* findLocalCommittedMethod(const char* nme);
2867 // returns a non-static method if it exists in the local class and has been committed to the class
2868 DLLLOCAL const QoreMethod* findLocalCommittedMethod(const char* nme) const;
2869
2870 // returns a static method if it exists in the local class and has been committed to the class
2871 DLLLOCAL QoreMethod* findLocalCommittedStaticMethod(const char* nme);
2872 // returns a static method if it exists in the local class and has been committed to the class
2873 DLLLOCAL const QoreMethod* findLocalCommittedStaticMethod(const char* nme) const;
2874
2875 DLLLOCAL void finalizeBuiltin(const char* nspath);
2876 DLLLOCAL void generateBuiltinSignature(const char* nspath);
2877 DLLLOCAL void initializeBuiltin();
2878
2879 DLLLOCAL QoreValue evalMethod(QoreObject* self, const char* nme, const QoreListNode* args, const qore_class_private* class_ctx, ExceptionSink* xsink) const;
2880
2881 DLLLOCAL QoreValue evalMethodGate(QoreObject* self, const char* nme, const QoreListNode* args, ExceptionSink* xsink) const;
2882
2883 DLLLOCAL static const QoreMethod* doParseMethodAccess(const QoreMethod* m, const qore_class_private* class_ctx);
2884
2885 DLLLOCAL static const QoreMethod* doMethodAccess(const QoreMethod* m, ClassAccess ma, const qore_class_private* class_ctx) {
2886 assert(m);
2887 return ((ma == Public) || ((ma == Private && class_ctx))) ? m : nullptr;
2888 }
2889
2890 DLLLOCAL static const QoreMethod* doMethodAccess(const QoreMethod* m, ClassAccess& access, ClassAccess ma) {
2891 assert(m);
2892
2893 if (ma >= Internal)
2894 m = nullptr;
2895 else if (access < ma)
2896 access = ma;
2897
2898 return m;
2899 }
2900
2901 DLLLOCAL const QoreMethod* doRuntimeMethodAccess(const QoreMethod* m, ClassAccess& access, ClassAccess ma, const qore_class_private* class_ctx) const {
2902 assert(m);
2903
2904 if (ma >= Internal && (!class_ctx || !equal(*class_ctx)))
2905 m = nullptr;
2906 else if (access < ma)
2907 access = ma;
2908
2909 return m;
2910 }
2911
2912 // performs class initialization; find a static method in the class hierarchy at parse time; inaccessible methods are ignored
2913 DLLLOCAL const QoreMethod* parseFindNormalMethod(const char* mname, const qore_class_private* class_ctx);
2914
2915 // performs class initialization; find a static method in the class hierarchy at parse time; inaccessible methods are ignored
2916 DLLLOCAL const QoreMethod* parseFindStaticMethod(const char* mname, const qore_class_private* class_ctx);
2917
2918 // performs class initialization; finds a non-static method in the class hierarchy at parse time, optionally initializes classes
2919 DLLLOCAL const QoreMethod* parseFindNormalMethodIntern(const char* mname, const qore_class_private* class_ctx);
2920
2921 // performs class initialization; finds a static method in the class hierarchy at parse time, optionally initializes classes
2922 DLLLOCAL const QoreMethod* parseFindStaticMethodIntern(const char* mname, const qore_class_private* class_ctx);
2923
2924 DLLLOCAL const QoreMethod* parseResolveSelfMethodIntern(const QoreProgramLocation* loc, const char* nme,
2925 const qore_class_private* class_ctx);
2926
2927 // returns a non-static method if it exists in class hierarchy and has been committed to the class
2928 // class_ctx is only set if it is present and accessible, so we only need to check for internal access here
2929 DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethodIntern(const char* nme, ClassAccess& access,
2930 const qore_class_private* class_ctx) const {
2931 const QoreMethod* m = findLocalCommittedStaticMethod(nme);
2932 if (m &&
2933 (class_ctx == this || doRuntimeMethodAccess(m, access, m->getAccess(), class_ctx))) {
2934 return m;
2935 }
2936 if (!scl) {
2937 return nullptr;
2938 }
2939 // access already checked in subclasses, do not need to check again
2940 return scl->runtimeFindCommittedStaticMethod(nme, access, class_ctx, class_ctx == this);
2941 }
2942
2943 // returns a non-static method if it exists in class hierarchy and has been committed to the class
2944 // class_ctx is only set if it is present and accessible, so we only need to check for internal access here
2945 DLLLOCAL const QoreMethod* runtimeFindCommittedMethodIntern(const char* nme, ClassAccess& access,
2946 const qore_class_private* class_ctx) const {
2947 const QoreMethod* m = findLocalCommittedMethod(nme);
2948 //printd(5, "qore_class_private::runtimeFindCommittedMethodIntern(%s) '%s' class_ctx: %p '%s' FIRST m: %p\n",
2949 // nme, name.c_str(), class_ctx, class_ctx ? class_ctx.name.c_str() : "n/a", m);
2950 if (m &&
2951 (class_ctx == this || doRuntimeMethodAccess(m, access, m->getAccess(), class_ctx))) {
2952 return m;
2953 }
2954 if (!scl) {
2955 return nullptr;
2956 }
2957 // access already checked in subclasses, do not need to check again
2958 return scl->runtimeFindCommittedMethod(nme, access, class_ctx, class_ctx == this);
2959 }
2960
2961 DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethod(const char* nme, ClassAccess& access,
2962 const qore_class_private* class_ctx) const;
2963
2964 DLLLOCAL const QoreMethod* runtimeFindCommittedMethod(const char* nme, ClassAccess& access,
2965 const qore_class_private* class_ctx) const;
2966
2967 DLLLOCAL const QoreMethod* runtimeFindCommittedMethodForEval(const char* nme, ClassAccess& access,
2968 const qore_class_private* class_ctx) const;
2969
2970 DLLLOCAL const QoreMethod* runtimeFindAnyCommittedMethod(const char* nme) const {
2971 ClassAccess access = Public;
2972 const qore_class_private* class_ctx = this;
2973 const QoreMethod* m = runtimeFindCommittedMethodIntern(nme, access, class_ctx);
2974 if (!m) {
2975 // check for special methods
2976 if (!strcmp(nme, "constructor"))
2977 return constructor;
2978 if (!strcmp(nme, "destructor"))
2979 return destructor;
2980 if (!strcmp(nme, "copy"))
2981 return copyMethod;
2982 if (!strcmp(nme, "methodGate"))
2983 return copyMethod;
2984 if (!strcmp(nme, "memberGate"))
2985 return memberGate;
2986 if (!strcmp(nme, "memberNotification"))
2987 return memberNotification;
2988 }
2989 return m;
2990 }
2991
2992 DLLLOCAL const QoreMethod* findMethod(const char* nme, ClassAccess& access) const {
2993 CurrentProgramRuntimeParseContextHelper pch;
2994 const qore_class_private* class_ctx = runtime_get_class();
2995 if (class_ctx && !runtimeCheckPrivateClassAccess(class_ctx))
2996 class_ctx = nullptr;
2997 return runtimeFindCommittedMethod(nme, access, class_ctx);
2998 }
2999
3000 DLLLOCAL bool runtimeHasCallableMethod(const char* m, int mask) const;
3001
3002 DLLLOCAL void execDestructor(QoreObject* self, ExceptionSink* xsink) const;
3003
3004 DLLLOCAL void execBaseClassDestructor(QoreObject* self, ExceptionSink* xsink) const;
3005
3006 DLLLOCAL void execBaseClassSystemDestructor(QoreObject* self, ExceptionSink* xsink) const;
3007
3008 DLLLOCAL void execBaseClassCopy(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const;
3009
3010 DLLLOCAL int parseInit();
3011 DLLLOCAL int parseResolveHierarchy();
3012 DLLLOCAL void parseResolveClassMembers();
3013 DLLLOCAL void parseResolveAbstract();
3014 DLLLOCAL void parseCommit();
3015 DLLLOCAL void parseCommitRuntimeInit(ExceptionSink* xsink);
3016 DLLLOCAL void parseRollback();
3017 DLLLOCAL int addUserMethod(const char* mname, MethodVariantBase* f, bool n_static);
3018 DLLLOCAL void addLocalMembersForInit();
3019
3020 DLLLOCAL QoreValue evalPseudoMethod(const QoreValue n, const char* name, const QoreListNode* args,
3021 ExceptionSink* xsink) const;
3022
3023 DLLLOCAL QoreValue evalPseudoMethod(const QoreMethod* m, const AbstractQoreFunctionVariant* variant,
3024 const QoreValue n, const QoreListNode* args, ExceptionSink* xsink) const;
3025
3026 DLLLOCAL const QoreMethod* runtimeFindPseudoMethod(const QoreValue n, const char* nme,
3027 ExceptionSink* xsink) const {
3028 const QoreMethod* w;
3029
3030 const qore_class_private* class_ctx = runtime_get_class();
3031 if (class_ctx && !runtimeCheckPrivateClassAccess(class_ctx)) {
3032 class_ctx = nullptr;
3033 }
3034 ClassAccess access;
3035 if (!(w = runtimeFindCommittedMethod(nme, access, class_ctx))) {
3036 qore_type_t t = n.getType();
3037 // throw an exception
3038 if (t == NT_OBJECT) {
3039 const char* cname = n.get<const QoreObject>()->getClassName();
3040 xsink->raiseException("METHOD-DOES-NOT-EXIST", "no method %s::%s() or pseudo-method %s::%s() is " \
3041 "available", cname, nme, name.c_str(), nme);
3042 } else {
3043 xsink->raiseException("PSEUDO-METHOD-DOES-NOT-EXIST", "no pseudo method <%s>::%s() has been defined",
3044 n.getTypeName(), nme);
3045 }
3046 return nullptr;
3047 }
3048
3049 return w;
3050 }
3051
3052 DLLLOCAL bool parseCheckPrivateClassAccess(const qore_class_private* qc = parse_get_class_priv()) const;
3053 DLLLOCAL bool runtimeCheckPrivateClassAccess(const qore_class_private* qc = runtime_get_class()) const;
3054
3055 // this = class to find in "oc"
3056 DLLLOCAL qore_type_result_e parseCheckCompatibleClass(const qore_class_private& oc) const {
3057 bool may_not_match = false;
3058 qore_type_result_e rv = parseCheckCompatibleClass(oc, may_not_match);
3059 // if the type may not match at runtime, then return no match with %strict-types
3060 if (may_not_match && (getProgram()->getParseOptions64() & PO_STRICT_TYPES)) {
3061 return QTI_NOT_EQUAL;
3062 }
3063 return rv;
3064 }
3065 DLLLOCAL qore_type_result_e parseCheckCompatibleClass(const qore_class_private& oc, bool& may_not_match) const;
3066 DLLLOCAL qore_type_result_e parseCheckCompatibleClassIntern(const qore_class_private& oc, bool& may_not_match) const;
3067 // this = class to find in "oc"
3068 DLLLOCAL qore_type_result_e runtimeCheckCompatibleClass(const qore_class_private& oc) const;
3069 DLLLOCAL qore_type_result_e runtimeCheckCompatibleClassIntern(const qore_class_private& oc) const;
3070
3071 // find the given class anywhere in the hierarchy regardless of access permissions or location
3072 DLLLOCAL const QoreClass* findInHierarchy(const qore_class_private& qc) {
3073 if (equal(qc))
3074 return cls;
3075 return scl ? scl->findInHierarchy(qc) : nullptr;
3076 }
3077
3078 DLLLOCAL const QoreClass* getClassIntern(qore_classid_t cid, ClassAccess& n_access, bool toplevel) const {
3079 if (cid == classID)
3080 return cls;
3081 return scl ? scl->getClass(cid, n_access, toplevel) : nullptr;
3082 }
3083
3084 DLLLOCAL const QoreClass* getClass(const qore_class_private& qc, ClassAccess& n_access) const {
3085 n_access = Public;
3086 return getClassIntern(qc, n_access, true);
3087 }
3088
3089 DLLLOCAL const QoreClass* getClassIntern(const qore_class_private& qc, ClassAccess& n_access,
3090 bool toplevel) const {
3091 if (equal(qc)) {
3092 return cls;
3093 }
3094
3095#ifdef DEBUG_1
3096 if (qc.name == name) {
3097 QoreString lh, rh;
3098 hash.toString(lh);
3099 qc.hash.toString(rh);
3100 printd(5, "qore_class_private::getClassIntern() this: %p '%s' != '%s' scl: %p (hash: %s qc.hash: %s)\n",
3101 this, name.c_str(), qc.name.c_str(), scl, lh.getBuffer(), rh.getBuffer());
3102 }
3103#endif
3104
3105 return scl ? scl->getClass(qc, n_access, toplevel) : nullptr;
3106 }
3107
3108 DLLLOCAL const QoreClass* parseGetClassIntern(const qore_class_private& qc, ClassAccess& n_access,
3109 bool toplevel) const {
3110 // check hashes if names are the same
3111 // FIXME: check fully-qualified namespace name
3112 if (parseEqual(qc))
3113 return cls;
3114
3115#ifdef DEBUG_SKIP
3116 if (qc.name == name) {
3117 printd(5, "qore_class_private::parseGetClassIntern() this: %p '%s' != '%s' scl: %p\n", this, name.c_str(),
3118 qc.name.c_str(), scl);
3119 parseShowHashes();
3120 qc.parseShowHashes();
3121 }
3122#endif
3123
3124 return scl ? scl->parseGetClass(qc, n_access, toplevel) : nullptr;
3125 }
3126
3127 DLLLOCAL bool inHierarchy(const qore_class_private& qc, ClassAccess& n_access) const {
3128 if (equal(qc)) {
3129 return cls;
3130 }
3131
3132 return scl ? scl->inHierarchy(qc, n_access) : false;
3133 }
3134
3135 DLLLOCAL bool inHierarchyStrict(const qore_class_private& qc, ClassAccess& n_access) const {
3136 if (strictEqual(qc)) {
3137 return cls;
3138 }
3139
3140 return scl ? scl->inHierarchyStrict(qc, n_access) : false;
3141 }
3142
3143#ifdef DEBUG_SKIP
3144 DLLLOCAL void parseShowHash() const {
3145 QoreString ch, ph;
3146 hash.toString(ch);
3147 printd(5, " + %p %s committed: %s\n", this, name.c_str(), ch.getBuffer());
3148 }
3149#endif
3150
3151 DLLLOCAL bool parseCheckEqualHash(const qore_class_private& qc) const {
3152#ifdef DEBUG_SKIP
3153 printd(5, "qore_class_private::parseCheckEqualHash() %s == %s\n", name.c_str(), qc.name.c_str());
3154 parseShowHash();
3155 qc.parseShowHash();
3156#endif
3157 return hash == qc.hash;
3158 }
3159
3160 DLLLOCAL bool strictEqual(const qore_class_private& qc) const {
3161 if (&qc == this) {
3162 return true;
3163 }
3164
3165 if (qc.classID == classID || (qc.name == name && qc.hash == hash)) {
3166 return true;
3167 }
3168
3169 return false;
3170 }
3171
3172 DLLLOCAL bool equal(const qore_class_private& qc) const {
3173 if (&qc == this)
3174 return true;
3175
3176 if (qc.classID == classID || (qc.name == name && qc.hash == hash))
3177 return true;
3178
3179 if (injectedClass && injectedClass->equal(qc))
3180 return true;
3181
3182 if (qc.injectedClass && equal(*qc.injectedClass))
3183 return true;
3184
3185 return false;
3186 }
3187
3188 DLLLOCAL bool parseEqual(const qore_class_private& qc) const {
3189 if (&qc == this)
3190 return true;
3191
3192 if (qc.classID == classID || (qc.name == name && parseCheckEqualHash(qc)))
3193 return true;
3194
3195 if (injectedClass && injectedClass->parseEqual(qc))
3196 return true;
3197
3198 if (qc.injectedClass && parseEqual(*qc.injectedClass))
3199 return true;
3200
3201 return false;
3202 }
3203
3204 DLLLOCAL const QoreClass* parseGetClass(const qore_class_private& qc, ClassAccess& n_access) const;
3205
3206 DLLLOCAL int addBaseClassesToSubclass(QoreClass* sc, bool is_virtual);
3207
3208 DLLLOCAL void setPublic();
3209
3210 DLLLOCAL void parseSetBaseClassList(BCList* bcl) {
3211 assert(!scl);
3212 if (bcl) {
3213 scl = bcl;
3214 if (!has_new_user_changes)
3215 has_new_user_changes = true;
3216 if (!has_sig_changes)
3217 has_sig_changes = true;
3218 }
3219 }
3220
3221 DLLLOCAL bool parseHasPendingChanges() const {
3222 return has_new_user_changes;
3223 }
3224
3225 DLLLOCAL bool parseCheckHierarchy(const QoreClass* n_cls, ClassAccess& access) const {
3226 access = Public;
3227 return parseCheckHierarchyIntern(n_cls, access, true);
3228 }
3229
3230 DLLLOCAL bool parseCheckHierarchyIntern(const QoreClass* n_cls, ClassAccess& access, bool toplevel) const {
3231 if (parseEqual(*n_cls->priv))
3232 return true;
3233
3234 return scl ? scl->parseCheckHierarchy(n_cls, access, toplevel) : false;
3235 }
3236
3237 DLLLOCAL VRMutex* getGate() const {
3238 return &gate;
3239 }
3240
3241 // class initialization; inaccessible methods are ignored
3242 DLLLOCAL const QoreMethod* parseFindAnyMethod(const char* nme, const qore_class_private* class_ctx);
3243
3244 // class initialization; inaccessible methods are ignored
3245 DLLLOCAL const QoreMethod* parseFindAnyMethodStaticFirst(const char* nme, const qore_class_private* class_ctx);
3246
3247 // class initialization
3248 DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, const char* nme,
3249 const qore_class_private* class_ctx);
3250 DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, NamedScope* nme);
3251
3252 // class initialization
3253 DLLLOCAL const QoreMethod* parseFindSelfMethod(const char* nme);
3254
3255 DLLLOCAL char* getHash() const {
3256 return hash.getHash();
3257 }
3258
3259 DLLLOCAL void setSerializer(q_serializer_t m) {
3260 assert(!serializer);
3261 serializer = m;
3262 }
3263
3264 DLLLOCAL void setDeserializer(q_deserializer_t m) {
3265 assert(!deserializer);
3266 deserializer = m;
3267 }
3268
3269 // static methods
3270 //DLLLOCAL static
3271
3272 DLLLOCAL static char* getHash(const QoreClass& qc) {
3273 return qc.priv->getHash();
3274 }
3275
3276 DLLLOCAL static void parseAddConstant(QoreClass& qc, const QoreProgramLocation* loc, const std::string &cname,
3277 QoreValue val, ClassAccess access) {
3278 qc.priv->parseAddConstant(loc, cname, val, access);
3279 }
3280
3281 DLLLOCAL static LocalVar* getSelfId(const QoreClass& qc) {
3282 return &qc.priv->selfid;
3283 }
3284
3285 DLLLOCAL static QoreObject* execConstructor(const QoreClass& qc, const AbstractQoreFunctionVariant* variant,
3286 const QoreListNode* args, ExceptionSink* xsink) {
3287 return qc.priv->execConstructor(xsink, variant, args);
3288 }
3289
3290 DLLLOCAL static bool injected(const QoreClass& qc) {
3291 return qc.priv->inject;
3292 }
3293
3294 DLLLOCAL static QoreClass* makeImportClass(const QoreClass& qc, QoreProgram* spgm, const char* nme, bool inject,
3295 const qore_class_private* injectedClass, qore_ns_private* ns, q_setpub_t set_pub) {
3296 qore_class_private* priv = new qore_class_private(*qc.priv, ns, spgm, nme, inject, injectedClass, set_pub);
3297 //printd(5, "qore_program_private::makeImportClass() name: '%s' as '%s' inject: %d rv: %p\n", qc.getName(),
3298 // priv->name.c_str(), inject, priv->cls);
3299 return priv->cls;
3300 }
3301
3302 DLLLOCAL static const QoreMethod* runtimeFindCommittedStaticMethod(const QoreClass& qc, const char* nme,
3303 ClassAccess& access, const qore_class_private* class_ctx) {
3304 return qc.priv->runtimeFindCommittedStaticMethod(nme, access, class_ctx);
3305 }
3306
3307 DLLLOCAL static const QoreMethod* parseFindLocalMethod(const QoreClass& qc, const char* mname) {
3308 return qc.priv->parseFindLocalMethod(mname);
3309 }
3310
3311 DLLLOCAL static bool parseHasPendingChanges(const QoreClass& qc) {
3312 return qc.priv->parseHasPendingChanges();
3313 }
3314
3315 DLLLOCAL static int parseCheckMemberAccess(const QoreClass& qc, const QoreProgramLocation* loc, const char* mem,
3316 const QoreTypeInfo*& memberTypeInfo, int pflag) {
3317 return qc.priv->parseCheckMemberAccess(loc, mem, memberTypeInfo, pflag);
3318 }
3319
3320 DLLLOCAL static bool runtimeHasCallableMethod(const QoreClass& qc, const char* m) {
3321 return qc.priv->runtimeHasCallableMethod(m, QCCM_NORMAL | QCCM_STATIC);
3322 }
3323
3324 DLLLOCAL static bool runtimeHasCallableNormalMethod(const QoreClass& qc, const char* m) {
3325 return qc.priv->runtimeHasCallableMethod(m, QCCM_NORMAL);
3326 }
3327
3328 DLLLOCAL static bool runtimeHasCallableStaticMethod(const QoreClass& qc, const char* m) {
3329 return qc.priv->runtimeHasCallableMethod(m, QCCM_STATIC);
3330 }
3331
3332 DLLLOCAL static int runtimeCheckInstantiateClass(const QoreClass& qc, ExceptionSink* xsink) {
3333 return qc.priv->runtimeCheckInstantiateClass(xsink);
3334 }
3335
3336 DLLLOCAL static int parseInitPartial(QoreClass& qc) {
3337 return qc.priv->parseInitPartial();
3338 }
3339
3340 DLLLOCAL static void parseCommit(QoreClass& qc) {
3341 qc.priv->parseCommit();
3342 }
3343
3344 DLLLOCAL static void parseCommitRuntimeInit(QoreClass& qc, ExceptionSink* xsink) {
3345 qc.priv->parseCommitRuntimeInit(xsink);
3346 }
3347
3348 DLLLOCAL static void parseRollback(QoreClass& qc) {
3349 qc.priv->parseRollback();
3350 }
3351
3352 DLLLOCAL static void resolveCopy(QoreClass& qc) {
3353 qc.priv->resolveCopy();
3354 }
3355
3356 DLLLOCAL static int addUserMethod(QoreClass& qc, const char* mname, MethodVariantBase* f, bool n_static) {
3357 return qc.priv->addUserMethod(mname, f, n_static);
3358 }
3359
3360 DLLLOCAL static void initialize(QoreClass& qc) {
3361 qc.priv->initialize();
3362 }
3363
3364 DLLLOCAL static void parseSetBaseClassList(QoreClass& qc, BCList* bcl) {
3365 qc.priv->parseSetBaseClassList(bcl);
3366 }
3367
3368 DLLLOCAL static BCList* getBaseClassList(const QoreClass& qc) {
3369 return qc.priv->scl;
3370 }
3371
3372 DLLLOCAL static void parseAddStaticVar(QoreClass* qc, char* dname, ClassAccess access, QoreVarInfo* VarInfo) {
3373 qc->priv->parseAddStaticVar(dname, access, VarInfo);
3374 }
3375
3376 // searches only the current class, returns 0 if private found and not accessible in the current parse context
3377 DLLLOCAL static QoreValue parseFindLocalConstantValue(QoreClass* qc, const char* cname,
3378 const QoreTypeInfo*& typeInfo, bool& found) {
3379 return qc->priv->parseFindLocalConstantValue(cname, typeInfo, found);
3380 }
3381
3382 // searches only the current class, returns 0 if private found and not accessible in the current parse context
3383 DLLLOCAL static QoreVarInfo* parseFindLocalStaticVar(const QoreClass* qc, const char* vname) {
3384 return qc->priv->parseFindLocalStaticVar(vname);
3385 }
3386
3387 // searches this class and all superclasses
3388 DLLLOCAL static QoreValue parseFindConstantValue(QoreClass* qc, const char* cname, const QoreTypeInfo*& typeInfo,
3389 bool& found, const qore_class_private* class_ctx) {
3390 return qc->priv->parseFindConstantValue(cname, typeInfo, found, class_ctx);
3391 }
3392
3393 // searches this class and all superclasses, if check = false, then assumes parsing from within the class
3394 // (parse_get_class() == this class)
3395 DLLLOCAL static QoreVarInfo* parseFindStaticVar(const QoreClass* qc, const char* vname, const QoreClass*& nqc,
3396 ClassAccess& access, bool check = false) {
3397 return qc->priv->parseFindStaticVar(vname, nqc, access, check);
3398 }
3399
3400 DLLLOCAL static int parseCheckInternalMemberAccess(const QoreClass* qc, const char* mem,
3401 const QoreTypeInfo*& memberTypeInfo, const QoreProgramLocation* loc) {
3402 return qc->priv->parseCheckInternalMemberAccess(mem, memberTypeInfo, loc);
3403 }
3404
3405 DLLLOCAL static int parseResolveInternalMemberAccess(const QoreClass* qc, const char* mem,
3406 const QoreTypeInfo*& memberTypeInfo) {
3407 return qc->priv->parseResolveInternalMemberAccess(mem, memberTypeInfo);
3408 }
3409
3410 DLLLOCAL static const QoreMethod* parseFindSelfMethod(QoreClass* qc, const char* mname) {
3411 return qc->priv->parseFindSelfMethod(mname);
3412 }
3413
3414 DLLLOCAL static void parseAddMember(QoreClass& qc, char* nme, ClassAccess access, QoreMemberInfo* mInfo) {
3415 qc.priv->parseAddMember(nme, access, mInfo);
3416 }
3417
3418 DLLLOCAL static QoreValue evalPseudoMethod(const QoreClass* qc, const QoreValue n, const char* name,
3419 const QoreListNode* args, ExceptionSink* xsink) {
3420 return qc->priv->evalPseudoMethod(n, name, args, xsink);
3421 }
3422
3423 DLLLOCAL static QoreValue evalPseudoMethod(const QoreClass* qc, const QoreMethod* m,
3424 const AbstractQoreFunctionVariant* variant, const QoreValue n, const QoreListNode* args,
3425 ExceptionSink* xsink) {
3426 return qc->priv->evalPseudoMethod(m, variant, n, args, xsink);
3427 }
3428
3429 DLLLOCAL static bool parseCheckPrivateClassAccess(const QoreClass& qc,
3430 const qore_class_private* oqc = parse_get_class_priv()) {
3431 return qc.priv->parseCheckPrivateClassAccess(oqc);
3432 }
3433
3434 DLLLOCAL static bool runtimeCheckPrivateClassAccess(const QoreClass& qc,
3435 const qore_class_private* oqc = runtime_get_class()) {
3436 return qc.priv->runtimeCheckPrivateClassAccess(oqc);
3437 }
3438
3439 DLLLOCAL static qore_type_result_e parseCheckCompatibleClass(const QoreClass* qc, const QoreClass* oc) {
3440 if (!oc)
3441 return QTI_NOT_EQUAL;
3442 return qc->priv->parseCheckCompatibleClass(*(oc->priv));
3443 }
3444
3445 DLLLOCAL static qore_type_result_e runtimeCheckCompatibleClass(const QoreClass& qc, const QoreClass& oc) {
3446 return qc.priv->runtimeCheckCompatibleClass(*oc.priv);
3447 }
3448
3449 DLLLOCAL static qore_class_private* get(QoreClass& qc) {
3450 return qc.priv;
3451 }
3452
3453 DLLLOCAL static const qore_class_private* get(const QoreClass& qc) {
3454 return qc.priv;
3455 }
3456
3457 DLLLOCAL static bool isPublic(const QoreClass& qc) {
3458 return qc.priv->pub;
3459 }
3460
3461 DLLLOCAL static bool isUserPublic(const QoreClass& qc) {
3462 return qc.priv->pub && !qc.priv->sys;
3463 }
3464
3465 DLLLOCAL static bool isFinal(const QoreClass& qc) {
3466 return qc.priv->final;
3467 }
3468
3469 DLLLOCAL static void setPublic(QoreClass& qc) {
3470 qc.priv->setPublic();
3471 }
3472
3473 DLLLOCAL static void setFinal(QoreClass& qc) {
3474 assert(!qc.priv->final);
3475 qc.priv->final = true;
3476 //printd(5, "class '%s' set to final\n", qc.getName());
3477 }
3478
3479protected:
3480 DLLLOCAL ~qore_class_private();
3481};
3482
3483class qore_class_private_holder {
3484 qore_class_private* c;
3485
3486public:
3487 DLLLOCAL qore_class_private_holder(QoreClass* n_c) : c(qore_class_private::get(*n_c)) {
3488 }
3489
3490 DLLLOCAL qore_class_private_holder(qore_class_private* n_c) : c(n_c) {
3491 }
3492
3493 DLLLOCAL ~qore_class_private_holder() {
3494 if (c) {
3495 c->deref(true, true);
3496 }
3497 }
3498
3499 DLLLOCAL qore_class_private* operator*() {
3500 return c;
3501 }
3502
3503 DLLLOCAL QoreClass* release() {
3504 if (c) {
3505 QoreClass* rv = c->cls;
3506 c = nullptr;
3507 return rv;
3508 }
3509 return nullptr;
3510 }
3511};
3512
3513class qore_method_private {
3514public:
3515 const QoreClass* parent_class;
3516 MethodFunctionBase* func;
3517 bool static_flag, all_user;
3518
3519 DLLLOCAL qore_method_private(const QoreClass* n_parent_class, MethodFunctionBase* n_func, bool n_static)
3520 : parent_class(n_parent_class), func(n_func), static_flag(n_static), all_user(true) {
3521 assert(parent_class == n_func->getClass());
3522 }
3523
3524 DLLLOCAL ~qore_method_private() {
3525 func->deref();
3526 }
3527
3528 DLLLOCAL void setBuiltin() {
3529 if (all_user)
3530 all_user = false;
3531 }
3532
3533 DLLLOCAL bool isUniquelyUser() const {
3534 return all_user;
3535 }
3536
3537 DLLLOCAL bool isAbstract() const {
3538 return func->isAbstract();
3539 }
3540
3541 DLLLOCAL int addUserVariant(MethodVariantBase* variant) {
3542 return func->parseAddUserMethodVariant(variant);
3543 }
3544
3545 DLLLOCAL void addBuiltinVariant(MethodVariantBase* variant) {
3546 setBuiltin();
3547 func->addBuiltinMethodVariant(variant);
3548 }
3549
3550 DLLLOCAL MethodFunctionBase* getFunction() const {
3551 return const_cast<MethodFunctionBase*>(func);
3552 }
3553
3554 DLLLOCAL const char* getName() const {
3555 return func->getName();
3556 }
3557
3558 DLLLOCAL const std::string& getNameStr() const {
3559 return func->getNameStr();
3560 }
3561
3562 DLLLOCAL int parseInit();
3563
3564 DLLLOCAL int parseInitStatic() {
3565 assert(static_flag);
3566 int err = func->parseInit();
3567 // make sure the method doesn't override a "final" method in a base class
3568 if (func->checkFinal() && !err) {
3569 err = -1;
3570 }
3571 return err;
3572 }
3573
3574 DLLLOCAL const QoreTypeInfo* getUniqueReturnTypeInfo() const {
3575 return func->getUniqueReturnTypeInfo();
3576 }
3577
3578 DLLLOCAL void evalConstructor(const AbstractQoreFunctionVariant* variant, QoreObject* self,
3579 const QoreListNode* args, BCEAList* bceal, ExceptionSink* xsink) {
3580 CONMF(func)->evalConstructor(variant, *parent_class, self, args, parent_class->priv->scl, bceal, xsink);
3581 }
3582
3583 DLLLOCAL void evalCopy(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const {
3584 COPYMF(func)->evalCopy(*parent_class, self, old, parent_class->priv->scl, xsink);
3585 }
3586
3587 DLLLOCAL void evalBaseClassCopy(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const {
3588 COPYMF(func)->evalCopy(*parent_class, self, old, nullptr, xsink);
3589 }
3590
3591 DLLLOCAL void evalDestructor(QoreObject* self, ExceptionSink* xsink) const {
3592 DESMF(func)->evalDestructor(*parent_class, self, xsink);
3593 }
3594
3595 DLLLOCAL void evalSystemDestructor(QoreObject* self, ExceptionSink* xsink) const {
3596 // execute function directly
3597 DESMF(func)->evalDestructor(*parent_class, self, xsink);
3598 }
3599
3600 DLLLOCAL void evalSystemConstructor(QoreObject* self, int code, va_list args) const {
3601 BSYSCONB(func)->eval(*parent_class, self, code, args);
3602 }
3603
3604 DLLLOCAL QoreValue eval(ExceptionSink* xsink, QoreObject* self, const QoreListNode* args,
3605 const qore_class_private* cctx = nullptr) const {
3606 if (!static_flag) {
3607 assert(self);
3608 return NMETHF(func)->evalMethod(xsink, 0, self, args, cctx);
3609 }
3610 return SMETHF(func)->evalMethod(xsink, 0, args, cctx);
3611 }
3612
3613 DLLLOCAL QoreValue evalTmpArgs(ExceptionSink* xsink, QoreObject* self, QoreListNode* args,
3614 const qore_class_private* cctx = nullptr) const {
3615 if (!static_flag) {
3616 assert(self);
3617 return NMETHF(func)->evalMethodTmpArgs(xsink, nullptr, self, args, cctx);
3618 }
3619 return SMETHF(func)->evalMethodTmpArgs(xsink, nullptr, args, cctx);
3620 }
3621
3622 DLLLOCAL QoreValue evalPseudoMethod(const AbstractQoreFunctionVariant* variant, const QoreValue n,
3623 const QoreListNode* args, ExceptionSink* xsink) const {
3624 //QORE_TRACE("qore_method_private::evalPseudoMethod()");
3625
3626 assert(!static_flag);
3627
3628 QoreValue rv = NMETHF(func)->evalPseudoMethod(xsink, variant, n, args);
3629 printd(5, "qore_method_private::evalPseudoMethod() %s::%s() returning type: %s\n", parent_class->getName(),
3630 getName(), rv.getTypeName());
3631 return rv;
3632 }
3633
3634 DLLLOCAL QoreValue evalNormalVariant(QoreObject* self, const QoreExternalMethodVariant* ev,
3635 const QoreListNode* args, ExceptionSink* xsink) const;
3636
3637 // returns the lowest access code for all variants
3638 DLLLOCAL ClassAccess getAccess() const;
3639
3640 // returns the lowest access code for all variants including uncommitted variants
3641 DLLLOCAL static ClassAccess getAccess(const QoreMethod& m) {
3642 return m.priv->getAccess();
3643 }
3644
3645 DLLLOCAL static QoreValue evalNormalVariant(const QoreMethod& m, ExceptionSink* xsink, QoreObject* self,
3646 const QoreExternalMethodVariant* ev, const QoreListNode* args) {
3647 return m.priv->evalNormalVariant(self, ev, args, xsink);
3648 }
3649
3650 DLLLOCAL static QoreValue evalPseudoMethod(const QoreMethod& m, ExceptionSink* xsink,
3651 const AbstractQoreFunctionVariant* variant, const QoreValue n, const QoreListNode* args) {
3652 return m.priv->evalPseudoMethod(variant, n, args, xsink);
3653 }
3654
3655 DLLLOCAL static QoreValue eval(const QoreMethod& m, ExceptionSink* xsink, QoreObject* self,
3656 const QoreListNode* args, const qore_class_private* cctx = nullptr) {
3657 return m.priv->eval(xsink, self, args, cctx);
3658 }
3659
3660 DLLLOCAL static QoreValue evalTmpArgs(const QoreMethod& m, ExceptionSink* xsink, QoreObject* self,
3661 QoreListNode* args, const qore_class_private* cctx = nullptr) {
3662 return m.priv->evalTmpArgs(xsink, self, args, cctx);
3663 }
3664
3665 DLLLOCAL static qore_method_private* get(QoreMethod& m) {
3666 return m.priv;
3667 }
3668
3669 DLLLOCAL static const qore_method_private* get(const QoreMethod& m) {
3670 return m.priv;
3671 }
3672};
3673
3674template <class T>
3675class PrivateIteratorBase {
3676public:
3677 DLLLOCAL PrivateIteratorBase(const T& obj) : obj(obj), i(obj.end()) {
3678 }
3679
3680 DLLLOCAL bool next() {
3681 if (i == obj.end()) {
3682 i = obj.begin();
3683 } else {
3684 ++i;
3685 }
3686 return (i != obj.end());
3687 }
3688
3690 DLLLOCAL bool valid() const {
3691 return i != obj.end();
3692 }
3693
3694protected:
3695 const T& obj;
3696 typename T::const_iterator i;
3697};
3698
3699template <class T, class U>
3700class PrivateMemberIteratorBase : public PrivateIteratorBase<typename T::member_list_t> {
3701public:
3702 DLLLOCAL PrivateMemberIteratorBase(const typename T::member_list_t& obj)
3703 : PrivateIteratorBase<typename T::member_list_t>(obj) {
3704 }
3705
3706 DLLLOCAL const U& getMember() const {
3707 assert(this->valid());
3708 return *reinterpret_cast<const U*>(this->i->second.get());
3709 }
3710
3711 DLLLOCAL const char* getName() const {
3712 assert(this->valid());
3713 return this->i->first;
3714 }
3715};
3716
3717#endif
static void discard(AbstractQoreNode *n, ExceptionSink *xsink)
to deref an AbstractQoreNode (when the pointer may be 0)
Definition: QoreLib.h:327
#define QDOM_DEFAULT
the default domain (no domain)
Definition: Restrictions.h:170
#define PO_REQUIRE_TYPES
require type information for all declarations
Definition: Restrictions.h:61
#define PO_STRICT_TYPES
enforce strict type checking and setting default values
Definition: Restrictions.h:98
#define PO_BROKEN_VARARGS
allow for old pre-Qore 1.17 vararg handling with implicit ellipses
Definition: Restrictions.h:101
the base class for all data to be used as private data of Qore objects
Definition: AbstractPrivateData.h:44
an abstract class for class-specific external user data
Definition: QoreClass.h:237
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:57
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
defines a Qore-language class
Definition: QoreClass.h:253
DLLEXPORT bool inHierarchy(const QoreClass &cls, ClassAccess &n_access) const
Returns true if the class passed as an argument is present in the current class's hierachy,...
DLLEXPORT bool inHierarchyStrict(const QoreClass &cls, ClassAccess &n_access) const
Returns true if the class passed as an argument is present in the current class's hierachy,...
DLLEXPORT const QoreClass * getClass(qore_classid_t cid) const
returns a pointer to the QoreClass object representing the class ID passed if it exists in the class ...
DLLEXPORT const char * getName() const
returns the class name
external wrapper class for method variants
Definition: QoreReflection.h:90
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
a method in a QoreClass
Definition: QoreClass.h:139
DLLEXPORT const char * getName() const
returns the method's name
DLLEXPORT bool isStatic() const
returns true if the method is static
DLLEXPORT ClassAccess getAccess() const
returns the lowest access code of all variants in the method
DLLEXPORT const QoreClass * getClass() const
returns a pointer to the parent class
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:60
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only
Definition: QoreProgram.h:128
virtual DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count of the object
provides atomic reference counting to Qore objects
Definition: QoreReferenceCounter.h:44
DLLEXPORT void ROreference() const
atomically increments the reference count
DLLEXPORT int reference_count() const
gets the reference count
DLLEXPORT bool ROdereference() const
atomically decrements the reference count
DLLLOCAL detail::QoreValueCastHelper< T >::Result get()
returns the value as the given type
Definition: QoreValue.h:214
DLLEXPORT qore_type_t getType() const
returns the type of value contained
DLLEXPORT const char * getTypeName() const
returns a string type description of the value contained (ex: "nothing" for a null AbstractQoreNode p...
DLLEXPORT void clear()
unconditionally set the QoreValue to QoreNothingNode (does not dereference any possible contained Abs...
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
DLLEXPORT const char * c_str() const
returns the string's buffer; this data should not be changed
DLLEXPORT void clear()
reset string to zero length; memory is not deallocated; string encoding does not change
DLLEXPORT const char * getBuffer() const
returns the string's buffer; this data should not be changed
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
holds an object and dereferences it in the destructor
Definition: QoreValue.h:487
QoreValue(* q_external_method_t)(const QoreMethod &method, const void *ptr, QoreObject *self, AbstractPrivateData *private_data, const QoreListNode *args, q_rt_flags_t flags, ExceptionSink *xsink)
the type used for builtin QoreClass method signatures
Definition: common.h:345
void(* q_external_destructor_t)(const QoreClass &thisclass, const void *ptr, QoreObject *self, AbstractPrivateData *private_data, ExceptionSink *xsink)
the type used for builtin QoreClass destructor signatures with the new generic calling convention and...
Definition: common.h:408
int16_t qore_type_t
used to identify unique Qore data and parse types (descendents of AbstractQoreNode)
Definition: common.h:70
uint64_t q_rt_flags_t
runtime code execution flags
Definition: common.h:263
QoreValue(* q_external_static_method_t)(const QoreMethod &method, const void *ptr, const QoreListNode *args, q_rt_flags_t flags, ExceptionSink *xsink)
the type used for external static methods
Definition: common.h:358
QoreValue(* q_func_n_t)(const QoreListNode *args, q_rt_flags_t flags, ExceptionSink *xsink)
the type used for builtin function signatures
Definition: common.h:307
void(* q_copy_t)(QoreObject *self, QoreObject *old, AbstractPrivateData *private_data, ExceptionSink *xsink)
the type used for builtin QoreClass copy signatures
Definition: common.h:417
void(* q_system_constructor_t)(QoreObject *self, int code, va_list args)
the type used for builtin QoreClass system constructor method signatures
Definition: common.h:390
QoreValue(* q_method_n_t)(QoreObject *self, AbstractPrivateData *private_data, const QoreListNode *args, q_rt_flags_t flags, ExceptionSink *xsink)
the type used for builtin QoreClass method signatures
Definition: common.h:330
void(* q_external_constructor_t)(const QoreMethod &method, const void *ptr, QoreObject *self, const QoreListNode *args, q_rt_flags_t rtflags, ExceptionSink *xsink)
the type used for builtin QoreClass constructor method signatures
Definition: common.h:378
std::vector< const QoreTypeInfo * > type_vec_t
vector of type information for parameter lists
Definition: common.h:251
QoreHashNode *(* q_serializer_t)(const QoreObject &self, const AbstractPrivateData &data, QoreSerializationContext &context, ExceptionSink *xsink)
the type used for builtin QoreClass serializer method signatures
Definition: common.h:438
void(* q_destructor_t)(QoreObject *self, AbstractPrivateData *private_data, ExceptionSink *xsink)
the type used for builtin QoreClass destructor signatures
Definition: common.h:398
void(* q_external_copy_t)(const QoreClass &thisclass, const void *ptr, QoreObject *self, QoreObject *old, AbstractPrivateData *private_data, ExceptionSink *xsink)
the type used for builtin QoreClass copy signatures with the new generic calling convention
Definition: common.h:428
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
std::vector< std::string > name_vec_t
vector of parameter names for parameter lists
Definition: common.h:257
void(* q_deserializer_t)(QoreObject &self, const QoreHashNode *sdata, QoreDeserializationContext &context, ExceptionSink *xsink)
the type used for builtin QoreClass deserializer method signatures
Definition: common.h:450
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
void(* q_constructor_n_t)(QoreObject *self, const QoreListNode *args, q_rt_flags_t rtflags, ExceptionSink *xsink)
the type used for builtin QoreClass constructor method signatures
Definition: common.h:366
std::vector< QoreValue > arg_vec_t
vector of value information for default argument lists
Definition: common.h:254
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
DLLEXPORT QoreProgram * getProgram()
returns the current QoreProgram
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:276
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values