1from __future__ import annotations
2
3import sys
4import warnings
5from typing import TYPE_CHECKING, Any, ClassVar, Literal
6
7from docutils import nodes
8
9from sphinx import addnodes
10from sphinx.domains.cpp._ids import (
11 _id_char_from_prefix,
12 _id_explicit_cast,
13 _id_fundamental_v1,
14 _id_fundamental_v2,
15 _id_operator_unary_v2,
16 _id_operator_v1,
17 _id_operator_v2,
18 _id_prefix,
19 _id_shorthands_v1,
20 _max_id,
21)
22from sphinx.util.cfamily import (
23 ASTAttributeList,
24 ASTBaseBase,
25 ASTBaseParenExprList,
26 NoOldIdError,
27 StringifyTransform,
28 UnsupportedMultiCharacterCharLiteral,
29 verify_description_mode,
30)
31
32if TYPE_CHECKING:
33
34 from docutils.nodes import Element, TextElement
35
36 from sphinx.addnodes import desc_signature
37 from sphinx.domains.cpp._symbol import Symbol
38 from sphinx.environment import BuildEnvironment
39
40
41class ASTBase(ASTBaseBase):
42 pass
43
44
45# Names
46################################################################################
47
48class ASTIdentifier(ASTBase):
49 def __init__(self, name: str) -> None:
50 if not isinstance(name, str) or len(name) == 0:
51 raise AssertionError
52 self.name = sys.intern(name)
53 self.is_anonymous = name[0] == '@'
54
55 # ASTBaseBase already implements this method,
56 # but specialising it here improves performance
57 def __eq__(self, other: object) -> bool:
58 if not isinstance(other, ASTIdentifier):
59 return NotImplemented
60 return self.name == other.name
61
62 def __hash__(self) -> int:
63 return hash(self.name)
64
65 def _stringify(self, transform: StringifyTransform) -> str:
66 return transform(self.name)
67
68 def is_anon(self) -> bool:
69 return self.is_anonymous
70
71 def get_id(self, version: int) -> str:
72 if self.is_anonymous and version < 3:
73 raise NoOldIdError
74 if version == 1:
75 if self.name == 'size_t':
76 return 's'
77 else:
78 return self.name
79 if self.name == "std":
80 return 'St'
81 elif self.name[0] == "~":
82 # a destructor, just use an arbitrary version of dtors
83 return 'D0'
84 else:
85 if self.is_anonymous:
86 return 'Ut%d_%s' % (len(self.name) - 1, self.name[1:])
87 else:
88 return str(len(self.name)) + self.name
89
90 # and this is where we finally make a difference between __str__ and the display string
91
92 def __str__(self) -> str:
93 return self.name
94
95 def get_display_string(self) -> str:
96 return "[anonymous]" if self.is_anonymous else self.name
97
98 def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironment,
99 prefix: str, templateArgs: str, symbol: Symbol) -> None:
100 verify_description_mode(mode)
101 if self.is_anonymous:
102 node = addnodes.desc_sig_name(text="[anonymous]")
103 else:
104 node = addnodes.desc_sig_name(self.name, self.name)
105 if mode == 'markType':
106 targetText = prefix + self.name + templateArgs
107 pnode = addnodes.pending_xref('', refdomain='cpp',
108 reftype='identifier',
109 reftarget=targetText, modname=None,
110 classname=None)
111 pnode['cpp:parent_key'] = symbol.get_lookup_key()
112 pnode += node
113 signode += pnode
114 elif mode == 'lastIsName':
115 nameNode = addnodes.desc_name()
116 nameNode += node
117 signode += nameNode
118 elif mode == 'noneIsName':
119 signode += node
120 elif mode == 'param':
121 node['classes'].append('sig-param')
122 signode += node
123 elif mode == 'udl':
124 # the target is 'operator""id' instead of just 'id'
125 assert len(prefix) == 0
126 assert len(templateArgs) == 0
127 assert not self.is_anonymous
128 targetText = 'operator""' + self.name
129 pnode = addnodes.pending_xref('', refdomain='cpp',
130 reftype='identifier',
131 reftarget=targetText, modname=None,
132 classname=None)
133 pnode['cpp:parent_key'] = symbol.get_lookup_key()
134 pnode += node
135 signode += pnode
136 else:
137 raise Exception('Unknown description mode: %s' % mode)
138
139 @property
140 def identifier(self) -> str:
141 warnings.warn(
142 '`ASTIdentifier.identifier` is deprecated, use `ASTIdentifier.name` instead',
143 DeprecationWarning, stacklevel=2,
144 )
145 return self.name
146
147
148class ASTNestedNameElement(ASTBase):
149 def __init__(self, identOrOp: ASTIdentifier | ASTOperator,
150 templateArgs: ASTTemplateArgs | None) -> None:
151 self.identOrOp = identOrOp
152 self.templateArgs = templateArgs
153
154 def __eq__(self, other: object) -> bool:
155 if not isinstance(other, ASTNestedNameElement):
156 return NotImplemented
157 return self.identOrOp == other.identOrOp and self.templateArgs == other.templateArgs
158
159 def __hash__(self) -> int:
160 return hash((self.identOrOp, self.templateArgs))
161
162 def is_operator(self) -> bool:
163 return False
164
165 def get_id(self, version: int) -> str:
166 res = self.identOrOp.get_id(version)
167 if self.templateArgs:
168 res += self.templateArgs.get_id(version)
169 return res
170
171 def _stringify(self, transform: StringifyTransform) -> str:
172 res = transform(self.identOrOp)
173 if self.templateArgs:
174 res += transform(self.templateArgs)
175 return res
176
177 def describe_signature(self, signode: TextElement, mode: str,
178 env: BuildEnvironment, prefix: str, symbol: Symbol) -> None:
179 tArgs = str(self.templateArgs) if self.templateArgs is not None else ''
180 self.identOrOp.describe_signature(signode, mode, env, prefix, tArgs, symbol)
181 if self.templateArgs is not None:
182 self.templateArgs.describe_signature(signode, 'markType', env, symbol)
183
184
185class ASTNestedName(ASTBase):
186 def __init__(self, names: list[ASTNestedNameElement],
187 templates: list[bool], rooted: bool) -> None:
188 assert len(names) > 0
189 self.names = names
190 self.templates = templates
191 assert len(self.names) == len(self.templates)
192 self.rooted = rooted
193
194 def __eq__(self, other: object) -> bool:
195 if not isinstance(other, ASTNestedName):
196 return NotImplemented
197 return (
198 self.names == other.names
199 and self.templates == other.templates
200 and self.rooted == other.rooted
201 )
202
203 def __hash__(self) -> int:
204 return hash((self.names, self.templates, self.rooted))
205
206 @property
207 def name(self) -> ASTNestedName:
208 return self
209
210 def num_templates(self) -> int:
211 count = 0
212 for n in self.names:
213 if n.is_operator():
214 continue
215 if n.templateArgs:
216 count += 1
217 return count
218
219 def get_id(self, version: int, modifiers: str = '') -> str:
220 if version == 1:
221 tt = str(self)
222 if tt in _id_shorthands_v1:
223 return _id_shorthands_v1[tt]
224 else:
225 return '::'.join(n.get_id(version) for n in self.names)
226
227 res = []
228 if len(self.names) > 1 or len(modifiers) > 0:
229 res.append('N')
230 res.append(modifiers)
231 res.extend(n.get_id(version) for n in self.names)
232 if len(self.names) > 1 or len(modifiers) > 0:
233 res.append('E')
234 return ''.join(res)
235
236 def _stringify(self, transform: StringifyTransform) -> str:
237 res = []
238 if self.rooted:
239 res.append('')
240 for i in range(len(self.names)):
241 n = self.names[i]
242 if self.templates[i]:
243 res.append("template " + transform(n))
244 else:
245 res.append(transform(n))
246 return '::'.join(res)
247
248 def describe_signature(self, signode: TextElement, mode: str,
249 env: BuildEnvironment, symbol: Symbol) -> None:
250 verify_description_mode(mode)
251 # just print the name part, with template args, not template params
252 if mode == 'noneIsName':
253 if self.rooted:
254 unreachable = "Can this happen?"
255 raise AssertionError(unreachable) # TODO
256 signode += nodes.Text('::')
257 for i in range(len(self.names)):
258 if i != 0:
259 unreachable = "Can this happen?"
260 raise AssertionError(unreachable) # TODO
261 signode += nodes.Text('::blah')
262 n = self.names[i]
263 if self.templates[i]:
264 unreachable = "Can this happen?"
265 raise AssertionError(unreachable) # TODO
266 signode += nodes.Text("template")
267 signode += nodes.Text(" ")
268 n.describe_signature(signode, mode, env, '', symbol)
269 elif mode == 'param':
270 assert not self.rooted, str(self)
271 assert len(self.names) == 1
272 assert not self.templates[0]
273 self.names[0].describe_signature(signode, 'param', env, '', symbol)
274 elif mode in ('markType', 'lastIsName', 'markName'):
275 # Each element should be a pending xref targeting the complete
276 # prefix. however, only the identifier part should be a link, such
277 # that template args can be a link as well.
278 # For 'lastIsName' we should also prepend template parameter lists.
279 templateParams: list[Any] = []
280 if mode == 'lastIsName':
281 assert symbol is not None
282 if symbol.declaration.templatePrefix is not None:
283 templateParams = symbol.declaration.templatePrefix.templates
284 iTemplateParams = 0
285 templateParamsPrefix = ''
286 prefix = ''
287 first = True
288 names = self.names[:-1] if mode == 'lastIsName' else self.names
289 # If lastIsName, then wrap all of the prefix in a desc_addname,
290 # else append directly to signode.
291 # NOTE: Breathe previously relied on the prefix being in the desc_addname node,
292 # so it can remove it in inner declarations.
293 dest = signode
294 if mode == 'lastIsName':
295 dest = addnodes.desc_addname()
296 if self.rooted:
297 prefix += '::'
298 if mode == 'lastIsName' and len(names) == 0:
299 signode += addnodes.desc_sig_punctuation('::', '::')
300 else:
301 dest += addnodes.desc_sig_punctuation('::', '::')
302 for i in range(len(names)):
303 nne = names[i]
304 template = self.templates[i]
305 if not first:
306 dest += addnodes.desc_sig_punctuation('::', '::')
307 prefix += '::'
308 if template:
309 dest += addnodes.desc_sig_keyword('template', 'template')
310 dest += addnodes.desc_sig_space()
311 first = False
312 txt_nne = str(nne)
313 if txt_nne != '':
314 if nne.templateArgs and iTemplateParams < len(templateParams):
315 templateParamsPrefix += str(templateParams[iTemplateParams])
316 iTemplateParams += 1
317 nne.describe_signature(dest, 'markType',
318 env, templateParamsPrefix + prefix, symbol)
319 prefix += txt_nne
320 if mode == 'lastIsName':
321 if len(self.names) > 1:
322 dest += addnodes.desc_sig_punctuation('::', '::')
323 signode += dest
324 if self.templates[-1]:
325 signode += addnodes.desc_sig_keyword('template', 'template')
326 signode += addnodes.desc_sig_space()
327 self.names[-1].describe_signature(signode, mode, env, '', symbol)
328 else:
329 raise Exception('Unknown description mode: %s' % mode)
330
331
332################################################################################
333# Expressions
334################################################################################
335
336class ASTExpression(ASTBase):
337 def get_id(self, version: int) -> str:
338 raise NotImplementedError(repr(self))
339
340 def describe_signature(self, signode: TextElement, mode: str,
341 env: BuildEnvironment, symbol: Symbol) -> None:
342 raise NotImplementedError(repr(self))
343
344
345# Primary expressions
346################################################################################
347
348class ASTLiteral(ASTExpression):
349 pass
350
351
352class ASTPointerLiteral(ASTLiteral):
353 def __eq__(self, other: object) -> bool:
354 return isinstance(other, ASTPointerLiteral)
355
356 def __hash__(self) -> int:
357 return hash('nullptr')
358
359 def _stringify(self, transform: StringifyTransform) -> str:
360 return 'nullptr'
361
362 def get_id(self, version: int) -> str:
363 return 'LDnE'
364
365 def describe_signature(self, signode: TextElement, mode: str,
366 env: BuildEnvironment, symbol: Symbol) -> None:
367 signode += addnodes.desc_sig_keyword('nullptr', 'nullptr')
368
369
370class ASTBooleanLiteral(ASTLiteral):
371 def __init__(self, value: bool) -> None:
372 self.value = value
373
374 def __eq__(self, other: object) -> bool:
375 if not isinstance(other, ASTBooleanLiteral):
376 return NotImplemented
377 return self.value == other.value
378
379 def __hash__(self) -> int:
380 return hash(self.value)
381
382 def _stringify(self, transform: StringifyTransform) -> str:
383 if self.value:
384 return 'true'
385 else:
386 return 'false'
387
388 def get_id(self, version: int) -> str:
389 if self.value:
390 return 'L1E'
391 else:
392 return 'L0E'
393
394 def describe_signature(self, signode: TextElement, mode: str,
395 env: BuildEnvironment, symbol: Symbol) -> None:
396 signode += addnodes.desc_sig_keyword(str(self), str(self))
397
398
399class ASTNumberLiteral(ASTLiteral):
400 def __init__(self, data: str) -> None:
401 self.data = data
402
403 def __eq__(self, other: object) -> bool:
404 if not isinstance(other, ASTNumberLiteral):
405 return NotImplemented
406 return self.data == other.data
407
408 def __hash__(self) -> int:
409 return hash(self.data)
410
411 def _stringify(self, transform: StringifyTransform) -> str:
412 return self.data
413
414 def get_id(self, version: int) -> str:
415 # TODO: floats should be mangled by writing the hex of the binary representation
416 return "L%sE" % self.data.replace("'", "")
417
418 def describe_signature(self, signode: TextElement, mode: str,
419 env: BuildEnvironment, symbol: Symbol) -> None:
420 signode += addnodes.desc_sig_literal_number(self.data, self.data)
421
422
423class ASTStringLiteral(ASTLiteral):
424 def __init__(self, data: str) -> None:
425 self.data = data
426
427 def __eq__(self, other: object) -> bool:
428 if not isinstance(other, ASTStringLiteral):
429 return NotImplemented
430 return self.data == other.data
431
432 def __hash__(self) -> int:
433 return hash(self.data)
434
435 def _stringify(self, transform: StringifyTransform) -> str:
436 return self.data
437
438 def get_id(self, version: int) -> str:
439 # note: the length is not really correct with escaping
440 return "LA%d_KcE" % (len(self.data) - 2)
441
442 def describe_signature(self, signode: TextElement, mode: str,
443 env: BuildEnvironment, symbol: Symbol) -> None:
444 signode += addnodes.desc_sig_literal_string(self.data, self.data)
445
446
447class ASTCharLiteral(ASTLiteral):
448 def __init__(self, prefix: str, data: str) -> None:
449 self.prefix = prefix # may be None when no prefix
450 self.data = data
451 assert prefix in _id_char_from_prefix
452 self.type = _id_char_from_prefix[prefix]
453 decoded = data.encode().decode('unicode-escape')
454 if len(decoded) == 1:
455 self.value = ord(decoded)
456 else:
457 raise UnsupportedMultiCharacterCharLiteral(decoded)
458
459 def __eq__(self, other: object) -> bool:
460 if not isinstance(other, ASTCharLiteral):
461 return NotImplemented
462 return (
463 self.prefix == other.prefix
464 and self.value == other.value
465 )
466
467 def __hash__(self) -> int:
468 return hash((self.prefix, self.value))
469
470 def _stringify(self, transform: StringifyTransform) -> str:
471 if self.prefix is None:
472 return "'" + self.data + "'"
473 else:
474 return self.prefix + "'" + self.data + "'"
475
476 def get_id(self, version: int) -> str:
477 # TODO: the ID should be have L E around it
478 return self.type + str(self.value)
479
480 def describe_signature(self, signode: TextElement, mode: str,
481 env: BuildEnvironment, symbol: Symbol) -> None:
482 if self.prefix is not None:
483 signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
484 txt = "'" + self.data + "'"
485 signode += addnodes.desc_sig_literal_char(txt, txt)
486
487
488class ASTUserDefinedLiteral(ASTLiteral):
489 def __init__(self, literal: ASTLiteral, ident: ASTIdentifier) -> None:
490 self.literal = literal
491 self.ident = ident
492
493 def __eq__(self, other: object) -> bool:
494 if not isinstance(other, ASTUserDefinedLiteral):
495 return NotImplemented
496 return self.literal == other.literal and self.ident == other.ident
497
498 def __hash__(self) -> int:
499 return hash((self.literal, self.ident))
500
501 def _stringify(self, transform: StringifyTransform) -> str:
502 return transform(self.literal) + transform(self.ident)
503
504 def get_id(self, version: int) -> str:
505 # mangle as if it was a function call: ident(literal)
506 return f'clL_Zli{self.ident.get_id(version)}E{self.literal.get_id(version)}E'
507
508 def describe_signature(self, signode: TextElement, mode: str,
509 env: BuildEnvironment, symbol: Symbol) -> None:
510 self.literal.describe_signature(signode, mode, env, symbol)
511 self.ident.describe_signature(signode, "udl", env, "", "", symbol)
512
513
514################################################################################
515
516class ASTThisLiteral(ASTExpression):
517 def __eq__(self, other: object) -> bool:
518 return isinstance(other, ASTThisLiteral)
519
520 def __hash__(self) -> int:
521 return hash("this")
522
523 def _stringify(self, transform: StringifyTransform) -> str:
524 return "this"
525
526 def get_id(self, version: int) -> str:
527 return "fpT"
528
529 def describe_signature(self, signode: TextElement, mode: str,
530 env: BuildEnvironment, symbol: Symbol) -> None:
531 signode += addnodes.desc_sig_keyword('this', 'this')
532
533
534class ASTFoldExpr(ASTExpression):
535 def __init__(self, leftExpr: ASTExpression | None,
536 op: str, rightExpr: ASTExpression | None) -> None:
537 assert leftExpr is not None or rightExpr is not None
538 self.leftExpr = leftExpr
539 self.op = op
540 self.rightExpr = rightExpr
541
542 def __eq__(self, other: object) -> bool:
543 if not isinstance(other, ASTFoldExpr):
544 return NotImplemented
545 return (
546 self.leftExpr == other.leftExpr
547 and self.op == other.op
548 and self.rightExpr == other.rightExpr
549 )
550
551 def __hash__(self) -> int:
552 return hash((self.leftExpr, self.op, self.rightExpr))
553
554 def _stringify(self, transform: StringifyTransform) -> str:
555 res = ['(']
556 if self.leftExpr:
557 res.append(transform(self.leftExpr))
558 res.append(' ')
559 res.append(self.op)
560 res.append(' ')
561 res.append('...')
562 if self.rightExpr:
563 res.append(' ')
564 res.append(self.op)
565 res.append(' ')
566 res.append(transform(self.rightExpr))
567 res.append(')')
568 return ''.join(res)
569
570 def get_id(self, version: int) -> str:
571 assert version >= 3
572 if version == 3:
573 return str(self)
574 # https://github.com/itanium-cxx-abi/cxx-abi/pull/67
575 res = []
576 if self.leftExpr is None: # (... op expr)
577 res.append('fl')
578 elif self.rightExpr is None: # (expr op ...)
579 res.append('fr')
580 else: # (expr op ... op expr)
581 # we don't check where the parameter pack is,
582 # we just always call this a binary left fold
583 res.append('fL')
584 res.append(_id_operator_v2[self.op])
585 if self.leftExpr:
586 res.append(self.leftExpr.get_id(version))
587 if self.rightExpr:
588 res.append(self.rightExpr.get_id(version))
589 return ''.join(res)
590
591 def describe_signature(self, signode: TextElement, mode: str,
592 env: BuildEnvironment, symbol: Symbol) -> None:
593 signode += addnodes.desc_sig_punctuation('(', '(')
594 if self.leftExpr:
595 self.leftExpr.describe_signature(signode, mode, env, symbol)
596 signode += addnodes.desc_sig_space()
597 signode += addnodes.desc_sig_operator(self.op, self.op)
598 signode += addnodes.desc_sig_space()
599 signode += addnodes.desc_sig_punctuation('...', '...')
600 if self.rightExpr:
601 signode += addnodes.desc_sig_space()
602 signode += addnodes.desc_sig_operator(self.op, self.op)
603 signode += addnodes.desc_sig_space()
604 self.rightExpr.describe_signature(signode, mode, env, symbol)
605 signode += addnodes.desc_sig_punctuation(')', ')')
606
607
608class ASTParenExpr(ASTExpression):
609 def __init__(self, expr: ASTExpression) -> None:
610 self.expr = expr
611
612 def __eq__(self, other: object) -> bool:
613 if not isinstance(other, ASTParenExpr):
614 return NotImplemented
615 return self.expr == other.expr
616
617 def __hash__(self) -> int:
618 return hash(self.expr)
619
620 def _stringify(self, transform: StringifyTransform) -> str:
621 return '(' + transform(self.expr) + ')'
622
623 def get_id(self, version: int) -> str:
624 return self.expr.get_id(version)
625
626 def describe_signature(self, signode: TextElement, mode: str,
627 env: BuildEnvironment, symbol: Symbol) -> None:
628 signode += addnodes.desc_sig_punctuation('(', '(')
629 self.expr.describe_signature(signode, mode, env, symbol)
630 signode += addnodes.desc_sig_punctuation(')', ')')
631
632
633class ASTIdExpression(ASTExpression):
634 def __init__(self, name: ASTNestedName) -> None:
635 # note: this class is basically to cast a nested name as an expression
636 self.name = name
637
638 def __eq__(self, other: object) -> bool:
639 if not isinstance(other, ASTIdExpression):
640 return NotImplemented
641 return self.name == other.name
642
643 def __hash__(self) -> int:
644 return hash(self.name)
645
646 def _stringify(self, transform: StringifyTransform) -> str:
647 return transform(self.name)
648
649 def get_id(self, version: int) -> str:
650 return self.name.get_id(version)
651
652 def describe_signature(self, signode: TextElement, mode: str,
653 env: BuildEnvironment, symbol: Symbol) -> None:
654 self.name.describe_signature(signode, mode, env, symbol)
655
656
657# Postfix expressions
658################################################################################
659
660class ASTPostfixOp(ASTBase):
661 def get_id(self, idPrefix: str, version: int) -> str:
662 raise NotImplementedError(repr(self))
663
664 def describe_signature(self, signode: TextElement, mode: str,
665 env: BuildEnvironment, symbol: Symbol) -> None:
666 raise NotImplementedError(repr(self))
667
668
669class ASTPostfixArray(ASTPostfixOp):
670 def __init__(self, expr: ASTExpression) -> None:
671 self.expr = expr
672
673 def __eq__(self, other: object) -> bool:
674 if not isinstance(other, ASTPostfixArray):
675 return NotImplemented
676 return self.expr == other.expr
677
678 def __hash__(self) -> int:
679 return hash(self.expr)
680
681 def _stringify(self, transform: StringifyTransform) -> str:
682 return '[' + transform(self.expr) + ']'
683
684 def get_id(self, idPrefix: str, version: int) -> str:
685 return 'ix' + idPrefix + self.expr.get_id(version)
686
687 def describe_signature(self, signode: TextElement, mode: str,
688 env: BuildEnvironment, symbol: Symbol) -> None:
689 signode += addnodes.desc_sig_punctuation('[', '[')
690 self.expr.describe_signature(signode, mode, env, symbol)
691 signode += addnodes.desc_sig_punctuation(']', ']')
692
693
694class ASTPostfixMember(ASTPostfixOp):
695 def __init__(self, name: ASTNestedName) -> None:
696 self.name = name
697
698 def __eq__(self, other: object) -> bool:
699 if not isinstance(other, ASTPostfixMember):
700 return NotImplemented
701 return self.name == other.name
702
703 def __hash__(self) -> int:
704 return hash(self.name)
705
706 def _stringify(self, transform: StringifyTransform) -> str:
707 return '.' + transform(self.name)
708
709 def get_id(self, idPrefix: str, version: int) -> str:
710 return 'dt' + idPrefix + self.name.get_id(version)
711
712 def describe_signature(self, signode: TextElement, mode: str,
713 env: BuildEnvironment, symbol: Symbol) -> None:
714 signode += addnodes.desc_sig_punctuation('.', '.')
715 self.name.describe_signature(signode, 'noneIsName', env, symbol)
716
717
718class ASTPostfixMemberOfPointer(ASTPostfixOp):
719 def __init__(self, name: ASTNestedName) -> None:
720 self.name = name
721
722 def __eq__(self, other: object) -> bool:
723 if not isinstance(other, ASTPostfixMemberOfPointer):
724 return NotImplemented
725 return self.name == other.name
726
727 def __hash__(self) -> int:
728 return hash(self.name)
729
730 def _stringify(self, transform: StringifyTransform) -> str:
731 return '->' + transform(self.name)
732
733 def get_id(self, idPrefix: str, version: int) -> str:
734 return 'pt' + idPrefix + self.name.get_id(version)
735
736 def describe_signature(self, signode: TextElement, mode: str,
737 env: BuildEnvironment, symbol: Symbol) -> None:
738 signode += addnodes.desc_sig_operator('->', '->')
739 self.name.describe_signature(signode, 'noneIsName', env, symbol)
740
741
742class ASTPostfixInc(ASTPostfixOp):
743 def __eq__(self, other: object) -> bool:
744 return isinstance(other, ASTPostfixInc)
745
746 def __hash__(self) -> int:
747 return hash('++')
748
749 def _stringify(self, transform: StringifyTransform) -> str:
750 return '++'
751
752 def get_id(self, idPrefix: str, version: int) -> str:
753 return 'pp' + idPrefix
754
755 def describe_signature(self, signode: TextElement, mode: str,
756 env: BuildEnvironment, symbol: Symbol) -> None:
757 signode += addnodes.desc_sig_operator('++', '++')
758
759
760class ASTPostfixDec(ASTPostfixOp):
761 def __eq__(self, other: object) -> bool:
762 return isinstance(other, ASTPostfixDec)
763
764 def __hash__(self) -> int:
765 return hash('--')
766
767 def _stringify(self, transform: StringifyTransform) -> str:
768 return '--'
769
770 def get_id(self, idPrefix: str, version: int) -> str:
771 return 'mm' + idPrefix
772
773 def describe_signature(self, signode: TextElement, mode: str,
774 env: BuildEnvironment, symbol: Symbol) -> None:
775 signode += addnodes.desc_sig_operator('--', '--')
776
777
778class ASTPostfixCallExpr(ASTPostfixOp):
779 def __init__(self, lst: ASTParenExprList | ASTBracedInitList) -> None:
780 self.lst = lst
781
782 def __eq__(self, other: object) -> bool:
783 if not isinstance(other, ASTPostfixCallExpr):
784 return NotImplemented
785 return self.lst == other.lst
786
787 def __hash__(self) -> int:
788 return hash(self.lst)
789
790 def _stringify(self, transform: StringifyTransform) -> str:
791 return transform(self.lst)
792
793 def get_id(self, idPrefix: str, version: int) -> str:
794 return ''.join([
795 'cl',
796 idPrefix,
797 *(e.get_id(version) for e in self.lst.exprs),
798 'E',
799 ])
800
801 def describe_signature(self, signode: TextElement, mode: str,
802 env: BuildEnvironment, symbol: Symbol) -> None:
803 self.lst.describe_signature(signode, mode, env, symbol)
804
805
806class ASTPostfixExpr(ASTExpression):
807 def __init__(self, prefix: ASTType, postFixes: list[ASTPostfixOp]) -> None:
808 self.prefix = prefix
809 self.postFixes = postFixes
810
811 def __eq__(self, other: object) -> bool:
812 if not isinstance(other, ASTPostfixExpr):
813 return NotImplemented
814 return self.prefix == other.prefix and self.postFixes == other.postFixes
815
816 def __hash__(self) -> int:
817 return hash((self.prefix, self.postFixes))
818
819 def _stringify(self, transform: StringifyTransform) -> str:
820 return ''.join([transform(self.prefix), *(transform(p) for p in self.postFixes)])
821
822 def get_id(self, version: int) -> str:
823 id = self.prefix.get_id(version)
824 for p in self.postFixes:
825 id = p.get_id(id, version)
826 return id
827
828 def describe_signature(self, signode: TextElement, mode: str,
829 env: BuildEnvironment, symbol: Symbol) -> None:
830 self.prefix.describe_signature(signode, mode, env, symbol)
831 for p in self.postFixes:
832 p.describe_signature(signode, mode, env, symbol)
833
834
835class ASTExplicitCast(ASTExpression):
836 def __init__(self, cast: str, typ: ASTType, expr: ASTExpression) -> None:
837 assert cast in _id_explicit_cast
838 self.cast = cast
839 self.typ = typ
840 self.expr = expr
841
842 def __eq__(self, other: object) -> bool:
843 if not isinstance(other, ASTExplicitCast):
844 return NotImplemented
845 return self.cast == other.cast and self.typ == other.typ and self.expr == other.expr
846
847 def __hash__(self) -> int:
848 return hash((self.cast, self.typ, self.expr))
849
850 def _stringify(self, transform: StringifyTransform) -> str:
851 res = [self.cast]
852 res.append('<')
853 res.append(transform(self.typ))
854 res.append('>(')
855 res.append(transform(self.expr))
856 res.append(')')
857 return ''.join(res)
858
859 def get_id(self, version: int) -> str:
860 return (_id_explicit_cast[self.cast] +
861 self.typ.get_id(version) +
862 self.expr.get_id(version))
863
864 def describe_signature(self, signode: TextElement, mode: str,
865 env: BuildEnvironment, symbol: Symbol) -> None:
866 signode += addnodes.desc_sig_keyword(self.cast, self.cast)
867 signode += addnodes.desc_sig_punctuation('<', '<')
868 self.typ.describe_signature(signode, mode, env, symbol)
869 signode += addnodes.desc_sig_punctuation('>', '>')
870 signode += addnodes.desc_sig_punctuation('(', '(')
871 self.expr.describe_signature(signode, mode, env, symbol)
872 signode += addnodes.desc_sig_punctuation(')', ')')
873
874
875class ASTTypeId(ASTExpression):
876 def __init__(self, typeOrExpr: ASTType | ASTExpression, isType: bool) -> None:
877 self.typeOrExpr = typeOrExpr
878 self.isType = isType
879
880 def __eq__(self, other: object) -> bool:
881 if not isinstance(other, ASTTypeId):
882 return NotImplemented
883 return self.typeOrExpr == other.typeOrExpr and self.isType == other.isType
884
885 def __hash__(self) -> int:
886 return hash((self.typeOrExpr, self.isType))
887
888 def _stringify(self, transform: StringifyTransform) -> str:
889 return 'typeid(' + transform(self.typeOrExpr) + ')'
890
891 def get_id(self, version: int) -> str:
892 prefix = 'ti' if self.isType else 'te'
893 return prefix + self.typeOrExpr.get_id(version)
894
895 def describe_signature(self, signode: TextElement, mode: str,
896 env: BuildEnvironment, symbol: Symbol) -> None:
897 signode += addnodes.desc_sig_keyword('typeid', 'typeid')
898 signode += addnodes.desc_sig_punctuation('(', '(')
899 self.typeOrExpr.describe_signature(signode, mode, env, symbol)
900 signode += addnodes.desc_sig_punctuation(')', ')')
901
902
903# Unary expressions
904################################################################################
905
906class ASTUnaryOpExpr(ASTExpression):
907 def __init__(self, op: str, expr: ASTExpression) -> None:
908 self.op = op
909 self.expr = expr
910
911 def __eq__(self, other: object) -> bool:
912 if not isinstance(other, ASTUnaryOpExpr):
913 return NotImplemented
914 return self.op == other.op and self.expr == other.expr
915
916 def __hash__(self) -> int:
917 return hash((self.op, self.expr))
918
919 def _stringify(self, transform: StringifyTransform) -> str:
920 if self.op[0] in 'cn':
921 return self.op + " " + transform(self.expr)
922 else:
923 return self.op + transform(self.expr)
924
925 def get_id(self, version: int) -> str:
926 return _id_operator_unary_v2[self.op] + self.expr.get_id(version)
927
928 def describe_signature(self, signode: TextElement, mode: str,
929 env: BuildEnvironment, symbol: Symbol) -> None:
930 if self.op[0] in 'cn':
931 signode += addnodes.desc_sig_keyword(self.op, self.op)
932 signode += addnodes.desc_sig_space()
933 else:
934 signode += addnodes.desc_sig_operator(self.op, self.op)
935 self.expr.describe_signature(signode, mode, env, symbol)
936
937
938class ASTSizeofParamPack(ASTExpression):
939 def __init__(self, identifier: ASTIdentifier) -> None:
940 self.identifier = identifier
941
942 def __eq__(self, other: object) -> bool:
943 if not isinstance(other, ASTSizeofParamPack):
944 return NotImplemented
945 return self.identifier == other.identifier
946
947 def __hash__(self) -> int:
948 return hash(self.identifier)
949
950 def _stringify(self, transform: StringifyTransform) -> str:
951 return "sizeof...(" + transform(self.identifier) + ")"
952
953 def get_id(self, version: int) -> str:
954 return 'sZ' + self.identifier.get_id(version)
955
956 def describe_signature(self, signode: TextElement, mode: str,
957 env: BuildEnvironment, symbol: Symbol) -> None:
958 signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
959 signode += addnodes.desc_sig_punctuation('...', '...')
960 signode += addnodes.desc_sig_punctuation('(', '(')
961 self.identifier.describe_signature(signode, 'markType', env,
962 symbol=symbol, prefix="", templateArgs="")
963 signode += addnodes.desc_sig_punctuation(')', ')')
964
965
966class ASTSizeofType(ASTExpression):
967 def __init__(self, typ: ASTType) -> None:
968 self.typ = typ
969
970 def __eq__(self, other: object) -> bool:
971 if not isinstance(other, ASTSizeofType):
972 return NotImplemented
973 return self.typ == other.typ
974
975 def __hash__(self) -> int:
976 return hash(self.typ)
977
978 def _stringify(self, transform: StringifyTransform) -> str:
979 return "sizeof(" + transform(self.typ) + ")"
980
981 def get_id(self, version: int) -> str:
982 return 'st' + self.typ.get_id(version)
983
984 def describe_signature(self, signode: TextElement, mode: str,
985 env: BuildEnvironment, symbol: Symbol) -> None:
986 signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
987 signode += addnodes.desc_sig_punctuation('(', '(')
988 self.typ.describe_signature(signode, mode, env, symbol)
989 signode += addnodes.desc_sig_punctuation(')', ')')
990
991
992class ASTSizeofExpr(ASTExpression):
993 def __init__(self, expr: ASTExpression) -> None:
994 self.expr = expr
995
996 def __eq__(self, other: object) -> bool:
997 if not isinstance(other, ASTSizeofExpr):
998 return NotImplemented
999 return self.expr == other.expr
1000
1001 def __hash__(self) -> int:
1002 return hash(self.expr)
1003
1004 def _stringify(self, transform: StringifyTransform) -> str:
1005 return "sizeof " + transform(self.expr)
1006
1007 def get_id(self, version: int) -> str:
1008 return 'sz' + self.expr.get_id(version)
1009
1010 def describe_signature(self, signode: TextElement, mode: str,
1011 env: BuildEnvironment, symbol: Symbol) -> None:
1012 signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
1013 signode += addnodes.desc_sig_space()
1014 self.expr.describe_signature(signode, mode, env, symbol)
1015
1016
1017class ASTAlignofExpr(ASTExpression):
1018 def __init__(self, typ: ASTType) -> None:
1019 self.typ = typ
1020
1021 def __eq__(self, other: object) -> bool:
1022 if not isinstance(other, ASTAlignofExpr):
1023 return NotImplemented
1024 return self.typ == other.typ
1025
1026 def __hash__(self) -> int:
1027 return hash(self.typ)
1028
1029 def _stringify(self, transform: StringifyTransform) -> str:
1030 return "alignof(" + transform(self.typ) + ")"
1031
1032 def get_id(self, version: int) -> str:
1033 return 'at' + self.typ.get_id(version)
1034
1035 def describe_signature(self, signode: TextElement, mode: str,
1036 env: BuildEnvironment, symbol: Symbol) -> None:
1037 signode += addnodes.desc_sig_keyword('alignof', 'alignof')
1038 signode += addnodes.desc_sig_punctuation('(', '(')
1039 self.typ.describe_signature(signode, mode, env, symbol)
1040 signode += addnodes.desc_sig_punctuation(')', ')')
1041
1042
1043class ASTNoexceptExpr(ASTExpression):
1044 def __init__(self, expr: ASTExpression) -> None:
1045 self.expr = expr
1046
1047 def __eq__(self, other: object) -> bool:
1048 if not isinstance(other, ASTNoexceptExpr):
1049 return NotImplemented
1050 return self.expr == other.expr
1051
1052 def __hash__(self) -> int:
1053 return hash(self.expr)
1054
1055 def _stringify(self, transform: StringifyTransform) -> str:
1056 return 'noexcept(' + transform(self.expr) + ')'
1057
1058 def get_id(self, version: int) -> str:
1059 return 'nx' + self.expr.get_id(version)
1060
1061 def describe_signature(self, signode: TextElement, mode: str,
1062 env: BuildEnvironment, symbol: Symbol) -> None:
1063 signode += addnodes.desc_sig_keyword('noexcept', 'noexcept')
1064 signode += addnodes.desc_sig_punctuation('(', '(')
1065 self.expr.describe_signature(signode, mode, env, symbol)
1066 signode += addnodes.desc_sig_punctuation(')', ')')
1067
1068
1069class ASTNewExpr(ASTExpression):
1070 def __init__(self, rooted: bool, isNewTypeId: bool, typ: ASTType,
1071 initList: ASTParenExprList | ASTBracedInitList) -> None:
1072 self.rooted = rooted
1073 self.isNewTypeId = isNewTypeId
1074 self.typ = typ
1075 self.initList = initList
1076
1077 def __eq__(self, other: object) -> bool:
1078 if not isinstance(other, ASTNewExpr):
1079 return NotImplemented
1080 return (
1081 self.rooted == other.rooted
1082 and self.isNewTypeId == other.isNewTypeId
1083 and self.typ == other.typ
1084 and self.initList == other.initList
1085 )
1086
1087 def __hash__(self) -> int:
1088 return hash((self.rooted, self.isNewTypeId, self.typ, self.initList))
1089
1090 def _stringify(self, transform: StringifyTransform) -> str:
1091 res = []
1092 if self.rooted:
1093 res.append('::')
1094 res.append('new ')
1095 # TODO: placement
1096 if self.isNewTypeId:
1097 res.append(transform(self.typ))
1098 else:
1099 raise AssertionError
1100 if self.initList is not None:
1101 res.append(transform(self.initList))
1102 return ''.join(res)
1103
1104 def get_id(self, version: int) -> str:
1105 # the array part will be in the type mangling, so na is not used
1106 res = ['nw']
1107 # TODO: placement
1108 res.append('_')
1109 res.append(self.typ.get_id(version))
1110 if self.initList is not None:
1111 res.append(self.initList.get_id(version))
1112 else:
1113 res.append('E')
1114 return ''.join(res)
1115
1116 def describe_signature(self, signode: TextElement, mode: str,
1117 env: BuildEnvironment, symbol: Symbol) -> None:
1118 if self.rooted:
1119 signode += addnodes.desc_sig_punctuation('::', '::')
1120 signode += addnodes.desc_sig_keyword('new', 'new')
1121 signode += addnodes.desc_sig_space()
1122 # TODO: placement
1123 if self.isNewTypeId:
1124 self.typ.describe_signature(signode, mode, env, symbol)
1125 else:
1126 raise AssertionError
1127 if self.initList is not None:
1128 self.initList.describe_signature(signode, mode, env, symbol)
1129
1130
1131class ASTDeleteExpr(ASTExpression):
1132 def __init__(self, rooted: bool, array: bool, expr: ASTExpression) -> None:
1133 self.rooted = rooted
1134 self.array = array
1135 self.expr = expr
1136
1137 def __eq__(self, other: object) -> bool:
1138 if not isinstance(other, ASTDeleteExpr):
1139 return NotImplemented
1140 return (
1141 self.rooted == other.rooted
1142 and self.array == other.array
1143 and self.expr == other.expr
1144 )
1145
1146 def __hash__(self) -> int:
1147 return hash((self.rooted, self.array, self.expr))
1148
1149 def _stringify(self, transform: StringifyTransform) -> str:
1150 res = []
1151 if self.rooted:
1152 res.append('::')
1153 res.append('delete ')
1154 if self.array:
1155 res.append('[] ')
1156 res.append(transform(self.expr))
1157 return ''.join(res)
1158
1159 def get_id(self, version: int) -> str:
1160 if self.array:
1161 id = "da"
1162 else:
1163 id = "dl"
1164 return id + self.expr.get_id(version)
1165
1166 def describe_signature(self, signode: TextElement, mode: str,
1167 env: BuildEnvironment, symbol: Symbol) -> None:
1168 if self.rooted:
1169 signode += addnodes.desc_sig_punctuation('::', '::')
1170 signode += addnodes.desc_sig_keyword('delete', 'delete')
1171 signode += addnodes.desc_sig_space()
1172 if self.array:
1173 signode += addnodes.desc_sig_punctuation('[]', '[]')
1174 signode += addnodes.desc_sig_space()
1175 self.expr.describe_signature(signode, mode, env, symbol)
1176
1177
1178# Other expressions
1179################################################################################
1180
1181class ASTCastExpr(ASTExpression):
1182 def __init__(self, typ: ASTType, expr: ASTExpression) -> None:
1183 self.typ = typ
1184 self.expr = expr
1185
1186 def __eq__(self, other: object) -> bool:
1187 if not isinstance(other, ASTCastExpr):
1188 return NotImplemented
1189 return (
1190 self.typ == other.typ
1191 and self.expr == other.expr
1192 )
1193
1194 def __hash__(self) -> int:
1195 return hash((self.typ, self.expr))
1196
1197 def _stringify(self, transform: StringifyTransform) -> str:
1198 res = ['(']
1199 res.append(transform(self.typ))
1200 res.append(')')
1201 res.append(transform(self.expr))
1202 return ''.join(res)
1203
1204 def get_id(self, version: int) -> str:
1205 return 'cv' + self.typ.get_id(version) + self.expr.get_id(version)
1206
1207 def describe_signature(self, signode: TextElement, mode: str,
1208 env: BuildEnvironment, symbol: Symbol) -> None:
1209 signode += addnodes.desc_sig_punctuation('(', '(')
1210 self.typ.describe_signature(signode, mode, env, symbol)
1211 signode += addnodes.desc_sig_punctuation(')', ')')
1212 self.expr.describe_signature(signode, mode, env, symbol)
1213
1214
1215class ASTBinOpExpr(ASTExpression):
1216 def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None:
1217 assert len(exprs) > 0
1218 assert len(exprs) == len(ops) + 1
1219 self.exprs = exprs
1220 self.ops = ops
1221
1222 def __eq__(self, other: object) -> bool:
1223 if not isinstance(other, ASTBinOpExpr):
1224 return NotImplemented
1225 return (
1226 self.exprs == other.exprs
1227 and self.ops == other.ops
1228 )
1229
1230 def __hash__(self) -> int:
1231 return hash((self.exprs, self.ops))
1232
1233 def _stringify(self, transform: StringifyTransform) -> str:
1234 res = []
1235 res.append(transform(self.exprs[0]))
1236 for i in range(1, len(self.exprs)):
1237 res.append(' ')
1238 res.append(self.ops[i - 1])
1239 res.append(' ')
1240 res.append(transform(self.exprs[i]))
1241 return ''.join(res)
1242
1243 def get_id(self, version: int) -> str:
1244 assert version >= 2
1245 res = []
1246 for i in range(len(self.ops)):
1247 res.append(_id_operator_v2[self.ops[i]])
1248 res.append(self.exprs[i].get_id(version))
1249 res.append(self.exprs[-1].get_id(version))
1250 return ''.join(res)
1251
1252 def describe_signature(self, signode: TextElement, mode: str,
1253 env: BuildEnvironment, symbol: Symbol) -> None:
1254 self.exprs[0].describe_signature(signode, mode, env, symbol)
1255 for i in range(1, len(self.exprs)):
1256 signode += addnodes.desc_sig_space()
1257 op = self.ops[i - 1]
1258 if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
1259 signode += addnodes.desc_sig_keyword(op, op)
1260 else:
1261 signode += addnodes.desc_sig_operator(op, op)
1262 signode += addnodes.desc_sig_space()
1263 self.exprs[i].describe_signature(signode, mode, env, symbol)
1264
1265
1266class ASTConditionalExpr(ASTExpression):
1267 def __init__(self, ifExpr: ASTExpression, thenExpr: ASTExpression,
1268 elseExpr: ASTExpression) -> None:
1269 self.ifExpr = ifExpr
1270 self.thenExpr = thenExpr
1271 self.elseExpr = elseExpr
1272
1273 def __eq__(self, other: object) -> bool:
1274 if not isinstance(other, ASTConditionalExpr):
1275 return NotImplemented
1276 return (
1277 self.ifExpr == other.ifExpr
1278 and self.thenExpr == other.thenExpr
1279 and self.elseExpr == other.elseExpr
1280 )
1281
1282 def __hash__(self) -> int:
1283 return hash((self.ifExpr, self.thenExpr, self.elseExpr))
1284
1285 def _stringify(self, transform: StringifyTransform) -> str:
1286 res = []
1287 res.append(transform(self.ifExpr))
1288 res.append(' ? ')
1289 res.append(transform(self.thenExpr))
1290 res.append(' : ')
1291 res.append(transform(self.elseExpr))
1292 return ''.join(res)
1293
1294 def get_id(self, version: int) -> str:
1295 assert version >= 2
1296 res = []
1297 res.append(_id_operator_v2['?'])
1298 res.append(self.ifExpr.get_id(version))
1299 res.append(self.thenExpr.get_id(version))
1300 res.append(self.elseExpr.get_id(version))
1301 return ''.join(res)
1302
1303 def describe_signature(self, signode: TextElement, mode: str,
1304 env: BuildEnvironment, symbol: Symbol) -> None:
1305 self.ifExpr.describe_signature(signode, mode, env, symbol)
1306 signode += addnodes.desc_sig_space()
1307 signode += addnodes.desc_sig_operator('?', '?')
1308 signode += addnodes.desc_sig_space()
1309 self.thenExpr.describe_signature(signode, mode, env, symbol)
1310 signode += addnodes.desc_sig_space()
1311 signode += addnodes.desc_sig_operator(':', ':')
1312 signode += addnodes.desc_sig_space()
1313 self.elseExpr.describe_signature(signode, mode, env, symbol)
1314
1315
1316class ASTBracedInitList(ASTBase):
1317 def __init__(self, exprs: list[ASTExpression | ASTBracedInitList],
1318 trailingComma: bool) -> None:
1319 self.exprs = exprs
1320 self.trailingComma = trailingComma
1321
1322 def __eq__(self, other: object) -> bool:
1323 if not isinstance(other, ASTBracedInitList):
1324 return NotImplemented
1325 return self.exprs == other.exprs and self.trailingComma == other.trailingComma
1326
1327 def __hash__(self) -> int:
1328 return hash((self.exprs, self.trailingComma))
1329
1330 def get_id(self, version: int) -> str:
1331 return "il%sE" % ''.join(e.get_id(version) for e in self.exprs)
1332
1333 def _stringify(self, transform: StringifyTransform) -> str:
1334 exprs = ', '.join(transform(e) for e in self.exprs)
1335 trailingComma = ',' if self.trailingComma else ''
1336 return f'{{{exprs}{trailingComma}}}'
1337
1338 def describe_signature(self, signode: TextElement, mode: str,
1339 env: BuildEnvironment, symbol: Symbol) -> None:
1340 verify_description_mode(mode)
1341 signode += addnodes.desc_sig_punctuation('{', '{')
1342 first = True
1343 for e in self.exprs:
1344 if not first:
1345 signode += addnodes.desc_sig_punctuation(',', ',')
1346 signode += addnodes.desc_sig_space()
1347 else:
1348 first = False
1349 e.describe_signature(signode, mode, env, symbol)
1350 if self.trailingComma:
1351 signode += addnodes.desc_sig_punctuation(',', ',')
1352 signode += addnodes.desc_sig_punctuation('}', '}')
1353
1354
1355class ASTAssignmentExpr(ASTExpression):
1356 def __init__(self, leftExpr: ASTExpression, op: str,
1357 rightExpr: ASTExpression | ASTBracedInitList) -> None:
1358 self.leftExpr = leftExpr
1359 self.op = op
1360 self.rightExpr = rightExpr
1361
1362 def __eq__(self, other: object) -> bool:
1363 if not isinstance(other, ASTAssignmentExpr):
1364 return NotImplemented
1365 return (
1366 self.leftExpr == other.leftExpr
1367 and self.op == other.op
1368 and self.rightExpr == other.rightExpr
1369 )
1370
1371 def __hash__(self) -> int:
1372 return hash((self.leftExpr, self.op, self.rightExpr))
1373
1374 def _stringify(self, transform: StringifyTransform) -> str:
1375 res = []
1376 res.append(transform(self.leftExpr))
1377 res.append(' ')
1378 res.append(self.op)
1379 res.append(' ')
1380 res.append(transform(self.rightExpr))
1381 return ''.join(res)
1382
1383 def get_id(self, version: int) -> str:
1384 # we end up generating the ID from left to right, instead of right to left
1385 res = []
1386 res.append(_id_operator_v2[self.op])
1387 res.append(self.leftExpr.get_id(version))
1388 res.append(self.rightExpr.get_id(version))
1389 return ''.join(res)
1390
1391 def describe_signature(self, signode: TextElement, mode: str,
1392 env: BuildEnvironment, symbol: Symbol) -> None:
1393 self.leftExpr.describe_signature(signode, mode, env, symbol)
1394 signode += addnodes.desc_sig_space()
1395 if ord(self.op[0]) >= ord('a') and ord(self.op[0]) <= ord('z'):
1396 signode += addnodes.desc_sig_keyword(self.op, self.op)
1397 else:
1398 signode += addnodes.desc_sig_operator(self.op, self.op)
1399 signode += addnodes.desc_sig_space()
1400 self.rightExpr.describe_signature(signode, mode, env, symbol)
1401
1402
1403class ASTCommaExpr(ASTExpression):
1404 def __init__(self, exprs: list[ASTExpression]) -> None:
1405 assert len(exprs) > 0
1406 self.exprs = exprs
1407
1408 def __eq__(self, other: object) -> bool:
1409 if not isinstance(other, ASTCommaExpr):
1410 return NotImplemented
1411 return self.exprs == other.exprs
1412
1413 def __hash__(self) -> int:
1414 return hash(self.exprs)
1415
1416 def _stringify(self, transform: StringifyTransform) -> str:
1417 return ', '.join(transform(e) for e in self.exprs)
1418
1419 def get_id(self, version: int) -> str:
1420 id_ = _id_operator_v2[',']
1421 res = []
1422 for i in range(len(self.exprs) - 1):
1423 res.append(id_)
1424 res.append(self.exprs[i].get_id(version))
1425 res.append(self.exprs[-1].get_id(version))
1426 return ''.join(res)
1427
1428 def describe_signature(self, signode: TextElement, mode: str,
1429 env: BuildEnvironment, symbol: Symbol) -> None:
1430 self.exprs[0].describe_signature(signode, mode, env, symbol)
1431 for i in range(1, len(self.exprs)):
1432 signode += addnodes.desc_sig_punctuation(',', ',')
1433 signode += addnodes.desc_sig_space()
1434 self.exprs[i].describe_signature(signode, mode, env, symbol)
1435
1436
1437class ASTFallbackExpr(ASTExpression):
1438 def __init__(self, expr: str) -> None:
1439 self.expr = expr
1440
1441 def __eq__(self, other: object) -> bool:
1442 if not isinstance(other, ASTFallbackExpr):
1443 return NotImplemented
1444 return self.expr == other.expr
1445
1446 def __hash__(self) -> int:
1447 return hash(self.expr)
1448
1449 def _stringify(self, transform: StringifyTransform) -> str:
1450 return self.expr
1451
1452 def get_id(self, version: int) -> str:
1453 return str(self.expr)
1454
1455 def describe_signature(self, signode: TextElement, mode: str,
1456 env: BuildEnvironment, symbol: Symbol) -> None:
1457 signode += nodes.literal(self.expr, self.expr)
1458
1459
1460################################################################################
1461# Types
1462################################################################################
1463
1464# Things for ASTNestedName
1465################################################################################
1466
1467class ASTOperator(ASTBase):
1468 is_anonymous: ClassVar[Literal[False]] = False
1469
1470 def __eq__(self, other: object) -> bool:
1471 raise NotImplementedError(repr(self))
1472
1473 def __hash__(self) -> int:
1474 raise NotImplementedError(repr(self))
1475
1476 def is_anon(self) -> bool:
1477 return self.is_anonymous
1478
1479 def is_operator(self) -> bool:
1480 return True
1481
1482 def get_id(self, version: int) -> str:
1483 raise NotImplementedError
1484
1485 def _describe_identifier(self, signode: TextElement, identnode: TextElement,
1486 env: BuildEnvironment, symbol: Symbol) -> None:
1487 """Render the prefix into signode, and the last part into identnode."""
1488 raise NotImplementedError
1489
1490 def describe_signature(self, signode: TextElement, mode: str,
1491 env: BuildEnvironment, prefix: str, templateArgs: str,
1492 symbol: Symbol) -> None:
1493 verify_description_mode(mode)
1494 if mode == 'lastIsName':
1495 mainName = addnodes.desc_name()
1496 self._describe_identifier(mainName, mainName, env, symbol)
1497 signode += mainName
1498 elif mode == 'markType':
1499 targetText = prefix + str(self) + templateArgs
1500 pnode = addnodes.pending_xref('', refdomain='cpp',
1501 reftype='identifier',
1502 reftarget=targetText, modname=None,
1503 classname=None)
1504 pnode['cpp:parent_key'] = symbol.get_lookup_key()
1505 # Render the identifier part, but collapse it into a string
1506 # and make that the a link to this operator.
1507 # E.g., if it is 'operator SomeType', then 'SomeType' becomes
1508 # a link to the operator, not to 'SomeType'.
1509 container = nodes.literal()
1510 self._describe_identifier(signode, container, env, symbol)
1511 txt = container.astext()
1512 pnode += addnodes.desc_name(txt, txt)
1513 signode += pnode
1514 else:
1515 addName = addnodes.desc_addname()
1516 self._describe_identifier(addName, addName, env, symbol)
1517 signode += addName
1518
1519
1520class ASTOperatorBuildIn(ASTOperator):
1521 def __init__(self, op: str) -> None:
1522 self.op = op
1523
1524 def __eq__(self, other: object) -> bool:
1525 if not isinstance(other, ASTOperatorBuildIn):
1526 return NotImplemented
1527 return self.op == other.op
1528
1529 def __hash__(self) -> int:
1530 return hash(self.op)
1531
1532 def get_id(self, version: int) -> str:
1533 if version == 1:
1534 ids = _id_operator_v1
1535 if self.op not in ids:
1536 raise NoOldIdError
1537 else:
1538 ids = _id_operator_v2
1539 if self.op not in ids:
1540 raise Exception('Internal error: Built-in operator "%s" can not '
1541 'be mapped to an id.' % self.op)
1542 return ids[self.op]
1543
1544 def _stringify(self, transform: StringifyTransform) -> str:
1545 if self.op in ('new', 'new[]', 'delete', 'delete[]') or self.op[0] in "abcnox":
1546 return 'operator ' + self.op
1547 else:
1548 return 'operator' + self.op
1549
1550 def _describe_identifier(self, signode: TextElement, identnode: TextElement,
1551 env: BuildEnvironment, symbol: Symbol) -> None:
1552 signode += addnodes.desc_sig_keyword('operator', 'operator')
1553 if self.op in ('new', 'new[]', 'delete', 'delete[]') or self.op[0] in "abcnox":
1554 signode += addnodes.desc_sig_space()
1555 identnode += addnodes.desc_sig_operator(self.op, self.op)
1556
1557
1558class ASTOperatorLiteral(ASTOperator):
1559 def __init__(self, identifier: ASTIdentifier) -> None:
1560 self.identifier = identifier
1561
1562 def __eq__(self, other: object) -> bool:
1563 if not isinstance(other, ASTOperatorLiteral):
1564 return NotImplemented
1565 return self.identifier == other.identifier
1566
1567 def __hash__(self) -> int:
1568 return hash(self.identifier)
1569
1570 def get_id(self, version: int) -> str:
1571 if version == 1:
1572 raise NoOldIdError
1573 return 'li' + self.identifier.get_id(version)
1574
1575 def _stringify(self, transform: StringifyTransform) -> str:
1576 return 'operator""' + transform(self.identifier)
1577
1578 def _describe_identifier(self, signode: TextElement, identnode: TextElement,
1579 env: BuildEnvironment, symbol: Symbol) -> None:
1580 signode += addnodes.desc_sig_keyword('operator', 'operator')
1581 signode += addnodes.desc_sig_literal_string('""', '""')
1582 self.identifier.describe_signature(identnode, 'markType', env, '', '', symbol)
1583
1584
1585class ASTOperatorType(ASTOperator):
1586 def __init__(self, type: ASTType) -> None:
1587 self.type = type
1588
1589 def __eq__(self, other: object) -> bool:
1590 if not isinstance(other, ASTOperatorType):
1591 return NotImplemented
1592 return self.type == other.type
1593
1594 def __hash__(self) -> int:
1595 return hash(self.type)
1596
1597 def get_id(self, version: int) -> str:
1598 if version == 1:
1599 return 'castto-%s-operator' % self.type.get_id(version)
1600 else:
1601 return 'cv' + self.type.get_id(version)
1602
1603 def _stringify(self, transform: StringifyTransform) -> str:
1604 return f'operator {transform(self.type)}'
1605
1606 def get_name_no_template(self) -> str:
1607 return str(self)
1608
1609 def _describe_identifier(self, signode: TextElement, identnode: TextElement,
1610 env: BuildEnvironment, symbol: Symbol) -> None:
1611 signode += addnodes.desc_sig_keyword('operator', 'operator')
1612 signode += addnodes.desc_sig_space()
1613 self.type.describe_signature(identnode, 'markType', env, symbol)
1614
1615
1616class ASTTemplateArgConstant(ASTBase):
1617 def __init__(self, value: ASTExpression) -> None:
1618 self.value = value
1619
1620 def __eq__(self, other: object) -> bool:
1621 if not isinstance(other, ASTTemplateArgConstant):
1622 return NotImplemented
1623 return self.value == other.value
1624
1625 def __hash__(self) -> int:
1626 return hash(self.value)
1627
1628 def _stringify(self, transform: StringifyTransform) -> str:
1629 return transform(self.value)
1630
1631 def get_id(self, version: int) -> str:
1632 if version == 1:
1633 return str(self).replace(' ', '-')
1634 if version == 2:
1635 return 'X' + str(self) + 'E'
1636 return 'X' + self.value.get_id(version) + 'E'
1637
1638 def describe_signature(self, signode: TextElement, mode: str,
1639 env: BuildEnvironment, symbol: Symbol) -> None:
1640 verify_description_mode(mode)
1641 self.value.describe_signature(signode, mode, env, symbol)
1642
1643
1644class ASTTemplateArgs(ASTBase):
1645 def __init__(self, args: list[ASTType | ASTTemplateArgConstant],
1646 packExpansion: bool) -> None:
1647 assert args is not None
1648 self.args = args
1649 self.packExpansion = packExpansion
1650
1651 def __eq__(self, other: object) -> bool:
1652 if not isinstance(other, ASTTemplateArgs):
1653 return NotImplemented
1654 return self.args == other.args and self.packExpansion == other.packExpansion
1655
1656 def __hash__(self) -> int:
1657 return hash((self.args, self.packExpansion))
1658
1659 def get_id(self, version: int) -> str:
1660 if version == 1:
1661 res = []
1662 res.append(':')
1663 res.append('.'.join(a.get_id(version) for a in self.args))
1664 res.append(':')
1665 return ''.join(res)
1666
1667 res = []
1668 res.append('I')
1669 if len(self.args) > 0:
1670 for a in self.args[:-1]:
1671 res.append(a.get_id(version))
1672 if self.packExpansion:
1673 res.append('J')
1674 res.append(self.args[-1].get_id(version))
1675 if self.packExpansion:
1676 res.append('E')
1677 res.append('E')
1678 return ''.join(res)
1679
1680 def _stringify(self, transform: StringifyTransform) -> str:
1681 res = ', '.join(transform(a) for a in self.args)
1682 if self.packExpansion:
1683 res += '...'
1684 return '<' + res + '>'
1685
1686 def describe_signature(self, signode: TextElement, mode: str,
1687 env: BuildEnvironment, symbol: Symbol) -> None:
1688 verify_description_mode(mode)
1689 signode += addnodes.desc_sig_punctuation('<', '<')
1690 first = True
1691 for a in self.args:
1692 if not first:
1693 signode += addnodes.desc_sig_punctuation(',', ',')
1694 signode += addnodes.desc_sig_space()
1695 first = False
1696 a.describe_signature(signode, 'markType', env, symbol=symbol)
1697 if self.packExpansion:
1698 signode += addnodes.desc_sig_punctuation('...', '...')
1699 signode += addnodes.desc_sig_punctuation('>', '>')
1700
1701
1702# Main part of declarations
1703################################################################################
1704
1705class ASTTrailingTypeSpec(ASTBase):
1706 def get_id(self, version: int) -> str:
1707 raise NotImplementedError(repr(self))
1708
1709 def describe_signature(self, signode: TextElement, mode: str,
1710 env: BuildEnvironment, symbol: Symbol) -> None:
1711 raise NotImplementedError(repr(self))
1712
1713
1714class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
1715 def __init__(self, names: list[str], canonNames: list[str]) -> None:
1716 assert len(names) != 0
1717 assert len(names) == len(canonNames), (names, canonNames)
1718 self.names = names
1719 # the canonical name list is for ID lookup
1720 self.canonNames = canonNames
1721
1722 def __eq__(self, other: object) -> bool:
1723 if not isinstance(other, ASTTrailingTypeSpecFundamental):
1724 return NotImplemented
1725 return self.names == other.names and self.canonNames == other.canonNames
1726
1727 def __hash__(self) -> int:
1728 return hash((self.names, self.canonNames))
1729
1730 def _stringify(self, transform: StringifyTransform) -> str:
1731 return ' '.join(self.names)
1732
1733 def get_id(self, version: int) -> str:
1734 if version == 1:
1735 res = []
1736 for a in self.canonNames:
1737 if a in _id_fundamental_v1:
1738 res.append(_id_fundamental_v1[a])
1739 else:
1740 res.append(a)
1741 return '-'.join(res)
1742
1743 txt = ' '.join(self.canonNames)
1744 if txt not in _id_fundamental_v2:
1745 raise Exception(
1746 'Semi-internal error: Fundamental type "%s" can not be mapped '
1747 'to an ID. Is it a true fundamental type? If not so, the '
1748 'parser should have rejected it.' % txt)
1749 return _id_fundamental_v2[txt]
1750
1751 def describe_signature(self, signode: TextElement, mode: str,
1752 env: BuildEnvironment, symbol: Symbol) -> None:
1753 first = True
1754 for n in self.names:
1755 if not first:
1756 signode += addnodes.desc_sig_space()
1757 else:
1758 first = False
1759 signode += addnodes.desc_sig_keyword_type(n, n)
1760
1761
1762class ASTTrailingTypeSpecDecltypeAuto(ASTTrailingTypeSpec):
1763 def __eq__(self, other: object) -> bool:
1764 return isinstance(other, ASTTrailingTypeSpecDecltypeAuto)
1765
1766 def __hash__(self) -> int:
1767 return hash('decltype(auto)')
1768
1769 def _stringify(self, transform: StringifyTransform) -> str:
1770 return 'decltype(auto)'
1771
1772 def get_id(self, version: int) -> str:
1773 if version == 1:
1774 raise NoOldIdError
1775 return 'Dc'
1776
1777 def describe_signature(self, signode: TextElement, mode: str,
1778 env: BuildEnvironment, symbol: Symbol) -> None:
1779 signode += addnodes.desc_sig_keyword('decltype', 'decltype')
1780 signode += addnodes.desc_sig_punctuation('(', '(')
1781 signode += addnodes.desc_sig_keyword('auto', 'auto')
1782 signode += addnodes.desc_sig_punctuation(')', ')')
1783
1784
1785class ASTTrailingTypeSpecDecltype(ASTTrailingTypeSpec):
1786 def __init__(self, expr: ASTExpression) -> None:
1787 self.expr = expr
1788
1789 def __eq__(self, other: object) -> bool:
1790 if not isinstance(other, ASTTrailingTypeSpecDecltype):
1791 return NotImplemented
1792 return self.expr == other.expr
1793
1794 def __hash__(self) -> int:
1795 return hash(self.expr)
1796
1797 def _stringify(self, transform: StringifyTransform) -> str:
1798 return 'decltype(' + transform(self.expr) + ')'
1799
1800 def get_id(self, version: int) -> str:
1801 if version == 1:
1802 raise NoOldIdError
1803 return 'DT' + self.expr.get_id(version) + "E"
1804
1805 def describe_signature(self, signode: TextElement, mode: str,
1806 env: BuildEnvironment, symbol: Symbol) -> None:
1807 signode += addnodes.desc_sig_keyword('decltype', 'decltype')
1808 signode += addnodes.desc_sig_punctuation('(', '(')
1809 self.expr.describe_signature(signode, mode, env, symbol)
1810 signode += addnodes.desc_sig_punctuation(')', ')')
1811
1812
1813class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
1814 def __init__(self, prefix: str, nestedName: ASTNestedName,
1815 placeholderType: str | None) -> None:
1816 self.prefix = prefix
1817 self.nestedName = nestedName
1818 self.placeholderType = placeholderType
1819
1820 def __eq__(self, other: object) -> bool:
1821 if not isinstance(other, ASTTrailingTypeSpecName):
1822 return NotImplemented
1823 return (
1824 self.prefix == other.prefix
1825 and self.nestedName == other.nestedName
1826 and self.placeholderType == other.placeholderType
1827 )
1828
1829 def __hash__(self) -> int:
1830 return hash((self.prefix, self.nestedName, self.placeholderType))
1831
1832 @property
1833 def name(self) -> ASTNestedName:
1834 return self.nestedName
1835
1836 def get_id(self, version: int) -> str:
1837 return self.nestedName.get_id(version)
1838
1839 def _stringify(self, transform: StringifyTransform) -> str:
1840 res = []
1841 if self.prefix:
1842 res.append(self.prefix)
1843 res.append(' ')
1844 res.append(transform(self.nestedName))
1845 if self.placeholderType is not None:
1846 res.append(' ')
1847 res.append(self.placeholderType)
1848 return ''.join(res)
1849
1850 def describe_signature(self, signode: TextElement, mode: str,
1851 env: BuildEnvironment, symbol: Symbol) -> None:
1852 if self.prefix:
1853 signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
1854 signode += addnodes.desc_sig_space()
1855 self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
1856 if self.placeholderType is not None:
1857 signode += addnodes.desc_sig_space()
1858 if self.placeholderType == 'auto':
1859 signode += addnodes.desc_sig_keyword('auto', 'auto')
1860 elif self.placeholderType == 'decltype(auto)':
1861 signode += addnodes.desc_sig_keyword('decltype', 'decltype')
1862 signode += addnodes.desc_sig_punctuation('(', '(')
1863 signode += addnodes.desc_sig_keyword('auto', 'auto')
1864 signode += addnodes.desc_sig_punctuation(')', ')')
1865 else:
1866 raise AssertionError(self.placeholderType)
1867
1868
1869class ASTFunctionParameter(ASTBase):
1870 def __init__(self, arg: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit,
1871 ellipsis: bool = False) -> None:
1872 self.arg = arg
1873 self.ellipsis = ellipsis
1874
1875 def __eq__(self, other: object) -> bool:
1876 if not isinstance(other, ASTFunctionParameter):
1877 return NotImplemented
1878 return self.arg == other.arg and self.ellipsis == other.ellipsis
1879
1880 def __hash__(self) -> int:
1881 return hash((self.arg, self.ellipsis))
1882
1883 def get_id(
1884 self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
1885 ) -> str:
1886 # this is not part of the normal name mangling in C++
1887 if symbol:
1888 # the anchor will be our parent
1889 return symbol.parent.declaration.get_id(version, prefixed=False)
1890 # else, do the usual
1891 if self.ellipsis:
1892 return 'z'
1893 else:
1894 return self.arg.get_id(version)
1895
1896 def _stringify(self, transform: StringifyTransform) -> str:
1897 if self.ellipsis:
1898 return '...'
1899 else:
1900 return transform(self.arg)
1901
1902 def describe_signature(self, signode: TextElement, mode: str,
1903 env: BuildEnvironment, symbol: Symbol) -> None:
1904 verify_description_mode(mode)
1905 if self.ellipsis:
1906 signode += addnodes.desc_sig_punctuation('...', '...')
1907 else:
1908 self.arg.describe_signature(signode, mode, env, symbol=symbol)
1909
1910
1911class ASTNoexceptSpec(ASTBase):
1912 def __init__(self, expr: ASTExpression | None) -> None:
1913 self.expr = expr
1914
1915 def __eq__(self, other: object) -> bool:
1916 if not isinstance(other, ASTNoexceptSpec):
1917 return NotImplemented
1918 return self.expr == other.expr
1919
1920 def __hash__(self) -> int:
1921 return hash(self.expr)
1922
1923 def _stringify(self, transform: StringifyTransform) -> str:
1924 if self.expr:
1925 return 'noexcept(' + transform(self.expr) + ')'
1926 return 'noexcept'
1927
1928 def describe_signature(self, signode: TextElement, mode: str,
1929 env: BuildEnvironment, symbol: Symbol) -> None:
1930 signode += addnodes.desc_sig_keyword('noexcept', 'noexcept')
1931 if self.expr:
1932 signode += addnodes.desc_sig_punctuation('(', '(')
1933 self.expr.describe_signature(signode, 'markType', env, symbol)
1934 signode += addnodes.desc_sig_punctuation(')', ')')
1935
1936
1937class ASTParametersQualifiers(ASTBase):
1938 def __init__(self, args: list[ASTFunctionParameter], volatile: bool, const: bool,
1939 refQual: str | None, exceptionSpec: ASTNoexceptSpec,
1940 trailingReturn: ASTType,
1941 override: bool, final: bool, attrs: ASTAttributeList,
1942 initializer: str | None) -> None:
1943 self.args = args
1944 self.volatile = volatile
1945 self.const = const
1946 self.refQual = refQual
1947 self.exceptionSpec = exceptionSpec
1948 self.trailingReturn = trailingReturn
1949 self.override = override
1950 self.final = final
1951 self.attrs = attrs
1952 self.initializer = initializer
1953
1954 def __eq__(self, other: object) -> bool:
1955 if not isinstance(other, ASTParametersQualifiers):
1956 return NotImplemented
1957 return (
1958 self.args == other.args
1959 and self.volatile == other.volatile
1960 and self.const == other.const
1961 and self.refQual == other.refQual
1962 and self.exceptionSpec == other.exceptionSpec
1963 and self.trailingReturn == other.trailingReturn
1964 and self.override == other.override
1965 and self.final == other.final
1966 and self.attrs == other.attrs
1967 and self.initializer == other.initializer
1968 )
1969
1970 def __hash__(self) -> int:
1971 return hash((
1972 self.args, self.volatile, self.const, self.refQual, self.exceptionSpec,
1973 self.trailingReturn, self.override, self.final, self.attrs, self.initializer
1974 ))
1975
1976 @property
1977 def function_params(self) -> list[ASTFunctionParameter]:
1978 return self.args
1979
1980 def get_modifiers_id(self, version: int) -> str:
1981 res = []
1982 if self.volatile:
1983 res.append('V')
1984 if self.const:
1985 if version == 1:
1986 res.append('C')
1987 else:
1988 res.append('K')
1989 if self.refQual == '&&':
1990 res.append('O')
1991 elif self.refQual == '&':
1992 res.append('R')
1993 return ''.join(res)
1994
1995 def get_param_id(self, version: int) -> str:
1996 if version == 1:
1997 if len(self.args) == 0:
1998 return ''
1999 else:
2000 return '__' + '.'.join(a.get_id(version) for a in self.args)
2001 if len(self.args) == 0:
2002 return 'v'
2003 else:
2004 return ''.join(a.get_id(version) for a in self.args)
2005
2006 def _stringify(self, transform: StringifyTransform) -> str:
2007 res = []
2008 res.append('(')
2009 first = True
2010 for a in self.args:
2011 if not first:
2012 res.append(', ')
2013 first = False
2014 res.append(str(a))
2015 res.append(')')
2016 if self.volatile:
2017 res.append(' volatile')
2018 if self.const:
2019 res.append(' const')
2020 if self.refQual:
2021 res.append(' ')
2022 res.append(self.refQual)
2023 if self.exceptionSpec:
2024 res.append(' ')
2025 res.append(transform(self.exceptionSpec))
2026 if self.trailingReturn:
2027 res.append(' -> ')
2028 res.append(transform(self.trailingReturn))
2029 if self.final:
2030 res.append(' final')
2031 if self.override:
2032 res.append(' override')
2033 if len(self.attrs) != 0:
2034 res.append(' ')
2035 res.append(transform(self.attrs))
2036 if self.initializer:
2037 res.append(' = ')
2038 res.append(self.initializer)
2039 return ''.join(res)
2040
2041 def describe_signature(self, signode: TextElement, mode: str,
2042 env: BuildEnvironment, symbol: Symbol) -> None:
2043 verify_description_mode(mode)
2044 multi_line_parameter_list = False
2045 test_node: Element = signode
2046 while test_node.parent:
2047 if not isinstance(test_node, addnodes.desc_signature):
2048 test_node = test_node.parent
2049 continue
2050 multi_line_parameter_list = test_node.get('multi_line_parameter_list', False)
2051 break
2052
2053 # only use the desc_parameterlist for the outer list, not for inner lists
2054 if mode == 'lastIsName':
2055 paramlist = addnodes.desc_parameterlist()
2056 paramlist['multi_line_parameter_list'] = multi_line_parameter_list
2057 for arg in self.args:
2058 param = addnodes.desc_parameter('', '', noemph=True)
2059 arg.describe_signature(param, 'param', env, symbol=symbol)
2060 paramlist += param
2061 signode += paramlist
2062 else:
2063 signode += addnodes.desc_sig_punctuation('(', '(')
2064 first = True
2065 for arg in self.args:
2066 if not first:
2067 signode += addnodes.desc_sig_punctuation(',', ',')
2068 signode += addnodes.desc_sig_space()
2069 first = False
2070 arg.describe_signature(signode, 'markType', env, symbol=symbol)
2071 signode += addnodes.desc_sig_punctuation(')', ')')
2072
2073 def _add_anno(signode: TextElement, text: str) -> None:
2074 signode += addnodes.desc_sig_space()
2075 signode += addnodes.desc_sig_keyword(text, text)
2076
2077 if self.volatile:
2078 _add_anno(signode, 'volatile')
2079 if self.const:
2080 _add_anno(signode, 'const')
2081 if self.refQual:
2082 signode += addnodes.desc_sig_space()
2083 signode += addnodes.desc_sig_punctuation(self.refQual, self.refQual)
2084 if self.exceptionSpec:
2085 signode += addnodes.desc_sig_space()
2086 self.exceptionSpec.describe_signature(signode, mode, env, symbol)
2087 if self.trailingReturn:
2088 signode += addnodes.desc_sig_space()
2089 signode += addnodes.desc_sig_operator('->', '->')
2090 signode += addnodes.desc_sig_space()
2091 self.trailingReturn.describe_signature(signode, mode, env, symbol)
2092 if self.final:
2093 _add_anno(signode, 'final')
2094 if self.override:
2095 _add_anno(signode, 'override')
2096 if len(self.attrs) != 0:
2097 signode += addnodes.desc_sig_space()
2098 self.attrs.describe_signature(signode)
2099 if self.initializer:
2100 signode += addnodes.desc_sig_space()
2101 signode += addnodes.desc_sig_punctuation('=', '=')
2102 signode += addnodes.desc_sig_space()
2103 assert self.initializer in ('0', 'delete', 'default')
2104 if self.initializer == '0':
2105 signode += addnodes.desc_sig_literal_number('0', '0')
2106 else:
2107 signode += addnodes.desc_sig_keyword(self.initializer, self.initializer)
2108
2109
2110class ASTExplicitSpec(ASTBase):
2111 def __init__(self, expr: ASTExpression | None) -> None:
2112 self.expr = expr
2113
2114 def __eq__(self, other: object) -> bool:
2115 if not isinstance(other, ASTExplicitSpec):
2116 return NotImplemented
2117 return self.expr == other.expr
2118
2119 def __hash__(self) -> int:
2120 return hash(self.expr)
2121
2122 def _stringify(self, transform: StringifyTransform) -> str:
2123 res = ['explicit']
2124 if self.expr is not None:
2125 res.append('(')
2126 res.append(transform(self.expr))
2127 res.append(')')
2128 return ''.join(res)
2129
2130 def describe_signature(self, signode: TextElement,
2131 env: BuildEnvironment, symbol: Symbol) -> None:
2132 signode += addnodes.desc_sig_keyword('explicit', 'explicit')
2133 if self.expr is not None:
2134 signode += addnodes.desc_sig_punctuation('(', '(')
2135 self.expr.describe_signature(signode, 'markType', env, symbol)
2136 signode += addnodes.desc_sig_punctuation(')', ')')
2137
2138
2139class ASTDeclSpecsSimple(ASTBase):
2140 def __init__(self, storage: str, threadLocal: bool, inline: bool, virtual: bool,
2141 explicitSpec: ASTExplicitSpec | None,
2142 consteval: bool, constexpr: bool, constinit: bool,
2143 volatile: bool, const: bool, friend: bool,
2144 attrs: ASTAttributeList) -> None:
2145 self.storage = storage
2146 self.threadLocal = threadLocal
2147 self.inline = inline
2148 self.virtual = virtual
2149 self.explicitSpec = explicitSpec
2150 self.consteval = consteval
2151 self.constexpr = constexpr
2152 self.constinit = constinit
2153 self.volatile = volatile
2154 self.const = const
2155 self.friend = friend
2156 self.attrs = attrs
2157
2158 def __eq__(self, other: object) -> bool:
2159 if not isinstance(other, ASTDeclSpecsSimple):
2160 return NotImplemented
2161 return (
2162 self.storage == other.storage
2163 and self.threadLocal == other.threadLocal
2164 and self.inline == other.inline
2165 and self.virtual == other.virtual
2166 and self.explicitSpec == other.explicitSpec
2167 and self.consteval == other.consteval
2168 and self.constexpr == other.constexpr
2169 and self.constinit == other.constinit
2170 and self.volatile == other.volatile
2171 and self.const == other.const
2172 and self.friend == other.friend
2173 and self.attrs == other.attrs
2174 )
2175
2176 def __hash__(self) -> int:
2177 return hash((
2178 self.storage,
2179 self.threadLocal,
2180 self.inline,
2181 self.virtual,
2182 self.explicitSpec,
2183 self.consteval,
2184 self.constexpr,
2185 self.constinit,
2186 self.volatile,
2187 self.const,
2188 self.friend,
2189 self.attrs,
2190 ))
2191
2192 def mergeWith(self, other: ASTDeclSpecsSimple) -> ASTDeclSpecsSimple:
2193 if not other:
2194 return self
2195 return ASTDeclSpecsSimple(self.storage or other.storage,
2196 self.threadLocal or other.threadLocal,
2197 self.inline or other.inline,
2198 self.virtual or other.virtual,
2199 self.explicitSpec or other.explicitSpec,
2200 self.consteval or other.consteval,
2201 self.constexpr or other.constexpr,
2202 self.constinit or other.constinit,
2203 self.volatile or other.volatile,
2204 self.const or other.const,
2205 self.friend or other.friend,
2206 self.attrs + other.attrs)
2207
2208 def _stringify(self, transform: StringifyTransform) -> str:
2209 res: list[str] = []
2210 if len(self.attrs) != 0:
2211 res.append(transform(self.attrs))
2212 if self.storage:
2213 res.append(self.storage)
2214 if self.threadLocal:
2215 res.append('thread_local')
2216 if self.inline:
2217 res.append('inline')
2218 if self.friend:
2219 res.append('friend')
2220 if self.virtual:
2221 res.append('virtual')
2222 if self.explicitSpec:
2223 res.append(transform(self.explicitSpec))
2224 if self.consteval:
2225 res.append('consteval')
2226 if self.constexpr:
2227 res.append('constexpr')
2228 if self.constinit:
2229 res.append('constinit')
2230 if self.volatile:
2231 res.append('volatile')
2232 if self.const:
2233 res.append('const')
2234 return ' '.join(res)
2235
2236 def describe_signature(self, signode: TextElement,
2237 env: BuildEnvironment, symbol: Symbol) -> None:
2238 self.attrs.describe_signature(signode)
2239 addSpace = len(self.attrs) != 0
2240
2241 def _add(signode: TextElement, text: str) -> bool:
2242 if addSpace:
2243 signode += addnodes.desc_sig_space()
2244 signode += addnodes.desc_sig_keyword(text, text)
2245 return True
2246
2247 if self.storage:
2248 addSpace = _add(signode, self.storage)
2249 if self.threadLocal:
2250 addSpace = _add(signode, 'thread_local')
2251 if self.inline:
2252 addSpace = _add(signode, 'inline')
2253 if self.friend:
2254 addSpace = _add(signode, 'friend')
2255 if self.virtual:
2256 addSpace = _add(signode, 'virtual')
2257 if self.explicitSpec:
2258 if addSpace:
2259 signode += addnodes.desc_sig_space()
2260 self.explicitSpec.describe_signature(signode, env, symbol)
2261 addSpace = True
2262 if self.consteval:
2263 addSpace = _add(signode, 'consteval')
2264 if self.constexpr:
2265 addSpace = _add(signode, 'constexpr')
2266 if self.constinit:
2267 addSpace = _add(signode, 'constinit')
2268 if self.volatile:
2269 addSpace = _add(signode, 'volatile')
2270 if self.const:
2271 addSpace = _add(signode, 'const')
2272
2273
2274class ASTDeclSpecs(ASTBase):
2275 def __init__(self, outer: str,
2276 leftSpecs: ASTDeclSpecsSimple, rightSpecs: ASTDeclSpecsSimple,
2277 trailing: ASTTrailingTypeSpec) -> None:
2278 # leftSpecs and rightSpecs are used for output
2279 # allSpecs are used for id generation
2280 self.outer = outer
2281 self.leftSpecs = leftSpecs
2282 self.rightSpecs = rightSpecs
2283 self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
2284 self.trailingTypeSpec = trailing
2285
2286 def __eq__(self, other: object) -> bool:
2287 if not isinstance(other, ASTDeclSpecs):
2288 return NotImplemented
2289 return (
2290 self.outer == other.outer
2291 and self.leftSpecs == other.leftSpecs
2292 and self.rightSpecs == other.rightSpecs
2293 and self.trailingTypeSpec == other.trailingTypeSpec
2294 )
2295
2296 def __hash__(self) -> int:
2297 return hash((
2298 self.outer,
2299 self.leftSpecs,
2300 self.rightSpecs,
2301 self.trailingTypeSpec,
2302 ))
2303
2304 def get_id(self, version: int) -> str:
2305 if version == 1:
2306 res = []
2307 res.append(self.trailingTypeSpec.get_id(version))
2308 if self.allSpecs.volatile:
2309 res.append('V')
2310 if self.allSpecs.const:
2311 res.append('C')
2312 return ''.join(res)
2313 res = []
2314 if self.allSpecs.volatile:
2315 res.append('V')
2316 if self.allSpecs.const:
2317 res.append('K')
2318 if self.trailingTypeSpec is not None:
2319 res.append(self.trailingTypeSpec.get_id(version))
2320 return ''.join(res)
2321
2322 def _stringify(self, transform: StringifyTransform) -> str:
2323 res: list[str] = []
2324 l = transform(self.leftSpecs)
2325 if len(l) > 0:
2326 res.append(l)
2327 if self.trailingTypeSpec:
2328 if len(res) > 0:
2329 res.append(" ")
2330 res.append(transform(self.trailingTypeSpec))
2331 r = str(self.rightSpecs)
2332 if len(r) > 0:
2333 if len(res) > 0:
2334 res.append(" ")
2335 res.append(r)
2336 return "".join(res)
2337
2338 def describe_signature(self, signode: TextElement, mode: str,
2339 env: BuildEnvironment, symbol: Symbol) -> None:
2340 verify_description_mode(mode)
2341 numChildren = len(signode)
2342 self.leftSpecs.describe_signature(signode, env, symbol)
2343 addSpace = len(signode) != numChildren
2344
2345 if self.trailingTypeSpec:
2346 if addSpace:
2347 signode += addnodes.desc_sig_space()
2348 numChildren = len(signode)
2349 self.trailingTypeSpec.describe_signature(signode, mode, env,
2350 symbol=symbol)
2351 addSpace = len(signode) != numChildren
2352
2353 if len(str(self.rightSpecs)) > 0:
2354 if addSpace:
2355 signode += addnodes.desc_sig_space()
2356 self.rightSpecs.describe_signature(signode, env, symbol)
2357
2358
2359# Declarator
2360################################################################################
2361
2362class ASTArray(ASTBase):
2363 def __init__(self, size: ASTExpression) -> None:
2364 self.size = size
2365
2366 def __eq__(self, other: object) -> bool:
2367 if not isinstance(other, ASTArray):
2368 return NotImplemented
2369 return self.size == other.size
2370
2371 def __hash__(self) -> int:
2372 return hash(self.size)
2373
2374 def _stringify(self, transform: StringifyTransform) -> str:
2375 if self.size:
2376 return '[' + transform(self.size) + ']'
2377 else:
2378 return '[]'
2379
2380 def get_id(self, version: int) -> str:
2381 if version == 1:
2382 return 'A'
2383 if version == 2:
2384 if self.size:
2385 return 'A' + str(self.size) + '_'
2386 else:
2387 return 'A_'
2388 if self.size:
2389 return 'A' + self.size.get_id(version) + '_'
2390 else:
2391 return 'A_'
2392
2393 def describe_signature(self, signode: TextElement, mode: str,
2394 env: BuildEnvironment, symbol: Symbol) -> None:
2395 verify_description_mode(mode)
2396 signode += addnodes.desc_sig_punctuation('[', '[')
2397 if self.size:
2398 self.size.describe_signature(signode, 'markType', env, symbol)
2399 signode += addnodes.desc_sig_punctuation(']', ']')
2400
2401
2402class ASTDeclarator(ASTBase):
2403 @property
2404 def name(self) -> ASTNestedName:
2405 raise NotImplementedError(repr(self))
2406
2407 @name.setter
2408 def name(self, name: ASTNestedName) -> None:
2409 raise NotImplementedError(repr(self))
2410
2411 @property
2412 def isPack(self) -> bool:
2413 raise NotImplementedError(repr(self))
2414
2415 @property
2416 def function_params(self) -> list[ASTFunctionParameter]:
2417 raise NotImplementedError(repr(self))
2418
2419 @property
2420 def trailingReturn(self) -> ASTType:
2421 raise NotImplementedError(repr(self))
2422
2423 def require_space_after_declSpecs(self) -> bool:
2424 raise NotImplementedError(repr(self))
2425
2426 def get_modifiers_id(self, version: int) -> str:
2427 raise NotImplementedError(repr(self))
2428
2429 def get_param_id(self, version: int) -> str:
2430 raise NotImplementedError(repr(self))
2431
2432 def get_ptr_suffix_id(self, version: int) -> str:
2433 raise NotImplementedError(repr(self))
2434
2435 def get_type_id(self, version: int, returnTypeId: str) -> str:
2436 raise NotImplementedError(repr(self))
2437
2438 def is_function_type(self) -> bool:
2439 raise NotImplementedError(repr(self))
2440
2441 def describe_signature(self, signode: TextElement, mode: str,
2442 env: BuildEnvironment, symbol: Symbol) -> None:
2443 raise NotImplementedError(repr(self))
2444
2445
2446class ASTDeclaratorNameParamQual(ASTDeclarator):
2447 def __init__(self, declId: ASTNestedName,
2448 arrayOps: list[ASTArray],
2449 paramQual: ASTParametersQualifiers) -> None:
2450 self.declId = declId
2451 self.arrayOps = arrayOps
2452 self.paramQual = paramQual
2453
2454 def __eq__(self, other: object) -> bool:
2455 if not isinstance(other, ASTDeclaratorNameParamQual):
2456 return NotImplemented
2457 return (
2458 self.declId == other.declId
2459 and self.arrayOps == other.arrayOps
2460 and self.paramQual == other.paramQual
2461 )
2462
2463 def __hash__(self) -> int:
2464 return hash((self.declId, self.arrayOps, self.paramQual))
2465
2466 @property
2467 def name(self) -> ASTNestedName:
2468 return self.declId
2469
2470 @name.setter
2471 def name(self, name: ASTNestedName) -> None:
2472 self.declId = name
2473
2474 @property
2475 def isPack(self) -> bool:
2476 return False
2477
2478 @property
2479 def function_params(self) -> list[ASTFunctionParameter]:
2480 return self.paramQual.function_params
2481
2482 @property
2483 def trailingReturn(self) -> ASTType:
2484 return self.paramQual.trailingReturn
2485
2486 # only the modifiers for a function, e.g.,
2487 def get_modifiers_id(self, version: int) -> str:
2488 # cv-qualifiers
2489 if self.paramQual:
2490 return self.paramQual.get_modifiers_id(version)
2491 raise Exception("This should only be called on a function: %s" % self)
2492
2493 def get_param_id(self, version: int) -> str: # only the parameters (if any)
2494 if self.paramQual:
2495 return self.paramQual.get_param_id(version)
2496 else:
2497 return ''
2498
2499 def get_ptr_suffix_id(self, version: int) -> str: # only the array specifiers
2500 return ''.join(a.get_id(version) for a in self.arrayOps)
2501
2502 def get_type_id(self, version: int, returnTypeId: str) -> str:
2503 assert version >= 2
2504 res = []
2505 # TODO: can we actually have both array ops and paramQual?
2506 res.append(self.get_ptr_suffix_id(version))
2507 if self.paramQual:
2508 res.append(self.get_modifiers_id(version))
2509 res.append('F')
2510 res.append(returnTypeId)
2511 res.append(self.get_param_id(version))
2512 res.append('E')
2513 else:
2514 res.append(returnTypeId)
2515 return ''.join(res)
2516
2517 # ------------------------------------------------------------------------
2518
2519 def require_space_after_declSpecs(self) -> bool:
2520 return self.declId is not None
2521
2522 def is_function_type(self) -> bool:
2523 return self.paramQual is not None
2524
2525 def _stringify(self, transform: StringifyTransform) -> str:
2526 res = []
2527 if self.declId:
2528 res.append(transform(self.declId))
2529 res.extend(transform(op) for op in self.arrayOps)
2530 if self.paramQual:
2531 res.append(transform(self.paramQual))
2532 return ''.join(res)
2533
2534 def describe_signature(self, signode: TextElement, mode: str,
2535 env: BuildEnvironment, symbol: Symbol) -> None:
2536 verify_description_mode(mode)
2537 if self.declId:
2538 self.declId.describe_signature(signode, mode, env, symbol)
2539 for op in self.arrayOps:
2540 op.describe_signature(signode, mode, env, symbol)
2541 if self.paramQual:
2542 self.paramQual.describe_signature(signode, mode, env, symbol)
2543
2544
2545class ASTDeclaratorNameBitField(ASTDeclarator):
2546 def __init__(self, declId: ASTNestedName, size: ASTExpression) -> None:
2547 self.declId = declId
2548 self.size = size
2549
2550 def __eq__(self, other: object) -> bool:
2551 if not isinstance(other, ASTDeclaratorNameBitField):
2552 return NotImplemented
2553 return self.declId == other.declId and self.size == other.size
2554
2555 def __hash__(self) -> int:
2556 return hash((self.declId, self.size))
2557
2558 @property
2559 def name(self) -> ASTNestedName:
2560 return self.declId
2561
2562 @name.setter
2563 def name(self, name: ASTNestedName) -> None:
2564 self.declId = name
2565
2566 def get_param_id(self, version: int) -> str: # only the parameters (if any)
2567 return ''
2568
2569 def get_ptr_suffix_id(self, version: int) -> str: # only the array specifiers
2570 return ''
2571
2572 # ------------------------------------------------------------------------
2573
2574 def require_space_after_declSpecs(self) -> bool:
2575 return self.declId is not None
2576
2577 def is_function_type(self) -> bool:
2578 return False
2579
2580 def _stringify(self, transform: StringifyTransform) -> str:
2581 res = []
2582 if self.declId:
2583 res.append(transform(self.declId))
2584 res.append(" : ")
2585 res.append(transform(self.size))
2586 return ''.join(res)
2587
2588 def describe_signature(self, signode: TextElement, mode: str,
2589 env: BuildEnvironment, symbol: Symbol) -> None:
2590 verify_description_mode(mode)
2591 if self.declId:
2592 self.declId.describe_signature(signode, mode, env, symbol)
2593 signode += addnodes.desc_sig_space()
2594 signode += addnodes.desc_sig_punctuation(':', ':')
2595 signode += addnodes.desc_sig_space()
2596 self.size.describe_signature(signode, mode, env, symbol)
2597
2598
2599class ASTDeclaratorPtr(ASTDeclarator):
2600 def __init__(self, next: ASTDeclarator, volatile: bool, const: bool,
2601 attrs: ASTAttributeList) -> None:
2602 assert next
2603 self.next = next
2604 self.volatile = volatile
2605 self.const = const
2606 self.attrs = attrs
2607
2608 def __eq__(self, other: object) -> bool:
2609 if not isinstance(other, ASTDeclaratorPtr):
2610 return NotImplemented
2611 return (
2612 self.next == other.next
2613 and self.volatile == other.volatile
2614 and self.const == other.const
2615 and self.attrs == other.attrs
2616 )
2617
2618 def __hash__(self) -> int:
2619 return hash((self.next, self.volatile, self.const, self.attrs))
2620
2621 @property
2622 def name(self) -> ASTNestedName:
2623 return self.next.name
2624
2625 @name.setter
2626 def name(self, name: ASTNestedName) -> None:
2627 self.next.name = name
2628
2629 @property
2630 def isPack(self) -> bool:
2631 return self.next.isPack
2632
2633 @property
2634 def function_params(self) -> list[ASTFunctionParameter]:
2635 return self.next.function_params
2636
2637 @property
2638 def trailingReturn(self) -> ASTType:
2639 return self.next.trailingReturn
2640
2641 def require_space_after_declSpecs(self) -> bool:
2642 return self.next.require_space_after_declSpecs()
2643
2644 def _stringify(self, transform: StringifyTransform) -> str:
2645 res = ['*']
2646 res.append(transform(self.attrs))
2647 if len(self.attrs) != 0 and (self.volatile or self.const):
2648 res.append(' ')
2649 if self.volatile:
2650 res.append('volatile')
2651 if self.const:
2652 if self.volatile:
2653 res.append(' ')
2654 res.append('const')
2655 if self.const or self.volatile or len(self.attrs) > 0:
2656 if self.next.require_space_after_declSpecs():
2657 res.append(' ')
2658 res.append(transform(self.next))
2659 return ''.join(res)
2660
2661 def get_modifiers_id(self, version: int) -> str:
2662 return self.next.get_modifiers_id(version)
2663
2664 def get_param_id(self, version: int) -> str:
2665 return self.next.get_param_id(version)
2666
2667 def get_ptr_suffix_id(self, version: int) -> str:
2668 if version == 1:
2669 res = ['P']
2670 if self.volatile:
2671 res.append('V')
2672 if self.const:
2673 res.append('C')
2674 res.append(self.next.get_ptr_suffix_id(version))
2675 return ''.join(res)
2676
2677 res = [self.next.get_ptr_suffix_id(version)]
2678 res.append('P')
2679 if self.volatile:
2680 res.append('V')
2681 if self.const:
2682 res.append('C')
2683 return ''.join(res)
2684
2685 def get_type_id(self, version: int, returnTypeId: str) -> str:
2686 # ReturnType *next, so we are part of the return type of 'next
2687 res = ['P']
2688 if self.volatile:
2689 res.append('V')
2690 if self.const:
2691 res.append('C')
2692 res.append(returnTypeId)
2693 return self.next.get_type_id(version, returnTypeId=''.join(res))
2694
2695 def is_function_type(self) -> bool:
2696 return self.next.is_function_type()
2697
2698 def describe_signature(self, signode: TextElement, mode: str,
2699 env: BuildEnvironment, symbol: Symbol) -> None:
2700 verify_description_mode(mode)
2701 signode += addnodes.desc_sig_punctuation('*', '*')
2702 self.attrs.describe_signature(signode)
2703 if len(self.attrs) != 0 and (self.volatile or self.const):
2704 signode += addnodes.desc_sig_space()
2705
2706 def _add_anno(signode: TextElement, text: str) -> None:
2707 signode += addnodes.desc_sig_keyword(text, text)
2708 if self.volatile:
2709 _add_anno(signode, 'volatile')
2710 if self.const:
2711 if self.volatile:
2712 signode += addnodes.desc_sig_space()
2713 _add_anno(signode, 'const')
2714 if self.const or self.volatile or len(self.attrs) > 0:
2715 if self.next.require_space_after_declSpecs():
2716 signode += addnodes.desc_sig_space()
2717 self.next.describe_signature(signode, mode, env, symbol)
2718
2719
2720class ASTDeclaratorRef(ASTDeclarator):
2721 def __init__(self, next: ASTDeclarator, attrs: ASTAttributeList) -> None:
2722 assert next
2723 self.next = next
2724 self.attrs = attrs
2725
2726 def __eq__(self, other: object) -> bool:
2727 if not isinstance(other, ASTDeclaratorRef):
2728 return NotImplemented
2729 return self.next == other.next and self.attrs == other.attrs
2730
2731 def __hash__(self) -> int:
2732 return hash((self.next, self.attrs))
2733
2734 @property
2735 def name(self) -> ASTNestedName:
2736 return self.next.name
2737
2738 @name.setter
2739 def name(self, name: ASTNestedName) -> None:
2740 self.next.name = name
2741
2742 @property
2743 def isPack(self) -> bool:
2744 return self.next.isPack
2745
2746 @property
2747 def function_params(self) -> list[ASTFunctionParameter]:
2748 return self.next.function_params
2749
2750 @property
2751 def trailingReturn(self) -> ASTType:
2752 return self.next.trailingReturn
2753
2754 def require_space_after_declSpecs(self) -> bool:
2755 return self.next.require_space_after_declSpecs()
2756
2757 def _stringify(self, transform: StringifyTransform) -> str:
2758 res = ['&']
2759 res.append(transform(self.attrs))
2760 if len(self.attrs) != 0 and self.next.require_space_after_declSpecs():
2761 res.append(' ')
2762 res.append(transform(self.next))
2763 return ''.join(res)
2764
2765 def get_modifiers_id(self, version: int) -> str:
2766 return self.next.get_modifiers_id(version)
2767
2768 def get_param_id(self, version: int) -> str: # only the parameters (if any)
2769 return self.next.get_param_id(version)
2770
2771 def get_ptr_suffix_id(self, version: int) -> str:
2772 if version == 1:
2773 return 'R' + self.next.get_ptr_suffix_id(version)
2774 else:
2775 return self.next.get_ptr_suffix_id(version) + 'R'
2776
2777 def get_type_id(self, version: int, returnTypeId: str) -> str:
2778 assert version >= 2
2779 # ReturnType &next, so we are part of the return type of 'next
2780 return self.next.get_type_id(version, returnTypeId='R' + returnTypeId)
2781
2782 def is_function_type(self) -> bool:
2783 return self.next.is_function_type()
2784
2785 def describe_signature(self, signode: TextElement, mode: str,
2786 env: BuildEnvironment, symbol: Symbol) -> None:
2787 verify_description_mode(mode)
2788 signode += addnodes.desc_sig_punctuation('&', '&')
2789 self.attrs.describe_signature(signode)
2790 if len(self.attrs) > 0 and self.next.require_space_after_declSpecs():
2791 signode += addnodes.desc_sig_space()
2792 self.next.describe_signature(signode, mode, env, symbol)
2793
2794
2795class ASTDeclaratorParamPack(ASTDeclarator):
2796 def __init__(self, next: ASTDeclarator) -> None:
2797 assert next
2798 self.next = next
2799
2800 def __eq__(self, other: object) -> bool:
2801 if not isinstance(other, ASTDeclaratorParamPack):
2802 return NotImplemented
2803 return self.next == other.next
2804
2805 def __hash__(self) -> int:
2806 return hash(self.next)
2807
2808 @property
2809 def name(self) -> ASTNestedName:
2810 return self.next.name
2811
2812 @name.setter
2813 def name(self, name: ASTNestedName) -> None:
2814 self.next.name = name
2815
2816 @property
2817 def function_params(self) -> list[ASTFunctionParameter]:
2818 return self.next.function_params
2819
2820 @property
2821 def trailingReturn(self) -> ASTType:
2822 return self.next.trailingReturn
2823
2824 @property
2825 def isPack(self) -> bool:
2826 return True
2827
2828 def require_space_after_declSpecs(self) -> bool:
2829 return False
2830
2831 def _stringify(self, transform: StringifyTransform) -> str:
2832 res = transform(self.next)
2833 if self.next.name:
2834 res = ' ' + res
2835 return '...' + res
2836
2837 def get_modifiers_id(self, version: int) -> str:
2838 return self.next.get_modifiers_id(version)
2839
2840 def get_param_id(self, version: int) -> str: # only the parameters (if any)
2841 return self.next.get_param_id(version)
2842
2843 def get_ptr_suffix_id(self, version: int) -> str:
2844 if version == 1:
2845 return 'Dp' + self.next.get_ptr_suffix_id(version)
2846 else:
2847 return self.next.get_ptr_suffix_id(version) + 'Dp'
2848
2849 def get_type_id(self, version: int, returnTypeId: str) -> str:
2850 assert version >= 2
2851 # ReturnType... next, so we are part of the return type of 'next
2852 return self.next.get_type_id(version, returnTypeId='Dp' + returnTypeId)
2853
2854 def is_function_type(self) -> bool:
2855 return self.next.is_function_type()
2856
2857 def describe_signature(self, signode: TextElement, mode: str,
2858 env: BuildEnvironment, symbol: Symbol) -> None:
2859 verify_description_mode(mode)
2860 signode += addnodes.desc_sig_punctuation('...', '...')
2861 if self.next.name:
2862 signode += addnodes.desc_sig_space()
2863 self.next.describe_signature(signode, mode, env, symbol)
2864
2865
2866class ASTDeclaratorMemPtr(ASTDeclarator):
2867 def __init__(self, className: ASTNestedName,
2868 const: bool, volatile: bool, next: ASTDeclarator) -> None:
2869 assert className
2870 assert next
2871 self.className = className
2872 self.const = const
2873 self.volatile = volatile
2874 self.next = next
2875
2876 def __eq__(self, other: object) -> bool:
2877 if not isinstance(other, ASTDeclaratorMemPtr):
2878 return NotImplemented
2879 return (
2880 self.className == other.className
2881 and self.const == other.const
2882 and self.volatile == other.volatile
2883 and self.next == other.next
2884 )
2885
2886 def __hash__(self) -> int:
2887 return hash((self.className, self.const, self.volatile, self.next))
2888
2889 @property
2890 def name(self) -> ASTNestedName:
2891 return self.next.name
2892
2893 @name.setter
2894 def name(self, name: ASTNestedName) -> None:
2895 self.next.name = name
2896
2897 @property
2898 def isPack(self) -> bool:
2899 return self.next.isPack
2900
2901 @property
2902 def function_params(self) -> list[ASTFunctionParameter]:
2903 return self.next.function_params
2904
2905 @property
2906 def trailingReturn(self) -> ASTType:
2907 return self.next.trailingReturn
2908
2909 def require_space_after_declSpecs(self) -> bool:
2910 return True
2911
2912 def _stringify(self, transform: StringifyTransform) -> str:
2913 res = []
2914 res.append(transform(self.className))
2915 res.append('::*')
2916 if self.volatile:
2917 res.append('volatile')
2918 if self.const:
2919 if self.volatile:
2920 res.append(' ')
2921 res.append('const')
2922 if self.next.require_space_after_declSpecs():
2923 res.append(' ')
2924 res.append(transform(self.next))
2925 return ''.join(res)
2926
2927 def get_modifiers_id(self, version: int) -> str:
2928 if version == 1:
2929 raise NoOldIdError
2930 return self.next.get_modifiers_id(version)
2931
2932 def get_param_id(self, version: int) -> str: # only the parameters (if any)
2933 if version == 1:
2934 raise NoOldIdError
2935 return self.next.get_param_id(version)
2936
2937 def get_ptr_suffix_id(self, version: int) -> str:
2938 if version == 1:
2939 raise NoOldIdError
2940 raise NotImplementedError
2941 return self.next.get_ptr_suffix_id(version) + 'Dp'
2942
2943 def get_type_id(self, version: int, returnTypeId: str) -> str:
2944 assert version >= 2
2945 # ReturnType name::* next, so we are part of the return type of next
2946 nextReturnTypeId = ''
2947 if self.volatile:
2948 nextReturnTypeId += 'V'
2949 if self.const:
2950 nextReturnTypeId += 'K'
2951 nextReturnTypeId += 'M'
2952 nextReturnTypeId += self.className.get_id(version)
2953 nextReturnTypeId += returnTypeId
2954 return self.next.get_type_id(version, nextReturnTypeId)
2955
2956 def is_function_type(self) -> bool:
2957 return self.next.is_function_type()
2958
2959 def describe_signature(self, signode: TextElement, mode: str,
2960 env: BuildEnvironment, symbol: Symbol) -> None:
2961 verify_description_mode(mode)
2962 self.className.describe_signature(signode, 'markType', env, symbol)
2963 signode += addnodes.desc_sig_punctuation('::', '::')
2964 signode += addnodes.desc_sig_punctuation('*', '*')
2965
2966 def _add_anno(signode: TextElement, text: str) -> None:
2967 signode += addnodes.desc_sig_keyword(text, text)
2968 if self.volatile:
2969 _add_anno(signode, 'volatile')
2970 if self.const:
2971 if self.volatile:
2972 signode += addnodes.desc_sig_space()
2973 _add_anno(signode, 'const')
2974 if self.next.require_space_after_declSpecs():
2975 signode += addnodes.desc_sig_space()
2976 self.next.describe_signature(signode, mode, env, symbol)
2977
2978
2979class ASTDeclaratorParen(ASTDeclarator):
2980 def __init__(self, inner: ASTDeclarator, next: ASTDeclarator) -> None:
2981 assert inner
2982 assert next
2983 self.inner = inner
2984 self.next = next
2985 # TODO: we assume the name, params, and qualifiers are in inner
2986
2987 def __eq__(self, other: object) -> bool:
2988 if not isinstance(other, ASTDeclaratorParen):
2989 return NotImplemented
2990 return self.inner == other.inner and self.next == other.next
2991
2992 def __hash__(self) -> int:
2993 return hash((self.inner, self.next))
2994
2995 @property
2996 def name(self) -> ASTNestedName:
2997 return self.inner.name
2998
2999 @name.setter
3000 def name(self, name: ASTNestedName) -> None:
3001 self.inner.name = name
3002
3003 @property
3004 def isPack(self) -> bool:
3005 return self.inner.isPack or self.next.isPack
3006
3007 @property
3008 def function_params(self) -> list[ASTFunctionParameter]:
3009 return self.inner.function_params
3010
3011 @property
3012 def trailingReturn(self) -> ASTType:
3013 return self.inner.trailingReturn
3014
3015 def require_space_after_declSpecs(self) -> bool:
3016 return True
3017
3018 def _stringify(self, transform: StringifyTransform) -> str:
3019 res = ['(']
3020 res.append(transform(self.inner))
3021 res.append(')')
3022 res.append(transform(self.next))
3023 return ''.join(res)
3024
3025 def get_modifiers_id(self, version: int) -> str:
3026 return self.inner.get_modifiers_id(version)
3027
3028 def get_param_id(self, version: int) -> str: # only the parameters (if any)
3029 return self.inner.get_param_id(version)
3030
3031 def get_ptr_suffix_id(self, version: int) -> str:
3032 if version == 1:
3033 raise NoOldIdError # TODO: was this implemented before?
3034 return self.next.get_ptr_suffix_id(version) + \
3035 self.inner.get_ptr_suffix_id(version)
3036 return self.inner.get_ptr_suffix_id(version) + \
3037 self.next.get_ptr_suffix_id(version)
3038
3039 def get_type_id(self, version: int, returnTypeId: str) -> str:
3040 assert version >= 2
3041 # ReturnType (inner)next, so 'inner' returns everything outside
3042 nextId = self.next.get_type_id(version, returnTypeId)
3043 return self.inner.get_type_id(version, returnTypeId=nextId)
3044
3045 def is_function_type(self) -> bool:
3046 return self.inner.is_function_type()
3047
3048 def describe_signature(self, signode: TextElement, mode: str,
3049 env: BuildEnvironment, symbol: Symbol) -> None:
3050 verify_description_mode(mode)
3051 signode += addnodes.desc_sig_punctuation('(', '(')
3052 self.inner.describe_signature(signode, mode, env, symbol)
3053 signode += addnodes.desc_sig_punctuation(')', ')')
3054 self.next.describe_signature(signode, "noneIsName", env, symbol)
3055
3056
3057# Type and initializer stuff
3058##############################################################################################
3059
3060class ASTPackExpansionExpr(ASTExpression):
3061 def __init__(self, expr: ASTExpression | ASTBracedInitList) -> None:
3062 self.expr = expr
3063
3064 def __eq__(self, other: object) -> bool:
3065 if not isinstance(other, ASTPackExpansionExpr):
3066 return NotImplemented
3067 return self.expr == other.expr
3068
3069 def __hash__(self) -> int:
3070 return hash(self.expr)
3071
3072 def _stringify(self, transform: StringifyTransform) -> str:
3073 return transform(self.expr) + '...'
3074
3075 def get_id(self, version: int) -> str:
3076 id = self.expr.get_id(version)
3077 return 'sp' + id
3078
3079 def describe_signature(self, signode: TextElement, mode: str,
3080 env: BuildEnvironment, symbol: Symbol) -> None:
3081 self.expr.describe_signature(signode, mode, env, symbol)
3082 signode += addnodes.desc_sig_punctuation('...', '...')
3083
3084
3085class ASTParenExprList(ASTBaseParenExprList):
3086 def __init__(self, exprs: list[ASTExpression | ASTBracedInitList]) -> None:
3087 self.exprs = exprs
3088
3089 def __eq__(self, other: object) -> bool:
3090 if not isinstance(other, ASTParenExprList):
3091 return NotImplemented
3092 return self.exprs == other.exprs
3093
3094 def __hash__(self) -> int:
3095 return hash(self.exprs)
3096
3097 def get_id(self, version: int) -> str:
3098 return "pi%sE" % ''.join(e.get_id(version) for e in self.exprs)
3099
3100 def _stringify(self, transform: StringifyTransform) -> str:
3101 exprs = [transform(e) for e in self.exprs]
3102 return '(%s)' % ', '.join(exprs)
3103
3104 def describe_signature(self, signode: TextElement, mode: str,
3105 env: BuildEnvironment, symbol: Symbol) -> None:
3106 verify_description_mode(mode)
3107 signode += addnodes.desc_sig_punctuation('(', '(')
3108 first = True
3109 for e in self.exprs:
3110 if not first:
3111 signode += addnodes.desc_sig_punctuation(',', ',')
3112 signode += addnodes.desc_sig_space()
3113 else:
3114 first = False
3115 e.describe_signature(signode, mode, env, symbol)
3116 signode += addnodes.desc_sig_punctuation(')', ')')
3117
3118
3119class ASTInitializer(ASTBase):
3120 def __init__(self, value: ASTExpression | ASTBracedInitList,
3121 hasAssign: bool = True) -> None:
3122 self.value = value
3123 self.hasAssign = hasAssign
3124
3125 def __eq__(self, other: object) -> bool:
3126 if not isinstance(other, ASTInitializer):
3127 return NotImplemented
3128 return self.value == other.value and self.hasAssign == other.hasAssign
3129
3130 def __hash__(self) -> int:
3131 return hash((self.value, self.hasAssign))
3132
3133 def _stringify(self, transform: StringifyTransform) -> str:
3134 val = transform(self.value)
3135 if self.hasAssign:
3136 return ' = ' + val
3137 else:
3138 return val
3139
3140 def describe_signature(self, signode: TextElement, mode: str,
3141 env: BuildEnvironment, symbol: Symbol) -> None:
3142 verify_description_mode(mode)
3143 if self.hasAssign:
3144 signode += addnodes.desc_sig_space()
3145 signode += addnodes.desc_sig_punctuation('=', '=')
3146 signode += addnodes.desc_sig_space()
3147 self.value.describe_signature(signode, 'markType', env, symbol)
3148
3149
3150class ASTType(ASTBase):
3151 def __init__(self, declSpecs: ASTDeclSpecs, decl: ASTDeclarator) -> None:
3152 assert declSpecs
3153 assert decl
3154 self.declSpecs = declSpecs
3155 self.decl = decl
3156
3157 def __eq__(self, other: object) -> bool:
3158 if not isinstance(other, ASTType):
3159 return NotImplemented
3160 return self.declSpecs == other.declSpecs and self.decl == other.decl
3161
3162 def __hash__(self) -> int:
3163 return hash((self.declSpecs, self.decl))
3164
3165 @property
3166 def name(self) -> ASTNestedName:
3167 return self.decl.name
3168
3169 @name.setter
3170 def name(self, name: ASTNestedName) -> None:
3171 self.decl.name = name
3172
3173 @property
3174 def isPack(self) -> bool:
3175 return self.decl.isPack
3176
3177 @property
3178 def function_params(self) -> list[ASTFunctionParameter]:
3179 return self.decl.function_params
3180
3181 @property
3182 def trailingReturn(self) -> ASTType:
3183 return self.decl.trailingReturn
3184
3185 def get_id(self, version: int, objectType: str | None = None,
3186 symbol: Symbol | None = None) -> str:
3187 if version == 1:
3188 res = []
3189 if objectType: # needs the name
3190 if objectType == 'function': # also modifiers
3191 res.append(symbol.get_full_nested_name().get_id(version))
3192 res.append(self.decl.get_param_id(version))
3193 res.append(self.decl.get_modifiers_id(version))
3194 if (self.declSpecs.leftSpecs.constexpr or
3195 (self.declSpecs.rightSpecs and
3196 self.declSpecs.rightSpecs.constexpr)):
3197 res.append('CE')
3198 elif objectType == 'type': # just the name
3199 res.append(symbol.get_full_nested_name().get_id(version))
3200 else:
3201 raise AssertionError(objectType)
3202 else: # only type encoding
3203 if self.decl.is_function_type():
3204 raise NoOldIdError
3205 res.append(self.declSpecs.get_id(version))
3206 res.append(self.decl.get_ptr_suffix_id(version))
3207 res.append(self.decl.get_param_id(version))
3208 return ''.join(res)
3209 # other versions
3210 res = []
3211 if objectType: # needs the name
3212 if objectType == 'function': # also modifiers
3213 modifiers = self.decl.get_modifiers_id(version)
3214 res.append(symbol.get_full_nested_name().get_id(version, modifiers))
3215 if version >= 4:
3216 # with templates we need to mangle the return type in as well
3217 templ = symbol.declaration.templatePrefix
3218 if templ is not None:
3219 typeId = self.decl.get_ptr_suffix_id(version)
3220 if self.trailingReturn:
3221 returnTypeId = self.trailingReturn.get_id(version)
3222 else:
3223 returnTypeId = self.declSpecs.get_id(version)
3224 res.append(typeId)
3225 res.append(returnTypeId)
3226 res.append(self.decl.get_param_id(version))
3227 elif objectType == 'type': # just the name
3228 res.append(symbol.get_full_nested_name().get_id(version))
3229 else:
3230 raise AssertionError(objectType)
3231 else: # only type encoding
3232 # the 'returnType' of a non-function type is simply just the last
3233 # type, i.e., for 'int*' it is 'int'
3234 returnTypeId = self.declSpecs.get_id(version)
3235 typeId = self.decl.get_type_id(version, returnTypeId)
3236 res.append(typeId)
3237 return ''.join(res)
3238
3239 def _stringify(self, transform: StringifyTransform) -> str:
3240 res = []
3241 declSpecs = transform(self.declSpecs)
3242 res.append(declSpecs)
3243 if self.decl.require_space_after_declSpecs() and len(declSpecs) > 0:
3244 res.append(' ')
3245 res.append(transform(self.decl))
3246 return ''.join(res)
3247
3248 def get_type_declaration_prefix(self) -> str:
3249 if self.declSpecs.trailingTypeSpec:
3250 return 'typedef'
3251 else:
3252 return 'type'
3253
3254 def describe_signature(self, signode: TextElement, mode: str,
3255 env: BuildEnvironment, symbol: Symbol) -> None:
3256 verify_description_mode(mode)
3257 self.declSpecs.describe_signature(signode, 'markType', env, symbol)
3258 if (self.decl.require_space_after_declSpecs() and
3259 len(str(self.declSpecs)) > 0):
3260 signode += addnodes.desc_sig_space()
3261 # for parameters that don't really declare new names we get 'markType',
3262 # this should not be propagated, but be 'noneIsName'.
3263 if mode == 'markType':
3264 mode = 'noneIsName'
3265 self.decl.describe_signature(signode, mode, env, symbol)
3266
3267
3268class ASTTemplateParamConstrainedTypeWithInit(ASTBase):
3269 def __init__(self, type: ASTType, init: ASTType) -> None:
3270 assert type
3271 self.type = type
3272 self.init = init
3273
3274 def __eq__(self, other: object) -> bool:
3275 if not isinstance(other, ASTTemplateParamConstrainedTypeWithInit):
3276 return NotImplemented
3277 return self.type == other.type and self.init == other.init
3278
3279 def __hash__(self) -> int:
3280 return hash((self.type, self.init))
3281
3282 @property
3283 def name(self) -> ASTNestedName:
3284 return self.type.name
3285
3286 @property
3287 def isPack(self) -> bool:
3288 return self.type.isPack
3289
3290 def get_id(
3291 self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
3292 ) -> str:
3293 # this is not part of the normal name mangling in C++
3294 assert version >= 2
3295 if symbol:
3296 # the anchor will be our parent
3297 return symbol.parent.declaration.get_id(version, prefixed=False)
3298 else:
3299 return self.type.get_id(version)
3300
3301 def _stringify(self, transform: StringifyTransform) -> str:
3302 res = transform(self.type)
3303 if self.init:
3304 res += " = "
3305 res += transform(self.init)
3306 return res
3307
3308 def describe_signature(self, signode: TextElement, mode: str,
3309 env: BuildEnvironment, symbol: Symbol) -> None:
3310 self.type.describe_signature(signode, mode, env, symbol)
3311 if self.init:
3312 signode += addnodes.desc_sig_space()
3313 signode += addnodes.desc_sig_punctuation('=', '=')
3314 signode += addnodes.desc_sig_space()
3315 self.init.describe_signature(signode, mode, env, symbol)
3316
3317
3318class ASTTypeWithInit(ASTBase):
3319 def __init__(self, type: ASTType, init: ASTInitializer) -> None:
3320 self.type = type
3321 self.init = init
3322
3323 def __eq__(self, other: object) -> bool:
3324 if not isinstance(other, ASTTypeWithInit):
3325 return NotImplemented
3326 return self.type == other.type and self.init == other.init
3327
3328 def __hash__(self) -> int:
3329 return hash((self.type, self.init))
3330
3331 @property
3332 def name(self) -> ASTNestedName:
3333 return self.type.name
3334
3335 @property
3336 def isPack(self) -> bool:
3337 return self.type.isPack
3338
3339 def get_id(self, version: int, objectType: str | None = None,
3340 symbol: Symbol | None = None) -> str:
3341 if objectType != 'member':
3342 return self.type.get_id(version, objectType)
3343 if version == 1:
3344 return (symbol.get_full_nested_name().get_id(version) + '__' +
3345 self.type.get_id(version))
3346 return symbol.get_full_nested_name().get_id(version)
3347
3348 def _stringify(self, transform: StringifyTransform) -> str:
3349 res = []
3350 res.append(transform(self.type))
3351 if self.init:
3352 res.append(transform(self.init))
3353 return ''.join(res)
3354
3355 def describe_signature(self, signode: TextElement, mode: str,
3356 env: BuildEnvironment, symbol: Symbol) -> None:
3357 verify_description_mode(mode)
3358 self.type.describe_signature(signode, mode, env, symbol)
3359 if self.init:
3360 self.init.describe_signature(signode, mode, env, symbol)
3361
3362
3363class ASTTypeUsing(ASTBase):
3364 def __init__(self, name: ASTNestedName, type: ASTType | None) -> None:
3365 self.name = name
3366 self.type = type
3367
3368 def __eq__(self, other: object) -> bool:
3369 if not isinstance(other, ASTTypeUsing):
3370 return NotImplemented
3371 return self.name == other.name and self.type == other.type
3372
3373 def __hash__(self) -> int:
3374 return hash((self.name, self.type))
3375
3376 def get_id(self, version: int, objectType: str | None = None,
3377 symbol: Symbol | None = None) -> str:
3378 if version == 1:
3379 raise NoOldIdError
3380 return symbol.get_full_nested_name().get_id(version)
3381
3382 def _stringify(self, transform: StringifyTransform) -> str:
3383 res = []
3384 res.append(transform(self.name))
3385 if self.type:
3386 res.append(' = ')
3387 res.append(transform(self.type))
3388 return ''.join(res)
3389
3390 def get_type_declaration_prefix(self) -> str:
3391 return 'using'
3392
3393 def describe_signature(self, signode: TextElement, mode: str,
3394 env: BuildEnvironment, symbol: Symbol) -> None:
3395 verify_description_mode(mode)
3396 self.name.describe_signature(signode, mode, env, symbol=symbol)
3397 if self.type:
3398 signode += addnodes.desc_sig_space()
3399 signode += addnodes.desc_sig_punctuation('=', '=')
3400 signode += addnodes.desc_sig_space()
3401 self.type.describe_signature(signode, 'markType', env, symbol=symbol)
3402
3403
3404# Other declarations
3405##############################################################################################
3406
3407class ASTConcept(ASTBase):
3408 def __init__(self, nestedName: ASTNestedName, initializer: ASTInitializer) -> None:
3409 self.nestedName = nestedName
3410 self.initializer = initializer
3411
3412 def __eq__(self, other: object) -> bool:
3413 if not isinstance(other, ASTConcept):
3414 return NotImplemented
3415 return self.nestedName == other.nestedName and self.initializer == other.initializer
3416
3417 def __hash__(self) -> int:
3418 return hash((self.nestedName, self.initializer))
3419
3420 @property
3421 def name(self) -> ASTNestedName:
3422 return self.nestedName
3423
3424 def get_id(self, version: int, objectType: str | None = None,
3425 symbol: Symbol | None = None) -> str:
3426 if version == 1:
3427 raise NoOldIdError
3428 return symbol.get_full_nested_name().get_id(version)
3429
3430 def _stringify(self, transform: StringifyTransform) -> str:
3431 res = transform(self.nestedName)
3432 if self.initializer:
3433 res += transform(self.initializer)
3434 return res
3435
3436 def describe_signature(self, signode: TextElement, mode: str,
3437 env: BuildEnvironment, symbol: Symbol) -> None:
3438 self.nestedName.describe_signature(signode, mode, env, symbol)
3439 if self.initializer:
3440 self.initializer.describe_signature(signode, mode, env, symbol)
3441
3442
3443class ASTBaseClass(ASTBase):
3444 def __init__(self, name: ASTNestedName, visibility: str,
3445 virtual: bool, pack: bool) -> None:
3446 self.name = name
3447 self.visibility = visibility
3448 self.virtual = virtual
3449 self.pack = pack
3450
3451 def __eq__(self, other: object) -> bool:
3452 if not isinstance(other, ASTBaseClass):
3453 return NotImplemented
3454 return (
3455 self.name == other.name
3456 and self.visibility == other.visibility
3457 and self.virtual == other.virtual
3458 and self.pack == other.pack
3459 )
3460
3461 def __hash__(self) -> int:
3462 return hash((self.name, self.visibility, self.virtual, self.pack))
3463
3464 def _stringify(self, transform: StringifyTransform) -> str:
3465 res = []
3466 if self.visibility is not None:
3467 res.append(self.visibility)
3468 res.append(' ')
3469 if self.virtual:
3470 res.append('virtual ')
3471 res.append(transform(self.name))
3472 if self.pack:
3473 res.append('...')
3474 return ''.join(res)
3475
3476 def describe_signature(self, signode: TextElement, mode: str,
3477 env: BuildEnvironment, symbol: Symbol) -> None:
3478 verify_description_mode(mode)
3479 if self.visibility is not None:
3480 signode += addnodes.desc_sig_keyword(self.visibility,
3481 self.visibility)
3482 signode += addnodes.desc_sig_space()
3483 if self.virtual:
3484 signode += addnodes.desc_sig_keyword('virtual', 'virtual')
3485 signode += addnodes.desc_sig_space()
3486 self.name.describe_signature(signode, 'markType', env, symbol=symbol)
3487 if self.pack:
3488 signode += addnodes.desc_sig_punctuation('...', '...')
3489
3490
3491class ASTClass(ASTBase):
3492 def __init__(self, name: ASTNestedName, final: bool, bases: list[ASTBaseClass],
3493 attrs: ASTAttributeList) -> None:
3494 self.name = name
3495 self.final = final
3496 self.bases = bases
3497 self.attrs = attrs
3498
3499 def __eq__(self, other: object) -> bool:
3500 if not isinstance(other, ASTClass):
3501 return NotImplemented
3502 return (
3503 self.name == other.name
3504 and self.final == other.final
3505 and self.bases == other.bases
3506 and self.attrs == other.attrs
3507 )
3508
3509 def __hash__(self) -> int:
3510 return hash((self.name, self.final, self.bases, self.attrs))
3511
3512 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
3513 return symbol.get_full_nested_name().get_id(version)
3514
3515 def _stringify(self, transform: StringifyTransform) -> str:
3516 res = []
3517 res.append(transform(self.attrs))
3518 if len(self.attrs) != 0:
3519 res.append(' ')
3520 res.append(transform(self.name))
3521 if self.final:
3522 res.append(' final')
3523 if len(self.bases) > 0:
3524 res.append(' : ')
3525 first = True
3526 for b in self.bases:
3527 if not first:
3528 res.append(', ')
3529 first = False
3530 res.append(transform(b))
3531 return ''.join(res)
3532
3533 def describe_signature(self, signode: TextElement, mode: str,
3534 env: BuildEnvironment, symbol: Symbol) -> None:
3535 verify_description_mode(mode)
3536 self.attrs.describe_signature(signode)
3537 if len(self.attrs) != 0:
3538 signode += addnodes.desc_sig_space()
3539 self.name.describe_signature(signode, mode, env, symbol=symbol)
3540 if self.final:
3541 signode += addnodes.desc_sig_space()
3542 signode += addnodes.desc_sig_keyword('final', 'final')
3543 if len(self.bases) > 0:
3544 signode += addnodes.desc_sig_space()
3545 signode += addnodes.desc_sig_punctuation(':', ':')
3546 signode += addnodes.desc_sig_space()
3547 for b in self.bases:
3548 b.describe_signature(signode, mode, env, symbol=symbol)
3549 signode += addnodes.desc_sig_punctuation(',', ',')
3550 signode += addnodes.desc_sig_space()
3551 signode.pop()
3552 signode.pop()
3553
3554
3555class ASTUnion(ASTBase):
3556 def __init__(self, name: ASTNestedName, attrs: ASTAttributeList) -> None:
3557 self.name = name
3558 self.attrs = attrs
3559
3560 def __eq__(self, other: object) -> bool:
3561 if not isinstance(other, ASTUnion):
3562 return NotImplemented
3563 return self.name == other.name and self.attrs == other.attrs
3564
3565 def __hash__(self) -> int:
3566 return hash((self.name, self.attrs))
3567
3568 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
3569 if version == 1:
3570 raise NoOldIdError
3571 return symbol.get_full_nested_name().get_id(version)
3572
3573 def _stringify(self, transform: StringifyTransform) -> str:
3574 res = []
3575 res.append(transform(self.attrs))
3576 if len(self.attrs) != 0:
3577 res.append(' ')
3578 res.append(transform(self.name))
3579 return ''.join(res)
3580
3581 def describe_signature(self, signode: TextElement, mode: str,
3582 env: BuildEnvironment, symbol: Symbol) -> None:
3583 verify_description_mode(mode)
3584 self.attrs.describe_signature(signode)
3585 if len(self.attrs) != 0:
3586 signode += addnodes.desc_sig_space()
3587 self.name.describe_signature(signode, mode, env, symbol=symbol)
3588
3589
3590class ASTEnum(ASTBase):
3591 def __init__(self, name: ASTNestedName, scoped: str, underlyingType: ASTType,
3592 attrs: ASTAttributeList) -> None:
3593 self.name = name
3594 self.scoped = scoped
3595 self.underlyingType = underlyingType
3596 self.attrs = attrs
3597
3598 def __eq__(self, other: object) -> bool:
3599 if not isinstance(other, ASTEnum):
3600 return NotImplemented
3601 return (
3602 self.name == other.name
3603 and self.scoped == other.scoped
3604 and self.underlyingType == other.underlyingType
3605 and self.attrs == other.attrs
3606 )
3607
3608 def __hash__(self) -> int:
3609 return hash((self.name, self.scoped, self.underlyingType, self.attrs))
3610
3611 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
3612 if version == 1:
3613 raise NoOldIdError
3614 return symbol.get_full_nested_name().get_id(version)
3615
3616 def _stringify(self, transform: StringifyTransform) -> str:
3617 res = []
3618 if self.scoped:
3619 res.append(self.scoped)
3620 res.append(' ')
3621 res.append(transform(self.attrs))
3622 if len(self.attrs) != 0:
3623 res.append(' ')
3624 res.append(transform(self.name))
3625 if self.underlyingType:
3626 res.append(' : ')
3627 res.append(transform(self.underlyingType))
3628 return ''.join(res)
3629
3630 def describe_signature(self, signode: TextElement, mode: str,
3631 env: BuildEnvironment, symbol: Symbol) -> None:
3632 verify_description_mode(mode)
3633 # self.scoped has been done by the CPPEnumObject
3634 self.attrs.describe_signature(signode)
3635 if len(self.attrs) != 0:
3636 signode += addnodes.desc_sig_space()
3637 self.name.describe_signature(signode, mode, env, symbol=symbol)
3638 if self.underlyingType:
3639 signode += addnodes.desc_sig_space()
3640 signode += addnodes.desc_sig_punctuation(':', ':')
3641 signode += addnodes.desc_sig_space()
3642 self.underlyingType.describe_signature(signode, 'noneIsName',
3643 env, symbol=symbol)
3644
3645
3646class ASTEnumerator(ASTBase):
3647 def __init__(self, name: ASTNestedName, init: ASTInitializer | None,
3648 attrs: ASTAttributeList) -> None:
3649 self.name = name
3650 self.init = init
3651 self.attrs = attrs
3652
3653 def __eq__(self, other: object) -> bool:
3654 if not isinstance(other, ASTEnumerator):
3655 return NotImplemented
3656 return (
3657 self.name == other.name
3658 and self.init == other.init
3659 and self.attrs == other.attrs
3660 )
3661
3662 def __hash__(self) -> int:
3663 return hash((self.name, self.init, self.attrs))
3664
3665 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
3666 if version == 1:
3667 raise NoOldIdError
3668 return symbol.get_full_nested_name().get_id(version)
3669
3670 def _stringify(self, transform: StringifyTransform) -> str:
3671 res = []
3672 res.append(transform(self.name))
3673 if len(self.attrs) != 0:
3674 res.append(' ')
3675 res.append(transform(self.attrs))
3676 if self.init:
3677 res.append(transform(self.init))
3678 return ''.join(res)
3679
3680 def describe_signature(self, signode: TextElement, mode: str,
3681 env: BuildEnvironment, symbol: Symbol) -> None:
3682 verify_description_mode(mode)
3683 self.name.describe_signature(signode, mode, env, symbol)
3684 if len(self.attrs) != 0:
3685 signode += addnodes.desc_sig_space()
3686 self.attrs.describe_signature(signode)
3687 if self.init:
3688 self.init.describe_signature(signode, 'markType', env, symbol)
3689
3690
3691################################################################################
3692# Templates
3693################################################################################
3694
3695# Parameters
3696################################################################################
3697
3698class ASTTemplateParam(ASTBase):
3699 def get_identifier(self) -> ASTIdentifier:
3700 raise NotImplementedError(repr(self))
3701
3702 def get_id(self, version: int) -> str:
3703 raise NotImplementedError(repr(self))
3704
3705 def describe_signature(self, parentNode: TextElement, mode: str,
3706 env: BuildEnvironment, symbol: Symbol) -> None:
3707 raise NotImplementedError(repr(self))
3708
3709 @property
3710 def isPack(self) -> bool:
3711 raise NotImplementedError(repr(self))
3712
3713 @property
3714 def name(self) -> ASTNestedName:
3715 raise NotImplementedError(repr(self))
3716
3717
3718class ASTTemplateKeyParamPackIdDefault(ASTTemplateParam):
3719 def __init__(self, key: str, identifier: ASTIdentifier,
3720 parameterPack: bool, default: ASTType) -> None:
3721 assert key
3722 if parameterPack:
3723 assert default is None
3724 self.key = key
3725 self.identifier = identifier
3726 self.parameterPack = parameterPack
3727 self.default = default
3728
3729 def __eq__(self, other: object) -> bool:
3730 if not isinstance(other, ASTTemplateKeyParamPackIdDefault):
3731 return NotImplemented
3732 return (
3733 self.key == other.key
3734 and self.identifier == other.identifier
3735 and self.parameterPack == other.parameterPack
3736 and self.default == other.default
3737 )
3738
3739 def __hash__(self) -> int:
3740 return hash((self.key, self.identifier, self.parameterPack, self.default))
3741
3742 def get_identifier(self) -> ASTIdentifier:
3743 return self.identifier
3744
3745 def get_id(self, version: int) -> str:
3746 assert version >= 2
3747 # this is not part of the normal name mangling in C++
3748 res = []
3749 if self.parameterPack:
3750 res.append('Dp')
3751 else:
3752 res.append('0') # we need to put something
3753 return ''.join(res)
3754
3755 def _stringify(self, transform: StringifyTransform) -> str:
3756 res = [self.key]
3757 if self.parameterPack:
3758 if self.identifier:
3759 res.append(' ')
3760 res.append('...')
3761 if self.identifier:
3762 if not self.parameterPack:
3763 res.append(' ')
3764 res.append(transform(self.identifier))
3765 if self.default:
3766 res.append(' = ')
3767 res.append(transform(self.default))
3768 return ''.join(res)
3769
3770 def describe_signature(self, signode: TextElement, mode: str,
3771 env: BuildEnvironment, symbol: Symbol) -> None:
3772 signode += addnodes.desc_sig_keyword(self.key, self.key)
3773 if self.parameterPack:
3774 if self.identifier:
3775 signode += addnodes.desc_sig_space()
3776 signode += addnodes.desc_sig_punctuation('...', '...')
3777 if self.identifier:
3778 if not self.parameterPack:
3779 signode += addnodes.desc_sig_space()
3780 self.identifier.describe_signature(signode, mode, env, '', '', symbol)
3781 if self.default:
3782 signode += addnodes.desc_sig_space()
3783 signode += addnodes.desc_sig_punctuation('=', '=')
3784 signode += addnodes.desc_sig_space()
3785 self.default.describe_signature(signode, 'markType', env, symbol)
3786
3787
3788class ASTTemplateParamType(ASTTemplateParam):
3789 def __init__(self, data: ASTTemplateKeyParamPackIdDefault) -> None:
3790 assert data
3791 self.data = data
3792
3793 def __eq__(self, other: object) -> bool:
3794 if not isinstance(other, ASTTemplateParamType):
3795 return NotImplemented
3796 return self.data == other.data
3797
3798 def __hash__(self) -> int:
3799 return hash(self.data)
3800
3801 @property
3802 def name(self) -> ASTNestedName:
3803 id = self.get_identifier()
3804 return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
3805
3806 @property
3807 def isPack(self) -> bool:
3808 return self.data.parameterPack
3809
3810 def get_identifier(self) -> ASTIdentifier:
3811 return self.data.get_identifier()
3812
3813 def get_id(
3814 self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
3815 ) -> str:
3816 # this is not part of the normal name mangling in C++
3817 assert version >= 2
3818 if symbol:
3819 # the anchor will be our parent
3820 return symbol.parent.declaration.get_id(version, prefixed=False)
3821 else:
3822 return self.data.get_id(version)
3823
3824 def _stringify(self, transform: StringifyTransform) -> str:
3825 return transform(self.data)
3826
3827 def describe_signature(self, signode: TextElement, mode: str,
3828 env: BuildEnvironment, symbol: Symbol) -> None:
3829 self.data.describe_signature(signode, mode, env, symbol)
3830
3831
3832class ASTTemplateParamTemplateType(ASTTemplateParam):
3833 def __init__(self, nestedParams: ASTTemplateParams,
3834 data: ASTTemplateKeyParamPackIdDefault) -> None:
3835 assert nestedParams
3836 assert data
3837 self.nestedParams = nestedParams
3838 self.data = data
3839
3840 def __eq__(self, other: object) -> bool:
3841 if not isinstance(other, ASTTemplateParamTemplateType):
3842 return NotImplemented
3843 return (
3844 self.nestedParams == other.nestedParams
3845 and self.data == other.data
3846 )
3847
3848 def __hash__(self) -> int:
3849 return hash((self.nestedParams, self.data))
3850
3851 @property
3852 def name(self) -> ASTNestedName:
3853 id = self.get_identifier()
3854 return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
3855
3856 @property
3857 def isPack(self) -> bool:
3858 return self.data.parameterPack
3859
3860 def get_identifier(self) -> ASTIdentifier:
3861 return self.data.get_identifier()
3862
3863 def get_id(
3864 self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
3865 ) -> str:
3866 assert version >= 2
3867 # this is not part of the normal name mangling in C++
3868 if symbol:
3869 # the anchor will be our parent
3870 return symbol.parent.declaration.get_id(version, prefixed=None)
3871 else:
3872 return self.nestedParams.get_id(version) + self.data.get_id(version)
3873
3874 def _stringify(self, transform: StringifyTransform) -> str:
3875 return transform(self.nestedParams) + transform(self.data)
3876
3877 def describe_signature(self, signode: TextElement, mode: str,
3878 env: BuildEnvironment, symbol: Symbol) -> None:
3879 self.nestedParams.describe_signature(signode, 'noneIsName', env, symbol)
3880 signode += addnodes.desc_sig_space()
3881 self.data.describe_signature(signode, mode, env, symbol)
3882
3883
3884class ASTTemplateParamNonType(ASTTemplateParam):
3885 def __init__(self,
3886 param: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit,
3887 parameterPack: bool = False) -> None:
3888 assert param
3889 self.param = param
3890 self.parameterPack = parameterPack
3891
3892 def __eq__(self, other: object) -> bool:
3893 if not isinstance(other, ASTTemplateParamNonType):
3894 return NotImplemented
3895 return (
3896 self.param == other.param
3897 and self.parameterPack == other.parameterPack
3898 )
3899
3900 @property
3901 def name(self) -> ASTNestedName:
3902 id = self.get_identifier()
3903 return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
3904
3905 @property
3906 def isPack(self) -> bool:
3907 return self.param.isPack or self.parameterPack
3908
3909 def get_identifier(self) -> ASTIdentifier:
3910 name = self.param.name
3911 if name:
3912 assert len(name.names) == 1
3913 assert name.names[0].identOrOp
3914 assert not name.names[0].templateArgs
3915 res = name.names[0].identOrOp
3916 assert isinstance(res, ASTIdentifier)
3917 return res
3918 else:
3919 return None
3920
3921 def get_id(
3922 self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
3923 ) -> str:
3924 assert version >= 2
3925 # this is not part of the normal name mangling in C++
3926 if symbol:
3927 # the anchor will be our parent
3928 return symbol.parent.declaration.get_id(version, prefixed=None)
3929 else:
3930 res = '_'
3931 if self.parameterPack:
3932 res += 'Dp'
3933 return res + self.param.get_id(version)
3934
3935 def _stringify(self, transform: StringifyTransform) -> str:
3936 res = transform(self.param)
3937 if self.parameterPack:
3938 res += '...'
3939 return res
3940
3941 def describe_signature(self, signode: TextElement, mode: str,
3942 env: BuildEnvironment, symbol: Symbol) -> None:
3943 self.param.describe_signature(signode, mode, env, symbol)
3944 if self.parameterPack:
3945 signode += addnodes.desc_sig_punctuation('...', '...')
3946
3947
3948class ASTTemplateParams(ASTBase):
3949 def __init__(self, params: list[ASTTemplateParam],
3950 requiresClause: ASTRequiresClause | None) -> None:
3951 assert params is not None
3952 self.params = params
3953 self.requiresClause = requiresClause
3954
3955 def __eq__(self, other: object) -> bool:
3956 if not isinstance(other, ASTTemplateParams):
3957 return NotImplemented
3958 return self.params == other.params and self.requiresClause == other.requiresClause
3959
3960 def __hash__(self) -> int:
3961 return hash((self.params, self.requiresClause))
3962
3963 def get_id(self, version: int, excludeRequires: bool = False) -> str:
3964 assert version >= 2
3965 res = []
3966 res.append("I")
3967 res.extend(param.get_id(version) for param in self.params)
3968 res.append("E")
3969 if not excludeRequires and self.requiresClause:
3970 res.extend(['IQ', self.requiresClause.expr.get_id(version), 'E'])
3971 return ''.join(res)
3972
3973 def _stringify(self, transform: StringifyTransform) -> str:
3974 res = []
3975 res.append("template<")
3976 res.append(", ".join(transform(a) for a in self.params))
3977 res.append("> ")
3978 if self.requiresClause is not None:
3979 res.append(transform(self.requiresClause))
3980 res.append(" ")
3981 return ''.join(res)
3982
3983 def describe_signature(self, signode: TextElement, mode: str,
3984 env: BuildEnvironment, symbol: Symbol) -> None:
3985 signode += addnodes.desc_sig_keyword('template', 'template')
3986 signode += addnodes.desc_sig_punctuation('<', '<')
3987 first = True
3988 for param in self.params:
3989 if not first:
3990 signode += addnodes.desc_sig_punctuation(',', ',')
3991 signode += addnodes.desc_sig_space()
3992 first = False
3993 param.describe_signature(signode, mode, env, symbol)
3994 signode += addnodes.desc_sig_punctuation('>', '>')
3995 if self.requiresClause is not None:
3996 signode += addnodes.desc_sig_space()
3997 self.requiresClause.describe_signature(signode, mode, env, symbol)
3998
3999 def describe_signature_as_introducer(
4000 self, parentNode: desc_signature, mode: str, env: BuildEnvironment,
4001 symbol: Symbol, lineSpec: bool) -> None:
4002 def makeLine(parentNode: desc_signature) -> addnodes.desc_signature_line:
4003 signode = addnodes.desc_signature_line()
4004 parentNode += signode
4005 signode.sphinx_line_type = 'templateParams'
4006 return signode
4007 lineNode = makeLine(parentNode)
4008 lineNode += addnodes.desc_sig_keyword('template', 'template')
4009 lineNode += addnodes.desc_sig_punctuation('<', '<')
4010 first = True
4011 for param in self.params:
4012 if not first:
4013 lineNode += addnodes.desc_sig_punctuation(',', ',')
4014 lineNode += addnodes.desc_sig_space()
4015 first = False
4016 if lineSpec:
4017 lineNode = makeLine(parentNode)
4018 param.describe_signature(lineNode, mode, env, symbol)
4019 if lineSpec and not first:
4020 lineNode = makeLine(parentNode)
4021 lineNode += addnodes.desc_sig_punctuation('>', '>')
4022 if self.requiresClause:
4023 reqNode = addnodes.desc_signature_line()
4024 reqNode.sphinx_line_type = 'requiresClause'
4025 parentNode += reqNode
4026 self.requiresClause.describe_signature(reqNode, 'markType', env, symbol)
4027
4028
4029# Template introducers
4030################################################################################
4031
4032class ASTTemplateIntroductionParameter(ASTBase):
4033 def __init__(self, identifier: ASTIdentifier, parameterPack: bool) -> None:
4034 self.identifier = identifier
4035 self.parameterPack = parameterPack
4036
4037 def __eq__(self, other: object) -> bool:
4038 if not isinstance(other, ASTTemplateIntroductionParameter):
4039 return NotImplemented
4040 return (
4041 self.identifier == other.identifier
4042 and self.parameterPack == other.parameterPack
4043 )
4044
4045 def __hash__(self) -> int:
4046 return hash((self.identifier, self.parameterPack))
4047
4048 @property
4049 def name(self) -> ASTNestedName:
4050 id = self.get_identifier()
4051 return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
4052
4053 @property
4054 def isPack(self) -> bool:
4055 return self.parameterPack
4056
4057 def get_identifier(self) -> ASTIdentifier:
4058 return self.identifier
4059
4060 def get_id(
4061 self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
4062 ) -> str:
4063 assert version >= 2
4064 # this is not part of the normal name mangling in C++
4065 if symbol:
4066 # the anchor will be our parent
4067 return symbol.parent.declaration.get_id(version, prefixed=None)
4068 else:
4069 if self.parameterPack:
4070 return 'Dp'
4071 else:
4072 return '0' # we need to put something
4073
4074 def get_id_as_arg(self, version: int) -> str:
4075 assert version >= 2
4076 # used for the implicit requires clause
4077 res = self.identifier.get_id(version)
4078 if self.parameterPack:
4079 return 'sp' + res
4080 else:
4081 return res
4082
4083 def _stringify(self, transform: StringifyTransform) -> str:
4084 res = []
4085 if self.parameterPack:
4086 res.append('...')
4087 res.append(transform(self.identifier))
4088 return ''.join(res)
4089
4090 def describe_signature(self, signode: TextElement, mode: str,
4091 env: BuildEnvironment, symbol: Symbol) -> None:
4092 if self.parameterPack:
4093 signode += addnodes.desc_sig_punctuation('...', '...')
4094 self.identifier.describe_signature(signode, mode, env, '', '', symbol)
4095
4096
4097class ASTTemplateIntroduction(ASTBase):
4098 def __init__(self, concept: ASTNestedName,
4099 params: list[ASTTemplateIntroductionParameter]) -> None:
4100 assert len(params) > 0
4101 self.concept = concept
4102 self.params = params
4103
4104 def __eq__(self, other: object) -> bool:
4105 if not isinstance(other, ASTTemplateIntroduction):
4106 return NotImplemented
4107 return self.concept == other.concept and self.params == other.params
4108
4109 def __hash__(self) -> int:
4110 return hash((self.concept, self.params))
4111
4112 def get_id(self, version: int) -> str:
4113 assert version >= 2
4114 return ''.join([
4115 # first do the same as a normal template parameter list
4116 "I",
4117 *(param.get_id(version) for param in self.params),
4118 "E",
4119 # let's use X expr E, which is otherwise for constant template args
4120 "X",
4121 self.concept.get_id(version),
4122 "I",
4123 *(param.get_id_as_arg(version) for param in self.params),
4124 "E",
4125 "E",
4126 ])
4127
4128 def _stringify(self, transform: StringifyTransform) -> str:
4129 res = []
4130 res.append(transform(self.concept))
4131 res.append('{')
4132 res.append(', '.join(transform(param) for param in self.params))
4133 res.append('} ')
4134 return ''.join(res)
4135
4136 def describe_signature_as_introducer(
4137 self, parentNode: desc_signature, mode: str,
4138 env: BuildEnvironment, symbol: Symbol, lineSpec: bool) -> None:
4139 # Note: 'lineSpec' has no effect on template introductions.
4140 signode = addnodes.desc_signature_line()
4141 parentNode += signode
4142 signode.sphinx_line_type = 'templateIntroduction'
4143 self.concept.describe_signature(signode, 'markType', env, symbol)
4144 signode += addnodes.desc_sig_punctuation('{', '{')
4145 first = True
4146 for param in self.params:
4147 if not first:
4148 signode += addnodes.desc_sig_punctuation(',', ',')
4149 signode += addnodes.desc_sig_space()
4150 first = False
4151 param.describe_signature(signode, mode, env, symbol)
4152 signode += addnodes.desc_sig_punctuation('}', '}')
4153
4154
4155################################################################################
4156
4157class ASTTemplateDeclarationPrefix(ASTBase):
4158 def __init__(self,
4159 templates: list[ASTTemplateParams | ASTTemplateIntroduction] | None) -> None:
4160 # templates is None means it's an explicit instantiation of a variable
4161 self.templates = templates
4162
4163 def __eq__(self, other: object) -> bool:
4164 if not isinstance(other, ASTTemplateDeclarationPrefix):
4165 return NotImplemented
4166 return self.templates == other.templates
4167
4168 def __hash__(self) -> int:
4169 return hash(self.templates)
4170
4171 def get_requires_clause_in_last(self) -> ASTRequiresClause | None:
4172 if self.templates is None:
4173 return None
4174 lastList = self.templates[-1]
4175 if not isinstance(lastList, ASTTemplateParams):
4176 return None
4177 return lastList.requiresClause # which may be None
4178
4179 def get_id_except_requires_clause_in_last(self, version: int) -> str:
4180 assert version >= 2
4181 # This is not part of the Itanium ABI mangling system.
4182 res = []
4183 lastIndex = len(self.templates) - 1
4184 for i, t in enumerate(self.templates):
4185 if isinstance(t, ASTTemplateParams):
4186 res.append(t.get_id(version, excludeRequires=(i == lastIndex)))
4187 else:
4188 res.append(t.get_id(version))
4189 return ''.join(res)
4190
4191 def _stringify(self, transform: StringifyTransform) -> str:
4192 return ''.join(map(transform, self.templates))
4193
4194 def describe_signature(self, signode: desc_signature, mode: str,
4195 env: BuildEnvironment, symbol: Symbol, lineSpec: bool) -> None:
4196 verify_description_mode(mode)
4197 for t in self.templates:
4198 t.describe_signature_as_introducer(signode, 'lastIsName', env, symbol, lineSpec)
4199
4200
4201class ASTRequiresClause(ASTBase):
4202 def __init__(self, expr: ASTExpression) -> None:
4203 self.expr = expr
4204
4205 def __eq__(self, other: object) -> bool:
4206 if not isinstance(other, ASTRequiresClause):
4207 return NotImplemented
4208 return self.expr == other.expr
4209
4210 def __hash__(self) -> int:
4211 return hash(self.expr)
4212
4213 def _stringify(self, transform: StringifyTransform) -> str:
4214 return 'requires ' + transform(self.expr)
4215
4216 def describe_signature(self, signode: nodes.TextElement, mode: str,
4217 env: BuildEnvironment, symbol: Symbol) -> None:
4218 signode += addnodes.desc_sig_keyword('requires', 'requires')
4219 signode += addnodes.desc_sig_space()
4220 self.expr.describe_signature(signode, mode, env, symbol)
4221
4222
4223################################################################################
4224################################################################################
4225
4226class ASTDeclaration(ASTBase):
4227 def __init__(self, objectType: str, directiveType: str | None = None,
4228 visibility: str | None = None,
4229 templatePrefix: ASTTemplateDeclarationPrefix | None = None,
4230 declaration: Any = None,
4231 trailingRequiresClause: ASTRequiresClause | None = None,
4232 semicolon: bool = False) -> None:
4233 self.objectType = objectType
4234 self.directiveType = directiveType
4235 self.visibility = visibility
4236 self.templatePrefix = templatePrefix
4237 self.declaration = declaration
4238 self.trailingRequiresClause = trailingRequiresClause
4239 self.semicolon = semicolon
4240
4241 self.symbol: Symbol | None = None
4242 # set by CPPObject._add_enumerator_to_parent
4243 self.enumeratorScopedSymbol: Symbol | None = None
4244
4245 # the cache assumes that by the time get_newest_id is called, no
4246 # further changes will be made to this object
4247 self._newest_id_cache: str | None = None
4248
4249 def __eq__(self, other: object) -> bool:
4250 if not isinstance(other, ASTDeclaration):
4251 return NotImplemented
4252 return (
4253 self.objectType == other.objectType
4254 and self.directiveType == other.directiveType
4255 and self.visibility == other.visibility
4256 and self.templatePrefix == other.templatePrefix
4257 and self.declaration == other.declaration
4258 and self.trailingRequiresClause == other.trailingRequiresClause
4259 and self.semicolon == other.semicolon
4260 and self.symbol == other.symbol
4261 and self.enumeratorScopedSymbol == other.enumeratorScopedSymbol
4262 )
4263
4264 def clone(self) -> ASTDeclaration:
4265 templatePrefixClone = self.templatePrefix.clone() if self.templatePrefix else None
4266 trailingRequiresClasueClone = self.trailingRequiresClause.clone() \
4267 if self.trailingRequiresClause else None
4268 return ASTDeclaration(self.objectType, self.directiveType, self.visibility,
4269 templatePrefixClone,
4270 self.declaration.clone(), trailingRequiresClasueClone,
4271 self.semicolon)
4272
4273 @property
4274 def name(self) -> ASTNestedName:
4275 return self.declaration.name
4276
4277 @property
4278 def function_params(self) -> list[ASTFunctionParameter]:
4279 if self.objectType != 'function':
4280 return None
4281 return self.declaration.function_params
4282
4283 def get_id(self, version: int, prefixed: bool = True) -> str:
4284 if version == 1:
4285 if self.templatePrefix or self.trailingRequiresClause:
4286 raise NoOldIdError
4287 if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
4288 return self.enumeratorScopedSymbol.declaration.get_id(version)
4289 return self.declaration.get_id(version, self.objectType, self.symbol)
4290 # version >= 2
4291 if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
4292 return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed)
4293 if prefixed:
4294 res = [_id_prefix[version]]
4295 else:
4296 res = []
4297 # (See also https://github.com/sphinx-doc/sphinx/pull/10286#issuecomment-1168102147)
4298 # The first implementation of requires clauses only supported a single clause after the
4299 # template prefix, and no trailing clause. It put the ID after the template parameter
4300 # list, i.e.,
4301 # "I" + template_parameter_list_id + "E" + "IQ" + requires_clause_id + "E"
4302 # but the second implementation associates the requires clause with each list, i.e.,
4303 # "I" + template_parameter_list_id + "IQ" + requires_clause_id + "E" + "E"
4304 # To avoid making a new ID version, we make an exception for the last requires clause
4305 # in the template prefix, and still put it in the end.
4306 # As we now support trailing requires clauses we add that as if it was a conjunction.
4307 if self.templatePrefix is not None:
4308 res.append(self.templatePrefix.get_id_except_requires_clause_in_last(version))
4309 requiresClauseInLast = self.templatePrefix.get_requires_clause_in_last()
4310 else:
4311 requiresClauseInLast = None
4312
4313 if requiresClauseInLast or self.trailingRequiresClause:
4314 if version < 4:
4315 raise NoOldIdError
4316 res.append('IQ')
4317 if requiresClauseInLast and self.trailingRequiresClause:
4318 # make a conjunction of them
4319 res.append('aa')
4320 if requiresClauseInLast:
4321 res.append(requiresClauseInLast.expr.get_id(version))
4322 if self.trailingRequiresClause:
4323 res.append(self.trailingRequiresClause.expr.get_id(version))
4324 res.append('E')
4325 res.append(self.declaration.get_id(version, self.objectType, self.symbol))
4326 return ''.join(res)
4327
4328 def get_newest_id(self) -> str:
4329 if self._newest_id_cache is None:
4330 self._newest_id_cache = self.get_id(_max_id, True)
4331 return self._newest_id_cache
4332
4333 def _stringify(self, transform: StringifyTransform) -> str:
4334 res = []
4335 if self.visibility and self.visibility != "public":
4336 res.append(self.visibility)
4337 res.append(' ')
4338 if self.templatePrefix:
4339 res.append(transform(self.templatePrefix))
4340 res.append(transform(self.declaration))
4341 if self.trailingRequiresClause:
4342 res.append(' ')
4343 res.append(transform(self.trailingRequiresClause))
4344 if self.semicolon:
4345 res.append(';')
4346 return ''.join(res)
4347
4348 def describe_signature(self, signode: desc_signature, mode: str,
4349 env: BuildEnvironment, options: dict[str, bool]) -> None:
4350 verify_description_mode(mode)
4351 assert self.symbol
4352 # The caller of the domain added a desc_signature node.
4353 # Always enable multiline:
4354 signode['is_multiline'] = True
4355 # Put each line in a desc_signature_line node.
4356 mainDeclNode = addnodes.desc_signature_line()
4357 mainDeclNode.sphinx_line_type = 'declarator'
4358 mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration
4359
4360 if self.templatePrefix:
4361 self.templatePrefix.describe_signature(signode, mode, env,
4362 symbol=self.symbol,
4363 lineSpec=options.get('tparam-line-spec'))
4364 signode += mainDeclNode
4365 if self.visibility and self.visibility != "public":
4366 mainDeclNode += addnodes.desc_sig_keyword(self.visibility, self.visibility)
4367 mainDeclNode += addnodes.desc_sig_space()
4368 if self.objectType == 'type':
4369 prefix = self.declaration.get_type_declaration_prefix()
4370 mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix)
4371 mainDeclNode += addnodes.desc_sig_space()
4372 elif self.objectType == 'concept':
4373 mainDeclNode += addnodes.desc_sig_keyword('concept', 'concept')
4374 mainDeclNode += addnodes.desc_sig_space()
4375 elif self.objectType in {'member', 'function'}:
4376 pass
4377 elif self.objectType == 'class':
4378 assert self.directiveType in ('class', 'struct')
4379 mainDeclNode += addnodes.desc_sig_keyword(self.directiveType, self.directiveType)
4380 mainDeclNode += addnodes.desc_sig_space()
4381 elif self.objectType == 'union':
4382 mainDeclNode += addnodes.desc_sig_keyword('union', 'union')
4383 mainDeclNode += addnodes.desc_sig_space()
4384 elif self.objectType == 'enum':
4385 mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum')
4386 mainDeclNode += addnodes.desc_sig_space()
4387 if self.directiveType == 'enum-class':
4388 mainDeclNode += addnodes.desc_sig_keyword('class', 'class')
4389 mainDeclNode += addnodes.desc_sig_space()
4390 elif self.directiveType == 'enum-struct':
4391 mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct')
4392 mainDeclNode += addnodes.desc_sig_space()
4393 else:
4394 assert self.directiveType == 'enum', self.directiveType
4395 elif self.objectType == 'enumerator':
4396 mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator')
4397 mainDeclNode += addnodes.desc_sig_space()
4398 else:
4399 raise AssertionError(self.objectType)
4400 self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
4401 lastDeclNode = mainDeclNode
4402 if self.trailingRequiresClause:
4403 trailingReqNode = addnodes.desc_signature_line()
4404 trailingReqNode.sphinx_line_type = 'trailingRequiresClause'
4405 signode.append(trailingReqNode)
4406 lastDeclNode = trailingReqNode
4407 self.trailingRequiresClause.describe_signature(
4408 trailingReqNode, 'markType', env, self.symbol)
4409 if self.semicolon:
4410 lastDeclNode += addnodes.desc_sig_punctuation(';', ';')
4411
4412
4413class ASTNamespace(ASTBase):
4414 def __init__(self, nestedName: ASTNestedName,
4415 templatePrefix: ASTTemplateDeclarationPrefix) -> None:
4416 self.nestedName = nestedName
4417 self.templatePrefix = templatePrefix
4418
4419 def __eq__(self, other: object) -> bool:
4420 if not isinstance(other, ASTNamespace):
4421 return NotImplemented
4422 return (
4423 self.nestedName == other.nestedName
4424 and self.templatePrefix == other.templatePrefix
4425 )
4426
4427 def _stringify(self, transform: StringifyTransform) -> str:
4428 res = []
4429 if self.templatePrefix:
4430 res.append(transform(self.templatePrefix))
4431 res.append(transform(self.nestedName))
4432 return ''.join(res)