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