C++, add namespace push/pop directives.

This commit is contained in:
Jakob Lykke Andersen
2015-09-06 22:28:55 +02:00
parent c9470fac65
commit a22fb0d45f
3 changed files with 115 additions and 7 deletions

View File

@@ -13,6 +13,7 @@ Features added
* #1909: Add "doc" references to Intersphinx inventories. * #1909: Add "doc" references to Intersphinx inventories.
* C++ type alias support (e.g., `.. type:: T = int`) * C++ type alias support (e.g., `.. type:: T = int`)
* C++ template support for classes, functions, type aliases, and variables (#1729, #1314). * C++ template support for classes, functions, type aliases, and variables (#1729, #1314).
* C++, added new scope management directives ``namespace-push`` and ``namespace-pop``.
Bugs fixed Bugs fixed
---------- ----------

View File

@@ -671,10 +671,19 @@ a visibility statement (``public``, ``private`` or ``protected``).
Namespacing Namespacing
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
Declarations in the C++ doamin are as default placed in global scope.
The current scope can be changed using three namespace directives.
They manage a stack declarations where ``cpp:namespace`` resets the stack and
changes a given scope.
The ``cpp:namespace-push`` directive changes the scope to a given inner scope
of the current one.
The ``cpp:namespace-pop`` directive undos the most recent ``cpp:namespace-push``
directive.
.. rst:directive:: .. cpp:namespace:: scope specification .. rst:directive:: .. cpp:namespace:: scope specification
Declarations in the C++ doamin are as default placed in global scope. Changes the current scope for the subsequent objects to the given scope,
The ``namespace`` directive changes the current scope for the subsequent objects. and resets the namespace directive stack.
Note that the namespace does not need to correspond to C++ namespaces, Note that the namespace does not need to correspond to C++ namespaces,
but can end in names of classes, e.g.,:: but can end in names of classes, e.g.,::
@@ -683,7 +692,7 @@ Namespacing
All subsequent objects will be defined as if their name were declared with the scope All subsequent objects will be defined as if their name were declared with the scope
prepended. The subsequent cross-references will be searched for starting in the current scope. prepended. The subsequent cross-references will be searched for starting in the current scope.
Using ``NULL``, ``0``, or ``nullptr`` as the namespace will reset it to the global namespace. Using ``NULL``, ``0``, or ``nullptr`` as the scope will change to global scope.
A namespace declaration can also be templated, e.g.,:: A namespace declaration can also be templated, e.g.,::
@@ -708,6 +717,38 @@ Namespacing
std::vector std::vector
.. rst:directive:: .. cpp:namespace-push:: scope specification
Change the scope relatively to the current scope. For example, after::
.. cpp:namespace:: A::B
.. cpp:namespace-push:: C::D
the current scope will be ``A::B::C::D``.
.. rst:directive:: .. cpp:namespace-pop::
Undo the previous ``cpp:namespace-push`` directive (*not* just pop a scope).
For example, after::
.. cpp:namespace:: A::B
.. cpp:namespace-push:: C::D
.. cpp:namespace-pop::
the current scope will be ``A::B`` (*not* ``A::B::C``).
If no previous ``cpp:namespace-push`` directive has been used, but only a ``cpp:namespace``
directive, then the current scope will be reset to global scope.
That is, ``.. cpp:namespace:: A::B`` is equivalent to::
.. cpp:namespace:: nullptr
.. cpp:namespace-push:: A::B
Info field lists Info field lists
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~

View File

@@ -3444,7 +3444,8 @@ class CPPNamespaceObject(Directive):
env = self.state.document.settings.env env = self.state.document.settings.env
rootSymbol = env.domaindata['cpp']['rootSymbol'] rootSymbol = env.domaindata['cpp']['rootSymbol']
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
env.ref_context['cpp:parentSymbol'] = rootSymbol symbol = rootSymbol
stack = []
else: else:
parser = DefinitionParser(self.arguments[0], self) parser = DefinitionParser(self.arguments[0], self)
try: try:
@@ -3455,8 +3456,71 @@ class CPPNamespaceObject(Directive):
line=self.lineno) line=self.lineno)
name = _make_phony_error_name() name = _make_phony_error_name()
ast = ASTNamespace(name, None) ast = ASTNamespace(name, None)
s = rootSymbol.add_name(ast.nestedName, ast.templatePrefix) symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix)
env.ref_context['cpp:parentSymbol'] = s stack = [symbol]
env.ref_context['cpp:parentSymbol'] = symbol
env.temp_data['cpp:namespaceStack'] = stack
return []
class CPPNamespacePushObject(Directive):
has_content = False
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {}
def warn(self, msg):
self.state_machine.reporter.warning(msg, lineno=self.lineno)
def run(self):
env = self.state.document.settings.env
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
return
parser = DefinitionParser(self.arguments[0], self)
try:
ast = parser.parse_namespace_object()
parser.assert_end()
except DefinitionError as e:
self.state_machine.reporter.warning(e.description,
line=self.lineno)
name = _make_phony_error_name()
ast = ASTNamespace(name, None)
oldParent = env.ref_context.get('cpp:parentSymbol', None)
if not oldParent:
oldParent = env.domaindata['cpp']['rootSymbol']
symbol = oldParent.add_name(ast.nestedName, ast.templatePrefix)
stack = env.temp_data.get('cpp:namespaceStack', [])
stack.append(symbol)
env.ref_context['cpp:parentSymbol'] = symbol
env.temp_data['cpp:namespaceStack'] = stack
return []
class CPPNamespacePopObject(Directive):
has_content = False
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = True
option_spec = {}
def warn(self, msg):
self.state_machine.reporter.warning(msg, lineno=self.lineno)
def run(self):
env = self.state.document.settings.env
stack = env.temp_data.get('cpp:namespaceStack', None)
if not stack or len(stack) == 0:
self.warn("C++ namespace pop on empty stack. Defaulting to gobal scope.")
stack = []
else:
stack.pop()
if len(stack) > 0:
symbol = stack[-1]
else:
symbol = env.domaindata['cpp']['rootSymbol']
env.ref_context['cpp:parentSymbol'] = symbol
env.temp_data['cpp:namespaceStack'] = stack
return [] return []
@@ -3501,7 +3565,9 @@ class CPPDomain(Domain):
'enum-struct': CPPEnumObject, 'enum-struct': CPPEnumObject,
'enum-class': CPPEnumObject, 'enum-class': CPPEnumObject,
'enumerator': CPPEnumeratorObject, 'enumerator': CPPEnumeratorObject,
'namespace': CPPNamespaceObject 'namespace': CPPNamespaceObject,
'namespace-push': CPPNamespacePushObject,
'namespace-pop': CPPNamespacePopObject
} }
roles = { roles = {
'any': CPPXRefRole(), 'any': CPPXRefRole(),