/** * A scoped C++ namespace symbol * * D supports the following syntax to declare symbol(s) as being part of a * C++ namespace: * --- * extern (C++, "myNamespace") { /+ Symbols +/ } // String variant * extern (C++, SomeNamespace) { /+ Other symbols +/ } // Identifier variant * --- * The first form is an attribute and only affects mangling, and is implemented * in `dmd.attrib`. * The second form introduces a named scope and allows symbols to be refered * to with or without the namespace name, much like a named template mixin, * and is implemented in this module. * --- * extern (C++, Basket) * { * struct StrawBerry; * void swapFood (Strawberry* f1, Strawberry* f2); * } * void main () * { * Basket.StrawBerry fruit1; * StrawBerry fruit2; * Basket.swapFood(fruit1, fruit2); * swapFood(fruit1, fruit2); * } * --- * Hence the `Nspace` symbol implements the usual `ScopeDsymbol` semantics. * * Note that it implies `extern(C++)` so it cannot be used as a generic * named scope. Additionally, `Nspace` with the same `Identifier` can be * defined in different module (as C++ allows a namespace to be spread accross * translation units), but symbols in it should be considered * part of the same scope. Lastly, not all possible C++ namespace names * are valid D identifier. * * See_Also: https://github.com/dlang/dmd/pull/10031 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d) * Documentation: https://dlang.org/phobos/dmd_nspace.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nspace.d */ module dmd.nspace; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.expression; import dmd.globals; import dmd.identifier; import dmd.visitor; import core.stdc.stdio; private enum LOG = false; /// Ditto extern (C++) final class Nspace : ScopeDsymbol { /** * Namespace identifier resolved during semantic. */ Expression identExp; extern (D) this(const ref Loc loc, Identifier ident, Expression identExp, Dsymbols* members) { super(loc, ident); //printf("Nspace::Nspace(ident = %s)\n", ident.toChars()); this.members = members; this.identExp = identExp; } override Nspace syntaxCopy(Dsymbol s) { auto ns = new Nspace(loc, ident, identExp, null); ScopeDsymbol.syntaxCopy(ns); return ns; } override void addMember(Scope* sc, ScopeDsymbol sds) { ScopeDsymbol.addMember(sc, sds); if (members) { if (!symtab) symtab = new DsymbolTable(); // The namespace becomes 'imported' into the enclosing scope for (Scope* sce = sc; 1; sce = sce.enclosing) { ScopeDsymbol sds2 = sce.scopesym; if (sds2) { sds2.importScope(this, Visibility(Visibility.Kind.public_)); break; } } assert(sc); sc = sc.push(this); sc.linkage = LINK.cpp; // namespaces default to C++ linkage sc.parent = this; members.foreachDsymbol(s => s.addMember(sc, this)); sc.pop(); } } override void setScope(Scope* sc) { ScopeDsymbol.setScope(sc); if (members) { assert(sc); sc = sc.push(this); sc.linkage = LINK.cpp; // namespaces default to C++ linkage sc.parent = this; members.foreachDsymbol(s => s.setScope(sc)); sc.pop(); } } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); if (_scope && !symtab) dsymbolSemantic(this, _scope); if (!members || !symtab) // opaque or semantic() is not yet called { if (!(flags & IgnoreErrors)) error("is forward referenced when looking for `%s`", ident.toChars()); return null; } return ScopeDsymbol.search(loc, ident, flags); } override bool hasPointers() { //printf("Nspace::hasPointers() %s\n", toChars()); return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) { //printf("Nspace::setFieldOffset() %s\n", toChars()); if (_scope) // if fwd reference dsymbolSemantic(this, null); // try to resolve it members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); } override const(char)* kind() const { return "namespace"; } override inout(Nspace) isNspace() inout { return this; } override void accept(Visitor v) { v.visit(this); } }