-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathparserstate.py
More file actions
161 lines (119 loc) · 4.68 KB
/
Copy pathparserstate.py
File metadata and controls
161 lines (119 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import typing
from dataclasses import dataclass
if typing.TYPE_CHECKING:
from .visitor import CxxVisitor # pragma: nocover
from .errors import CxxParseError
from .lexer import LexToken, Location
from .types import ClassDecl, NamespaceDecl, Value
@dataclass
class ParsedTypeModifiers:
#: Modifiers allowed on variables and functions.
constexpr: typing.Optional[LexToken] = None
extern: typing.Optional[LexToken] = None
inline: typing.Optional[LexToken] = None
static: typing.Optional[LexToken] = None
#: Modifiers only allowed on variables/fields.
mutable: typing.Optional[LexToken] = None
#: Modifiers only allowed on methods.
explicit: typing.Optional[LexToken] = None
virtual: typing.Optional[LexToken] = None
#: For C++20 ``explicit(<expr>)``: the constant expression inside the
#: parens (omitting the parens themselves). ``None`` if absent or if
#: ``explicit`` was used as a bare keyword.
explicit_value: typing.Optional[Value] = None
#: ``friend`` if encountered while parsing declaration specifiers.
friend: typing.Optional[LexToken] = None
def validate(
self, *, var_ok: bool, meth_ok: bool, msg: str, friend_ok: bool = False
) -> None:
# Almost there! Do any checks the caller asked for
if not var_ok:
for tok in (self.mutable,):
if tok is not None:
raise CxxParseError(f"{msg}: unexpected '{tok.value}'")
if not meth_ok:
for tok in (self.explicit, self.virtual):
if tok is not None:
raise CxxParseError(f"{msg}: unexpected '{tok.value}'")
if not meth_ok and not var_ok:
for tok in (self.constexpr, self.extern, self.inline, self.static):
if tok is not None:
raise CxxParseError(f"{msg}: unexpected '{tok.value}'")
if not friend_ok and self.friend is not None:
raise CxxParseError(f"{msg}: unexpected '{self.friend.value}'")
#: custom user data for this state type
T = typing.TypeVar("T")
#: type of custom user data for a parent state
PT = typing.TypeVar("PT")
class BaseState(typing.Generic[T, PT]):
#: Uninitialized user data available for use by visitor implementations. You
#: should set this in a ``*_start`` method.
user_data: T
#: parent state
parent: typing.Optional["State"]
#: Approximate location that the parsed element was found at
location: Location
#: internal detail used by parser
_prior_visitor: "CxxVisitor"
def __init__(self, parent: typing.Optional["State"], location: Location) -> None:
self.parent = parent
self.location = location
def _finish(self, visitor: "CxxVisitor") -> None:
pass
class ExternBlockState(BaseState[T, PT]):
parent: "NonClassBlockState"
#: The linkage for this extern block
linkage: str
def __init__(
self, parent: "NonClassBlockState", location: Location, linkage: str
) -> None:
super().__init__(parent, location)
self.linkage = linkage
def _finish(self, visitor: "CxxVisitor") -> None:
visitor.on_extern_block_end(self)
class NamespaceBlockState(BaseState[T, PT]):
parent: "NonClassBlockState"
#: The incremental namespace for this block
namespace: NamespaceDecl
def __init__(
self,
parent: typing.Optional["NonClassBlockState"],
location: Location,
namespace: NamespaceDecl,
) -> None:
super().__init__(parent, location)
self.namespace = namespace
def _finish(self, visitor: "CxxVisitor") -> None:
visitor.on_namespace_end(self)
class ClassBlockState(BaseState[T, PT]):
parent: "State"
#: class decl block being processed
class_decl: ClassDecl
#: Current access level for items encountered
access: str
#: Currently parsing as a typedef
typedef: bool
#: modifiers to apply to following variables
mods: ParsedTypeModifiers
def __init__(
self,
parent: typing.Optional["State"],
location: Location,
class_decl: ClassDecl,
access: str,
typedef: bool,
mods: ParsedTypeModifiers,
) -> None:
super().__init__(parent, location)
self.class_decl = class_decl
self.access = access
self.typedef = typedef
self.mods = mods
def _set_access(self, access: str) -> None:
self.access = access
def _finish(self, visitor: "CxxVisitor") -> None:
visitor.on_class_end(self)
State = typing.Union[
NamespaceBlockState[T, PT], ExternBlockState[T, PT], ClassBlockState[T, PT]
]
NonClassBlockState = typing.Union[ExternBlockState[T, PT], NamespaceBlockState[T, PT]]