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)