aboutsummaryrefslogtreecommitdiff
path: root/src/MoonP/ast.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MoonP/ast.hpp')
-rw-r--r--src/MoonP/ast.hpp565
1 files changed, 565 insertions, 0 deletions
diff --git a/src/MoonP/ast.hpp b/src/MoonP/ast.hpp
new file mode 100644
index 0000000..f2ef76c
--- /dev/null
+++ b/src/MoonP/ast.hpp
@@ -0,0 +1,565 @@
1/* Copyright (c) 2012, Achilleas Margaritis, modified by Jin Li
2All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
6 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
9THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
10
11#pragma once
12
13
14#include <cassert>
15#include <list>
16#include <stdexcept>
17#include <type_traits>
18#include "MoonP/parser.hpp"
19
20
21namespace parserlib {
22
23
24class ast_node;
25template <bool Required, class T> class ast_ptr;
26template <bool Required, class T> class ast_list;
27template <class T> class ast;
28
29
30/** type of AST node stack.
31 */
32typedef std::vector<ast_node*> ast_stack;
33typedef std::list<ast_node*> node_container;
34
35extern int ast_type_id;
36
37template<class T>
38int ast_type() {
39 static int type = ast_type_id++;
40 return type;
41}
42
43enum class traversal {
44 Continue,
45 Return,
46 Stop
47};
48
49/** Base class for AST nodes.
50 */
51class ast_node : public input_range {
52public:
53 ast_node() : _ref(0) {}
54
55 void retain() {
56 ++_ref;
57 }
58
59 void release() {
60 --_ref;
61 if (_ref == 0) {
62 delete this;
63 }
64 }
65
66 /** interface for filling the contents of the node
67 from a node stack.
68 @param st stack.
69 */
70 virtual void construct(ast_stack&) {}
71
72 /** interface for visiting AST tree use.
73 */
74 virtual traversal traverse(const std::function<traversal (ast_node*)>& func);
75
76 template <typename... Ts>
77 struct select_last {
78 using type = typename decltype((std::enable_if<true,Ts>{}, ...))::type;
79 };
80 template <typename... Ts>
81 using select_last_t = typename select_last<Ts...>::type;
82
83 template <class ...Args>
84 select_last_t<Args...>* getByPath() {
85 int types[] = {ast_type<Args>()...};
86 return static_cast<select_last_t<Args...>*>(getByTypeIds(std::begin(types), std::end(types)));
87 }
88
89 virtual bool visitChild(const std::function<bool (ast_node*)>& func);
90
91 virtual size_t getId() const = 0;
92
93 virtual int get_type() = 0;
94
95 template<class T>
96 inline ast_ptr<false, T> new_ptr() {
97 auto item = new T;
98 item->m_begin.m_line = m_begin.m_line;
99 item->m_end.m_line = m_begin.m_line;
100 return ast_ptr<false, T>(item);
101 }
102private:
103 int _ref;
104 ast_node* getByTypeIds(int* begin, int* end);
105};
106
107template<class T>
108T* ast_cast(ast_node* node) {
109 return node && ast_type<T>() == node->get_type() ? static_cast<T*>(node) : nullptr;
110}
111
112template<class T>
113T* ast_to(ast_node* node) {
114 assert(node->get_type() == ast_type<T>());
115 return static_cast<T*>(node);
116}
117
118template <class ...Args>
119bool ast_is(ast_node* node) {
120 if (!node) return false;
121 bool result = false;
122 int type = node->get_type();
123 using swallow = bool[];
124 (void)swallow{result || (result = ast_type<Args>() == type)...};
125 return result;
126}
127
128class ast_member;
129
130/** type of ast member vector.
131 */
132typedef std::vector<ast_member*> ast_member_vector;
133
134
135/** base class for AST nodes with children.
136 */
137class ast_container : public ast_node {
138public:
139 void add_members(std::initializer_list<ast_member*> members) {
140 for (auto member : members) {
141 m_members.push_back(member);
142 }
143 }
144
145 /** returns the vector of AST members.
146 @return the vector of AST members.
147 */
148 const ast_member_vector& members() const {
149 return m_members;
150 }
151
152 /** Asks all members to construct themselves from the stack.
153 The members are asked to construct themselves in reverse order.
154 from a node stack.
155 @param st stack.
156 */
157 virtual void construct(ast_stack& st) override;
158
159 virtual traversal traverse(const std::function<traversal (ast_node*)>& func) override;
160
161 virtual bool visitChild(const std::function<bool (ast_node*)>& func) override;
162private:
163 ast_member_vector m_members;
164
165 friend class ast_member;
166};
167
168
169/** Base class for children of ast_container.
170 */
171class ast_member {
172public:
173 virtual ~ast_member() {}
174
175 /** interface for filling the the member from a node stack.
176 @param st stack.
177 */
178 virtual void construct(ast_stack& st) = 0;
179
180 virtual bool accept(ast_node* node) = 0;
181
182 virtual int get_type() { return ast_type<ast_member>(); }
183};
184
185template<class T>
186T* ast_cast(ast_member* member) {
187 return member && ast_type<T>() == member->get_type() ? static_cast<T*>(member) : nullptr;
188}
189
190class _ast_ptr : public ast_member {
191public:
192 _ast_ptr(ast_node* node) : m_ptr(node) {
193 if (node) node->retain();
194 }
195
196 virtual ~_ast_ptr() {
197 if (m_ptr) {
198 m_ptr->release();
199 m_ptr = nullptr;
200 }
201 }
202
203 ast_node* get() const {
204 return m_ptr;
205 }
206
207 template <class T>
208 T* as() const {
209 return ast_cast<T>(m_ptr);
210 }
211
212 template <class T>
213 T* to() const {
214 assert(m_ptr && m_ptr->get_type() == ast_type<T>());
215 return static_cast<T*>(m_ptr);
216 }
217
218 template <class T>
219 bool is() const {
220 return m_ptr && m_ptr->get_type() == ast_type<T>();
221 }
222
223 void set(ast_node* node) {
224 if (node == m_ptr) {
225 return;
226 } else if (!node) {
227 if (m_ptr) m_ptr->release();
228 m_ptr = nullptr;
229 } else {
230 assert(accept(node));
231 if (m_ptr) m_ptr->release();
232 m_ptr = node;
233 node->retain();
234 }
235 }
236
237 virtual int get_type() override {
238 return ast_type<_ast_ptr>();
239 }
240protected:
241 ast_node* m_ptr;
242};
243
244/** pointer to an AST object.
245 It assumes ownership of the object.
246 It pops an object of the given type from the stack.
247 @tparam Required if true, the object is required.
248 @tparam T type of object to control.
249 */
250template <bool Required, class T> class ast_ptr : public _ast_ptr {
251public:
252 ast_ptr(T* node = nullptr) : _ast_ptr(node) {}
253
254 ast_ptr(const ast_ptr& other) : _ast_ptr(other.get()) {}
255
256 ast_ptr& operator=(const ast_ptr& other) {
257 set(other.get());
258 return *this;
259 }
260
261 /** gets the underlying ptr value.
262 @return the underlying ptr value.
263 */
264 T* get() const {
265 return static_cast<T*>(m_ptr);
266 }
267
268 /** auto conversion to the underlying object ptr.
269 @return the underlying ptr value.
270 */
271 operator T*() const {
272 return static_cast<T*>(m_ptr);
273 }
274
275 /** member access.
276 @return the underlying ptr value.
277 */
278 T* operator->() const {
279 assert(m_ptr);
280 return static_cast<T*>(m_ptr);
281 }
282
283 /** Pops a node from the stack.
284 @param st stack.
285 @exception std::logic_error thrown if the node is not of the appropriate type;
286 thrown only if Required == true or if the stack is empty.
287 */
288 virtual void construct(ast_stack& st) override {
289 // check the stack node
290 if (st.empty()) {
291 if (!Required) return;
292 throw std::logic_error("Invalid AST stack.");
293 }
294 ast_node* node = st.back();
295 if (!ast_ptr::accept(node)) {
296 // if the object is not required, simply return
297 if (!Required) return;
298 // else if the object is mandatory, throw an exception
299 throw std::logic_error("Invalid AST node.");
300 }
301 st.pop_back();
302 m_ptr = node;
303 node->retain();
304 }
305private:
306 virtual bool accept(ast_node* node) override {
307 return node && (std::is_same<ast_node,T>() || ast_type<T>() == node->get_type());
308 }
309};
310
311template <bool Required, class ...Args> class ast_sel : public _ast_ptr {
312public:
313 ast_sel() : _ast_ptr(nullptr) {}
314
315 ast_sel(const ast_sel& other) : _ast_ptr(other.get()) {}
316
317 ast_sel& operator=(const ast_sel& other) {
318 set(other.get());
319 return *this;
320 }
321
322 operator ast_node*() const {
323 return m_ptr;
324 }
325
326 ast_node* operator->() const {
327 assert(m_ptr);
328 return m_ptr;
329 }
330
331 virtual void construct(ast_stack& st) override {
332 if (st.empty()) {
333 if (!Required) return;
334 throw std::logic_error("Invalid AST stack.");
335 }
336 ast_node* node = st.back();
337 if (!ast_sel::accept(node)) {
338 if (!Required) return;
339 throw std::logic_error("Invalid AST node.");
340 }
341 st.pop_back();
342 m_ptr = node;
343 node->retain();
344 }
345private:
346 virtual bool accept(ast_node* node) override {
347 if (!node) return false;
348 using swallow = bool[];
349 bool result = false;
350 (void)swallow{result || (result = ast_type<Args>() == node->get_type())...};
351 return result;
352 }
353};
354
355class _ast_list : public ast_member {
356public:
357 ~_ast_list() {
358 clear();
359 }
360
361 inline ast_node* back() const {
362 return m_objects.back();
363 }
364
365 inline ast_node* front() const {
366 return m_objects.front();
367 }
368
369 inline size_t size() const {
370 return m_objects.size();
371 }
372
373 inline bool empty() const {
374 return m_objects.empty();
375 }
376
377 void push_back(ast_node* node) {
378 assert(node && accept(node));
379 m_objects.push_back(node);
380 node->retain();
381 }
382
383 void push_front(ast_node* node) {
384 assert(node && accept(node));
385 m_objects.push_front(node);
386 node->retain();
387 }
388
389 void pop_front() {
390 auto node = m_objects.front();
391 m_objects.pop_front();
392 node->release();
393 }
394
395 const node_container& objects() const {
396 return m_objects;
397 }
398
399 void clear() {
400 for(ast_node* obj : m_objects) {
401 if (obj) obj->release();
402 }
403 m_objects.clear();
404 }
405
406 void dup(const _ast_list& src) {
407 for(ast_node* obj : src.m_objects) {
408 m_objects.push_back(obj);
409 obj->retain();
410 }
411 }
412
413 virtual int get_type() override { return ast_type<_ast_list>(); }
414protected:
415 node_container m_objects;
416};
417
418/** A list of objects.
419 It pops objects of the given type from the ast stack, until no more objects can be popped.
420 It assumes ownership of objects.
421 @tparam Required if true, the object is required.
422 @tparam T type of object to control.
423 */
424template <bool Required, class T> class ast_list : public _ast_list {
425public:
426 ast_list() { }
427
428 ast_list(const ast_list& other) {
429 dup(other);
430 }
431
432 ast_list& operator=(const ast_list& other) {
433 clear();
434 dup(other);
435 return *this;
436 }
437
438 /** Pops objects of type T from the stack until no more objects can be popped.
439 @param st stack.
440 */
441 virtual void construct(ast_stack &st) override {
442 while (!st.empty()) {
443 ast_node* node = st.back();
444 // if the object was not not of the appropriate type,
445 // end the list parsing
446 if (!ast_list::accept(node)) {
447 if (Required && m_objects.empty()) {
448 throw std::logic_error("Invalid AST node.");
449 }
450 return;
451 }
452 st.pop_back();
453 // insert the object in the list, in reverse order
454 m_objects.push_front(node);
455 node->retain();
456 }
457 if (Required && m_objects.empty()) {
458 throw std::logic_error("Invalid AST stack.");
459 }
460 }
461private:
462 virtual bool accept(ast_node* node) override {
463 return node && (std::is_same<ast_node,T>() || ast_type<T>() == node->get_type());
464 }
465};
466
467template <bool Required, class ...Args> class ast_sel_list : public _ast_list {
468public:
469 ast_sel_list() { }
470
471 ast_sel_list(const ast_sel_list& other) {
472 dup(other);
473 }
474
475 ast_sel_list& operator=(const ast_sel_list& other) {
476 clear();
477 dup(other);
478 return *this;
479 }
480
481 virtual void construct(ast_stack &st) override {
482 while (!st.empty()) {
483 ast_node* node = st.back();
484 if (!ast_sel_list::accept(node)) {
485 if (Required && m_objects.empty()) {
486 throw std::logic_error("Invalid AST node.");
487 }
488 return;
489 }
490 st.pop_back();
491 m_objects.push_front(node);
492 node->retain();
493 }
494 if (Required && m_objects.empty()) {
495 throw std::logic_error("Invalid AST stack.");
496 }
497 }
498private:
499 virtual bool accept(ast_node* node) override {
500 if (!node) return false;
501 using swallow = bool[];
502 bool result = false;
503 (void)swallow{result || (result = ast_type<Args>() == node->get_type())...};
504 return result;
505 }
506};
507
508/** AST function which creates an object of type T
509 and pushes it to the node stack.
510 */
511template <class T> class ast {
512public:
513 /** constructor.
514 @param r rule to attach the AST function to.
515 */
516 ast(rule& r) {
517 r.set_parse_proc(&_parse_proc);
518 }
519
520private:
521 //parse proc
522 static void _parse_proc(const pos& b, const pos& e, void* d) {
523 ast_stack* st = reinterpret_cast<ast_stack*>(d);
524 T* obj = new T;
525 obj->m_begin = b;
526 obj->m_end = e;
527 obj->construct(*st);
528 st->push_back(obj);
529 }
530};
531
532
533/** parses the given input.
534 @param i input.
535 @param g root rule of grammar.
536 @param el list of errors.
537 @param ud user data, passed to the parse procedures.
538 @return pointer to ast node created, or null if there was an error.
539 The return object must be deleted by the caller.
540 */
541ast_node* _parse(input& i, rule& g, error_list& el, void* ud);
542
543
544/** parses the given input.
545 @param i input.
546 @param g root rule of grammar.
547 @param el list of errors.
548 @param ud user data, passed to the parse procedures.
549 @return ast nodes.
550 */
551template <class T> ast_ptr<false, T> parse(input& i, rule& g, error_list& el, void* ud = nullptr) {
552 ast_node* node = _parse(i, g, el, ud);
553 T* ast = ast_cast<T>(node);
554 ast_ptr<false, T> ptr;
555 if (ast) {
556 ast_stack st{node};
557 ptr.construct(st);
558 } else if (node) {
559 delete node;
560 }
561 return ptr;
562}
563
564
565} //namespace parserlib