1from __future__ import annotations
2
3import sys
4import warnings
5from typing import TYPE_CHECKING, Any, Union, cast
6
7from docutils import nodes
8
9from sphinx import addnodes
10from sphinx.domains.c._ids import _id_prefix, _max_id
11from sphinx.util.cfamily import (
12 ASTAttributeList,
13 ASTBaseBase,
14 ASTBaseParenExprList,
15 StringifyTransform,
16 UnsupportedMultiCharacterCharLiteral,
17 verify_description_mode,
18)
19
20if TYPE_CHECKING:
21
22 from docutils.nodes import Element, Node, TextElement
23
24 from sphinx.domains.c._symbol import Symbol
25 from sphinx.environment import BuildEnvironment
26
27DeclarationType = Union[
28 "ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
29 "ASTType", "ASTTypeWithInit", "ASTMacro",
30]
31
32
33class ASTBase(ASTBaseBase):
34 def describe_signature(self, signode: TextElement, mode: str,
35 env: BuildEnvironment, symbol: Symbol) -> None:
36 raise NotImplementedError(repr(self))
37
38
39# Names
40################################################################################
41
42class ASTIdentifier(ASTBaseBase):
43 def __init__(self, name: str) -> None:
44 if not isinstance(name, str) or len(name) == 0:
45 raise AssertionError
46 self.name = sys.intern(name)
47 self.is_anonymous = name[0] == '@'
48
49 # ASTBaseBase already implements this method,
50 # but specialising it here improves performance
51 def __eq__(self, other: object) -> bool:
52 if not isinstance(other, ASTIdentifier):
53 return NotImplemented
54 return self.name == other.name
55
56 def is_anon(self) -> bool:
57 return self.is_anonymous
58
59 # and this is where we finally make a difference between __str__ and the display string
60
61 def __str__(self) -> str:
62 return self.name
63
64 def get_display_string(self) -> str:
65 return "[anonymous]" if self.is_anonymous else self.name
66
67 def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironment,
68 prefix: str, symbol: Symbol) -> None:
69 # note: slightly different signature of describe_signature due to the prefix
70 verify_description_mode(mode)
71 if self.is_anonymous:
72 node = addnodes.desc_sig_name(text="[anonymous]")
73 else:
74 node = addnodes.desc_sig_name(self.name, self.name)
75 if mode == 'markType':
76 targetText = prefix + self.name
77 pnode = addnodes.pending_xref('', refdomain='c',
78 reftype='identifier',
79 reftarget=targetText, modname=None,
80 classname=None)
81 pnode['c:parent_key'] = symbol.get_lookup_key()
82 pnode += node
83 signode += pnode
84 elif mode == 'lastIsName':
85 nameNode = addnodes.desc_name()
86 nameNode += node
87 signode += nameNode
88 elif mode == 'noneIsName':
89 signode += node
90 else:
91 raise Exception('Unknown description mode: %s' % mode)
92
93 @property
94 def identifier(self) -> str:
95 warnings.warn(
96 '`ASTIdentifier.identifier` is deprecated, use `ASTIdentifier.name` instead',
97 DeprecationWarning, stacklevel=2,
98 )
99 return self.name
100
101
102class ASTNestedName(ASTBase):
103 def __init__(self, names: list[ASTIdentifier], rooted: bool) -> None:
104 assert len(names) > 0
105 self.names = names
106 self.rooted = rooted
107
108 def __eq__(self, other: object) -> bool:
109 if not isinstance(other, ASTNestedName):
110 return NotImplemented
111 return self.names == other.names and self.rooted == other.rooted
112
113 def __hash__(self) -> int:
114 return hash((self.names, self.rooted))
115
116 @property
117 def name(self) -> ASTNestedName:
118 return self
119
120 def get_id(self, version: int) -> str:
121 return '.'.join(str(n) for n in self.names)
122
123 def _stringify(self, transform: StringifyTransform) -> str:
124 res = '.'.join(transform(n) for n in self.names)
125 if self.rooted:
126 return '.' + res
127 else:
128 return res
129
130 def describe_signature(self, signode: TextElement, mode: str,
131 env: BuildEnvironment, symbol: Symbol) -> None:
132 verify_description_mode(mode)
133 # just print the name part, with template args, not template params
134 if mode == 'noneIsName':
135 if self.rooted:
136 unreachable = "Can this happen?"
137 raise AssertionError(unreachable) # TODO
138 signode += nodes.Text('.')
139 for i in range(len(self.names)):
140 if i != 0:
141 unreachable = "Can this happen?"
142 raise AssertionError(unreachable) # TODO
143 signode += nodes.Text('.')
144 n = self.names[i]
145 n.describe_signature(signode, mode, env, '', symbol)
146 elif mode == 'param':
147 assert not self.rooted, str(self)
148 assert len(self.names) == 1
149 self.names[0].describe_signature(signode, 'noneIsName', env, '', symbol)
150 elif mode in ('markType', 'lastIsName', 'markName'):
151 # Each element should be a pending xref targeting the complete
152 # prefix.
153 prefix = ''
154 first = True
155 names = self.names[:-1] if mode == 'lastIsName' else self.names
156 # If lastIsName, then wrap all of the prefix in a desc_addname,
157 # else append directly to signode.
158 # TODO: also for C?
159 # NOTE: Breathe previously relied on the prefix being in the desc_addname node,
160 # so it can remove it in inner declarations.
161 dest = signode
162 if mode == 'lastIsName':
163 dest = addnodes.desc_addname()
164 if self.rooted:
165 prefix += '.'
166 if mode == 'lastIsName' and len(names) == 0:
167 signode += addnodes.desc_sig_punctuation('.', '.')
168 else:
169 dest += addnodes.desc_sig_punctuation('.', '.')
170 for i in range(len(names)):
171 ident = names[i]
172 if not first:
173 dest += addnodes.desc_sig_punctuation('.', '.')
174 prefix += '.'
175 first = False
176 txt_ident = str(ident)
177 if txt_ident != '':
178 ident.describe_signature(dest, 'markType', env, prefix, symbol)
179 prefix += txt_ident
180 if mode == 'lastIsName':
181 if len(self.names) > 1:
182 dest += addnodes.desc_sig_punctuation('.', '.')
183 signode += dest
184 self.names[-1].describe_signature(signode, mode, env, '', symbol)
185 else:
186 raise Exception('Unknown description mode: %s' % mode)
187
188
189################################################################################
190# Expressions
191################################################################################
192
193class ASTExpression(ASTBase):
194 pass
195
196
197# Primary expressions
198################################################################################
199
200class ASTLiteral(ASTExpression):
201 pass
202
203
204class ASTBooleanLiteral(ASTLiteral):
205 def __init__(self, value: bool) -> None:
206 self.value = value
207
208 def __eq__(self, other: object) -> bool:
209 if not isinstance(other, ASTBooleanLiteral):
210 return NotImplemented
211 return self.value == other.value
212
213 def __hash__(self) -> int:
214 return hash(self.value)
215
216 def _stringify(self, transform: StringifyTransform) -> str:
217 if self.value:
218 return 'true'
219 else:
220 return 'false'
221
222 def describe_signature(self, signode: TextElement, mode: str,
223 env: BuildEnvironment, symbol: Symbol) -> None:
224 txt = str(self)
225 signode += addnodes.desc_sig_keyword(txt, txt)
226
227
228class ASTNumberLiteral(ASTLiteral):
229 def __init__(self, data: str) -> None:
230 self.data = data
231
232 def __eq__(self, other: object) -> bool:
233 if not isinstance(other, ASTNumberLiteral):
234 return NotImplemented
235 return self.data == other.data
236
237 def __hash__(self) -> int:
238 return hash(self.data)
239
240 def _stringify(self, transform: StringifyTransform) -> str:
241 return self.data
242
243 def describe_signature(self, signode: TextElement, mode: str,
244 env: BuildEnvironment, symbol: Symbol) -> None:
245 txt = str(self)
246 signode += addnodes.desc_sig_literal_number(txt, txt)
247
248
249class ASTCharLiteral(ASTLiteral):
250 def __init__(self, prefix: str, data: str) -> None:
251 self.prefix = prefix # may be None when no prefix
252 self.data = data
253 decoded = data.encode().decode('unicode-escape')
254 if len(decoded) == 1:
255 self.value = ord(decoded)
256 else:
257 raise UnsupportedMultiCharacterCharLiteral(decoded)
258
259 def __eq__(self, other: object) -> bool:
260 if not isinstance(other, ASTCharLiteral):
261 return NotImplemented
262 return (
263 self.prefix == other.prefix
264 and self.value == other.value
265 )
266
267 def __hash__(self) -> int:
268 return hash((self.prefix, self.value))
269
270 def _stringify(self, transform: StringifyTransform) -> str:
271 if self.prefix is None:
272 return "'" + self.data + "'"
273 else:
274 return self.prefix + "'" + self.data + "'"
275
276 def describe_signature(self, signode: TextElement, mode: str,
277 env: BuildEnvironment, symbol: Symbol) -> None:
278 txt = str(self)
279 signode += addnodes.desc_sig_literal_char(txt, txt)
280
281
282class ASTStringLiteral(ASTLiteral):
283 def __init__(self, data: str) -> None:
284 self.data = data
285
286 def __eq__(self, other: object) -> bool:
287 if not isinstance(other, ASTStringLiteral):
288 return NotImplemented
289 return self.data == other.data
290
291 def __hash__(self) -> int:
292 return hash(self.data)
293
294 def _stringify(self, transform: StringifyTransform) -> str:
295 return self.data
296
297 def describe_signature(self, signode: TextElement, mode: str,
298 env: BuildEnvironment, symbol: Symbol) -> None:
299 txt = str(self)
300 signode += addnodes.desc_sig_literal_string(txt, txt)
301
302
303class ASTIdExpression(ASTExpression):
304 def __init__(self, name: ASTNestedName) -> None:
305 # note: this class is basically to cast a nested name as an expression
306 self.name = name
307
308 def __eq__(self, other: object) -> bool:
309 if not isinstance(other, ASTIdExpression):
310 return NotImplemented
311 return self.name == other.name
312
313 def __hash__(self) -> int:
314 return hash(self.name)
315
316 def _stringify(self, transform: StringifyTransform) -> str:
317 return transform(self.name)
318
319 def get_id(self, version: int) -> str:
320 return self.name.get_id(version)
321
322 def describe_signature(self, signode: TextElement, mode: str,
323 env: BuildEnvironment, symbol: Symbol) -> None:
324 self.name.describe_signature(signode, mode, env, symbol)
325
326
327class ASTParenExpr(ASTExpression):
328 def __init__(self, expr: ASTExpression) -> None:
329 self.expr = expr
330
331 def __eq__(self, other: object) -> bool:
332 if not isinstance(other, ASTParenExpr):
333 return NotImplemented
334 return self.expr == other.expr
335
336 def __hash__(self) -> int:
337 return hash(self.expr)
338
339 def _stringify(self, transform: StringifyTransform) -> str:
340 return '(' + transform(self.expr) + ')'
341
342 def get_id(self, version: int) -> str:
343 return self.expr.get_id(version) # type: ignore[attr-defined]
344
345 def describe_signature(self, signode: TextElement, mode: str,
346 env: BuildEnvironment, symbol: Symbol) -> None:
347 signode += addnodes.desc_sig_punctuation('(', '(')
348 self.expr.describe_signature(signode, mode, env, symbol)
349 signode += addnodes.desc_sig_punctuation(')', ')')
350
351
352# Postfix expressions
353################################################################################
354
355class ASTPostfixOp(ASTBase):
356 pass
357
358
359class ASTPostfixCallExpr(ASTPostfixOp):
360 def __init__(self, lst: ASTParenExprList | ASTBracedInitList) -> None:
361 self.lst = lst
362
363 def __eq__(self, other: object) -> bool:
364 if not isinstance(other, ASTPostfixCallExpr):
365 return NotImplemented
366 return self.lst == other.lst
367
368 def __hash__(self) -> int:
369 return hash(self.lst)
370
371 def _stringify(self, transform: StringifyTransform) -> str:
372 return transform(self.lst)
373
374 def describe_signature(self, signode: TextElement, mode: str,
375 env: BuildEnvironment, symbol: Symbol) -> None:
376 self.lst.describe_signature(signode, mode, env, symbol)
377
378
379class ASTPostfixArray(ASTPostfixOp):
380 def __init__(self, expr: ASTExpression) -> None:
381 self.expr = expr
382
383 def __eq__(self, other: object) -> bool:
384 if not isinstance(other, ASTPostfixArray):
385 return NotImplemented
386 return self.expr == other.expr
387
388 def __hash__(self) -> int:
389 return hash(self.expr)
390
391 def _stringify(self, transform: StringifyTransform) -> str:
392 return '[' + transform(self.expr) + ']'
393
394 def describe_signature(self, signode: TextElement, mode: str,
395 env: BuildEnvironment, symbol: Symbol) -> None:
396 signode += addnodes.desc_sig_punctuation('[', '[')
397 self.expr.describe_signature(signode, mode, env, symbol)
398 signode += addnodes.desc_sig_punctuation(']', ']')
399
400
401class ASTPostfixInc(ASTPostfixOp):
402 def _stringify(self, transform: StringifyTransform) -> str:
403 return '++'
404
405 def describe_signature(self, signode: TextElement, mode: str,
406 env: BuildEnvironment, symbol: Symbol) -> None:
407 signode += addnodes.desc_sig_operator('++', '++')
408
409
410class ASTPostfixDec(ASTPostfixOp):
411 def _stringify(self, transform: StringifyTransform) -> str:
412 return '--'
413
414 def describe_signature(self, signode: TextElement, mode: str,
415 env: BuildEnvironment, symbol: Symbol) -> None:
416 signode += addnodes.desc_sig_operator('--', '--')
417
418
419class ASTPostfixMemberOfPointer(ASTPostfixOp):
420 def __init__(self, name: ASTNestedName) -> None:
421 self.name = name
422
423 def __eq__(self, other: object) -> bool:
424 if not isinstance(other, ASTPostfixMemberOfPointer):
425 return NotImplemented
426 return self.name == other.name
427
428 def __hash__(self) -> int:
429 return hash(self.name)
430
431 def _stringify(self, transform: StringifyTransform) -> str:
432 return '->' + transform(self.name)
433
434 def describe_signature(self, signode: TextElement, mode: str,
435 env: BuildEnvironment, symbol: Symbol) -> None:
436 signode += addnodes.desc_sig_operator('->', '->')
437 self.name.describe_signature(signode, 'noneIsName', env, symbol)
438
439
440class ASTPostfixExpr(ASTExpression):
441 def __init__(self, prefix: ASTExpression, postFixes: list[ASTPostfixOp]) -> None:
442 self.prefix = prefix
443 self.postFixes = postFixes
444
445 def __eq__(self, other: object) -> bool:
446 if not isinstance(other, ASTPostfixExpr):
447 return NotImplemented
448 return self.prefix == other.prefix and self.postFixes == other.postFixes
449
450 def __hash__(self) -> int:
451 return hash((self.prefix, self.postFixes))
452
453 def _stringify(self, transform: StringifyTransform) -> str:
454 return ''.join([transform(self.prefix), *(transform(p) for p in self.postFixes)])
455
456 def describe_signature(self, signode: TextElement, mode: str,
457 env: BuildEnvironment, symbol: Symbol) -> None:
458 self.prefix.describe_signature(signode, mode, env, symbol)
459 for p in self.postFixes:
460 p.describe_signature(signode, mode, env, symbol)
461
462
463# Unary expressions
464################################################################################
465
466class ASTUnaryOpExpr(ASTExpression):
467 def __init__(self, op: str, expr: ASTExpression) -> None:
468 self.op = op
469 self.expr = expr
470
471 def __eq__(self, other: object) -> bool:
472 if not isinstance(other, ASTUnaryOpExpr):
473 return NotImplemented
474 return self.op == other.op and self.expr == other.expr
475
476 def __hash__(self) -> int:
477 return hash((self.op, self.expr))
478
479 def _stringify(self, transform: StringifyTransform) -> str:
480 if self.op[0] in 'cn':
481 return self.op + " " + transform(self.expr)
482 else:
483 return self.op + transform(self.expr)
484
485 def describe_signature(self, signode: TextElement, mode: str,
486 env: BuildEnvironment, symbol: Symbol) -> None:
487 if self.op[0] in 'cn':
488 signode += addnodes.desc_sig_keyword(self.op, self.op)
489 signode += addnodes.desc_sig_space()
490 else:
491 signode += addnodes.desc_sig_operator(self.op, self.op)
492 self.expr.describe_signature(signode, mode, env, symbol)
493
494
495class ASTSizeofType(ASTExpression):
496 def __init__(self, typ: ASTType) -> None:
497 self.typ = typ
498
499 def __eq__(self, other: object) -> bool:
500 if not isinstance(other, ASTSizeofType):
501 return NotImplemented
502 return self.typ == other.typ
503
504 def __hash__(self) -> int:
505 return hash(self.typ)
506
507 def _stringify(self, transform: StringifyTransform) -> str:
508 return "sizeof(" + transform(self.typ) + ")"
509
510 def describe_signature(self, signode: TextElement, mode: str,
511 env: BuildEnvironment, symbol: Symbol) -> None:
512 signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
513 signode += addnodes.desc_sig_punctuation('(', '(')
514 self.typ.describe_signature(signode, mode, env, symbol)
515 signode += addnodes.desc_sig_punctuation(')', ')')
516
517
518class ASTSizeofExpr(ASTExpression):
519 def __init__(self, expr: ASTExpression) -> None:
520 self.expr = expr
521
522 def __eq__(self, other: object) -> bool:
523 if not isinstance(other, ASTSizeofExpr):
524 return NotImplemented
525 return self.expr == other.expr
526
527 def __hash__(self) -> int:
528 return hash(self.expr)
529
530 def _stringify(self, transform: StringifyTransform) -> str:
531 return "sizeof " + transform(self.expr)
532
533 def describe_signature(self, signode: TextElement, mode: str,
534 env: BuildEnvironment, symbol: Symbol) -> None:
535 signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
536 signode += addnodes.desc_sig_space()
537 self.expr.describe_signature(signode, mode, env, symbol)
538
539
540class ASTAlignofExpr(ASTExpression):
541 def __init__(self, typ: ASTType) -> None:
542 self.typ = typ
543
544 def __eq__(self, other: object) -> bool:
545 if not isinstance(other, ASTAlignofExpr):
546 return NotImplemented
547 return self.typ == other.typ
548
549 def __hash__(self) -> int:
550 return hash(self.typ)
551
552 def _stringify(self, transform: StringifyTransform) -> str:
553 return "alignof(" + transform(self.typ) + ")"
554
555 def describe_signature(self, signode: TextElement, mode: str,
556 env: BuildEnvironment, symbol: Symbol) -> None:
557 signode += addnodes.desc_sig_keyword('alignof', 'alignof')
558 signode += addnodes.desc_sig_punctuation('(', '(')
559 self.typ.describe_signature(signode, mode, env, symbol)
560 signode += addnodes.desc_sig_punctuation(')', ')')
561
562
563# Other expressions
564################################################################################
565
566class ASTCastExpr(ASTExpression):
567 def __init__(self, typ: ASTType, expr: ASTExpression) -> None:
568 self.typ = typ
569 self.expr = expr
570
571 def __eq__(self, other: object) -> bool:
572 if not isinstance(other, ASTCastExpr):
573 return NotImplemented
574 return (
575 self.typ == other.typ
576 and self.expr == other.expr
577 )
578
579 def __hash__(self) -> int:
580 return hash((self.typ, self.expr))
581
582 def _stringify(self, transform: StringifyTransform) -> str:
583 res = ['(']
584 res.append(transform(self.typ))
585 res.append(')')
586 res.append(transform(self.expr))
587 return ''.join(res)
588
589 def describe_signature(self, signode: TextElement, mode: str,
590 env: BuildEnvironment, symbol: Symbol) -> None:
591 signode += addnodes.desc_sig_punctuation('(', '(')
592 self.typ.describe_signature(signode, mode, env, symbol)
593 signode += addnodes.desc_sig_punctuation(')', ')')
594 self.expr.describe_signature(signode, mode, env, symbol)
595
596
597class ASTBinOpExpr(ASTBase):
598 def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None:
599 assert len(exprs) > 0
600 assert len(exprs) == len(ops) + 1
601 self.exprs = exprs
602 self.ops = ops
603
604 def __eq__(self, other: object) -> bool:
605 if not isinstance(other, ASTBinOpExpr):
606 return NotImplemented
607 return (
608 self.exprs == other.exprs
609 and self.ops == other.ops
610 )
611
612 def __hash__(self) -> int:
613 return hash((self.exprs, self.ops))
614
615 def _stringify(self, transform: StringifyTransform) -> str:
616 res = []
617 res.append(transform(self.exprs[0]))
618 for i in range(1, len(self.exprs)):
619 res.append(' ')
620 res.append(self.ops[i - 1])
621 res.append(' ')
622 res.append(transform(self.exprs[i]))
623 return ''.join(res)
624
625 def describe_signature(self, signode: TextElement, mode: str,
626 env: BuildEnvironment, symbol: Symbol) -> None:
627 self.exprs[0].describe_signature(signode, mode, env, symbol)
628 for i in range(1, len(self.exprs)):
629 signode += addnodes.desc_sig_space()
630 op = self.ops[i - 1]
631 if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
632 signode += addnodes.desc_sig_keyword(op, op)
633 else:
634 signode += addnodes.desc_sig_operator(op, op)
635 signode += addnodes.desc_sig_space()
636 self.exprs[i].describe_signature(signode, mode, env, symbol)
637
638
639class ASTAssignmentExpr(ASTExpression):
640 def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None:
641 assert len(exprs) > 0
642 assert len(exprs) == len(ops) + 1
643 self.exprs = exprs
644 self.ops = ops
645
646 def __eq__(self, other: object) -> bool:
647 if not isinstance(other, ASTAssignmentExpr):
648 return NotImplemented
649 return (
650 self.exprs == other.exprs
651 and self.ops == other.ops
652 )
653
654 def __hash__(self) -> int:
655 return hash((self.exprs, self.ops))
656
657 def _stringify(self, transform: StringifyTransform) -> str:
658 res = []
659 res.append(transform(self.exprs[0]))
660 for i in range(1, len(self.exprs)):
661 res.append(' ')
662 res.append(self.ops[i - 1])
663 res.append(' ')
664 res.append(transform(self.exprs[i]))
665 return ''.join(res)
666
667 def describe_signature(self, signode: TextElement, mode: str,
668 env: BuildEnvironment, symbol: Symbol) -> None:
669 self.exprs[0].describe_signature(signode, mode, env, symbol)
670 for i in range(1, len(self.exprs)):
671 signode += addnodes.desc_sig_space()
672 op = self.ops[i - 1]
673 if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
674 signode += addnodes.desc_sig_keyword(op, op)
675 else:
676 signode += addnodes.desc_sig_operator(op, op)
677 signode += addnodes.desc_sig_space()
678 self.exprs[i].describe_signature(signode, mode, env, symbol)
679
680
681class ASTFallbackExpr(ASTExpression):
682 def __init__(self, expr: str) -> None:
683 self.expr = expr
684
685 def __eq__(self, other: object) -> bool:
686 if not isinstance(other, ASTFallbackExpr):
687 return NotImplemented
688 return self.expr == other.expr
689
690 def __hash__(self) -> int:
691 return hash(self.expr)
692
693 def _stringify(self, transform: StringifyTransform) -> str:
694 return self.expr
695
696 def get_id(self, version: int) -> str:
697 return str(self.expr)
698
699 def describe_signature(self, signode: TextElement, mode: str,
700 env: BuildEnvironment, symbol: Symbol) -> None:
701 signode += nodes.literal(self.expr, self.expr)
702
703
704################################################################################
705# Types
706################################################################################
707
708class ASTTrailingTypeSpec(ASTBase):
709 pass
710
711
712class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
713 def __init__(self, names: list[str]) -> None:
714 assert len(names) != 0
715 self.names = names
716
717 def __eq__(self, other: object) -> bool:
718 if not isinstance(other, ASTTrailingTypeSpecFundamental):
719 return NotImplemented
720 return self.names == other.names
721
722 def __hash__(self) -> int:
723 return hash(self.names)
724
725 def _stringify(self, transform: StringifyTransform) -> str:
726 return ' '.join(self.names)
727
728 def describe_signature(self, signode: TextElement, mode: str,
729 env: BuildEnvironment, symbol: Symbol) -> None:
730 first = True
731 for n in self.names:
732 if not first:
733 signode += addnodes.desc_sig_space()
734 else:
735 first = False
736 signode += addnodes.desc_sig_keyword_type(n, n)
737
738
739class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
740 def __init__(self, prefix: str, nestedName: ASTNestedName) -> None:
741 self.prefix = prefix
742 self.nestedName = nestedName
743
744 def __eq__(self, other: object) -> bool:
745 if not isinstance(other, ASTTrailingTypeSpecName):
746 return NotImplemented
747 return (
748 self.prefix == other.prefix
749 and self.nestedName == other.nestedName
750 )
751
752 def __hash__(self) -> int:
753 return hash((self.prefix, self.nestedName))
754
755 @property
756 def name(self) -> ASTNestedName:
757 return self.nestedName
758
759 def _stringify(self, transform: StringifyTransform) -> str:
760 res = []
761 if self.prefix:
762 res.append(self.prefix)
763 res.append(' ')
764 res.append(transform(self.nestedName))
765 return ''.join(res)
766
767 def describe_signature(self, signode: TextElement, mode: str,
768 env: BuildEnvironment, symbol: Symbol) -> None:
769 if self.prefix:
770 signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
771 signode += addnodes.desc_sig_space()
772 self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
773
774
775class ASTFunctionParameter(ASTBase):
776 def __init__(self, arg: ASTTypeWithInit | None, ellipsis: bool = False) -> None:
777 self.arg = arg
778 self.ellipsis = ellipsis
779
780 def __eq__(self, other: object) -> bool:
781 if not isinstance(other, ASTFunctionParameter):
782 return NotImplemented
783 return self.arg == other.arg and self.ellipsis == other.ellipsis
784
785 def __hash__(self) -> int:
786 return hash((self.arg, self.ellipsis))
787
788 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
789 # the anchor will be our parent
790 return symbol.parent.declaration.get_id(version, prefixed=False)
791
792 def _stringify(self, transform: StringifyTransform) -> str:
793 if self.ellipsis:
794 return '...'
795 else:
796 return transform(self.arg)
797
798 def describe_signature(self, signode: Any, mode: str,
799 env: BuildEnvironment, symbol: Symbol) -> None:
800 verify_description_mode(mode)
801 if self.ellipsis:
802 signode += addnodes.desc_sig_punctuation('...', '...')
803 else:
804 self.arg.describe_signature(signode, mode, env, symbol=symbol)
805
806
807class ASTParameters(ASTBase):
808 def __init__(self, args: list[ASTFunctionParameter], attrs: ASTAttributeList) -> None:
809 self.args = args
810 self.attrs = attrs
811
812 def __eq__(self, other: object) -> bool:
813 if not isinstance(other, ASTParameters):
814 return NotImplemented
815 return self.args == other.args and self.attrs == other.attrs
816
817 def __hash__(self) -> int:
818 return hash((self.args, self.attrs))
819
820 @property
821 def function_params(self) -> list[ASTFunctionParameter]:
822 return self.args
823
824 def _stringify(self, transform: StringifyTransform) -> str:
825 res = []
826 res.append('(')
827 first = True
828 for a in self.args:
829 if not first:
830 res.append(', ')
831 first = False
832 res.append(str(a))
833 res.append(')')
834 if len(self.attrs) != 0:
835 res.append(' ')
836 res.append(transform(self.attrs))
837 return ''.join(res)
838
839 def describe_signature(self, signode: TextElement, mode: str,
840 env: BuildEnvironment, symbol: Symbol) -> None:
841 verify_description_mode(mode)
842 multi_line_parameter_list = False
843 test_node: Element = signode
844 while test_node.parent:
845 if not isinstance(test_node, addnodes.desc_signature):
846 test_node = test_node.parent
847 continue
848 multi_line_parameter_list = test_node.get('multi_line_parameter_list', False)
849 break
850
851 # only use the desc_parameterlist for the outer list, not for inner lists
852 if mode == 'lastIsName':
853 paramlist = addnodes.desc_parameterlist()
854 paramlist['multi_line_parameter_list'] = multi_line_parameter_list
855 for arg in self.args:
856 param = addnodes.desc_parameter('', '', noemph=True)
857 arg.describe_signature(param, 'param', env, symbol=symbol)
858 paramlist += param
859 signode += paramlist
860 else:
861 signode += addnodes.desc_sig_punctuation('(', '(')
862 first = True
863 for arg in self.args:
864 if not first:
865 signode += addnodes.desc_sig_punctuation(',', ',')
866 signode += addnodes.desc_sig_space()
867 first = False
868 arg.describe_signature(signode, 'markType', env, symbol=symbol)
869 signode += addnodes.desc_sig_punctuation(')', ')')
870
871 if len(self.attrs) != 0:
872 signode += addnodes.desc_sig_space()
873 self.attrs.describe_signature(signode)
874
875
876class ASTDeclSpecsSimple(ASTBaseBase):
877 def __init__(self, storage: str, threadLocal: str, inline: bool,
878 restrict: bool, volatile: bool, const: bool, attrs: ASTAttributeList) -> None:
879 self.storage = storage
880 self.threadLocal = threadLocal
881 self.inline = inline
882 self.restrict = restrict
883 self.volatile = volatile
884 self.const = const
885 self.attrs = attrs
886
887 def __eq__(self, other: object) -> bool:
888 if not isinstance(other, ASTDeclSpecsSimple):
889 return NotImplemented
890 return (
891 self.storage == other.storage
892 and self.threadLocal == other.threadLocal
893 and self.inline == other.inline
894 and self.restrict == other.restrict
895 and self.volatile == other.volatile
896 and self.const == other.const
897 and self.attrs == other.attrs
898 )
899
900 def __hash__(self) -> int:
901 return hash((
902 self.storage,
903 self.threadLocal,
904 self.inline,
905 self.restrict,
906 self.volatile,
907 self.const,
908 self.attrs,
909 ))
910
911 def mergeWith(self, other: ASTDeclSpecsSimple) -> ASTDeclSpecsSimple:
912 if not other:
913 return self
914 return ASTDeclSpecsSimple(self.storage or other.storage,
915 self.threadLocal or other.threadLocal,
916 self.inline or other.inline,
917 self.volatile or other.volatile,
918 self.const or other.const,
919 self.restrict or other.restrict,
920 self.attrs + other.attrs)
921
922 def _stringify(self, transform: StringifyTransform) -> str:
923 res: list[str] = []
924 if len(self.attrs) != 0:
925 res.append(transform(self.attrs))
926 if self.storage:
927 res.append(self.storage)
928 if self.threadLocal:
929 res.append(self.threadLocal)
930 if self.inline:
931 res.append('inline')
932 if self.restrict:
933 res.append('restrict')
934 if self.volatile:
935 res.append('volatile')
936 if self.const:
937 res.append('const')
938 return ' '.join(res)
939
940 def describe_signature(self, modifiers: list[Node]) -> None:
941 def _add(modifiers: list[Node], text: str) -> None:
942 if len(modifiers) != 0:
943 modifiers.append(addnodes.desc_sig_space())
944 modifiers.append(addnodes.desc_sig_keyword(text, text))
945
946 if len(modifiers) != 0 and len(self.attrs) != 0:
947 modifiers.append(addnodes.desc_sig_space())
948 tempNode = nodes.TextElement()
949 self.attrs.describe_signature(tempNode)
950 modifiers.extend(tempNode.children)
951 if self.storage:
952 _add(modifiers, self.storage)
953 if self.threadLocal:
954 _add(modifiers, self.threadLocal)
955 if self.inline:
956 _add(modifiers, 'inline')
957 if self.restrict:
958 _add(modifiers, 'restrict')
959 if self.volatile:
960 _add(modifiers, 'volatile')
961 if self.const:
962 _add(modifiers, 'const')
963
964
965class ASTDeclSpecs(ASTBase):
966 def __init__(self, outer: str,
967 leftSpecs: ASTDeclSpecsSimple,
968 rightSpecs: ASTDeclSpecsSimple,
969 trailing: ASTTrailingTypeSpec) -> None:
970 # leftSpecs and rightSpecs are used for output
971 # allSpecs are used for id generation TODO: remove?
972 self.outer = outer
973 self.leftSpecs = leftSpecs
974 self.rightSpecs = rightSpecs
975 self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
976 self.trailingTypeSpec = trailing
977
978 def __eq__(self, other: object) -> bool:
979 if not isinstance(other, ASTDeclSpecs):
980 return NotImplemented
981 return (
982 self.outer == other.outer
983 and self.leftSpecs == other.leftSpecs
984 and self.rightSpecs == other.rightSpecs
985 and self.trailingTypeSpec == other.trailingTypeSpec
986 )
987
988 def __hash__(self) -> int:
989 return hash((
990 self.outer,
991 self.leftSpecs,
992 self.rightSpecs,
993 self.trailingTypeSpec,
994 ))
995
996 def _stringify(self, transform: StringifyTransform) -> str:
997 res: list[str] = []
998 l = transform(self.leftSpecs)
999 if len(l) > 0:
1000 res.append(l)
1001 if self.trailingTypeSpec:
1002 if len(res) > 0:
1003 res.append(" ")
1004 res.append(transform(self.trailingTypeSpec))
1005 r = str(self.rightSpecs)
1006 if len(r) > 0:
1007 if len(res) > 0:
1008 res.append(" ")
1009 res.append(r)
1010 return "".join(res)
1011
1012 def describe_signature(self, signode: TextElement, mode: str,
1013 env: BuildEnvironment, symbol: Symbol) -> None:
1014 verify_description_mode(mode)
1015 modifiers: list[Node] = []
1016
1017 self.leftSpecs.describe_signature(modifiers)
1018
1019 for m in modifiers:
1020 signode += m
1021 if self.trailingTypeSpec:
1022 if len(modifiers) > 0:
1023 signode += addnodes.desc_sig_space()
1024 self.trailingTypeSpec.describe_signature(signode, mode, env,
1025 symbol=symbol)
1026 modifiers = []
1027 self.rightSpecs.describe_signature(modifiers)
1028 if len(modifiers) > 0:
1029 signode += addnodes.desc_sig_space()
1030 for m in modifiers:
1031 signode += m
1032
1033
1034# Declarator
1035################################################################################
1036
1037class ASTArray(ASTBase):
1038 def __init__(self, static: bool, const: bool, volatile: bool, restrict: bool,
1039 vla: bool, size: ASTExpression) -> None:
1040 self.static = static
1041 self.const = const
1042 self.volatile = volatile
1043 self.restrict = restrict
1044 self.vla = vla
1045 self.size = size
1046 if vla:
1047 assert size is None
1048 if size is not None:
1049 assert not vla
1050
1051 def __eq__(self, other: object) -> bool:
1052 if not isinstance(other, ASTArray):
1053 return NotImplemented
1054 return (
1055 self.static == other.static
1056 and self.const == other.const
1057 and self.volatile == other.volatile
1058 and self.restrict == other.restrict
1059 and self.vla == other.vla
1060 and self.size == other.size
1061 )
1062
1063 def __hash__(self) -> int:
1064 return hash((
1065 self.static,
1066 self.const,
1067 self.volatile,
1068 self.restrict,
1069 self.vla,
1070 self.size,
1071 ))
1072
1073 def _stringify(self, transform: StringifyTransform) -> str:
1074 el = []
1075 if self.static:
1076 el.append('static')
1077 if self.restrict:
1078 el.append('restrict')
1079 if self.volatile:
1080 el.append('volatile')
1081 if self.const:
1082 el.append('const')
1083 if self.vla:
1084 return '[' + ' '.join(el) + '*]'
1085 elif self.size:
1086 el.append(transform(self.size))
1087 return '[' + ' '.join(el) + ']'
1088
1089 def describe_signature(self, signode: TextElement, mode: str,
1090 env: BuildEnvironment, symbol: Symbol) -> None:
1091 verify_description_mode(mode)
1092 signode += addnodes.desc_sig_punctuation('[', '[')
1093 addSpace = False
1094
1095 def _add(signode: TextElement, text: str) -> bool:
1096 if addSpace:
1097 signode += addnodes.desc_sig_space()
1098 signode += addnodes.desc_sig_keyword(text, text)
1099 return True
1100
1101 if self.static:
1102 addSpace = _add(signode, 'static')
1103 if self.restrict:
1104 addSpace = _add(signode, 'restrict')
1105 if self.volatile:
1106 addSpace = _add(signode, 'volatile')
1107 if self.const:
1108 addSpace = _add(signode, 'const')
1109 if self.vla:
1110 signode += addnodes.desc_sig_punctuation('*', '*')
1111 elif self.size:
1112 if addSpace:
1113 signode += addnodes.desc_sig_space()
1114 self.size.describe_signature(signode, 'markType', env, symbol)
1115 signode += addnodes.desc_sig_punctuation(']', ']')
1116
1117
1118class ASTDeclarator(ASTBase):
1119 @property
1120 def name(self) -> ASTNestedName:
1121 raise NotImplementedError(repr(self))
1122
1123 @property
1124 def function_params(self) -> list[ASTFunctionParameter]:
1125 raise NotImplementedError(repr(self))
1126
1127 def require_space_after_declSpecs(self) -> bool:
1128 raise NotImplementedError(repr(self))
1129
1130
1131class ASTDeclaratorNameParam(ASTDeclarator):
1132 def __init__(self, declId: ASTNestedName,
1133 arrayOps: list[ASTArray], param: ASTParameters) -> None:
1134 self.declId = declId
1135 self.arrayOps = arrayOps
1136 self.param = param
1137
1138 def __eq__(self, other: object) -> bool:
1139 if not isinstance(other, ASTDeclaratorNameParam):
1140 return NotImplemented
1141 return (
1142 self.declId == other.declId
1143 and self.arrayOps == other.arrayOps
1144 and self.param == other.param
1145 )
1146
1147 def __hash__(self) -> int:
1148 return hash((self.declId, self.arrayOps, self.param))
1149
1150 @property
1151 def name(self) -> ASTNestedName:
1152 return self.declId
1153
1154 @property
1155 def function_params(self) -> list[ASTFunctionParameter]:
1156 return self.param.function_params
1157
1158 # ------------------------------------------------------------------------
1159
1160 def require_space_after_declSpecs(self) -> bool:
1161 return self.declId is not None
1162
1163 def _stringify(self, transform: StringifyTransform) -> str:
1164 res = []
1165 if self.declId:
1166 res.append(transform(self.declId))
1167 res.extend(transform(op) for op in self.arrayOps)
1168 if self.param:
1169 res.append(transform(self.param))
1170 return ''.join(res)
1171
1172 def describe_signature(self, signode: TextElement, mode: str,
1173 env: BuildEnvironment, symbol: Symbol) -> None:
1174 verify_description_mode(mode)
1175 if self.declId:
1176 self.declId.describe_signature(signode, mode, env, symbol)
1177 for op in self.arrayOps:
1178 op.describe_signature(signode, mode, env, symbol)
1179 if self.param:
1180 self.param.describe_signature(signode, mode, env, symbol)
1181
1182
1183class ASTDeclaratorNameBitField(ASTDeclarator):
1184 def __init__(self, declId: ASTNestedName, size: ASTExpression) -> None:
1185 self.declId = declId
1186 self.size = size
1187
1188 def __eq__(self, other: object) -> bool:
1189 if not isinstance(other, ASTDeclaratorNameBitField):
1190 return NotImplemented
1191 return self.declId == other.declId and self.size == other.size
1192
1193 def __hash__(self) -> int:
1194 return hash((self.declId, self.size))
1195
1196 @property
1197 def name(self) -> ASTNestedName:
1198 return self.declId
1199
1200 # ------------------------------------------------------------------------
1201
1202 def require_space_after_declSpecs(self) -> bool:
1203 return self.declId is not None
1204
1205 def _stringify(self, transform: StringifyTransform) -> str:
1206 res = []
1207 if self.declId:
1208 res.append(transform(self.declId))
1209 res.append(" : ")
1210 res.append(transform(self.size))
1211 return ''.join(res)
1212
1213 def describe_signature(self, signode: TextElement, mode: str,
1214 env: BuildEnvironment, symbol: Symbol) -> None:
1215 verify_description_mode(mode)
1216 if self.declId:
1217 self.declId.describe_signature(signode, mode, env, symbol)
1218 signode += addnodes.desc_sig_space()
1219 signode += addnodes.desc_sig_punctuation(':', ':')
1220 signode += addnodes.desc_sig_space()
1221 self.size.describe_signature(signode, mode, env, symbol)
1222
1223
1224class ASTDeclaratorPtr(ASTDeclarator):
1225 def __init__(self, next: ASTDeclarator, restrict: bool, volatile: bool, const: bool,
1226 attrs: ASTAttributeList) -> None:
1227 assert next
1228 self.next = next
1229 self.restrict = restrict
1230 self.volatile = volatile
1231 self.const = const
1232 self.attrs = attrs
1233
1234 def __eq__(self, other: object) -> bool:
1235 if not isinstance(other, ASTDeclaratorPtr):
1236 return NotImplemented
1237 return (
1238 self.next == other.next
1239 and self.restrict == other.restrict
1240 and self.volatile == other.volatile
1241 and self.const == other.const
1242 and self.attrs == other.attrs
1243 )
1244
1245 def __hash__(self) -> int:
1246 return hash((self.next, self.restrict, self.volatile, self.const, self.attrs))
1247
1248 @property
1249 def name(self) -> ASTNestedName:
1250 return self.next.name
1251
1252 @property
1253 def function_params(self) -> list[ASTFunctionParameter]:
1254 return self.next.function_params
1255
1256 def require_space_after_declSpecs(self) -> bool:
1257 return self.const or self.volatile or self.restrict or \
1258 len(self.attrs) > 0 or \
1259 self.next.require_space_after_declSpecs()
1260
1261 def _stringify(self, transform: StringifyTransform) -> str:
1262 res = ['*']
1263 res.append(transform(self.attrs))
1264 if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
1265 res.append(' ')
1266 if self.restrict:
1267 res.append('restrict')
1268 if self.volatile:
1269 if self.restrict:
1270 res.append(' ')
1271 res.append('volatile')
1272 if self.const:
1273 if self.restrict or self.volatile:
1274 res.append(' ')
1275 res.append('const')
1276 if self.const or self.volatile or self.restrict or len(self.attrs) > 0:
1277 if self.next.require_space_after_declSpecs():
1278 res.append(' ')
1279 res.append(transform(self.next))
1280 return ''.join(res)
1281
1282 def describe_signature(self, signode: TextElement, mode: str,
1283 env: BuildEnvironment, symbol: Symbol) -> None:
1284 verify_description_mode(mode)
1285 signode += addnodes.desc_sig_punctuation('*', '*')
1286 self.attrs.describe_signature(signode)
1287 if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
1288 signode += addnodes.desc_sig_space()
1289
1290 def _add_anno(signode: TextElement, text: str) -> None:
1291 signode += addnodes.desc_sig_keyword(text, text)
1292
1293 if self.restrict:
1294 _add_anno(signode, 'restrict')
1295 if self.volatile:
1296 if self.restrict:
1297 signode += addnodes.desc_sig_space()
1298 _add_anno(signode, 'volatile')
1299 if self.const:
1300 if self.restrict or self.volatile:
1301 signode += addnodes.desc_sig_space()
1302 _add_anno(signode, 'const')
1303 if self.const or self.volatile or self.restrict or len(self.attrs) > 0:
1304 if self.next.require_space_after_declSpecs():
1305 signode += addnodes.desc_sig_space()
1306 self.next.describe_signature(signode, mode, env, symbol)
1307
1308
1309class ASTDeclaratorParen(ASTDeclarator):
1310 def __init__(self, inner: ASTDeclarator, next: ASTDeclarator) -> None:
1311 assert inner
1312 assert next
1313 self.inner = inner
1314 self.next = next
1315 # TODO: we assume the name and params are in inner
1316
1317 def __eq__(self, other: object) -> bool:
1318 if not isinstance(other, ASTDeclaratorParen):
1319 return NotImplemented
1320 return self.inner == other.inner and self.next == other.next
1321
1322 def __hash__(self) -> int:
1323 return hash((self.inner, self.next))
1324
1325 @property
1326 def name(self) -> ASTNestedName:
1327 return self.inner.name
1328
1329 @property
1330 def function_params(self) -> list[ASTFunctionParameter]:
1331 return self.inner.function_params
1332
1333 def require_space_after_declSpecs(self) -> bool:
1334 return True
1335
1336 def _stringify(self, transform: StringifyTransform) -> str:
1337 res = ['(']
1338 res.append(transform(self.inner))
1339 res.append(')')
1340 res.append(transform(self.next))
1341 return ''.join(res)
1342
1343 def describe_signature(self, signode: TextElement, mode: str,
1344 env: BuildEnvironment, symbol: Symbol) -> None:
1345 verify_description_mode(mode)
1346 signode += addnodes.desc_sig_punctuation('(', '(')
1347 self.inner.describe_signature(signode, mode, env, symbol)
1348 signode += addnodes.desc_sig_punctuation(')', ')')
1349 self.next.describe_signature(signode, "noneIsName", env, symbol)
1350
1351
1352# Initializer
1353################################################################################
1354
1355class ASTParenExprList(ASTBaseParenExprList):
1356 def __init__(self, exprs: list[ASTExpression]) -> None:
1357 self.exprs = exprs
1358
1359 def __eq__(self, other: object) -> bool:
1360 if not isinstance(other, ASTParenExprList):
1361 return NotImplemented
1362 return self.exprs == other.exprs
1363
1364 def __hash__(self) -> int:
1365 return hash(self.exprs)
1366
1367 def _stringify(self, transform: StringifyTransform) -> str:
1368 exprs = [transform(e) for e in self.exprs]
1369 return '(%s)' % ', '.join(exprs)
1370
1371 def describe_signature(self, signode: TextElement, mode: str,
1372 env: BuildEnvironment, symbol: Symbol) -> None:
1373 verify_description_mode(mode)
1374 signode += addnodes.desc_sig_punctuation('(', '(')
1375 first = True
1376 for e in self.exprs:
1377 if not first:
1378 signode += addnodes.desc_sig_punctuation(',', ',')
1379 signode += addnodes.desc_sig_space()
1380 else:
1381 first = False
1382 e.describe_signature(signode, mode, env, symbol)
1383 signode += addnodes.desc_sig_punctuation(')', ')')
1384
1385
1386class ASTBracedInitList(ASTBase):
1387 def __init__(self, exprs: list[ASTExpression], trailingComma: bool) -> None:
1388 self.exprs = exprs
1389 self.trailingComma = trailingComma
1390
1391 def __eq__(self, other: object) -> bool:
1392 if not isinstance(other, ASTBracedInitList):
1393 return NotImplemented
1394 return self.exprs == other.exprs and self.trailingComma == other.trailingComma
1395
1396 def __hash__(self) -> int:
1397 return hash((self.exprs, self.trailingComma))
1398
1399 def _stringify(self, transform: StringifyTransform) -> str:
1400 exprs = ', '.join(transform(e) for e in self.exprs)
1401 trailingComma = ',' if self.trailingComma else ''
1402 return f'{{{exprs}{trailingComma}}}'
1403
1404 def describe_signature(self, signode: TextElement, mode: str,
1405 env: BuildEnvironment, symbol: Symbol) -> None:
1406 verify_description_mode(mode)
1407 signode += addnodes.desc_sig_punctuation('{', '{')
1408 first = True
1409 for e in self.exprs:
1410 if not first:
1411 signode += addnodes.desc_sig_punctuation(',', ',')
1412 signode += addnodes.desc_sig_space()
1413 else:
1414 first = False
1415 e.describe_signature(signode, mode, env, symbol)
1416 if self.trailingComma:
1417 signode += addnodes.desc_sig_punctuation(',', ',')
1418 signode += addnodes.desc_sig_punctuation('}', '}')
1419
1420
1421class ASTInitializer(ASTBase):
1422 def __init__(self, value: ASTBracedInitList | ASTExpression,
1423 hasAssign: bool = True) -> None:
1424 self.value = value
1425 self.hasAssign = hasAssign
1426
1427 def __eq__(self, other: object) -> bool:
1428 if not isinstance(other, ASTInitializer):
1429 return NotImplemented
1430 return self.value == other.value and self.hasAssign == other.hasAssign
1431
1432 def __hash__(self) -> int:
1433 return hash((self.value, self.hasAssign))
1434
1435 def _stringify(self, transform: StringifyTransform) -> str:
1436 val = transform(self.value)
1437 if self.hasAssign:
1438 return ' = ' + val
1439 else:
1440 return val
1441
1442 def describe_signature(self, signode: TextElement, mode: str,
1443 env: BuildEnvironment, symbol: Symbol) -> None:
1444 verify_description_mode(mode)
1445 if self.hasAssign:
1446 signode += addnodes.desc_sig_space()
1447 signode += addnodes.desc_sig_punctuation('=', '=')
1448 signode += addnodes.desc_sig_space()
1449 self.value.describe_signature(signode, 'markType', env, symbol)
1450
1451
1452class ASTType(ASTBase):
1453 def __init__(self, declSpecs: ASTDeclSpecs, decl: ASTDeclarator) -> None:
1454 assert declSpecs
1455 assert decl
1456 self.declSpecs = declSpecs
1457 self.decl = decl
1458
1459 def __eq__(self, other: object) -> bool:
1460 if not isinstance(other, ASTType):
1461 return NotImplemented
1462 return self.declSpecs == other.declSpecs and self.decl == other.decl
1463
1464 def __hash__(self) -> int:
1465 return hash((self.declSpecs, self.decl))
1466
1467 @property
1468 def name(self) -> ASTNestedName:
1469 return self.decl.name
1470
1471 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1472 return symbol.get_full_nested_name().get_id(version)
1473
1474 @property
1475 def function_params(self) -> list[ASTFunctionParameter]:
1476 return self.decl.function_params
1477
1478 def _stringify(self, transform: StringifyTransform) -> str:
1479 res = []
1480 declSpecs = transform(self.declSpecs)
1481 res.append(declSpecs)
1482 if self.decl.require_space_after_declSpecs() and len(declSpecs) > 0:
1483 res.append(' ')
1484 res.append(transform(self.decl))
1485 return ''.join(res)
1486
1487 def get_type_declaration_prefix(self) -> str:
1488 if self.declSpecs.trailingTypeSpec:
1489 return 'typedef'
1490 else:
1491 return 'type'
1492
1493 def describe_signature(self, signode: TextElement, mode: str,
1494 env: BuildEnvironment, symbol: Symbol) -> None:
1495 verify_description_mode(mode)
1496 self.declSpecs.describe_signature(signode, 'markType', env, symbol)
1497 if (self.decl.require_space_after_declSpecs() and
1498 len(str(self.declSpecs)) > 0):
1499 signode += addnodes.desc_sig_space()
1500 # for parameters that don't really declare new names we get 'markType',
1501 # this should not be propagated, but be 'noneIsName'.
1502 if mode == 'markType':
1503 mode = 'noneIsName'
1504 self.decl.describe_signature(signode, mode, env, symbol)
1505
1506
1507class ASTTypeWithInit(ASTBase):
1508 def __init__(self, type: ASTType, init: ASTInitializer) -> None:
1509 self.type = type
1510 self.init = init
1511
1512 def __eq__(self, other: object) -> bool:
1513 if not isinstance(other, ASTTypeWithInit):
1514 return NotImplemented
1515 return self.type == other.type and self.init == other.init
1516
1517 def __hash__(self) -> int:
1518 return hash((self.type, self.init))
1519
1520 @property
1521 def name(self) -> ASTNestedName:
1522 return self.type.name
1523
1524 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1525 return self.type.get_id(version, objectType, symbol)
1526
1527 def _stringify(self, transform: StringifyTransform) -> str:
1528 res = []
1529 res.append(transform(self.type))
1530 if self.init:
1531 res.append(transform(self.init))
1532 return ''.join(res)
1533
1534 def describe_signature(self, signode: TextElement, mode: str,
1535 env: BuildEnvironment, symbol: Symbol) -> None:
1536 verify_description_mode(mode)
1537 self.type.describe_signature(signode, mode, env, symbol)
1538 if self.init:
1539 self.init.describe_signature(signode, mode, env, symbol)
1540
1541
1542class ASTMacroParameter(ASTBase):
1543 def __init__(self, arg: ASTNestedName | None, ellipsis: bool = False,
1544 variadic: bool = False) -> None:
1545 self.arg = arg
1546 self.ellipsis = ellipsis
1547 self.variadic = variadic
1548
1549 def __eq__(self, other: object) -> bool:
1550 if not isinstance(other, ASTMacroParameter):
1551 return NotImplemented
1552 return (
1553 self.arg == other.arg
1554 and self.ellipsis == other.ellipsis
1555 and self.variadic == other.variadic
1556 )
1557
1558 def __hash__(self) -> int:
1559 return hash((self.arg, self.ellipsis, self.variadic))
1560
1561 def _stringify(self, transform: StringifyTransform) -> str:
1562 if self.ellipsis:
1563 return '...'
1564 elif self.variadic:
1565 return transform(self.arg) + '...'
1566 else:
1567 return transform(self.arg)
1568
1569 def describe_signature(self, signode: Any, mode: str,
1570 env: BuildEnvironment, symbol: Symbol) -> None:
1571 verify_description_mode(mode)
1572 if self.ellipsis:
1573 signode += addnodes.desc_sig_punctuation('...', '...')
1574 elif self.variadic:
1575 name = str(self)
1576 signode += addnodes.desc_sig_name(name, name)
1577 else:
1578 self.arg.describe_signature(signode, mode, env, symbol=symbol)
1579
1580
1581class ASTMacro(ASTBase):
1582 def __init__(self, ident: ASTNestedName, args: list[ASTMacroParameter] | None) -> None:
1583 self.ident = ident
1584 self.args = args
1585
1586 def __eq__(self, other: object) -> bool:
1587 if not isinstance(other, ASTMacro):
1588 return NotImplemented
1589 return self.ident == other.ident and self.args == other.args
1590
1591 def __hash__(self) -> int:
1592 return hash((self.ident, self.args))
1593
1594 @property
1595 def name(self) -> ASTNestedName:
1596 return self.ident
1597
1598 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1599 return symbol.get_full_nested_name().get_id(version)
1600
1601 def _stringify(self, transform: StringifyTransform) -> str:
1602 res = []
1603 res.append(transform(self.ident))
1604 if self.args is not None:
1605 res.append('(')
1606 first = True
1607 for arg in self.args:
1608 if not first:
1609 res.append(', ')
1610 first = False
1611 res.append(transform(arg))
1612 res.append(')')
1613 return ''.join(res)
1614
1615 def describe_signature(self, signode: TextElement, mode: str,
1616 env: BuildEnvironment, symbol: Symbol) -> None:
1617 verify_description_mode(mode)
1618 self.ident.describe_signature(signode, mode, env, symbol)
1619 if self.args is None:
1620 return
1621 paramlist = addnodes.desc_parameterlist()
1622 for arg in self.args:
1623 param = addnodes.desc_parameter('', '', noemph=True)
1624 arg.describe_signature(param, 'param', env, symbol=symbol)
1625 paramlist += param
1626 signode += paramlist
1627
1628
1629class ASTStruct(ASTBase):
1630 def __init__(self, name: ASTNestedName) -> None:
1631 self.name = name
1632
1633 def __eq__(self, other: object) -> bool:
1634 if not isinstance(other, ASTStruct):
1635 return NotImplemented
1636 return self.name == other.name
1637
1638 def __hash__(self) -> int:
1639 return hash(self.name)
1640
1641 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1642 return symbol.get_full_nested_name().get_id(version)
1643
1644 def _stringify(self, transform: StringifyTransform) -> str:
1645 return transform(self.name)
1646
1647 def describe_signature(self, signode: TextElement, mode: str,
1648 env: BuildEnvironment, symbol: Symbol) -> None:
1649 verify_description_mode(mode)
1650 self.name.describe_signature(signode, mode, env, symbol=symbol)
1651
1652
1653class ASTUnion(ASTBase):
1654 def __init__(self, name: ASTNestedName) -> None:
1655 self.name = name
1656
1657 def __eq__(self, other: object) -> bool:
1658 if not isinstance(other, ASTUnion):
1659 return NotImplemented
1660 return self.name == other.name
1661
1662 def __hash__(self) -> int:
1663 return hash(self.name)
1664
1665 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1666 return symbol.get_full_nested_name().get_id(version)
1667
1668 def _stringify(self, transform: StringifyTransform) -> str:
1669 return transform(self.name)
1670
1671 def describe_signature(self, signode: TextElement, mode: str,
1672 env: BuildEnvironment, symbol: Symbol) -> None:
1673 verify_description_mode(mode)
1674 self.name.describe_signature(signode, mode, env, symbol=symbol)
1675
1676
1677class ASTEnum(ASTBase):
1678 def __init__(self, name: ASTNestedName) -> None:
1679 self.name = name
1680
1681 def __eq__(self, other: object) -> bool:
1682 if not isinstance(other, ASTEnum):
1683 return NotImplemented
1684 return self.name == other.name
1685
1686 def __hash__(self) -> int:
1687 return hash(self.name)
1688
1689 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1690 return symbol.get_full_nested_name().get_id(version)
1691
1692 def _stringify(self, transform: StringifyTransform) -> str:
1693 return transform(self.name)
1694
1695 def describe_signature(self, signode: TextElement, mode: str,
1696 env: BuildEnvironment, symbol: Symbol) -> None:
1697 verify_description_mode(mode)
1698 self.name.describe_signature(signode, mode, env, symbol=symbol)
1699
1700
1701class ASTEnumerator(ASTBase):
1702 def __init__(self, name: ASTNestedName, init: ASTInitializer | None,
1703 attrs: ASTAttributeList) -> None:
1704 self.name = name
1705 self.init = init
1706 self.attrs = attrs
1707
1708 def __eq__(self, other: object) -> bool:
1709 if not isinstance(other, ASTEnumerator):
1710 return NotImplemented
1711 return (
1712 self.name == other.name
1713 and self.init == other.init
1714 and self.attrs == other.attrs
1715 )
1716
1717 def __hash__(self) -> int:
1718 return hash((self.name, self.init, self.attrs))
1719
1720 def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
1721 return symbol.get_full_nested_name().get_id(version)
1722
1723 def _stringify(self, transform: StringifyTransform) -> str:
1724 res = []
1725 res.append(transform(self.name))
1726 if len(self.attrs) != 0:
1727 res.append(' ')
1728 res.append(transform(self.attrs))
1729 if self.init:
1730 res.append(transform(self.init))
1731 return ''.join(res)
1732
1733 def describe_signature(self, signode: TextElement, mode: str,
1734 env: BuildEnvironment, symbol: Symbol) -> None:
1735 verify_description_mode(mode)
1736 self.name.describe_signature(signode, mode, env, symbol)
1737 if len(self.attrs) != 0:
1738 signode += addnodes.desc_sig_space()
1739 self.attrs.describe_signature(signode)
1740 if self.init:
1741 self.init.describe_signature(signode, 'markType', env, symbol)
1742
1743
1744class ASTDeclaration(ASTBaseBase):
1745 def __init__(self, objectType: str, directiveType: str | None,
1746 declaration: DeclarationType | ASTFunctionParameter,
1747 semicolon: bool = False) -> None:
1748 self.objectType = objectType
1749 self.directiveType = directiveType
1750 self.declaration = declaration
1751 self.semicolon = semicolon
1752
1753 self.symbol: Symbol | None = None
1754 # set by CObject._add_enumerator_to_parent
1755 self.enumeratorScopedSymbol: Symbol | None = None
1756
1757 # the cache assumes that by the time get_newest_id is called, no
1758 # further changes will be made to this object
1759 self._newest_id_cache: str | None = None
1760
1761 def __eq__(self, other: object) -> bool:
1762 if not isinstance(other, ASTDeclaration):
1763 return NotImplemented
1764 return (
1765 self.objectType == other.objectType
1766 and self.directiveType == other.directiveType
1767 and self.declaration == other.declaration
1768 and self.semicolon == other.semicolon
1769 and self.symbol == other.symbol
1770 and self.enumeratorScopedSymbol == other.enumeratorScopedSymbol
1771 )
1772
1773 def clone(self) -> ASTDeclaration:
1774 return ASTDeclaration(self.objectType, self.directiveType,
1775 self.declaration.clone(), self.semicolon)
1776
1777 @property
1778 def name(self) -> ASTNestedName:
1779 decl = cast(DeclarationType, self.declaration)
1780 return decl.name
1781
1782 @property
1783 def function_params(self) -> list[ASTFunctionParameter] | None:
1784 if self.objectType != 'function':
1785 return None
1786 decl = cast(ASTType, self.declaration)
1787 return decl.function_params
1788
1789 def get_id(self, version: int, prefixed: bool = True) -> str:
1790 if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
1791 return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed)
1792 id_ = self.declaration.get_id(version, self.objectType, self.symbol)
1793 if prefixed:
1794 return _id_prefix[version] + id_
1795 else:
1796 return id_
1797
1798 def get_newest_id(self) -> str:
1799 if self._newest_id_cache is None:
1800 self._newest_id_cache = self.get_id(_max_id, True)
1801 return self._newest_id_cache
1802
1803 def _stringify(self, transform: StringifyTransform) -> str:
1804 res = transform(self.declaration)
1805 if self.semicolon:
1806 res += ';'
1807 return res
1808
1809 def describe_signature(self, signode: TextElement, mode: str,
1810 env: BuildEnvironment, options: dict[str, bool]) -> None:
1811 verify_description_mode(mode)
1812 assert self.symbol
1813 # The caller of the domain added a desc_signature node.
1814 # Always enable multiline:
1815 signode['is_multiline'] = True
1816 # Put each line in a desc_signature_line node.
1817 mainDeclNode = addnodes.desc_signature_line()
1818 mainDeclNode.sphinx_line_type = 'declarator'
1819 mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration
1820 signode += mainDeclNode
1821
1822 if self.objectType in {'member', 'function', 'macro'}:
1823 pass
1824 elif self.objectType == 'struct':
1825 mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct')
1826 mainDeclNode += addnodes.desc_sig_space()
1827 elif self.objectType == 'union':
1828 mainDeclNode += addnodes.desc_sig_keyword('union', 'union')
1829 mainDeclNode += addnodes.desc_sig_space()
1830 elif self.objectType == 'enum':
1831 mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum')
1832 mainDeclNode += addnodes.desc_sig_space()
1833 elif self.objectType == 'enumerator':
1834 mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator')
1835 mainDeclNode += addnodes.desc_sig_space()
1836 elif self.objectType == 'type':
1837 decl = cast(ASTType, self.declaration)
1838 prefix = decl.get_type_declaration_prefix()
1839 mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix)
1840 mainDeclNode += addnodes.desc_sig_space()
1841 else:
1842 raise AssertionError
1843 self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
1844 if self.semicolon:
1845 mainDeclNode += addnodes.desc_sig_punctuation(';', ';')