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 import typing
from .errors import CxxParseError from .errors import CxxParseError
from .lexer import Lexer, LexToken, Location from .lexer import Lexer, LexToken, Location, PhonyEnding
from .options import ParserOptions from .options import ParserOptions
from .parserstate import ( from .parserstate import (
BlockState, BlockState,
@ -559,24 +559,52 @@ class CxxParser:
""" """
args: typing.List[TemplateArgument] = [] args: typing.List[TemplateArgument] = []
param_pack = False
# On entry, < has just been consumed # On entry, < has just been consumed
while True: 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 == ">": if tok.type == ">":
break break
elif tok.type == "ELLIPSIS":
param_pack = True
self._next_token_must_be(">")
break
return TemplateSpecialization(args, param_pack) return TemplateSpecialization(args)
# #
# Attributes # Attributes
@ -1666,8 +1694,11 @@ class CxxParser:
return Array(dtype, value) return Array(dtype, value)
def _parse_cv_ptr( 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: ) -> DecoratedType:
# nonptr_fn is for parsing function types directly in template specialization
while True: while True:
tok = self.lex.token_if("*", "const", "volatile", "(") tok = self.lex.token_if("*", "const", "volatile", "(")
@ -1680,6 +1711,19 @@ class CxxParser:
dtype.const = True dtype.const = True
elif tok.type == "volatile": elif tok.type == "volatile":
dtype.volatile = True 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: else:
# Check to see if this is a grouping paren or something else # Check to see if this is a grouping paren or something else
if not self.lex.token_peek_if("*", "&"): if not self.lex.token_peek_if("*", "&"):

View File

@ -188,9 +188,13 @@ class TemplateArgument:
""" """
#: This contains unparsed arbitrary expressions, including additional #: If this argument is a type, it is stored here as a DecoratedType,
#: specializations or decltypes or whatever #: otherwise it's stored as an unparsed set of values
tokens: typing.List[Token] arg: typing.Union["DecoratedType", Value]
#: Set if starts with "typename"
has_typename: bool = False
param_pack: bool = False
@dataclass @dataclass
@ -207,9 +211,6 @@ class TemplateSpecialization:
args: typing.List[TemplateArgument] args: typing.List[TemplateArgument]
#: If True, indicates a parameter pack (...) on the last parameter
param_pack: bool = False
@dataclass @dataclass
class FunctionType: class FunctionType: