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