Skip to content

Commit 7634566

Browse files
committed
Support extern template declarations
1 parent 8c54f68 commit 7634566

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

CppHeaderParser/CppHeaderParser.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,10 @@ def __str__(self):
14251425
return self["value"]
14261426

14271427

1428+
class CppExternTemplate(dict):
1429+
pass
1430+
1431+
14281432
# Implementation is shared between CppPragma, CppDefine, CppInclude but they are
14291433
# distinct so that they may diverge if required without interface-breaking
14301434
# changes
@@ -2747,6 +2751,8 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
27472751
#: List of enums in this header as :class:`.CppEnum`
27482752
self.enums = []
27492753

2754+
self.extern_templates = []
2755+
27502756
#: List of variables in this header as :class:`.CppVariable`
27512757
self.variables = []
27522758
self.global_enums = {}
@@ -2879,7 +2885,7 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs):
28792885
break
28802886
tok.value = TagStr(tok.value, location=tok.location)
28812887

2882-
# debug_print("TOK: %s", tok)
2888+
debug_print("TOK: %s", tok)
28832889
if tok.type == "NAME":
28842890
if tok.value in self.IGNORE_NAMES:
28852891
continue
@@ -3459,6 +3465,21 @@ def _evaluate_stack(self, token=None):
34593465
self.curTemplate = None
34603466

34613467
def _parse_template(self):
3468+
# check for 'extern template'
3469+
extern_template = False
3470+
if len(self.stmtTokens) == 1 and self.stmtTokens[0].value == "extern":
3471+
extern_template = True
3472+
tok = self._next_token_must_be("NAME")
3473+
if not tok.value == "class":
3474+
raise self._parse_error((tok,), "class")
3475+
3476+
tok = self._next_token_must_be("NAME")
3477+
if tok.value == "__attribute__":
3478+
self._parse_gcc_attribute()
3479+
tok = self._next_token_must_be("NAME")
3480+
3481+
extern_template_name = tok.value
3482+
34623483
tok = self._next_token_must_be("<")
34633484
consumed = self._consume_balanced_tokens(tok)
34643485
tmpl = " ".join(tok.value for tok in consumed)
@@ -3471,7 +3492,20 @@ def _parse_template(self):
34713492
.replace(" , ", ", ")
34723493
.replace(" = ", "=")
34733494
)
3474-
self.curTemplate = "template" + tmpl
3495+
3496+
if extern_template:
3497+
self.extern_templates.append(
3498+
CppExternTemplate(
3499+
name=extern_template_name,
3500+
params=tmpl,
3501+
namespace=self.cur_namespace(),
3502+
)
3503+
)
3504+
self.stack = []
3505+
self.nameStack = []
3506+
self.stmtTokens = []
3507+
else:
3508+
self.curTemplate = "template" + tmpl
34753509

34763510
def _parse_gcc_attribute(self):
34773511
tok1 = self._next_token_must_be("(")

test/test_CppHeaderParser.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4078,5 +4078,37 @@ 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+
40814113
if __name__ == "__main__":
40824114
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