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