Skip to content

Commit 77d2c98

Browse files
authored
Merge pull request #78 from robotpy/more-madness
More madness
2 parents 8c54f68 + f98128c commit 77d2c98

File tree

3 files changed

+118
-17
lines changed

3 files changed

+118
-17
lines changed

CppHeaderParser/CppHeaderParser.py

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,7 +1207,7 @@ class CppVariable(_CppVariable):
12071207

12081208
Vars = []
12091209

1210-
def __init__(self, nameStack, doxygen, location, **kwargs):
1210+
def __init__(self, nameStack, doxygen, location, is_var=True, **kwargs):
12111211
debug_print("var trace %s", nameStack)
12121212
if len(nameStack) and nameStack[0] == "extern":
12131213
self["extern"] = True
@@ -1297,7 +1297,8 @@ def __init__(self, nameStack, doxygen, location, **kwargs):
12971297
pass
12981298

12991299
self.init()
1300-
CppVariable.Vars.append(self) # save and resolve later
1300+
if is_var:
1301+
CppVariable.Vars.append(self) # save and resolve later
13011302

13021303
def _filter_name(self, name):
13031304
name = name.replace(" :", ":").replace(": ", ":")
@@ -1425,6 +1426,10 @@ def __str__(self):
14251426
return self["value"]
14261427

14271428

1429+
class CppExternTemplate(dict):
1430+
pass
1431+
1432+
14281433
# Implementation is shared between CppPragma, CppDefine, CppInclude but they are
14291434
# distinct so that they may diverge if required without interface-breaking
14301435
# changes
@@ -2747,6 +2752,8 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
27472752
#: List of enums in this header as :class:`.CppEnum`
27482753
self.enums = []
27492754

2755+
self.extern_templates = []
2756+
27502757
#: List of variables in this header as :class:`.CppVariable`
27512758
self.variables = []
27522759
self.global_enums = {}
@@ -2879,7 +2886,7 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
28792886
break
28802887
tok.value = TagStr(tok.value, location=tok.location)
28812888

2882-
# debug_print("TOK: %s", tok)
2889+
debug_print("TOK: %s", tok)
28832890
if tok.type == "NAME":
28842891
if tok.value in self.IGNORE_NAMES:
28852892
continue
@@ -3353,7 +3360,10 @@ def _evaluate_stack(self, token=None):
33533360
alias = self.nameStack[1]
33543361
ns, stack = _split_namespace(self.nameStack[3:])
33553362
atype = CppVariable(
3356-
stack, self._get_stmt_doxygen(), self._get_location(stack)
3363+
stack,
3364+
self._get_stmt_doxygen(),
3365+
self._get_location(stack),
3366+
is_var=False,
33573367
)
33583368

33593369
# namespace refers to the embedded type
@@ -3368,7 +3378,10 @@ def _evaluate_stack(self, token=None):
33683378
# from a base class
33693379
ns, stack = _split_namespace(self.nameStack[1:])
33703380
atype = CppVariable(
3371-
stack, self._get_stmt_doxygen(), self._get_location(stack)
3381+
stack,
3382+
self._get_stmt_doxygen(),
3383+
self._get_location(stack),
3384+
is_var=False,
33723385
)
33733386
alias = atype["type"]
33743387
atype["using_type"] = "declaration"
@@ -3377,6 +3390,9 @@ def _evaluate_stack(self, token=None):
33773390
else:
33783391
atype["namespace"] = ns
33793392

3393+
atype["template"] = self.curTemplate
3394+
self.curTemplate = None
3395+
33803396
if atype["type"].startswith("typename "):
33813397
atype["raw_type"] = "typename " + ns + atype["type"][9:]
33823398
else:
@@ -3459,6 +3475,21 @@ def _evaluate_stack(self, token=None):
34593475
self.curTemplate = None
34603476

34613477
def _parse_template(self):
3478+
# check for 'extern template'
3479+
extern_template = False
3480+
if len(self.stmtTokens) == 1 and self.stmtTokens[0].value == "extern":
3481+
extern_template = True
3482+
tok = self._next_token_must_be("NAME")
3483+
if not tok.value == "class":
3484+
raise self._parse_error((tok,), "class")
3485+
3486+
tok = self._next_token_must_be("NAME")
3487+
if tok.value == "__attribute__":
3488+
self._parse_gcc_attribute()
3489+
tok = self._next_token_must_be("NAME")
3490+
3491+
extern_template_name = tok.value
3492+
34623493
tok = self._next_token_must_be("<")
34633494
consumed = self._consume_balanced_tokens(tok)
34643495
tmpl = " ".join(tok.value for tok in consumed)
@@ -3471,7 +3502,20 @@ def _parse_template(self):
34713502
.replace(" , ", ", ")
34723503
.replace(" = ", "=")
34733504
)
3474-
self.curTemplate = "template" + tmpl
3505+
3506+
if extern_template:
3507+
self.extern_templates.append(
3508+
CppExternTemplate(
3509+
name=extern_template_name,
3510+
params=tmpl,
3511+
namespace=self.cur_namespace(),
3512+
)
3513+
)
3514+
self.stack = []
3515+
self.nameStack = []
3516+
self.stmtTokens = []
3517+
else:
3518+
self.curTemplate = "template" + tmpl
34753519

34763520
def _parse_gcc_attribute(self):
34773521
tok1 = self._next_token_must_be("(")

docs/conf.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
master_doc = "index"
3232

3333
# General information about the project.
34-
project = u"robotpy-cppheaderparser"
35-
copyright = u"2019 RobotPy Development Team"
34+
project = "robotpy-cppheaderparser"
35+
copyright = "2019 RobotPy Development Team"
3636

3737
# The version info for the project you're documenting, acts as replacement for
3838
# |version| and |release|, also used in various other places throughout the
@@ -200,8 +200,8 @@
200200
(
201201
"index",
202202
"sphinx.tex",
203-
u"robotpy-cppheaderparser Documentation",
204-
u"Author",
203+
"robotpy-cppheaderparser Documentation",
204+
"Author",
205205
"manual",
206206
)
207207
]
@@ -232,7 +232,7 @@
232232
# One entry per manual page. List of tuples
233233
# (source start file, name, description, authors, manual section).
234234
man_pages = [
235-
("index", "sphinx", u"robotpy-cppheaderparser Documentation", [u"Author"], 1)
235+
("index", "sphinx", "robotpy-cppheaderparser Documentation", ["Author"], 1)
236236
]
237237

238238
# If true, show URL addresses after external links.
@@ -248,8 +248,8 @@
248248
(
249249
"index",
250250
"sphinx",
251-
u"robotpy-cppheaderparser Documentation",
252-
u"Author",
251+
"robotpy-cppheaderparser Documentation",
252+
"Author",
253253
"sphinx",
254254
"One line description of project.",
255255
"Miscellaneous",
@@ -272,10 +272,10 @@
272272
# -- Options for Epub output ----------------------------------------------
273273

274274
# Bibliographic Dublin Core info.
275-
epub_title = u"robotpy-cppheaderparser"
276-
epub_author = u"RobotPy Development Team"
277-
epub_publisher = u"RobotPy Development Team"
278-
epub_copyright = u"2019 RobotPy Development Team"
275+
epub_title = "robotpy-cppheaderparser"
276+
epub_author = "RobotPy Development Team"
277+
epub_publisher = "RobotPy Development Team"
278+
epub_copyright = "2019 RobotPy Development Team"
279279

280280
# The basename for the epub file. It defaults to the project name.
281281
# epub_basename = u'..'

test/test_CppHeaderParser.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4078,5 +4078,62 @@ def test_fn(self):
40784078
self.assertEqual(c.typedefs["mmmmp"], "typedef int ( * ) ( int , int )")
40794079

40804080

4081+
class ExternTemplateTest(unittest.TestCase):
4082+
def setUp(self):
4083+
self.cppHeader = CppHeaderParser.CppHeader(
4084+
"""
4085+
extern template class MyClass<1,2>;
4086+
extern template class __attribute__(("something")) MyClass<3,4>;
4087+
4088+
namespace foo {
4089+
extern template class MyClass<5,6>;
4090+
};
4091+
4092+
""",
4093+
"string",
4094+
)
4095+
4096+
def test_fn(self):
4097+
c = self.cppHeader
4098+
et0, et1, et2 = c.extern_templates
4099+
4100+
self.assertEqual(et0["name"], "MyClass")
4101+
self.assertEqual(et0["namespace"], "")
4102+
self.assertEqual(et0["params"], "<1, 2>")
4103+
4104+
self.assertEqual(et1["name"], "MyClass")
4105+
self.assertEqual(et1["namespace"], "")
4106+
self.assertEqual(et1["params"], "<3, 4>")
4107+
4108+
self.assertEqual(et2["name"], "MyClass")
4109+
self.assertEqual(et2["namespace"], "foo")
4110+
self.assertEqual(et2["params"], "<5, 6>")
4111+
4112+
4113+
class UsingTemplateTest(unittest.TestCase):
4114+
def setUp(self):
4115+
self.cppHeader = CppHeaderParser.CppHeader(
4116+
"""
4117+
class X {
4118+
template <typename T>
4119+
using TT = U<T>;
4120+
};
4121+
4122+
""",
4123+
"string",
4124+
)
4125+
4126+
def test_fn(self):
4127+
u = self.cppHeader.classes["X"]["using"]
4128+
self.assertEqual(len(u), 1)
4129+
tt = u["TT"]
4130+
4131+
self.assertEqual(tt["access"], "private")
4132+
self.assertEqual(tt["raw_type"], "U<T >")
4133+
self.assertEqual(tt["type"], "U<T >")
4134+
self.assertEqual(tt["typealias"], "TT")
4135+
self.assertEqual(tt["template"], "template<typename T>")
4136+
4137+
40814138
if __name__ == "__main__":
40824139
unittest.main()

0 commit comments

Comments
 (0)
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