1 /**
2  * A scoped C++ namespace symbol
3  *
4  * D supports the following syntax to declare symbol(s) as being part of a
5  * C++ namespace:
6  * ---
7  * extern (C++, "myNamespace") { /+ Symbols +/ }       // String variant
8  * extern (C++, SomeNamespace) { /+ Other symbols +/ } // Identifier variant
9  * ---
10  * The first form is an attribute and only affects mangling, and is implemented
11  * in `dmd.attrib`.
12  * The second form introduces a named scope and allows symbols to be refered
13  * to with or without the namespace name, much like a named template mixin,
14  * and is implemented in this module.
15  * ---
16  * extern (C++, Basket)
17  * {
18  *     struct StrawBerry;
19  *     void swapFood (Strawberry* f1, Strawberry* f2);
20  * }
21  * void main ()
22  * {
23  *     Basket.StrawBerry fruit1;
24  *     StrawBerry fruit2;
25  *     Basket.swapFood(fruit1, fruit2);
26  *     swapFood(fruit1, fruit2);
27  * }
28  * ---
29  * Hence the `Nspace` symbol implements the usual `ScopeDsymbol` semantics.
30  *
31  * Note that it implies `extern(C++)` so it cannot be used as a generic
32  * named scope. Additionally, `Nspace` with the same `Identifier` can be
33  * defined in different module (as C++ allows a namespace to be spread accross
34  * translation units), but symbols in it should be considered
35  * part of the same scope. Lastly, not all possible C++ namespace names
36  * are valid D identifier.
37  *
38  * See_Also:    https://github.com/dlang/dmd/pull/10031
39  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
40  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
41  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
42  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d)
43  * Documentation:  https://dlang.org/phobos/dmd_nspace.html
44  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nspace.d
45  */
46 
47 module dmd.nspace;
48 
49 import dmd.aggregate;
50 import dmd.arraytypes;
51 import dmd.dscope;
52 import dmd.dsymbol;
53 import dmd.dsymbolsem;
54 import dmd.expression;
55 import dmd.globals;
56 import dmd.identifier;
57 import dmd.visitor;
58 import core.stdc.stdio;
59 
60 private enum LOG = false;
61 
62 /// Ditto
63 extern (C++) final class Nspace : ScopeDsymbol
64 {
65     /**
66      * Namespace identifier resolved during semantic.
67      */
68     Expression identExp;
69 
70     extern (D) this(const ref Loc loc, Identifier ident, Expression identExp, Dsymbols* members)
71     {
72         super(loc, ident);
73         //printf("Nspace::Nspace(ident = %s)\n", ident.toChars());
74         this.members = members;
75         this.identExp = identExp;
76     }
77 
78     override Dsymbol syntaxCopy(Dsymbol s)
79     {
80         auto ns = new Nspace(loc, ident, identExp, null);
81         return ScopeDsymbol.syntaxCopy(ns);
82     }
83 
84     override void addMember(Scope* sc, ScopeDsymbol sds)
85     {
86         ScopeDsymbol.addMember(sc, sds);
87 
88         if (members)
89         {
90             if (!symtab)
91                 symtab = new DsymbolTable();
92             // The namespace becomes 'imported' into the enclosing scope
93             for (Scope* sce = sc; 1; sce = sce.enclosing)
94             {
95                 ScopeDsymbol sds2 = sce.scopesym;
96                 if (sds2)
97                 {
98                     sds2.importScope(this, Prot(Prot.Kind.public_));
99                     break;
100                 }
101             }
102             assert(sc);
103             sc = sc.push(this);
104             sc.linkage = LINK.cpp; // namespaces default to C++ linkage
105             sc.parent = this;
106             members.foreachDsymbol(s => s.addMember(sc, this));
107             sc.pop();
108         }
109     }
110 
111     override void setScope(Scope* sc)
112     {
113         ScopeDsymbol.setScope(sc);
114         if (members)
115         {
116             assert(sc);
117             sc = sc.push(this);
118             sc.linkage = LINK.cpp; // namespaces default to C++ linkage
119             sc.parent = this;
120             members.foreachDsymbol(s => s.setScope(sc));
121             sc.pop();
122         }
123     }
124 
125     override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
126     {
127         //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
128         if (_scope && !symtab)
129             dsymbolSemantic(this, _scope);
130 
131         if (!members || !symtab) // opaque or semantic() is not yet called
132         {
133             error("is forward referenced when looking for `%s`", ident.toChars());
134             return null;
135         }
136 
137         return ScopeDsymbol.search(loc, ident, flags);
138     }
139 
140     override bool hasPointers()
141     {
142         //printf("Nspace::hasPointers() %s\n", toChars());
143         return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
144     }
145 
146     override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion)
147     {
148         //printf("Nspace::setFieldOffset() %s\n", toChars());
149         if (_scope) // if fwd reference
150             dsymbolSemantic(this, null); // try to resolve it
151         members.foreachDsymbol( s => s.setFieldOffset(ad, poffset, isunion) );
152     }
153 
154     override const(char)* kind() const
155     {
156         return "namespace";
157     }
158 
159     override inout(Nspace) isNspace() inout
160     {
161         return this;
162     }
163 
164     override void accept(Visitor v)
165     {
166         v.visit(this);
167     }
168 }