Support using 'typename' qualifier before type names

- Fixes #7
This commit is contained in:
Dustin Spicuzza 2021-01-09 12:54:45 -05:00
parent 07b63127f7
commit 3c51a30efe
4 changed files with 125 additions and 11 deletions

View File

@ -574,7 +574,6 @@ class CxxParser:
# tokens. If it succeeds we're done, otherwise we use the value
param_pack = False
has_typename = True if self.lex.token_if("typename") else False
raw_toks = self._consume_value_until([], ",", ">", "ELLIPSIS")
val = self._create_value(raw_toks)
@ -601,9 +600,9 @@ class CxxParser:
param_pack = True
if dtype:
args.append(TemplateArgument(dtype, has_typename, param_pack))
args.append(TemplateArgument(dtype, param_pack))
else:
args.append(TemplateArgument(val, has_typename, param_pack))
args.append(TemplateArgument(val, param_pack))
tok = self._next_token_must_be(",", ">")
if tok.type == ">":
@ -1251,7 +1250,7 @@ class CxxParser:
return parts
_pqname_start_tokens = (
{"auto", "decltype", "NAME", "operator", "template", "DBL_COLON"}
{"auto", "decltype", "NAME", "operator", "template", "typename", "DBL_COLON"}
| _name_compound_start
| _fundamentals
)
@ -1329,6 +1328,7 @@ class CxxParser:
classkey = None
segments: typing.List[PQNameSegment] = []
op = None
has_typename = False
if tok is None:
tok = self.lex.token()
@ -1369,6 +1369,11 @@ class CxxParser:
self.anon_id += 1
segments.append(AnonymousName(self.anon_id))
return PQName(segments, classkey), None
elif tok.type == "typename":
has_typename = True
tok = self.lex.token()
if tok.type not in self._pqname_start_tokens:
raise self._parse_error(tok)
# First section of the name: Add empty segment if starting out with a
# namespace specifier
@ -1415,7 +1420,7 @@ class CxxParser:
tok = self._next_token_must_be("NAME", "operator", "template", "decltype")
pqname = PQName(segments, classkey)
pqname = PQName(segments, classkey, has_typename)
self.debug_print(
"parse_pqname: %s op=%s",

View File

@ -140,6 +140,9 @@ class PQName:
#: Set if the name starts with class/enum/struct
classkey: typing.Optional[str] = None
#: Set to true if the type was preceded with 'typename'
has_typename: bool = False
@dataclass
class Enumerator:
@ -192,8 +195,6 @@ class TemplateArgument:
#: otherwise it's stored as an unparsed set of values
arg: typing.Union["DecoratedType", Value]
#: Set if starts with "typename"
has_typename: bool = False
param_pack: bool = False

View File

@ -17,6 +17,7 @@ from cxxheaderparser.types import (
TemplateTypeParam,
Token,
Type,
Value,
)
from cxxheaderparser.simple import (
NamespaceScope,
@ -71,6 +72,61 @@ def test_fn_returns_class():
)
def test_fn_returns_typename():
content = """
typename ns::X fn();
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(
segments=[
NameSpecifier(name="ns"),
NameSpecifier(name="X"),
],
has_typename=True,
)
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[],
)
]
)
)
def test_fn_returns_typename_const():
content = """
const typename ns::X fn();
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(
segments=[
NameSpecifier(name="ns"),
NameSpecifier(name="X"),
],
has_typename=True,
),
const=True,
),
name=PQName(segments=[NameSpecifier(name="fn")]),
parameters=[],
)
]
)
)
def test_fn_pointer_params():
content = """
int fn1(int *);
@ -194,6 +250,58 @@ def test_fn_array_param():
)
def test_fn_typename_param():
content = """
void MethodA(const mynamespace::SomeObject &x,
typename mynamespace::SomeObject * = 0);
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="void")])
),
name=PQName(segments=[NameSpecifier(name="MethodA")]),
parameters=[
Parameter(
type=Reference(
ref_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="mynamespace"),
NameSpecifier(name="SomeObject"),
]
),
const=True,
)
),
name="x",
),
Parameter(
type=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
NameSpecifier(name="mynamespace"),
NameSpecifier(name="SomeObject"),
],
has_typename=True,
)
)
),
default=Value(tokens=[Token(value="0")]),
),
],
)
]
)
)
def test_fn_weird_refs():
content = """
int aref(int(&x));

View File

@ -1702,10 +1702,10 @@ def test_template_specialized_fn_typename():
segments=[
NameSpecifier(name=""),
NameSpecifier(name="T"),
]
],
has_typename=True,
)
),
has_typename=True,
)
]
),
@ -1795,10 +1795,10 @@ def test_template_specialized_fn_typename_template():
]
),
),
]
],
has_typename=True,
)
),
has_typename=True,
)
]
),