diff --git a/CppHeaderParser/CppHeaderParser.py b/CppHeaderParser/CppHeaderParser.py index 0d6b76c..87dae7d 100644 --- a/CppHeaderParser/CppHeaderParser.py +++ b/CppHeaderParser/CppHeaderParser.py @@ -1207,7 +1207,7 @@ class CppVariable(_CppVariable): Vars = [] - def __init__(self, nameStack, doxygen, location, **kwargs): + def __init__(self, nameStack, doxygen, location, is_var=True, **kwargs): debug_print("var trace %s", nameStack) if len(nameStack) and nameStack[0] == "extern": self["extern"] = True @@ -1297,7 +1297,8 @@ def __init__(self, nameStack, doxygen, location, **kwargs): pass self.init() - CppVariable.Vars.append(self) # save and resolve later + if is_var: + CppVariable.Vars.append(self) # save and resolve later def _filter_name(self, name): name = name.replace(" :", ":").replace(": ", ":") @@ -1425,6 +1426,10 @@ def __str__(self): return self["value"] +class CppExternTemplate(dict): + pass + + # Implementation is shared between CppPragma, CppDefine, CppInclude but they are # distinct so that they may diverge if required without interface-breaking # changes @@ -2747,6 +2752,8 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs): #: List of enums in this header as :class:`.CppEnum` self.enums = [] + self.extern_templates = [] + #: List of variables in this header as :class:`.CppVariable` self.variables = [] self.global_enums = {} @@ -2879,7 +2886,7 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs): break tok.value = TagStr(tok.value, location=tok.location) - # debug_print("TOK: %s", tok) + debug_print("TOK: %s", tok) if tok.type == "NAME": if tok.value in self.IGNORE_NAMES: continue @@ -3353,7 +3360,10 @@ def _evaluate_stack(self, token=None): alias = self.nameStack[1] ns, stack = _split_namespace(self.nameStack[3:]) atype = CppVariable( - stack, self._get_stmt_doxygen(), self._get_location(stack) + stack, + self._get_stmt_doxygen(), + self._get_location(stack), + is_var=False, ) # namespace refers to the embedded type @@ -3368,7 +3378,10 @@ def _evaluate_stack(self, token=None): # from a base class ns, stack = _split_namespace(self.nameStack[1:]) atype = CppVariable( - stack, self._get_stmt_doxygen(), self._get_location(stack) + stack, + self._get_stmt_doxygen(), + self._get_location(stack), + is_var=False, ) alias = atype["type"] atype["using_type"] = "declaration" @@ -3377,6 +3390,9 @@ def _evaluate_stack(self, token=None): else: atype["namespace"] = ns + atype["template"] = self.curTemplate + self.curTemplate = None + if atype["type"].startswith("typename "): atype["raw_type"] = "typename " + ns + atype["type"][9:] else: @@ -3459,6 +3475,21 @@ def _evaluate_stack(self, token=None): self.curTemplate = None def _parse_template(self): + # check for 'extern template' + extern_template = False + if len(self.stmtTokens) == 1 and self.stmtTokens[0].value == "extern": + extern_template = True + tok = self._next_token_must_be("NAME") + if not tok.value == "class": + raise self._parse_error((tok,), "class") + + tok = self._next_token_must_be("NAME") + if tok.value == "__attribute__": + self._parse_gcc_attribute() + tok = self._next_token_must_be("NAME") + + extern_template_name = tok.value + tok = self._next_token_must_be("<") consumed = self._consume_balanced_tokens(tok) tmpl = " ".join(tok.value for tok in consumed) @@ -3471,7 +3502,20 @@ def _parse_template(self): .replace(" , ", ", ") .replace(" = ", "=") ) - self.curTemplate = "template" + tmpl + + if extern_template: + self.extern_templates.append( + CppExternTemplate( + name=extern_template_name, + params=tmpl, + namespace=self.cur_namespace(), + ) + ) + self.stack = [] + self.nameStack = [] + self.stmtTokens = [] + else: + self.curTemplate = "template" + tmpl def _parse_gcc_attribute(self): tok1 = self._next_token_must_be("(") diff --git a/docs/conf.py b/docs/conf.py index 696192f..cc167b2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,8 +31,8 @@ master_doc = "index" # General information about the project. -project = u"robotpy-cppheaderparser" -copyright = u"2019 RobotPy Development Team" +project = "robotpy-cppheaderparser" +copyright = "2019 RobotPy Development Team" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -200,8 +200,8 @@ ( "index", "sphinx.tex", - u"robotpy-cppheaderparser Documentation", - u"Author", + "robotpy-cppheaderparser Documentation", + "Author", "manual", ) ] @@ -232,7 +232,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ("index", "sphinx", u"robotpy-cppheaderparser Documentation", [u"Author"], 1) + ("index", "sphinx", "robotpy-cppheaderparser Documentation", ["Author"], 1) ] # If true, show URL addresses after external links. @@ -248,8 +248,8 @@ ( "index", "sphinx", - u"robotpy-cppheaderparser Documentation", - u"Author", + "robotpy-cppheaderparser Documentation", + "Author", "sphinx", "One line description of project.", "Miscellaneous", @@ -272,10 +272,10 @@ # -- Options for Epub output ---------------------------------------------- # Bibliographic Dublin Core info. -epub_title = u"robotpy-cppheaderparser" -epub_author = u"RobotPy Development Team" -epub_publisher = u"RobotPy Development Team" -epub_copyright = u"2019 RobotPy Development Team" +epub_title = "robotpy-cppheaderparser" +epub_author = "RobotPy Development Team" +epub_publisher = "RobotPy Development Team" +epub_copyright = "2019 RobotPy Development Team" # The basename for the epub file. It defaults to the project name. # epub_basename = u'..' diff --git a/test/test_CppHeaderParser.py b/test/test_CppHeaderParser.py index 374658c..8337858 100644 --- a/test/test_CppHeaderParser.py +++ b/test/test_CppHeaderParser.py @@ -4078,5 +4078,62 @@ def test_fn(self): self.assertEqual(c.typedefs["mmmmp"], "typedef int ( * ) ( int , int )") +class ExternTemplateTest(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +extern template class MyClass<1,2>; +extern template class __attribute__(("something")) MyClass<3,4>; + +namespace foo { +extern template class MyClass<5,6>; +}; + +""", + "string", + ) + + def test_fn(self): + c = self.cppHeader + et0, et1, et2 = c.extern_templates + + self.assertEqual(et0["name"], "MyClass") + self.assertEqual(et0["namespace"], "") + self.assertEqual(et0["params"], "<1, 2>") + + self.assertEqual(et1["name"], "MyClass") + self.assertEqual(et1["namespace"], "") + self.assertEqual(et1["params"], "<3, 4>") + + self.assertEqual(et2["name"], "MyClass") + self.assertEqual(et2["namespace"], "foo") + self.assertEqual(et2["params"], "<5, 6>") + + +class UsingTemplateTest(unittest.TestCase): + def setUp(self): + self.cppHeader = CppHeaderParser.CppHeader( + """ +class X { + template + using TT = U; +}; + +""", + "string", + ) + + def test_fn(self): + u = self.cppHeader.classes["X"]["using"] + self.assertEqual(len(u), 1) + tt = u["TT"] + + self.assertEqual(tt["access"], "private") + self.assertEqual(tt["raw_type"], "U") + self.assertEqual(tt["type"], "U") + self.assertEqual(tt["typealias"], "TT") + self.assertEqual(tt["template"], "template") + + if __name__ == "__main__": unittest.main() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy