parent
1aa9e72ca1
commit
2fe350bf35
@ -35,6 +35,7 @@ from .types import (
|
||||
Method,
|
||||
MoveReference,
|
||||
NameSpecifier,
|
||||
NamespaceAlias,
|
||||
NamespaceDecl,
|
||||
Operator,
|
||||
PQNameSegment,
|
||||
@ -404,13 +405,26 @@ class CxxParser:
|
||||
|
||||
names = []
|
||||
location = tok.location
|
||||
ns_alias: typing.Union[typing.Literal[False], LexToken] = False
|
||||
|
||||
tok = self._next_token_must_be("NAME", "{")
|
||||
if tok.type != "{":
|
||||
endtok = "{"
|
||||
# Check for namespace alias here
|
||||
etok = self.lex.token_if("=")
|
||||
if etok:
|
||||
ns_alias = tok
|
||||
endtok = ";"
|
||||
# They can start with ::
|
||||
maybe_tok = self.lex.token_if("DBL_COLON")
|
||||
if maybe_tok:
|
||||
names.append(maybe_tok.value)
|
||||
tok = self._next_token_must_be("NAME")
|
||||
|
||||
while True:
|
||||
names.append(tok.value)
|
||||
tok = self._next_token_must_be("DBL_COLON", "{")
|
||||
if tok.type == "{":
|
||||
tok = self._next_token_must_be("DBL_COLON", endtok)
|
||||
if tok.type == endtok:
|
||||
break
|
||||
|
||||
tok = self._next_token_must_be("NAME")
|
||||
@ -418,7 +432,10 @@ class CxxParser:
|
||||
if inline and len(names) > 1:
|
||||
raise CxxParseError("a nested namespace definition cannot be inline")
|
||||
|
||||
# TODO: namespace_alias_definition
|
||||
if ns_alias:
|
||||
alias = NamespaceAlias(ns_alias.value, names)
|
||||
self.visitor.on_namespace_alias(self.state, alias)
|
||||
return
|
||||
|
||||
ns = NamespaceDecl(names, inline, doxygen)
|
||||
state = self._push_state(NamespaceBlockState, ns)
|
||||
|
@ -39,6 +39,7 @@ from .types import (
|
||||
FriendDecl,
|
||||
Function,
|
||||
Method,
|
||||
NamespaceAlias,
|
||||
TemplateInst,
|
||||
Typedef,
|
||||
UsingAlias,
|
||||
@ -110,6 +111,7 @@ class NamespaceScope:
|
||||
using: typing.List[UsingDecl] = field(default_factory=list)
|
||||
using_ns: typing.List["UsingNamespace"] = field(default_factory=list)
|
||||
using_alias: typing.List[UsingAlias] = field(default_factory=list)
|
||||
ns_alias: typing.List[NamespaceAlias] = field(default_factory=list)
|
||||
|
||||
#: Explicit template instantiations
|
||||
template_insts: typing.List[TemplateInst] = field(default_factory=list)
|
||||
@ -261,6 +263,10 @@ class SimpleCxxVisitor:
|
||||
self.block = self.block_stack.pop()
|
||||
self.namespace = self.ns_stack.pop()
|
||||
|
||||
def on_namespace_alias(self, state: State, alias: NamespaceAlias) -> None:
|
||||
assert isinstance(self.block, NamespaceScope)
|
||||
self.block.ns_alias.append(alias)
|
||||
|
||||
def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None:
|
||||
self.block.forward_decls.append(fdecl)
|
||||
|
||||
|
@ -38,6 +38,26 @@ class Value:
|
||||
tokens: typing.List[Token]
|
||||
|
||||
|
||||
@dataclass
|
||||
class NamespaceAlias:
|
||||
"""
|
||||
A namespace alias
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
namespace ANS = my::ns;
|
||||
~~~ ~~~~~~
|
||||
|
||||
"""
|
||||
|
||||
alias: str
|
||||
|
||||
#: These are the names (split by ::) for the namespace that this alias
|
||||
#: refers to, but does not include any parent namespace names. It may
|
||||
#: include a leading "::", but does not include a following :: string.
|
||||
names: typing.List[str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class NamespaceDecl:
|
||||
"""
|
||||
|
@ -14,6 +14,7 @@ from .types import (
|
||||
FriendDecl,
|
||||
Function,
|
||||
Method,
|
||||
NamespaceAlias,
|
||||
TemplateInst,
|
||||
Typedef,
|
||||
UsingAlias,
|
||||
@ -94,6 +95,11 @@ class CxxVisitor(Protocol):
|
||||
Called at the end of a ``namespace`` block
|
||||
"""
|
||||
|
||||
def on_namespace_alias(self, state: State, alias: NamespaceAlias) -> None:
|
||||
"""
|
||||
Called when a ``namespace`` alias is encountered
|
||||
"""
|
||||
|
||||
def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None:
|
||||
"""
|
||||
Called when a forward declaration is encountered
|
||||
|
@ -4,6 +4,7 @@ from cxxheaderparser.errors import CxxParseError
|
||||
from cxxheaderparser.types import (
|
||||
ForwardDecl,
|
||||
FundamentalSpecifier,
|
||||
NamespaceAlias,
|
||||
NameSpecifier,
|
||||
PQName,
|
||||
Token,
|
||||
@ -168,3 +169,29 @@ def test_invalid_inline_namespace() -> None:
|
||||
err = "<str>:1: parse error evaluating 'inline': a nested namespace definition cannot be inline"
|
||||
with pytest.raises(CxxParseError, match=re.escape(err)):
|
||||
parse_string(content, cleandoc=True)
|
||||
|
||||
|
||||
def test_ns_alias() -> None:
|
||||
content = """
|
||||
namespace ANS = my::ns;
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
ns_alias=[NamespaceAlias(alias="ANS", names=["my", "ns"])]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_ns_alias_global() -> None:
|
||||
content = """
|
||||
namespace ANS = ::my::ns;
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
ns_alias=[NamespaceAlias(alias="ANS", names=["::", "my", "ns"])]
|
||||
)
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user