Merge pull request #6 from robotpy/fmt-types
Add pretty formatting for types
This commit is contained in:
commit
175815525f
@ -1,7 +1,7 @@
|
|||||||
|
from dataclasses import dataclass, field
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from .lexer import LexToken, PlyLexer, LexerTokenStream
|
from .lexer import LexToken, PlyLexer, LexerTokenStream
|
||||||
from .types import Token
|
|
||||||
|
|
||||||
# key: token type, value: (left spacing, right spacing)
|
# key: token type, value: (left spacing, right spacing)
|
||||||
_want_spacing = {
|
_want_spacing = {
|
||||||
@ -35,6 +35,27 @@ _want_spacing = {
|
|||||||
_want_spacing.update(dict.fromkeys(PlyLexer.keywords, (2, 2)))
|
_want_spacing.update(dict.fromkeys(PlyLexer.keywords, (2, 2)))
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Token:
|
||||||
|
"""
|
||||||
|
In an ideal world, this Token class would not be exposed via the user
|
||||||
|
visible API. Unfortunately, getting to that point would take a significant
|
||||||
|
amount of effort.
|
||||||
|
|
||||||
|
It is not expected that these will change, but they might.
|
||||||
|
|
||||||
|
At the moment, the only supported use of Token objects are in conjunction
|
||||||
|
with the ``tokfmt`` function. As this library matures, we'll try to clarify
|
||||||
|
the expectations around these. File an issue on github if you have ideas!
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: Raw value of the token
|
||||||
|
value: str
|
||||||
|
|
||||||
|
#: Lex type of the token
|
||||||
|
type: str = field(repr=False, compare=False, default="")
|
||||||
|
|
||||||
|
|
||||||
def tokfmt(toks: typing.List[Token]) -> str:
|
def tokfmt(toks: typing.List[Token]) -> str:
|
||||||
"""
|
"""
|
||||||
Helper function that takes a list of tokens and converts them to a string
|
Helper function that takes a list of tokens and converts them to a string
|
||||||
|
@ -1,26 +1,7 @@
|
|||||||
import typing
|
import typing
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
from .tokfmt import tokfmt, Token
|
||||||
@dataclass
|
|
||||||
class Token:
|
|
||||||
"""
|
|
||||||
In an ideal world, this Token class would not be exposed via the user
|
|
||||||
visible API. Unfortunately, getting to that point would take a significant
|
|
||||||
amount of effort.
|
|
||||||
|
|
||||||
It is not expected that these will change, but they might.
|
|
||||||
|
|
||||||
At the moment, the only supported use of Token objects are in conjunction
|
|
||||||
with the ``tokfmt`` function. As this library matures, we'll try to clarify
|
|
||||||
the expectations around these. File an issue on github if you have ideas!
|
|
||||||
"""
|
|
||||||
|
|
||||||
#: Raw value of the token
|
|
||||||
value: str
|
|
||||||
|
|
||||||
#: Lex type of the token
|
|
||||||
type: str = field(repr=False, compare=False, default="")
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -37,6 +18,9 @@ class Value:
|
|||||||
#: Tokens corresponding to the value
|
#: Tokens corresponding to the value
|
||||||
tokens: typing.List[Token]
|
tokens: typing.List[Token]
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
return tokfmt(self.tokens)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NamespaceAlias:
|
class NamespaceAlias:
|
||||||
@ -94,6 +78,9 @@ class DecltypeSpecifier:
|
|||||||
#: Unparsed tokens within the decltype
|
#: Unparsed tokens within the decltype
|
||||||
tokens: typing.List[Token]
|
tokens: typing.List[Token]
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
return f"decltype({tokfmt(self.tokens)})"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FundamentalSpecifier:
|
class FundamentalSpecifier:
|
||||||
@ -107,6 +94,9 @@ class FundamentalSpecifier:
|
|||||||
|
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NameSpecifier:
|
class NameSpecifier:
|
||||||
@ -124,6 +114,12 @@ class NameSpecifier:
|
|||||||
|
|
||||||
specialization: typing.Optional["TemplateSpecialization"] = None
|
specialization: typing.Optional["TemplateSpecialization"] = None
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
if self.specialization:
|
||||||
|
return f"{self.name}{self.specialization.format()}"
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AutoSpecifier:
|
class AutoSpecifier:
|
||||||
@ -133,6 +129,9 @@ class AutoSpecifier:
|
|||||||
|
|
||||||
name: str = "auto"
|
name: str = "auto"
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AnonymousName:
|
class AnonymousName:
|
||||||
@ -145,6 +144,10 @@ class AnonymousName:
|
|||||||
#: Unique id associated with this name (only unique per parser instance!)
|
#: Unique id associated with this name (only unique per parser instance!)
|
||||||
id: int
|
id: int
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
# TODO: not sure what makes sense here, subject to change
|
||||||
|
return f"<<id={self.id}>>"
|
||||||
|
|
||||||
|
|
||||||
PQNameSegment = typing.Union[
|
PQNameSegment = typing.Union[
|
||||||
AnonymousName, FundamentalSpecifier, NameSpecifier, DecltypeSpecifier, AutoSpecifier
|
AnonymousName, FundamentalSpecifier, NameSpecifier, DecltypeSpecifier, AutoSpecifier
|
||||||
@ -170,6 +173,13 @@ class PQName:
|
|||||||
#: Set to true if the type was preceded with 'typename'
|
#: Set to true if the type was preceded with 'typename'
|
||||||
has_typename: bool = False
|
has_typename: bool = False
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
tn = "typename " if self.has_typename else ""
|
||||||
|
if self.classkey:
|
||||||
|
return f"{tn}{self.classkey} {'::'.join(seg.format() for seg in self.segments)}"
|
||||||
|
else:
|
||||||
|
return tn + "::".join(seg.format() for seg in self.segments)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TemplateArgument:
|
class TemplateArgument:
|
||||||
@ -189,6 +199,12 @@ class TemplateArgument:
|
|||||||
|
|
||||||
param_pack: bool = False
|
param_pack: bool = False
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
if self.param_pack:
|
||||||
|
return f"{self.arg.format()}..."
|
||||||
|
else:
|
||||||
|
return self.arg.format()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TemplateSpecialization:
|
class TemplateSpecialization:
|
||||||
@ -204,6 +220,9 @@ class TemplateSpecialization:
|
|||||||
|
|
||||||
args: typing.List[TemplateArgument]
|
args: typing.List[TemplateArgument]
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
return f"<{', '.join(arg.format() for arg in self.args)}>"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FunctionType:
|
class FunctionType:
|
||||||
@ -238,6 +257,23 @@ class FunctionType:
|
|||||||
#: calling convention
|
#: calling convention
|
||||||
msvc_convention: typing.Optional[str] = None
|
msvc_convention: typing.Optional[str] = None
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
vararg = "..." if self.vararg else ""
|
||||||
|
params = ", ".join(p.format() for p in self.parameters)
|
||||||
|
if self.has_trailing_return:
|
||||||
|
return f"auto ({params}{vararg}) -> {self.return_type.format()}"
|
||||||
|
else:
|
||||||
|
return f"{self.return_type.format()} ({params}{vararg})"
|
||||||
|
|
||||||
|
def format_decl(self, name: str) -> str:
|
||||||
|
"""Format as a named declaration"""
|
||||||
|
vararg = "..." if self.vararg else ""
|
||||||
|
params = ", ".join(p.format() for p in self.parameters)
|
||||||
|
if self.has_trailing_return:
|
||||||
|
return f"auto {name}({params}{vararg}) -> {self.return_type.format()}"
|
||||||
|
else:
|
||||||
|
return f"{self.return_type.format()} {name}({params}{vararg})"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Type:
|
class Type:
|
||||||
@ -250,6 +286,17 @@ class Type:
|
|||||||
const: bool = False
|
const: bool = False
|
||||||
volatile: bool = False
|
volatile: bool = False
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
c = "const " if self.const else ""
|
||||||
|
v = "volatile " if self.volatile else ""
|
||||||
|
return f"{c}{v}{self.typename.format()}"
|
||||||
|
|
||||||
|
def format_decl(self, name: str):
|
||||||
|
"""Format as a named declaration"""
|
||||||
|
c = "const " if self.const else ""
|
||||||
|
v = "volatile " if self.volatile else ""
|
||||||
|
return f"{c}{v}{self.typename.format()} {name}"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Array:
|
class Array:
|
||||||
@ -269,6 +316,14 @@ class Array:
|
|||||||
#: ~~
|
#: ~~
|
||||||
size: typing.Optional[Value]
|
size: typing.Optional[Value]
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
s = self.size.format() if self.size else ""
|
||||||
|
return f"{self.array_of.format()}[{s}]"
|
||||||
|
|
||||||
|
def format_decl(self, name: str) -> str:
|
||||||
|
s = self.size.format() if self.size else ""
|
||||||
|
return f"{self.array_of.format()} {name}[{s}]"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Pointer:
|
class Pointer:
|
||||||
@ -282,6 +337,25 @@ class Pointer:
|
|||||||
const: bool = False
|
const: bool = False
|
||||||
volatile: bool = False
|
volatile: bool = False
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
c = " const" if self.const else ""
|
||||||
|
v = " volatile" if self.volatile else ""
|
||||||
|
ptr_to = self.ptr_to
|
||||||
|
if isinstance(ptr_to, (Array, FunctionType)):
|
||||||
|
return ptr_to.format_decl(f"(*{c}{v})")
|
||||||
|
else:
|
||||||
|
return f"{ptr_to.format()}*{c}{v}"
|
||||||
|
|
||||||
|
def format_decl(self, name: str):
|
||||||
|
"""Format as a named declaration"""
|
||||||
|
c = " const" if self.const else ""
|
||||||
|
v = " volatile" if self.volatile else ""
|
||||||
|
ptr_to = self.ptr_to
|
||||||
|
if isinstance(ptr_to, (Array, FunctionType)):
|
||||||
|
return ptr_to.format_decl(f"(*{c}{v} {name})")
|
||||||
|
else:
|
||||||
|
return f"{ptr_to.format()}*{c}{v} {name}"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Reference:
|
class Reference:
|
||||||
@ -291,6 +365,22 @@ class Reference:
|
|||||||
|
|
||||||
ref_to: typing.Union[Array, FunctionType, Pointer, Type]
|
ref_to: typing.Union[Array, FunctionType, Pointer, Type]
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
ref_to = self.ref_to
|
||||||
|
if isinstance(ref_to, Array):
|
||||||
|
return ref_to.format_decl("(&)")
|
||||||
|
else:
|
||||||
|
return f"{ref_to.format()}&"
|
||||||
|
|
||||||
|
def format_decl(self, name: str):
|
||||||
|
"""Format as a named declaration"""
|
||||||
|
ref_to = self.ref_to
|
||||||
|
|
||||||
|
if isinstance(ref_to, Array):
|
||||||
|
return ref_to.format_decl(f"(& {name})")
|
||||||
|
else:
|
||||||
|
return f"{ref_to.format()}& {name}"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MoveReference:
|
class MoveReference:
|
||||||
@ -300,6 +390,13 @@ class MoveReference:
|
|||||||
|
|
||||||
moveref_to: typing.Union[Array, FunctionType, Pointer, Type]
|
moveref_to: typing.Union[Array, FunctionType, Pointer, Type]
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
return f"{self.moveref_to.format()}&&"
|
||||||
|
|
||||||
|
def format_decl(self, name: str):
|
||||||
|
"""Format as a named declaration"""
|
||||||
|
return f"{self.moveref_to.format()}&& {name}"
|
||||||
|
|
||||||
|
|
||||||
#: A type or function type that is decorated with various things
|
#: A type or function type that is decorated with various things
|
||||||
#:
|
#:
|
||||||
@ -505,6 +602,15 @@ class Parameter:
|
|||||||
default: typing.Optional[Value] = None
|
default: typing.Optional[Value] = None
|
||||||
param_pack: bool = False
|
param_pack: bool = False
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
default = f" = {self.default.format()}" if self.default else ""
|
||||||
|
pp = "... " if self.param_pack else ""
|
||||||
|
name = self.name
|
||||||
|
if name:
|
||||||
|
return f"{self.type.format_decl(f'{pp}{name}')}{default}"
|
||||||
|
else:
|
||||||
|
return f"{self.type.format()}{pp}{default}"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Function:
|
class Function:
|
||||||
|
313
tests/test_typefmt.py
Normal file
313
tests/test_typefmt.py
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
import typing
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from cxxheaderparser.tokfmt import Token
|
||||||
|
from cxxheaderparser.types import (
|
||||||
|
Array,
|
||||||
|
DecoratedType,
|
||||||
|
FunctionType,
|
||||||
|
FundamentalSpecifier,
|
||||||
|
Method,
|
||||||
|
MoveReference,
|
||||||
|
NameSpecifier,
|
||||||
|
PQName,
|
||||||
|
Parameter,
|
||||||
|
Pointer,
|
||||||
|
Reference,
|
||||||
|
TemplateArgument,
|
||||||
|
TemplateSpecialization,
|
||||||
|
TemplateDecl,
|
||||||
|
Type,
|
||||||
|
Value,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"pytype,typestr,declstr",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
Type(typename=PQName(segments=[FundamentalSpecifier(name="int")])),
|
||||||
|
"int",
|
||||||
|
"int name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")]), const=True
|
||||||
|
),
|
||||||
|
"const int",
|
||||||
|
"const int name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Type(
|
||||||
|
typename=PQName(segments=[NameSpecifier(name="S")], classkey="struct")
|
||||||
|
),
|
||||||
|
"struct S",
|
||||||
|
"struct S name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Pointer(
|
||||||
|
ptr_to=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"int*",
|
||||||
|
"int* name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Pointer(
|
||||||
|
ptr_to=Pointer(
|
||||||
|
ptr_to=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"int**",
|
||||||
|
"int** name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Reference(
|
||||||
|
ref_to=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"int&",
|
||||||
|
"int& name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Reference(
|
||||||
|
ref_to=Array(
|
||||||
|
array_of=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
size=Value(tokens=[Token(value="3")]),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"int (&)[3]",
|
||||||
|
"int (& name)[3]",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
MoveReference(
|
||||||
|
moveref_to=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[NameSpecifier(name="T"), NameSpecifier(name="T")]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"T::T&&",
|
||||||
|
"T::T&& name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Pointer(
|
||||||
|
ptr_to=Array(
|
||||||
|
array_of=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
size=Value(tokens=[Token(value="3")]),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"int (*)[3]",
|
||||||
|
"int (* name)[3]",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Pointer(
|
||||||
|
ptr_to=Array(
|
||||||
|
array_of=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
size=Value(tokens=[Token(value="3")]),
|
||||||
|
),
|
||||||
|
const=True,
|
||||||
|
),
|
||||||
|
"int (* const)[3]",
|
||||||
|
"int (* const name)[3]",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FunctionType(
|
||||||
|
return_type=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
parameters=[
|
||||||
|
Parameter(
|
||||||
|
type=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
"int (int)",
|
||||||
|
"int name(int)",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FunctionType(
|
||||||
|
return_type=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
parameters=[
|
||||||
|
Parameter(
|
||||||
|
type=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
has_trailing_return=True,
|
||||||
|
),
|
||||||
|
"auto (int) -> int",
|
||||||
|
"auto name(int) -> int",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FunctionType(
|
||||||
|
return_type=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[FundamentalSpecifier(name="void")],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
parameters=[
|
||||||
|
Parameter(
|
||||||
|
type=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[FundamentalSpecifier(name="int")],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
name="a",
|
||||||
|
),
|
||||||
|
Parameter(
|
||||||
|
type=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[FundamentalSpecifier(name="int")],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
name="b",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
"void (int a, int b)",
|
||||||
|
"void name(int a, int b)",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Pointer(
|
||||||
|
ptr_to=FunctionType(
|
||||||
|
return_type=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
parameters=[
|
||||||
|
Parameter(
|
||||||
|
type=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[FundamentalSpecifier(name="int")]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"int (*)(int)",
|
||||||
|
"int (* name)(int)",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
NameSpecifier(name="std"),
|
||||||
|
NameSpecifier(
|
||||||
|
name="function",
|
||||||
|
specialization=TemplateSpecialization(
|
||||||
|
args=[
|
||||||
|
TemplateArgument(
|
||||||
|
arg=FunctionType(
|
||||||
|
return_type=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
FundamentalSpecifier(name="int")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
parameters=[
|
||||||
|
Parameter(
|
||||||
|
type=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
FundamentalSpecifier(
|
||||||
|
name="int"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"std::function<int (int)>",
|
||||||
|
"std::function<int (int)> name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
NameSpecifier(
|
||||||
|
name="foo",
|
||||||
|
specialization=TemplateSpecialization(
|
||||||
|
args=[
|
||||||
|
TemplateArgument(
|
||||||
|
arg=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
NameSpecifier(name=""),
|
||||||
|
NameSpecifier(name="T"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"foo<::T>",
|
||||||
|
"foo<::T> name",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
NameSpecifier(
|
||||||
|
name="foo",
|
||||||
|
specialization=TemplateSpecialization(
|
||||||
|
args=[
|
||||||
|
TemplateArgument(
|
||||||
|
arg=Type(
|
||||||
|
typename=PQName(
|
||||||
|
segments=[
|
||||||
|
NameSpecifier(name=""),
|
||||||
|
NameSpecifier(name="T"),
|
||||||
|
],
|
||||||
|
has_typename=True,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"foo<typename ::T>",
|
||||||
|
"foo<typename ::T> name",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_typefmt(
|
||||||
|
pytype: typing.Union[DecoratedType, FunctionType], typestr: str, declstr: str
|
||||||
|
):
|
||||||
|
# basic formatting
|
||||||
|
assert pytype.format() == typestr
|
||||||
|
|
||||||
|
# as a type declaration
|
||||||
|
assert pytype.format_decl("name") == declstr
|
Loading…
x
Reference in New Issue
Block a user