Pegmatite
/Users/theraven/Documents/Work/Teaching/Compilers ACS Module/Coursework/Resources/Pegmatite/ast.hh
1 /*-
2  * Copyright (c) 2012, Achilleas Margaritis
3  * Copyright (c) 2014-2016, David T. Chisnall
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 #ifndef PEGMATITE_AST_HPP
29 #define PEGMATITE_AST_HPP
30 
31 
32 #include <cassert>
33 #include <list>
34 #include <unordered_map>
35 #include <sstream>
36 #include <memory>
37 #include <cxxabi.h>
38 #include "parser.hh"
39 
40 
41 namespace pegmatite {
42 
47 std::string demangle(std::string);
48 
49 #ifdef DEBUG_AST_CONSTRUCTION
50 template <class T> void debug_log(const char *msg, size_t depth, T *obj)
51 {
52  std::string demangled = demangle(typeid(*obj).name());
53  fprintf(stderr, "[%ld] %s %s (%p) off the AST stack\n",
54  depth, msg, demangled.c_str(), static_cast<const void*>(obj));
55 }
56 #else
57 template <class T> void debug_log(const char *, size_t /* depth */, T *) {}
58 #endif // DEBUG_AST_CONSTRUCTION
59 
60 class ASTNode;
61 template <class T, bool Optional> class ASTPtr;
62 template <class T> class ASTList;
63 template <class T> class BindAST;
64 
65 
66 typedef std::pair<const InputRange, std::unique_ptr<ASTNode>> ASTStackEntry;
69 typedef std::vector<ASTStackEntry> ASTStack;
70 
71 #ifdef USE_RTTI
72 #define PEGMATITE_RTTI(thisclass, superclass)
73 #else
74 
79 #define PEGMATITE_RTTI(thisclass, superclass) \
80  friend ASTNode; \
81 protected: \
82  static char *classKind() \
83  { \
84  static char thisclass ## id; \
85  return &thisclass ## id; \
86  } \
87 public: \
88  virtual bool isa(char *x) override \
89  { \
90  return (x == classKind()) || \
91  (superclass::isa(x)); \
92  }
93 #endif
94 
95 
99 class ASTNode
100 {
101 public:
105  ASTNode() : parent_node(0) {}
109  ASTNode(const ASTNode&) = delete;
110 
116  virtual ~ASTNode();
117 
123  ASTNode *parent() const { return parent_node; }
124 
129  virtual void construct(const InputRange &r, ASTStack &st) = 0;
130 
131 private:
135  ASTNode *parent_node;
136 
137  template <class T, bool Optional> friend class ASTPtr;
138  template <class T> friend class ASTList;
139  template <class T> friend class BindAST;
140 
141 #ifndef USE_RTTI
142 protected:
148  virtual char *kind() { return classKind(); }
152  static char *classKind()
153  {
154  static char ASTNodeid;
155  return &ASTNodeid;
156  }
157 public:
163  virtual bool isa(char *x)
164  {
165  return x == classKind();
166  }
173  template <class T> bool isa()
174  {
175  return isa(T::classKind());
176  }
185  template <class T> T* get_as()
186  {
187  auto *t = this;
188  return t ? (isa<T>() ? static_cast<T*>(this) : nullptr) : nullptr;
189  }
190 #else
191 public:
192  template <class T> T* get_as()
193  {
194  return dynamic_cast<T*>(this);
195  }
196 #endif
197 };
198 
199 
200 class ASTMember;
201 
202 
211 class ASTContainer : public ASTNode
212 {
213 public:
219  ASTContainer();
220 
228  virtual void construct(const InputRange &r, ASTStack &st);
229 
230 private:
234  typedef std::vector<ASTMember *> ASTMember_vector;
239  ASTMember_vector members;
240 
241  friend class ASTMember;
242  PEGMATITE_RTTI(ASTContainer, ASTNode)
243 };
244 
245 
250 {
251 public:
257  ASTMember();
258 
262  ASTContainer *container() const { return container_node; }
263 
267  virtual void construct(const InputRange &r, ASTStack &st) = 0;
268  virtual ~ASTMember();
269 protected:
274 };
275 
281 template<typename T>
282 T& constructValue(const pegmatite::InputRange &r, T& value)
283 {
284  std::stringstream stream;
285  for_each(r.begin(), r.end(), [&](char c) {stream << c;});
286  stream >> value;
287  return value;
288 }
289 
295 template <class T, bool Optional = false> class ASTPtr : public ASTMember
296 {
297 public:
301  ASTPtr() : ptr(nullptr) {}
302 
306  T *get() const
307  {
308  return ptr.get();
309  }
310 
314  const std::unique_ptr<T> &operator *() const
315  {
316  return ptr;
317  }
318 
322  const std::unique_ptr<T> &operator ->() const
323  {
324  assert(ptr);
325  return ptr;
326  }
327 
328  explicit operator bool() const noexcept
329  {
330  return static_cast<bool>(ptr);
331  }
332 
336  virtual void construct(const InputRange &r, ASTStack &st)
337  {
338  if (st.empty() && Optional)
339  {
340  return;
341  }
342  assert(!st.empty() && "Stack must not be empty");
343  ASTStackEntry &e = st.back();
344  const InputRange &childRange = e.first;
345  // If the entry isn't within the range of this, then it's just
346  // something of the same type that happens to be adjacent to this
347  // entry.
348  if ((childRange.begin() < r.begin()) ||
349  (childRange.end() > r.end()))
350  {
351  assert(Optional && "Required object not found");
352  return;
353  }
354  //get the node
355  ASTNode *node = e.second.get();
356 
357  //get the object
358  T *obj = node->get_as<T>();
359 
360  assert((obj || Optional) && "Required objects must exist!");
361  //if the object is optional, simply return
362  if (Optional && !obj)
363  {
364  return;
365  }
366  debug_log("Popped", st.size()-1, obj);
367  //set the new object
368  ptr.reset(obj);
369  //pop the node from the stack
370  st.back().second.release();
371  st.pop_back();
372  ptr->parent_node = container_node;
373  }
374 
375 private:
379  std::unique_ptr<T> ptr;
380 };
381 
382 
388 template <class T> class ASTList : public ASTMember
389 {
390 public:
392  typedef std::list<std::unique_ptr<T>> container;
393 
395  ASTList() {}
396 
400  ASTList(const ASTList<T> &src)
401  {
402  _dup(src);
403  }
404 
408  const container &objects() const
409  {
410  return child_objects;
411  }
412 
413  size_t size() { return child_objects.size(); }
414  bool empty() const { return child_objects.size() == 0; }
415  typename container::iterator begin() { return child_objects.begin(); }
416  typename container::iterator end() { return child_objects.end(); }
417  typename container::reverse_iterator rbegin() { return child_objects.rbegin(); }
418  typename container::reverse_iterator rend() { return child_objects.rend(); }
419 
420  typename container::const_iterator begin() const
421  {
422  return child_objects.begin();
423  }
424  typename container::const_iterator end() const
425  {
426  return child_objects.end();
427  }
428  typename container::const_reverse_iterator rbegin() const
429  {
430  return child_objects.rbegin();
431  }
432  typename container::const_reverse_iterator rend() const
433  {
434  return child_objects.rend();
435  }
436 
441  virtual void construct(const InputRange &r, ASTStack &st)
442  {
443  for(;;)
444  {
445  // If the stack is empty, don't fetch anything from it
446  if (st.empty()) break;
447  // Get the top entry on the stack
448  ASTStackEntry &e = st.back();
449  const InputRange &childRange = e.first;
450  // If the entry isn't within the range of this, then it's just
451  // something of the same type that happens to be adjacent to this
452  // entry.
453  if ((childRange.begin() < r.begin()) ||
454  (childRange.end() > r.end()))
455  {
456  break;
457  }
458 
459  //get the node
460  ASTNode *node = e.second.get();
461 
462  //get the object
463  T *obj = node->get_as<T>();
464 
465  //if the object was not not of the appropriate type,
466  //end the list parsing
467  if (!obj) return;
468  debug_log("Popped", st.size()-1, obj);
469 
470  //remove the node from the stack
471  e.second.release();
472  st.pop_back();
473 
474  //insert the object in the list, in reverse order
475  child_objects.push_front(std::unique_ptr<T>(obj));
476 
477  //set the object's parent
478  obj->parent_node = ASTMember::container();
479  }
480  }
481  virtual ~ASTList() {}
482 
483 private:
484  //objects
485  container child_objects;
486 
487  //duplicate the given list.
488  void _dup(const ASTList<T> &src)
489  {
490  for (auto child : src.child_objects)
491  {
492  T *obj = new T(child.get());
493  child_objects.push_back(obj);
494  obj->parent_node = ASTMember::container();
495  }
496  }
497 };
498 
508 std::unique_ptr<ASTNode> parse(Input &i, const Rule &g, const Rule &ws,
509  ErrorReporter &err, const ParserDelegate &d);
510 
524 {
529  template <class T> friend class BindAST;
530  private:
534  std::unordered_map<const Rule*, parse_proc> handlers;
535  protected:
539  void set_parse_proc(const Rule &r, parse_proc p);
544  static void bind_parse_proc(const Rule &r, parse_proc p);
545  public:
552  virtual parse_proc get_parse_proc(const Rule &) const;
561  template <class T> bool parse(Input &i, const Rule &g, const Rule &ws,
562  ErrorReporter err,
563  std::unique_ptr<T> &ast) const
564  {
565  std::unique_ptr<ASTNode> node = pegmatite::parse(i, g, ws, err, *this);
566  T *n = node->get_as<T>();
567  if (n)
568  {
569  node.release();
570  ast.reset(n);
571  return true;
572  }
573  return false;
574  }
575 };
576 
582 template <class T> class BindAST
583 {
584 public:
588  BindAST(const Rule &r)
589  {
591  void *d)
592  {
593  ASTStack *st = reinterpret_cast<ASTStack *>(d);
594  T *obj = new T();
595  debug_log("Constructing", st->size(), obj);
596  obj->construct(range, *st);
597  st->push_back(std::make_pair(range, std::unique_ptr<ASTNode>(obj)));
598  debug_log("Constructed", st->size()-1, obj);
599  return true;
600  });
601  }
602 };
603 
604 
605 } //namespace pegmatite
606 
607 
608 #endif //PEGMATITE_AST_HPP
Input::iterator end() const
Iterator to the end of the input range.
Definition: parser.hh:490
virtual void construct(const InputRange &r, ASTStack &st)=0
Interface for constructing the AST node.
virtual ~ASTNode()
Destructor does nothing, virtual for subclasses to use.
Parser delegate abstract class.
Definition: parser.hh:793
An ASTPtr is a wrapper around a pointer to an AST object.
Definition: ast.hh:61
Base class for children of ASTContainer.
Definition: ast.hh:249
T * get_as()
Returns a pointer to this object as a pointer to a child class, or nullptr if the cast would be unsaf...
Definition: ast.hh:185
bool isa()
Returns true if this object is an instance of T.
Definition: ast.hh:173
Input::iterator begin() const
Iterator to the start of the input range.
Definition: parser.hh:486
A parser delegate that is responsible for creating AST nodes from the input.
Definition: ast.hh:523
virtual void construct(const InputRange &r, ASTStack &st)
Pops objects of type T from the stack (st) until no more objects can be popped.
Definition: ast.hh:441
ASTContainer * container_node
The container that owns this object.
Definition: ast.hh:273
static char * classKind()
Returns the unique identifier for this class.
Definition: ast.hh:152
virtual char * kind()
Returns the kind of object class.
Definition: ast.hh:148
Rule class, which represents a rule in a grammar.
Definition: parser.hh:554
bool parse(Input &i, const Rule &g, const Rule &ws, ErrorReporter err, std::unique_ptr< T > &ast) const
Parse an input i, starting from rule g in the grammar for which this is a delegate.
Definition: ast.hh:561
type of ast member vector.
Definition: ast.hh:211
A range within input.
Definition: parser.hh:466
ASTPtr()
Constructs the object in the.
Definition: ast.hh:301
A list of objects.
Definition: ast.hh:62
BindAST(const Rule &r)
Bind the AST class described in the grammar to the rule specified.
Definition: ast.hh:588
The BindAST class is responsible for binding an action to a rule.
Definition: ast.hh:63
static void bind_parse_proc(const Rule &r, parse_proc p)
Registers a callback for a specific rule in the instance of this class currently under construction i...
Abstract superclass for indexing into a buffer with arbitrary storage.
Definition: parser.hh:52
ASTNode()
Constructs the AST node, with a null parent.
Definition: ast.hh:105
Base class for AST nodes.
Definition: ast.hh:99
virtual void construct(const InputRange &r, ASTStack &st)
Pops the next matching object from the AST stack st and claims it.
Definition: ast.hh:336
const container & objects() const
returns the container of objects.
Definition: ast.hh:408
ASTNode * parent() const
Returns the parent of this AST node, or nullptr if there isn&#39;t one (either if this is the root...
Definition: ast.hh:123
std::list< std::unique_ptr< T > > container
list type.
Definition: ast.hh:392
ASTList(const ASTList< T > &src)
duplicates the objects of the given list.
Definition: ast.hh:400
Definition: ast.hh:41
ASTList()
the default constructor.
Definition: ast.hh:395
virtual bool isa(char *x)
Root implementation of the RTTI-replacement for builds not wishing to use RTTI.
Definition: ast.hh:163
ASTContainer * container() const
Returns the container of which this object is a field.
Definition: ast.hh:262