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