Qore Programming Language  0.9.4.6
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()), loc(old.loc), parseTypeInfo(old.parseTypeInfo ? new QoreParseTypeInfo(*old.parseTypeInfo) : nullptr) {
843  }
844 
845 public:
846  // initialization expression
847  QoreValue exp;
848 
849  // store parse location in case of errors
850  const QoreProgramLocation* loc;
851  QoreParseTypeInfo* parseTypeInfo;
852 
853  DLLLOCAL QoreMemberInfoBase(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeinfo = nullptr, QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue()) :
854  typeInfo(n_typeinfo), exp(e), loc(loc), parseTypeInfo(n_parseTypeInfo) {
855  }
856 
857  DLLLOCAL ~QoreMemberInfoBase() {
858  del();
859  }
860 
861  DLLLOCAL void del() {
862  exp.discard(nullptr);
863  if (parseTypeInfo) {
864  delete parseTypeInfo;
865  parseTypeInfo = nullptr;
866  }
867  }
868 
869  DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
870  return typeInfo;
871  }
872 
873  DLLLOCAL const QoreTypeInfo* parseGetTypeInfo() const {
874  // we cannot tell if the member has been initialized, so we return anyTypeInfo here for potential references
875  return QoreTypeInfo::isReference(typeInfo) ? anyTypeInfo : typeInfo;
876  //return typeInfo;
877  }
878 
879  DLLLOCAL bool parseHasTypeInfo() const {
880  return (typeInfo || parseTypeInfo);
881  }
882 };
883 
884 class QoreMemberInfoBaseAccess : public QoreMemberInfoBase {
885 public:
886  ClassAccess access;
887 
888  DLLLOCAL QoreMemberInfoBaseAccess(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeinfo = nullptr, QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue(), ClassAccess n_access = Public) :
889  QoreMemberInfoBase(loc, n_typeinfo, n_parseTypeInfo, e), access(n_access) {
890  }
891 
892  DLLLOCAL ClassAccess getAccess() const {
893  return access;
894  }
895 
896 protected:
897  DLLLOCAL QoreMemberInfoBaseAccess(const QoreMemberInfoBaseAccess& old, ClassAccess n_access) : QoreMemberInfoBase(old), access(old.access >= n_access ? old.access : n_access) {
898  }
899 
900  bool init = false;
901 };
902 
903 // for the inheritance list for each member
904 typedef std::vector<const qore_class_private*> cls_vec_t;
905 
906 // maps from an accessing context to the object storage context
907 typedef std::map<const qore_class_private*, const qore_class_private*> cls_context_map_t;
908 
909 // list of inherited member info dsta structures for initialization
910 typedef std::deque<const QoreMemberInfo*> member_info_list_t;
911 
912 // the access stored here is a composite access for the member; the maximum of the class inheritance access
913 // (for accessible members imported from base classes) and the member's access in the class where it's
914 // defined
915 class QoreMemberInfo : public QoreMemberInfoBaseAccess {
916  friend class qore_class_private;
917 public:
918  DLLLOCAL QoreMemberInfo(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeInfo = nullptr, QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue(), ClassAccess n_access = Public, const qore_class_private* qc = nullptr) : QoreMemberInfoBaseAccess(loc, n_typeInfo, n_parseTypeInfo, e, n_access), is_local(true) {
919  if (qc) {
920  cls_vec.push_back(qc);
921  }
922  }
923 
924  // copy to a new class - same member, new class
925  DLLLOCAL QoreMemberInfo(const QoreMemberInfo& old, const qore_class_private* cls);
926 
927  DLLLOCAL ~QoreMemberInfo() {
928  delete cls_context_map;
929  delete member_info_list;
930  }
931 
932  DLLLOCAL void setDeclaringClass(const qore_class_private* qc) {
933  assert(cls_vec.empty());
934  cls_vec.push_back(qc);
935  assert(is_local);
936  }
937 
938  // returns true if the member is a locally-defined member with private:internal member access
939  DLLLOCAL bool isLocalInternal() const {
940  return is_local && access == Internal;
941  }
942 
943  // returns true if the member is locally defined
944  DLLLOCAL bool local() const {
945  return is_local;
946  }
947 
948  // returns the class where the member was declared
949  DLLLOCAL const qore_class_private* getClass() const {
950  return cls_vec[0];
951  }
952 
953  // 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
954  DLLLOCAL const qore_class_private* getClassContext(const qore_class_private* class_ctx) const {
955  if (local() && class_ctx == getClass()) {
956  if (access == Internal) {
957  return class_ctx;
958  }
959  return nullptr;
960  }
961  if (cls_context_map) {
962  cls_context_map_t::const_iterator i = cls_context_map->find(class_ctx);
963  if (i != cls_context_map->end()) {
964  return i->second;
965  }
966  }
967 
968  return nullptr;
969  }
970 
971  DLLLOCAL size_t getContextSize() const {
972  return cls_context_map ? cls_context_map->size() : 0;
973  }
974 
975  // issue #2970: marks the member to be accessed with the classes in the argument when
976  // accessing the object's data
977  DLLLOCAL void addContextAccess(const QoreMemberInfo& mi);
978 
979  // issue #2970: marks the member to be accessed with the classes in the argument when
980  // accessing the object's data
981  DLLLOCAL void addContextAccess(const QoreMemberInfo& mi, const qore_class_private* qc);
982 
983  // issue #2970: returns the number of parent class members to initialize
984  DLLLOCAL size_t numParentMembers() const {
985  return member_info_list ? member_info_list->size() : 0;
986  }
987 
988  // issue #2970: initialization begin
989  DLLLOCAL member_info_list_t::const_iterator initializationBegin() const {
990  assert(member_info_list);
991  return member_info_list->begin();
992  }
993 
994  // issue #2970: initialization end
995  DLLLOCAL member_info_list_t::const_iterator initializationEnd() const {
996  assert(member_info_list);
997  return member_info_list->end();
998  }
999 
1000  // initializes the member
1001  DLLLOCAL void parseInit(const char* name, LocalVar& selfid);
1002 
1003  // sets the transient flag
1004  DLLLOCAL void setTransient() {
1005  assert(!is_transient);
1006  is_transient = true;
1007  }
1008 
1009  // returns the transient flag
1010  DLLLOCAL bool getTransient() const {
1011  return is_transient;
1012  }
1013 
1014 private:
1015  // the classes where this member is accessible; the first class is the class where the member was defined
1016  cls_vec_t cls_vec;
1017  // maps class contexts to class pointers in object storage for private members
1018  cls_context_map_t* cls_context_map = nullptr;
1019  // list of inherited members for initialization
1020  member_info_list_t* member_info_list = nullptr;
1021 
1022  // local flag
1023  bool is_local,
1024  // transient flag
1025  is_transient = false;
1026 
1037  DLLLOCAL QoreMemberInfo(const QoreMemberInfo& old, const qore_class_private* cls, ClassAccess cls_access);
1038 };
1039 
1040 class QoreVarInfo : public QoreMemberInfoBaseAccess {
1041 public:
1042  mutable QoreVarRWLock rwl;
1043  QoreLValueGeneric val;
1044  bool finalized;
1045 
1046  DLLLOCAL QoreVarInfo(const QoreProgramLocation* loc, const QoreTypeInfo* n_typeinfo = nullptr, QoreParseTypeInfo* n_parseTypeInfo = nullptr, QoreValue e = QoreValue(), ClassAccess n_access = Public) :
1047  QoreMemberInfoBaseAccess(loc, n_typeinfo, n_parseTypeInfo, e, n_access), finalized(false) {
1048  }
1049 
1050  DLLLOCAL QoreVarInfo(const QoreVarInfo& old, ClassAccess n_access = Public) : QoreMemberInfoBaseAccess(old, n_access), val(old.val), finalized(old.finalized) {
1051  }
1052 
1053  DLLLOCAL ~QoreVarInfo() {
1054  assert(!val.hasValue());
1055  }
1056 
1057 #ifdef DEBUG
1058  DLLLOCAL void del() {
1059  assert(!val.hasValue());
1060  QoreMemberInfoBaseAccess::del();
1061  }
1062 #endif
1063 
1064  DLLLOCAL void clear(ExceptionSink* xsink) {
1065  ValueHolder tmp(xsink);
1066  QoreAutoVarRWWriteLocker al(rwl);
1067  if (!finalized)
1068  finalized = true;
1069  tmp = val.removeValue(true);
1070  }
1071 
1072  DLLLOCAL void delVar(ExceptionSink* xsink) {
1073 #ifdef DEBUG
1074  QoreMemberInfoBaseAccess::del();
1075 #else
1076  del();
1077 #endif
1078  val.removeValue(true).discard(xsink);
1079  }
1080 
1081  DLLLOCAL AbstractQoreNode* assignInit(QoreValue v) {
1082  // try to set an optimized value type for the value holder if possible
1083  val.set(getTypeInfo());
1084  return val.assignInitial(v);
1085  }
1086 
1087  DLLLOCAL void getLValue(LValueHelper& lvh) {
1088  lvh.setAndLock(rwl);
1089  if (checkFinalized(lvh.vl.xsink))
1090  return;
1091  lvh.setValue(val, getTypeInfo());
1092  }
1093 
1094  DLLLOCAL void init() {
1095  val.set(getTypeInfo());
1096  if (getProgram()->getParseOptions64() & PO_STRICT_TYPES) {
1097  // try to set an optimized value type for the value holder if possible
1098  discard(val.assignInitial(QoreTypeInfo::getDefaultQoreValue(typeInfo)), nullptr);
1099  }
1100  }
1101 
1102  DLLLOCAL QoreValue getReferencedValue() const {
1103  QoreAutoVarRWReadLocker al(rwl);
1104  return val.getReferencedValue();
1105  }
1106 
1107  DLLLOCAL int64 getAsBigInt() const {
1108  QoreAutoVarRWReadLocker al(rwl);
1109  return val.getAsBigInt();
1110  }
1111 
1112  DLLLOCAL double getAsFloat() const {
1113  QoreAutoVarRWReadLocker al(rwl);
1114  return val.getAsFloat();
1115  }
1116 
1117  DLLLOCAL bool getAsBool() const {
1118  QoreAutoVarRWReadLocker al(rwl);
1119  return val.getAsBool();
1120  }
1121 
1122  DLLLOCAL void parseInit(const char* name);
1123 
1124 protected:
1125  DLLLOCAL int checkFinalized(ExceptionSink* xsink) const {
1126  if (finalized) {
1127  xsink->raiseException("DESTRUCTOR-ERROR", "illegal class static variable assignment after second phase of variable destruction");
1128  return -1;
1129  }
1130  return 0;
1131  }
1132 };
1133 
1134 template <typename T>
1135 class QoreMemberMapBase {
1136 public:
1137  typedef std::pair<char*, std::unique_ptr<T>> member_list_element_t;
1138  typedef std::deque<member_list_element_t> member_list_t;
1139  typedef typename member_list_t::iterator iterator;
1140  typedef typename member_list_t::const_iterator const_iterator;
1141  member_list_t member_list;
1142 
1143  DLLLOCAL ~QoreMemberMapBase() {
1144  for (auto& i : member_list) {
1145  //printd(5, "QoreMemberMap::~QoreMemberMap() this: %p freeing member %p '%s'\n", this, i->second, i->first);
1146  // the key is allocated normally in the scanner, and must be freed manually here
1147  free(i.first);
1148  }
1149  member_list.clear();
1150  }
1151 
1152  DLLLOCAL bool inList(const char* name) const {
1153  return (bool)find(name);
1154  }
1155 
1156  DLLLOCAL T* find(const char* name) const {
1157  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); });
1158  return i == member_list.end() ? nullptr : i->second.get();
1159  }
1160 
1161  DLLLOCAL bool empty() const {
1162  return member_list.empty();
1163  }
1164 
1165  DLLLOCAL void addNoCheck(char* name, T* info) {
1166  assert(name);
1167  assert(info);
1168  assert(!inList(name));
1169  member_list.push_back(std::make_pair(name, std::unique_ptr<T>(info)));
1170  }
1171 
1172  DLLLOCAL void addNoCheck(std::pair<char*, T*> pair) {
1173  addNoCheck(pair.first, pair.second);
1174  }
1175 
1176  DLLLOCAL void moveAllTo(QoreMemberMapBase<T>& dest) {
1177  dest.member_list.insert(dest.member_list.end(), member_list.begin(), member_list.end());
1178  member_list.clear();
1179  }
1180 
1181  DLLLOCAL size_t size() const {
1182  return member_list.size();
1183  }
1184 };
1185 
1186 class QoreMemberMap : public QoreMemberMapBase<QoreMemberInfo> {
1187 public:
1188  using QoreMemberMapBase<QoreMemberInfo>::moveAllTo;
1189  DLLLOCAL void moveAllTo(QoreClass* qc, ClassAccess access);
1190 
1191  using QoreMemberMapBase<QoreMemberInfo>::addNoCheck;
1192  DLLLOCAL void addNoCheck(char* name, QoreMemberInfo* info) {
1193  assert(info->getClass());
1194  QoreMemberMapBase<QoreMemberInfo>::addNoCheck(name, info);
1195  }
1196 
1197  DLLLOCAL void addInheritedNoCheck(char* name, QoreMemberInfo* info) {
1198  assert(name);
1199  assert(info);
1200  assert(!inList(name));
1201  member_list.insert(member_list.begin(), std::make_pair(name, std::unique_ptr<QoreMemberInfo>(info)));
1202  }
1203 
1204  DLLLOCAL void parseInit(LocalVar& selfid);
1205 
1206 private:
1207  bool init = false;
1208 };
1209 
1210 class QoreVarMap : public QoreMemberMapBase<QoreVarInfo> {
1211 public:
1212  DLLLOCAL void clear(ExceptionSink* xsink) {
1213  for (member_list_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
1214  i->second->clear(xsink);
1215  }
1216  }
1217 
1218  DLLLOCAL void del(ExceptionSink* xsink) {
1219  for (member_list_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
1220  i->second->delVar(xsink);
1221  // the key is allocated normally in the scanner, and must be freed manually here
1222  free(i->first);
1223  }
1224  member_list.clear();
1225  }
1226 
1227  DLLLOCAL void del() {
1228  for (member_list_t::reverse_iterator i = member_list.rbegin(), e = member_list.rend(); i != e; ++i) {
1229  assert(!i->second->val.hasValue());
1230  /*
1231  // when rolling back a failed parse, vars may have values, but no exception can happen, so xsink can be nullptr
1232  i->second->delVar(nullptr);
1233  */
1234  // the key is allocated normally in the scanner, and must be freed manually here
1235  free(i->first);
1236  }
1237  member_list.clear();
1238  }
1239 
1240  DLLLOCAL void clearNoFree() {
1241  member_list.clear();
1242  }
1243 
1244  DLLLOCAL void moveAllTo(QoreClass* qc, ClassAccess access);
1245 
1246  DLLLOCAL void parseCommitRuntimeInit(ExceptionSink* xsink);
1247 
1248 private:
1249  bool init = false;
1250 };
1251 
1252 /*
1253  BCANode
1254  base class constructor argument node
1255 */
1256 class BCANode : public FunctionCallBase {
1257 public:
1258  // set automatically when created
1259  const QoreProgramLocation* loc;
1260  qore_classid_t classid = 0;
1261  //QoreClass* sclass;
1262  NamedScope* ns;
1263  char* name;
1264 
1265  // this function takes ownership of n and arg
1266  DLLLOCAL BCANode(NamedScope* n, QoreParseListNode* n_args, const QoreProgramLocation* loc) : FunctionCallBase(n_args), loc(loc), ns(n), name(nullptr) {
1267  assert(loc->start_line > 0);
1268  }
1269 
1270  // this function takes ownership of n and arg
1271  DLLLOCAL BCANode(char* n, QoreParseListNode* n_args, const QoreProgramLocation* loc) : FunctionCallBase(n_args), loc(loc), ns(nullptr), name(n) {
1272  assert(loc->start_line > 0);
1273  }
1274 
1275  DLLLOCAL ~BCANode() {
1276  delete ns;
1277  if (name)
1278  free(name);
1279  }
1280 
1281  // resolves classes, parses arguments, and attempts to find constructor variant
1282  DLLLOCAL void parseInit(BCList* bcl, const char* classname);
1283 };
1284 
1285 typedef std::vector<BCANode*> bcalist_t;
1286 
1287 // BCAList
1288 // base class constructor argument list
1289 // this data structure will not be modified even if the class is copied
1290 // to a subprogram object
1291 class BCAList : public bcalist_t {
1292 public:
1293  DLLLOCAL BCAList(BCANode* n) {
1294  push_back(n);
1295  }
1296 
1297  DLLLOCAL ~BCAList() {
1298  for (bcalist_t::iterator i = begin(), e = end(); i != e; ++i)
1299  delete *i;
1300  }
1301 
1302  // returns 0 for no errors, -1 for exception raised
1303  DLLLOCAL int execBaseClassConstructorArgs(BCEAList* bceal, ExceptionSink* xsink) const;
1304 };
1305 
1306 typedef std::pair<QoreClass*, bool> class_virt_pair_t;
1307 //typedef std::list<class_virt_pair_t> class_list_t;
1308 typedef std::vector<class_virt_pair_t> class_list_t;
1309 
1310 // member initialization list entry
1311 hashdecl member_init_entry_t {
1312  const char* name;
1313  const QoreMemberInfo* info;
1314  const qore_class_private* member_class_ctx;
1315 
1316  DLLLOCAL member_init_entry_t(const char* name, const QoreMemberInfo* info, const qore_class_private* member_class_ctx) :
1317  name(name), info(info), member_class_ctx(member_class_ctx) {
1318  }
1319 };
1320 
1321 // list of members in initialization order
1322 typedef std::vector<member_init_entry_t> member_init_list_t;
1323 
1324 // BCSMList: Base Class Special Method List
1325 // unique list of base classes for a class hierarchy to ensure that "special" methods, constructor(), destructor(), copy() - are executed only once
1326 // this class also tracks virtual classes to ensure that they are not inserted into the list in a complex tree and executed here
1327 class BCSMList : public class_list_t {
1328 public:
1329  DLLLOCAL BCSMList() {
1330  }
1331 
1332  DLLLOCAL BCSMList(const BCSMList &old);
1333 
1334  DLLLOCAL ~BCSMList();
1335 
1336  DLLLOCAL void processMemberInitializationList(const QoreMemberMap& members, member_init_list_t& member_init_list);
1337 
1338  DLLLOCAL int add(QoreClass* thisclass, QoreClass* qc, bool is_virtual);
1339  DLLLOCAL int addBaseClassesToSubclass(QoreClass* thisclass, QoreClass* sc, bool is_virtual);
1340 
1341  DLLLOCAL void alignBaseClassesInSubclass(QoreClass* thisclass, QoreClass* child, bool is_virtual);
1342 
1343  // returns 0 = can add, non-0 = cannot add
1344  DLLLOCAL void align(QoreClass* thisclass, QoreClass* qc, bool is_virtual);
1345 
1346  DLLLOCAL QoreClass* getClass(qore_classid_t cid) const;
1347  //DLLLOCAL void execConstructors(QoreObject* o, BCEAList* bceal, ExceptionSink* xsink) const;
1348  DLLLOCAL void execDestructors(QoreObject* o, ExceptionSink* xsink) const;
1349  DLLLOCAL void execSystemDestructors(QoreObject* o, ExceptionSink* xsink) const;
1350  DLLLOCAL void execCopyMethods(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const;
1351 
1352  // parseResolve classes to the new class pointer after all namespaces and classes have been copied
1353  DLLLOCAL void resolveCopy();
1354 };
1355 
1356 // set of private class pointers; used when checking for recursive class inheritance lists
1357 typedef vector_set_t<qore_class_private*> qcp_set_t;
1358 //typedef std::set<qore_class_private*> qcp_set_t;
1359 
1360 // BCNode
1361 // base class pointer
1362 class BCNode {
1363 public:
1364  // populated automatically on creation
1365  const QoreProgramLocation* loc;
1366  NamedScope* cname;
1367  char* cstr;
1368  QoreClass* sclass;
1369  ClassAccess access;
1370  bool is_virtual : 1;
1371 
1372  DLLLOCAL BCNode(const QoreProgramLocation* loc, NamedScope* c, ClassAccess a) : loc(loc), cname(c), cstr(nullptr), sclass(nullptr), access(a), is_virtual(false) {
1373  }
1374 
1375  // this method takes ownership of *str
1376  DLLLOCAL BCNode(const QoreProgramLocation* loc, char* str, ClassAccess a) : loc(loc), cname(0), cstr(str), sclass(nullptr), access(a), is_virtual(false) {
1377  }
1378 
1379  // for builtin base classes
1380  DLLLOCAL BCNode(const QoreProgramLocation* loc, QoreClass* qc, bool n_virtual = false)
1381  : loc(loc), cname(nullptr), cstr(nullptr), sclass(qc), access(Public), is_virtual(n_virtual) {
1382  }
1383 
1384  // called at runtime with committed classes
1385  DLLLOCAL BCNode(const BCNode &old) : loc(old.loc), cname(nullptr), cstr(nullptr), sclass(old.sclass), access(old.access), is_virtual(old.is_virtual) {
1386  assert(!old.cname);
1387  assert(!old.cstr);
1388  assert(old.sclass);
1389  }
1390 
1391  DLLLOCAL ~BCNode() {
1392  delete cname;
1393  if (cstr)
1394  free(cstr);
1395  }
1396 
1397  DLLLOCAL ClassAccess getAccess() const { return access; }
1398 
1399  // returns -1 if a recursive reference is found, 0 if not
1400  DLLLOCAL int initializeHierarchy(QoreClass* cls, qcp_set_t& qcp_set);
1401 
1402  DLLLOCAL void initializeMembers(QoreClass* cls);
1403 
1404  // returns -1 if a recursive reference is found, 0 if not
1405  DLLLOCAL int initialize(QoreClass* cls, bool& has_delete_blocker);
1406 
1407  DLLLOCAL bool isBaseClass(QoreClass* qc, bool toplevel) const;
1408 
1409  DLLLOCAL const QoreMethod* runtimeFindCommittedMethod(const char* name, ClassAccess& n_access, const qore_class_private* class_ctx, bool allow_internal) const;
1410  DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethod(const char* name, ClassAccess& n_access, const qore_class_private* class_ctx, bool allow_internal) const;
1411 
1412  DLLLOCAL bool runtimeIsPrivateMember(const char* str, bool toplevel) const;
1413 
1414  DLLLOCAL void execConstructors(QoreObject* o, BCEAList* bceal, ExceptionSink* xsink) const;
1415 
1416  DLLLOCAL const QoreMemberInfo* parseFindMember(const char* mem, const qore_class_private*& qc, ClassAccess& n_access, bool toplevel) const;
1417  DLLLOCAL const QoreVarInfo* parseFindVar(const char* name, const qore_class_private*& qc, ClassAccess& n_access, bool toplevel) const;
1418 
1419  DLLLOCAL const QoreClass* findInHierarchy(const qore_class_private& qc);
1420 
1421  DLLLOCAL const QoreClass* getClass(qore_classid_t cid, ClassAccess& n_access, bool toplevel) const;
1422  DLLLOCAL const QoreClass* getClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1423  DLLLOCAL const QoreClass* parseGetClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1424  DLLLOCAL bool inHierarchy(const qore_class_private& qc, ClassAccess& n_access) const;
1425 
1426  // inaccessible methods are ignored
1427  DLLLOCAL const QoreMethod* parseFindNormalMethod(const char* name, const qore_class_private* class_ctx, bool allow_internal) const;
1428 
1429  // inaccessible methods are ignored
1430  DLLLOCAL const QoreMethod* parseFindStaticMethod(const char* name, const qore_class_private* class_ctx, bool allow_internal) const;
1431 
1432  // inaccessible methods are ignored
1433  DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, const char* name, const qore_class_private* class_ctx, bool allow_internal) const;
1434 
1435  DLLLOCAL bool parseCheckHierarchy(const QoreClass* cls, ClassAccess& n_access, bool toplevel) const;
1436 
1437  DLLLOCAL QoreVarInfo* parseFindStaticVar(const char* vname, const QoreClass*& qc, ClassAccess& n_access, bool check, bool toplevel) const;
1438 
1439  DLLLOCAL QoreValue parseFindConstantValue(const char* cname, const QoreTypeInfo*& typeInfo, bool &found, const qore_class_private* class_ctx, bool allow_internal) const;
1440 
1441  DLLLOCAL int addBaseClassesToSubclass(QoreClass* child, bool is_virtual);
1442 
1443  DLLLOCAL void initializeBuiltin();
1444 };
1445 
1446 typedef std::vector<BCNode*> bclist_t;
1447 
1448 // BCList
1449 // linked list of base classes, constructors called head->tail,
1450 // destructors called in reverse order (tail->head) (stored in BCSMList)
1451 // note that this data structure cannot be modified even if the class is
1452 // copied to a subprogram object and extended
1453 // this class is a QoreReferenceCounter so it won't be copied when the class is copied
1454 class BCList : public bclist_t {
1455 protected:
1456 public:
1457  // special method (constructor, destructor, copy) list for superclasses
1458  BCSMList sml;
1459  bool valid = true;
1460  bool rescanned = false;
1461 
1462  DLLLOCAL BCList(BCNode* n) {
1463  push_back(n);
1464  }
1465 
1466  DLLLOCAL BCList() {
1467  }
1468 
1469  DLLLOCAL BCList(const BCList& old) : sml(old.sml) {
1470  assert(old.valid);
1471  reserve(old.size());
1472  for (bclist_t::const_iterator i = old.begin(), e = old.end(); i != e; ++i)
1473  push_back(new BCNode(*(*i)));
1474  }
1475 
1476  DLLLOCAL ~BCList() {
1477  for (bclist_t::iterator i = begin(), e = end(); i != e; ++i)
1478  delete *i;
1479  }
1480 
1481  DLLLOCAL int initializeHierarchy(QoreClass* thisclass, qcp_set_t& qcp_set);
1482 
1483  DLLLOCAL void initializeMembers(QoreClass* thisclass);
1484 
1485  DLLLOCAL int initialize(QoreClass* thisclass, bool& has_delete_blocker);
1486 
1487  // inaccessible methods are ignored
1488  DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, const char* name, const qore_class_private* class_ctx, bool allow_internal);
1489 
1490  // inaccessible methods are ignored
1491  DLLLOCAL const QoreMethod* parseFindNormalMethod(const char* name, const qore_class_private* class_ctx, bool allow_internal);
1492  // inaccessible methods are ignored
1493  DLLLOCAL const QoreMethod* parseFindStaticMethod(const char* name, const qore_class_private* class_ctx, bool allow_internal);
1494 
1495  DLLLOCAL const QoreMethod* runtimeFindCommittedMethod(const char* name, ClassAccess& access, const qore_class_private* class_ctx, bool allow_internal) const;
1496  DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethod(const char* name, ClassAccess& access, const qore_class_private* class_ctx, bool allow_internal) const;
1497 
1498  DLLLOCAL bool match(const QoreClass* cls);
1499  DLLLOCAL void execConstructors(QoreObject* o, BCEAList* bceal, ExceptionSink* xsink) const;
1500  DLLLOCAL bool execDeleteBlockers(QoreObject* o, ExceptionSink* xsink) const;
1501 
1502  DLLLOCAL bool runtimeIsPrivateMember(const char* str, bool toplevel) const;
1503 
1504  DLLLOCAL bool parseCheckHierarchy(const QoreClass* cls, ClassAccess& access, bool toplevel) const;
1505 
1506  DLLLOCAL const QoreMemberInfo* parseFindMember(const char* mem, const qore_class_private*& qc, ClassAccess& n_access, bool toplevel) const;
1507 
1508  DLLLOCAL const QoreVarInfo* parseFindVar(const char* vname, const qore_class_private*& qc, ClassAccess& access, bool toplevel) const;
1509 
1510  DLLLOCAL bool parseHasPublicMembersInHierarchy() const;
1511 
1512  DLLLOCAL const QoreClass* findInHierarchy(const qore_class_private& qc);
1513 
1514  DLLLOCAL const QoreClass* getClass(qore_classid_t cid, ClassAccess& n_access, bool toplevel) const;
1515  DLLLOCAL const QoreClass* getClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1516 
1517  DLLLOCAL const QoreClass* parseGetClass(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const;
1518  DLLLOCAL bool inHierarchy(const qore_class_private& qc, ClassAccess& n_access) const;
1519 
1520  DLLLOCAL void addNewAncestors(QoreMethod* m);
1521  DLLLOCAL void addAncestors(QoreMethod* m);
1522  DLLLOCAL void addNewStaticAncestors(QoreMethod* m);
1523  DLLLOCAL void addStaticAncestors(QoreMethod* m);
1524  DLLLOCAL void parseAddAncestors(QoreMethod* m);
1525  DLLLOCAL void parseAddStaticAncestors(QoreMethod* m);
1526 
1527  DLLLOCAL void parseResolveAbstract();
1528 
1529  DLLLOCAL QoreValue parseFindConstantValue(const char* cname, const QoreTypeInfo*& typeInfo, bool& found, const qore_class_private* class_ctx, bool allow_internal) const;
1530 
1531  DLLLOCAL QoreVarInfo* parseFindStaticVar(const char* vname, const QoreClass*& qc, ClassAccess& access, bool check, bool toplevel) const;
1532 
1533  DLLLOCAL void resolveCopy();
1534 
1535  DLLLOCAL MethodVariantBase* matchNonAbstractVariant(const std::string& name, MethodVariantBase* v) const;
1536 
1537  DLLLOCAL bool isBaseClass(QoreClass* qc, bool toplevel) const;
1538 
1539  DLLLOCAL int addBaseClassesToSubclass(QoreClass* thisparent, QoreClass* child, bool is_virtual) {
1540  for (auto& i : *this) {
1541  if ((*i).addBaseClassesToSubclass(child, is_virtual))
1542  return -1;
1543  }
1544  return sml.addBaseClassesToSubclass(thisparent, child, is_virtual);
1545  }
1546 
1547  DLLLOCAL void rescanParents(QoreClass* cls);
1548 
1549  DLLLOCAL void initializeBuiltin() {
1550  for (auto& i : *this) {
1551  (*i).initializeBuiltin();
1552  }
1553  }
1554 };
1555 
1556 // BCEANode
1557 // base constructor evaluated argument node; created locally at run time
1558 class BCEANode {
1559 public:
1560  const QoreProgramLocation* loc;
1561  QoreListNode* args = nullptr;
1562  const AbstractQoreFunctionVariant* variant = nullptr;
1563  bool execed = false;
1564  bool member_init_done = false;
1565 
1566  DLLLOCAL BCEANode(const QoreProgramLocation* loc, QoreListNode* args, const AbstractQoreFunctionVariant* variant) : loc(loc), args(args), variant(reinterpret_cast<const MethodVariant*>(variant)) {
1567  }
1568 
1569  DLLLOCAL BCEANode(bool n_execed = true, bool mid = true) : execed(n_execed), member_init_done(mid) {
1570  }
1571 };
1572 
1573 /*
1574 hashdecl ltqc {
1575  bool operator()(const QoreClass* qc1, const QoreClass* qc2) const {
1576  return qc1 < qc2;
1577  }
1578 };
1579 */
1580 
1581 //typedef std::map<qore_classid_t, BCEANode*> bceamap_t;
1582 typedef vector_map_t<qore_classid_t, BCEANode*> bceamap_t;
1583 
1584 /*
1585  BCEAList
1586  base constructor evaluated argument list
1587 */
1588 class BCEAList : public bceamap_t {
1589 protected:
1590  DLLLOCAL ~BCEAList() {
1591  assert(empty());
1592  }
1593 
1594 public:
1595  DLLLOCAL void deref(ExceptionSink* xsink);
1596  // evaluates arguments, returns -1 if an exception was thrown
1597  DLLLOCAL int add(qore_classid_t classid, const QoreListNode* arg, const AbstractQoreFunctionVariant* variant, const QoreProgramLocation* loc, ExceptionSink* xsink);
1598  DLLLOCAL QoreListNode* findArgs(qore_classid_t classid, bool* aexeced, const AbstractQoreFunctionVariant*& variant, const QoreProgramLocation*& loc);
1599  /*
1600  DLLLOCAL bool initMembers(qore_classid_t classid) {
1601  bceamap_t::iterator i = lower_bound(classid);
1602  if (i == end() || i->first != classid) {
1603  insert(i, bceamap_t::value_type(classid, new BCEANode(false, true)));
1604  return false;
1605  }
1606  if (!i->second->member_init_done) {
1607  i->second->member_init_done = true;
1608  return false;
1609  }
1610  return true;
1611  }
1612  */
1613 };
1614 
1615 hashdecl SelfInstantiatorHelper {
1616  LocalVar* selfid;
1617  DLLLOCAL SelfInstantiatorHelper(LocalVar* n_selfid, QoreObject* self) : selfid(n_selfid) {
1618  selfid->instantiateSelf(self);
1619  }
1620  DLLLOCAL ~SelfInstantiatorHelper() {
1621  selfid->uninstantiateSelf();
1622  }
1623 };
1624 
1625 // signature hash size - we use SHA1 for performance reasons (and because we don't necessarily need the best cryptographic security)
1626 #define SH_SIZE 20
1627 
1628 // class "signature" hash for comparing classes with the same name from different program objects at runtime
1629 class SignatureHash {
1630 protected:
1631  unsigned char buf[SH_SIZE];
1632  bool is_set;
1633 
1634  DLLLOCAL void set(const QoreString& str);
1635 
1636  DLLLOCAL void clearHash() {
1637  memset(buf, 0, SH_SIZE);
1638  }
1639 
1640  DLLLOCAL void copyHash(const SignatureHash& other) {
1641  memcpy(buf, other.buf, SH_SIZE);
1642  }
1643 
1644 public:
1645  DLLLOCAL SignatureHash() : is_set(false) {
1646  clearHash();
1647  }
1648 
1649  DLLLOCAL SignatureHash(const SignatureHash& old) : is_set(old.is_set) {
1650  if (is_set)
1651  copyHash(old);
1652  }
1653 
1654  DLLLOCAL void update(const QoreString& str);
1655 
1656  DLLLOCAL void updateEmpty() {
1657  assert(!is_set);
1658  clearHash();
1659  is_set = true;
1660  }
1661 
1662  DLLLOCAL bool operator==(const SignatureHash& other) const {
1663  // if either one of the hashes is not set, then the comparison always fails
1664  if (!is_set || !other.is_set)
1665  return false;
1666  return !memcmp(buf, other.buf, SH_SIZE);
1667  }
1668 
1669  DLLLOCAL SignatureHash& operator=(const SignatureHash& other) {
1670  if (!other.is_set) {
1671  assert(false);
1672  clear();
1673  }
1674  else {
1675  if (!is_set)
1676  is_set = true;
1677  copyHash(other);
1678  }
1679  return *this;
1680  }
1681 
1682  DLLLOCAL operator bool() const {
1683  return is_set;
1684  }
1685 
1686  // appends the hash to the string
1687  DLLLOCAL void toString(QoreString& str) const {
1688  for (unsigned i = 0; i < SH_SIZE; ++i)
1689  str.sprintf("%02x", buf[i]);
1690  }
1691 
1692  DLLLOCAL char* getHash() const {
1693  assert(is_set);
1694  return (char*)buf;
1695  }
1696 
1697  DLLLOCAL void clear() {
1698  if (is_set) {
1699  is_set = false;
1700  clearHash();
1701  }
1702  }
1703 };
1704 
1705 #define QCCM_NORMAL (1 << 0)
1706 #define QCCM_STATIC (1 << 1)
1707 
1708 // set of QoreClass pointers associted to a qore_class_private object
1709 typedef vector_set_t<QoreClass*> qc_set_t;
1710 //typedef std::set<QoreClass*> qc_set_t;
1711 
1712 // private QoreClass implementation
1713 // only dynamically allocated; reference counter managed in "refs"
1714 class qore_class_private {
1715 public:
1716  const QoreProgramLocation* loc; // location of declaration
1717  std::string name; // the name of the class
1718  QoreClass* cls; // parent class
1719  qore_ns_private* ns = nullptr; // parent namespace
1720  BCList* scl = nullptr; // base class list
1721  qc_set_t qcset; // set of QoreClass pointers associated with this private object (besides cls)
1722 
1723  mutable VRMutex gate; // for synchronized static methods
1724 
1725  hm_method_t hm, // "normal" (non-static) method map
1726  shm; // static method map
1727 
1728  AbstractMethodMap ahm; // holds abstract variants with no implementation in the current class
1729 
1730  ConstantList constlist; // class constants
1731 
1732  // member list (map)
1733  QoreMemberMap members;
1734  // member initialization list in hierarchy nitialization order
1735  member_init_list_t member_init_list;
1736 
1737  // static var list (map)
1738  QoreVarMap vars;
1739 
1740  const QoreMethod* system_constructor = nullptr,
1741  * constructor = nullptr,
1742  * destructor = nullptr,
1743  * copyMethod = nullptr,
1744  * methodGate = nullptr,
1745  * memberGate = nullptr,
1746  * deleteBlocker = nullptr,
1747  * memberNotification = nullptr;
1748 
1749  q_serializer_t serializer = nullptr;
1750  q_deserializer_t deserializer = nullptr;
1751 
1752  qore_classid_t classID, // class ID
1753  methodID; // for subclasses of builtin classes that will not have their own private data,
1754  // instead they will get the private data from this class
1755 
1756  bool sys : 1, // system/builtin class?
1757  initialized : 1, // is initialized? (only performed once)
1758  static_init : 1, // has static initialization been called for the class?
1759  parse_init_called : 1, // has parseInit() been called? (performed once for each parseCommit())
1760  parse_init_partial_called : 1, // has parseInitPartial() been called? (performed once for each parseCommit())
1761  has_delete_blocker : 1, // has a delete_blocker function somewhere in the hierarchy?
1762  has_public_memdecl : 1, // has a public member declaration somewhere in the hierarchy?
1763  pending_has_public_memdecl : 1, // has a pending public member declaration in this class?
1764  owns_typeinfo : 1, // do we own the typeInfo data or not?
1765  resolve_copy_done : 1, // has the copy already been resolved
1766  has_new_user_changes : 1, // does the class have new user code that needs to be processed?
1767  has_sig_changes : 1, // does the class have code affecting the signature to be processed?
1768  owns_ornothingtypeinfo : 1, // do we own the "or nothing" type info
1769  pub : 1, // is a public class (modules only)
1770  final : 1, // is the class "final" (cannot be inherited)
1771  inject : 1, // has the class been injected
1772  gate_access : 1, // if the methodGate and memberGate methods should be called with a class access boolean
1773  committed : 1, // can only parse to a class once
1774  parse_resolve_hierarchy : 1, // class hierarchy resolved
1775  parse_resolve_class_members : 1, // class members resolved
1776  parse_resolve_abstract : 1, // abstract methods resolved
1777  has_transient_member : 1 // has at least one transient member
1778  ;
1779 
1780  int64 domain; // capabilities of builtin class to use in the context of parse restrictions
1781  mutable QoreReferenceCounter refs; // existence references
1782  mutable QoreReferenceCounter const_refs; // constant references
1783  mutable QoreReferenceCounter var_refs; // static var references
1784 
1785  unsigned num_methods, num_user_methods, num_static_methods, num_static_user_methods;
1786 
1787  // type information for the class, may not have a pointer to the same QoreClass
1788  // as the actual owning class in case of a copy
1789  QoreTypeInfo* typeInfo,
1790  *orNothingTypeInfo;
1791 
1792  const qore_class_private* injectedClass = nullptr;
1793 
1794  // common "self" local variable for all constructors
1795  mutable LocalVar selfid;
1796 
1797  // class "signature" hash for comparing classes with the same name from different program objects at runtime
1798  SignatureHash hash;
1799 
1800  // user-specific data
1801  const void* ptr = nullptr;
1802 
1803  // managed user-specific data
1804  AbstractQoreClassUserData* mud = nullptr;
1805 
1806  // pointer to new class when copying
1807  mutable QoreClass* new_copy = nullptr;
1808 
1809  // pointer to owning program for imported classes
1810  QoreProgram* spgm = nullptr;
1811 
1812  // if the souorce program should be dereference when the class is destroyed
1813  bool deref_source_program = true;
1814 
1815  // the module that defined this class, if any
1816  std::string from_module;
1817 
1818  DLLLOCAL qore_class_private(QoreClass* n_cls, std::string&& nme, int64 dom = QDOM_DEFAULT, QoreTypeInfo* n_typeinfo = nullptr);
1819 
1820  // only called while the parse lock for the QoreProgram owning "old" is held
1821  // called for injected classes only
1822  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);
1823 
1824 public:
1825  DLLLOCAL const char* getModuleName() const {
1826  return from_module.empty() ? nullptr : from_module.c_str();
1827  }
1828 
1829  DLLLOCAL void pgmRef() const {
1830  refs.ROreference();
1831  var_refs.ROreference();
1832  const_refs.ROreference();
1833  }
1834 
1835  DLLLOCAL void ref() const {
1836  refs.ROreference();
1837  }
1838 
1839  DLLLOCAL bool deref(bool ns_const, bool ns_vars, bool in_del = false) {
1840  if (ns_const && const_refs.ROdereference()) {
1841  // constants may not be empty when deleting an uninitialized user class
1842  if (!constlist.empty()) {
1843  constlist.deleteAll(nullptr);
1844  }
1845  }
1846  if (ns_vars && var_refs.ROdereference()) {
1847  // vars may not be empty when deleting an uninitialized user class
1848  if (!vars.empty()) {
1849  vars.del(nullptr);
1850  }
1851  }
1852 
1853  if (refs.ROdereference()) {
1854  // remove the private data pointer, delete the class object, then delete ourselves
1855  cls->priv = nullptr;
1856  if (!in_del) {
1857  delete cls;
1858  }
1859 
1860  // delete all linked QoreClass objects
1861  for (auto& i : qcset) {
1862  i->priv = nullptr;
1863  delete i;
1864  }
1865 
1866  delete this;
1867  return true;
1868  }
1869  return false;
1870  }
1871 
1872  DLLLOCAL bool hasAbstract() const {
1873  return !ahm.empty();
1874  }
1875 
1876  DLLLOCAL int runtimeCheckInstantiateClass(ExceptionSink* xsink) const {
1877  return ahm.runtimeCheckInstantiateClass(name.c_str(), xsink);
1878  }
1879 
1880  DLLLOCAL void parseCheckAbstractNew(const QoreProgramLocation* loc) const;
1881 
1882  DLLLOCAL void parseDoCheckAbstractNew(const QoreProgramLocation* loc) const {
1883  ahm.parseCheckAbstractNew(loc, name.c_str());
1884  }
1885 
1886  DLLLOCAL void setNamespace(qore_ns_private* n) {
1887  assert(!ns);
1888  ns = n;
1889  }
1890 
1891  // returns true if the namespace was assigned
1892  DLLLOCAL bool setNamespaceConditional(qore_ns_private* n) {
1893  // only assign the namespace if it hasn't already been assiogned
1894  if (!ns) {
1895  ns = n;
1896  return true;
1897  }
1898  return false;
1899  }
1900 
1901  // used when assimilating a namespace at parse time
1902  DLLLOCAL void updateNamespace(qore_ns_private* n) {
1903  assert(ns);
1904  ns = n;
1905  }
1906 
1907  DLLLOCAL void resolveCopy();
1908 
1909  DLLLOCAL void setUserData(const void* n_ptr) {
1910  assert(!ptr);
1911  ptr = n_ptr;
1912  }
1913 
1914  DLLLOCAL const void* getUserData() const {
1915  return ptr;
1916  }
1917 
1918  DLLLOCAL void setManagedUserData(AbstractQoreClassUserData* n_mud) {
1919  assert(!mud);
1920  mud = n_mud;
1921  }
1922 
1923  DLLLOCAL AbstractQoreClassUserData* getManagedUserData() const {
1924  return mud;
1925  }
1926 
1927  DLLLOCAL const QoreTypeInfo* getTypeInfo() const {
1928  return typeInfo;
1929  }
1930 
1931  DLLLOCAL const QoreTypeInfo* getOrNothingTypeInfo() const {
1932  return orNothingTypeInfo;
1933  }
1934 
1935  DLLLOCAL bool runtimeIsPrivateMemberIntern(const char* str, bool toplevel) const;
1936 
1937  DLLLOCAL void parseImportMembers(qore_class_private& qc, ClassAccess access);
1938 
1939  DLLLOCAL bool parseHasMemberGate() const {
1940  return memberGate || hm.find("memberGate") != hm.end();
1941  }
1942 
1943  DLLLOCAL bool parseHasMethodGate() const {
1944  return methodGate || hm.find("methodGate") != hm.end();
1945  }
1946 
1947  // checks for all special methods except constructor & destructor
1948  DLLLOCAL bool checkAssignSpecialIntern(const QoreMethod* m) {
1949  // set quick pointers
1950  if (!methodGate && !strcmp(m->getName(), "methodGate")) {
1951  methodGate = m;
1952  return true;
1953  }
1954 
1955  if (!memberGate && !strcmp(m->getName(), "memberGate")) {
1956  memberGate = m;
1957  //printd(5, "qore_class_private::checkAssignSpecialIntern() this: %p got %s::%s()\n", this, name.c_str(), m->getName());
1958  return true;
1959  }
1960 
1961  if (!memberNotification && !strcmp(m->getName(), "memberNotification")) {
1962  memberNotification = m;
1963  return true;
1964  }
1965 
1966  return false;
1967  }
1968 
1969  // checks for all special methods except constructor, destructor, and copy
1970  DLLLOCAL bool checkSpecialStaticIntern(const char* mname) {
1971  // set quick pointers
1972  if ((!methodGate && !strcmp(mname, "methodGate"))
1973  || (!memberGate && !strcmp(mname, "memberGate"))
1974  || (!memberNotification && !strcmp(mname, "memberNotification")))
1975  return true;
1976  return false;
1977  }
1978 
1979  // checks for all special methods
1980  DLLLOCAL bool checkSpecial(const char* mname) {
1981  // set quick pointers
1982  if ((!methodGate && !strcmp(mname, "methodGate"))
1983  || (!memberGate && !strcmp(mname, "memberGate"))
1984  || (!memberNotification && !strcmp(mname, "memberNotification"))
1985  || (!constructor && !strcmp(mname, "constructor"))
1986  || (!destructor && !strcmp(mname, "destructor"))
1987  || (!copyMethod && !strcmp(mname, "copy")))
1988  return true;
1989  return false;
1990  }
1991 
1992  // checks for all special methods
1993  DLLLOCAL bool checkAssignSpecial(const QoreMethod* m) {
1994  // set quick pointers
1995  if (!constructor && !strcmp(m->getName(), "constructor")) {
1996  constructor = m;
1997  return true;
1998  }
1999 
2000  if (!destructor && !strcmp(m->getName(), "destructor")) {
2001  destructor = m;
2002  return true;
2003  }
2004 
2005  if (!copyMethod && !strcmp(m->getName(), "copy")) {
2006  copyMethod = m;
2007  return true;
2008  }
2009 
2010  return checkAssignSpecialIntern(m);
2011  }
2012 
2013  // merge abstract variants from base classes to child class
2014  DLLLOCAL void mergeAbstract();
2015 
2016  // returns -1 if a recursive inheritance list was found, 0 if not
2017  DLLLOCAL int initializeIntern();
2018  DLLLOCAL int initializeHierarchy(qcp_set_t& qcp_set);
2019  DLLLOCAL void initializeMembers();
2020  DLLLOCAL void initialize();
2021 
2022  DLLLOCAL void parseInitPartial();
2023  DLLLOCAL void parseInitPartialIntern();
2024 
2025  DLLLOCAL int parseCheckMemberAccess(const QoreProgramLocation* loc, const char* mem, const QoreTypeInfo*& memberTypeInfo, int pflag) const {
2026  const_cast<qore_class_private*>(this)->parseInitPartial();
2027 
2028  const qore_class_private* qc = nullptr;
2029  ClassAccess access;
2030  const QoreMemberInfo* omi = parseFindMember(mem, qc, access);
2031 
2032  if (!omi) {
2033  int rc = 0;
2034  if (!parseHasMemberGate() || (pflag & PF_FOR_ASSIGNMENT)) {
2035  if (parse_check_parse_option(PO_REQUIRE_TYPES)) {
2036  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",
2037  mem, name.c_str());
2038  rc = -1;
2039  }
2040  if (parseHasPublicMembersInHierarchy()) {
2041  //printd(5, "qore_class_private::parseCheckMemberAccess() %s %%.%s memberGate: %d pflag: %d\n", name.c_str(), mem, parseHasMemberGate(), pflag);
2042  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());
2043  rc = -1;
2044  }
2045  }
2046  return rc;
2047  }
2048 
2049  memberTypeInfo = omi->getTypeInfo();
2050 
2051  // only raise a parse error for illegal access to private members if there is not memberGate function
2052  if ((access > Public) && !parseHasMemberGate() && !parseCheckPrivateClassAccess()) {
2053  memberTypeInfo = 0;
2054  parse_error(*loc, "illegal access to private member '%s' of class '%s'", mem, name.c_str());
2055  return -1;
2056  }
2057  return 0;
2058  }
2059 
2060  DLLLOCAL int parseResolveInternalMemberAccess(const char* mem, const QoreTypeInfo*& memberTypeInfo) const {
2061  const_cast<qore_class_private*>(this)->parseInitPartial();
2062 
2063  const qore_class_private* qc = nullptr;
2064  ClassAccess access;
2065  const QoreMemberInfo* omi = parseFindMember(mem, qc, access);
2066  if (omi) {
2067  memberTypeInfo = omi->getTypeInfo();
2068  }
2069 
2070  return omi ? 0 : -1;
2071  }
2072 
2073  DLLLOCAL int parseCheckInternalMemberAccess(const char* mem, const QoreTypeInfo*& memberTypeInfo, const QoreProgramLocation* loc) const {
2074  const_cast<qore_class_private*>(this)->parseInitPartial();
2075 
2076  // throws a parse exception if there are public members and the name is not valid
2077  const qore_class_private* qc = nullptr;
2078  ClassAccess access;
2079  const QoreMemberInfo* omi = parseFindMember(mem, qc, access);
2080  if (omi) {
2081  // issue #3355: to handle out of order initialization properly, we need to ensure that the member is
2082  // initialized before accessing its type. We cannot rely on calling members.parseInit() here because
2083  // we may have already been called by this call
2084  const_cast<QoreMemberInfo*>(omi)->parseInit(mem, selfid);
2085  memberTypeInfo = omi->parseGetTypeInfo();
2086  }
2087 
2088  int rc = 0;
2089  if (!omi) {
2090  if (parse_check_parse_option(PO_REQUIRE_TYPES)) {
2091  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());
2092  rc = -1;
2093  }
2094  if (parseHasPublicMembersInHierarchy()) {
2095  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());
2096  rc = -1;
2097  }
2098  }
2099  return rc;
2100  }
2101 
2102  DLLLOCAL bool parseHasPublicMembersInHierarchy() const {
2103  if (has_public_memdecl || pending_has_public_memdecl)
2104  return true;
2105 
2106  return scl ? scl->parseHasPublicMembersInHierarchy() : false;
2107  }
2108 
2116  DLLLOCAL const qore_class_private* runtimeGetMemberContext(const char* mem, const qore_class_private* class_ctx) const {
2117  const QoreMemberInfo* info = runtimeGetMemberInfo(mem, class_ctx);
2118  //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);
2119  return info ? info->getClassContext(class_ctx) : nullptr;
2120  }
2121 
2122  DLLLOCAL bool runtimeIsMemberInternal(const char* mem) const {
2123  QoreMemberInfo* info = members.find(mem);
2124  return info && info->isLocalInternal() ? true : false;
2125  }
2126 
2137  DLLLOCAL const QoreMemberInfo* runtimeGetMemberInfo(const char* mem, const qore_class_private* class_ctx) const {
2138  QoreMemberInfo* info;
2139  if (class_ctx) {
2140  info = class_ctx->members.find(mem);
2141  if (info && info->isLocalInternal()) {
2142  return info;
2143  }
2144  }
2145  else {
2146  info = nullptr;
2147  }
2148 
2149  if (class_ctx != this) {
2150  info = members.find(mem);
2151  }
2152 
2153  if (info && info->access == Inaccessible && !info->getClassContext(class_ctx)) {
2154  info = nullptr;
2155  }
2156 
2157  return info;
2158  }
2159 
2160  DLLLOCAL const QoreMemberInfo* parseFindMember(const char* mem, const qore_class_private*& qc, ClassAccess& access) const {
2161  access = Public;
2162  const_cast<qore_class_private*>(this)->initialize();
2163  return parseFindMemberNoInit(mem, qc, access, true);
2164  }
2165 
2166  // returns the member if it's defined and reachable from the class and cannot be declared again in the top-level class
2169  DLLLOCAL const QoreMemberInfo* parseFindMemberNoInit(const char* mem, const qore_class_private*& qc, ClassAccess& access, bool toplevel) const {
2170  const QoreMemberInfo* mi = members.find(mem);
2171  if (mi) {
2172  ClassAccess ma = mi->getAccess();
2173  if (toplevel || ma != Internal) {
2174  if (access < ma) {
2175  access = ma;
2176  }
2177  qc = mi->getClass();
2178  return mi;
2179  }
2180  }
2181 
2182  return scl ? scl->parseFindMember(mem, qc, access, true) : 0;
2183  }
2184 
2185  DLLLOCAL const QoreVarInfo* parseFindVar(const char* vname, const qore_class_private*& qc, ClassAccess& access, bool toplevel) const {
2186  //printd(5, "parseFindVar() this: %p cls: %p (%s) scl: %p\n", this, cls, cls->getName(), scl);
2187 
2188  QoreVarInfo* vi = vars.find(const_cast<char*>(vname));
2189 
2190  if (vi) {
2191  qc = this;
2192  access = vi->getAccess();
2193  return vi;
2194  }
2195 
2196  return scl ? scl->parseFindVar(vname, qc, access, toplevel) : nullptr;
2197  }
2198 
2199  DLLLOCAL int parseCheckClassHierarchyMembers(const char* mname, const QoreMemberInfo& l_mi, const QoreMemberInfo& b_mi) const;
2200 
2201  DLLLOCAL int checkExistingVarMember(const char* dname, const QoreMemberInfoBaseAccess* mi, const QoreMemberInfoBaseAccess* omi, const qore_class_private* qc, ClassAccess oaccess, bool var = false) const;
2202 
2203  DLLLOCAL int parseCheckVar(const char* dname, const QoreVarInfo* vi) const {
2204  const qore_class_private* qc = 0;
2205  ClassAccess access;
2206  const QoreVarInfo* ovi = parseFindVar(dname, qc, access, true);
2207  //printd(5, "parseCheckVar() %s cls: %p (%s)\n", dname, sclass, sclass ? sclass->getName() : "n/a");
2208  if (!ovi) {
2209  if (parseHasConstant(dname)) {
2210  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());
2211  return -1;
2212  }
2213  return 0;
2214  }
2215 
2216  return checkExistingVarMember(dname, vi, ovi, qc, access, true);
2217  }
2218 
2219  DLLLOCAL int parseCheckMember(const char* mem, const QoreMemberInfo* mi) const {
2220  const qore_class_private* qc = nullptr;
2221  ClassAccess access = Public;
2222  const QoreMemberInfo* omi = parseFindMemberNoInit(mem, qc, access, true);
2223  if (!omi) {
2224  return 0;
2225  }
2226 
2227  return checkExistingVarMember(mem, mi, omi, qc, omi->access);
2228  }
2229 
2230  DLLLOCAL int parseCheckMemberInBaseClasses(const char* mem, const QoreMemberInfo* mi) const {
2231  const qore_class_private* qc = nullptr;
2232  ClassAccess access = Public;
2233  // issue #2970: do not check classes inherited by direct parents with private:internal inheritance
2234  // as these members cannot cause a conflict
2235  const QoreMemberInfo* omi = scl ? scl->parseFindMember(mem, qc, access, false) : nullptr;
2236  if (!omi || (omi->getClass() == mi->getClass())) {
2237  return 0;
2238  }
2239 
2240  return checkExistingVarMember(mem, mi, omi, qc, omi->access);
2241  }
2242 
2243  DLLLOCAL int parseCheckSystemCommitted(const QoreProgramLocation* loc) {
2244  if (sys) {
2245  parse_error(*loc, "cannot modify system class '%s'", name.c_str());
2246  return -1;
2247  }
2248  if (committed) {
2249  parse_error(*loc, "cannot modify user class '%s' once it's been committed", name.c_str());
2250  return -1;
2251  }
2252  return 0;
2253  }
2254 
2255  DLLLOCAL void parseAddMember(char* mem, ClassAccess access, QoreMemberInfo* memberInfo) {
2256  memberInfo->access = access;
2257  if (!parseCheckSystemCommitted(memberInfo->loc) && !parseCheckMember(mem, memberInfo)) {
2258  if (!has_new_user_changes) {
2259  has_new_user_changes = true;
2260  }
2261  if (!has_sig_changes) {
2262  has_sig_changes = true;
2263  }
2264  memberInfo->setDeclaringClass(this);
2265  if (!has_transient_member && memberInfo->getTransient()) {
2266  has_transient_member = true;
2267  }
2268  //printd(5, "qore_class_private::parseAddMember() this: %p %s adding %s %p %s\n", this, name.c_str(), privpub(access), mem, mem);
2269  members.addNoCheck(mem, memberInfo);
2270  return;
2271  }
2272 
2273  free(mem);
2274  delete memberInfo;
2275  }
2276 
2277  DLLLOCAL void parseAddStaticVar(char* dname, ClassAccess access, QoreVarInfo* VarInfo) {
2278  VarInfo->access = access;
2279  if (!parseCheckSystemCommitted(VarInfo->loc) && !parseCheckVar(dname, VarInfo)) {
2280  if (!has_new_user_changes) {
2281  has_new_user_changes = true;
2282  }
2283  if (!has_sig_changes) {
2284  has_sig_changes = true;
2285  }
2286 
2287  //printd(5, "qore_class_private::parseAddStaticVar() this: %p %s adding %p %s\n", this, name.c_str(), mem, mem);
2288  vars.addNoCheck(dname, VarInfo);
2289  return;
2290  }
2291 
2292  free(dname);
2293  delete VarInfo;
2294  }
2295 
2296  DLLLOCAL void addBuiltinConstant(const char* cname, QoreValue value, ClassAccess access = Public, const QoreTypeInfo* cTypeInfo = nullptr) {
2297  assert(!constlist.inList(cname));
2298  if (!sys) {
2299  sys = committed = true;
2300  }
2301  constlist.add(cname, value, cTypeInfo, access);
2302  }
2303 
2304  DLLLOCAL void addBuiltinStaticVar(const char* vname, QoreValue value, ClassAccess access = Public, const QoreTypeInfo* vTypeInfo = nullptr);
2305 
2306  DLLLOCAL void parseAssimilateConstants(ConstantList &cmap, ClassAccess access) {
2307  assert(!sys && !committed);
2308  if (!has_new_user_changes)
2309  has_new_user_changes = true;
2310  if (!has_sig_changes)
2311  has_sig_changes = true;
2312 
2313  // set access if necessary
2314  cmap.setAccess(access);
2315  constlist.assimilate(cmap, "class", name.c_str());
2316  }
2317 
2318  DLLLOCAL void parseAddConstant(const QoreProgramLocation* loc, const std::string &cname, QoreValue val, ClassAccess access) {
2319  ValueHolder val_holder(val, nullptr);
2320  if (parseCheckSystemCommitted(loc)) {
2321  return;
2322  }
2323  if (parseHasVar(cname.c_str())) {
2324  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());
2325  return;
2326  }
2327  if (!has_new_user_changes)
2328  has_new_user_changes = true;
2329  if (!has_sig_changes)
2330  has_sig_changes = true;
2331 
2332  //printd(5, "parseAddConstant() this: %p cls: %p const: %s access: %d\n", this, cls, cname.c_str(), access);
2333 
2334  constlist.parseAdd(loc, cname, val_holder.release(), access, name.c_str());
2335  }
2336 
2337  DLLLOCAL bool parseHasVar(const char* vn) {
2338  return vars.inList(vn);
2339  }
2340 
2341  DLLLOCAL bool parseHasConstant(const std::string &cname) const {
2342  return constlist.inList(cname);
2343  }
2344 
2345  DLLLOCAL QoreValue parseFindLocalConstantValue(const char* cname, const QoreTypeInfo*& cTypeInfo, bool& found) {
2346  parseInitPartial();
2347 
2348  // first check committed constants
2349  ClassAccess access = Public;
2350  QoreValue rv = constlist.find(cname, cTypeInfo, access, found);
2351 
2352  // check for accessibility to private constants
2353  if (found && (access > Public)) {
2354  qore_class_private* class_ctx = parse_get_class_priv();
2355  if ((access == Internal && class_ctx != this) || !parseCheckPrivateClassAccess(class_ctx)) {
2356  rv.clear();
2357  cTypeInfo = nullptr;
2358  found = false;
2359  }
2360  }
2361 
2362  //printd(5, "qore_class_private::parseFindLocalConstantValue(%s) this: %p (cls: %p %s) rv: %p\n", cname, this, cls, name.c_str(), rv);
2363  return rv;
2364  }
2365 
2366  DLLLOCAL QoreValue parseFindConstantValue(const char* cname, const QoreTypeInfo*& cTypeInfo, bool& found, const qore_class_private* class_ctx) {
2367  found = false;
2368  return parseFindConstantValueIntern(cname, cTypeInfo, found, class_ctx);
2369  }
2370 
2371  DLLLOCAL QoreValue parseFindConstantValueIntern(const char* cname, const QoreTypeInfo*& cTypeInfo, bool& found, const qore_class_private* class_ctx) {
2372  parseInitPartial();
2373 
2374  // check constant list
2375  ClassAccess access = Public;
2376  QoreValue rv = constlist.find(cname, cTypeInfo, access, found);
2377 
2378  // check for accessibility to private constants
2379  if (found) {
2380  if (access == Internal) {
2381  if (class_ctx == this)
2382  return rv;
2383  else {
2384  cTypeInfo = nullptr;
2385  found = false;
2386  }
2387  }
2388  else if (access == Private && !parseCheckPrivateClassAccess(class_ctx)) {
2389  cTypeInfo = nullptr;
2390  found = false;
2391  }
2392  else {
2393  return rv;
2394  }
2395  }
2396 
2397  return scl ? scl->parseFindConstantValue(cname, cTypeInfo, found, class_ctx, class_ctx == this) : QoreValue();
2398  }
2399 
2400  DLLLOCAL QoreVarInfo* parseFindLocalStaticVar(const char* vname) const {
2401  QoreVarInfo* vi = vars.find(vname);
2402 
2403  if (vi && (vi->access > Public) && !parseCheckPrivateClassAccess())
2404  vi = nullptr;
2405 
2406  return vi;
2407  }
2408 
2409  DLLLOCAL QoreVarInfo* parseFindStaticVar(const char* vname, const QoreClass*& qc, ClassAccess& access, bool check = false) const {
2410  access = Public;
2411  return parseFindStaticVarIntern(vname, qc, access, check, true);
2412  }
2413 
2414  DLLLOCAL QoreVarInfo* parseFindStaticVarIntern(const char* vname, const QoreClass*& qc, ClassAccess& access, bool check, bool toplevel) const {
2415  QoreVarInfo* vi = vars.find(vname);
2416 
2417  if (vi) {
2418  ClassAccess va = vi->getAccess();
2419  if (toplevel || va != Internal) {
2420  if (access < va) {
2421  access = va;
2422  }
2423 
2424  // return null and stop searching in this class if we should verify access, and the var is not accessible
2425  if (check && (access > Public) && !parseCheckPrivateClassAccess()) {
2426  return nullptr;
2427  }
2428 
2429  qc = cls;
2430  return vi;
2431  }
2432  }
2433 
2434  return scl ? scl->parseFindStaticVar(vname, qc, access, check, toplevel) : nullptr;
2435  }
2436 
2437  DLLLOCAL void addMember(const char* mem, ClassAccess access, const QoreTypeInfo* n_typeinfo, QoreValue initial_value) {
2438  assert(!members.inList(mem));
2439  if (!has_sig_changes) {
2440  has_sig_changes = true;
2441  }
2442  members.addNoCheck(strdup(mem), new QoreMemberInfo(&loc_builtin, n_typeinfo, nullptr, initial_value, access, this));
2443  if (access == Public && !has_public_memdecl) {
2444  has_public_memdecl = true;
2445  }
2446  }
2447 
2448  DLLLOCAL void insertBuiltinStaticMethod(QoreMethod* m) {
2449  assert(m->isStatic());
2450  //printd(5, "QoreClass::insertBuiltinStaticMethod() %s::%s() size: %d\n", name.c_str(), m->getName(), numMethods());
2451  shm[m->getName()] = m;
2452  // maintain method counts (safely inside parse lock)
2453  ++num_static_methods;
2454  if (!sys) {
2455  sys = committed = true;
2456  }
2457  // check for special methods (except constructor and destructor) and abort if found
2458  assert(!checkSpecialStaticIntern(m->getName()));
2459  // add ancestors
2460  addStaticAncestors(m);
2461  }
2462 
2463  DLLLOCAL void insertBuiltinMethod(QoreMethod* m, bool special_method = false) {
2464  assert(!m->isStatic());
2465  //printd(5, "QoreClass::insertBuiltinMethod() %s::%s() size: %d\n", name.c_str(), m->getName(), numMethods());
2466  hm[m->getName()] = m;
2467  // maintain method counts (safely inside parse lock)
2468  ++num_methods;
2469  if (!sys) {
2470  sys = committed = true;
2471  }
2472  // check for special methods (except constructor and destructor)
2473  if (!special_method && !checkAssignSpecialIntern(m))
2474  // add ancestors
2475  addAncestors(m);
2476  }
2477 
2478  DLLLOCAL void recheckBuiltinMethodHierarchy();
2479 
2480  DLLLOCAL void addNewAncestors(QoreMethod* m) {
2481  if (!scl)
2482  return;
2483 
2484  scl->addNewAncestors(m);
2485  }
2486 
2487  DLLLOCAL void addNewStaticAncestors(QoreMethod* m) {
2488  if (!scl)
2489  return;
2490 
2491  scl->addNewStaticAncestors(m);
2492  }
2493 
2494  DLLLOCAL void addStaticAncestors(QoreMethod* m) {
2495  if (!scl)
2496  return;
2497 
2498  scl->addStaticAncestors(m);
2499  }
2500 
2501  DLLLOCAL void addAncestors(QoreMethod* m) {
2502  assert(strcmp(m->getName(), "constructor"));
2503 
2504  if (!scl)
2505  return;
2506 
2507  scl->addAncestors(m);
2508  }
2509 
2510  DLLLOCAL void parseAddStaticAncestors(QoreMethod* m) {
2511  if (!scl)
2512  return;
2513 
2514  scl->parseAddStaticAncestors(m);
2515  }
2516 
2517  DLLLOCAL void parseAddAncestors(QoreMethod* m) {
2518  //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);
2519  assert(strcmp(m->getName(), "constructor"));
2520 
2521  if (!scl)
2522  return;
2523 
2524  scl->parseAddAncestors(m);
2525  }
2526 
2527  DLLLOCAL int initMembers(QoreObject& o, bool& need_scan, ExceptionSink* xsink) const;
2528 
2529  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;
2530 
2531  DLLLOCAL void clearConstants(QoreListNode& l) {
2532  if (const_refs.ROdereference()) {
2533  constlist.clear(l);
2534  }
2535  }
2536 
2537  DLLLOCAL void clearConstants(ExceptionSink* xsink) {
2538  if (const_refs.ROdereference()) {
2539  constlist.deleteAll(xsink);
2540  }
2541  }
2542 
2543  DLLLOCAL void clear(ExceptionSink* xsink) {
2544  //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);
2545 
2546  if (var_refs.ROdereference()) {
2547  // issue #3521: only clear vars here; do not delete
2548  vars.clear(xsink);
2549  }
2550  }
2551 
2552  DLLLOCAL void deleteClassData(bool deref_vars, ExceptionSink* xsink) {
2553  if (deref_vars && var_refs.ROdereference()) {
2554  vars.clear(xsink);
2555  vars.del(xsink);
2556  }
2557  else if (!var_refs.reference_count()) {
2558  // delete vars again if possible
2559  vars.del(xsink);
2560  }
2561 
2562  /*
2563  if (!const_refs.reference_count()) {
2564  constlist.deleteAll(xsink);
2565  }
2566  */
2567  if (spgm) {
2568  if (deref_source_program) {
2569  spgm->deref(xsink);
2570  }
2571  spgm = nullptr;
2572  }
2573  }
2574 
2575  /*
2576  DLLLOCAL int initMembers(QoreObject& o, BCEAList* bceal, ExceptionSink* xsink) const {
2577  if (scl && scl->initMembers(o, bceal, xsink))
2578  return -1;
2579 
2580  if (members.empty())
2581  return 0;
2582 
2583  // ensure class is only initialized once
2584  if (bceal && bceal->initMembers(cls->getID()))
2585  return 0;
2586 
2587  SelfInstantiatorHelper sih(&selfid, &o, xsink);
2588 
2589  if (initMembers(o, members.begin(), members.end(), xsink))
2590  return -1;
2591  return 0;
2592  }
2593  */
2594 
2595  DLLLOCAL const QoreMethod* getMethodForEval(const char* nme, QoreProgram* pgm,
2596  const qore_class_private* class_ctx, ExceptionSink* xsink) const;
2597 
2598  DLLLOCAL QoreObject* execConstructor(const AbstractQoreFunctionVariant* variant, const QoreListNode* args, ExceptionSink* xsink) const;
2599 
2600  DLLLOCAL void addBuiltinMethod(const char* mname, MethodVariantBase* variant);
2601  DLLLOCAL void addBuiltinStaticMethod(const char* mname, MethodVariantBase* variant);
2602  DLLLOCAL void addBuiltinConstructor(BuiltinConstructorVariantBase* variant);
2603  DLLLOCAL void addBuiltinDestructor(BuiltinDestructorVariantBase* variant);
2604  DLLLOCAL void addBuiltinCopyMethod(BuiltinCopyVariantBase* variant);
2605  DLLLOCAL void setDeleteBlocker(q_delete_blocker_t func);
2606  DLLLOCAL void setBuiltinSystemConstructor(BuiltinSystemConstructorBase* m);
2607 
2608  DLLLOCAL void execBaseClassConstructor(QoreObject* self, BCEAList* bceal, ExceptionSink* xsink) const;
2609  DLLLOCAL QoreObject* execSystemConstructor(QoreObject* self, int code, va_list args) const;
2610  DLLLOCAL bool execDeleteBlocker(QoreObject* self, ExceptionSink* xsink) const;
2611  DLLLOCAL QoreObject* execCopy(QoreObject* old, ExceptionSink* xsink) const;
2612 
2613  // returns a non-static method if it exists in the local class
2614  DLLLOCAL QoreMethod* parseFindLocalMethod(const char* nme) {
2615  hm_method_t::iterator i = hm.find(nme);
2616  return (i != hm.end()) ? i->second : nullptr;
2617  }
2618  // returns a non-static method if it exists in the local class
2619  DLLLOCAL const QoreMethod* parseFindLocalMethod(const char* nme) const {
2620  hm_method_t::const_iterator i = hm.find(nme);
2621  return (i != hm.end()) ? i->second : nullptr;
2622  }
2623 
2624  DLLLOCAL QoreMethod* parseFindLocalMethod(const std::string& nme) {
2625  hm_method_t::iterator i = hm.find(nme);
2626  return (i != hm.end()) ? i->second : nullptr;
2627  }
2628  // returns a non-static method if it exists in the local class
2629  DLLLOCAL const QoreMethod* parseFindLocalMethod(const std::string& nme) const {
2630  hm_method_t::const_iterator i = hm.find(nme);
2631  return (i != hm.end()) ? i->second : nullptr;
2632  }
2633 
2634  // returns any method if it exists in the local class
2635  DLLLOCAL const QoreMethod* parseFindAnyLocalMethod(const char* nme) const {
2636  const QoreMethod* m = parseFindLocalMethod(nme);
2637  return m ? m : parseFindLocalStaticMethod(nme);
2638  }
2639 
2640  // returns a static method if it exists in the local class
2641  DLLLOCAL QoreMethod* parseFindLocalStaticMethod(const char* nme) {
2642  hm_method_t::iterator i = shm.find(nme);
2643  return (i != shm.end()) ? i->second : nullptr;
2644  }
2645  // returns a static method if it exists in the local class
2646  DLLLOCAL const QoreMethod* parseFindLocalStaticMethod(const char* nme) const {
2647  hm_method_t::const_iterator i = shm.find(nme);
2648  return (i != shm.end()) ? i->second : nullptr;
2649  }
2650 
2651  // returns a non-static method if it exists in the local class and has been committed to the class
2652  DLLLOCAL QoreMethod* findLocalCommittedMethod(const char* nme);
2653  // returns a non-static method if it exists in the local class and has been committed to the class
2654  DLLLOCAL const QoreMethod* findLocalCommittedMethod(const char* nme) const;
2655 
2656  // returns a static method if it exists in the local class and has been committed to the class
2657  DLLLOCAL QoreMethod* findLocalCommittedStaticMethod(const char* nme);
2658  // returns a static method if it exists in the local class and has been committed to the class
2659  DLLLOCAL const QoreMethod* findLocalCommittedStaticMethod(const char* nme) const;
2660 
2661  DLLLOCAL void finalizeBuiltin(const char* nspath);
2662  DLLLOCAL void generateBuiltinSignature(const char* nspath);
2663  DLLLOCAL void initializeBuiltin();
2664 
2665  DLLLOCAL QoreValue evalMethod(QoreObject* self, const char* nme, const QoreListNode* args, const qore_class_private* class_ctx, ExceptionSink* xsink) const;
2666 
2667  DLLLOCAL QoreValue evalMethodGate(QoreObject* self, const char* nme, const QoreListNode* args, ExceptionSink* xsink) const;
2668 
2669  DLLLOCAL static const QoreMethod* doParseMethodAccess(const QoreMethod* m, const qore_class_private* class_ctx);
2670 
2671  DLLLOCAL static const QoreMethod* doMethodAccess(const QoreMethod* m, ClassAccess ma, const qore_class_private* class_ctx) {
2672  assert(m);
2673  return ((ma == Public) || ((ma == Private && class_ctx))) ? m : nullptr;
2674  }
2675 
2676  DLLLOCAL static const QoreMethod* doMethodAccess(const QoreMethod* m, ClassAccess& access, ClassAccess ma) {
2677  assert(m);
2678 
2679  if (ma == Internal)
2680  m = nullptr;
2681  else if (access < ma)
2682  access = ma;
2683 
2684  return m;
2685  }
2686 
2687  DLLLOCAL const QoreMethod* doRuntimeMethodAccess(const QoreMethod* m, ClassAccess& access, ClassAccess ma, const qore_class_private* class_ctx) const {
2688  assert(m);
2689 
2690  if (ma == Internal && (!class_ctx || !equal(*class_ctx)))
2691  m = nullptr;
2692  else if (access < ma)
2693  access = ma;
2694 
2695  return m;
2696  }
2697 
2698  // performs class initialization; find a static method in the class hierarchy at parse time; inaccessible methods are ignored
2699  DLLLOCAL const QoreMethod* parseFindNormalMethod(const char* mname, const qore_class_private* class_ctx);
2700 
2701  // performs class initialization; find a static method in the class hierarchy at parse time; inaccessible methods are ignored
2702  DLLLOCAL const QoreMethod* parseFindStaticMethod(const char* mname, const qore_class_private* class_ctx);
2703 
2704  // performs class initialization; finds a non-static method in the class hierarchy at parse time, optionally initializes classes
2705  DLLLOCAL const QoreMethod* parseFindNormalMethodIntern(const char* mname, const qore_class_private* class_ctx);
2706 
2707  // performs class initialization; finds a static method in the class hierarchy at parse time, optionally initializes classes
2708  DLLLOCAL const QoreMethod* parseFindStaticMethodIntern(const char* mname, const qore_class_private* class_ctx);
2709 
2710  DLLLOCAL const QoreMethod* parseResolveSelfMethodIntern(const QoreProgramLocation* loc, const char* nme, const qore_class_private* class_ctx);
2711 
2712  // returns a non-static method if it exists in class hierarchy and has been committed to the class
2713  // class_ctx is only set if it is present and accessible, so we only need to check for internal access here
2714  DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethodIntern(const char* nme, ClassAccess& access, const qore_class_private* class_ctx) const {
2715  const QoreMethod* m = findLocalCommittedStaticMethod(nme);
2716  if (m &&
2717  (class_ctx == this || doRuntimeMethodAccess(m, access, m->getAccess(), class_ctx))) {
2718  return m;
2719  }
2720  if (!scl) {
2721  return nullptr;
2722  }
2723  // access already checked in subclasses, do not need to check again
2724  return scl->runtimeFindCommittedStaticMethod(nme, access, class_ctx, class_ctx == this);
2725  }
2726 
2727  // returns a non-static method if it exists in class hierarchy and has been committed to the class
2728  // class_ctx is only set if it is present and accessible, so we only need to check for internal access here
2729  DLLLOCAL const QoreMethod* runtimeFindCommittedMethodIntern(const char* nme, ClassAccess& access, const qore_class_private* class_ctx) const {
2730  const QoreMethod* m = findLocalCommittedMethod(nme);
2731  //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);
2732  if (m &&
2733  (class_ctx == this || doRuntimeMethodAccess(m, access, m->getAccess(), class_ctx))) {
2734  return m;
2735  }
2736  if (!scl) {
2737  return nullptr;
2738  }
2739  // access already checked in subclasses, do not need to check again
2740  return scl->runtimeFindCommittedMethod(nme, access, class_ctx, class_ctx == this);
2741  }
2742 
2743  DLLLOCAL const QoreMethod* runtimeFindCommittedStaticMethod(const char* nme, ClassAccess& access,
2744  const qore_class_private* class_ctx) const;
2745 
2746  DLLLOCAL const QoreMethod* runtimeFindCommittedMethod(const char* nme, ClassAccess& access,
2747  const qore_class_private* class_ctx) const;
2748 
2749  DLLLOCAL const QoreMethod* runtimeFindCommittedMethodForEval(const char* nme, ClassAccess& access,
2750  const qore_class_private* class_ctx) const;
2751 
2752  DLLLOCAL const QoreMethod* runtimeFindAnyCommittedMethod(const char* nme) const {
2753  ClassAccess access = Public;
2754  const qore_class_private* class_ctx = this;
2755  const QoreMethod* m = runtimeFindCommittedMethodIntern(nme, access, class_ctx);
2756  if (!m) {
2757  // check for special methods
2758  if (!strcmp(nme, "constructor"))
2759  return constructor;
2760  if (!strcmp(nme, "destructor"))
2761  return destructor;
2762  if (!strcmp(nme, "copy"))
2763  return copyMethod;
2764  if (!strcmp(nme, "methodGate"))
2765  return copyMethod;
2766  if (!strcmp(nme, "memberGate"))
2767  return memberGate;
2768  if (!strcmp(nme, "memberNotification"))
2769  return memberNotification;
2770  }
2771  return m;
2772  }
2773 
2774  DLLLOCAL const QoreMethod* findMethod(const char* nme, ClassAccess& access) const {
2775  CurrentProgramRuntimeParseContextHelper pch;
2776  const qore_class_private* class_ctx = runtime_get_class();
2777  if (class_ctx && !runtimeCheckPrivateClassAccess(class_ctx))
2778  class_ctx = nullptr;
2779  return runtimeFindCommittedMethod(nme, access, class_ctx);
2780  }
2781 
2782  DLLLOCAL bool runtimeHasCallableMethod(const char* m, int mask) const;
2783 
2784  DLLLOCAL void execDestructor(QoreObject* self, ExceptionSink* xsink) const;
2785 
2786  DLLLOCAL void execBaseClassDestructor(QoreObject* self, ExceptionSink* xsink) const;
2787 
2788  DLLLOCAL void execBaseClassSystemDestructor(QoreObject* self, ExceptionSink* xsink) const;
2789 
2790  DLLLOCAL void execBaseClassCopy(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const;
2791 
2792  DLLLOCAL void parseInit();
2793  DLLLOCAL void parseResolveHierarchy();
2794  DLLLOCAL void parseResolveClassMembers();
2795  DLLLOCAL void parseResolveAbstract();
2796  DLLLOCAL void parseCommit();
2797  DLLLOCAL void parseCommitRuntimeInit(ExceptionSink* xsink);
2798  DLLLOCAL void parseRollback();
2799  DLLLOCAL int addUserMethod(const char* mname, MethodVariantBase* f, bool n_static);
2800  DLLLOCAL void addLocalMembersForInit();
2801 
2802  DLLLOCAL QoreValue evalPseudoMethod(const QoreValue n, const char* name, const QoreListNode* args, ExceptionSink* xsink) const;
2803 
2804  DLLLOCAL QoreValue evalPseudoMethod(const QoreMethod* m, const AbstractQoreFunctionVariant* variant, const QoreValue n, const QoreListNode* args, ExceptionSink* xsink) const;
2805 
2806  DLLLOCAL const QoreMethod* runtimeFindPseudoMethod(const QoreValue n, const char* nme, ExceptionSink* xsink) const {
2807  const QoreMethod* w;
2808 
2809  const qore_class_private* class_ctx = runtime_get_class();
2810  if (class_ctx && !runtimeCheckPrivateClassAccess(class_ctx))
2811  class_ctx = nullptr;
2812  ClassAccess access;
2813  if (!(w = runtimeFindCommittedMethod(nme, access, class_ctx))) {
2814  qore_type_t t = n.getType();
2815  // throw an exception
2816  if (t == NT_OBJECT) {
2817  const char* cname = n.get<const QoreObject>()->getClassName();
2818  xsink->raiseException("METHOD-DOES-NOT-EXIST", "no method %s::%s() or pseudo-method %s::%s() is available", cname, nme, name.c_str(), nme);
2819  }
2820  else
2821  xsink->raiseException("PSEUDO-METHOD-DOES-NOT-EXIST", "no pseudo method <%s>::%s() has been defined", n.getTypeName(), nme);
2822  return nullptr;
2823  }
2824 
2825  return w;
2826  }
2827 
2828  DLLLOCAL bool parseCheckPrivateClassAccess(const qore_class_private* qc = parse_get_class_priv()) const;
2829  DLLLOCAL bool runtimeCheckPrivateClassAccess(const qore_class_private* qc = runtime_get_class()) const;
2830 
2831  // this = class to find in "oc"
2832  DLLLOCAL qore_type_result_e parseCheckCompatibleClass(const qore_class_private& oc) const {
2833  bool may_not_match = false;
2834  qore_type_result_e rv = parseCheckCompatibleClass(oc, may_not_match);
2835  // if the type may not match at runtime, then return no match with %strict-types
2836  if (may_not_match && (getProgram()->getParseOptions64() & PO_STRICT_TYPES)) {
2837  return QTI_NOT_EQUAL;
2838  }
2839  return rv;
2840  }
2841  DLLLOCAL qore_type_result_e parseCheckCompatibleClass(const qore_class_private& oc, bool& may_not_match) const;
2842  DLLLOCAL qore_type_result_e parseCheckCompatibleClassIntern(const qore_class_private& oc, bool& may_not_match) const;
2843  // this = class to find in "oc"
2844  DLLLOCAL qore_type_result_e runtimeCheckCompatibleClass(const qore_class_private& oc) const;
2845  DLLLOCAL qore_type_result_e runtimeCheckCompatibleClassIntern(const qore_class_private& oc) const;
2846 
2847  // find the given class anywhere in the hierarchy regardless of access permissions or location
2848  DLLLOCAL const QoreClass* findInHierarchy(const qore_class_private& qc) {
2849  if (equal(qc))
2850  return cls;
2851  return scl ? scl->findInHierarchy(qc) : nullptr;
2852  }
2853 
2854  DLLLOCAL const QoreClass* getClassIntern(qore_classid_t cid, ClassAccess& n_access, bool toplevel) const {
2855  if (cid == classID)
2856  return cls;
2857  return scl ? scl->getClass(cid, n_access, toplevel) : nullptr;
2858  }
2859 
2860  DLLLOCAL const QoreClass* getClass(const qore_class_private& qc, ClassAccess& n_access) const {
2861  n_access = Public;
2862  return getClassIntern(qc, n_access, true);
2863  }
2864 
2865  DLLLOCAL const QoreClass* getClassIntern(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const {
2866  if (equal(qc))
2867  return cls;
2868 
2869 #ifdef DEBUG_1
2870  if (qc.name == name) {
2871  QoreString lh, rh;
2872  hash.toString(lh);
2873  qc.hash.toString(rh);
2874  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());
2875  }
2876 #endif
2877 
2878  return scl ? scl->getClass(qc, n_access, toplevel) : nullptr;
2879  }
2880 
2881  DLLLOCAL const QoreClass* parseGetClassIntern(const qore_class_private& qc, ClassAccess& n_access, bool toplevel) const {
2882  // check hashes if names are the same
2883  // FIXME: check fully-qualified namespace name
2884  if (parseEqual(qc))
2885  return cls;
2886 
2887 #ifdef DEBUG_SKIP
2888  if (qc.name == name) {
2889  printd(5, "qore_class_private::parseGetClassIntern() this: %p '%s' != '%s' scl: %p\n", this, name.c_str(), qc.name.c_str(), scl);
2890  parseShowHashes();
2891  qc.parseShowHashes();
2892  }
2893 #endif
2894 
2895  return scl ? scl->parseGetClass(qc, n_access, toplevel) : nullptr;
2896  }
2897 
2898  DLLLOCAL bool inHierarchy(const qore_class_private& qc, ClassAccess& n_access) const {
2899  if (equal(qc)) {
2900  return cls;
2901  }
2902 
2903  return scl ? scl->inHierarchy(qc, n_access) : false;
2904  }
2905 
2906 #ifdef DEBUG_SKIP
2907  DLLLOCAL void parseShowHash() const {
2908  QoreString ch, ph;
2909  hash.toString(ch);
2910  printd(5, " + %p %s committed: %s\n", this, name.c_str(), ch.getBuffer());
2911  }
2912 #endif
2913 
2914  DLLLOCAL bool parseCheckEqualHash(const qore_class_private& qc) const {
2915 #ifdef DEBUG_SKIP
2916  printd(5, "qore_class_private::parseCheckEqualHash() %s == %s\n", name.c_str(), qc.name.c_str());
2917  parseShowHash();
2918  qc.parseShowHash();
2919 #endif
2920  return hash == qc.hash;
2921  }
2922 
2923  DLLLOCAL bool equal(const qore_class_private& qc) const {
2924  if (&qc == this)
2925  return true;
2926 
2927  if (qc.classID == classID || (qc.name == name && qc.hash == hash))
2928  return true;
2929 
2930  if (injectedClass && injectedClass->equal(qc))
2931  return true;
2932 
2933  if (qc.injectedClass && equal(*qc.injectedClass))
2934  return true;
2935 
2936  return false;
2937  }
2938 
2939  DLLLOCAL bool parseEqual(const qore_class_private& qc) const {
2940  if (&qc == this)
2941  return true;
2942 
2943  if (qc.classID == classID || (qc.name == name && parseCheckEqualHash(qc)))
2944  return true;
2945 
2946  if (injectedClass && injectedClass->parseEqual(qc))
2947  return true;
2948 
2949  if (qc.injectedClass && parseEqual(*qc.injectedClass))
2950  return true;
2951 
2952  return false;
2953  }
2954 
2955  DLLLOCAL const QoreClass* parseGetClass(const qore_class_private& qc, ClassAccess& n_access) const;
2956 
2957  DLLLOCAL int addBaseClassesToSubclass(QoreClass* sc, bool is_virtual);
2958 
2959  DLLLOCAL void setPublic();
2960 
2961  DLLLOCAL void parseSetBaseClassList(BCList* bcl) {
2962  assert(!scl);
2963  if (bcl) {
2964  scl = bcl;
2965  if (!has_new_user_changes)
2966  has_new_user_changes = true;
2967  if (!has_sig_changes)
2968  has_sig_changes = true;
2969  }
2970  }
2971 
2972  DLLLOCAL bool parseHasPendingChanges() const {
2973  return has_new_user_changes;
2974  }
2975 
2976  DLLLOCAL bool parseCheckHierarchy(const QoreClass* n_cls, ClassAccess& access) const {
2977  access = Public;
2978  return parseCheckHierarchyIntern(n_cls, access, true);
2979  }
2980 
2981  DLLLOCAL bool parseCheckHierarchyIntern(const QoreClass* n_cls, ClassAccess& access, bool toplevel) const {
2982  if (parseEqual(*n_cls->priv))
2983  return true;
2984 
2985  return scl ? scl->parseCheckHierarchy(n_cls, access, toplevel) : false;
2986  }
2987 
2988  DLLLOCAL VRMutex* getGate() const {
2989  return &gate;
2990  }
2991 
2992  // class initialization; inaccessible methods are ignored
2993  DLLLOCAL const QoreMethod* parseFindAnyMethod(const char* nme, const qore_class_private* class_ctx);
2994 
2995  // class initialization; inaccessible methods are ignored
2996  DLLLOCAL const QoreMethod* parseFindAnyMethodStaticFirst(const char* nme, const qore_class_private* class_ctx);
2997 
2998  // class initialization
2999  DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, const char* nme, const qore_class_private* class_ctx);
3000  DLLLOCAL const QoreMethod* parseResolveSelfMethod(const QoreProgramLocation* loc, NamedScope* nme);
3001 
3002  // class initialization
3003  DLLLOCAL const QoreMethod* parseFindSelfMethod(const char* nme);
3004 
3005  DLLLOCAL char* getHash() const {
3006  return hash.getHash();
3007  }
3008 
3009  DLLLOCAL void setSerializer(q_serializer_t m) {
3010  assert(!serializer);
3011  serializer = m;
3012  }
3013 
3014  DLLLOCAL void setDeserializer(q_deserializer_t m) {
3015  assert(!deserializer);
3016  deserializer = m;
3017  }
3018 
3019  // static methods
3020  //DLLLOCAL static
3021 
3022  DLLLOCAL static char* getHash(const QoreClass& qc) {
3023  return qc.priv->getHash();
3024  }
3025 
3026  DLLLOCAL static void parseAddConstant(QoreClass& qc, const QoreProgramLocation* loc, const std::string &cname, QoreValue val, ClassAccess access) {
3027  qc.priv->parseAddConstant(loc, cname, val, access);
3028  }
3029 
3030  DLLLOCAL static LocalVar* getSelfId(const QoreClass& qc) {
3031  return &qc.priv->selfid;
3032  }
3033 
3034  DLLLOCAL static QoreObject* execConstructor(const QoreClass& qc, const AbstractQoreFunctionVariant* variant, const QoreListNode* args, ExceptionSink* xsink) {
3035  return qc.priv->execConstructor(variant, args, xsink);
3036  }
3037 
3038  DLLLOCAL static bool injected(const QoreClass& qc) {
3039  return qc.priv->inject;
3040  }
3041 
3042  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) {
3043  qore_class_private* priv = new qore_class_private(*qc.priv, ns, spgm, nme, inject, injectedClass, set_pub);
3044  //printd(5, "qore_program_private::makeImportClass() name: '%s' as '%s' inject: %d rv: %p\n", qc.getName(), priv->name.c_str(), inject, priv->cls);
3045  return priv->cls;
3046  }
3047 
3048  DLLLOCAL static const QoreMethod* runtimeFindCommittedStaticMethod(const QoreClass& qc, const char* nme, ClassAccess& access, const qore_class_private* class_ctx) {
3049  return qc.priv->runtimeFindCommittedStaticMethod(nme, access, class_ctx);
3050  }
3051 
3052  DLLLOCAL static const QoreMethod* parseFindLocalMethod(const QoreClass& qc, const char* mname) {
3053  return qc.priv->parseFindLocalMethod(mname);
3054  }
3055 
3056  DLLLOCAL static bool parseHasPendingChanges(const QoreClass& qc) {
3057  return qc.priv->parseHasPendingChanges();
3058  }
3059 
3060  DLLLOCAL static int parseCheckMemberAccess(const QoreClass& qc, const QoreProgramLocation* loc, const char* mem, const QoreTypeInfo*& memberTypeInfo, int pflag) {
3061  return qc.priv->parseCheckMemberAccess(loc, mem, memberTypeInfo, pflag);
3062  }
3063 
3064  DLLLOCAL static bool runtimeHasCallableMethod(const QoreClass& qc, const char* m) {
3065  return qc.priv->runtimeHasCallableMethod(m, QCCM_NORMAL | QCCM_STATIC);
3066  }
3067 
3068  DLLLOCAL static bool runtimeHasCallableNormalMethod(const QoreClass& qc, const char* m) {
3069  return qc.priv->runtimeHasCallableMethod(m, QCCM_NORMAL);
3070  }
3071 
3072  DLLLOCAL static bool runtimeHasCallableStaticMethod(const QoreClass& qc, const char* m) {
3073  return qc.priv->runtimeHasCallableMethod(m, QCCM_STATIC);
3074  }
3075 
3076  DLLLOCAL static int runtimeCheckInstantiateClass(const QoreClass& qc, ExceptionSink* xsink) {
3077  return qc.priv->runtimeCheckInstantiateClass(xsink);
3078  }
3079 
3080  DLLLOCAL static void parseInit(QoreClass& qc) {
3081  qc.priv->parseInit();
3082  }
3083 
3084  DLLLOCAL static void parseInitPartial(QoreClass& qc) {
3085  qc.priv->parseInitPartial();
3086  }
3087 
3088  DLLLOCAL static void parseCommit(QoreClass& qc) {
3089  qc.priv->parseCommit();
3090  }
3091 
3092  DLLLOCAL static void parseCommitRuntimeInit(QoreClass& qc, ExceptionSink* xsink) {
3093  qc.priv->parseCommitRuntimeInit(xsink);
3094  }
3095 
3096  DLLLOCAL static void parseRollback(QoreClass& qc) {
3097  qc.priv->parseRollback();
3098  }
3099 
3100  DLLLOCAL static void resolveCopy(QoreClass& qc) {
3101  qc.priv->resolveCopy();
3102  }
3103 
3104  DLLLOCAL static int addUserMethod(QoreClass& qc, const char* mname, MethodVariantBase* f, bool n_static) {
3105  return qc.priv->addUserMethod(mname, f, n_static);
3106  }
3107 
3108  DLLLOCAL static void initialize(QoreClass& qc) {
3109  qc.priv->initialize();
3110  }
3111 
3112  DLLLOCAL static void parseSetBaseClassList(QoreClass& qc, BCList* bcl) {
3113  qc.priv->parseSetBaseClassList(bcl);
3114  }
3115 
3116  DLLLOCAL static BCList* getBaseClassList(const QoreClass& qc) {
3117  return qc.priv->scl;
3118  }
3119 
3120  DLLLOCAL static void parseAddStaticVar(QoreClass* qc, char* dname, ClassAccess access, QoreVarInfo* VarInfo) {
3121  qc->priv->parseAddStaticVar(dname, access, VarInfo);
3122  }
3123 
3124  // searches only the current class, returns 0 if private found and not accessible in the current parse context
3125  DLLLOCAL static QoreValue parseFindLocalConstantValue(QoreClass* qc, const char* cname, const QoreTypeInfo*& typeInfo, bool& found) {
3126  return qc->priv->parseFindLocalConstantValue(cname, typeInfo, found);
3127  }
3128 
3129  // searches only the current class, returns 0 if private found and not accessible in the current parse context
3130  DLLLOCAL static QoreVarInfo* parseFindLocalStaticVar(const QoreClass* qc, const char* vname) {
3131  return qc->priv->parseFindLocalStaticVar(vname);
3132  }
3133 
3134  // searches this class and all superclasses
3135  DLLLOCAL static QoreValue parseFindConstantValue(QoreClass* qc, const char* cname, const QoreTypeInfo*& typeInfo, bool& found, const qore_class_private* class_ctx) {
3136  return qc->priv->parseFindConstantValue(cname, typeInfo, found, class_ctx);
3137  }
3138 
3139  // searches this class and all superclasses, if check = false, then assumes parsing from within the class (parse_get_class() == this class)
3140  DLLLOCAL static QoreVarInfo* parseFindStaticVar(const QoreClass* qc, const char* vname, const QoreClass*& nqc, ClassAccess& access, bool check = false) {
3141  return qc->priv->parseFindStaticVar(vname, nqc, access, check);
3142  }
3143 
3144  DLLLOCAL static int parseCheckInternalMemberAccess(const QoreClass* qc, const char* mem, const QoreTypeInfo*& memberTypeInfo, const QoreProgramLocation* loc) {
3145  return qc->priv->parseCheckInternalMemberAccess(mem, memberTypeInfo, loc);
3146  }
3147 
3148  DLLLOCAL static int parseResolveInternalMemberAccess(const QoreClass* qc, const char* mem, const QoreTypeInfo*& memberTypeInfo) {
3149  return qc->priv->parseResolveInternalMemberAccess(mem, memberTypeInfo);
3150  }
3151 
3152  DLLLOCAL static const QoreMethod* parseFindSelfMethod(QoreClass* qc, const char* mname) {
3153  return qc->priv->parseFindSelfMethod(mname);
3154  }
3155 
3156  DLLLOCAL static void parseAddMember(QoreClass& qc, char* nme, ClassAccess access, QoreMemberInfo* mInfo) {
3157  qc.priv->parseAddMember(nme, access, mInfo);
3158  }
3159 
3160  DLLLOCAL static QoreValue evalPseudoMethod(const QoreClass* qc, const QoreValue n, const char* name, const QoreListNode* args, ExceptionSink* xsink) {
3161  return qc->priv->evalPseudoMethod(n, name, args, xsink);
3162  }
3163 
3164  DLLLOCAL static QoreValue evalPseudoMethod(const QoreClass* qc, const QoreMethod* m, const AbstractQoreFunctionVariant* variant, const QoreValue n, const QoreListNode* args, ExceptionSink* xsink) {
3165  return qc->priv->evalPseudoMethod(m, variant, n, args, xsink);
3166  }
3167 
3168  DLLLOCAL static bool parseCheckPrivateClassAccess(const QoreClass& qc, const qore_class_private* oqc = parse_get_class_priv()) {
3169  return qc.priv->parseCheckPrivateClassAccess(oqc);
3170  }
3171 
3172  DLLLOCAL static bool runtimeCheckPrivateClassAccess(const QoreClass& qc, const qore_class_private* oqc = runtime_get_class()) {
3173  return qc.priv->runtimeCheckPrivateClassAccess(oqc);
3174  }
3175 
3176  DLLLOCAL static qore_type_result_e parseCheckCompatibleClass(const QoreClass* qc, const QoreClass* oc) {
3177  if (!oc)
3178  return QTI_NOT_EQUAL;
3179  return qc->priv->parseCheckCompatibleClass(*(oc->priv));
3180  }
3181 
3182  DLLLOCAL static qore_type_result_e runtimeCheckCompatibleClass(const QoreClass& qc, const QoreClass& oc) {
3183  return qc.priv->runtimeCheckCompatibleClass(*oc.priv);
3184  }
3185 
3186  DLLLOCAL static qore_class_private* get(QoreClass& qc) {
3187  return qc.priv;
3188  }
3189 
3190  DLLLOCAL static const qore_class_private* get(const QoreClass& qc) {
3191  return qc.priv;
3192  }
3193 
3194  DLLLOCAL static bool isPublic(const QoreClass& qc) {
3195  return qc.priv->pub;
3196  }
3197 
3198  DLLLOCAL static bool isUserPublic(const QoreClass& qc) {
3199  return qc.priv->pub && !qc.priv->sys;
3200  }
3201 
3202  DLLLOCAL static bool isFinal(const QoreClass& qc) {
3203  return qc.priv->final;
3204  }
3205 
3206  DLLLOCAL static void setPublic(QoreClass& qc) {
3207  qc.priv->setPublic();
3208  }
3209 
3210  DLLLOCAL static void setFinal(QoreClass& qc) {
3211  assert(!qc.priv->final);
3212  qc.priv->final = true;
3213  }
3214 
3215 protected:
3216  DLLLOCAL ~qore_class_private();
3217 };
3218 
3219 class qore_class_private_holder {
3220  qore_class_private* c;
3221 
3222 public:
3223  DLLLOCAL qore_class_private_holder(QoreClass* n_c) : c(qore_class_private::get(*n_c)) {
3224  }
3225 
3226  DLLLOCAL qore_class_private_holder(qore_class_private* n_c) : c(n_c) {
3227  }
3228 
3229  DLLLOCAL ~qore_class_private_holder() {
3230  if (c) {
3231  c->deref(true, true);
3232  }
3233  }
3234 
3235  DLLLOCAL qore_class_private* operator*() {
3236  return c;
3237  }
3238 
3239  DLLLOCAL QoreClass* release() {
3240  if (c) {
3241  QoreClass* rv = c->cls;
3242  c = nullptr;
3243  return rv;
3244  }
3245  return nullptr;
3246  }
3247 };
3248 
3249 class qore_method_private {
3250 public:
3251  const QoreClass* parent_class;
3252  MethodFunctionBase* func;
3253  bool static_flag, all_user;
3254 
3255  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) {
3256  assert(parent_class == n_func->getClass());
3257  }
3258 
3259  DLLLOCAL ~qore_method_private() {
3260  func->deref();
3261  }
3262 
3263  DLLLOCAL void setBuiltin() {
3264  if (all_user)
3265  all_user = false;
3266  }
3267 
3268  DLLLOCAL bool isUniquelyUser() const {
3269  return all_user;
3270  }
3271 
3272  DLLLOCAL bool isAbstract() const {
3273  return func->isAbstract();
3274  }
3275 
3276  DLLLOCAL int addUserVariant(MethodVariantBase* variant) {
3277  return func->parseAddUserMethodVariant(variant);
3278  }
3279 
3280  DLLLOCAL void addBuiltinVariant(MethodVariantBase* variant) {
3281  setBuiltin();
3282  func->addBuiltinMethodVariant(variant);
3283  }
3284 
3285  DLLLOCAL MethodFunctionBase* getFunction() const {
3286  return const_cast<MethodFunctionBase* >(func);
3287  }
3288 
3289  DLLLOCAL const char* getName() const {
3290  return func->getName();
3291  }
3292 
3293  DLLLOCAL const std::string& getNameStr() const {
3294  return func->getNameStr();
3295  }
3296 
3297  DLLLOCAL void parseInit();
3298 
3299  DLLLOCAL void parseInitStatic() {
3300  assert(static_flag);
3301  func->parseInit();
3302  // make sure the method doesn't override a "final" method in a base class
3303  func->checkFinal();
3304  }
3305 
3306  DLLLOCAL const QoreTypeInfo* getUniqueReturnTypeInfo() const {
3307  return func->getUniqueReturnTypeInfo();
3308  }
3309 
3310  DLLLOCAL void evalConstructor(const AbstractQoreFunctionVariant* variant, QoreObject* self, const QoreListNode* args, BCEAList* bceal, ExceptionSink* xsink) {
3311  CONMF(func)->evalConstructor(variant, *parent_class, self, args, parent_class->priv->scl, bceal, xsink);
3312  }
3313 
3314  DLLLOCAL void evalCopy(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const {
3315  COPYMF(func)->evalCopy(*parent_class, self, old, parent_class->priv->scl, xsink);
3316  }
3317 
3318  DLLLOCAL void evalBaseClassCopy(QoreObject* self, QoreObject* old, ExceptionSink* xsink) const {
3319  COPYMF(func)->evalCopy(*parent_class, self, old, nullptr, xsink);
3320  }
3321 
3322  DLLLOCAL bool evalDeleteBlocker(QoreObject* self) const {
3323  // can only be builtin
3324  return self->evalDeleteBlocker(parent_class->priv->methodID, reinterpret_cast<BuiltinDeleteBlocker*>(func));
3325  }
3326 
3327  DLLLOCAL void evalDestructor(QoreObject* self, ExceptionSink* xsink) const {
3328  DESMF(func)->evalDestructor(*parent_class, self, xsink);
3329  }
3330 
3331  DLLLOCAL void evalSystemDestructor(QoreObject* self, ExceptionSink* xsink) const {
3332  // execute function directly
3333  DESMF(func)->evalDestructor(*parent_class, self, xsink);
3334  }
3335 
3336  DLLLOCAL void evalSystemConstructor(QoreObject* self, int code, va_list args) const {
3337  BSYSCONB(func)->eval(*parent_class, self, code, args);
3338  }
3339 
3340  DLLLOCAL QoreValue eval(ExceptionSink* xsink, QoreObject* self, const QoreListNode* args, const qore_class_private* cctx = nullptr) const {
3341  if (!static_flag) {
3342  assert(self);
3343  return NMETHF(func)->evalMethod(xsink, 0, self, args, cctx);
3344  }
3345  return SMETHF(func)->evalMethod(xsink, 0, args, cctx);
3346  }
3347 
3348  DLLLOCAL QoreValue evalTmpArgs(ExceptionSink* xsink, QoreObject* self, QoreListNode* args, const qore_class_private* cctx = nullptr) const {
3349  if (!static_flag) {
3350  assert(self);
3351  return NMETHF(func)->evalMethodTmpArgs(xsink, nullptr, self, args, cctx);
3352  }
3353  return SMETHF(func)->evalMethodTmpArgs(xsink, nullptr, args, cctx);
3354  }
3355 
3356  DLLLOCAL QoreValue evalPseudoMethod(const AbstractQoreFunctionVariant* variant, const QoreValue n, const QoreListNode* args, ExceptionSink* xsink) const {
3357  QORE_TRACE("qore_method_private::evalPseudoMethod()");
3358 
3359  assert(!static_flag);
3360 
3361  QoreValue rv = NMETHF(func)->evalPseudoMethod(xsink, variant, n, args);
3362  printd(5, "qore_method_private::evalPseudoMethod() %s::%s() returning type: %s\n", parent_class->getName(), getName(), rv.getTypeName());
3363  return rv;
3364  }
3365 
3366  DLLLOCAL QoreValue evalNormalVariant(QoreObject* self, const QoreExternalMethodVariant* ev, const QoreListNode* args, ExceptionSink* xsink) const;
3367 
3368  // returns the lowest access code for all variants
3369  DLLLOCAL ClassAccess getAccess() const;
3370 
3371  // returns the lowest access code for all variants including uncommitted variants
3372  DLLLOCAL static ClassAccess getAccess(const QoreMethod& m) {
3373  return m.priv->getAccess();
3374  }
3375 
3376  DLLLOCAL static QoreValue evalNormalVariant(const QoreMethod& m, ExceptionSink* xsink, QoreObject* self, const QoreExternalMethodVariant* ev, const QoreListNode* args) {
3377  return m.priv->evalNormalVariant(self, ev, args, xsink);
3378  }
3379 
3380  DLLLOCAL static QoreValue evalPseudoMethod(const QoreMethod& m, ExceptionSink* xsink, const AbstractQoreFunctionVariant* variant, const QoreValue n, const QoreListNode* args) {
3381  return m.priv->evalPseudoMethod(variant, n, args, xsink);
3382  }
3383 
3384  DLLLOCAL static QoreValue eval(const QoreMethod& m, ExceptionSink* xsink, QoreObject* self, const QoreListNode* args, const qore_class_private* cctx = nullptr) {
3385  return m.priv->eval(xsink, self, args, cctx);
3386  }
3387 
3388  DLLLOCAL static QoreValue evalTmpArgs(const QoreMethod& m, ExceptionSink* xsink, QoreObject* self, QoreListNode* args, const qore_class_private* cctx = nullptr) {
3389  return m.priv->evalTmpArgs(xsink, self, args, cctx);
3390  }
3391 
3392  DLLLOCAL static qore_method_private* get(QoreMethod& m) {
3393  return m.priv;
3394  }
3395 
3396  DLLLOCAL static const qore_method_private* get(const QoreMethod& m) {
3397  return m.priv;
3398  }
3399 };
3400 
3401 template <class T>
3402 class PrivateIteratorBase {
3403 public:
3404  DLLLOCAL PrivateIteratorBase(const T& obj) : obj(obj), i(obj.end()) {
3405  }
3406 
3407  DLLLOCAL bool next() {
3408  if (i == obj.end()) {
3409  i = obj.begin();
3410  }
3411  else {
3412  ++i;
3413  }
3414  return (i != obj.end());
3415  }
3416 
3418  DLLLOCAL bool valid() const {
3419  return i != obj.end();
3420  }
3421 
3422 protected:
3423  const T& obj;
3424  typename T::const_iterator i;
3425 };
3426 
3427 template <class T, class U>
3428 class PrivateMemberIteratorBase : public PrivateIteratorBase<typename T::member_list_t> {
3429 public:
3430  DLLLOCAL PrivateMemberIteratorBase(const typename T::member_list_t& obj) : PrivateIteratorBase<typename T::member_list_t>(obj) {
3431  }
3432 
3433  DLLLOCAL const U& getMember() const {
3434  assert(this->valid());
3435  return *reinterpret_cast<const U*>(this->i->second.get());
3436  }
3437 
3438  DLLLOCAL const char* getName() const {
3439  assert(this->valid());
3440  return this->i->first;
3441  }
3442 };
3443 
3444 #endif
DLLEXPORT QoreClass * getClass(qore_classid_t cid) const
returns a pointer to the QoreClass object representing the class ID passed if it exists in the class ...
DLLEXPORT int reference_count() const
gets the reference count
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:366
the base class for all data to be used as private data of Qore objects
Definition: AbstractPrivateData.h:44
void(* q_destructor_t)(QoreObject *self, AbstractPrivateData *private_data, ExceptionSink *xsink)
the type used for builtin QoreClass destructor signatures
Definition: common.h:386
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:346
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:378
virtual DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count of the object
an abstract class for class-specific external user data
Definition: QoreClass.h:223
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
DLLEXPORT const char * getName() const
returns the method&#39;s name
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
static void discard(AbstractQoreNode *n, ExceptionSink *xsink)
to deref an AbstractQoreNode (when the pointer may be 0)
Definition: QoreLib.h:323
uint64_t q_rt_flags_t
runtime code execution flags
Definition: common.h:263
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:434
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
DLLEXPORT bool ROdereference() const
atomically decrements the reference count
Qore&#39;s string type supported by the QoreEncoding class.
Definition: QoreString.h:81
Qore&#39;s string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
DLLEXPORT const QoreClass * getClass() const
returns a pointer to the parent class
DLLEXPORT const char * getBuffer() const
returns the string&#39;s buffer; this data should not be changed
DLLEXPORT QoreProgram * getProgram()
returns the current QoreProgram
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
provides atomic reference counting to Qore objects
Definition: QoreReferenceCounter.h:44
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:416
defines a Qore-language class
Definition: QoreClass.h:239
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:396
DLLEXPORT bool isStatic() const
returns true if the method is static
bool(* q_delete_blocker_t)(QoreObject *self, AbstractPrivateData *private_data)
the typed used for QoreClass deleteBlocker signatures
Definition: common.h:424
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:446
#define PO_STRICT_TYPES
enforce strict type checking and setting default values
Definition: Restrictions.h:98
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:354
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:318
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only ...
Definition: QoreProgram.h:126
the implementation of Qore&#39;s object data type, reference counted, dynamically-allocated only ...
Definition: QoreObject.h:61
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
external wrapper class for method variants
Definition: QoreReflection.h:90
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
std::vector< std::string > name_vec_t
vector of parameter names for parameter lists
Definition: common.h:257
DLLEXPORT ClassAccess getAccess() const
returns the lowest access code of all variants in the method
#define PO_REQUIRE_TYPES
require type information for all declarations
Definition: Restrictions.h:61
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
std::vector< QoreValue > arg_vec_t
vector of value information for default argument lists
Definition: common.h:254
DLLEXPORT void ROreference() const
atomically increments the reference count
int16_t qore_type_t
used to identify unique Qore data and parse types (descendents of AbstractQoreNode) ...
Definition: common.h:70
void(* q_copy_t)(QoreObject *self, QoreObject *old, AbstractPrivateData *private_data, ExceptionSink *xsink)
the type used for builtin QoreClass copy signatures
Definition: common.h:405
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:333
std::vector< const QoreTypeInfo * > type_vec_t
vector of type information for parameter lists
Definition: common.h:251
a method in a QoreClass
Definition: QoreClass.h:125
DLLEXPORT const char * getName() const
returns the class name
holds an object and dereferences it in the destructor
Definition: QoreValue.h:452
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
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values ...
#define QDOM_DEFAULT
the default domain (no domain)
Definition: Restrictions.h:155