1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _nspace.d)
9  */
10 
11 module ddmd.nspace;
12 
13 import ddmd.aggregate;
14 import ddmd.arraytypes;
15 import ddmd.dscope;
16 import ddmd.dsymbol;
17 import ddmd.globals;
18 import ddmd.identifier;
19 import ddmd.visitor;
20 import core.stdc.stdio;
21 
22 private enum LOG = false;
23 
24 /***********************************************************
25  * A namespace corresponding to a C++ namespace.
26  * Implies extern(C++).
27  */
28 extern (C++) final class Nspace : ScopeDsymbol
29 {
30     extern (D) this(Loc loc, Identifier ident, Dsymbols* members)
31     {
32         super(ident);
33         //printf("Nspace::Nspace(ident = %s)\n", ident->toChars());
34         this.loc = loc;
35         this.members = members;
36     }
37 
38     override Dsymbol syntaxCopy(Dsymbol s)
39     {
40         auto ns = new Nspace(loc, ident, null);
41         return ScopeDsymbol.syntaxCopy(ns);
42     }
43 
44     override void addMember(Scope* sc, ScopeDsymbol sds)
45     {
46         ScopeDsymbol.addMember(sc, sds);
47         if (members)
48         {
49             if (!symtab)
50                 symtab = new DsymbolTable();
51             // The namespace becomes 'imported' into the enclosing scope
52             for (Scope* sce = sc; 1; sce = sce.enclosing)
53             {
54                 ScopeDsymbol sds2 = sce.scopesym;
55                 if (sds2)
56                 {
57                     sds2.importScope(this, Prot(PROTpublic));
58                     break;
59                 }
60             }
61             assert(sc);
62             sc = sc.push(this);
63             sc.linkage = LINKcpp; // namespaces default to C++ linkage
64             sc.parent = this;
65             foreach (s; *members)
66             {
67                 //printf("add %s to scope %s\n", s->toChars(), toChars());
68                 s.addMember(sc, this);
69             }
70             sc.pop();
71         }
72     }
73 
74     override void setScope(Scope* sc)
75     {
76         ScopeDsymbol.setScope(sc);
77         if (members)
78         {
79             assert(sc);
80             sc = sc.push(this);
81             sc.linkage = LINKcpp; // namespaces default to C++ linkage
82             sc.parent = this;
83             foreach (s; *members)
84             {
85                 s.setScope(sc);
86             }
87             sc.pop();
88         }
89     }
90 
91     override void semantic(Scope* sc)
92     {
93         if (semanticRun >= PASSsemantic)
94             return;
95         semanticRun = PASSsemantic;
96         static if (LOG)
97         {
98             printf("+Nspace::semantic('%s')\n", toChars());
99         }
100         if (_scope)
101         {
102             sc = _scope;
103             _scope = null;
104         }
105         parent = sc.parent;
106         if (members)
107         {
108             assert(sc);
109             sc = sc.push(this);
110             sc.linkage = LINKcpp; // note that namespaces imply C++ linkage
111             sc.parent = this;
112             foreach (s; *members)
113             {
114                 s.importAll(sc);
115             }
116             foreach (s; *members)
117             {
118                 static if (LOG)
119                 {
120                     printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
121                 }
122                 s.semantic(sc);
123             }
124             sc.pop();
125         }
126         static if (LOG)
127         {
128             printf("-Nspace::semantic('%s')\n", toChars());
129         }
130     }
131 
132     override void semantic2(Scope* sc)
133     {
134         if (semanticRun >= PASSsemantic2)
135             return;
136         semanticRun = PASSsemantic2;
137         static if (LOG)
138         {
139             printf("+Nspace::semantic2('%s')\n", toChars());
140         }
141         if (members)
142         {
143             assert(sc);
144             sc = sc.push(this);
145             sc.linkage = LINKcpp;
146             foreach (s; *members)
147             {
148                 static if (LOG)
149                 {
150                     printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
151                 }
152                 s.semantic2(sc);
153             }
154             sc.pop();
155         }
156         static if (LOG)
157         {
158             printf("-Nspace::semantic2('%s')\n", toChars());
159         }
160     }
161 
162     override void semantic3(Scope* sc)
163     {
164         if (semanticRun >= PASSsemantic3)
165             return;
166         semanticRun = PASSsemantic3;
167         static if (LOG)
168         {
169             printf("Nspace::semantic3('%s')\n", toChars());
170         }
171         if (members)
172         {
173             sc = sc.push(this);
174             sc.linkage = LINKcpp;
175             foreach (s; *members)
176             {
177                 s.semantic3(sc);
178             }
179             sc.pop();
180         }
181     }
182 
183     override bool oneMember(Dsymbol* ps, Identifier ident)
184     {
185         return Dsymbol.oneMember(ps, ident);
186     }
187 
188     override final Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly)
189     {
190         //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
191         if (_scope && !symtab)
192             semantic(_scope);
193 
194         if (!members || !symtab) // opaque or semantic() is not yet called
195         {
196             error("is forward referenced when looking for '%s'", ident.toChars());
197             return null;
198         }
199 
200         return ScopeDsymbol.search(loc, ident, flags);
201     }
202 
203     override int apply(Dsymbol_apply_ft_t fp, void* param)
204     {
205         if (members)
206         {
207             foreach (s; *members)
208             {
209                 if (s)
210                 {
211                     if (s.apply(fp, param))
212                         return 1;
213                 }
214             }
215         }
216         return 0;
217     }
218 
219     override bool hasPointers()
220     {
221         //printf("Nspace::hasPointers() %s\n", toChars());
222         if (members)
223         {
224             foreach (s; *members)
225             {
226                 //printf(" s = %s %s\n", s->kind(), s->toChars());
227                 if (s.hasPointers())
228                 {
229                     return true;
230                 }
231             }
232         }
233         return false;
234     }
235 
236     override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion)
237     {
238         //printf("Nspace::setFieldOffset() %s\n", toChars());
239         if (_scope) // if fwd reference
240             semantic(null); // try to resolve it
241         if (members)
242         {
243             foreach (s; *members)
244             {
245                 //printf("\t%s\n", s->toChars());
246                 s.setFieldOffset(ad, poffset, isunion);
247             }
248         }
249     }
250 
251     override const(char)* kind() const
252     {
253         return "namespace";
254     }
255 
256     override inout(Nspace) isNspace() inout
257     {
258         return this;
259     }
260 
261     override void accept(Visitor v)
262     {
263         v.visit(this);
264     }
265 }