Parse template specialization arguments

- Falls back to Value when it can't figure it out
This commit is contained in:
Dustin Spicuzza 2020-12-30 02:52:02 -05:00
parent 0c9c49b7e3
commit cd110bbe29
2 changed files with 63 additions and 18 deletions

View File

@ -5,7 +5,7 @@ import re
import typing
from .errors import CxxParseError
from .lexer import Lexer, LexToken, Location
from .lexer import Lexer, LexToken, Location, PhonyEnding
from .options import ParserOptions
from .parserstate import (
BlockState,
@ -559,24 +559,52 @@ class CxxParser:
"""
args: typing.List[TemplateArgument] = []
param_pack = False
# On entry, < has just been consumed
while True:
raw_name = self._consume_value_until([], ",", ">", "...")
raw_name = [Token(tok.value, tok.type) for tok in raw_name]
args.append(TemplateArgument(raw_name))
tok = self._next_token_must_be(",", ">", "ELLIPSIS")
# We don't know whether each argument will be a type or an expression.
# Retrieve the expression first, then try to parse the name using those
# 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)
dtype = None
if raw_toks and raw_toks[0].type in self._pqname_start_tokens:
# append a token to make other parsing components happy
raw_toks.append(PhonyEnding)
with self.lex.set_group_of_tokens(raw_toks) as remainder:
try:
parsed_type, mods = self._parse_type(None)
mods.validate(var_ok=False, meth_ok=False, msg="")
dtype = self._parse_cv_ptr(parsed_type, nonptr_fn=True)
self._next_token_must_be(PhonyEnding.type)
except CxxParseError:
dtype = None
else:
if remainder:
dtype = None
if self.lex.token_if("ELLIPSIS"):
param_pack = True
if dtype:
args.append(TemplateArgument(dtype, has_typename, param_pack))
else:
args.append(TemplateArgument(val, has_typename, param_pack))
tok = self._next_token_must_be(",", ">")
if tok.type == ">":
break
elif tok.type == "ELLIPSIS":
param_pack = True
self._next_token_must_be(">")
break
return TemplateSpecialization(args, param_pack)
return TemplateSpecialization(args)
#
# Attributes
@ -1666,8 +1694,11 @@ class CxxParser:
return Array(dtype, value)
def _parse_cv_ptr(
self, dtype: typing.Union[Array, FunctionType, Pointer, Type]
self,
dtype: typing.Union[Array, FunctionType, Pointer, Type],
nonptr_fn: bool = False,
) -> DecoratedType:
# nonptr_fn is for parsing function types directly in template specialization
while True:
tok = self.lex.token_if("*", "const", "volatile", "(")
@ -1680,6 +1711,19 @@ class CxxParser:
dtype.const = True
elif tok.type == "volatile":
dtype.volatile = True
elif nonptr_fn:
# remove any inner grouping parens
while True:
gtok = self.lex.token_if("(")
if not gtok:
break
toks = self._consume_balanced_tokens(gtok)
self.lex.return_tokens(toks[1:-1])
fn_params, vararg = self._parse_parameters()
dtype = FunctionType(dtype, fn_params, vararg)
else:
# Check to see if this is a grouping paren or something else
if not self.lex.token_peek_if("*", "&"):

View File

@ -188,9 +188,13 @@ class TemplateArgument:
"""
#: This contains unparsed arbitrary expressions, including additional
#: specializations or decltypes or whatever
tokens: typing.List[Token]
#: If this argument is a type, it is stored here as a DecoratedType,
#: 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
@dataclass
@ -207,9 +211,6 @@ class TemplateSpecialization:
args: typing.List[TemplateArgument]
#: If True, indicates a parameter pack (...) on the last parameter
param_pack: bool = False
@dataclass
class FunctionType: