code: def test_domain_cpp_ast_expressions():
      def exprCheck(expr, id, id4=None):
          ids = "IE1CIA%s_1aE"
          # call .format() on the expr to unescape double curly braces
          idDict = {2: ids % expr.format(), 3: ids % id}
          if id4 is not None:
              idDict[4] = ids % id4
          check("class", "template<> {key}C<a[%s]>" % expr, idDict)
  
          class Config:
              cpp_id_attributes = ["id_attr"]
              cpp_paren_attributes = ["paren_attr"]
  
          parser = DefinitionParser(
              expr, location=None, config=Config()
          )
          parser.allowFallbackExpressionParsing = False
          ast = parser.parse_expression()
          res = str(ast)
          if res != expr:
              print("")
              print("Input:    ", expr)
              print("Result:   ", res)
              raise DefinitionError
          displayString = ast.get_display_string()
          if res != displayString:
              # note: if the expression contains an anon name then this will trigger a falsely
              print("")
              print("Input:    ", expr)
              print("Result:   ", res)
              print("Display:  ", displayString)
              raise DefinitionError
  
      # primary
      exprCheck("nullptr", "LDnE")
      exprCheck("true", "L1E")
      exprCheck("false", "L0E")
      ints = [
          "5",
          "0",
          "075",
          "0x0123456789ABCDEF",
          "0XF",
          "0b1",
          "0B1",
          "0b0'1'0",
          "00'1'2",
          "0x0'1'2",
          "1'2'3",
      ]
      unsignedSuffix = ["", "u", "U"]
      longSuffix = ["", "l", "L", "ll", "LL"]
      for i in ints:
          for u in unsignedSuffix:
              for l in longSuffix:
                  expr = i + u + l
                  exprCheck(expr, "L" + expr.replace("'", "") + "E")
                  expr = i + l + u
                  exprCheck(expr, "L" + expr.replace("'", "") + "E")
      decimalFloats = [
          "5e42",
          "5e+42",
          "5e-42",
          "5.",
          "5.e42",
          "5.e+42",
          "5.e-42",
          ".5",
          ".5e42",
          ".5e+42",
          ".5e-42",
          "5.0",
          "5.0e42",
          "5.0e+42",
          "5.0e-42",
          "1'2'3e7'8'9",
          "1'2'3.e7'8'9",
          ".4'5'6e7'8'9",
          "1'2'3.4'5'6e7'8'9",
      ]
      hexFloats = [
          "ApF",
          "Ap+F",
          "Ap-F",
          "A.",
          "A.pF",
          "A.p+F",
          "A.p-F",
          ".A",
          ".ApF",
          ".Ap+F",
          ".Ap-F",
          "A.B",
          "A.BpF",
          "A.Bp+F",
          "A.Bp-F",
          "A'B'Cp1'2'3",
          "A'B'C.p1'2'3",
          ".D'E'Fp1'2'3",
          "A'B'C.D'E'Fp1'2'3",
      ]
      for suffix in ["", "f", "F", "l", "L"]:
          for e in decimalFloats:
              expr = e + suffix
              exprCheck(expr, "L" + expr.replace("'", "") + "E")
          for e in hexFloats:
              expr = "0x" + e + suffix
              exprCheck(expr, "L" + expr.replace("'", "") + "E")
      exprCheck('"abc\\"cba"', "LA8_KcE")  # string
      exprCheck("this", "fpT")
      # character literals
      charPrefixAndIds = [
          ("", "c"),
          ("u8", "c"),
          ("u", "Ds"),
          ("U", "Di"),
          ("L", "w"),
      ]
      chars = [
          ("a", "97"),
          ("\\n", "10"),
          ("\\012", "10"),
          ("\\0", "0"),
          ("\\x0a", "10"),
          ("\\x0A", "10"),
          ("\\u0a42", "2626"),
          ("\\u0A42", "2626"),
          ("\\U0001f34c", "127820"),
          ("\\U0001F34C", "127820"),
      ]
      for p, t in charPrefixAndIds:
          for c, val in chars:
              exprCheck(f"{p}'{c}'", t + val)
      # user-defined literals
      for i in ints:
          exprCheck(
              i + "_udl", "clL_Zli4_udlEL" + i.replace("'", "") + "EE"
          )
          exprCheck(
              i + "uludl", "clL_Zli5uludlEL" + i.replace("'", "") + "EE"
          )
      for f in decimalFloats:
          exprCheck(
              f + "_udl", "clL_Zli4_udlEL" + f.replace("'", "") + "EE"
          )
          exprCheck(
              f + "fudl", "clL_Zli4fudlEL" + f.replace("'", "") + "EE"
          )
      for f in hexFloats:
          exprCheck(
              "0x" + f + "_udl",
              "clL_Zli4_udlEL0x" + f.replace("'", "") + "EE",
          )
      for p, t in charPrefixAndIds:
          for c, val in chars:
              exprCheck(
                  f"{p}'{c}'_udl", "clL_Zli4_udlE" + t + val + "E"
              )
      exprCheck('"abc"_udl', "clL_Zli4_udlELA3_KcEE")
      # from issue #7294
      exprCheck("6.62607015e-34q_J", "clL_Zli3q_JEL6.62607015e-34EE")
  
      # fold expressions, paren, name
      exprCheck("(... + Ns)", "(... + Ns)", id4="flpl2Ns")
      exprCheck("(Ns + ...)", "(Ns + ...)", id4="frpl2Ns")
      exprCheck("(Ns + ... + 0)", "(Ns + ... + 0)", id4="fLpl2NsL0E")
      exprCheck("(5)", "L5E")
      exprCheck("C", "1C")
      # postfix
      exprCheck("A(2)", "cl1AL2EE")
      exprCheck("A[2]", "ix1AL2E")
      exprCheck("a.b.c", "dtdt1a1b1c")
      exprCheck("a->b->c", "ptpt1a1b1c")
      exprCheck("i++", "pp1i")
      exprCheck("i--", "mm1i")
      exprCheck("dynamic_cast<T&>(i)++", "ppdcR1T1i")
      exprCheck("static_cast<T&>(i)++", "ppscR1T1i")
      exprCheck("reinterpret_cast<T&>(i)++", "pprcR1T1i")
      exprCheck("const_cast<T&>(i)++", "ppccR1T1i")
      exprCheck("typeid(T).name", "dtti1T4name")
      exprCheck("typeid(a + b).name", "dttepl1a1b4name")
      # unary
      exprCheck("++5", "pp_L5E")
      exprCheck("--5", "mm_L5E")
      exprCheck("*5", "deL5E")
      exprCheck("&5", "adL5E")
      exprCheck("+5", "psL5E")
      exprCheck("-5", "ngL5E")
      exprCheck("!5", "ntL5E")
      exprCheck("not 5", "ntL5E")
      exprCheck("~5", "coL5E")
      exprCheck("compl 5", "coL5E")
      exprCheck("sizeof...(a)", "sZ1a")
      exprCheck("sizeof(T)", "st1T")
      exprCheck("sizeof -42", "szngL42E")
      exprCheck("alignof(T)", "at1T")
      exprCheck("noexcept(-42)", "nxngL42E")
      # new-expression
      exprCheck("new int", "nw_iE")
      exprCheck("new volatile int", "nw_ViE")
      exprCheck("new int[42]", "nw_AL42E_iE")
      exprCheck("new int()", "nw_ipiE")
      exprCheck("new int(5, 42)", "nw_ipiL5EL42EE")
      exprCheck("::new int", "nw_iE")
      exprCheck("new int{{}}", "nw_iilE")
      exprCheck("new int{{5, 42}}", "nw_iilL5EL42EE")
      # delete-expression
      exprCheck("delete p", "dl1p")
      exprCheck("delete [] p", "da1p")
      exprCheck("::delete p", "dl1p")
      exprCheck("::delete [] p", "da1p")
      # cast
      exprCheck("(int)2", "cviL2E")
      # binary op
      exprCheck("5 || 42", "ooL5EL42E")
      exprCheck("5 or 42", "ooL5EL42E")
      exprCheck("5 && 42", "aaL5EL42E")
      exprCheck("5 and 42", "aaL5EL42E")
      exprCheck("5 | 42", "orL5EL42E")
      exprCheck("5 bitor 42", "orL5EL42E")
      exprCheck("5 ^ 42", "eoL5EL42E")
      exprCheck("5 xor 42", "eoL5EL42E")
      exprCheck("5 & 42", "anL5EL42E")
      exprCheck("5 bitand 42", "anL5EL42E")
      # ['==', '!=']
      exprCheck("5 == 42", "eqL5EL42E")
      exprCheck("5 != 42", "neL5EL42E")
      exprCheck("5 not_eq 42", "neL5EL42E")
      # ['<=', '>=', '<', '>', '<=>']
      exprCheck("5 <= 42", "leL5EL42E")
      exprCheck("A <= 42", "le1AL42E")
      exprCheck("5 >= 42", "geL5EL42E")
      exprCheck("5 < 42", "ltL5EL42E")
      exprCheck("A < 42", "lt1AL42E")
      exprCheck("5 > 42", "gtL5EL42E")
      exprCheck("A > 42", "gt1AL42E")
      exprCheck("5 <=> 42", "ssL5EL42E")
      exprCheck("A <=> 42", "ss1AL42E")
      # ['<<', '>>']
      exprCheck("5 << 42", "lsL5EL42E")
      exprCheck("A << 42", "ls1AL42E")
      exprCheck("5 >> 42", "rsL5EL42E")
      # ['+', '-']
      exprCheck("5 + 42", "plL5EL42E")
      exprCheck("5 - 42", "miL5EL42E")
      # ['*', '/', '%']
      exprCheck("5 * 42", "mlL5EL42E")
      exprCheck("5 / 42", "dvL5EL42E")
      exprCheck("5 % 42", "rmL5EL42E")
      # ['.*', '->*']
      exprCheck("5 .* 42", "dsL5EL42E")
      exprCheck("5 ->* 42", "pmL5EL42E")
      # conditional
      exprCheck("5 ? 7 : 3", "quL5EL7EL3E")
      # assignment
      exprCheck("a = 5", "aS1aL5E")
      exprCheck("a *= 5", "mL1aL5E")
      exprCheck("a /= 5", "dV1aL5E")
      exprCheck("a %= 5", "rM1aL5E")
      exprCheck("a += 5", "pL1aL5E")
      exprCheck("a -= 5", "mI1aL5E")
      exprCheck("a >>= 5", "rS1aL5E")
      exprCheck("a <<= 5", "lS1aL5E")
      exprCheck("a &= 5", "aN1aL5E")
      exprCheck("a and_eq 5", "aN1aL5E")
      exprCheck("a ^= 5", "eO1aL5E")
      exprCheck("a xor_eq 5", "eO1aL5E")
      exprCheck("a |= 5", "oR1aL5E")
      exprCheck("a or_eq 5", "oR1aL5E")
      exprCheck("a = {{1, 2, 3}}", "aS1ailL1EL2EL3EE")
      # complex assignment and conditional
      exprCheck("5 = 6 = 7", "aSL5EaSL6EL7E")
      exprCheck("5 = 6 ? 7 = 8 : 3", "aSL5EquL6EaSL7EL8EL3E")
      # comma operator
      exprCheck("a, 5", "cm1aL5E")
  
      # Additional tests
      # a < expression that starts with something that could be a template
      exprCheck("A < 42", "lt1AL42E")
      check(
          "function",
          "template<> void f(A<B, 2> &v)",
          {
              2: "IE1fR1AI1BX2EE",
              3: "IE1fR1AI1BXL2EEE",
              4: "IE1fvR1AI1BXL2EEE",
          },
      )
      exprCheck("A<1>::value", "N1AIXL1EEE5valueE")
      check("class", "template<int T = 42> {key}A", {2: "I_iE1A"})
      check(
          "enumerator",
          "{key}A = std::numeric_limits<unsigned long>::max()",
          {2: "1A"},
      )
  
      exprCheck("operator()()", "clclE")
      exprCheck("operator()<int>()", "clclIiEE")
  
      # pack expansion
      exprCheck(
          "a(b(c, 1 + d...)..., e(f..., g))",
          "cl1aspcl1b1cspplL1E1dEcl1esp1f1gEE",
      )
  
imports: import itertools
  import re
  import zlib
  import pytest
  import sphinx.domains.cpp
  from sphinx import addnodes
  from sphinx.addnodes import desc, desc_content, desc_name, desc_parameter, desc_parameterlist, desc_sig_name, desc_sig_space, desc_signature, desc_signature_line, pending_xref
  from sphinx.domains.cpp import DefinitionError, DefinitionParser, NoOldIdError, Symbol, _id_prefix, _max_id
  from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
  from sphinx.testing import restructuredtext
  from sphinx.testing.util import assert_node
  from sphinx.writers.text import STDINDENT
label_desc: Use image node_id 5 for calling a global function with example usage: test_domain_cpp_ast_expressions() without return types