Parse template specialization arguments
- Falls back to Value when it can't figure it out
This commit is contained in:
parent
0c9c49b7e3
commit
cd110bbe29
@ -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("*", "&"):
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user