From 763456603410470eea7933e49fb9fb2d3164950c Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Tue, 27 Sep 2022 23:37:12 -0400 Subject: [PATCH 1/3] Support extern template declarations --- CppHeaderParser/CppHeaderParser.py | 38 ++++++++++++++++++++++++++++-- test/test_CppHeaderParser.py | 32 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/CppHeaderParser/CppHeaderParser.py b/CppHeaderParser/CppHeaderParser.py index 0d6b76c..eb5c5ac 100644 --- a/CppHeaderParser/CppHeaderParser.py +++ b/CppHeaderParser/CppHeaderParser.py @@ -1425,6 +1425,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 +2751,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 +2885,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 @@ -3459,6 +3465,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 +3492,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/test/test_CppHeaderParser.py b/test/test_CppHeaderParser.py index 374658c..f5c5d10 100644 --- a/test/test_CppHeaderParser.py +++ b/test/test_CppHeaderParser.py @@ -4078,5 +4078,37 @@ 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>") + + if __name__ == "__main__": unittest.main() From cc0d4a0610a73488ec301bda9332415c37a4e3e9 Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Tue, 27 Sep 2022 23:57:37 -0400 Subject: [PATCH 2/3] Correctly detect templates for 'using' statements --- CppHeaderParser/CppHeaderParser.py | 18 ++++++++++++++---- test/test_CppHeaderParser.py | 25 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/CppHeaderParser/CppHeaderParser.py b/CppHeaderParser/CppHeaderParser.py index eb5c5ac..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(": ", ":") @@ -3359,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 @@ -3374,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" @@ -3383,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: diff --git a/test/test_CppHeaderParser.py b/test/test_CppHeaderParser.py index f5c5d10..8337858 100644 --- a/test/test_CppHeaderParser.py +++ b/test/test_CppHeaderParser.py @@ -4110,5 +4110,30 @@ def test_fn(self): 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() From f98128ce340fb4419800d01751e191ad26fa5177 Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Tue, 27 Sep 2022 23:59:04 -0400 Subject: [PATCH 3/3] Update black formatting --- docs/conf.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) 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'..' 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