blob: 40f2676d88f5e14a2edce7871f1ba45c6903e57f [file] [log] [blame]
/**
* 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);
}
}