1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity very high)
4 module dil.ast.Node;
5 
6 import common;
7 
8 public import dil.lexer.Token;
9 public import dil.ast.NodesEnum;
10 
11 /// The root class of all D syntax tree elements.
12 abstract class Node
13 {
14   /// The possible semantic states of a Node.
15   enum State
16   {
17     Wait,   /// Wait for dependencies.
18     Error,  /// There is an error.
19     Finish, /// Dependencies are done.
20     Done    /// The symbol is done.
21   }
22 
23   NodeKind kind; /// The kind of this node.
24   Node[] children; /// List of subnodes. (May be removed to save space.)
25   Token* begin, end; /// The begin and end tokens of this node.
26   State state; /// The semantic state of this node.
27 
28   /// Sets the begin and end tokens.
29   void setTokens(Token* begin, Token* end)
30   {
31     this.begin = begin;
32     this.end = end;
33   }
34 
35   /// Sets the location tokens (begin and end) using another node.
36   void setLoc(Node other)
37   {
38     this.begin = other.begin;
39     this.end = other.end;
40   }
41 
42   /// Adds a child node.
43   void addChild(Node child)
44   {
45     assert(child !is null, "failed in " ~ typeid(this).name);
46     this.children ~= child;
47   }
48 
49   /// Adss a child node if not null.
50   void addOptChild(Node child)
51   {
52     child is null || addChild(child);
53   }
54 
55   /// Adds a list of child nodes.
56   void addChildren(N)(N children)
57   {
58     assert(children !is null && delegate{
59       foreach (child; children)
60         if (child is null)
61           return false;
62       return true; }(),
63       "failed in " ~ typeid(this).name
64     );
65     this.children ~= cast(Node[])children;
66   }
67 
68   /// Adds a list of child nodes if not null.
69   void addOptChildren(N)(N children)
70   {
71     children is null || addChildren(children);
72   }
73 
74   /// Returns the text spanned by the begin and end tokens.
75   /// Warning: The Tokens must refer to the same piece of text.
76   cstring toText()
77   {
78     assert(begin && end);
79     return begin.textSpan(end);
80   }
81 
82   /// Returns a reference to Class if this node can be cast to it.
83   Class Is(Class)()
84   {
85     if (kind == mixin("NodeKind." ~ Class.stringof))
86       return cast(Class)cast(void*)this;
87     return null;
88   }
89 
90   /// Casts this node to Class.
91   Class to(Class)()
92   {
93     return cast(Class)cast(void*)this;
94   }
95 
96   /// Returns a deep copy of this node.
97   abstract Node copy();
98 
99   /// Returns a shallow copy of this object.
100   final Node dup()
101   {
102     // Find out the size of this object.
103     auto init = typeid(this).init;
104     auto size = init.length;
105     alias byte_t = typeof(init[0]); // Get the element type.
106     auto bytes = (cast(byte_t*)this)[0..size].dup; // Make an array and copy.
107     return cast(Node)bytes.ptr; // Cast back to Node.
108   }
109 
110   /// This string is mixed into the constructor of a class that inherits
111   /// from Node. It sets the member kind. E.g.: this.kind = NodeKind.IfStmt;
112   static enum set_kind =
113     `this.kind = __traits(getMember, NodeKind, typeof(this).stringof);`;
114 
115   /// Returns true if Declaration.
116   final bool isDeclaration()
117   {
118     return kind.isDeclaration;
119   }
120 
121   /// Returns true if Statement.
122   final bool isStatement()
123   {
124     return kind.isStatement;
125   }
126 
127   /// Returns true if Expression.
128   final bool isExpression()
129   {
130     return kind.isExpression;
131   }
132 
133   /// Returns true if Type.
134   final bool isType()
135   {
136     return kind.isType;
137   }
138 
139   /// Returns true if Parameter.
140   final bool isParameter()
141   {
142     return kind.isParameter;
143   }
144 
145   bool wait()
146   {
147     return state == State.Wait;
148   }
149 
150   bool error()
151   {
152     return state == State.Error;
153   }
154 
155   bool finish()
156   {
157     return state == State.Finish;
158   }
159 
160   bool done()
161   {
162     return state == State.Done;
163   }
164 
165   void setwait()
166   {
167     state = State.Wait;
168   }
169 
170   void seterror()
171   {
172     state = State.Error;
173   }
174 
175   void setfinish()
176   {
177     state = State.Finish;
178   }
179 
180   void setdone()
181   {
182     state = State.Done;
183   }
184 }