1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity average)
4 module dil.semantic.Symbol;
5 
6 import dil.ast.Node;
7 import dil.lexer.Identifier,
8        dil.lexer.IdTable;
9 import dil.String : itoa;
10 import common;
11 
12 /// Enumeration of Symbol IDs.
13 enum SYM
14 {
15   Module,
16   Package,
17   Class,
18   Interface,
19   Struct,
20   Union,
21   Enum,
22   EnumMember,
23   Template,
24   TemplateInstance,
25   TemplateMixin,
26   Variable,
27   Function,
28   Alias,
29   Typedef,
30   OverloadSet,
31   Scope,
32   Parameter,
33   Parameters,
34   Tuple,
35   Type,
36 }
37 
38 /// Info on a symbol's source code location.
39 struct SLoc
40 {
41   Token* t; /// Gives a precise location. Usually the name of a symbol.
42   Node n; /// For Ddoc comments other possibly other info.
43 }
44 
45 /// A symbol represents an object with semantic code information.
46 class Symbol
47 { /// Enumeration of symbol statuses.
48   enum Status : ushort
49   {
50     Declared,   /// The symbol has been declared.
51     Completing, /// The symbol is being processed.
52     Complete    /// The symbol is complete.
53   }
54 
55   SYM sid; /// The ID of this symbol.
56   Status status; /// The semantic status of this symbol.
57   Symbol parent; /// The parent this symbol belongs to.
58   /// The name of this symbol.
59   /// If the symbol is nameless Ident.Empty is assigned to it.
60   Identifier* name;
61   SLoc loc; /// For locating a symbol.
62 
63   /// Constructs a Symbol object.
64   /// Params:
65   ///   sid = The symbol's ID.
66   ///   name = The symbol's name.
67   ///   node = The symbol's node.
68   this(SYM sid, Identifier* name, SLoc loc)
69   {
70     this.sid = sid;
71     this.name = name ? name : Ident.Empty;
72     this.loc = loc;
73   }
74 
75   /// Change the status to Status.Completing.
76   void setCompleting()
77   { status = Status.Completing; }
78 
79   /// Change the status to Status.Complete.
80   void setComplete()
81   { status = Status.Complete; }
82 
83   /// Returns true if the symbol is being completed.
84   bool isCompleting()
85   { return status == Status.Completing; }
86 
87   /// Returns true if the symbols is complete.
88   bool isComplete()
89   { return status == Status.Complete; }
90 
91   /// A template for building isXYZ() methods.
92   private static string is_()(string kind)
93   {
94     return `bool is`~kind~`(){ return sid == SYM.`~kind~`; }`;
95   }
96 
97   mixin(is_("Module"));
98   mixin(is_("Package"));
99   mixin(is_("Class"));
100   mixin(is_("Interface"));
101   mixin(is_("Struct"));
102   mixin(is_("Union"));
103   mixin(is_("Enum"));
104   mixin(is_("EnumMember"));
105   mixin(is_("Template"));
106   mixin(is_("TemplateInstance"));
107   mixin(is_("TemplateMixin"));
108   mixin(is_("Variable"));
109   mixin(is_("Function"));
110   mixin(is_("Alias"));
111   mixin(is_("Typedef"));
112   mixin(is_("OverloadSet"));
113   mixin(is_("Scope"));
114   mixin(is_("Parameter"));
115   mixin(is_("Parameters"));
116   mixin(is_("Tuple"));
117   mixin(is_("Type"));
118 
119   /// Casts the symbol to Class.
120   Class to(Class)()
121   {
122     assert(mixin(`this.sid == mixin("SYM." ~
123       { const N = Class.stringof; // Slice off "Symbol" from the name.
124         return N[$-6..$] == "Symbol" ? N[0..$-6] : N; }())`));
125     return cast(Class)cast(void*)this;
126   }
127 
128   /// Returns: the fully qualified name of this symbol.
129   /// E.g.: dil.semantic.Symbol.Symbol.getFQN
130   cstring getFQN()
131   {
132     cstring fqn = name.str;
133     if (parent) // Iter upwards until the root package is reached.
134       for (auto s = parent; s.parent; s = s.parent)
135         fqn = s.name.str ~ '.' ~ fqn;
136     return fqn;
137   }
138 
139   /// Returns the module this symbol belongs to or null if orphaned.
140   Symbol getModule()
141   {
142     auto s = this;
143     for (; s && !s.isModule(); s = s.parent)
144     {}
145     return s;
146   }
147 
148   /// Returns the type of this symbol or null if inexistent.
149   /// The return type is Object to avoid circular imports.
150   Object getType()
151   {
152     return null;
153   }
154 
155   /// Returns the mangled name of this symbol.
156   cstring toMangle()
157   { // := ParentMangle? NameMangleLength NameMangle
158     if (name is Ident.Empty)
159     {} // TODO: ?
160     cstring pm; // Parent mangle.
161     if (parent)
162     {
163       pm = parent.toMangle();
164       if (pm.length >= 2 && pm[0..2] == "_D")
165         pm = pm[2..$]; // Skip the prefix.
166     }
167     cstring id = name.str;
168     return pm ~ itoa(id.length) ~ id;
169   }
170 
171   static cstring toMangle(Symbol s)
172   {
173     return s.toMangle();
174   }
175 
176   cstring toCppMangle()
177   { // TODO:
178     return null;
179   }
180 
181   /// Returns the string representation of this symbol.
182   override string toString()
183   {
184     return name.str;
185   }
186 }