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 }