Qore Programming Language  0.9.3.2
QoreException.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  QoreException.h
4 
5  Qore programming language exception handling support
6 
7  Copyright (C) 2003 - 2018 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_QOREEXCEPTION_H
33 
34 #define _QORE_QOREEXCEPTION_H
35 
36 #include <cstdarg>
37 #include <string>
38 
39 hashdecl QoreExceptionBase {
40  qore_call_t type;
41  QoreListNode* callStack = new QoreListNode(autoTypeInfo);
42  QoreValue err, desc, arg;
43 
44  DLLLOCAL QoreExceptionBase(QoreValue n_err, QoreValue n_desc, QoreValue n_arg = QoreValue(),
45  qore_call_t n_type = CT_BUILTIN);
46 
47  DLLLOCAL QoreExceptionBase(const QoreExceptionBase& old) :
48  type(old.type), callStack(old.callStack->copy()),
49  err(old.err.refSelf()), desc(old.desc.refSelf()),
50  arg(old.arg.refSelf()) {
51  }
52 
53  DLLLOCAL ~QoreExceptionBase() {
54  assert(!callStack);
55  }
56 };
57 
58 hashdecl QoreExceptionLocation : QoreProgramLineLocation {
59  std::string file;
60  std::string source;
61  std::string lang;
62  int offset;
63 
64  DLLLOCAL QoreExceptionLocation(const QoreProgramLocation& loc) : QoreProgramLineLocation(loc),
65  file(loc.getFileValue()), source(loc.getSourceValue()), lang(loc.getLanguageValue()), offset(loc.offset) {
66  }
67 
68  DLLLOCAL QoreExceptionLocation(const QoreExceptionLocation& old) : QoreProgramLineLocation(old),
69  file(old.file), source(old.source), lang(old.lang), offset(old.offset) {
70  }
71 
72  DLLLOCAL QoreExceptionLocation(QoreExceptionLocation&& old) = default;
73 
74  DLLLOCAL void set(const QoreProgramLocation& loc) {
75  start_line = loc.start_line;
76  end_line = loc.end_line;
77  file = loc.getFileValue();
78  source = loc.getSourceValue();
79  lang = loc.getLanguageValue();
80  offset = loc.offset;
81  }
82 };
83 
84 class QoreException : public QoreExceptionBase, public QoreExceptionLocation {
85  friend class ExceptionSink;
86  friend hashdecl qore_es_private;
87 
88 public:
89  QoreException* next = nullptr;
90 
91  // called for generic exceptions
92  DLLLOCAL QoreHashNode* makeExceptionObjectAndDelete(ExceptionSink *xsink);
93  DLLLOCAL QoreHashNode* makeExceptionObject();
94 
95  // called for runtime exceptions
96  DLLLOCAL QoreException(const char *n_err, QoreValue n_desc, QoreValue n_arg = QoreValue())
97  : QoreExceptionBase(new QoreStringNode(n_err), n_desc, n_arg),
98  QoreExceptionLocation(*get_runtime_location()) {
99  }
100 
101  DLLLOCAL QoreException(QoreStringNode *n_err, QoreValue n_desc, QoreValue n_arg = QoreValue())
102  : QoreExceptionBase(n_err, n_desc, n_arg),
103  QoreExceptionLocation(*get_runtime_location()) {
104  }
105 
106  DLLLOCAL QoreException(const QoreException& old) : QoreExceptionBase(old),
107  QoreExceptionLocation(old), next(old.next ? new QoreException(*old.next) : nullptr) {
108  }
109 
110  // called for user exceptions
111  DLLLOCAL QoreException(const QoreListNode* n) : QoreExceptionBase(0, 0, 0, CT_USER),
112  QoreExceptionLocation(*get_runtime_location()) {
113  if (n) {
114  err = n->getReferencedEntry(0);
115  desc = n->getReferencedEntry(1);
116  arg = n->size() > 3 ? n->copyListFrom(2) : n->getReferencedEntry(2);
117  }
118  }
119 
120  DLLLOCAL QoreException(const QoreProgramLocation& n_loc, const char *n_err, QoreValue n_desc,
121  QoreValue n_arg = QoreValue(), qore_call_t n_type = CT_BUILTIN) :
122  QoreExceptionBase(new QoreStringNode(n_err), n_desc, n_arg, n_type), QoreExceptionLocation(n_loc) {
123  }
124 
125  DLLLOCAL void del(ExceptionSink *xsink);
126 
127  DLLLOCAL QoreException* rethrow();
128 
129 protected:
130  DLLLOCAL ~QoreException() {
131  assert(!callStack);
132  assert(!err.hasNode());
133  assert(!desc.hasNode());
134  assert(!arg.hasNode());
135  }
136 
137  DLLLOCAL void addStackInfo(QoreHashNode* n);
138 
139  DLLLOCAL static const char* getType(qore_call_t type);
140 
141  DLLLOCAL static QoreHashNode* getStackHash(const QoreCallStackElement& cse);
142 
143 private:
144  DLLLOCAL QoreException& operator=(const QoreException&) = delete;
145 };
146 
147 class ParseException : public QoreException {
148 public:
149  // called for parse exceptions
150  DLLLOCAL ParseException(const QoreProgramLocation& loc, const char* err, QoreStringNode* desc) : QoreException(loc, err, desc) {
151  }
152 };
153 
154 hashdecl qore_es_private {
155  bool thread_exit = false;
156  QoreException* head = nullptr, * tail = nullptr;
157 
158  DLLLOCAL qore_es_private() {
159  }
160 
161  DLLLOCAL ~qore_es_private() {
162  }
163 
164  DLLLOCAL void clearIntern() {
165  // delete all exceptions
166  ExceptionSink xs;
167  if (head) {
168  head->del(&xs);
169  head = tail = nullptr;
170  }
171  }
172 
173  DLLLOCAL void insert(QoreException *e) {
174  // append exception to the list
175  if (!head)
176  head = e;
177  else
178  tail->next = e;
179  tail = e;
180  }
181 
182  DLLLOCAL void appendListIntern(QoreString& str) const {
183  QoreException* w = head;
184  while (w) {
185  QoreStringNodeValueHelper err(w->err);
186  QoreStringNodeValueHelper desc(w->desc);
187 
188  str.concat(" * ");
189  if (!w->file.empty())
190  str.sprintf("%s:", w->file.c_str());
191  if (w->start_line) {
192  str.sprintf("%d", w->start_line);
193  if (w->end_line && w->end_line != w->start_line)
194  str.sprintf("-%d", w->end_line);
195  str.concat(": ");
196  }
197  str.sprintf("%s: %s", err->getBuffer(), desc->getBuffer());
198  if (w != tail)
199  str.concat('\n');
200 
201  w = w->next;
202  }
203  }
204 
205  // creates a stack trace node and adds it to all exceptions in this sink
206  DLLLOCAL void addStackInfo(qore_call_t type, const char *class_name, const char *code,
207  const QoreProgramLocation& loc);
208 
209  DLLLOCAL void addStackInfo(const QoreCallStackElement& cse) {
210  assert(head);
211  QoreHashNode* n = QoreException::getStackHash(cse);
212 
213  assert(head);
214  QoreException* w = head;
215  while (w) {
216  w->addStackInfo(n);
217  w = w->next;
218  if (w)
219  n->ref();
220  }
221  }
222 
223  DLLLOCAL void addStackInfo(const QoreCallStack& stack) {
224  for (auto& i : stack)
225  addStackInfo(i);
226  }
227 
228  DLLLOCAL static void addStackInfo(ExceptionSink& xsink, qore_call_t type, const char* class_name,
229  const char* code, const QoreProgramLocation& loc) {
230  xsink.priv->addStackInfo(type, class_name, code, loc);
231  }
232 
233  DLLLOCAL static void appendList(ExceptionSink& xsink, QoreString& str) {
234  xsink.priv->appendListIntern(str);
235  }
236 };
237 
238 class ParseExceptionSink {
239 protected:
240  ExceptionSink xsink;
241 
242 public:
243  DLLLOCAL ~ParseExceptionSink();
244 
245  DLLLOCAL ExceptionSink *operator*() {
246  return &xsink;
247  }
248 };
249 
250 #endif
DLLEXPORT QoreValue getReferencedEntry(size_t index) const
returns the element at "index" (first element is index 0), the caller owns the reference ...
This is the hash or associative list container type in Qore, dynamically allocated only...
Definition: QoreHashNode.h:50
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
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 void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
DLLEXPORT size_t size() const
returns the number of elements in the list
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:46
DLLEXPORT void ref() const
increments the reference count
this class is used to safely manage calls to AbstractQoreNode::getStringRepresentation() when a QoreS...
Definition: QoreStringNode.h:401
DLLEXPORT QoreListNode * copyListFrom(size_t index) const
performs a deep copy of the list starting from element "offset" and returns the new list ...
Qore call stack.
Definition: ExceptionSink.h:310
DLLEXPORT bool hasNode() const
returns true if the object contains a non-null AbstractQoreNode pointer (ie type == QV_Node && v...
call stack element; strings must be in the default encoding for the Qore process
Definition: ExceptionSink.h:291