[
  {
    "path": ".github/workflows/analysis.yml",
    "content": "name: Analysis\n\non:\n  push:\n    paths-ignore:\n      - 'doc/**'\n    branches: [ main ]\n  pull_request:\n    paths-ignore:\n      - 'doc/**'\n    branches: [ main ]\n\njobs:\n  build:\n    name: Microsoft C++ Code Analysis\n    runs-on: windows-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        config: [Release]\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install MSVC Build Tools Preview\n        shell: pwsh\n        run: |\n          $url = \"https://aka.ms/vs/18/insiders/vs_buildtools.exe\"\n          Invoke-WebRequest -Uri $url -OutFile \"$env:TEMP\\vs_buildtools.exe\" -UseBasicParsing\n          $process = Start-Process -Wait -PassThru -FilePath \"$env:TEMP\\vs_buildtools.exe\" `\n            -ArgumentList \"--quiet  --wait --norestart --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.26100 --add Microsoft.VisualStudio.Component.VC.CMake.Project --includeRecommended\"\n          $exitCode = $process.ExitCode\n          Write-Output \"VS installer exit code: $exitCode\"\n          if ($exitCode -notin 0,3010,3015) { throw \"VS Installer failed: $exitCode\" }\n\n      - name: Set up MSVC environment\n        uses: ilammy/msvc-dev-cmd@v1\n        with:\n          vsversion: '18'\n\n      - name: Configure\n        shell: pwsh\n        run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.config }}\n\n      - name: Build\n        shell: pwsh\n        run: cmake --build build\n\n      - name: Run Microsoft Visual C++ Analysis\n        id: run-analysis\n        uses: gdr-at-ms/msvc-code-analysis-action@support-cxx-modules\n        with:\n          cmakeBuildDirectory: build\n          buildConfiguration: ${{ matrix.config }}\n          ignoredTargetPaths: ${{ github.workspace }}/tests\n          ruleset: '${{ github.workspace }}/infra/Analysis.ruleset'\n\n      - name: Upload SARIF as an Artifact\n        uses: actions/upload-artifact@v4\n        with:\n          name: sarif-file\n          path: ${{ steps.run-analysis.outputs.sarif }}\n          if-no-files-found: error\n\n      - name: Upload SARIF to GitHub\n        uses: github/codeql-action/upload-sarif@v4\n        with:\n          sarif_file: ${{ steps.run-analysis.outputs.sarif }}\n"
  },
  {
    "path": ".github/workflows/docs.yaml",
    "content": "name: Docs\n\non:\n  push:\n    paths:\n      - 'doc/**'\n      - '.github/workflows/docs.yaml'\n    branches: [ main ]\n  pull_request:\n    paths:\n      - 'doc/**'\n      - '.github/workflows/docs.yaml'\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    name: Build Ubuntu\n\n    steps:\n    - uses: actions/checkout@v2\n\n    - name: Install GCC, CMake\n      run: |\n        # https://github.com/actions/runner-images/issues/7192\n        echo 'APT::Get::Always-Include-Phased-Updates \"false\";' | sudo tee /etc/apt/apt.conf.d/99-phased-updates\n        sudo apt-get update && sudo apt-get -y upgrade --fix-missing\n        sudo apt-get install build-essential cmake texlive texlive-latex-extra\n\n    - name: Configure & Build CMake\n      uses: lukka/run-cmake@v3\n      with:\n        buildDirectory: build\n        cmakeAppendedArgs: -DBUILD_DOC=ON\n        cmakeListsOrSettingsJson: CMakeListsTxtAdvanced\n        buildWithCMakeArgs: --target doc\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: Build & Test\n\non:\n  push:\n    paths-ignore:\n      - 'doc/**'\n    branches: [ main ]\n  pull_request:\n    paths-ignore:\n      - 'doc/**'\n    branches: [ main ]\n\njobs:\n  # For linux runners\n  build-on-linux:\n    name: Linux -x- ${{ matrix.name }} -x- ${{ matrix.config }}\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        config: [Debug, Release]\n        name: [gcc-15, clang-21-libstdc++, clang-21-libc++]\n        include:\n          - name: gcc-15\n            compiler: g++-15\n            install: |\n              sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test\n              sudo apt-get update\n              sudo apt-get install -y g++-15\n            cmake_extra: \"\"\n          - name: clang-21-libstdc++\n            compiler: clang++-21\n            install: |\n              wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc\n              sudo add-apt-repository -y \"deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-21 main\"\n              sudo apt-get update\n              sudo apt-get install -y clang-21\n            cmake_extra: \"\"\n          - name: clang-21-libc++\n            compiler: clang++-21\n            install: |\n              wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc\n              sudo add-apt-repository -y \"deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-21 main\"\n              sudo apt-get update\n              sudo apt-get install -y clang-21 libc++-21-dev libc++abi-21-dev\n            cmake_extra: \"-DCMAKE_CXX_FLAGS=-stdlib=libc++\"\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install C++ compilers and tools\n        run: |\n          # https://github.com/actions/runner-images/issues/7192\n          echo 'APT::Get::Always-Include-Phased-Updates \"false\";' | sudo tee /etc/apt/apt.conf.d/99-phased-updates\n          sudo apt-get update && sudo apt-get -y upgrade --fix-missing\n          sudo apt-get install -y build-essential cmake ninja-build\n          ${{ matrix.install }}\n\n      - name: Configure\n        run: >\n          cmake -S . -B build -G Ninja\n          -DCMAKE_CXX_COMPILER=${{ matrix.compiler }}\n          -DCMAKE_BUILD_TYPE=${{ matrix.config }}\n          ${{ matrix.cmake_extra }}\n\n      - name: Build\n        run: cmake --build build --parallel --config ${{ matrix.config }}\n\n      - name: Test\n        run: ctest --test-dir build --output-on-failure\n\n  # For macOS runners\n  build-on-macos:\n    name: macOS -x- Clang (Homebrew) -x- ${{ matrix.config }}\n    runs-on: macos-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        config: [Debug, Release]\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install LLVM and CMake\n        run: |\n          brew install llvm cmake ninja\n          echo \"$(brew --prefix llvm)/bin\" >> $GITHUB_PATH\n\n      - name: Configure\n        run: >\n          cmake -S . -B build -G Ninja\n          -DCMAKE_CXX_COMPILER=$(brew --prefix llvm)/bin/clang++\n          -DCMAKE_OSX_SYSROOT=$(xcrun --show-sdk-path)\n          -DCMAKE_BUILD_TYPE=${{ matrix.config }}\n\n      - name: Build\n        run: cmake --build build --parallel --config ${{ matrix.config }}\n\n      - name: Test\n        run: ctest --test-dir build --output-on-failure\n\n  # For Windows runners\n  build-on-windows:\n    name: Windows -x- MSVC Preview -x- ${{ matrix.config }}\n    runs-on: windows-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        config: [Debug, Release]\n            \n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install MSVC Build Tools Preview\n        shell: pwsh\n        run: |\n          $url = \"https://aka.ms/vs/18/insiders/vs_buildtools.exe\"\n          Invoke-WebRequest -Uri $url -OutFile \"$env:TEMP\\vs_buildtools.exe\" -UseBasicParsing\n          $process = Start-Process -Wait -PassThru -FilePath \"$env:TEMP\\vs_buildtools.exe\" `\n            -ArgumentList \"--quiet  --wait --norestart --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.26100 --add Microsoft.VisualStudio.Component.VC.CMake.Project --includeRecommended\"\n          $exitCode = $process.ExitCode\n          Write-Output \"VS installer exit code: $exitCode\"\n          if ($exitCode -notin 0,3010,3015) { throw \"VS Installer failed: $exitCode\" }\n\n      - name: Set up MSVC environment\n        uses: ilammy/msvc-dev-cmd@v1\n        with:\n          vsversion: '18'\n\n      - name: Configure\n        shell: pwsh\n        run: >\n          cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.config }}\n\n      - name: Build\n        shell: pwsh\n        run: cmake --build build --parallel --config ${{ matrix.config }}\n\n      - name: Test\n        shell: pwsh\n        run: ctest --test-dir build --output-on-failure\n"
  },
  {
    "path": ".gitignore",
    "content": ".vscode/\n.vs/\nbuild/\n"
  },
  {
    "path": "3rdparty/doctest/doctest.h",
    "content": "// ====================================================================== lgtm [cpp/missing-header-guard]\n// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! ==\n// ======================================================================\n//\n// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD\n//\n// Copyright (c) 2016-2021 Viktor Kirilov\n//\n// Distributed under the MIT Software License\n// See accompanying file LICENSE.txt or copy at\n// https://opensource.org/licenses/MIT\n//\n// The documentation can be found at the library's page:\n// https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md\n//\n// =================================================================================================\n// =================================================================================================\n// =================================================================================================\n//\n// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2\n// which uses the Boost Software License - Version 1.0\n// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt\n//\n// The concept of subcases (sections in Catch) and expression decomposition are from there.\n// Some parts of the code are taken directly:\n// - stringification - the detection of \"ostream& operator<<(ostream&, const T&)\" and StringMaker<>\n// - the Approx() helper class for floating point comparison\n// - colors in the console\n// - breaking into a debugger\n// - signal / SEH handling\n// - timer\n// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste)\n//\n// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest\n// which uses the Boost Software License - Version 1.0\n// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt\n//\n// =================================================================================================\n// =================================================================================================\n// =================================================================================================\n\n#ifndef DOCTEST_LIBRARY_INCLUDED\n#define DOCTEST_LIBRARY_INCLUDED\n\n// =================================================================================================\n// == VERSION ======================================================================================\n// =================================================================================================\n\n#define DOCTEST_VERSION_MAJOR 2\n#define DOCTEST_VERSION_MINOR 4\n#define DOCTEST_VERSION_PATCH 8\n\n// util we need here\n#define DOCTEST_TOSTR_IMPL(x) #x\n#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x)\n\n#define DOCTEST_VERSION_STR                                                                        \\\n    DOCTEST_TOSTR(DOCTEST_VERSION_MAJOR) \".\"                                                       \\\n    DOCTEST_TOSTR(DOCTEST_VERSION_MINOR) \".\"                                                       \\\n    DOCTEST_TOSTR(DOCTEST_VERSION_PATCH)\n\n#define DOCTEST_VERSION                                                                            \\\n    (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH)\n\n// =================================================================================================\n// == COMPILER VERSION =============================================================================\n// =================================================================================================\n\n// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect\n\n#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH))\n\n// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl...\n#if defined(_MSC_VER) && defined(_MSC_FULL_VER)\n#if _MSC_VER == _MSC_FULL_VER / 10000\n#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000)\n#else // MSVC\n#define DOCTEST_MSVC                                                                               \\\n    DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000)\n#endif // MSVC\n#endif // MSVC\n#if defined(__clang__) && defined(__clang_minor__)\n#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__)\n#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) &&              \\\n        !defined(__INTEL_COMPILER)\n#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#endif // GCC\n\n#ifndef DOCTEST_MSVC\n#define DOCTEST_MSVC 0\n#endif // DOCTEST_MSVC\n#ifndef DOCTEST_CLANG\n#define DOCTEST_CLANG 0\n#endif // DOCTEST_CLANG\n#ifndef DOCTEST_GCC\n#define DOCTEST_GCC 0\n#endif // DOCTEST_GCC\n\n// =================================================================================================\n// == COMPILER WARNINGS HELPERS ====================================================================\n// =================================================================================================\n\n#if DOCTEST_CLANG\n#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x)\n#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma(\"clang diagnostic push\")\n#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w)\n#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma(\"clang diagnostic pop\")\n#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w)                                                \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w)\n#else // DOCTEST_CLANG\n#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH\n#define DOCTEST_CLANG_SUPPRESS_WARNING(w)\n#define DOCTEST_CLANG_SUPPRESS_WARNING_POP\n#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w)\n#endif // DOCTEST_CLANG\n\n#if DOCTEST_GCC\n#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x)\n#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma(\"GCC diagnostic push\")\n#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w)\n#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma(\"GCC diagnostic pop\")\n#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w)                                                  \\\n    DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w)\n#else // DOCTEST_GCC\n#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH\n#define DOCTEST_GCC_SUPPRESS_WARNING(w)\n#define DOCTEST_GCC_SUPPRESS_WARNING_POP\n#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w)\n#endif // DOCTEST_GCC\n\n#if DOCTEST_MSVC\n#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push))\n#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w))\n#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop))\n#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w)                                                 \\\n    DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w)\n#else // DOCTEST_MSVC\n#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH\n#define DOCTEST_MSVC_SUPPRESS_WARNING(w)\n#define DOCTEST_MSVC_SUPPRESS_WARNING_POP\n#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w)\n#endif // DOCTEST_MSVC\n\n// =================================================================================================\n// == COMPILER WARNINGS ============================================================================\n// =================================================================================================\n\n// both the header and the implementation suppress all of these,\n// so it only makes sense to aggregrate them like so\n#define DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH                                                      \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_PUSH                                                            \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wunknown-pragmas\")                                            \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wweak-vtables\")                                               \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wpadded\")                                                     \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wmissing-prototypes\")                                         \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wunused-local-typedef\")                                       \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wc++98-compat\")                                               \\\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wc++98-compat-pedantic\")                                      \\\n                                                                                                   \\\n    DOCTEST_GCC_SUPPRESS_WARNING_PUSH                                                              \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wunknown-pragmas\")                                              \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wpragmas\")                                                      \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Weffc++\")                                                       \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wstrict-overflow\")                                              \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wstrict-aliasing\")                                              \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wmissing-declarations\")                                         \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wunused-local-typedefs\")                                        \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wuseless-cast\")                                                 \\\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wnoexcept\")                                                     \\\n                                                                                                   \\\n    DOCTEST_MSVC_SUPPRESS_WARNING_PUSH                                                             \\\n    /* these 4 also disabled globally via cmake: */                                                \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4514) /* unreferenced inline function has been removed */        \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4571) /* SEH related */                                          \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */                                 \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/                \\\n    /* */                                                                                          \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */                             \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */                             \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */    \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4706) /* assignment within conditional expression */             \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4512) /* 'class' : assignment operator could not be generated */ \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4127) /* conditional expression is constant */                   \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */                                              \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */              \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */           \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */          \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */              \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */  \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */                   \\\n    /* static analysis */                                                                          \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */       \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */                 \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(26451) /* Arithmetic overflow ... */                             \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(26444) /* Avoid unnamed objects with custom ctor and dtor... */  \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(26812) /* Prefer 'enum class' over 'enum' */\n\n#define DOCTEST_SUPPRESS_COMMON_WARNINGS_POP                                                       \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP                                                             \\\n    DOCTEST_GCC_SUPPRESS_WARNING_POP                                                               \\\n    DOCTEST_MSVC_SUPPRESS_WARNING_POP\n\nDOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH\n\nDOCTEST_CLANG_SUPPRESS_WARNING_PUSH\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wnon-virtual-dtor\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wdeprecated\")\n\nDOCTEST_GCC_SUPPRESS_WARNING_PUSH\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wctor-dtor-privacy\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wnon-virtual-dtor\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wsign-promo\")\n\nDOCTEST_MSVC_SUPPRESS_WARNING_PUSH\nDOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted\n\n#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN                                 \\\n    DOCTEST_MSVC_SUPPRESS_WARNING_PUSH                                                             \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4548) /* before comma no effect; expected side - effect */       \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4265) /* virtual functions, but destructor is not virtual */     \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4986) /* exception specification does not match previous */      \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4350) /* 'member1' called instead of 'member2' */                \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4668) /* not defined as a preprocessor macro */                  \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */                             \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4774) /* format string not a string literal */                   \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */                                              \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */              \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */           \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */          \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */              \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */           \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */                   \\\n    DOCTEST_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */\n\n#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP\n\n// =================================================================================================\n// == FEATURE DETECTION ============================================================================\n// =================================================================================================\n\n// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support\n// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx\n// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html\n// MSVC version table:\n// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering\n// MSVC++ 14.3 (17) _MSC_VER == 1930 (Visual Studio 2022)\n// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019)\n// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017)\n// MSVC++ 14.0      _MSC_VER == 1900 (Visual Studio 2015)\n// MSVC++ 12.0      _MSC_VER == 1800 (Visual Studio 2013)\n// MSVC++ 11.0      _MSC_VER == 1700 (Visual Studio 2012)\n// MSVC++ 10.0      _MSC_VER == 1600 (Visual Studio 2010)\n// MSVC++ 9.0       _MSC_VER == 1500 (Visual Studio 2008)\n// MSVC++ 8.0       _MSC_VER == 1400 (Visual Studio 2005)\n\n// Universal Windows Platform support\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)\n#define DOCTEST_CONFIG_NO_WINDOWS_SEH\n#endif // WINAPI_FAMILY\n#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH)\n#define DOCTEST_CONFIG_WINDOWS_SEH\n#endif // MSVC\n#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH)\n#undef DOCTEST_CONFIG_WINDOWS_SEH\n#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH\n\n#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) &&             \\\n        !defined(__EMSCRIPTEN__)\n#define DOCTEST_CONFIG_POSIX_SIGNALS\n#endif // _WIN32\n#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS)\n#undef DOCTEST_CONFIG_POSIX_SIGNALS\n#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS\n\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)\n#define DOCTEST_CONFIG_NO_EXCEPTIONS\n#endif // no exceptions\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n\n#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n#define DOCTEST_CONFIG_NO_EXCEPTIONS\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS\n\n#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS)\n#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS\n\n#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT)\n#define DOCTEST_CONFIG_IMPLEMENT\n#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\n\n#if defined(_WIN32) || defined(__CYGWIN__)\n#if DOCTEST_MSVC\n#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport)\n#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport)\n#else // MSVC\n#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport))\n#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport))\n#endif // MSVC\n#else  // _WIN32\n#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility(\"default\")))\n#define DOCTEST_SYMBOL_IMPORT\n#endif // _WIN32\n\n#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL\n#ifdef DOCTEST_CONFIG_IMPLEMENT\n#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT\n#else // DOCTEST_CONFIG_IMPLEMENT\n#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT\n#endif // DOCTEST_CONFIG_IMPLEMENT\n#else  // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL\n#define DOCTEST_INTERFACE\n#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL\n\n#define DOCTEST_EMPTY\n\n#if DOCTEST_MSVC\n#define DOCTEST_NOINLINE __declspec(noinline)\n#define DOCTEST_UNUSED\n#define DOCTEST_ALIGNMENT(x)\n#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0)\n#define DOCTEST_NOINLINE\n#define DOCTEST_UNUSED\n#define DOCTEST_ALIGNMENT(x)\n#else\n#define DOCTEST_NOINLINE __attribute__((noinline))\n#define DOCTEST_UNUSED __attribute__((unused))\n#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x)))\n#endif\n\n#ifndef DOCTEST_NORETURN\n#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))\n#define DOCTEST_NORETURN\n#else // DOCTEST_MSVC\n#define DOCTEST_NORETURN [[noreturn]]\n#endif // DOCTEST_MSVC\n#endif // DOCTEST_NORETURN\n\n#ifndef DOCTEST_NOEXCEPT\n#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))\n#define DOCTEST_NOEXCEPT\n#else // DOCTEST_MSVC\n#define DOCTEST_NOEXCEPT noexcept\n#endif // DOCTEST_MSVC\n#endif // DOCTEST_NOEXCEPT\n\n#ifndef DOCTEST_CONSTEXPR\n#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))\n#define DOCTEST_CONSTEXPR const\n#else // DOCTEST_MSVC\n#define DOCTEST_CONSTEXPR constexpr\n#endif // DOCTEST_MSVC\n#endif // DOCTEST_CONSTEXPR\n\n// =================================================================================================\n// == FEATURE DETECTION END ========================================================================\n// =================================================================================================\n\n// internal macros for string concatenation and anonymous variable name generation\n#define DOCTEST_CAT_IMPL(s1, s2) s1##s2\n#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2)\n#ifdef __COUNTER__ // not standard and may be missing for some compilers\n#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__)\n#else // __COUNTER__\n#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__)\n#endif // __COUNTER__\n\n#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE\n#define DOCTEST_REF_WRAP(x) x&\n#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE\n#define DOCTEST_REF_WRAP(x) x\n#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE\n\n// not using __APPLE__ because... this is how Catch does it\n#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED\n#define DOCTEST_PLATFORM_MAC\n#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)\n#define DOCTEST_PLATFORM_IPHONE\n#elif defined(_WIN32)\n#define DOCTEST_PLATFORM_WINDOWS\n#else // DOCTEST_PLATFORM\n#define DOCTEST_PLATFORM_LINUX\n#endif // DOCTEST_PLATFORM\n\nnamespace doctest { namespace detail {\n    static DOCTEST_CONSTEXPR int consume(const int*, int) { return 0; }\n}}\n\n#define DOCTEST_GLOBAL_NO_WARNINGS(var, ...)                                                       \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wglobal-constructors\")                              \\\n    static const int var = doctest::detail::consume(&var, __VA_ARGS__);                            \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n\n#ifndef DOCTEST_BREAK_INTO_DEBUGGER\n// should probably take a look at https://github.com/scottt/debugbreak\n#ifdef DOCTEST_PLATFORM_LINUX\n#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))\n// Break at the location of the failing check if possible\n#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__(\"int $3\\n\" : :) // NOLINT (hicpp-no-assembler)\n#else\n#include <signal.h>\n#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP)\n#endif\n#elif defined(DOCTEST_PLATFORM_MAC)\n#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386)\n#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__(\"int $3\\n\" : :) // NOLINT (hicpp-no-assembler)\n#else\n#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__(\"brk #0\"); // NOLINT (hicpp-no-assembler)\n#endif\n#elif DOCTEST_MSVC\n#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak()\n#elif defined(__MINGW32__)\nDOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wredundant-decls\")\nextern \"C\" __declspec(dllimport) void __stdcall DebugBreak();\nDOCTEST_GCC_SUPPRESS_WARNING_POP\n#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak()\n#else // linux\n#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast<void>(0))\n#endif // linux\n#endif // DOCTEST_BREAK_INTO_DEBUGGER\n\n// this is kept here for backwards compatibility since the config option was changed\n#ifdef DOCTEST_CONFIG_USE_IOSFWD\n#define DOCTEST_CONFIG_USE_STD_HEADERS\n#endif // DOCTEST_CONFIG_USE_IOSFWD\n\n// for clang - always include ciso646 (which drags some std stuff) because\n// we want to check if we are using libc++ with the _LIBCPP_VERSION macro in\n// which case we don't want to forward declare stuff from std - for reference:\n// https://github.com/doctest/doctest/issues/126\n// https://github.com/doctest/doctest/issues/356\n#if DOCTEST_CLANG\n#include <ciso646>\n#ifdef _LIBCPP_VERSION\n#define DOCTEST_CONFIG_USE_STD_HEADERS\n#endif // _LIBCPP_VERSION\n#endif // clang\n\n#ifdef DOCTEST_CONFIG_USE_STD_HEADERS\n#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n#include <cstddef>\n#include <ostream>\n#include <istream>\n#else // DOCTEST_CONFIG_USE_STD_HEADERS\n\n// Forward declaring 'X' in namespace std is not permitted by the C++ Standard.\nDOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643)\n\nnamespace std { // NOLINT (cert-dcl58-cpp)\ntypedef decltype(nullptr) nullptr_t;\ntemplate <class charT>\nstruct char_traits;\ntemplate <>\nstruct char_traits<char>;\ntemplate <class charT, class traits>\nclass basic_ostream;\ntypedef basic_ostream<char, char_traits<char>> ostream;\ntemplate <class charT, class traits>\nclass basic_istream;\ntypedef basic_istream<char, char_traits<char>> istream;\ntemplate <class... Types>\nclass tuple;\n#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)\n// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183\ntemplate <class Ty>\nclass allocator;\ntemplate <class Elem, class Traits, class Alloc>\nclass basic_string;\nusing string = basic_string<char, char_traits<char>, allocator<char>>;\n#endif // VS 2019\n} // namespace std\n\nDOCTEST_MSVC_SUPPRESS_WARNING_POP\n\n#endif // DOCTEST_CONFIG_USE_STD_HEADERS\n\n#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n#include <type_traits>\n#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n\nnamespace doctest {\n\nDOCTEST_INTERFACE extern bool is_running_in_test;\n\n// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length\n// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for:\n// - \"is small\" bit - the highest bit - if \"0\" then it is small - otherwise its \"1\" (128)\n// - if small - capacity left before going on the heap - using the lowest 5 bits\n// - if small - 2 bits are left unused - the second and third highest ones\n// - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator)\n//              and the \"is small\" bit remains \"0\" (\"as well as the capacity left\") so its OK\n// Idea taken from this lecture about the string implementation of facebook/folly - fbstring\n// https://www.youtube.com/watch?v=kPR8h4-qZdk\n// TODO:\n// - optimizations - like not deleting memory unnecessarily in operator= and etc.\n// - resize/reserve/clear\n// - substr\n// - replace\n// - back/front\n// - iterator stuff\n// - find & friends\n// - push_back/pop_back\n// - assign/insert/erase\n// - relational operators as free functions - taking const char* as one of the params\nclass DOCTEST_INTERFACE String\n{\n    static const unsigned len  = 24;      //!OCLINT avoid private static members\n    static const unsigned last = len - 1; //!OCLINT avoid private static members\n\n    struct view // len should be more than sizeof(view) - because of the final byte for flags\n    {\n        char*    ptr;\n        unsigned size;\n        unsigned capacity;\n    };\n\n    union\n    {\n        char buf[len];\n        view data;\n    };\n\n    char* allocate(unsigned sz);\n\n    bool isOnStack() const { return (buf[last] & 128) == 0; }\n    void setOnHeap();\n    void setLast(unsigned in = last);\n\n    void copy(const String& other);\n\npublic:\n    String();\n    ~String();\n\n    // cppcheck-suppress noExplicitConstructor\n    String(const char* in);\n    String(const char* in, unsigned in_size);\n\n    String(std::istream& in, unsigned in_size);\n\n    String(const String& other);\n    String& operator=(const String& other);\n\n    String& operator+=(const String& other);\n\n    String(String&& other);\n    String& operator=(String&& other);\n\n    char  operator[](unsigned i) const;\n    char& operator[](unsigned i);\n\n    // the only functions I'm willing to leave in the interface - available for inlining\n    const char* c_str() const { return const_cast<String*>(this)->c_str(); } // NOLINT\n    char*       c_str() {\n        if(isOnStack())\n            return reinterpret_cast<char*>(buf);\n        return data.ptr;\n    }\n\n    unsigned size() const;\n    unsigned capacity() const;\n\n    int compare(const char* other, bool no_case = false) const;\n    int compare(const String& other, bool no_case = false) const;\n};\n\nDOCTEST_INTERFACE String operator+(const String& lhs, const String& rhs);\n\nDOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs);\nDOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs);\nDOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs);\nDOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs);\nDOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs);\nDOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs);\n\nDOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in);\n\nnamespace Color {\n    enum Enum\n    {\n        None = 0,\n        White,\n        Red,\n        Green,\n        Blue,\n        Cyan,\n        Yellow,\n        Grey,\n\n        Bright = 0x10,\n\n        BrightRed   = Bright | Red,\n        BrightGreen = Bright | Green,\n        LightGrey   = Bright | Grey,\n        BrightWhite = Bright | White\n    };\n\n    DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code);\n} // namespace Color\n\nnamespace assertType {\n    enum Enum\n    {\n        // macro traits\n\n        is_warn    = 1,\n        is_check   = 2 * is_warn,\n        is_require = 2 * is_check,\n\n        is_normal      = 2 * is_require,\n        is_throws      = 2 * is_normal,\n        is_throws_as   = 2 * is_throws,\n        is_throws_with = 2 * is_throws_as,\n        is_nothrow     = 2 * is_throws_with,\n\n        is_false = 2 * is_nothrow,\n        is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types\n\n        is_eq = 2 * is_unary,\n        is_ne = 2 * is_eq,\n\n        is_lt = 2 * is_ne,\n        is_gt = 2 * is_lt,\n\n        is_ge = 2 * is_gt,\n        is_le = 2 * is_ge,\n\n        // macro types\n\n        DT_WARN    = is_normal | is_warn,\n        DT_CHECK   = is_normal | is_check,\n        DT_REQUIRE = is_normal | is_require,\n\n        DT_WARN_FALSE    = is_normal | is_false | is_warn,\n        DT_CHECK_FALSE   = is_normal | is_false | is_check,\n        DT_REQUIRE_FALSE = is_normal | is_false | is_require,\n\n        DT_WARN_THROWS    = is_throws | is_warn,\n        DT_CHECK_THROWS   = is_throws | is_check,\n        DT_REQUIRE_THROWS = is_throws | is_require,\n\n        DT_WARN_THROWS_AS    = is_throws_as | is_warn,\n        DT_CHECK_THROWS_AS   = is_throws_as | is_check,\n        DT_REQUIRE_THROWS_AS = is_throws_as | is_require,\n\n        DT_WARN_THROWS_WITH    = is_throws_with | is_warn,\n        DT_CHECK_THROWS_WITH   = is_throws_with | is_check,\n        DT_REQUIRE_THROWS_WITH = is_throws_with | is_require,\n        \n        DT_WARN_THROWS_WITH_AS    = is_throws_with | is_throws_as | is_warn,\n        DT_CHECK_THROWS_WITH_AS   = is_throws_with | is_throws_as | is_check,\n        DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require,\n\n        DT_WARN_NOTHROW    = is_nothrow | is_warn,\n        DT_CHECK_NOTHROW   = is_nothrow | is_check,\n        DT_REQUIRE_NOTHROW = is_nothrow | is_require,\n\n        DT_WARN_EQ    = is_normal | is_eq | is_warn,\n        DT_CHECK_EQ   = is_normal | is_eq | is_check,\n        DT_REQUIRE_EQ = is_normal | is_eq | is_require,\n\n        DT_WARN_NE    = is_normal | is_ne | is_warn,\n        DT_CHECK_NE   = is_normal | is_ne | is_check,\n        DT_REQUIRE_NE = is_normal | is_ne | is_require,\n\n        DT_WARN_GT    = is_normal | is_gt | is_warn,\n        DT_CHECK_GT   = is_normal | is_gt | is_check,\n        DT_REQUIRE_GT = is_normal | is_gt | is_require,\n\n        DT_WARN_LT    = is_normal | is_lt | is_warn,\n        DT_CHECK_LT   = is_normal | is_lt | is_check,\n        DT_REQUIRE_LT = is_normal | is_lt | is_require,\n\n        DT_WARN_GE    = is_normal | is_ge | is_warn,\n        DT_CHECK_GE   = is_normal | is_ge | is_check,\n        DT_REQUIRE_GE = is_normal | is_ge | is_require,\n\n        DT_WARN_LE    = is_normal | is_le | is_warn,\n        DT_CHECK_LE   = is_normal | is_le | is_check,\n        DT_REQUIRE_LE = is_normal | is_le | is_require,\n\n        DT_WARN_UNARY    = is_normal | is_unary | is_warn,\n        DT_CHECK_UNARY   = is_normal | is_unary | is_check,\n        DT_REQUIRE_UNARY = is_normal | is_unary | is_require,\n\n        DT_WARN_UNARY_FALSE    = is_normal | is_false | is_unary | is_warn,\n        DT_CHECK_UNARY_FALSE   = is_normal | is_false | is_unary | is_check,\n        DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require,\n    };\n} // namespace assertType\n\nDOCTEST_INTERFACE const char* assertString(assertType::Enum at);\nDOCTEST_INTERFACE const char* failureString(assertType::Enum at);\nDOCTEST_INTERFACE const char* skipPathFromFilename(const char* file);\n\nstruct DOCTEST_INTERFACE TestCaseData\n{\n    String      m_file;       // the file in which the test was registered (using String - see #350)\n    unsigned    m_line;       // the line where the test was registered\n    const char* m_name;       // name of the test case\n    const char* m_test_suite; // the test suite in which the test was added\n    const char* m_description;\n    bool        m_skip;\n    bool        m_no_breaks;\n    bool        m_no_output;\n    bool        m_may_fail;\n    bool        m_should_fail;\n    int         m_expected_failures;\n    double      m_timeout;\n};\n\nstruct DOCTEST_INTERFACE AssertData\n{\n    // common - for all asserts\n    const TestCaseData* m_test_case;\n    assertType::Enum    m_at;\n    const char*         m_file;\n    int                 m_line;\n    const char*         m_expr;\n    bool                m_failed;\n\n    // exception-related - for all asserts\n    bool   m_threw;\n    String m_exception;\n\n    // for normal asserts\n    String m_decomp;\n\n    // for specific exception-related asserts\n    bool        m_threw_as;\n    const char* m_exception_type;\n    const char* m_exception_string;\n};\n\nstruct DOCTEST_INTERFACE MessageData\n{\n    String           m_string;\n    const char*      m_file;\n    int              m_line;\n    assertType::Enum m_severity;\n};\n\nstruct DOCTEST_INTERFACE SubcaseSignature\n{\n    String      m_name;\n    const char* m_file;\n    int         m_line;\n\n    bool operator<(const SubcaseSignature& other) const;\n};\n\nstruct DOCTEST_INTERFACE IContextScope\n{\n    IContextScope();\n    virtual ~IContextScope();\n    virtual void stringify(std::ostream*) const = 0;\n};\n\nnamespace detail {\n    struct DOCTEST_INTERFACE TestCase;\n} // namespace detail\n\nstruct ContextOptions //!OCLINT too many fields\n{\n    std::ostream* cout = nullptr; // stdout stream\n    String        binary_name;    // the test binary name\n\n    const detail::TestCase* currentTest = nullptr;\n\n    // == parameters from the command line\n    String   out;       // output filename\n    String   order_by;  // how tests should be ordered\n    unsigned rand_seed; // the seed for rand ordering\n\n    unsigned first; // the first (matching) test to be executed\n    unsigned last;  // the last (matching) test to be executed\n\n    int abort_after;           // stop tests after this many failed assertions\n    int subcase_filter_levels; // apply the subcase filters for the first N levels\n\n    bool success;              // include successful assertions in output\n    bool case_sensitive;       // if filtering should be case sensitive\n    bool exit;                 // if the program should be exited after the tests are ran/whatever\n    bool duration;             // print the time duration of each test case\n    bool minimal;              // minimal console output (only test failures)\n    bool quiet;                // no console output\n    bool no_throw;             // to skip exceptions-related assertion macros\n    bool no_exitcode;          // if the framework should return 0 as the exitcode\n    bool no_run;               // to not run the tests at all (can be done with an \"*\" exclude)\n    bool no_intro;             // to not print the intro of the framework\n    bool no_version;           // to not print the version of the framework\n    bool no_colors;            // if output to the console should be colorized\n    bool force_colors;         // forces the use of colors even when a tty cannot be detected\n    bool no_breaks;            // to not break into the debugger\n    bool no_skip;              // don't skip test cases which are marked to be skipped\n    bool gnu_file_line;        // if line numbers should be surrounded with :x: and not (x):\n    bool no_path_in_filenames; // if the path to files should be removed from the output\n    bool no_line_numbers;      // if source code line numbers should be omitted from the output\n    bool no_debug_output;      // no output in the debug console when a debugger is attached\n    bool no_skipped_summary;   // don't print \"skipped\" in the summary !!! UNDOCUMENTED !!!\n    bool no_time_in_output;    // omit any time/timestamps from output !!! UNDOCUMENTED !!!\n\n    bool help;             // to print the help\n    bool version;          // to print the version\n    bool count;            // if only the count of matching tests is to be retrieved\n    bool list_test_cases;  // to list all tests matching the filters\n    bool list_test_suites; // to list all suites matching the filters\n    bool list_reporters;   // lists all registered reporters\n};\n\nnamespace detail {\n    template <bool CONDITION, typename TYPE = void>\n    struct enable_if\n    {};\n\n    template <typename TYPE>\n    struct enable_if<true, TYPE>\n    { typedef TYPE type; };\n\n    // clang-format off\n    template<class T> struct remove_reference      { typedef T type; };\n    template<class T> struct remove_reference<T&>  { typedef T type; };\n    template<class T> struct remove_reference<T&&> { typedef T type; };\n\n    template<typename T, typename U = T&&> U declval(int); \n\n    template<typename T> T declval(long); \n\n    template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;\n\n    template<class T> struct is_lvalue_reference { const static bool value=false; };\n    template<class T> struct is_lvalue_reference<T&> { const static bool value=true; };\n\n    template<class T> struct is_rvalue_reference { const static bool value=false; };\n    template<class T> struct is_rvalue_reference<T&&> { const static bool value=true; };\n\n    template <class T>\n    inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT\n    {\n        return static_cast<T&&>(t);\n    }\n\n    template <class T>\n    inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT\n    {\n        static_assert(!is_lvalue_reference<T>::value,\n                        \"Can not forward an rvalue as an lvalue.\");\n        return static_cast<T&&>(t);\n    }\n\n    template<class T> struct remove_const          { typedef T type; };\n    template<class T> struct remove_const<const T> { typedef T type; };\n#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n    template<class T> struct is_enum : public std::is_enum<T> {};\n    template<class T> struct underlying_type : public std::underlying_type<T> {};\n#else\n    // Use compiler intrinsics\n    template<class T> struct is_enum { DOCTEST_CONSTEXPR static bool value = __is_enum(T); };\n    template<class T> struct underlying_type { typedef __underlying_type(T) type; };\n#endif\n    // clang-format on\n\n    template <typename T>\n    struct deferred_false\n    // cppcheck-suppress unusedStructMember\n    { static const bool value = false; };\n\n    namespace has_insertion_operator_impl {\n        std::ostream &os();\n        template<class T>\n        DOCTEST_REF_WRAP(T) val();\n\n        template<class, class = void>\n        struct check {\n            static DOCTEST_CONSTEXPR bool value = false;\n        };\n\n        template<class T>\n        struct check<T, decltype(os() << val<T>(), void())> {\n            static DOCTEST_CONSTEXPR bool value = true;\n        };\n    } // namespace has_insertion_operator_impl\n\n    template<class T>\n    using has_insertion_operator = has_insertion_operator_impl::check<const T>;\n\n    DOCTEST_INTERFACE std::ostream* tlssPush();\n    DOCTEST_INTERFACE String tlssPop();\n\n\n    template <bool C>\n    struct StringMakerBase\n    {\n        template <typename T>\n        static String convert(const DOCTEST_REF_WRAP(T)) {\n            return \"{?}\";\n        }\n    };\n\n    // Vector<int> and various type other than pointer or array.\n    template<typename T>\n    struct filldata\n    {\n        static void fill(std::ostream* stream, const T &in) {\n          *stream << in;\n        }\n    };\n\n    template<typename T,unsigned long N>\n    struct filldata<T[N]>\n    {\n        static void fill(std::ostream* stream, const T (&in)[N]) {\n            for (unsigned long i = 0; i < N; i++) {\n                *stream << in[i];\n            }\n        }\n    };\n\n    // Specialized since we don't want the terminating null byte!\n    template<unsigned long N>\n    struct filldata<const char[N]>\n    {\n        static void fill(std::ostream* stream, const char(&in)[N]) {\n            *stream << in;\n        }\n    };\n\n    template<typename T>\n    void filloss(std::ostream* stream, const T& in) {\n        filldata<T>::fill(stream, in);\n    }\n\n    template<typename T,unsigned long N>\n    void filloss(std::ostream* stream, const T (&in)[N]) {\n        // T[N], T(&)[N], T(&&)[N] have same behaviour.\n        // Hence remove reference.\n        filldata<typename remove_reference<decltype(in)>::type>::fill(stream, in);\n    }\n\n    template <>\n    struct StringMakerBase<true>\n    {\n        template <typename T>\n        static String convert(const DOCTEST_REF_WRAP(T) in) {\n            /* When parameter \"in\" is a null terminated const char* it works.\n             * When parameter \"in\" is a T arr[N] without '\\0' we can fill the\n             * stringstream with N objects (T=char).If in is char pointer *\n             * without '\\0' , it would cause segfault\n             * stepping over unaccessible memory.\n             */\n\n            std::ostream* stream = tlssPush();\n            filloss(stream, in);\n            return tlssPop();\n        }\n    };\n\n    DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size);\n\n    template <typename T>\n    String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) {\n        return rawMemoryToString(&object, sizeof(object));\n    }\n\n    template <typename T>\n    const char* type_to_string() {\n        return \"<>\";\n    }\n} // namespace detail\n\ntemplate <typename T>\nstruct StringMaker : public detail::StringMakerBase<detail::has_insertion_operator<T>::value>\n{};\n\ntemplate <typename T>\nstruct StringMaker<T*>\n{\n    template <typename U>\n    static String convert(U* p) {\n        if(p)\n            return detail::rawMemoryToString(p);\n        return \"NULL\";\n    }\n};\n\ntemplate <typename R, typename C>\nstruct StringMaker<R C::*>\n{\n    static String convert(R C::*p) {\n        if(p)\n            return detail::rawMemoryToString(p);\n        return \"NULL\";\n    }\n};\n\ntemplate <typename T, typename detail::enable_if<!detail::is_enum<T>::value, bool>::type = true>\nString toString(const DOCTEST_REF_WRAP(T) value) {\n    return StringMaker<T>::convert(value);\n}\n\n#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\nDOCTEST_INTERFACE String toString(char* in);\nDOCTEST_INTERFACE String toString(const char* in);\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\nDOCTEST_INTERFACE String toString(bool in);\nDOCTEST_INTERFACE String toString(float in);\nDOCTEST_INTERFACE String toString(double in);\nDOCTEST_INTERFACE String toString(double long in);\n\nDOCTEST_INTERFACE String toString(char in);\nDOCTEST_INTERFACE String toString(char signed in);\nDOCTEST_INTERFACE String toString(char unsigned in);\nDOCTEST_INTERFACE String toString(int short in);\nDOCTEST_INTERFACE String toString(int short unsigned in);\nDOCTEST_INTERFACE String toString(int in);\nDOCTEST_INTERFACE String toString(int unsigned in);\nDOCTEST_INTERFACE String toString(int long in);\nDOCTEST_INTERFACE String toString(int long unsigned in);\nDOCTEST_INTERFACE String toString(int long long in);\nDOCTEST_INTERFACE String toString(int long long unsigned in);\nDOCTEST_INTERFACE String toString(std::nullptr_t in);\n\ntemplate <typename T, typename detail::enable_if<detail::is_enum<T>::value, bool>::type = true>\nString toString(const DOCTEST_REF_WRAP(T) value) {\n    typedef typename detail::underlying_type<T>::type UT;\n    return toString(static_cast<UT>(value));\n}\n\n#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)\n// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183\nDOCTEST_INTERFACE String toString(const std::string& in);\n#endif // VS 2019\n\nclass DOCTEST_INTERFACE Approx\n{\npublic:\n    explicit Approx(double value);\n\n    Approx operator()(double value) const;\n\n#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n    template <typename T>\n    explicit Approx(const T& value,\n                    typename detail::enable_if<std::is_constructible<double, T>::value>::type* =\n                            static_cast<T*>(nullptr)) {\n        *this = Approx(static_cast<double>(value));\n    }\n#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n\n    Approx& epsilon(double newEpsilon);\n\n#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n    template <typename T>\n    typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type epsilon(\n            const T& newEpsilon) {\n        m_epsilon = static_cast<double>(newEpsilon);\n        return *this;\n    }\n#endif //  DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n\n    Approx& scale(double newScale);\n\n#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n    template <typename T>\n    typename detail::enable_if<std::is_constructible<double, T>::value, Approx&>::type scale(\n            const T& newScale) {\n        m_scale = static_cast<double>(newScale);\n        return *this;\n    }\n#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n\n    // clang-format off\n    DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs);\n    DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs);\n    DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs);\n    DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs);\n    DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs);\n    DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs);\n    DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs);\n    DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs);\n    DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs);\n    DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs);\n    DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs);\n    DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs);\n\n    DOCTEST_INTERFACE friend String toString(const Approx& in);\n\n#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n#define DOCTEST_APPROX_PREFIX \\\n    template <typename T> friend typename detail::enable_if<std::is_constructible<double, T>::value, bool>::type\n\n    DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); }\n    DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); }\n    DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); }\n    DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); }\n    DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; }\n    DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; }\n    DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; }\n    DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; }\n    DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; }\n    DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; }\n    DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; }\n    DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; }\n#undef DOCTEST_APPROX_PREFIX\n#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS\n\n    // clang-format on\n\nprivate:\n    double m_epsilon;\n    double m_scale;\n    double m_value;\n};\n\nDOCTEST_INTERFACE String toString(const Approx& in);\n\nDOCTEST_INTERFACE const ContextOptions* getContextOptions();\n\n#if !defined(DOCTEST_CONFIG_DISABLE)\n\nnamespace detail {\n    // clang-format off\n#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    template<class T>               struct decay_array       { typedef T type; };\n    template<class T, unsigned N>   struct decay_array<T[N]> { typedef T* type; };\n    template<class T>               struct decay_array<T[]>  { typedef T* type; };\n\n    template<class T>   struct not_char_pointer              { enum { value = 1 }; };\n    template<>          struct not_char_pointer<char*>       { enum { value = 0 }; };\n    template<>          struct not_char_pointer<const char*> { enum { value = 0 }; };\n\n    template<class T> struct can_use_op : public not_char_pointer<typename decay_array<T>::type> {};\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    // clang-format on\n\n    struct DOCTEST_INTERFACE TestFailureException\n    {\n    };\n\n    DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at);\n\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n    DOCTEST_NORETURN\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n    DOCTEST_INTERFACE void throwException();\n\n    struct DOCTEST_INTERFACE Subcase\n    {\n        SubcaseSignature m_signature;\n        bool             m_entered = false;\n\n        Subcase(const String& name, const char* file, int line);\n        ~Subcase();\n\n        operator bool() const;\n    };\n\n    template <typename L, typename R>\n    String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op,\n                               const DOCTEST_REF_WRAP(R) rhs) {\n        // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n        return toString(lhs) + op + toString(rhs);\n    }\n\n#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)\nDOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wunused-comparison\")\n#endif\n\n// This will check if there is any way it could find a operator like member or friend and uses it.\n// If not it doesn't find the operator or if the operator at global scope is defined after\n// this template, the template won't be instantiated due to SFINAE. Once the template is not\n// instantiated it can look for global operator using normal conversions.\n#define SFINAE_OP(ret,op) decltype((void)(doctest::detail::declval<L>() op doctest::detail::declval<R>()),ret{})\n\n#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro)                              \\\n    template <typename R>                                                                          \\\n    DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(const R&& rhs) {                             \\\n    bool res = op_macro(doctest::detail::forward<const L>(lhs), doctest::detail::forward<const R>(rhs));                                                             \\\n        if(m_at & assertType::is_false)                                                            \\\n            res = !res;                                                                            \\\n        if(!res || doctest::getContextOptions()->success)                                          \\\n            return Result(res, stringifyBinaryExpr(lhs, op_str, rhs));                             \\\n        return Result(res);                                                                        \\\n    }                                                                                              \\\n    template <typename R ,typename enable_if<!doctest::detail::is_rvalue_reference<R>::value, void >::type* = nullptr> \\\n    DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(const R& rhs) {                              \\\n    bool res = op_macro(doctest::detail::forward<const L>(lhs), rhs);                              \\\n        if(m_at & assertType::is_false)                                                            \\\n            res = !res;                                                                            \\\n        if(!res || doctest::getContextOptions()->success)                                          \\\n            return Result(res, stringifyBinaryExpr(lhs, op_str, rhs));                             \\\n        return Result(res);                                                                        \\\n    }\n\n    // more checks could be added - like in Catch:\n    // https://github.com/catchorg/Catch2/pull/1480/files\n    // https://github.com/catchorg/Catch2/pull/1481/files\n#define DOCTEST_FORBIT_EXPRESSION(rt, op)                                                          \\\n    template <typename R>                                                                          \\\n    rt& operator op(const R&) {                                                                    \\\n        static_assert(deferred_false<R>::value,                                                    \\\n                      \"Expression Too Complex Please Rewrite As Binary Comparison!\");              \\\n        return *this;                                                                              \\\n    }\n\n    struct DOCTEST_INTERFACE Result\n    {\n        bool   m_passed;\n        String m_decomp;\n\n        Result() = default;\n        Result(bool passed, const String& decomposition = String());\n\n        // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence\n        DOCTEST_FORBIT_EXPRESSION(Result, &)\n        DOCTEST_FORBIT_EXPRESSION(Result, ^)\n        DOCTEST_FORBIT_EXPRESSION(Result, |)\n        DOCTEST_FORBIT_EXPRESSION(Result, &&)\n        DOCTEST_FORBIT_EXPRESSION(Result, ||)\n        DOCTEST_FORBIT_EXPRESSION(Result, ==)\n        DOCTEST_FORBIT_EXPRESSION(Result, !=)\n        DOCTEST_FORBIT_EXPRESSION(Result, <)\n        DOCTEST_FORBIT_EXPRESSION(Result, >)\n        DOCTEST_FORBIT_EXPRESSION(Result, <=)\n        DOCTEST_FORBIT_EXPRESSION(Result, >=)\n        DOCTEST_FORBIT_EXPRESSION(Result, =)\n        DOCTEST_FORBIT_EXPRESSION(Result, +=)\n        DOCTEST_FORBIT_EXPRESSION(Result, -=)\n        DOCTEST_FORBIT_EXPRESSION(Result, *=)\n        DOCTEST_FORBIT_EXPRESSION(Result, /=)\n        DOCTEST_FORBIT_EXPRESSION(Result, %=)\n        DOCTEST_FORBIT_EXPRESSION(Result, <<=)\n        DOCTEST_FORBIT_EXPRESSION(Result, >>=)\n        DOCTEST_FORBIT_EXPRESSION(Result, &=)\n        DOCTEST_FORBIT_EXPRESSION(Result, ^=)\n        DOCTEST_FORBIT_EXPRESSION(Result, |=)\n    };\n\n#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION\n\n    DOCTEST_CLANG_SUPPRESS_WARNING_PUSH\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wsign-conversion\")\n    DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wsign-compare\")\n    //DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wdouble-promotion\")\n    //DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wconversion\")\n    //DOCTEST_CLANG_SUPPRESS_WARNING(\"-Wfloat-equal\")\n\n    DOCTEST_GCC_SUPPRESS_WARNING_PUSH\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wsign-conversion\")\n    DOCTEST_GCC_SUPPRESS_WARNING(\"-Wsign-compare\")\n    //DOCTEST_GCC_SUPPRESS_WARNING(\"-Wdouble-promotion\")\n    //DOCTEST_GCC_SUPPRESS_WARNING(\"-Wconversion\")\n    //DOCTEST_GCC_SUPPRESS_WARNING(\"-Wfloat-equal\")\n\n    DOCTEST_MSVC_SUPPRESS_WARNING_PUSH\n    // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389\n    DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch\n    DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch\n    DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch\n    //DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation\n\n#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION\n\n    // clang-format off\n#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n#define DOCTEST_COMPARISON_RETURN_TYPE bool\n#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type\n    // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n    inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); }\n    inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); }\n    inline bool lt(const char* lhs, const char* rhs) { return String(lhs) <  String(rhs); }\n    inline bool gt(const char* lhs, const char* rhs) { return String(lhs) >  String(rhs); }\n    inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); }\n    inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); }\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    // clang-format on\n\n#define DOCTEST_RELATIONAL_OP(name, op)                                                            \\\n    template <typename L, typename R>                                                              \\\n    DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs,                             \\\n                                        const DOCTEST_REF_WRAP(R) rhs) {                           \\\n        return lhs op rhs;                                                                         \\\n    }\n\n    DOCTEST_RELATIONAL_OP(eq, ==)\n    DOCTEST_RELATIONAL_OP(ne, !=)\n    DOCTEST_RELATIONAL_OP(lt, <)\n    DOCTEST_RELATIONAL_OP(gt, >)\n    DOCTEST_RELATIONAL_OP(le, <=)\n    DOCTEST_RELATIONAL_OP(ge, >=)\n\n#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n#define DOCTEST_CMP_EQ(l, r) l == r\n#define DOCTEST_CMP_NE(l, r) l != r\n#define DOCTEST_CMP_GT(l, r) l > r\n#define DOCTEST_CMP_LT(l, r) l < r\n#define DOCTEST_CMP_GE(l, r) l >= r\n#define DOCTEST_CMP_LE(l, r) l <= r\n#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n#define DOCTEST_CMP_EQ(l, r) eq(l, r)\n#define DOCTEST_CMP_NE(l, r) ne(l, r)\n#define DOCTEST_CMP_GT(l, r) gt(l, r)\n#define DOCTEST_CMP_LT(l, r) lt(l, r)\n#define DOCTEST_CMP_GE(l, r) ge(l, r)\n#define DOCTEST_CMP_LE(l, r) le(l, r)\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n\n    template <typename L>\n    // cppcheck-suppress copyCtorAndEqOperator\n    struct Expression_lhs\n    {\n        L                lhs;\n        assertType::Enum m_at;\n\n        explicit Expression_lhs(L&& in, assertType::Enum at)\n                : lhs(doctest::detail::forward<L>(in))\n                , m_at(at) {}\n\n        DOCTEST_NOINLINE operator Result() {\n// this is needed only for MSVC 2015\nDOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool\n            bool res = static_cast<bool>(lhs);\nDOCTEST_MSVC_SUPPRESS_WARNING_POP\n            if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional\n                res = !res;\n\n            if(!res || getContextOptions()->success)\n                return Result(res, toString(lhs));\n            return Result(res);\n        }\n\n        /* This is required for user-defined conversions from Expression_lhs to L */\n        operator L() const { return lhs; }\n\n        // clang-format off\n        DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, \" == \", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional\n        DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, \" != \", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional\n        DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>,  \" >  \", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional\n        DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<,  \" <  \", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional\n        DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, \" >= \", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional\n        DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, \" <= \", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional\n        // clang-format on\n\n        // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=)\n        // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the\n        // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression...\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<)\n        DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>)\n    };\n\n#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION\n\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n    DOCTEST_MSVC_SUPPRESS_WARNING_POP\n    DOCTEST_GCC_SUPPRESS_WARNING_POP\n\n#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION\n\n#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)\nDOCTEST_CLANG_SUPPRESS_WARNING_POP\n#endif\n\n    struct DOCTEST_INTERFACE ExpressionDecomposer\n    {\n        assertType::Enum m_at;\n\n        ExpressionDecomposer(assertType::Enum at);\n\n        // The right operator for capturing expressions is \"<=\" instead of \"<<\" (based on the operator precedence table)\n        // but then there will be warnings from GCC about \"-Wparentheses\" and since \"_Pragma()\" is problematic this will stay for now...\n        // https://github.com/catchorg/Catch2/issues/870\n        // https://github.com/catchorg/Catch2/issues/565\n        template <typename L>\n        Expression_lhs<const L> operator<<(const L &&operand) {\n            return Expression_lhs<const L>(doctest::detail::forward<const L>(operand), m_at);\n        }\n\n        template <typename L,typename enable_if<!doctest::detail::is_rvalue_reference<L>::value,void >::type* = nullptr>\n        Expression_lhs<const L&> operator<<(const L &operand) {\n            return Expression_lhs<const L&>(operand, m_at);\n        }\n    };\n\n    struct DOCTEST_INTERFACE TestSuite\n    {\n        const char* m_test_suite = nullptr;\n        const char* m_description = nullptr;\n        bool        m_skip = false;\n        bool        m_no_breaks = false;\n        bool        m_no_output = false;\n        bool        m_may_fail = false;\n        bool        m_should_fail = false;\n        int         m_expected_failures = 0;\n        double      m_timeout = 0;\n\n        TestSuite& operator*(const char* in);\n\n        template <typename T>\n        TestSuite& operator*(const T& in) {\n            in.fill(*this);\n            return *this;\n        }\n    };\n\n    typedef void (*funcType)();\n\n    struct DOCTEST_INTERFACE TestCase : public TestCaseData\n    {\n        funcType m_test; // a function pointer to the test case\n\n        const char* m_type; // for templated test cases - gets appended to the real name\n        int m_template_id; // an ID used to distinguish between the different versions of a templated test case\n        String m_full_name; // contains the name (only for templated test cases!) + the template type\n\n        TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,\n                 const char* type = \"\", int template_id = -1);\n\n        TestCase(const TestCase& other);\n\n        DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function\n        TestCase& operator=(const TestCase& other);\n        DOCTEST_MSVC_SUPPRESS_WARNING_POP\n\n        TestCase& operator*(const char* in);\n\n        template <typename T>\n        TestCase& operator*(const T& in) {\n            in.fill(*this);\n            return *this;\n        }\n\n        bool operator<(const TestCase& other) const;\n    };\n\n    // forward declarations of functions used by the macros\n    DOCTEST_INTERFACE int  regTest(const TestCase& tc);\n    DOCTEST_INTERFACE int  setTestSuite(const TestSuite& ts);\n    DOCTEST_INTERFACE bool isDebuggerActive();\n\n    template<typename T>\n    int instantiationHelper(const T&) { return 0; }\n\n    namespace binaryAssertComparison {\n        enum Enum\n        {\n            eq = 0,\n            ne,\n            gt,\n            lt,\n            ge,\n            le\n        };\n    } // namespace binaryAssertComparison\n\n    // clang-format off\n    template <int, class L, class R> struct RelationalComparator     { bool operator()(const DOCTEST_REF_WRAP(L),     const DOCTEST_REF_WRAP(R)    ) const { return false;        } };\n\n#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \\\n    template <class L, class R> struct RelationalComparator<n, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } };\n    // clang-format on\n\n    DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq)\n    DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne)\n    DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt)\n    DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt)\n    DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge)\n    DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le)\n\n    struct DOCTEST_INTERFACE ResultBuilder : public AssertData\n    {\n        ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr,\n                      const char* exception_type = \"\", const char* exception_string = \"\");\n\n        void setResult(const Result& res);\n\n        template <int comparison, typename L, typename R>\n        DOCTEST_NOINLINE bool binary_assert(const DOCTEST_REF_WRAP(L) lhs,\n                                            const DOCTEST_REF_WRAP(R) rhs) {\n            m_failed = !RelationalComparator<comparison, L, R>()(lhs, rhs);\n            if(m_failed || getContextOptions()->success)\n                m_decomp = stringifyBinaryExpr(lhs, \", \", rhs);\n            return !m_failed;\n        }\n\n        template <typename L>\n        DOCTEST_NOINLINE bool unary_assert(const DOCTEST_REF_WRAP(L) val) {\n            m_failed = !val;\n\n            if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional\n                m_failed = !m_failed;\n\n            if(m_failed || getContextOptions()->success)\n                m_decomp = toString(val);\n\n            return !m_failed;\n        }\n\n        void translateException();\n\n        bool log();\n        void react() const;\n    };\n\n    namespace assertAction {\n        enum Enum\n        {\n            nothing     = 0,\n            dbgbreak    = 1,\n            shouldthrow = 2\n        };\n    } // namespace assertAction\n\n    DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad);\n\n    DOCTEST_INTERFACE bool decomp_assert(assertType::Enum at, const char* file, int line,\n                                         const char* expr, Result result);\n\n#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp)                                                        \\\n    do {                                                                                           \\\n        if(!is_running_in_test) {                                                                  \\\n            if(failed) {                                                                           \\\n                ResultBuilder rb(at, file, line, expr);                                            \\\n                rb.m_failed = failed;                                                              \\\n                rb.m_decomp = decomp;                                                              \\\n                failed_out_of_a_testing_context(rb);                                               \\\n                if(isDebuggerActive() && !getContextOptions()->no_breaks)                          \\\n                    DOCTEST_BREAK_INTO_DEBUGGER();                                                 \\\n                if(checkIfShouldThrow(at))                                                         \\\n                    throwException();                                                              \\\n            }                                                                                      \\\n            return !failed;                                                                        \\\n        }                                                                                          \\\n    } while(false)\n\n#define DOCTEST_ASSERT_IN_TESTS(decomp)                                                            \\\n    ResultBuilder rb(at, file, line, expr);                                                        \\\n    rb.m_failed = failed;                                                                          \\\n    if(rb.m_failed || getContextOptions()->success)                                                \\\n        rb.m_decomp = decomp;                                                                      \\\n    if(rb.log())                                                                                   \\\n        DOCTEST_BREAK_INTO_DEBUGGER();                                                             \\\n    if(rb.m_failed && checkIfShouldThrow(at))                                                      \\\n    throwException()\n\n    template <int comparison, typename L, typename R>\n    DOCTEST_NOINLINE bool binary_assert(assertType::Enum at, const char* file, int line,\n                                        const char* expr, const DOCTEST_REF_WRAP(L) lhs,\n                                        const DOCTEST_REF_WRAP(R) rhs) {\n        bool failed = !RelationalComparator<comparison, L, R>()(lhs, rhs);\n\n        // ###################################################################################\n        // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT\n        // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED\n        // ###################################################################################\n        DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, \", \", rhs));\n        DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, \", \", rhs));\n        return !failed;\n    }\n\n    template <typename L>\n    DOCTEST_NOINLINE bool unary_assert(assertType::Enum at, const char* file, int line,\n                                       const char* expr, const DOCTEST_REF_WRAP(L) val) {\n        bool failed = !val;\n\n        if(at & assertType::is_false) //!OCLINT bitwise operator in conditional\n            failed = !failed;\n\n        // ###################################################################################\n        // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT\n        // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED\n        // ###################################################################################\n        DOCTEST_ASSERT_OUT_OF_TESTS(toString(val));\n        DOCTEST_ASSERT_IN_TESTS(toString(val));\n        return !failed;\n    }\n\n    struct DOCTEST_INTERFACE IExceptionTranslator\n    {\n        IExceptionTranslator();\n        virtual ~IExceptionTranslator();\n        virtual bool translate(String&) const = 0;\n    };\n\n    template <typename T>\n    class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class\n    {\n    public:\n        explicit ExceptionTranslator(String (*translateFunction)(T))\n                : m_translateFunction(translateFunction) {}\n\n        bool translate(String& res) const override {\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n            try {\n                throw; // lgtm [cpp/rethrow-no-exception]\n                // cppcheck-suppress catchExceptionByValue\n            } catch(T ex) {                    // NOLINT\n                res = m_translateFunction(ex); //!OCLINT parameter reassignment\n                return true;\n            } catch(...) {}         //!OCLINT -  empty catch statement\n#endif                              // DOCTEST_CONFIG_NO_EXCEPTIONS\n            static_cast<void>(res); // to silence -Wunused-parameter\n            return false;\n        }\n\n    private:\n        String (*m_translateFunction)(T);\n    };\n\n    DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et);\n\n    template <bool C>\n    struct StringStreamBase\n    {\n        template <typename T>\n        static void convert(std::ostream* s, const T& in) {\n            *s << toString(in);\n        }\n\n        // always treat char* as a string in this context - no matter\n        // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined\n        static void convert(std::ostream* s, const char* in) { *s << String(in); }\n    };\n\n    template <>\n    struct StringStreamBase<true>\n    {\n        template <typename T>\n        static void convert(std::ostream* s, const T& in) {\n            *s << in;\n        }\n    };\n\n    template <typename T>\n    struct StringStream : public StringStreamBase<has_insertion_operator<T>::value>\n    {};\n\n    template <typename T>\n    void toStream(std::ostream* s, const T& value) {\n        StringStream<T>::convert(s, value);\n    }\n\n#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    DOCTEST_INTERFACE void toStream(std::ostream* s, char* in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in);\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    DOCTEST_INTERFACE void toStream(std::ostream* s, bool in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, float in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, double in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, double long in);\n\n    DOCTEST_INTERFACE void toStream(std::ostream* s, char in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int short in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int long in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in);\n    DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in);\n\n    // ContextScope base class used to allow implementing methods of ContextScope \n    // that don't depend on the template parameter in doctest.cpp.\n    class DOCTEST_INTERFACE ContextScopeBase : public IContextScope {\n    protected:\n        ContextScopeBase();\n        ContextScopeBase(ContextScopeBase&& other);\n\n        void destroy();\n        bool need_to_destroy{true};\n    };\n\n    template <typename L> class ContextScope : public ContextScopeBase\n    {\n        const L lambda_;\n\n    public:\n        explicit ContextScope(const L &lambda) : lambda_(lambda) {}\n\n        ContextScope(ContextScope &&other) : ContextScopeBase(static_cast<ContextScopeBase&&>(other)), lambda_(other.lambda_) {}\n\n        void stringify(std::ostream* s) const override { lambda_(s); }\n\n        ~ContextScope() override {\n            if (need_to_destroy) {\n                destroy();\n            }\n        }\n    };\n\n    struct DOCTEST_INTERFACE MessageBuilder : public MessageData\n    {\n        std::ostream* m_stream;\n        bool          logged = false;\n\n        MessageBuilder(const char* file, int line, assertType::Enum severity);\n        MessageBuilder() = delete;\n        ~MessageBuilder();\n\n        // the preferred way of chaining parameters for stringification\n        template <typename T>\n        MessageBuilder& operator,(const T& in) {\n            toStream(m_stream, in);\n            return *this;\n        }\n\n        // kept here just for backwards-compatibility - the comma operator should be preferred now\n        template <typename T>\n        MessageBuilder& operator<<(const T& in) { return this->operator,(in); }\n\n        // the `,` operator has the lowest operator precedence - if `<<` is used by the user then\n        // the `,` operator will be called last which is not what we want and thus the `*` operator\n        // is used first (has higher operator precedence compared to `<<`) so that we guarantee that\n        // an operator of the MessageBuilder class is called first before the rest of the parameters\n        template <typename T>\n        MessageBuilder& operator*(const T& in) { return this->operator,(in); }\n\n        bool log();\n        void react();\n    };\n    \n    template <typename L>\n    ContextScope<L> MakeContextScope(const L &lambda) {\n        return ContextScope<L>(lambda);\n    }\n} // namespace detail\n\n#define DOCTEST_DEFINE_DECORATOR(name, type, def)                                                  \\\n    struct name                                                                                    \\\n    {                                                                                              \\\n        type data;                                                                                 \\\n        name(type in = def)                                                                        \\\n                : data(in) {}                                                                      \\\n        void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; }           \\\n        void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; }          \\\n    }\n\nDOCTEST_DEFINE_DECORATOR(test_suite, const char*, \"\");\nDOCTEST_DEFINE_DECORATOR(description, const char*, \"\");\nDOCTEST_DEFINE_DECORATOR(skip, bool, true);\nDOCTEST_DEFINE_DECORATOR(no_breaks, bool, true);\nDOCTEST_DEFINE_DECORATOR(no_output, bool, true);\nDOCTEST_DEFINE_DECORATOR(timeout, double, 0);\nDOCTEST_DEFINE_DECORATOR(may_fail, bool, true);\nDOCTEST_DEFINE_DECORATOR(should_fail, bool, true);\nDOCTEST_DEFINE_DECORATOR(expected_failures, int, 0);\n\ntemplate <typename T>\nint registerExceptionTranslator(String (*translateFunction)(T)) {\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wexit-time-destructors\")\n    static detail::ExceptionTranslator<T> exceptionTranslator(translateFunction);\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n    detail::registerExceptionTranslatorImpl(&exceptionTranslator);\n    return 0;\n}\n\n} // namespace doctest\n\n// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro\n// introduces an anonymous namespace in which getCurrentTestSuite gets overridden\nnamespace doctest_detail_test_suite_ns {\nDOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite();\n} // namespace doctest_detail_test_suite_ns\n\nnamespace doctest {\n#else  // DOCTEST_CONFIG_DISABLE\ntemplate <typename T>\nint registerExceptionTranslator(String (*)(T)) {\n    return 0;\n}\n#endif // DOCTEST_CONFIG_DISABLE\n\nnamespace detail {\n    typedef void (*assert_handler)(const AssertData&);\n    struct ContextState;\n} // namespace detail\n\nclass DOCTEST_INTERFACE Context\n{\n    detail::ContextState* p;\n\n    void parseArgs(int argc, const char* const* argv, bool withDefaults = false);\n\npublic:\n    explicit Context(int argc = 0, const char* const* argv = nullptr);\n\n    ~Context();\n\n    void applyCommandLine(int argc, const char* const* argv);\n\n    void addFilter(const char* filter, const char* value);\n    void clearFilters();\n    void setOption(const char* option, bool value);\n    void setOption(const char* option, int value);\n    void setOption(const char* option, const char* value);\n\n    bool shouldExit();\n\n    void setAsDefaultForAssertsOutOfTestCases();\n\n    void setAssertHandler(detail::assert_handler ah);\n\n    void setCout(std::ostream* out);\n\n    int run();\n};\n\nnamespace TestCaseFailureReason {\n    enum Enum\n    {\n        None                     = 0,\n        AssertFailure            = 1,   // an assertion has failed in the test case\n        Exception                = 2,   // test case threw an exception\n        Crash                    = 4,   // a crash...\n        TooManyFailedAsserts     = 8,   // the abort-after option\n        Timeout                  = 16,  // see the timeout decorator\n        ShouldHaveFailedButDidnt = 32,  // see the should_fail decorator\n        ShouldHaveFailedAndDid   = 64,  // see the should_fail decorator\n        DidntFailExactlyNumTimes = 128, // see the expected_failures decorator\n        FailedExactlyNumTimes    = 256, // see the expected_failures decorator\n        CouldHaveFailedAndDid    = 512  // see the may_fail decorator\n    };\n} // namespace TestCaseFailureReason\n\nstruct DOCTEST_INTERFACE CurrentTestCaseStats\n{\n    int    numAssertsCurrentTest;\n    int    numAssertsFailedCurrentTest;\n    double seconds;\n    int    failure_flags; // use TestCaseFailureReason::Enum\n    bool   testCaseSuccess;\n};\n\nstruct DOCTEST_INTERFACE TestCaseException\n{\n    String error_string;\n    bool   is_crash;\n};\n\nstruct DOCTEST_INTERFACE TestRunStats\n{\n    unsigned numTestCases;\n    unsigned numTestCasesPassingFilters;\n    unsigned numTestSuitesPassingFilters;\n    unsigned numTestCasesFailed;\n    int      numAsserts;\n    int      numAssertsFailed;\n};\n\nstruct QueryData\n{\n    const TestRunStats*  run_stats = nullptr;\n    const TestCaseData** data      = nullptr;\n    unsigned             num_data  = 0;\n};\n\nstruct DOCTEST_INTERFACE IReporter\n{\n    // The constructor has to accept \"const ContextOptions&\" as a single argument\n    // which has most of the options for the run + a pointer to the stdout stream\n    // Reporter(const ContextOptions& in)\n\n    // called when a query should be reported (listing test cases, printing the version, etc.)\n    virtual void report_query(const QueryData&) = 0;\n\n    // called when the whole test run starts\n    virtual void test_run_start() = 0;\n    // called when the whole test run ends (caching a pointer to the input doesn't make sense here)\n    virtual void test_run_end(const TestRunStats&) = 0;\n\n    // called when a test case is started (safe to cache a pointer to the input)\n    virtual void test_case_start(const TestCaseData&) = 0;\n    // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input)\n    virtual void test_case_reenter(const TestCaseData&) = 0;\n    // called when a test case has ended\n    virtual void test_case_end(const CurrentTestCaseStats&) = 0;\n\n    // called when an exception is thrown from the test case (or it crashes)\n    virtual void test_case_exception(const TestCaseException&) = 0;\n\n    // called whenever a subcase is entered (don't cache pointers to the input)\n    virtual void subcase_start(const SubcaseSignature&) = 0;\n    // called whenever a subcase is exited (don't cache pointers to the input)\n    virtual void subcase_end() = 0;\n\n    // called for each assert (don't cache pointers to the input)\n    virtual void log_assert(const AssertData&) = 0;\n    // called for each message (don't cache pointers to the input)\n    virtual void log_message(const MessageData&) = 0;\n\n    // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator\n    // or isn't in the execution range (between first and last) (safe to cache a pointer to the input)\n    virtual void test_case_skipped(const TestCaseData&) = 0;\n\n    // doctest will not be managing the lifetimes of reporters given to it but this would still be nice to have\n    virtual ~IReporter();\n\n    // can obtain all currently active contexts and stringify them if one wishes to do so\n    static int                         get_num_active_contexts();\n    static const IContextScope* const* get_active_contexts();\n\n    // can iterate through contexts which have been stringified automatically in their destructors when an exception has been thrown\n    static int           get_num_stringified_contexts();\n    static const String* get_stringified_contexts();\n};\n\nnamespace detail {\n    typedef IReporter* (*reporterCreatorFunc)(const ContextOptions&);\n\n    DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter);\n\n    template <typename Reporter>\n    IReporter* reporterCreator(const ContextOptions& o) {\n        return new Reporter(o);\n    }\n} // namespace detail\n\ntemplate <typename Reporter>\nint registerReporter(const char* name, int priority, bool isReporter) {\n    detail::registerReporterImpl(name, priority, detail::reporterCreator<Reporter>, isReporter);\n    return 0;\n}\n} // namespace doctest\n\n// if registering is not disabled\n#if !defined(DOCTEST_CONFIG_DISABLE)\n\n// common code in asserts - for convenience\n#define DOCTEST_ASSERT_LOG_REACT_RETURN(b)                                                         \\\n    if(b.log())                                                                                    \\\n        DOCTEST_BREAK_INTO_DEBUGGER();                                                             \\\n    b.react(); \\\n    return !b.m_failed\n\n#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS\n#define DOCTEST_WRAP_IN_TRY(x) x;\n#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS\n#define DOCTEST_WRAP_IN_TRY(x)                                                                     \\\n    try {                                                                                          \\\n        x;                                                                                         \\\n    } catch(...) { DOCTEST_RB.translateException(); }\n#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS\n\n#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS\n#define DOCTEST_CAST_TO_VOID(...)                                                                  \\\n    DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wuseless-cast\")                                       \\\n    static_cast<void>(__VA_ARGS__);                                                                \\\n    DOCTEST_GCC_SUPPRESS_WARNING_POP\n#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS\n#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__;\n#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS\n\n// registers the test by initializing a dummy var with a function\n#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators)                                    \\\n    global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_),                 \\\n            doctest::detail::regTest(                                                              \\\n                    doctest::detail::TestCase(                                                     \\\n                            f, __FILE__, __LINE__,                                                 \\\n                            doctest_detail_test_suite_ns::getCurrentTestSuite()) *                 \\\n                    decorators))\n\n#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators)                                     \\\n    namespace {                                                                                    \\\n        struct der : public base                                                                   \\\n        {                                                                                          \\\n            void f();                                                                              \\\n        };                                                                                         \\\n        static void func() {                                                                       \\\n            der v;                                                                                 \\\n            v.f();                                                                                 \\\n        }                                                                                          \\\n        DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators)                                 \\\n    }                                                                                              \\\n    inline DOCTEST_NOINLINE void der::f()\n\n#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators)                                        \\\n    static void f();                                                                               \\\n    DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators)                                        \\\n    static void f()\n\n#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators)                        \\\n    static doctest::detail::funcType proxy() { return f; }                                         \\\n    DOCTEST_REGISTER_FUNCTION(inline, proxy(), decorators)                                   \\\n    static void f()\n\n// for registering tests\n#define DOCTEST_TEST_CASE(decorators)                                                              \\\n    DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators)\n\n// for registering tests in classes - requires C++17 for inline variables!\n#if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && _MSVC_LANG >= 201703L)\n#define DOCTEST_TEST_CASE_CLASS(decorators)                                                        \\\n    DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_),           \\\n                                                  DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_),          \\\n                                                  decorators)\n#else // DOCTEST_TEST_CASE_CLASS\n#define DOCTEST_TEST_CASE_CLASS(...)                                                               \\\n    TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER\n#endif // DOCTEST_TEST_CASE_CLASS\n\n// for registering tests with a fixture\n#define DOCTEST_TEST_CASE_FIXTURE(c, decorators)                                                   \\\n    DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), c,                           \\\n                              DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators)\n\n// for converting types to strings without the <typeinfo> header and demangling\n#define DOCTEST_TYPE_TO_STRING_IMPL(...)                                                           \\\n    template <>                                                                                    \\\n    inline const char* type_to_string<__VA_ARGS__>() {                                             \\\n        return \"<\" #__VA_ARGS__ \">\";                                                               \\\n    }\n#define DOCTEST_TYPE_TO_STRING(...)                                                                \\\n    namespace doctest { namespace detail {                                                         \\\n            DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__)                                               \\\n        }                                                                                          \\\n    }                                                                                              \\\n    static_assert(true, \"\")\n\n#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func)                                 \\\n    template <typename T>                                                                          \\\n    static void func();                                                                            \\\n    namespace {                                                                                    \\\n        template <typename Tuple>                                                                  \\\n        struct iter;                                                                               \\\n        template <typename Type, typename... Rest>                                                 \\\n        struct iter<std::tuple<Type, Rest...>>                                                     \\\n        {                                                                                          \\\n            iter(const char* file, unsigned line, int index) {                                     \\\n                doctest::detail::regTest(doctest::detail::TestCase(func<Type>, file, line,         \\\n                                            doctest_detail_test_suite_ns::getCurrentTestSuite(),   \\\n                                            doctest::detail::type_to_string<Type>(),               \\\n                                            int(line) * 1000 + index)                              \\\n                                         * dec);                                                   \\\n                iter<std::tuple<Rest...>>(file, line, index + 1);                                  \\\n            }                                                                                      \\\n        };                                                                                         \\\n        template <>                                                                                \\\n        struct iter<std::tuple<>>                                                                  \\\n        {                                                                                          \\\n            iter(const char*, unsigned, int) {}                                                    \\\n        };                                                                                         \\\n    }                                                                                              \\\n    template <typename T>                                                                          \\\n    static void func()\n\n#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id)                                              \\\n    DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR),                      \\\n                                           DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_))\n\n#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...)                                 \\\n    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY),                                           \\\n        doctest::detail::instantiationHelper(                                                      \\\n            DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0)))\n\n#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...)                                                 \\\n    DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \\\n    static_assert(true, \"\")\n\n#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...)                                                  \\\n    DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) \\\n    static_assert(true, \"\")\n\n#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...)                                         \\\n    DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon);             \\\n    DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>)               \\\n    template <typename T>                                                                          \\\n    static void anon()\n\n#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...)                                                    \\\n    DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__)\n\n// for subcases\n#define DOCTEST_SUBCASE(name)                                                                      \\\n    if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED =  \\\n               doctest::detail::Subcase(name, __FILE__, __LINE__))\n\n// for grouping tests in test suites by using code blocks\n#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name)                                               \\\n    namespace ns_name { namespace doctest_detail_test_suite_ns {                                   \\\n            static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() {            \\\n                DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640)                                      \\\n                DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wexit-time-destructors\")                \\\n                DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wmissing-field-initializers\")             \\\n                static doctest::detail::TestSuite data{};                                          \\\n                static bool                       inited = false;                                  \\\n                DOCTEST_MSVC_SUPPRESS_WARNING_POP                                                  \\\n                DOCTEST_CLANG_SUPPRESS_WARNING_POP                                                 \\\n                DOCTEST_GCC_SUPPRESS_WARNING_POP                                                   \\\n                if(!inited) {                                                                      \\\n                    data* decorators;                                                              \\\n                    inited = true;                                                                 \\\n                }                                                                                  \\\n                return data;                                                                       \\\n            }                                                                                      \\\n        }                                                                                          \\\n    }                                                                                              \\\n    namespace ns_name\n\n#define DOCTEST_TEST_SUITE(decorators)                                                             \\\n    DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(DOCTEST_ANON_SUITE_))\n\n// for starting a testsuite block\n#define DOCTEST_TEST_SUITE_BEGIN(decorators)                                                       \\\n    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_),                               \\\n            doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators))              \\\n    static_assert(true, \"\")\n\n// for ending a testsuite block\n#define DOCTEST_TEST_SUITE_END                                                                     \\\n    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_),                               \\\n            doctest::detail::setTestSuite(doctest::detail::TestSuite() * \"\"))                      \\\n    typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)\n\n// for registering exception translators\n#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature)                      \\\n    inline doctest::String translatorName(signature);                                              \\\n    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_),                        \\\n            doctest::registerExceptionTranslator(translatorName))                                  \\\n    doctest::String translatorName(signature)\n\n#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)                                           \\\n    DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_),        \\\n                                               signature)\n\n// for registering reporters\n#define DOCTEST_REGISTER_REPORTER(name, priority, reporter)                                        \\\n    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_),                          \\\n            doctest::registerReporter<reporter>(name, priority, true))                             \\\n    static_assert(true, \"\")\n\n// for registering listeners\n#define DOCTEST_REGISTER_LISTENER(name, priority, reporter)                                        \\\n    DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_),                          \\\n            doctest::registerReporter<reporter>(name, priority, false))                            \\\n    static_assert(true, \"\")\n\n// clang-format off\n// for logging - disabling formatting because it's important to have these on 2 separate lines - see PR #557\n#define DOCTEST_INFO(...)                                                                          \\\n    DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_),                                         \\\n                      DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_),                                   \\\n                      __VA_ARGS__)\n// clang-format on\n\n#define DOCTEST_INFO_IMPL(mb_name, s_name, ...)                                       \\\n    auto DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(                  \\\n        [&](std::ostream* s_name) {                                                                \\\n        doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \\\n        mb_name.m_stream = s_name;                                                                 \\\n        mb_name * __VA_ARGS__;                                                                     \\\n    })\n\n#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x \" := \", x)\n\n#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...)                                             \\\n    [&] {                                                                                          \\\n        doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type);                 \\\n        mb * __VA_ARGS__;                                                                          \\\n        if(mb.log())                                                                               \\\n            DOCTEST_BREAK_INTO_DEBUGGER();                                                         \\\n        mb.react();                                                                                \\\n    }()\n\n// clang-format off\n#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__)\n#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__)\n#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__)\n// clang-format on\n\n#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__)\n#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__)\n#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__)\n\n#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility.\n\n#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS\n\n#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...)                                               \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Woverloaded-shift-op-parentheses\")                  \\\n    doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__,          \\\n                                               __LINE__, #__VA_ARGS__);                            \\\n    DOCTEST_WRAP_IN_TRY(DOCTEST_RB.setResult(                                                      \\\n            doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type)                \\\n            << __VA_ARGS__))                                                                       \\\n    DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB)                                                    \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n\n#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...)                                               \\\n    [&] {                                                                                          \\\n        DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__);                                      \\\n    }()\n\n#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS\n\n// necessary for <ASSERT>_MESSAGE\n#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1\n\n#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...)                                               \\\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Woverloaded-shift-op-parentheses\")                  \\\n    doctest::detail::decomp_assert(                                                                \\\n            doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__,                    \\\n            doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type)                \\\n                    << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP\n\n#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS\n\n#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__)\n#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__)\n#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__)\n#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__)\n#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__)\n#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__)\n\n// clang-format off\n#define DOCTEST_WARN_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); }()\n#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); }()\n#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); }()\n#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); }()\n#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); }()\n#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); }()\n// clang-format on\n\n#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...)                                  \\\n    [&] {                                                                                          \\\n        if(!doctest::getContextOptions()->no_throw) {                                              \\\n            doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__,  \\\n                                                       __LINE__, #expr, #__VA_ARGS__, message);    \\\n            try {                                                                                  \\\n                DOCTEST_CAST_TO_VOID(expr)                                                         \\\n            } catch(const typename doctest::detail::remove_const<                                  \\\n                    typename doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) {       \\\n                DOCTEST_RB.translateException();                                                   \\\n                DOCTEST_RB.m_threw_as = true;                                                      \\\n            } catch(...) { DOCTEST_RB.translateException(); }                                      \\\n            DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB);                                           \\\n        } else {                                                                                   \\\n            return false;                                                                          \\\n        }                                                                                          \\\n    }()\n\n#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...)                               \\\n    [&] {                                                                                          \\\n        if(!doctest::getContextOptions()->no_throw) {                                              \\\n            doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__,  \\\n                                                       __LINE__, expr_str, \"\", __VA_ARGS__);       \\\n            try {                                                                                  \\\n                DOCTEST_CAST_TO_VOID(expr)                                                         \\\n            } catch(...) { DOCTEST_RB.translateException(); }                                      \\\n            DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB);                                           \\\n        } else {                                                                                   \\\n           return false;                                                                           \\\n        }                                                                                          \\\n    }()\n\n#define DOCTEST_ASSERT_NOTHROW(assert_type, ...)                                                   \\\n    [&] {                                                                                          \\\n        doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__,      \\\n                                                   __LINE__, #__VA_ARGS__);                        \\\n        try {                                                                                      \\\n            DOCTEST_CAST_TO_VOID(__VA_ARGS__)                                                      \\\n        } catch(...) { DOCTEST_RB.translateException(); }                                          \\\n        DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB);                                               \\\n    }()\n\n// clang-format off\n#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, \"\")\n#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, \"\")\n#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, \"\")\n\n#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, \"\", __VA_ARGS__)\n#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, \"\", __VA_ARGS__)\n#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, \"\", __VA_ARGS__)\n\n#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__)\n#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__)\n#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__)\n\n#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__)\n#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__)\n#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__)\n\n#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__)\n#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__)\n#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__)\n\n#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); }()\n#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); }()\n#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); }()\n#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); }()\n#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); }()\n#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); }()\n#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); }()\n#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); }()\n#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); }()\n#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); }()\n#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); }()\n#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); }()\n#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); }()\n#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); }()\n#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) [&] {DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); }()\n// clang-format on\n\n#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS\n\n#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...)                                              \\\n    [&] {                                                                                          \\\n        doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__,      \\\n                                                   __LINE__, #__VA_ARGS__);                        \\\n        DOCTEST_WRAP_IN_TRY(                                                                       \\\n                DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>(           \\\n                        __VA_ARGS__))                                                              \\\n        DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB);                                               \\\n    }()\n\n#define DOCTEST_UNARY_ASSERT(assert_type, ...)                                                     \\\n    [&] {                                                                                          \\\n        doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__,      \\\n                                                   __LINE__, #__VA_ARGS__);                        \\\n        DOCTEST_WRAP_IN_TRY(DOCTEST_RB.unary_assert(__VA_ARGS__))                                  \\\n        DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB);                                               \\\n    }()\n\n#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS\n\n#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...)                                        \\\n    doctest::detail::binary_assert<doctest::detail::binaryAssertComparison::comparison>(           \\\n            doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__)\n\n#define DOCTEST_UNARY_ASSERT(assert_type, ...)                                                     \\\n    doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__,            \\\n                                  #__VA_ARGS__, __VA_ARGS__)\n\n#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS\n\n#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__)\n#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__)\n#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__)\n#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__)\n#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__)\n#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__)\n#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__)\n#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__)\n#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__)\n#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__)\n#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__)\n#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__)\n#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__)\n#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__)\n#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__)\n#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__)\n#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__)\n#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__)\n\n#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__)\n#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__)\n#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__)\n#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__)\n#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__)\n#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__)\n\n#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS\n\n#undef DOCTEST_WARN_THROWS\n#undef DOCTEST_CHECK_THROWS\n#undef DOCTEST_REQUIRE_THROWS\n#undef DOCTEST_WARN_THROWS_AS\n#undef DOCTEST_CHECK_THROWS_AS\n#undef DOCTEST_REQUIRE_THROWS_AS\n#undef DOCTEST_WARN_THROWS_WITH\n#undef DOCTEST_CHECK_THROWS_WITH\n#undef DOCTEST_REQUIRE_THROWS_WITH\n#undef DOCTEST_WARN_THROWS_WITH_AS\n#undef DOCTEST_CHECK_THROWS_WITH_AS\n#undef DOCTEST_REQUIRE_THROWS_WITH_AS\n#undef DOCTEST_WARN_NOTHROW\n#undef DOCTEST_CHECK_NOTHROW\n#undef DOCTEST_REQUIRE_NOTHROW\n\n#undef DOCTEST_WARN_THROWS_MESSAGE\n#undef DOCTEST_CHECK_THROWS_MESSAGE\n#undef DOCTEST_REQUIRE_THROWS_MESSAGE\n#undef DOCTEST_WARN_THROWS_AS_MESSAGE\n#undef DOCTEST_CHECK_THROWS_AS_MESSAGE\n#undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE\n#undef DOCTEST_WARN_THROWS_WITH_MESSAGE\n#undef DOCTEST_CHECK_THROWS_WITH_MESSAGE\n#undef DOCTEST_REQUIRE_THROWS_WITH_MESSAGE\n#undef DOCTEST_WARN_THROWS_WITH_AS_MESSAGE\n#undef DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE\n#undef DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE\n#undef DOCTEST_WARN_NOTHROW_MESSAGE\n#undef DOCTEST_CHECK_NOTHROW_MESSAGE\n#undef DOCTEST_REQUIRE_NOTHROW_MESSAGE\n\n#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS\n\n#define DOCTEST_WARN_THROWS(...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS(...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS(...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_AS(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_AS(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ([] { return false; })\n#define DOCTEST_WARN_NOTHROW(...) ([] { return false; })\n#define DOCTEST_CHECK_NOTHROW(...) ([] { return false; })\n#define DOCTEST_REQUIRE_NOTHROW(...) ([] { return false; })\n\n#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; })\n#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) ([] { return false; })\n\n#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS\n\n#undef DOCTEST_REQUIRE\n#undef DOCTEST_REQUIRE_FALSE\n#undef DOCTEST_REQUIRE_MESSAGE\n#undef DOCTEST_REQUIRE_FALSE_MESSAGE\n#undef DOCTEST_REQUIRE_EQ\n#undef DOCTEST_REQUIRE_NE\n#undef DOCTEST_REQUIRE_GT\n#undef DOCTEST_REQUIRE_LT\n#undef DOCTEST_REQUIRE_GE\n#undef DOCTEST_REQUIRE_LE\n#undef DOCTEST_REQUIRE_UNARY\n#undef DOCTEST_REQUIRE_UNARY_FALSE\n\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS\n\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n\n// =================================================================================================\n// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING!                      ==\n// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY!                            ==\n// =================================================================================================\n#else // DOCTEST_CONFIG_DISABLE\n\n#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name)                                           \\\n    namespace {                                                                                    \\\n        template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                           \\\n        struct der : public base                                                                   \\\n        { void f(); };                                                                             \\\n    }                                                                                              \\\n    template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                               \\\n    inline void der<DOCTEST_UNUSED_TEMPLATE_TYPE>::f()\n\n#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name)                                              \\\n    template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                               \\\n    static inline void f()\n\n// for registering tests\n#define DOCTEST_TEST_CASE(name)                                                                    \\\n    DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name)\n\n// for registering tests in classes\n#define DOCTEST_TEST_CASE_CLASS(name)                                                              \\\n    DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name)\n\n// for registering tests with a fixture\n#define DOCTEST_TEST_CASE_FIXTURE(x, name)                                                         \\\n    DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), x,                           \\\n                              DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name)\n\n// for converting types to strings without the <typeinfo> header and demangling\n#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, \"\")\n#define DOCTEST_TYPE_TO_STRING_IMPL(...)\n\n// for typed tests\n#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...)                                                \\\n    template <typename type>                                                                       \\\n    inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)()\n\n#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id)                                          \\\n    template <typename type>                                                                       \\\n    inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)()\n\n#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) static_assert(true, \"\")\n#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) static_assert(true, \"\")\n\n// for subcases\n#define DOCTEST_SUBCASE(name)\n\n// for a testsuite block\n#define DOCTEST_TEST_SUITE(name) namespace\n\n// for starting a testsuite block\n#define DOCTEST_TEST_SUITE_BEGIN(name) static_assert(true, \"\")\n\n// for ending a testsuite block\n#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_)\n\n#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)                                           \\\n    template <typename DOCTEST_UNUSED_TEMPLATE_TYPE>                                               \\\n    static inline doctest::String DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)(signature)\n\n#define DOCTEST_REGISTER_REPORTER(name, priority, reporter)\n#define DOCTEST_REGISTER_LISTENER(name, priority, reporter)\n\n#define DOCTEST_INFO(...) (static_cast<void>(0))\n#define DOCTEST_CAPTURE(x) (static_cast<void>(0))\n#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast<void>(0))\n#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast<void>(0))\n#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast<void>(0))\n#define DOCTEST_MESSAGE(...) (static_cast<void>(0))\n#define DOCTEST_FAIL_CHECK(...) (static_cast<void>(0))\n#define DOCTEST_FAIL(...) (static_cast<void>(0))\n\n#ifdef DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED\n\n#define DOCTEST_WARN(...) [&] { return __VA_ARGS__; }()\n#define DOCTEST_CHECK(...) [&] { return __VA_ARGS__; }()\n#define DOCTEST_REQUIRE(...) [&] { return __VA_ARGS__; }()\n#define DOCTEST_WARN_FALSE(...) [&] { return !(__VA_ARGS__); }()\n#define DOCTEST_CHECK_FALSE(...) [&] { return !(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_FALSE(...) [&] { return !(__VA_ARGS__); }()\n\n#define DOCTEST_WARN_MESSAGE(cond, ...) [&] { return cond; }()\n#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] { return cond; }()\n#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] { return cond; }()\n#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }()\n#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }()\n#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }()\n\nnamespace doctest {\nnamespace detail {\n#define DOCTEST_RELATIONAL_OP(name, op)                                                            \\\n    template <typename L, typename R>                                                              \\\n    bool name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs op rhs; }\n\n    DOCTEST_RELATIONAL_OP(eq, ==)\n    DOCTEST_RELATIONAL_OP(ne, !=)\n    DOCTEST_RELATIONAL_OP(lt, <)\n    DOCTEST_RELATIONAL_OP(gt, >)\n    DOCTEST_RELATIONAL_OP(le, <=)\n    DOCTEST_RELATIONAL_OP(ge, >=)\n} // namespace detail\n} // namespace doctest\n\n#define DOCTEST_WARN_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }()\n#define DOCTEST_CHECK_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }()\n#define DOCTEST_WARN_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }()\n#define DOCTEST_CHECK_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }()\n#define DOCTEST_WARN_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }()\n#define DOCTEST_CHECK_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }()\n#define DOCTEST_WARN_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }()\n#define DOCTEST_CHECK_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }()\n#define DOCTEST_WARN_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }()\n#define DOCTEST_CHECK_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }()\n#define DOCTEST_WARN_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }()\n#define DOCTEST_CHECK_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }()\n#define DOCTEST_WARN_UNARY(...) [&] { return __VA_ARGS__; }()\n#define DOCTEST_CHECK_UNARY(...) [&] { return __VA_ARGS__; }()\n#define DOCTEST_REQUIRE_UNARY(...) [&] { return __VA_ARGS__; }()\n#define DOCTEST_WARN_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }()\n#define DOCTEST_CHECK_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }()\n#define DOCTEST_REQUIRE_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }()\n\n#else // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED\n\n#define DOCTEST_WARN(...) ([] { return false; })\n#define DOCTEST_CHECK(...) ([] { return false; })\n#define DOCTEST_REQUIRE(...) ([] { return false; })\n#define DOCTEST_WARN_FALSE(...) ([] { return false; })\n#define DOCTEST_CHECK_FALSE(...) ([] { return false; })\n#define DOCTEST_REQUIRE_FALSE(...) ([] { return false; })\n\n#define DOCTEST_WARN_MESSAGE(cond, ...) ([] { return false; })\n#define DOCTEST_CHECK_MESSAGE(cond, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_MESSAGE(cond, ...) ([] { return false; })\n#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) ([] { return false; })\n#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) ([] { return false; })\n\n#define DOCTEST_WARN_EQ(...) ([] { return false; })\n#define DOCTEST_CHECK_EQ(...) ([] { return false; })\n#define DOCTEST_REQUIRE_EQ(...) ([] { return false; })\n#define DOCTEST_WARN_NE(...) ([] { return false; })\n#define DOCTEST_CHECK_NE(...) ([] { return false; })\n#define DOCTEST_REQUIRE_NE(...) ([] { return false; })\n#define DOCTEST_WARN_GT(...) ([] { return false; })\n#define DOCTEST_CHECK_GT(...) ([] { return false; })\n#define DOCTEST_REQUIRE_GT(...) ([] { return false; })\n#define DOCTEST_WARN_LT(...) ([] { return false; })\n#define DOCTEST_CHECK_LT(...) ([] { return false; })\n#define DOCTEST_REQUIRE_LT(...) ([] { return false; })\n#define DOCTEST_WARN_GE(...) ([] { return false; })\n#define DOCTEST_CHECK_GE(...) ([] { return false; })\n#define DOCTEST_REQUIRE_GE(...) ([] { return false; })\n#define DOCTEST_WARN_LE(...) ([] { return false; })\n#define DOCTEST_CHECK_LE(...) ([] { return false; })\n#define DOCTEST_REQUIRE_LE(...) ([] { return false; })\n\n#define DOCTEST_WARN_UNARY(...) ([] { return false; })\n#define DOCTEST_CHECK_UNARY(...) ([] { return false; })\n#define DOCTEST_REQUIRE_UNARY(...) ([] { return false; })\n#define DOCTEST_WARN_UNARY_FALSE(...) ([] { return false; })\n#define DOCTEST_CHECK_UNARY_FALSE(...) ([] { return false; })\n#define DOCTEST_REQUIRE_UNARY_FALSE(...) ([] { return false; })\n\n#endif // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED\n\n// TODO: think about if these also need to work properly even when doctest is disabled\n#define DOCTEST_WARN_THROWS(...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS(...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS(...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_AS(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_AS(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ([] { return false; })\n#define DOCTEST_WARN_NOTHROW(...) ([] { return false; })\n#define DOCTEST_CHECK_NOTHROW(...) ([] { return false; })\n#define DOCTEST_REQUIRE_NOTHROW(...) ([] { return false; })\n\n#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) ([] { return false; })\n#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; })\n#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) ([] { return false; })\n#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) ([] { return false; })\n#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) ([] { return false; })\n\n#endif // DOCTEST_CONFIG_DISABLE\n\n// clang-format off\n// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS\n#define DOCTEST_FAST_WARN_EQ             DOCTEST_WARN_EQ\n#define DOCTEST_FAST_CHECK_EQ            DOCTEST_CHECK_EQ\n#define DOCTEST_FAST_REQUIRE_EQ          DOCTEST_REQUIRE_EQ\n#define DOCTEST_FAST_WARN_NE             DOCTEST_WARN_NE\n#define DOCTEST_FAST_CHECK_NE            DOCTEST_CHECK_NE\n#define DOCTEST_FAST_REQUIRE_NE          DOCTEST_REQUIRE_NE\n#define DOCTEST_FAST_WARN_GT             DOCTEST_WARN_GT\n#define DOCTEST_FAST_CHECK_GT            DOCTEST_CHECK_GT\n#define DOCTEST_FAST_REQUIRE_GT          DOCTEST_REQUIRE_GT\n#define DOCTEST_FAST_WARN_LT             DOCTEST_WARN_LT\n#define DOCTEST_FAST_CHECK_LT            DOCTEST_CHECK_LT\n#define DOCTEST_FAST_REQUIRE_LT          DOCTEST_REQUIRE_LT\n#define DOCTEST_FAST_WARN_GE             DOCTEST_WARN_GE\n#define DOCTEST_FAST_CHECK_GE            DOCTEST_CHECK_GE\n#define DOCTEST_FAST_REQUIRE_GE          DOCTEST_REQUIRE_GE\n#define DOCTEST_FAST_WARN_LE             DOCTEST_WARN_LE\n#define DOCTEST_FAST_CHECK_LE            DOCTEST_CHECK_LE\n#define DOCTEST_FAST_REQUIRE_LE          DOCTEST_REQUIRE_LE\n\n#define DOCTEST_FAST_WARN_UNARY          DOCTEST_WARN_UNARY\n#define DOCTEST_FAST_CHECK_UNARY         DOCTEST_CHECK_UNARY\n#define DOCTEST_FAST_REQUIRE_UNARY       DOCTEST_REQUIRE_UNARY\n#define DOCTEST_FAST_WARN_UNARY_FALSE    DOCTEST_WARN_UNARY_FALSE\n#define DOCTEST_FAST_CHECK_UNARY_FALSE   DOCTEST_CHECK_UNARY_FALSE\n#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE\n\n#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__)\n// clang-format on\n\n// BDD style macros\n// clang-format off\n#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(\"  Scenario: \" name)\n#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(\"  Scenario: \" name)\n#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...)  DOCTEST_TEST_CASE_TEMPLATE(\"  Scenario: \" name, T, __VA_ARGS__)\n#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(\"  Scenario: \" name, T, id)\n\n#define DOCTEST_GIVEN(name)     DOCTEST_SUBCASE(\"   Given: \" name)\n#define DOCTEST_WHEN(name)      DOCTEST_SUBCASE(\"    When: \" name)\n#define DOCTEST_AND_WHEN(name)  DOCTEST_SUBCASE(\"And when: \" name)\n#define DOCTEST_THEN(name)      DOCTEST_SUBCASE(\"    Then: \" name)\n#define DOCTEST_AND_THEN(name)  DOCTEST_SUBCASE(\"     And: \" name)\n// clang-format on\n\n// == SHORT VERSIONS OF THE MACROS\n#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES)\n\n#define TEST_CASE(name) DOCTEST_TEST_CASE(name)\n#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)\n#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)\n#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)\n#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)\n#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)\n#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__)\n#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__)\n#define SUBCASE(name) DOCTEST_SUBCASE(name)\n#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators)\n#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name)\n#define TEST_SUITE_END DOCTEST_TEST_SUITE_END\n#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)\n#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter)\n#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter)\n#define INFO(...) DOCTEST_INFO(__VA_ARGS__)\n#define CAPTURE(x) DOCTEST_CAPTURE(x)\n#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__)\n#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__)\n#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__)\n#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__)\n#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__)\n#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__)\n#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__)\n\n#define WARN(...) DOCTEST_WARN(__VA_ARGS__)\n#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__)\n#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__)\n#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__)\n#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__)\n#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__)\n#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__)\n#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__)\n#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__)\n#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__)\n#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__)\n#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__)\n#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__)\n#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__)\n#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__)\n#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__)\n#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__)\n#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__)\n#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__)\n#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__)\n#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__)\n\n#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__)\n#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__)\n#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__)\n#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)\n#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)\n#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)\n#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__)\n#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__)\n#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__)\n#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__)\n#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)\n#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)\n#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)\n#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__)\n#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__)\n#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__)\n#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__)\n#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)\n#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)\n#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)\n#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__)\n\n#define SCENARIO(name) DOCTEST_SCENARIO(name)\n#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name)\n#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__)\n#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id)\n#define GIVEN(name) DOCTEST_GIVEN(name)\n#define WHEN(name) DOCTEST_WHEN(name)\n#define AND_WHEN(name) DOCTEST_AND_WHEN(name)\n#define THEN(name) DOCTEST_THEN(name)\n#define AND_THEN(name) DOCTEST_AND_THEN(name)\n\n#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__)\n#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__)\n#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__)\n#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__)\n#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__)\n#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__)\n#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__)\n#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__)\n#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__)\n#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__)\n#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__)\n#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__)\n#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__)\n#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__)\n#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__)\n#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__)\n#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__)\n#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__)\n#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__)\n#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__)\n#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__)\n#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__)\n#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__)\n#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__)\n\n// KEPT FOR BACKWARDS COMPATIBILITY\n#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__)\n#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__)\n#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__)\n#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__)\n#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__)\n#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__)\n#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__)\n#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__)\n#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__)\n#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__)\n#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__)\n#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__)\n#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__)\n#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__)\n#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__)\n#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__)\n#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__)\n#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__)\n\n#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__)\n#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__)\n#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__)\n#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__)\n#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__)\n#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__)\n\n#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__)\n\n#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES\n\n#if !defined(DOCTEST_CONFIG_DISABLE)\n\n// this is here to clear the 'current test suite' for the current translation unit - at the top\nDOCTEST_TEST_SUITE_END();\n\n// add stringification for primitive/fundamental types\nnamespace doctest { namespace detail {\n    DOCTEST_TYPE_TO_STRING_IMPL(bool)\n    DOCTEST_TYPE_TO_STRING_IMPL(float)\n    DOCTEST_TYPE_TO_STRING_IMPL(double)\n    DOCTEST_TYPE_TO_STRING_IMPL(long double)\n    DOCTEST_TYPE_TO_STRING_IMPL(char)\n    DOCTEST_TYPE_TO_STRING_IMPL(signed char)\n    DOCTEST_TYPE_TO_STRING_IMPL(unsigned char)\n#if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED)\n    DOCTEST_TYPE_TO_STRING_IMPL(wchar_t)\n#endif // not MSVC or wchar_t support enabled\n    DOCTEST_TYPE_TO_STRING_IMPL(short int)\n    DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int)\n    DOCTEST_TYPE_TO_STRING_IMPL(int)\n    DOCTEST_TYPE_TO_STRING_IMPL(unsigned int)\n    DOCTEST_TYPE_TO_STRING_IMPL(long int)\n    DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int)\n    DOCTEST_TYPE_TO_STRING_IMPL(long long int)\n    DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int)\n}} // namespace doctest::detail\n\n#endif // DOCTEST_CONFIG_DISABLE\n\nDOCTEST_CLANG_SUPPRESS_WARNING_POP\nDOCTEST_MSVC_SUPPRESS_WARNING_POP\nDOCTEST_GCC_SUPPRESS_WARNING_POP\n\nDOCTEST_SUPPRESS_COMMON_WARNINGS_POP\n\n#endif // DOCTEST_LIBRARY_INCLUDED\n\n#ifndef DOCTEST_SINGLE_HEADER\n#define DOCTEST_SINGLE_HEADER\n#endif // DOCTEST_SINGLE_HEADER\n\n#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER)\n\n#ifndef DOCTEST_SINGLE_HEADER\n#include \"doctest_fwd.h\"\n#endif // DOCTEST_SINGLE_HEADER\n\nDOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wunused-macros\")\n\n#ifndef DOCTEST_LIBRARY_IMPLEMENTATION\n#define DOCTEST_LIBRARY_IMPLEMENTATION\n\nDOCTEST_CLANG_SUPPRESS_WARNING_POP\n\nDOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH\n\nDOCTEST_CLANG_SUPPRESS_WARNING_PUSH\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wglobal-constructors\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wexit-time-destructors\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wsign-conversion\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wshorten-64-to-32\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wmissing-variable-declarations\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wswitch\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wswitch-enum\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wcovered-switch-default\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wmissing-noreturn\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wdisabled-macro-expansion\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wmissing-braces\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wmissing-field-initializers\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wunused-member-function\")\nDOCTEST_CLANG_SUPPRESS_WARNING(\"-Wnonportable-system-include-path\")\n\nDOCTEST_GCC_SUPPRESS_WARNING_PUSH\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wconversion\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wsign-conversion\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wmissing-field-initializers\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wmissing-braces\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wswitch\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wswitch-enum\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wswitch-default\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wunsafe-loop-optimizations\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wold-style-cast\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wunused-function\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wmultiple-inheritance\")\nDOCTEST_GCC_SUPPRESS_WARNING(\"-Wsuggest-attribute\")\n\nDOCTEST_MSVC_SUPPRESS_WARNING_PUSH\nDOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data\nDOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled\nDOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified\nDOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal\nDOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch\nDOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C\nDOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning)\nDOCTEST_MSVC_SUPPRESS_WARNING(5245) // unreferenced function with internal linkage has been removed\n\nDOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN\n\n// required includes - will go only in one translation unit!\n#include <ctime>\n#include <cmath>\n#include <climits>\n// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/doctest/doctest/pull/37\n#ifdef __BORLANDC__\n#include <math.h>\n#endif // __BORLANDC__\n#include <new>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <limits>\n#include <utility>\n#include <fstream>\n#include <sstream>\n#include <iostream>\n#include <algorithm>\n#include <iomanip>\n#include <vector>\n#include <atomic>\n#include <mutex>\n#include <set>\n#include <map>\n#include <exception>\n#include <stdexcept>\n#include <csignal>\n#include <cfloat>\n#include <cctype>\n#include <cstdint>\n\n#ifdef DOCTEST_PLATFORM_MAC\n#include <sys/types.h>\n#include <unistd.h>\n#include <sys/sysctl.h>\n#endif // DOCTEST_PLATFORM_MAC\n\n#ifdef DOCTEST_PLATFORM_WINDOWS\n\n// defines for a leaner windows.h\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif // WIN32_LEAN_AND_MEAN\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif // NOMINMAX\n\n// not sure what AfxWin.h is for - here I do what Catch does\n#ifdef __AFXDLL\n#include <AfxWin.h>\n#else\n#include <windows.h>\n#endif\n#include <io.h>\n\n#else // DOCTEST_PLATFORM_WINDOWS\n\n#include <sys/time.h>\n#include <unistd.h>\n\n#endif // DOCTEST_PLATFORM_WINDOWS\n\n// this is a fix for https://github.com/doctest/doctest/issues/348\n// https://mail.gnome.org/archives/xml/2012-January/msg00000.html\n#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO)\n#define STDOUT_FILENO fileno(stdout)\n#endif // HAVE_UNISTD_H\n\nDOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END\n\n// counts the number of elements in a C array\n#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0]))\n\n#ifdef DOCTEST_CONFIG_DISABLE\n#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled\n#else // DOCTEST_CONFIG_DISABLE\n#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled\n#endif // DOCTEST_CONFIG_DISABLE\n\n#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX\n#define DOCTEST_CONFIG_OPTIONS_PREFIX \"dt-\"\n#endif\n\n#ifndef DOCTEST_THREAD_LOCAL\n#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0))\n#define DOCTEST_THREAD_LOCAL\n#else // DOCTEST_MSVC\n#define DOCTEST_THREAD_LOCAL thread_local\n#endif // DOCTEST_MSVC\n#endif // DOCTEST_THREAD_LOCAL\n\n#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES\n#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32\n#endif\n\n#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE\n#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64\n#endif\n\n#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS\n#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX\n#else\n#define DOCTEST_OPTIONS_PREFIX_DISPLAY \"\"\n#endif\n\n#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)\n#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS\n#endif\n\n#ifndef DOCTEST_CDECL\n#define DOCTEST_CDECL __cdecl\n#endif\n\nnamespace doctest {\n\nbool is_running_in_test = false;\n\nnamespace {\n    using namespace detail;\n\n    template <typename Ex>\n    DOCTEST_NORETURN void throw_exception(Ex const& e) {\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n        throw e;\n#else  // DOCTEST_CONFIG_NO_EXCEPTIONS\n        std::cerr << \"doctest will terminate because it needed to throw an exception.\\n\"\n                  << \"The message was: \" << e.what() << '\\n';\n        std::terminate();\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n    }\n\n#ifndef DOCTEST_INTERNAL_ERROR\n#define DOCTEST_INTERNAL_ERROR(msg)                                                                \\\n    throw_exception(std::logic_error(                                                              \\\n            __FILE__ \":\" DOCTEST_TOSTR(__LINE__) \": Internal doctest error: \" msg))\n#endif // DOCTEST_INTERNAL_ERROR\n\n    // case insensitive strcmp\n    int stricmp(const char* a, const char* b) {\n        for(;; a++, b++) {\n            const int d = tolower(*a) - tolower(*b);\n            if(d != 0 || !*a)\n                return d;\n        }\n    }\n\n    template <typename T>\n    String fpToString(T value, int precision) {\n        std::ostringstream oss;\n        oss << std::setprecision(precision) << std::fixed << value;\n        std::string d = oss.str();\n        size_t      i = d.find_last_not_of('0');\n        if(i != std::string::npos && i != d.size() - 1) {\n            if(d[i] == '.')\n                i++;\n            d = d.substr(0, i + 1);\n        }\n        return d.c_str();\n    }\n\n    struct Endianness\n    {\n        enum Arch\n        {\n            Big,\n            Little\n        };\n\n        static Arch which() {\n            int x = 1;\n            // casting any data pointer to char* is allowed\n            auto ptr = reinterpret_cast<char*>(&x);\n            if(*ptr)\n                return Little;\n            return Big;\n        }\n    };\n} // namespace\n\nnamespace detail {\n    String rawMemoryToString(const void* object, unsigned size) {\n        // Reverse order for little endian architectures\n        int i = 0, end = static_cast<int>(size), inc = 1;\n        if(Endianness::which() == Endianness::Little) {\n            i   = end - 1;\n            end = inc = -1;\n        }\n\n        unsigned const char* bytes = static_cast<unsigned const char*>(object);\n        std::ostream*        oss   = tlssPush();\n        *oss << \"0x\" << std::setfill('0') << std::hex;\n        for(; i != end; i += inc)\n            *oss << std::setw(2) << static_cast<unsigned>(bytes[i]);\n        return tlssPop();\n    }\n\n    DOCTEST_THREAD_LOCAL class\n    {\n        std::vector<std::streampos> stack;\n        std::stringstream           ss;\n\n    public:\n        std::ostream* push() {\n            stack.push_back(ss.tellp());\n            return &ss;\n        }\n\n        String pop() {\n            if (stack.empty())\n                DOCTEST_INTERNAL_ERROR(\"TLSS was empty when trying to pop!\");\n\n            std::streampos pos = stack.back();\n            stack.pop_back();\n            unsigned sz = static_cast<unsigned>(ss.tellp() - pos);\n            ss.rdbuf()->pubseekpos(pos, std::ios::in | std::ios::out);\n            return String(ss, sz);\n        }\n    } g_oss;\n\n    std::ostream* tlssPush() {\n        return g_oss.push();\n    }\n\n    String tlssPop() {\n        return g_oss.pop();\n    }\n\n#ifndef DOCTEST_CONFIG_DISABLE\n\nnamespace timer_large_integer\n{\n    \n#if defined(DOCTEST_PLATFORM_WINDOWS)\n    typedef ULONGLONG type;\n#else // DOCTEST_PLATFORM_WINDOWS\n    typedef std::uint64_t type;\n#endif // DOCTEST_PLATFORM_WINDOWS\n}\n\ntypedef timer_large_integer::type ticks_t;\n\n#ifdef DOCTEST_CONFIG_GETCURRENTTICKS\n    ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); }\n#elif defined(DOCTEST_PLATFORM_WINDOWS)\n    ticks_t getCurrentTicks() {\n        static LARGE_INTEGER hz = {0}, hzo = {0};\n        if(!hz.QuadPart) {\n            QueryPerformanceFrequency(&hz);\n            QueryPerformanceCounter(&hzo);\n        }\n        LARGE_INTEGER t;\n        QueryPerformanceCounter(&t);\n        return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart;\n    }\n#else  // DOCTEST_PLATFORM_WINDOWS\n    ticks_t getCurrentTicks() {\n        timeval t;\n        gettimeofday(&t, nullptr);\n        return static_cast<ticks_t>(t.tv_sec) * 1000000 + static_cast<ticks_t>(t.tv_usec);\n    }\n#endif // DOCTEST_PLATFORM_WINDOWS\n\n    struct Timer\n    {\n        void         start() { m_ticks = getCurrentTicks(); }\n        unsigned int getElapsedMicroseconds() const {\n            return static_cast<unsigned int>(getCurrentTicks() - m_ticks);\n        }\n        //unsigned int getElapsedMilliseconds() const {\n        //    return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);\n        //}\n        double getElapsedSeconds() const { return static_cast<double>(getCurrentTicks() - m_ticks) / 1000000.0; }\n\n    private:\n        ticks_t m_ticks = 0;\n    };\n\n#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS\n    template <typename T>\n    using AtomicOrMultiLaneAtomic = std::atomic<T>;\n#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS\n    // Provides a multilane implementation of an atomic variable that supports add, sub, load,\n    // store. Instead of using a single atomic variable, this splits up into multiple ones,\n    // each sitting on a separate cache line. The goal is to provide a speedup when most\n    // operations are modifying. It achieves this with two properties:\n    //\n    // * Multiple atomics are used, so chance of congestion from the same atomic is reduced.\n    // * Each atomic sits on a separate cache line, so false sharing is reduced.\n    //\n    // The disadvantage is that there is a small overhead due to the use of TLS, and load/store\n    // is slower because all atomics have to be accessed.\n    template <typename T>\n    class MultiLaneAtomic\n    {\n        struct CacheLineAlignedAtomic\n        {\n            std::atomic<T> atomic{};\n            char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];\n        };\n        CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];\n\n        static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE,\n                      \"guarantee one atomic takes exactly one cache line\");\n\n    public:\n        T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }\n\n        T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }\n\n        T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {\n            return myAtomic().fetch_add(arg, order);\n        }\n\n        T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {\n            return myAtomic().fetch_sub(arg, order);\n        }\n\n        operator T() const DOCTEST_NOEXCEPT { return load(); }\n\n        T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {\n            auto result = T();\n            for(auto const& c : m_atomics) {\n                result += c.atomic.load(order);\n            }\n            return result;\n        }\n\n        T operator=(T desired) DOCTEST_NOEXCEPT { // lgtm [cpp/assignment-does-not-return-this]\n            store(desired);\n            return desired;\n        }\n\n        void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {\n            // first value becomes desired\", all others become 0.\n            for(auto& c : m_atomics) {\n                c.atomic.store(desired, order);\n                desired = {};\n            }\n        }\n\n    private:\n        // Each thread has a different atomic that it operates on. If more than NumLanes threads\n        // use this, some will use the same atomic. So performance will degrade a bit, but still\n        // everything will work.\n        //\n        // The logic here is a bit tricky. The call should be as fast as possible, so that there\n        // is minimal to no overhead in determining the correct atomic for the current thread.\n        //\n        // 1. A global static counter laneCounter counts continuously up.\n        // 2. Each successive thread will use modulo operation of that counter so it gets an atomic\n        //    assigned in a round-robin fashion.\n        // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with\n        //    little overhead.\n        std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {\n            static std::atomic<size_t> laneCounter;\n            DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =\n                    laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;\n\n            return m_atomics[tlsLaneIdx].atomic;\n        }\n    };\n\n    template <typename T>\n    using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>;\n#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS\n\n    // this holds both parameters from the command line and runtime data for tests\n    struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats\n    {\n        AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;\n        AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;\n\n        std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters\n\n        std::vector<IReporter*> reporters_currently_used;\n\n        assert_handler ah = nullptr;\n\n        Timer timer;\n\n        std::vector<String> stringifiedContexts; // logging from INFO() due to an exception\n\n        // stuff for subcases\n        std::vector<SubcaseSignature>     subcasesStack;\n        std::set<decltype(subcasesStack)> subcasesPassed;\n        int                               subcasesCurrentMaxLevel;\n        bool                              should_reenter;\n        std::atomic<bool>                 shouldLogCurrentException;\n\n        void resetRunData() {\n            numTestCases                = 0;\n            numTestCasesPassingFilters  = 0;\n            numTestSuitesPassingFilters = 0;\n            numTestCasesFailed          = 0;\n            numAsserts                  = 0;\n            numAssertsFailed            = 0;\n            numAssertsCurrentTest       = 0;\n            numAssertsFailedCurrentTest = 0;\n        }\n\n        void finalizeTestCaseData() {\n            seconds = timer.getElapsedSeconds();\n\n            // update the non-atomic counters\n            numAsserts += numAssertsCurrentTest_atomic;\n            numAssertsFailed += numAssertsFailedCurrentTest_atomic;\n            numAssertsCurrentTest       = numAssertsCurrentTest_atomic;\n            numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic;\n\n            if(numAssertsFailedCurrentTest)\n                failure_flags |= TestCaseFailureReason::AssertFailure;\n\n            if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 &&\n               Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout)\n                failure_flags |= TestCaseFailureReason::Timeout;\n\n            if(currentTest->m_should_fail) {\n                if(failure_flags) {\n                    failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid;\n                } else {\n                    failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt;\n                }\n            } else if(failure_flags && currentTest->m_may_fail) {\n                failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid;\n            } else if(currentTest->m_expected_failures > 0) {\n                if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) {\n                    failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes;\n                } else {\n                    failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes;\n                }\n            }\n\n            bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) ||\n                              (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) ||\n                              (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags);\n\n            // if any subcase has failed - the whole test case has failed\n            testCaseSuccess = !(failure_flags && !ok_to_fail);\n            if(!testCaseSuccess)\n                numTestCasesFailed++;\n        }\n    };\n\n    ContextState* g_cs = nullptr;\n\n    // used to avoid locks for the debug output\n    // TODO: figure out if this is indeed necessary/correct - seems like either there still\n    // could be a race or that there wouldn't be a race even if using the context directly\n    DOCTEST_THREAD_LOCAL bool g_no_colors;\n\n#endif // DOCTEST_CONFIG_DISABLE\n} // namespace detail\n\nchar* String::allocate(unsigned sz) {\n    if (sz <= last) {\n        buf[sz] = '\\0';\n        setLast(last - sz);\n        return buf;\n    } else {\n        setOnHeap();\n        data.size = sz;\n        data.capacity = data.size + 1;\n        data.ptr = new char[data.capacity];\n        data.ptr[sz] = '\\0';\n        return data.ptr;\n    }\n}\n\nvoid String::setOnHeap() { *reinterpret_cast<unsigned char*>(&buf[last]) = 128; }\nvoid String::setLast(unsigned in) { buf[last] = char(in); }\n\nvoid String::copy(const String& other) {\n    if(other.isOnStack()) {\n        memcpy(buf, other.buf, len);\n    } else {\n        memcpy(allocate(other.data.size), other.data.ptr, other.data.size);\n    }\n}\n\nString::String() {\n    buf[0] = '\\0';\n    setLast();\n}\n\nString::~String() {\n    if(!isOnStack())\n        delete[] data.ptr;\n    // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n}\n\nString::String(const char* in)\n        : String(in, strlen(in)) {}\n\nString::String(const char* in, unsigned in_size) {\n    memcpy(allocate(in_size), in, in_size);\n}\n\nString::String(std::istream& in, unsigned in_size) {\n    in.read(allocate(in_size), in_size);\n}\n\nString::String(const String& other) { copy(other); }\n\nString& String::operator=(const String& other) {\n    if(this != &other) {\n        if(!isOnStack())\n            delete[] data.ptr;\n\n        copy(other);\n    }\n\n    return *this;\n}\n\nString& String::operator+=(const String& other) {\n    const unsigned my_old_size = size();\n    const unsigned other_size  = other.size();\n    const unsigned total_size  = my_old_size + other_size;\n    if(isOnStack()) {\n        if(total_size < len) {\n            // append to the current stack space\n            memcpy(buf + my_old_size, other.c_str(), other_size + 1);\n            // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n            setLast(last - total_size);\n        } else {\n            // alloc new chunk\n            char* temp = new char[total_size + 1];\n            // copy current data to new location before writing in the union\n            memcpy(temp, buf, my_old_size); // skip the +1 ('\\0') for speed\n            // update data in union\n            setOnHeap();\n            data.size     = total_size;\n            data.capacity = data.size + 1;\n            data.ptr      = temp;\n            // transfer the rest of the data\n            memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);\n        }\n    } else {\n        if(data.capacity > total_size) {\n            // append to the current heap block\n            data.size = total_size;\n            memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);\n        } else {\n            // resize\n            data.capacity *= 2;\n            if(data.capacity <= total_size)\n                data.capacity = total_size + 1;\n            // alloc new chunk\n            char* temp = new char[data.capacity];\n            // copy current data to new location before releasing it\n            memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\\0') for speed\n            // release old chunk\n            delete[] data.ptr;\n            // update the rest of the union members\n            data.size = total_size;\n            data.ptr  = temp;\n            // transfer the rest of the data\n            memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1);\n        }\n    }\n\n    return *this;\n}\n\nString::String(String&& other) {\n    memcpy(buf, other.buf, len);\n    other.buf[0] = '\\0';\n    other.setLast();\n}\n\nString& String::operator=(String&& other) {\n    if(this != &other) {\n        if(!isOnStack())\n            delete[] data.ptr;\n        memcpy(buf, other.buf, len);\n        other.buf[0] = '\\0';\n        other.setLast();\n    }\n    return *this;\n}\n\nchar String::operator[](unsigned i) const {\n    return const_cast<String*>(this)->operator[](i); // NOLINT\n}\n\nchar& String::operator[](unsigned i) {\n    if(isOnStack())\n        return reinterpret_cast<char*>(buf)[i];\n    return data.ptr[i];\n}\n\nDOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wmaybe-uninitialized\")\nunsigned String::size() const {\n    if(isOnStack())\n        return last - (unsigned(buf[last]) & 31); // using \"last\" would work only if \"len\" is 32\n    return data.size;\n}\nDOCTEST_GCC_SUPPRESS_WARNING_POP\n\nunsigned String::capacity() const {\n    if(isOnStack())\n        return len;\n    return data.capacity;\n}\n\nint String::compare(const char* other, bool no_case) const {\n    if(no_case)\n        return doctest::stricmp(c_str(), other);\n    return std::strcmp(c_str(), other);\n}\n\nint String::compare(const String& other, bool no_case) const {\n    return compare(other.c_str(), no_case);\n}\n\n// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\nString operator+(const String& lhs, const String& rhs) { return  String(lhs) += rhs; }\n\n// clang-format off\nbool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; }\nbool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; }\nbool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; }\nbool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; }\nbool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; }\nbool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; }\n// clang-format on\n\nstd::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); }\n\nnamespace {\n    void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;)\n} // namespace\n\nnamespace Color {\n    std::ostream& operator<<(std::ostream& s, Color::Enum code) {\n        color_to_stream(s, code);\n        return s;\n    }\n} // namespace Color\n\n// clang-format off\nconst char* assertString(assertType::Enum at) {\n    DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4062) // enum 'x' in switch of enum 'y' is not handled\n    switch(at) {  //!OCLINT missing default in switch statements\n        case assertType::DT_WARN                    : return \"WARN\";\n        case assertType::DT_CHECK                   : return \"CHECK\";\n        case assertType::DT_REQUIRE                 : return \"REQUIRE\";\n\n        case assertType::DT_WARN_FALSE              : return \"WARN_FALSE\";\n        case assertType::DT_CHECK_FALSE             : return \"CHECK_FALSE\";\n        case assertType::DT_REQUIRE_FALSE           : return \"REQUIRE_FALSE\";\n\n        case assertType::DT_WARN_THROWS             : return \"WARN_THROWS\";\n        case assertType::DT_CHECK_THROWS            : return \"CHECK_THROWS\";\n        case assertType::DT_REQUIRE_THROWS          : return \"REQUIRE_THROWS\";\n\n        case assertType::DT_WARN_THROWS_AS          : return \"WARN_THROWS_AS\";\n        case assertType::DT_CHECK_THROWS_AS         : return \"CHECK_THROWS_AS\";\n        case assertType::DT_REQUIRE_THROWS_AS       : return \"REQUIRE_THROWS_AS\";\n\n        case assertType::DT_WARN_THROWS_WITH        : return \"WARN_THROWS_WITH\";\n        case assertType::DT_CHECK_THROWS_WITH       : return \"CHECK_THROWS_WITH\";\n        case assertType::DT_REQUIRE_THROWS_WITH     : return \"REQUIRE_THROWS_WITH\";\n\n        case assertType::DT_WARN_THROWS_WITH_AS     : return \"WARN_THROWS_WITH_AS\";\n        case assertType::DT_CHECK_THROWS_WITH_AS    : return \"CHECK_THROWS_WITH_AS\";\n        case assertType::DT_REQUIRE_THROWS_WITH_AS  : return \"REQUIRE_THROWS_WITH_AS\";\n\n        case assertType::DT_WARN_NOTHROW            : return \"WARN_NOTHROW\";\n        case assertType::DT_CHECK_NOTHROW           : return \"CHECK_NOTHROW\";\n        case assertType::DT_REQUIRE_NOTHROW         : return \"REQUIRE_NOTHROW\";\n\n        case assertType::DT_WARN_EQ                 : return \"WARN_EQ\";\n        case assertType::DT_CHECK_EQ                : return \"CHECK_EQ\";\n        case assertType::DT_REQUIRE_EQ              : return \"REQUIRE_EQ\";\n        case assertType::DT_WARN_NE                 : return \"WARN_NE\";\n        case assertType::DT_CHECK_NE                : return \"CHECK_NE\";\n        case assertType::DT_REQUIRE_NE              : return \"REQUIRE_NE\";\n        case assertType::DT_WARN_GT                 : return \"WARN_GT\";\n        case assertType::DT_CHECK_GT                : return \"CHECK_GT\";\n        case assertType::DT_REQUIRE_GT              : return \"REQUIRE_GT\";\n        case assertType::DT_WARN_LT                 : return \"WARN_LT\";\n        case assertType::DT_CHECK_LT                : return \"CHECK_LT\";\n        case assertType::DT_REQUIRE_LT              : return \"REQUIRE_LT\";\n        case assertType::DT_WARN_GE                 : return \"WARN_GE\";\n        case assertType::DT_CHECK_GE                : return \"CHECK_GE\";\n        case assertType::DT_REQUIRE_GE              : return \"REQUIRE_GE\";\n        case assertType::DT_WARN_LE                 : return \"WARN_LE\";\n        case assertType::DT_CHECK_LE                : return \"CHECK_LE\";\n        case assertType::DT_REQUIRE_LE              : return \"REQUIRE_LE\";\n\n        case assertType::DT_WARN_UNARY              : return \"WARN_UNARY\";\n        case assertType::DT_CHECK_UNARY             : return \"CHECK_UNARY\";\n        case assertType::DT_REQUIRE_UNARY           : return \"REQUIRE_UNARY\";\n        case assertType::DT_WARN_UNARY_FALSE        : return \"WARN_UNARY_FALSE\";\n        case assertType::DT_CHECK_UNARY_FALSE       : return \"CHECK_UNARY_FALSE\";\n        case assertType::DT_REQUIRE_UNARY_FALSE     : return \"REQUIRE_UNARY_FALSE\";\n    }\n    DOCTEST_MSVC_SUPPRESS_WARNING_POP\n    return \"\";\n}\n// clang-format on\n\nconst char* failureString(assertType::Enum at) {\n    if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional\n        return \"WARNING\";\n    if(at & assertType::is_check) //!OCLINT bitwise operator in conditional\n        return \"ERROR\";\n    if(at & assertType::is_require) //!OCLINT bitwise operator in conditional\n        return \"FATAL ERROR\";\n    return \"\";\n}\n\nDOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wnull-dereference\")\nDOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wnull-dereference\")\n// depending on the current options this will remove the path of filenames\nconst char* skipPathFromFilename(const char* file) {\n#ifndef DOCTEST_CONFIG_DISABLE\n    if(getContextOptions()->no_path_in_filenames) {\n        auto back    = std::strrchr(file, '\\\\');\n        auto forward = std::strrchr(file, '/');\n        if(back || forward) {\n            if(back > forward)\n                forward = back;\n            return forward + 1;\n        }\n    }\n#endif // DOCTEST_CONFIG_DISABLE\n    return file;\n}\nDOCTEST_CLANG_SUPPRESS_WARNING_POP\nDOCTEST_GCC_SUPPRESS_WARNING_POP\n\nbool SubcaseSignature::operator<(const SubcaseSignature& other) const {\n    if(m_line != other.m_line)\n        return m_line < other.m_line;\n    if(std::strcmp(m_file, other.m_file) != 0)\n        return std::strcmp(m_file, other.m_file) < 0;\n    return m_name.compare(other.m_name) < 0;\n}\n\nIContextScope::IContextScope()  = default;\nIContextScope::~IContextScope() = default;\n\n#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\nString toString(char* in) { return toString(static_cast<const char*>(in)); }\n// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\nString toString(const char* in) { return String(\"\\\"\") + (in ? in : \"{null string}\") + \"\\\"\"; }\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\nString toString(bool in) { return in ? \"true\" : \"false\"; }\nString toString(float in) { return fpToString(in, 5) + \"f\"; }\nString toString(double in) { return fpToString(in, 10); }\nString toString(double long in) { return fpToString(in, 15); }\n\n#define DOCTEST_TO_STRING_OVERLOAD(type, fmt)                                                      \\\n    String toString(type in) {                                                                     \\\n        char buf[64];                                                                              \\\n        std::sprintf(buf, fmt, in);                                                                \\\n        return buf;                                                                                \\\n    }\n\nDOCTEST_TO_STRING_OVERLOAD(char, \"%d\")\nDOCTEST_TO_STRING_OVERLOAD(char signed, \"%d\")\nDOCTEST_TO_STRING_OVERLOAD(char unsigned, \"%u\")\nDOCTEST_TO_STRING_OVERLOAD(int short, \"%d\")\nDOCTEST_TO_STRING_OVERLOAD(int short unsigned, \"%u\")\nDOCTEST_TO_STRING_OVERLOAD(int, \"%d\")\nDOCTEST_TO_STRING_OVERLOAD(unsigned, \"%u\")\nDOCTEST_TO_STRING_OVERLOAD(int long, \"%ld\")\nDOCTEST_TO_STRING_OVERLOAD(int long unsigned, \"%lu\")\nDOCTEST_TO_STRING_OVERLOAD(int long long, \"%lld\")\nDOCTEST_TO_STRING_OVERLOAD(int long long unsigned, \"%llu\")\n\nString toString(std::nullptr_t) { return \"NULL\"; }\n\n#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)\n// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183\nString toString(const std::string& in) { return in.c_str(); }\n#endif // VS 2019\n\nApprox::Approx(double value)\n        : m_epsilon(static_cast<double>(std::numeric_limits<float>::epsilon()) * 100)\n        , m_scale(1.0)\n        , m_value(value) {}\n\nApprox Approx::operator()(double value) const {\n    Approx approx(value);\n    approx.epsilon(m_epsilon);\n    approx.scale(m_scale);\n    return approx;\n}\n\nApprox& Approx::epsilon(double newEpsilon) {\n    m_epsilon = newEpsilon;\n    return *this;\n}\nApprox& Approx::scale(double newScale) {\n    m_scale = newScale;\n    return *this;\n}\n\nbool operator==(double lhs, const Approx& rhs) {\n    // Thanks to Richard Harris for his help refining this formula\n    return std::fabs(lhs - rhs.m_value) <\n           rhs.m_epsilon * (rhs.m_scale + std::max<double>(std::fabs(lhs), std::fabs(rhs.m_value)));\n}\nbool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); }\nbool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); }\nbool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); }\nbool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; }\nbool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; }\nbool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; }\nbool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; }\nbool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; }\nbool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; }\nbool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; }\nbool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; }\n\nString toString(const Approx& in) {\n    // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n    return \"Approx( \" + doctest::toString(in.m_value) + \" )\";\n}\nconst ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }\n\n} // namespace doctest\n\n#ifdef DOCTEST_CONFIG_DISABLE\nnamespace doctest {\nContext::Context(int, const char* const*) {}\nContext::~Context() = default;\nvoid Context::applyCommandLine(int, const char* const*) {}\nvoid Context::addFilter(const char*, const char*) {}\nvoid Context::clearFilters() {}\nvoid Context::setOption(const char*, bool) {}\nvoid Context::setOption(const char*, int) {}\nvoid Context::setOption(const char*, const char*) {}\nbool Context::shouldExit() { return false; }\nvoid Context::setAsDefaultForAssertsOutOfTestCases() {}\nvoid Context::setAssertHandler(detail::assert_handler) {}\nvoid Context::setCout(std::ostream* out) {}\nint  Context::run() { return 0; }\n\nIReporter::~IReporter() = default;\n\nint                         IReporter::get_num_active_contexts() { return 0; }\nconst IContextScope* const* IReporter::get_active_contexts() { return nullptr; }\nint                         IReporter::get_num_stringified_contexts() { return 0; }\nconst String*               IReporter::get_stringified_contexts() { return nullptr; }\n\nint registerReporter(const char*, int, IReporter*) { return 0; }\n\n} // namespace doctest\n#else // DOCTEST_CONFIG_DISABLE\n\n#if !defined(DOCTEST_CONFIG_COLORS_NONE)\n#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI)\n#ifdef DOCTEST_PLATFORM_WINDOWS\n#define DOCTEST_CONFIG_COLORS_WINDOWS\n#else // linux\n#define DOCTEST_CONFIG_COLORS_ANSI\n#endif // platform\n#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI\n#endif // DOCTEST_CONFIG_COLORS_NONE\n\nnamespace doctest_detail_test_suite_ns {\n// holds the current test suite\ndoctest::detail::TestSuite& getCurrentTestSuite() {\n    static doctest::detail::TestSuite data{};\n    return data;\n}\n} // namespace doctest_detail_test_suite_ns\n\nnamespace doctest {\nnamespace {\n    // the int (priority) is part of the key for automatic sorting - sadly one can register a\n    // reporter with a duplicate name and a different priority but hopefully that won't happen often :|\n    typedef std::map<std::pair<int, String>, reporterCreatorFunc> reporterMap;\n\n    reporterMap& getReporters() {\n        static reporterMap data;\n        return data;\n    }\n    reporterMap& getListeners() {\n        static reporterMap data;\n        return data;\n    }\n} // namespace\nnamespace detail {\n#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...)                                           \\\n    for(auto& curr_rep : g_cs->reporters_currently_used)                                           \\\n    curr_rep->function(__VA_ARGS__)\n\n    bool checkIfShouldThrow(assertType::Enum at) {\n        if(at & assertType::is_require) //!OCLINT bitwise operator in conditional\n            return true;\n\n        if((at & assertType::is_check) //!OCLINT bitwise operator in conditional\n           && getContextOptions()->abort_after > 0 &&\n           (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >=\n                   getContextOptions()->abort_after)\n            return true;\n\n        return false;\n    }\n\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n    DOCTEST_NORETURN void throwException() {\n        g_cs->shouldLogCurrentException = false;\n        throw TestFailureException();\n    } // NOLINT(cert-err60-cpp)\n#else // DOCTEST_CONFIG_NO_EXCEPTIONS\n    void throwException() {}\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n} // namespace detail\n\nnamespace {\n    using namespace detail;\n    // matching of a string against a wildcard mask (case sensitivity configurable) taken from\n    // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing\n    int wildcmp(const char* str, const char* wild, bool caseSensitive) {\n        const char* cp = str;\n        const char* mp = wild;\n\n        while((*str) && (*wild != '*')) {\n            if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) &&\n               (*wild != '?')) {\n                return 0;\n            }\n            wild++;\n            str++;\n        }\n\n        while(*str) {\n            if(*wild == '*') {\n                if(!*++wild) {\n                    return 1;\n                }\n                mp = wild;\n                cp = str + 1;\n            } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) ||\n                      (*wild == '?')) {\n                wild++;\n                str++;\n            } else {\n                wild = mp;   //!OCLINT parameter reassignment\n                str  = cp++; //!OCLINT parameter reassignment\n            }\n        }\n\n        while(*wild == '*') {\n            wild++;\n        }\n        return !*wild;\n    }\n\n    //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html\n    //unsigned hashStr(unsigned const char* str) {\n    //    unsigned long hash = 5381;\n    //    char          c;\n    //    while((c = *str++))\n    //        hash = ((hash << 5) + hash) + c; // hash * 33 + c\n    //    return hash;\n    //}\n\n    // checks if the name matches any of the filters (and can be configured what to do when empty)\n    bool matchesAny(const char* name, const std::vector<String>& filters, bool matchEmpty,\n                    bool caseSensitive) {\n        if(filters.empty() && matchEmpty)\n            return true;\n        for(auto& curr : filters)\n            if(wildcmp(name, curr.c_str(), caseSensitive))\n                return true;\n        return false;\n    }\n} // namespace\nnamespace detail {\n\n    Subcase::Subcase(const String& name, const char* file, int line)\n            : m_signature({name, file, line}) {\n        auto* s = g_cs;\n\n        // check subcase filters\n        if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) {\n            if(!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive))\n                return;\n            if(matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive))\n                return;\n        }\n        \n        // if a Subcase on the same level has already been entered\n        if(s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) {\n            s->should_reenter = true;\n            return;\n        }\n\n        // push the current signature to the stack so we can check if the\n        // current stack + the current new subcase have been traversed\n        s->subcasesStack.push_back(m_signature);\n        if(s->subcasesPassed.count(s->subcasesStack) != 0) {\n            // pop - revert to previous stack since we've already passed this\n            s->subcasesStack.pop_back();\n            return;\n        }\n\n        s->subcasesCurrentMaxLevel = s->subcasesStack.size();\n        m_entered = true;\n\n        DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature);\n    }\n\n    DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17\n    DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wdeprecated-declarations\")\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wdeprecated-declarations\")\n\n    Subcase::~Subcase() {\n        if(m_entered) {\n            // only mark the subcase stack as passed if no subcases have been skipped\n            if(g_cs->should_reenter == false)\n                g_cs->subcasesPassed.insert(g_cs->subcasesStack);\n            g_cs->subcasesStack.pop_back();\n\n#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)\n            if(std::uncaught_exceptions() > 0\n#else\n            if(std::uncaught_exception()\n#endif\n            && g_cs->shouldLogCurrentException) {\n                DOCTEST_ITERATE_THROUGH_REPORTERS(\n                        test_case_exception, {\"exception thrown in subcase - will translate later \"\n                                              \"when the whole test case has been exited (cannot \"\n                                              \"translate while there is an active exception)\",\n                                              false});\n                g_cs->shouldLogCurrentException = false;\n            }\n            DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY);\n        }\n    }\n\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n    DOCTEST_GCC_SUPPRESS_WARNING_POP\n    DOCTEST_MSVC_SUPPRESS_WARNING_POP\n\n    Subcase::operator bool() const { return m_entered; }\n\n    Result::Result(bool passed, const String& decomposition)\n            : m_passed(passed)\n            , m_decomp(decomposition) {}\n\n    ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at)\n            : m_at(at) {}\n\n    TestSuite& TestSuite::operator*(const char* in) {\n        m_test_suite = in;\n        return *this;\n    }\n\n    TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite,\n                       const char* type, int template_id) {\n        m_file              = file;\n        m_line              = line;\n        m_name              = nullptr; // will be later overridden in operator*\n        m_test_suite        = test_suite.m_test_suite;\n        m_description       = test_suite.m_description;\n        m_skip              = test_suite.m_skip;\n        m_no_breaks         = test_suite.m_no_breaks;\n        m_no_output         = test_suite.m_no_output;\n        m_may_fail          = test_suite.m_may_fail;\n        m_should_fail       = test_suite.m_should_fail;\n        m_expected_failures = test_suite.m_expected_failures;\n        m_timeout           = test_suite.m_timeout;\n\n        m_test        = test;\n        m_type        = type;\n        m_template_id = template_id;\n    }\n\n    TestCase::TestCase(const TestCase& other)\n            : TestCaseData() {\n        *this = other;\n    }\n\n    DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function\n    DOCTEST_MSVC_SUPPRESS_WARNING(26437)           // Do not slice\n    TestCase& TestCase::operator=(const TestCase& other) {\n        static_cast<TestCaseData&>(*this) = static_cast<const TestCaseData&>(other);\n\n        m_test        = other.m_test;\n        m_type        = other.m_type;\n        m_template_id = other.m_template_id;\n        m_full_name   = other.m_full_name;\n\n        if(m_template_id != -1)\n            m_name = m_full_name.c_str();\n        return *this;\n    }\n    DOCTEST_MSVC_SUPPRESS_WARNING_POP\n\n    TestCase& TestCase::operator*(const char* in) {\n        m_name = in;\n        // make a new name with an appended type for templated test case\n        if(m_template_id != -1) {\n            m_full_name = String(m_name) + m_type;\n            // redirect the name to point to the newly constructed full name\n            m_name = m_full_name.c_str();\n        }\n        return *this;\n    }\n\n    bool TestCase::operator<(const TestCase& other) const {\n        // this will be used only to differentiate between test cases - not relevant for sorting\n        if(m_line != other.m_line)\n            return m_line < other.m_line;\n        const int name_cmp = strcmp(m_name, other.m_name);\n        if(name_cmp != 0)\n            return name_cmp < 0;\n        const int file_cmp = m_file.compare(other.m_file);\n        if(file_cmp != 0)\n            return file_cmp < 0;\n        return m_template_id < other.m_template_id;\n    }\n\n    // all the registered tests\n    std::set<TestCase>& getRegisteredTests() {\n        static std::set<TestCase> data;\n        return data;\n    }\n} // namespace detail\nnamespace {\n    using namespace detail;\n    // for sorting tests by file/line\n    bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) {\n        // this is needed because MSVC gives different case for drive letters\n        // for __FILE__ when evaluated in a header and a source file\n        const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC));\n        if(res != 0)\n            return res < 0;\n        if(lhs->m_line != rhs->m_line)\n            return lhs->m_line < rhs->m_line;\n        return lhs->m_template_id < rhs->m_template_id;\n    }\n\n    // for sorting tests by suite/file/line\n    bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) {\n        const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite);\n        if(res != 0)\n            return res < 0;\n        return fileOrderComparator(lhs, rhs);\n    }\n\n    // for sorting tests by name/suite/file/line\n    bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) {\n        const int res = std::strcmp(lhs->m_name, rhs->m_name);\n        if(res != 0)\n            return res < 0;\n        return suiteOrderComparator(lhs, rhs);\n    }\n\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wdeprecated-declarations\")\n    void color_to_stream(std::ostream& s, Color::Enum code) {\n        static_cast<void>(s);    // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS\n        static_cast<void>(code); // for DOCTEST_CONFIG_COLORS_NONE\n#ifdef DOCTEST_CONFIG_COLORS_ANSI\n        if(g_no_colors ||\n           (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false))\n            return;\n\n        auto col = \"\";\n        // clang-format off\n            switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement\n                case Color::Red:         col = \"[0;31m\"; break;\n                case Color::Green:       col = \"[0;32m\"; break;\n                case Color::Blue:        col = \"[0;34m\"; break;\n                case Color::Cyan:        col = \"[0;36m\"; break;\n                case Color::Yellow:      col = \"[0;33m\"; break;\n                case Color::Grey:        col = \"[1;30m\"; break;\n                case Color::LightGrey:   col = \"[0;37m\"; break;\n                case Color::BrightRed:   col = \"[1;31m\"; break;\n                case Color::BrightGreen: col = \"[1;32m\"; break;\n                case Color::BrightWhite: col = \"[1;37m\"; break;\n                case Color::Bright: // invalid\n                case Color::None:\n                case Color::White:\n                default:                 col = \"[0m\";\n            }\n        // clang-format on\n        s << \"\\033\" << col;\n#endif // DOCTEST_CONFIG_COLORS_ANSI\n\n#ifdef DOCTEST_CONFIG_COLORS_WINDOWS\n        if(g_no_colors ||\n           (_isatty(_fileno(stdout)) == false && getContextOptions()->force_colors == false))\n            return;\n\n        static struct ConsoleHelper {\n            HANDLE stdoutHandle;\n            WORD   origFgAttrs;\n            WORD   origBgAttrs;\n\n            ConsoleHelper() {\n                stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);\n                CONSOLE_SCREEN_BUFFER_INFO csbiInfo;\n                GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo);\n                origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED |\n                    BACKGROUND_BLUE | BACKGROUND_INTENSITY);\n                origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED |\n                    FOREGROUND_BLUE | FOREGROUND_INTENSITY);\n            }\n        } ch;\n\n#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(ch.stdoutHandle, x | ch.origBgAttrs)\n\n        // clang-format off\n        switch (code) {\n            case Color::White:       DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break;\n            case Color::Red:         DOCTEST_SET_ATTR(FOREGROUND_RED);                                      break;\n            case Color::Green:       DOCTEST_SET_ATTR(FOREGROUND_GREEN);                                    break;\n            case Color::Blue:        DOCTEST_SET_ATTR(FOREGROUND_BLUE);                                     break;\n            case Color::Cyan:        DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN);                  break;\n            case Color::Yellow:      DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN);                   break;\n            case Color::Grey:        DOCTEST_SET_ATTR(0);                                                   break;\n            case Color::LightGrey:   DOCTEST_SET_ATTR(FOREGROUND_INTENSITY);                                break;\n            case Color::BrightRed:   DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED);               break;\n            case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN);             break;\n            case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break;\n            case Color::None:\n            case Color::Bright: // invalid\n            default:                 DOCTEST_SET_ATTR(ch.origFgAttrs);\n        }\n            // clang-format on\n#endif // DOCTEST_CONFIG_COLORS_WINDOWS\n    }\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n\n    std::vector<const IExceptionTranslator*>& getExceptionTranslators() {\n        static std::vector<const IExceptionTranslator*> data;\n        return data;\n    }\n\n    String translateActiveException() {\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n        String res;\n        auto&  translators = getExceptionTranslators();\n        for(auto& curr : translators)\n            if(curr->translate(res))\n                return res;\n        // clang-format off\n        DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wcatch-value\")\n        try {\n            throw;\n        } catch(std::exception& ex) {\n            return ex.what();\n        } catch(std::string& msg) {\n            return msg.c_str();\n        } catch(const char* msg) {\n            return msg;\n        } catch(...) {\n            return \"unknown exception\";\n        }\n        DOCTEST_GCC_SUPPRESS_WARNING_POP\n// clang-format on\n#else  // DOCTEST_CONFIG_NO_EXCEPTIONS\n        return \"\";\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n    }\n} // namespace\n\nnamespace detail {\n    // used by the macros for registering tests\n    int regTest(const TestCase& tc) {\n        getRegisteredTests().insert(tc);\n        return 0;\n    }\n\n    // sets the current test suite\n    int setTestSuite(const TestSuite& ts) {\n        doctest_detail_test_suite_ns::getCurrentTestSuite() = ts;\n        return 0;\n    }\n\n#ifdef DOCTEST_IS_DEBUGGER_ACTIVE\n    bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); }\n#else // DOCTEST_IS_DEBUGGER_ACTIVE\n#ifdef DOCTEST_PLATFORM_LINUX\n    class ErrnoGuard {\n    public:\n        ErrnoGuard() : m_oldErrno(errno) {}\n        ~ErrnoGuard() { errno = m_oldErrno; }\n    private:\n        int m_oldErrno;\n    };\n    // See the comments in Catch2 for the reasoning behind this implementation:\n    // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102\n    bool isDebuggerActive() {\n        ErrnoGuard guard;\n        std::ifstream in(\"/proc/self/status\");\n        for(std::string line; std::getline(in, line);) {\n            static const int PREFIX_LEN = 11;\n            if(line.compare(0, PREFIX_LEN, \"TracerPid:\\t\") == 0) {\n                return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';\n            }\n        }\n        return false;\n    }\n#elif defined(DOCTEST_PLATFORM_MAC)\n    // The following function is taken directly from the following technical note:\n    // https://developer.apple.com/library/archive/qa/qa1361/_index.html\n    // Returns true if the current process is being debugged (either\n    // running under the debugger or has a debugger attached post facto).\n    bool isDebuggerActive() {\n        int        mib[4];\n        kinfo_proc info;\n        size_t     size;\n        // Initialize the flags so that, if sysctl fails for some bizarre\n        // reason, we get a predictable result.\n        info.kp_proc.p_flag = 0;\n        // Initialize mib, which tells sysctl the info we want, in this case\n        // we're looking for information about a specific process ID.\n        mib[0] = CTL_KERN;\n        mib[1] = KERN_PROC;\n        mib[2] = KERN_PROC_PID;\n        mib[3] = getpid();\n        // Call sysctl.\n        size = sizeof(info);\n        if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) {\n            std::cerr << \"\\nCall to sysctl failed - unable to determine if debugger is active **\\n\";\n            return false;\n        }\n        // We're being debugged if the P_TRACED flag is set.\n        return ((info.kp_proc.p_flag & P_TRACED) != 0);\n    }\n#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__)\n    bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; }\n#else\n    bool isDebuggerActive() { return false; }\n#endif // Platform\n#endif // DOCTEST_IS_DEBUGGER_ACTIVE\n\n    void registerExceptionTranslatorImpl(const IExceptionTranslator* et) {\n        if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) ==\n           getExceptionTranslators().end())\n            getExceptionTranslators().push_back(et);\n    }\n\n#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    void toStream(std::ostream* s, char* in) { *s << in; }\n    void toStream(std::ostream* s, const char* in) { *s << in; }\n#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING\n    void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; }\n    void toStream(std::ostream* s, float in) { *s << in; }\n    void toStream(std::ostream* s, double in) { *s << in; }\n    void toStream(std::ostream* s, double long in) { *s << in; }\n\n    void toStream(std::ostream* s, char in) { *s << in; }\n    void toStream(std::ostream* s, char signed in) { *s << in; }\n    void toStream(std::ostream* s, char unsigned in) { *s << in; }\n    void toStream(std::ostream* s, int short in) { *s << in; }\n    void toStream(std::ostream* s, int short unsigned in) { *s << in; }\n    void toStream(std::ostream* s, int in) { *s << in; }\n    void toStream(std::ostream* s, int unsigned in) { *s << in; }\n    void toStream(std::ostream* s, int long in) { *s << in; }\n    void toStream(std::ostream* s, int long unsigned in) { *s << in; }\n    void toStream(std::ostream* s, int long long in) { *s << in; }\n    void toStream(std::ostream* s, int long long unsigned in) { *s << in; }\n\n    DOCTEST_THREAD_LOCAL std::vector<IContextScope*> g_infoContexts; // for logging with INFO()\n\n    ContextScopeBase::ContextScopeBase() {\n        g_infoContexts.push_back(this);\n    }\n\n    ContextScopeBase::ContextScopeBase(ContextScopeBase&& other) {\n        if (other.need_to_destroy) {\n            other.destroy();\n        }\n        other.need_to_destroy = false;\n        g_infoContexts.push_back(this);\n    }\n\n    DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17\n    DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(\"-Wdeprecated-declarations\")\n    DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(\"-Wdeprecated-declarations\")\n\n    // destroy cannot be inlined into the destructor because that would mean calling stringify after\n    // ContextScope has been destroyed (base class destructors run after derived class destructors).\n    // Instead, ContextScope calls this method directly from its destructor.\n    void ContextScopeBase::destroy() {\n#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)\n        if(std::uncaught_exceptions() > 0) {\n#else\n        if(std::uncaught_exception()) {\n#endif\n            std::ostringstream s;\n            this->stringify(&s);\n            g_cs->stringifiedContexts.push_back(s.str().c_str());\n        }\n        g_infoContexts.pop_back();\n    }\n\n    DOCTEST_CLANG_SUPPRESS_WARNING_POP\n    DOCTEST_GCC_SUPPRESS_WARNING_POP\n    DOCTEST_MSVC_SUPPRESS_WARNING_POP\n} // namespace detail\nnamespace {\n    using namespace detail;\n\n#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH)\n    struct FatalConditionHandler\n    {\n        static void reset() {}\n        static void allocateAltStackMem() {}\n        static void freeAltStackMem() {}\n    };\n#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH\n\n    void reportFatal(const std::string&);\n\n#ifdef DOCTEST_PLATFORM_WINDOWS\n\n    struct SignalDefs\n    {\n        DWORD id;\n        const char* name;\n    };\n    // There is no 1-1 mapping between signals and windows exceptions.\n    // Windows can easily distinguish between SO and SigSegV,\n    // but SigInt, SigTerm, etc are handled differently.\n    SignalDefs signalDefs[] = {\n            {static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION),\n             \"SIGILL - Illegal instruction signal\"},\n            {static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), \"SIGSEGV - Stack overflow\"},\n            {static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION),\n             \"SIGSEGV - Segmentation violation signal\"},\n            {static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), \"Divide by zero error\"},\n    };\n\n    struct FatalConditionHandler\n    {\n        static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) {\n            // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the\n            // console just once no matter how many threads have crashed.\n            static std::mutex mutex;\n            static bool execute = true;\n            {\n                std::lock_guard<std::mutex> lock(mutex);\n                if(execute) {\n                    bool reported = false;\n                    for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {\n                        if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {\n                            reportFatal(signalDefs[i].name);\n                            reported = true;\n                            break;\n                        }\n                    }\n                    if(reported == false)\n                        reportFatal(\"Unhandled SEH exception caught\");\n                    if(isDebuggerActive() && !g_cs->no_breaks)\n                        DOCTEST_BREAK_INTO_DEBUGGER();\n                }\n                execute = false;\n            }\n            std::exit(EXIT_FAILURE);\n        }\n\n        static void allocateAltStackMem() {}\n        static void freeAltStackMem() {}\n\n        FatalConditionHandler() {\n            isSet = true;\n            // 32k seems enough for doctest to handle stack overflow,\n            // but the value was found experimentally, so there is no strong guarantee\n            guaranteeSize = 32 * 1024;\n            // Register an unhandled exception filter\n            previousTop = SetUnhandledExceptionFilter(handleException);\n            // Pass in guarantee size to be filled\n            SetThreadStackGuarantee(&guaranteeSize);\n\n            // On Windows uncaught exceptions from another thread, exceptions from\n            // destructors, or calls to std::terminate are not a SEH exception\n\n            // The terminal handler gets called when:\n            // - std::terminate is called FROM THE TEST RUNNER THREAD\n            // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD\n            original_terminate_handler = std::get_terminate();\n            std::set_terminate([]() DOCTEST_NOEXCEPT {\n                reportFatal(\"Terminate handler called\");\n                if(isDebuggerActive() && !g_cs->no_breaks)\n                    DOCTEST_BREAK_INTO_DEBUGGER();\n                std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well\n            });\n\n            // SIGABRT is raised when:\n            // - std::terminate is called FROM A DIFFERENT THREAD\n            // - an exception is thrown from a destructor FROM A DIFFERENT THREAD\n            // - an uncaught exception is thrown FROM A DIFFERENT THREAD\n            prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT {\n                if(signal == SIGABRT) {\n                    reportFatal(\"SIGABRT - Abort (abnormal termination) signal\");\n                    if(isDebuggerActive() && !g_cs->no_breaks)\n                        DOCTEST_BREAK_INTO_DEBUGGER();\n                    std::exit(EXIT_FAILURE);\n                }\n            });\n\n            // The following settings are taken from google test, and more\n            // specifically from UnitTest::Run() inside of gtest.cc\n\n            // the user does not want to see pop-up dialogs about crashes\n            prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |\n                                             SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n            // This forces the abort message to go to stderr in all circumstances.\n            prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR);\n            // In the debug version, Visual Studio pops up a separate dialog\n            // offering a choice to debug the aborted program - we want to disable that.\n            prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\n            // In debug mode, the Windows CRT can crash with an assertion over invalid\n            // input (e.g. passing an invalid file descriptor). The default handling\n            // for these assertions is to pop up a dialog and wait for user input.\n            // Instead ask the CRT to dump such assertions to stderr non-interactively.\n            prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);\n            prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);\n        }\n\n        static void reset() {\n            if(isSet) {\n                // Unregister handler and restore the old guarantee\n                SetUnhandledExceptionFilter(previousTop);\n                SetThreadStackGuarantee(&guaranteeSize);\n                std::set_terminate(original_terminate_handler);\n                std::signal(SIGABRT, prev_sigabrt_handler);\n                SetErrorMode(prev_error_mode_1);\n                _set_error_mode(prev_error_mode_2);\n                _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\n                static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode));\n                static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file));\n                isSet = false;\n            }\n        }\n\n        ~FatalConditionHandler() { reset(); }\n\n    private:\n        static UINT         prev_error_mode_1;\n        static int          prev_error_mode_2;\n        static unsigned int prev_abort_behavior;\n        static int          prev_report_mode;\n        static _HFILE       prev_report_file;\n        static void (DOCTEST_CDECL *prev_sigabrt_handler)(int);\n        static std::terminate_handler original_terminate_handler;\n        static bool isSet;\n        static ULONG guaranteeSize;\n        static LPTOP_LEVEL_EXCEPTION_FILTER previousTop;\n    };\n\n    UINT         FatalConditionHandler::prev_error_mode_1;\n    int          FatalConditionHandler::prev_error_mode_2;\n    unsigned int FatalConditionHandler::prev_abort_behavior;\n    int          FatalConditionHandler::prev_report_mode;\n    _HFILE       FatalConditionHandler::prev_report_file;\n    void (DOCTEST_CDECL *FatalConditionHandler::prev_sigabrt_handler)(int);\n    std::terminate_handler FatalConditionHandler::original_terminate_handler;\n    bool FatalConditionHandler::isSet = false;\n    ULONG FatalConditionHandler::guaranteeSize = 0;\n    LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr;\n\n#else // DOCTEST_PLATFORM_WINDOWS\n\n    struct SignalDefs\n    {\n        int         id;\n        const char* name;\n    };\n    SignalDefs signalDefs[] = {{SIGINT, \"SIGINT - Terminal interrupt signal\"},\n                               {SIGILL, \"SIGILL - Illegal instruction signal\"},\n                               {SIGFPE, \"SIGFPE - Floating point error signal\"},\n                               {SIGSEGV, \"SIGSEGV - Segmentation violation signal\"},\n                               {SIGTERM, \"SIGTERM - Termination request signal\"},\n                               {SIGABRT, \"SIGABRT - Abort (abnormal termination) signal\"}};\n\n    struct FatalConditionHandler\n    {\n        static bool             isSet;\n        static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)];\n        static stack_t          oldSigStack;\n        static size_t           altStackSize;\n        static char*            altStackMem;\n\n        static void handleSignal(int sig) {\n            const char* name = \"<unknown signal>\";\n            for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {\n                SignalDefs& def = signalDefs[i];\n                if(sig == def.id) {\n                    name = def.name;\n                    break;\n                }\n            }\n            reset();\n            reportFatal(name);\n            raise(sig);\n        }\n\n        static void allocateAltStackMem() {\n            altStackMem = new char[altStackSize];\n        }\n\n        static void freeAltStackMem() {\n            delete[] altStackMem;\n        }\n\n        FatalConditionHandler() {\n            isSet = true;\n            stack_t sigStack;\n            sigStack.ss_sp    = altStackMem;\n            sigStack.ss_size  = altStackSize;\n            sigStack.ss_flags = 0;\n            sigaltstack(&sigStack, &oldSigStack);\n            struct sigaction sa = {};\n            sa.sa_handler       = handleSignal; // NOLINT\n            sa.sa_flags         = SA_ONSTACK;\n            for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {\n                sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);\n            }\n        }\n\n        ~FatalConditionHandler() { reset(); }\n        static void reset() {\n            if(isSet) {\n                // Set signals back to previous values -- hopefully nobody overwrote them in the meantime\n                for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {\n                    sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);\n                }\n                // Return the old stack\n                sigaltstack(&oldSigStack, nullptr);\n                isSet = false;\n            }\n        }\n    };\n\n    bool             FatalConditionHandler::isSet = false;\n    struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {};\n    stack_t          FatalConditionHandler::oldSigStack = {};\n    size_t           FatalConditionHandler::altStackSize = 4 * SIGSTKSZ;\n    char*            FatalConditionHandler::altStackMem = nullptr;\n\n#endif // DOCTEST_PLATFORM_WINDOWS\n#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH\n\n} // namespace\n\nnamespace {\n    using namespace detail;\n\n#ifdef DOCTEST_PLATFORM_WINDOWS\n#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text)\n#else\n    // TODO: integration with XCode and other IDEs\n#define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros)\n#endif // Platform\n\n    void addAssert(assertType::Enum at) {\n        if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional\n            g_cs->numAssertsCurrentTest_atomic++;\n    }\n\n    void addFailedAssert(assertType::Enum at) {\n        if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional\n            g_cs->numAssertsFailedCurrentTest_atomic++;\n    }\n\n#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH)\n    void reportFatal(const std::string& message) {\n        g_cs->failure_flags |= TestCaseFailureReason::Crash;\n\n        DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true});\n\n        while(g_cs->subcasesStack.size()) {\n            g_cs->subcasesStack.pop_back();\n            DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY);\n        }\n\n        g_cs->finalizeTestCaseData();\n\n        DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs);\n\n        DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs);\n    }\n#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH\n} // namespace\nnamespace detail {\n\n    ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr,\n                                 const char* exception_type, const char* exception_string) {\n        m_test_case        = g_cs->currentTest;\n        m_at               = at;\n        m_file             = file;\n        m_line             = line;\n        m_expr             = expr;\n        m_failed           = true;\n        m_threw            = false;\n        m_threw_as         = false;\n        m_exception_type   = exception_type;\n        m_exception_string = exception_string;\n#if DOCTEST_MSVC\n        if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC\n            ++m_expr;\n#endif // MSVC\n    }\n\n    void ResultBuilder::setResult(const Result& res) {\n        m_decomp = res.m_decomp;\n        m_failed = !res.m_passed;\n    }\n\n    void ResultBuilder::translateException() {\n        m_threw     = true;\n        m_exception = translateActiveException();\n    }\n\n    bool ResultBuilder::log() {\n        if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional\n            m_failed = !m_threw;\n        } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT\n            m_failed = !m_threw_as || (m_exception != m_exception_string);\n        } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional\n            m_failed = !m_threw_as;\n        } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional\n            m_failed = m_exception != m_exception_string;\n        } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional\n            m_failed = m_threw;\n        }\n\n        if(m_exception.size())\n            m_exception = \"\\\"\" + m_exception + \"\\\"\";\n\n        if(is_running_in_test) {\n            addAssert(m_at);\n            DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this);\n\n            if(m_failed)\n                addFailedAssert(m_at);\n        } else if(m_failed) {\n            failed_out_of_a_testing_context(*this);\n        }\n\n        return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&\n            (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger\n    }\n\n    void ResultBuilder::react() const {\n        if(m_failed && checkIfShouldThrow(m_at))\n            throwException();\n    }\n\n    void failed_out_of_a_testing_context(const AssertData& ad) {\n        if(g_cs->ah)\n            g_cs->ah(ad);\n        else\n            std::abort();\n    }\n\n    bool decomp_assert(assertType::Enum at, const char* file, int line, const char* expr,\n                       Result result) {\n        bool failed = !result.m_passed;\n\n        // ###################################################################################\n        // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT\n        // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED\n        // ###################################################################################\n        DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp);\n        DOCTEST_ASSERT_IN_TESTS(result.m_decomp);\n        // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n        return !failed;\n    }\n\n    MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) {\n        m_stream   = tlssPush();\n        m_file     = file;\n        m_line     = line;\n        m_severity = severity;\n    }\n\n    MessageBuilder::~MessageBuilder() {\n        if (!logged)\n            tlssPop();\n    }\n\n    IExceptionTranslator::IExceptionTranslator()  = default;\n    IExceptionTranslator::~IExceptionTranslator() = default;\n\n    bool MessageBuilder::log() {\n        if (!logged) {\n            m_string = tlssPop();\n            logged = true;\n        }\n        \n        DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this);\n\n        const bool isWarn = m_severity & assertType::is_warn;\n\n        // warn is just a message in this context so we don't treat it as an assert\n        if(!isWarn) {\n            addAssert(m_severity);\n            addFailedAssert(m_severity);\n        }\n\n        return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn &&\n            (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger\n    }\n\n    void MessageBuilder::react() {\n        if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional\n            throwException();\n    }\n} // namespace detail\nnamespace {\n    using namespace detail;\n\n    // clang-format off\n\n// =================================================================================================\n// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp\n// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched.\n// =================================================================================================\n\n    class XmlEncode {\n    public:\n        enum ForWhat { ForTextNodes, ForAttributes };\n\n        XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );\n\n        void encodeTo( std::ostream& os ) const;\n\n        friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );\n\n    private:\n        std::string m_str;\n        ForWhat m_forWhat;\n    };\n\n    class XmlWriter {\n    public:\n\n        class ScopedElement {\n        public:\n            ScopedElement( XmlWriter* writer );\n\n            ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT;\n            ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT;\n\n            ~ScopedElement();\n\n            ScopedElement& writeText( std::string const& text, bool indent = true );\n\n            template<typename T>\n            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {\n                m_writer->writeAttribute( name, attribute );\n                return *this;\n            }\n\n        private:\n            mutable XmlWriter* m_writer = nullptr;\n        };\n\n        XmlWriter( std::ostream& os = std::cout );\n        ~XmlWriter();\n\n        XmlWriter( XmlWriter const& ) = delete;\n        XmlWriter& operator=( XmlWriter const& ) = delete;\n\n        XmlWriter& startElement( std::string const& name );\n\n        ScopedElement scopedElement( std::string const& name );\n\n        XmlWriter& endElement();\n\n        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );\n\n        XmlWriter& writeAttribute( std::string const& name, const char* attribute );\n\n        XmlWriter& writeAttribute( std::string const& name, bool attribute );\n\n        template<typename T>\n        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {\n        std::stringstream rss;\n            rss << attribute;\n            return writeAttribute( name, rss.str() );\n        }\n\n        XmlWriter& writeText( std::string const& text, bool indent = true );\n\n        //XmlWriter& writeComment( std::string const& text );\n\n        //void writeStylesheetRef( std::string const& url );\n\n        //XmlWriter& writeBlankLine();\n\n        void ensureTagClosed();\n\n    private:\n\n        void writeDeclaration();\n\n        void newlineIfNecessary();\n\n        bool m_tagIsOpen = false;\n        bool m_needsNewline = false;\n        std::vector<std::string> m_tags;\n        std::string m_indent;\n        std::ostream& m_os;\n    };\n\n// =================================================================================================\n// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp\n// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched.\n// =================================================================================================\n\nusing uchar = unsigned char;\n\nnamespace {\n\n    size_t trailingBytes(unsigned char c) {\n        if ((c & 0xE0) == 0xC0) {\n            return 2;\n        }\n        if ((c & 0xF0) == 0xE0) {\n            return 3;\n        }\n        if ((c & 0xF8) == 0xF0) {\n            return 4;\n        }\n        DOCTEST_INTERNAL_ERROR(\"Invalid multibyte utf-8 start byte encountered\");\n    }\n\n    uint32_t headerValue(unsigned char c) {\n        if ((c & 0xE0) == 0xC0) {\n            return c & 0x1F;\n        }\n        if ((c & 0xF0) == 0xE0) {\n            return c & 0x0F;\n        }\n        if ((c & 0xF8) == 0xF0) {\n            return c & 0x07;\n        }\n        DOCTEST_INTERNAL_ERROR(\"Invalid multibyte utf-8 start byte encountered\");\n    }\n\n    void hexEscapeChar(std::ostream& os, unsigned char c) {\n        std::ios_base::fmtflags f(os.flags());\n        os << \"\\\\x\"\n            << std::uppercase << std::hex << std::setfill('0') << std::setw(2)\n            << static_cast<int>(c);\n        os.flags(f);\n    }\n\n} // anonymous namespace\n\n    XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )\n    :   m_str( str ),\n        m_forWhat( forWhat )\n    {}\n\n    void XmlEncode::encodeTo( std::ostream& os ) const {\n        // Apostrophe escaping not necessary if we always use \" to write attributes\n        // (see: https://www.w3.org/TR/xml/#syntax)\n\n        for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {\n            uchar c = m_str[idx];\n            switch (c) {\n            case '<':   os << \"&lt;\"; break;\n            case '&':   os << \"&amp;\"; break;\n\n            case '>':\n                // See: https://www.w3.org/TR/xml/#syntax\n                if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')\n                    os << \"&gt;\";\n                else\n                    os << c;\n                break;\n\n            case '\\\"':\n                if (m_forWhat == ForAttributes)\n                    os << \"&quot;\";\n                else\n                    os << c;\n                break;\n\n            default:\n                // Check for control characters and invalid utf-8\n\n                // Escape control characters in standard ascii\n                // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0\n                if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n\n                // Plain ASCII: Write it to stream\n                if (c < 0x7F) {\n                    os << c;\n                    break;\n                }\n\n                // UTF-8 territory\n                // Check if the encoding is valid and if it is not, hex escape bytes.\n                // Important: We do not check the exact decoded values for validity, only the encoding format\n                // First check that this bytes is a valid lead byte:\n                // This means that it is not encoded as 1111 1XXX\n                // Or as 10XX XXXX\n                if (c <  0xC0 ||\n                    c >= 0xF8) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n\n                auto encBytes = trailingBytes(c);\n                // Are there enough bytes left to avoid accessing out-of-bounds memory?\n                if (idx + encBytes - 1 >= m_str.size()) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n                // The header is valid, check data\n                // The next encBytes bytes must together be a valid utf-8\n                // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)\n                bool valid = true;\n                uint32_t value = headerValue(c);\n                for (std::size_t n = 1; n < encBytes; ++n) {\n                    uchar nc = m_str[idx + n];\n                    valid &= ((nc & 0xC0) == 0x80);\n                    value = (value << 6) | (nc & 0x3F);\n                }\n\n                if (\n                    // Wrong bit pattern of following bytes\n                    (!valid) ||\n                    // Overlong encodings\n                    (value < 0x80) ||\n                    (                 value < 0x800   && encBytes > 2) || // removed \"0x80 <= value &&\" because redundant\n                    (0x800 < value && value < 0x10000 && encBytes > 3) ||\n                    // Encoded value out of range\n                    (value >= 0x110000)\n                    ) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n\n                // If we got here, this is in fact a valid(ish) utf-8 sequence\n                for (std::size_t n = 0; n < encBytes; ++n) {\n                    os << m_str[idx + n];\n                }\n                idx += encBytes - 1;\n                break;\n            }\n        }\n    }\n\n    std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {\n        xmlEncode.encodeTo( os );\n        return os;\n    }\n\n    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )\n    :   m_writer( writer )\n    {}\n\n    XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT\n    :   m_writer( other.m_writer ){\n        other.m_writer = nullptr;\n    }\n    XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT {\n        if ( m_writer ) {\n            m_writer->endElement();\n        }\n        m_writer = other.m_writer;\n        other.m_writer = nullptr;\n        return *this;\n    }\n\n\n    XmlWriter::ScopedElement::~ScopedElement() {\n        if( m_writer )\n            m_writer->endElement();\n    }\n\n    XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {\n        m_writer->writeText( text, indent );\n        return *this;\n    }\n\n    XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )\n    {\n        writeDeclaration();\n    }\n\n    XmlWriter::~XmlWriter() {\n        while( !m_tags.empty() )\n            endElement();\n    }\n\n    XmlWriter& XmlWriter::startElement( std::string const& name ) {\n        ensureTagClosed();\n        newlineIfNecessary();\n        m_os << m_indent << '<' << name;\n        m_tags.push_back( name );\n        m_indent += \"  \";\n        m_tagIsOpen = true;\n        return *this;\n    }\n\n    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {\n        ScopedElement scoped( this );\n        startElement( name );\n        return scoped;\n    }\n\n    XmlWriter& XmlWriter::endElement() {\n        newlineIfNecessary();\n        m_indent = m_indent.substr( 0, m_indent.size()-2 );\n        if( m_tagIsOpen ) {\n            m_os << \"/>\";\n            m_tagIsOpen = false;\n        }\n        else {\n            m_os << m_indent << \"</\" << m_tags.back() << \">\";\n        }\n        m_os << std::endl;\n        m_tags.pop_back();\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {\n        if( !name.empty() && !attribute.empty() )\n            m_os << ' ' << name << \"=\\\"\" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '\"';\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) {\n        if( !name.empty() && attribute && attribute[0] != '\\0' )\n            m_os << ' ' << name << \"=\\\"\" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '\"';\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {\n        m_os << ' ' << name << \"=\\\"\" << ( attribute ? \"true\" : \"false\" ) << '\"';\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {\n        if( !text.empty() ){\n            bool tagWasOpen = m_tagIsOpen;\n            ensureTagClosed();\n            if( tagWasOpen && indent )\n                m_os << m_indent;\n            m_os << XmlEncode( text );\n            m_needsNewline = true;\n        }\n        return *this;\n    }\n\n    //XmlWriter& XmlWriter::writeComment( std::string const& text ) {\n    //    ensureTagClosed();\n    //    m_os << m_indent << \"<!--\" << text << \"-->\";\n    //    m_needsNewline = true;\n    //    return *this;\n    //}\n\n    //void XmlWriter::writeStylesheetRef( std::string const& url ) {\n    //    m_os << \"<?xml-stylesheet type=\\\"text/xsl\\\" href=\\\"\" << url << \"\\\"?>\\n\";\n    //}\n\n    //XmlWriter& XmlWriter::writeBlankLine() {\n    //    ensureTagClosed();\n    //    m_os << '\\n';\n    //    return *this;\n    //}\n\n    void XmlWriter::ensureTagClosed() {\n        if( m_tagIsOpen ) {\n            m_os << \">\" << std::endl;\n            m_tagIsOpen = false;\n        }\n    }\n\n    void XmlWriter::writeDeclaration() {\n        m_os << \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\";\n    }\n\n    void XmlWriter::newlineIfNecessary() {\n        if( m_needsNewline ) {\n            m_os << std::endl;\n            m_needsNewline = false;\n        }\n    }\n\n// =================================================================================================\n// End of copy-pasted code from Catch\n// =================================================================================================\n\n    // clang-format on\n\n    struct XmlReporter : public IReporter\n    {\n        XmlWriter  xml;\n        std::mutex mutex;\n\n        // caching pointers/references to objects of these types - safe to do\n        const ContextOptions& opt;\n        const TestCaseData*   tc = nullptr;\n\n        XmlReporter(const ContextOptions& co)\n                : xml(*co.cout)\n                , opt(co) {}\n\n        void log_contexts() {\n            int num_contexts = get_num_active_contexts();\n            if(num_contexts) {\n                auto              contexts = get_active_contexts();\n                std::stringstream ss;\n                for(int i = 0; i < num_contexts; ++i) {\n                    contexts[i]->stringify(&ss);\n                    xml.scopedElement(\"Info\").writeText(ss.str());\n                    ss.str(\"\");\n                }\n            }\n        }\n\n        unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }\n\n        void test_case_start_impl(const TestCaseData& in) {\n            bool open_ts_tag = false;\n            if(tc != nullptr) { // we have already opened a test suite\n                if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) {\n                    xml.endElement();\n                    open_ts_tag = true;\n                }\n            }\n            else {\n                open_ts_tag = true; // first test case ==> first test suite\n            }\n\n            if(open_ts_tag) {\n                xml.startElement(\"TestSuite\");\n                xml.writeAttribute(\"name\", in.m_test_suite);\n            }\n\n            tc = &in;\n            xml.startElement(\"TestCase\")\n                    .writeAttribute(\"name\", in.m_name)\n                    .writeAttribute(\"filename\", skipPathFromFilename(in.m_file.c_str()))\n                    .writeAttribute(\"line\", line(in.m_line))\n                    .writeAttribute(\"description\", in.m_description);\n\n            if(Approx(in.m_timeout) != 0)\n                xml.writeAttribute(\"timeout\", in.m_timeout);\n            if(in.m_may_fail)\n                xml.writeAttribute(\"may_fail\", true);\n            if(in.m_should_fail)\n                xml.writeAttribute(\"should_fail\", true);\n        }\n\n        // =========================================================================================\n        // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE\n        // =========================================================================================\n\n        void report_query(const QueryData& in) override {\n            test_run_start();\n            if(opt.list_reporters) {\n                for(auto& curr : getListeners())\n                    xml.scopedElement(\"Listener\")\n                            .writeAttribute(\"priority\", curr.first.first)\n                            .writeAttribute(\"name\", curr.first.second);\n                for(auto& curr : getReporters())\n                    xml.scopedElement(\"Reporter\")\n                            .writeAttribute(\"priority\", curr.first.first)\n                            .writeAttribute(\"name\", curr.first.second);\n            } else if(opt.count || opt.list_test_cases) {\n                for(unsigned i = 0; i < in.num_data; ++i) {\n                    xml.scopedElement(\"TestCase\").writeAttribute(\"name\", in.data[i]->m_name)\n                        .writeAttribute(\"testsuite\", in.data[i]->m_test_suite)\n                        .writeAttribute(\"filename\", skipPathFromFilename(in.data[i]->m_file.c_str()))\n                        .writeAttribute(\"line\", line(in.data[i]->m_line))\n                        .writeAttribute(\"skipped\", in.data[i]->m_skip);\n                }\n                xml.scopedElement(\"OverallResultsTestCases\")\n                        .writeAttribute(\"unskipped\", in.run_stats->numTestCasesPassingFilters);\n            } else if(opt.list_test_suites) {\n                for(unsigned i = 0; i < in.num_data; ++i)\n                    xml.scopedElement(\"TestSuite\").writeAttribute(\"name\", in.data[i]->m_test_suite);\n                xml.scopedElement(\"OverallResultsTestCases\")\n                        .writeAttribute(\"unskipped\", in.run_stats->numTestCasesPassingFilters);\n                xml.scopedElement(\"OverallResultsTestSuites\")\n                        .writeAttribute(\"unskipped\", in.run_stats->numTestSuitesPassingFilters);\n            }\n            xml.endElement();\n        }\n\n        void test_run_start() override {\n            // remove .exe extension - mainly to have the same output on UNIX and Windows\n            std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());\n#ifdef DOCTEST_PLATFORM_WINDOWS\n            if(binary_name.rfind(\".exe\") != std::string::npos)\n                binary_name = binary_name.substr(0, binary_name.length() - 4);\n#endif // DOCTEST_PLATFORM_WINDOWS\n\n            xml.startElement(\"doctest\").writeAttribute(\"binary\", binary_name);\n            if(opt.no_version == false)\n                xml.writeAttribute(\"version\", DOCTEST_VERSION_STR);\n\n            // only the consequential ones (TODO: filters)\n            xml.scopedElement(\"Options\")\n                    .writeAttribute(\"order_by\", opt.order_by.c_str())\n                    .writeAttribute(\"rand_seed\", opt.rand_seed)\n                    .writeAttribute(\"first\", opt.first)\n                    .writeAttribute(\"last\", opt.last)\n                    .writeAttribute(\"abort_after\", opt.abort_after)\n                    .writeAttribute(\"subcase_filter_levels\", opt.subcase_filter_levels)\n                    .writeAttribute(\"case_sensitive\", opt.case_sensitive)\n                    .writeAttribute(\"no_throw\", opt.no_throw)\n                    .writeAttribute(\"no_skip\", opt.no_skip);\n        }\n\n        void test_run_end(const TestRunStats& p) override {\n            if(tc) // the TestSuite tag - only if there has been at least 1 test case\n                xml.endElement();\n\n            xml.scopedElement(\"OverallResultsAsserts\")\n                    .writeAttribute(\"successes\", p.numAsserts - p.numAssertsFailed)\n                    .writeAttribute(\"failures\", p.numAssertsFailed);\n\n            xml.startElement(\"OverallResultsTestCases\")\n                    .writeAttribute(\"successes\",\n                                    p.numTestCasesPassingFilters - p.numTestCasesFailed)\n                    .writeAttribute(\"failures\", p.numTestCasesFailed);\n            if(opt.no_skipped_summary == false)\n                xml.writeAttribute(\"skipped\", p.numTestCases - p.numTestCasesPassingFilters);\n            xml.endElement();\n\n            xml.endElement();\n        }\n\n        void test_case_start(const TestCaseData& in) override {\n            test_case_start_impl(in);\n            xml.ensureTagClosed();\n        }\n        \n        void test_case_reenter(const TestCaseData&) override {}\n\n        void test_case_end(const CurrentTestCaseStats& st) override {\n            xml.startElement(\"OverallResultsAsserts\")\n                    .writeAttribute(\"successes\",\n                                    st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest)\n                    .writeAttribute(\"failures\", st.numAssertsFailedCurrentTest)\n                    .writeAttribute(\"test_case_success\", st.testCaseSuccess);\n            if(opt.duration)\n                xml.writeAttribute(\"duration\", st.seconds);\n            if(tc->m_expected_failures)\n                xml.writeAttribute(\"expected_failures\", tc->m_expected_failures);\n            xml.endElement();\n\n            xml.endElement();\n        }\n\n        void test_case_exception(const TestCaseException& e) override {\n            std::lock_guard<std::mutex> lock(mutex);\n\n            xml.scopedElement(\"Exception\")\n                    .writeAttribute(\"crash\", e.is_crash)\n                    .writeText(e.error_string.c_str());\n        }\n\n        void subcase_start(const SubcaseSignature& in) override {\n            xml.startElement(\"SubCase\")\n                    .writeAttribute(\"name\", in.m_name)\n                    .writeAttribute(\"filename\", skipPathFromFilename(in.m_file))\n                    .writeAttribute(\"line\", line(in.m_line));\n            xml.ensureTagClosed();\n        }\n\n        void subcase_end() override { xml.endElement(); }\n\n        void log_assert(const AssertData& rb) override {\n            if(!rb.m_failed && !opt.success)\n                return;\n\n            std::lock_guard<std::mutex> lock(mutex);\n\n            xml.startElement(\"Expression\")\n                    .writeAttribute(\"success\", !rb.m_failed)\n                    .writeAttribute(\"type\", assertString(rb.m_at))\n                    .writeAttribute(\"filename\", skipPathFromFilename(rb.m_file))\n                    .writeAttribute(\"line\", line(rb.m_line));\n\n            xml.scopedElement(\"Original\").writeText(rb.m_expr);\n\n            if(rb.m_threw)\n                xml.scopedElement(\"Exception\").writeText(rb.m_exception.c_str());\n\n            if(rb.m_at & assertType::is_throws_as)\n                xml.scopedElement(\"ExpectedException\").writeText(rb.m_exception_type);\n            if(rb.m_at & assertType::is_throws_with)\n                xml.scopedElement(\"ExpectedExceptionString\").writeText(rb.m_exception_string);\n            if((rb.m_at & assertType::is_normal) && !rb.m_threw)\n                xml.scopedElement(\"Expanded\").writeText(rb.m_decomp.c_str());\n\n            log_contexts();\n\n            xml.endElement();\n        }\n\n        void log_message(const MessageData& mb) override {\n            std::lock_guard<std::mutex> lock(mutex);\n\n            xml.startElement(\"Message\")\n                    .writeAttribute(\"type\", failureString(mb.m_severity))\n                    .writeAttribute(\"filename\", skipPathFromFilename(mb.m_file))\n                    .writeAttribute(\"line\", line(mb.m_line));\n\n            xml.scopedElement(\"Text\").writeText(mb.m_string.c_str());\n\n            log_contexts();\n\n            xml.endElement();\n        }\n\n        void test_case_skipped(const TestCaseData& in) override {\n            if(opt.no_skipped_summary == false) {\n                test_case_start_impl(in);\n                xml.writeAttribute(\"skipped\", \"true\");\n                xml.endElement();\n            }\n        }\n    };\n\n    DOCTEST_REGISTER_REPORTER(\"xml\", 0, XmlReporter);\n\n    void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) {\n        if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) ==\n            0) //!OCLINT bitwise operator in conditional\n            s << Color::Cyan << assertString(rb.m_at) << \"( \" << rb.m_expr << \" ) \"\n                << Color::None;\n\n        if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional\n            s << (rb.m_threw ? \"threw as expected!\" : \"did NOT throw at all!\") << \"\\n\";\n        } else if((rb.m_at & assertType::is_throws_as) &&\n                    (rb.m_at & assertType::is_throws_with)) { //!OCLINT\n            s << Color::Cyan << assertString(rb.m_at) << \"( \" << rb.m_expr << \", \\\"\"\n                << rb.m_exception_string << \"\\\", \" << rb.m_exception_type << \" ) \" << Color::None;\n            if(rb.m_threw) {\n                if(!rb.m_failed) {\n                    s << \"threw as expected!\\n\";\n                } else {\n                    s << \"threw a DIFFERENT exception! (contents: \" << rb.m_exception << \")\\n\";\n                }\n            } else {\n                s << \"did NOT throw at all!\\n\";\n            }\n        } else if(rb.m_at &\n                    assertType::is_throws_as) { //!OCLINT bitwise operator in conditional\n            s << Color::Cyan << assertString(rb.m_at) << \"( \" << rb.m_expr << \", \"\n                << rb.m_exception_type << \" ) \" << Color::None\n                << (rb.m_threw ? (rb.m_threw_as ? \"threw as expected!\" :\n                                                \"threw a DIFFERENT exception: \") :\n                                \"did NOT throw at all!\")\n                << Color::Cyan << rb.m_exception << \"\\n\";\n        } else if(rb.m_at &\n                    assertType::is_throws_with) { //!OCLINT bitwise operator in conditional\n            s << Color::Cyan << assertString(rb.m_at) << \"( \" << rb.m_expr << \", \\\"\"\n                << rb.m_exception_string << \"\\\" ) \" << Color::None\n                << (rb.m_threw ? (!rb.m_failed ? \"threw as expected!\" :\n                                                \"threw a DIFFERENT exception: \") :\n                                \"did NOT throw at all!\")\n                << Color::Cyan << rb.m_exception << \"\\n\";\n        } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional\n            s << (rb.m_threw ? \"THREW exception: \" : \"didn't throw!\") << Color::Cyan\n                << rb.m_exception << \"\\n\";\n        } else {\n            s << (rb.m_threw ? \"THREW exception: \" :\n                                (!rb.m_failed ? \"is correct!\\n\" : \"is NOT correct!\\n\"));\n            if(rb.m_threw)\n                s << rb.m_exception << \"\\n\";\n            else\n                s << \"  values: \" << assertString(rb.m_at) << \"( \" << rb.m_decomp << \" )\\n\";\n        }\n    }\n\n    // TODO:\n    // - log_message()\n    // - respond to queries\n    // - honor remaining options\n    // - more attributes in tags\n    struct JUnitReporter : public IReporter\n    {\n        XmlWriter  xml;\n        std::mutex mutex;\n        Timer timer;\n        std::vector<String> deepestSubcaseStackNames;\n\n        struct JUnitTestCaseData\n        {\n            static std::string getCurrentTimestamp() {\n                // Beware, this is not reentrant because of backward compatibility issues\n                // Also, UTC only, again because of backward compatibility (%z is C++11)\n                time_t rawtime;\n                std::time(&rawtime);\n                auto const timeStampSize = sizeof(\"2017-01-16T17:06:45Z\");\n\n                std::tm timeInfo;\n#ifdef DOCTEST_PLATFORM_WINDOWS\n                gmtime_s(&timeInfo, &rawtime);\n#else // DOCTEST_PLATFORM_WINDOWS\n                gmtime_r(&rawtime, &timeInfo);\n#endif // DOCTEST_PLATFORM_WINDOWS\n\n                char timeStamp[timeStampSize];\n                const char* const fmt = \"%Y-%m-%dT%H:%M:%SZ\";\n\n                std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);\n                return std::string(timeStamp);\n            }\n\n            struct JUnitTestMessage\n            {\n                JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details)\n                    : message(_message), type(_type), details(_details) {}\n\n                JUnitTestMessage(const std::string& _message, const std::string& _details)\n                    : message(_message), type(), details(_details) {}\n\n                std::string message, type, details;\n            };\n\n            struct JUnitTestCase\n            {\n                JUnitTestCase(const std::string& _classname, const std::string& _name)\n                    : classname(_classname), name(_name), time(0), failures() {}\n\n                std::string classname, name;\n                double time;\n                std::vector<JUnitTestMessage> failures, errors;\n            };\n\n            void add(const std::string& classname, const std::string& name) {\n                testcases.emplace_back(classname, name);\n            }\n\n            void appendSubcaseNamesToLastTestcase(std::vector<String> nameStack) {\n                for(auto& curr: nameStack)\n                    if(curr.size())\n                        testcases.back().name += std::string(\"/\") + curr.c_str();\n            }\n\n            void addTime(double time) {\n                if(time < 1e-4)\n                    time = 0;\n                testcases.back().time = time;\n                totalSeconds += time;\n            }\n\n            void addFailure(const std::string& message, const std::string& type, const std::string& details) {\n                testcases.back().failures.emplace_back(message, type, details);\n                ++totalFailures;\n            }\n\n            void addError(const std::string& message, const std::string& details) {\n                testcases.back().errors.emplace_back(message, details);\n                ++totalErrors;\n            }\n\n            std::vector<JUnitTestCase> testcases;\n            double totalSeconds = 0;\n            int totalErrors = 0, totalFailures = 0;\n        };\n\n        JUnitTestCaseData testCaseData;\n\n        // caching pointers/references to objects of these types - safe to do\n        const ContextOptions& opt;\n        const TestCaseData*   tc = nullptr;\n\n        JUnitReporter(const ContextOptions& co)\n                : xml(*co.cout)\n                , opt(co) {}\n\n        unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }\n\n        // =========================================================================================\n        // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE\n        // =========================================================================================\n\n        void report_query(const QueryData&) override {}\n\n        void test_run_start() override {}\n\n        void test_run_end(const TestRunStats& p) override {\n            // remove .exe extension - mainly to have the same output on UNIX and Windows\n            std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());\n#ifdef DOCTEST_PLATFORM_WINDOWS\n            if(binary_name.rfind(\".exe\") != std::string::npos)\n                binary_name = binary_name.substr(0, binary_name.length() - 4);\n#endif // DOCTEST_PLATFORM_WINDOWS\n            xml.startElement(\"testsuites\");\n            xml.startElement(\"testsuite\").writeAttribute(\"name\", binary_name)\n                    .writeAttribute(\"errors\", testCaseData.totalErrors)\n                    .writeAttribute(\"failures\", testCaseData.totalFailures)\n                    .writeAttribute(\"tests\", p.numAsserts);\n            if(opt.no_time_in_output == false) {\n                xml.writeAttribute(\"time\", testCaseData.totalSeconds);\n                xml.writeAttribute(\"timestamp\", JUnitTestCaseData::getCurrentTimestamp());\n            }\n            if(opt.no_version == false)\n                xml.writeAttribute(\"doctest_version\", DOCTEST_VERSION_STR);\n\n            for(const auto& testCase : testCaseData.testcases) {\n                xml.startElement(\"testcase\")\n                    .writeAttribute(\"classname\", testCase.classname)\n                    .writeAttribute(\"name\", testCase.name);\n                if(opt.no_time_in_output == false)\n                    xml.writeAttribute(\"time\", testCase.time);\n                // This is not ideal, but it should be enough to mimic gtest's junit output.\n                xml.writeAttribute(\"status\", \"run\");\n\n                for(const auto& failure : testCase.failures) {\n                    xml.scopedElement(\"failure\")\n                        .writeAttribute(\"message\", failure.message)\n                        .writeAttribute(\"type\", failure.type)\n                        .writeText(failure.details, false);\n                }\n\n                for(const auto& error : testCase.errors) {\n                    xml.scopedElement(\"error\")\n                        .writeAttribute(\"message\", error.message)\n                        .writeText(error.details);\n                }\n\n                xml.endElement();\n            }\n            xml.endElement();\n            xml.endElement();\n        }\n\n        void test_case_start(const TestCaseData& in) override {\n            testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);\n            timer.start();\n        }\n\n        void test_case_reenter(const TestCaseData& in) override {\n            testCaseData.addTime(timer.getElapsedSeconds());\n            testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);\n            deepestSubcaseStackNames.clear();\n\n            timer.start();\n            testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);\n        }\n\n        void test_case_end(const CurrentTestCaseStats&) override {\n            testCaseData.addTime(timer.getElapsedSeconds());\n            testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);\n            deepestSubcaseStackNames.clear();\n        }\n\n        void test_case_exception(const TestCaseException& e) override {\n            std::lock_guard<std::mutex> lock(mutex);\n            testCaseData.addError(\"exception\", e.error_string.c_str());\n        }\n\n        void subcase_start(const SubcaseSignature& in) override {\n            deepestSubcaseStackNames.push_back(in.m_name);\n        }\n\n        void subcase_end() override {}\n\n        void log_assert(const AssertData& rb) override {\n            if(!rb.m_failed) // report only failures & ignore the `success` option\n                return;\n\n            std::lock_guard<std::mutex> lock(mutex);\n\n            std::ostringstream os;\n            os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? \":\" : \"(\")\n              << line(rb.m_line) << (opt.gnu_file_line ? \":\" : \"):\") << std::endl;\n\n            fulltext_log_assert_to_stream(os, rb);\n            log_contexts(os);\n            testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str());\n        }\n\n        void log_message(const MessageData&) override {}\n\n        void test_case_skipped(const TestCaseData&) override {}\n\n        void log_contexts(std::ostringstream& s) {\n            int num_contexts = get_num_active_contexts();\n            if(num_contexts) {\n                auto contexts = get_active_contexts();\n\n                s << \"  logged: \";\n                for(int i = 0; i < num_contexts; ++i) {\n                    s << (i == 0 ? \"\" : \"          \");\n                    contexts[i]->stringify(&s);\n                    s << std::endl;\n                }\n            }\n        }\n    };\n\n    DOCTEST_REGISTER_REPORTER(\"junit\", 0, JUnitReporter);\n\n    struct Whitespace\n    {\n        int nrSpaces;\n        explicit Whitespace(int nr)\n                : nrSpaces(nr) {}\n    };\n\n    std::ostream& operator<<(std::ostream& out, const Whitespace& ws) {\n        if(ws.nrSpaces != 0)\n            out << std::setw(ws.nrSpaces) << ' ';\n        return out;\n    }\n\n    struct ConsoleReporter : public IReporter\n    {\n        std::ostream&                 s;\n        bool                          hasLoggedCurrentTestStart;\n        std::vector<SubcaseSignature> subcasesStack;\n        size_t                        currentSubcaseLevel;\n        std::mutex                    mutex;\n\n        // caching pointers/references to objects of these types - safe to do\n        const ContextOptions& opt;\n        const TestCaseData*   tc;\n\n        ConsoleReporter(const ContextOptions& co)\n                : s(*co.cout)\n                , opt(co) {}\n\n        ConsoleReporter(const ContextOptions& co, std::ostream& ostr)\n                : s(ostr)\n                , opt(co) {}\n\n        // =========================================================================================\n        // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE\n        // =========================================================================================\n\n        void separator_to_stream() {\n            s << Color::Yellow\n              << \"===============================================================================\"\n                 \"\\n\";\n        }\n\n        const char* getSuccessOrFailString(bool success, assertType::Enum at,\n                                           const char* success_str) {\n            if(success)\n                return success_str;\n            return failureString(at);\n        }\n\n        Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) {\n            return success ? Color::BrightGreen :\n                             (at & assertType::is_warn) ? Color::Yellow : Color::Red;\n        }\n\n        void successOrFailColoredStringToStream(bool success, assertType::Enum at,\n                                                const char* success_str = \"SUCCESS\") {\n            s << getSuccessOrFailColor(success, at)\n              << getSuccessOrFailString(success, at, success_str) << \": \";\n        }\n\n        void log_contexts() {\n            int num_contexts = get_num_active_contexts();\n            if(num_contexts) {\n                auto contexts = get_active_contexts();\n\n                s << Color::None << \"  logged: \";\n                for(int i = 0; i < num_contexts; ++i) {\n                    s << (i == 0 ? \"\" : \"          \");\n                    contexts[i]->stringify(&s);\n                    s << \"\\n\";\n                }\n            }\n\n            s << \"\\n\";\n        }\n\n        // this was requested to be made virtual so users could override it\n        virtual void file_line_to_stream(const char* file, int line,\n                                        const char* tail = \"\") {\n            s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? \":\" : \"(\")\n            << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option\n            << (opt.gnu_file_line ? \":\" : \"):\") << tail;\n        }\n\n        void logTestStart() {\n            if(hasLoggedCurrentTestStart)\n                return;\n\n            separator_to_stream();\n            file_line_to_stream(tc->m_file.c_str(), tc->m_line, \"\\n\");\n            if(tc->m_description)\n                s << Color::Yellow << \"DESCRIPTION: \" << Color::None << tc->m_description << \"\\n\";\n            if(tc->m_test_suite && tc->m_test_suite[0] != '\\0')\n                s << Color::Yellow << \"TEST SUITE: \" << Color::None << tc->m_test_suite << \"\\n\";\n            if(strncmp(tc->m_name, \"  Scenario:\", 11) != 0)\n                s << Color::Yellow << \"TEST CASE:  \";\n            s << Color::None << tc->m_name << \"\\n\";\n\n            for(size_t i = 0; i < currentSubcaseLevel; ++i) {\n                if(subcasesStack[i].m_name[0] != '\\0')\n                    s << \"  \" << subcasesStack[i].m_name << \"\\n\";\n            }\n\n            if(currentSubcaseLevel != subcasesStack.size()) {\n                s << Color::Yellow << \"\\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\\n\" << Color::None;\n                for(size_t i = 0; i < subcasesStack.size(); ++i) {\n                    if(subcasesStack[i].m_name[0] != '\\0')\n                        s << \"  \" << subcasesStack[i].m_name << \"\\n\";\n                }\n            }\n\n            s << \"\\n\";\n\n            hasLoggedCurrentTestStart = true;\n        }\n\n        void printVersion() {\n            if(opt.no_version == false)\n                s << Color::Cyan << \"[doctest] \" << Color::None << \"doctest version is \\\"\"\n                  << DOCTEST_VERSION_STR << \"\\\"\\n\";\n        }\n\n        void printIntro() {\n            if(opt.no_intro == false) {\n                printVersion();\n                s << Color::Cyan << \"[doctest] \" << Color::None\n                  << \"run with \\\"--\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"help\\\" for options\\n\";\n            }\n        }\n\n        void printHelp() {\n            int sizePrefixDisplay = static_cast<int>(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY));\n            printVersion();\n            // clang-format off\n            s << Color::Cyan << \"[doctest]\\n\" << Color::None;\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"boolean values: \\\"1/on/yes/true\\\" or \\\"0/off/no/false\\\"\\n\";\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"filter  values: \\\"str1,str2,str3\\\" (comma separated strings)\\n\";\n            s << Color::Cyan << \"[doctest]\\n\" << Color::None;\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"filters use wildcards for matching strings\\n\";\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"something passes a filter if any of the strings in a filter matches\\n\";\n#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS\n            s << Color::Cyan << \"[doctest]\\n\" << Color::None;\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \\\"\" DOCTEST_CONFIG_OPTIONS_PREFIX \"\\\" PREFIX!!!\\n\";\n#endif\n            s << Color::Cyan << \"[doctest]\\n\" << Color::None;\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"Query flags - the program quits after them. Available:\\n\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"?,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"help, -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"h                      \"\n              << Whitespace(sizePrefixDisplay*0) <<  \"prints this message\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"v,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"version                       \"\n              << Whitespace(sizePrefixDisplay*1) << \"prints the version\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"c,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"count                         \"\n              << Whitespace(sizePrefixDisplay*1) << \"prints the number of matching tests\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"ltc, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"list-test-cases               \"\n              << Whitespace(sizePrefixDisplay*1) << \"lists all matching tests by name\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"lts, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"list-test-suites              \"\n              << Whitespace(sizePrefixDisplay*1) << \"lists all matching test suites\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"lr,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"list-reporters                \"\n              << Whitespace(sizePrefixDisplay*1) << \"lists all registered reporters\\n\\n\";\n            // ================================================================================== << 79\n            s << Color::Cyan << \"[doctest] \" << Color::None;\n            s << \"The available <int>/<string> options/filters are:\\n\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"tc,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"test-case=<filters>           \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters     tests by their name\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"tce, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"test-case-exclude=<filters>   \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters OUT tests by their name\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"sf,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"source-file=<filters>         \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters     tests by their file\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"sfe, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"source-file-exclude=<filters> \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters OUT tests by their file\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"ts,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"test-suite=<filters>          \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters     tests by their test suite\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"tse, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"test-suite-exclude=<filters>  \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters OUT tests by their test suite\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"sc,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"subcase=<filters>             \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters     subcases by their name\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"sce, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"subcase-exclude=<filters>     \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters OUT subcases by their name\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"r,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"reporters=<filters>           \"\n              << Whitespace(sizePrefixDisplay*1) << \"reporters to use (console is default)\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"o,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"out=<string>                  \"\n              << Whitespace(sizePrefixDisplay*1) << \"output filename\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"ob,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"order-by=<string>             \"\n              << Whitespace(sizePrefixDisplay*1) << \"how the tests should be ordered\\n\";\n            s << Whitespace(sizePrefixDisplay*3) << \"                                       <string> - [file/suite/name/rand/none]\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"rs,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"rand-seed=<int>               \"\n              << Whitespace(sizePrefixDisplay*1) << \"seed for random ordering\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"f,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"first=<int>                   \"\n              << Whitespace(sizePrefixDisplay*1) << \"the first test passing the filters to\\n\";\n            s << Whitespace(sizePrefixDisplay*3) << \"                                       execute - for range-based execution\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"l,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"last=<int>                    \"\n              << Whitespace(sizePrefixDisplay*1) << \"the last test passing the filters to\\n\";\n            s << Whitespace(sizePrefixDisplay*3) << \"                                       execute - for range-based execution\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"aa,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"abort-after=<int>             \"\n              << Whitespace(sizePrefixDisplay*1) << \"stop after <int> failed assertions\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"scfl,--\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"subcase-filter-levels=<int>   \"\n              << Whitespace(sizePrefixDisplay*1) << \"apply filters for the first <int> levels\\n\";\n            s << Color::Cyan << \"\\n[doctest] \" << Color::None;\n            s << \"Bool options - can be used like flags and true is assumed. Available:\\n\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"s,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"success=<bool>                \"\n              << Whitespace(sizePrefixDisplay*1) << \"include successful assertions in output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"cs,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"case-sensitive=<bool>         \"\n              << Whitespace(sizePrefixDisplay*1) << \"filters being treated as case sensitive\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"e,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"exit=<bool>                   \"\n              << Whitespace(sizePrefixDisplay*1) << \"exits after the tests finish\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"d,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"duration=<bool>               \"\n              << Whitespace(sizePrefixDisplay*1) << \"prints the time duration of each test\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"m,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"minimal=<bool>                \"\n              << Whitespace(sizePrefixDisplay*1) << \"minimal console output (only failures)\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"q,   --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"quiet=<bool>                  \"\n              << Whitespace(sizePrefixDisplay*1) << \"no console output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"nt,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-throw=<bool>               \"\n              << Whitespace(sizePrefixDisplay*1) << \"skips exceptions-related assert checks\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"ne,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-exitcode=<bool>            \"\n              << Whitespace(sizePrefixDisplay*1) << \"returns (or exits) always with success\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"nr,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-run=<bool>                 \"\n              << Whitespace(sizePrefixDisplay*1) << \"skips all runtime doctest operations\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"ni,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-intro=<bool>               \"\n              << Whitespace(sizePrefixDisplay*1) << \"omit the framework intro in the output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"nv,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-version=<bool>             \"\n              << Whitespace(sizePrefixDisplay*1) << \"omit the framework version in the output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"nc,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-colors=<bool>              \"\n              << Whitespace(sizePrefixDisplay*1) << \"disables colors in output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"fc,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"force-colors=<bool>           \"\n              << Whitespace(sizePrefixDisplay*1) << \"use colors even when not in a tty\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"nb,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-breaks=<bool>              \"\n              << Whitespace(sizePrefixDisplay*1) << \"disables breakpoints in debuggers\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"ns,  --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-skip=<bool>                \"\n              << Whitespace(sizePrefixDisplay*1) << \"don't skip test cases marked as skip\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"gfl, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"gnu-file-line=<bool>          \"\n              << Whitespace(sizePrefixDisplay*1) << \":n: vs (n): for line numbers in output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"npf, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-path-filenames=<bool>      \"\n              << Whitespace(sizePrefixDisplay*1) << \"only filenames and no paths in output\\n\";\n            s << \" -\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"nln, --\" DOCTEST_OPTIONS_PREFIX_DISPLAY \"no-line-numbers=<bool>        \"\n              << Whitespace(sizePrefixDisplay*1) << \"0 instead of real line numbers in output\\n\";\n            // ================================================================================== << 79\n            // clang-format on\n\n            s << Color::Cyan << \"\\n[doctest] \" << Color::None;\n            s << \"for more information visit the project documentation\\n\\n\";\n        }\n\n        void printRegisteredReporters() {\n            printVersion();\n            auto printReporters = [this] (const reporterMap& reporters, const char* type) {\n                if(reporters.size()) {\n                    s << Color::Cyan << \"[doctest] \" << Color::None << \"listing all registered \" << type << \"\\n\";\n                    for(auto& curr : reporters)\n                        s << \"priority: \" << std::setw(5) << curr.first.first\n                          << \" name: \" << curr.first.second << \"\\n\";\n                }\n            };\n            printReporters(getListeners(), \"listeners\");\n            printReporters(getReporters(), \"reporters\");\n        }\n\n        // =========================================================================================\n        // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE\n        // =========================================================================================\n\n        void report_query(const QueryData& in) override {\n            if(opt.version) {\n                printVersion();\n            } else if(opt.help) {\n                printHelp();\n            } else if(opt.list_reporters) {\n                printRegisteredReporters();\n            } else if(opt.count || opt.list_test_cases) {\n                if(opt.list_test_cases) {\n                    s << Color::Cyan << \"[doctest] \" << Color::None\n                      << \"listing all test case names\\n\";\n                    separator_to_stream();\n                }\n\n                for(unsigned i = 0; i < in.num_data; ++i)\n                    s << Color::None << in.data[i]->m_name << \"\\n\";\n\n                separator_to_stream();\n\n                s << Color::Cyan << \"[doctest] \" << Color::None\n                  << \"unskipped test cases passing the current filters: \"\n                  << g_cs->numTestCasesPassingFilters << \"\\n\";\n\n            } else if(opt.list_test_suites) {\n                s << Color::Cyan << \"[doctest] \" << Color::None << \"listing all test suites\\n\";\n                separator_to_stream();\n\n                for(unsigned i = 0; i < in.num_data; ++i)\n                    s << Color::None << in.data[i]->m_test_suite << \"\\n\";\n\n                separator_to_stream();\n\n                s << Color::Cyan << \"[doctest] \" << Color::None\n                  << \"unskipped test cases passing the current filters: \"\n                  << g_cs->numTestCasesPassingFilters << \"\\n\";\n                s << Color::Cyan << \"[doctest] \" << Color::None\n                  << \"test suites with unskipped test cases passing the current filters: \"\n                  << g_cs->numTestSuitesPassingFilters << \"\\n\";\n            }\n        }\n\n        void test_run_start() override {\n            if(!opt.minimal)\n                printIntro();\n        }\n\n        void test_run_end(const TestRunStats& p) override {\n            if(opt.minimal && p.numTestCasesFailed == 0)\n                return;\n\n            separator_to_stream();\n            s << std::dec;\n\n            auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast<unsigned>(p.numAsserts))) + 1)));\n            auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast<unsigned>(p.numAsserts - p.numAssertsFailed))) + 1)));\n            auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast<unsigned>(p.numAssertsFailed))) + 1)));\n            const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0;\n            s << Color::Cyan << \"[doctest] \" << Color::None << \"test cases: \" << std::setw(totwidth)\n              << p.numTestCasesPassingFilters << \" | \"\n              << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None :\n                                                                          Color::Green)\n              << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << \" passed\"\n              << Color::None << \" | \" << (p.numTestCasesFailed > 0 ? Color::Red : Color::None)\n              << std::setw(failwidth) << p.numTestCasesFailed << \" failed\" << Color::None << \" |\";\n            if(opt.no_skipped_summary == false) {\n                const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters;\n                s << \" \" << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped\n                  << \" skipped\" << Color::None;\n            }\n            s << \"\\n\";\n            s << Color::Cyan << \"[doctest] \" << Color::None << \"assertions: \" << std::setw(totwidth)\n              << p.numAsserts << \" | \"\n              << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green)\n              << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << \" passed\" << Color::None\n              << \" | \" << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth)\n              << p.numAssertsFailed << \" failed\" << Color::None << \" |\\n\";\n            s << Color::Cyan << \"[doctest] \" << Color::None\n              << \"Status: \" << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green)\n              << ((p.numTestCasesFailed > 0) ? \"FAILURE!\" : \"SUCCESS!\") << Color::None << std::endl;\n        }\n\n        void test_case_start(const TestCaseData& in) override {\n            hasLoggedCurrentTestStart = false;\n            tc                        = &in;\n            subcasesStack.clear();\n            currentSubcaseLevel = 0;\n        }\n        \n        void test_case_reenter(const TestCaseData&) override {\n            subcasesStack.clear();\n        }\n\n        void test_case_end(const CurrentTestCaseStats& st) override {\n            if(tc->m_no_output)\n                return;\n\n            // log the preamble of the test case only if there is something\n            // else to print - something other than that an assert has failed\n            if(opt.duration ||\n               (st.failure_flags && st.failure_flags != TestCaseFailureReason::AssertFailure))\n                logTestStart();\n\n            if(opt.duration)\n                s << Color::None << std::setprecision(6) << std::fixed << st.seconds\n                  << \" s: \" << tc->m_name << \"\\n\";\n\n            if(st.failure_flags & TestCaseFailureReason::Timeout)\n                s << Color::Red << \"Test case exceeded time limit of \" << std::setprecision(6)\n                  << std::fixed << tc->m_timeout << \"!\\n\";\n\n            if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) {\n                s << Color::Red << \"Should have failed but didn't! Marking it as failed!\\n\";\n            } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) {\n                s << Color::Yellow << \"Failed as expected so marking it as not failed\\n\";\n            } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) {\n                s << Color::Yellow << \"Allowed to fail so marking it as not failed\\n\";\n            } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) {\n                s << Color::Red << \"Didn't fail exactly \" << tc->m_expected_failures\n                  << \" times so marking it as failed!\\n\";\n            } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) {\n                s << Color::Yellow << \"Failed exactly \" << tc->m_expected_failures\n                  << \" times as expected so marking it as not failed!\\n\";\n            }\n            if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) {\n                s << Color::Red << \"Aborting - too many failed asserts!\\n\";\n            }\n            s << Color::None; // lgtm [cpp/useless-expression]\n        }\n\n        void test_case_exception(const TestCaseException& e) override {\n            std::lock_guard<std::mutex> lock(mutex);\n            if(tc->m_no_output)\n                return;\n\n            logTestStart();\n\n            file_line_to_stream(tc->m_file.c_str(), tc->m_line, \" \");\n            successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require :\n                                                                   assertType::is_check);\n            s << Color::Red << (e.is_crash ? \"test case CRASHED: \" : \"test case THREW exception: \")\n              << Color::Cyan << e.error_string << \"\\n\";\n\n            int num_stringified_contexts = get_num_stringified_contexts();\n            if(num_stringified_contexts) {\n                auto stringified_contexts = get_stringified_contexts();\n                s << Color::None << \"  logged: \";\n                for(int i = num_stringified_contexts; i > 0; --i) {\n                    s << (i == num_stringified_contexts ? \"\" : \"          \")\n                      << stringified_contexts[i - 1] << \"\\n\";\n                }\n            }\n            s << \"\\n\" << Color::None;\n        }\n\n        void subcase_start(const SubcaseSignature& subc) override {\n            subcasesStack.push_back(subc);\n            ++currentSubcaseLevel;\n            hasLoggedCurrentTestStart = false;\n        }\n\n        void subcase_end() override {\n            --currentSubcaseLevel;\n            hasLoggedCurrentTestStart = false;\n        }\n\n        void log_assert(const AssertData& rb) override {\n            if((!rb.m_failed && !opt.success) || tc->m_no_output)\n                return;\n\n            std::lock_guard<std::mutex> lock(mutex);\n\n            logTestStart();\n\n            file_line_to_stream(rb.m_file, rb.m_line, \" \");\n            successOrFailColoredStringToStream(!rb.m_failed, rb.m_at);\n\n            fulltext_log_assert_to_stream(s, rb);\n\n            log_contexts();\n        }\n\n        void log_message(const MessageData& mb) override {\n            if(tc->m_no_output)\n                return;\n\n            std::lock_guard<std::mutex> lock(mutex);\n\n            logTestStart();\n\n            file_line_to_stream(mb.m_file, mb.m_line, \" \");\n            s << getSuccessOrFailColor(false, mb.m_severity)\n              << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity,\n                                        \"MESSAGE\") << \": \";\n            s << Color::None << mb.m_string << \"\\n\";\n            log_contexts();\n        }\n\n        void test_case_skipped(const TestCaseData&) override {}\n    };\n\n    DOCTEST_REGISTER_REPORTER(\"console\", 0, ConsoleReporter);\n\n#ifdef DOCTEST_PLATFORM_WINDOWS\n    struct DebugOutputWindowReporter : public ConsoleReporter\n    {\n        DOCTEST_THREAD_LOCAL static std::ostringstream oss;\n\n        DebugOutputWindowReporter(const ContextOptions& co)\n                : ConsoleReporter(co, oss) {}\n\n#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg)                                    \\\n    void func(type arg) override {                                                                 \\\n        bool with_col = g_no_colors;                                                               \\\n        g_no_colors   = false;                                                                     \\\n        ConsoleReporter::func(arg);                                                                \\\n        if(oss.tellp() != std::streampos{}) {                                                      \\\n            DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str());                                        \\\n            oss.str(\"\");                                                                           \\\n        }                                                                                          \\\n        g_no_colors = with_col;                                                                    \\\n    }\n\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in)\n        DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in)\n    };\n\n    DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss;\n#endif // DOCTEST_PLATFORM_WINDOWS\n\n    // the implementation of parseOption()\n    bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) {\n        // going from the end to the beginning and stopping on the first occurrence from the end\n        for(int i = argc; i > 0; --i) {\n            auto index = i - 1;\n            auto temp = std::strstr(argv[index], pattern);\n            if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue\n                // eliminate matches in which the chars before the option are not '-'\n                bool noBadCharsFound = true;\n                auto curr            = argv[index];\n                while(curr != temp) {\n                    if(*curr++ != '-') {\n                        noBadCharsFound = false;\n                        break;\n                    }\n                }\n                if(noBadCharsFound && argv[index][0] == '-') {\n                    if(value) {\n                        // parsing the value of an option\n                        temp += strlen(pattern);\n                        const unsigned len = strlen(temp);\n                        if(len) {\n                            *value = temp;\n                            return true;\n                        }\n                    } else {\n                        // just a flag - no value\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    // parses an option and returns the string after the '=' character\n    bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr,\n                     const String& defaultVal = String()) {\n        if(value)\n            *value = defaultVal;\n#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS\n        // offset (normally 3 for \"dt-\") to skip prefix\n        if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value))\n            return true;\n#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS\n        return parseOptionImpl(argc, argv, pattern, value);\n    }\n\n    // locates a flag on the command line\n    bool parseFlag(int argc, const char* const* argv, const char* pattern) {\n        return parseOption(argc, argv, pattern);\n    }\n\n    // parses a comma separated list of words after a pattern in one of the arguments in argv\n    bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern,\n                           std::vector<String>& res) {\n        String filtersString;\n        if(parseOption(argc, argv, pattern, &filtersString)) {\n            // tokenize with \",\" as a separator, unless escaped with backslash\n            std::ostringstream s;\n            auto flush = [&s, &res]() {\n                auto string = s.str();\n                if(string.size() > 0) {\n                    res.push_back(string.c_str());\n                }\n                s.str(\"\");\n            };\n\n            bool seenBackslash = false;\n            const char* current = filtersString.c_str();\n            const char* end = current + strlen(current);\n            while(current != end) {\n                char character = *current++;\n                if(seenBackslash) {\n                    seenBackslash = false;\n                    if(character == ',') {\n                        s.put(',');\n                        continue;\n                    }\n                    s.put('\\\\');\n                }\n                if(character == '\\\\') {\n                    seenBackslash = true;\n                } else if(character == ',') {\n                    flush();\n                } else {\n                    s.put(character);\n                }\n            }\n\n            if(seenBackslash) {\n                s.put('\\\\');\n            }\n            flush();\n            return true;\n        }\n        return false;\n    }\n\n    enum optionType\n    {\n        option_bool,\n        option_int\n    };\n\n    // parses an int/bool option from the command line\n    bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type,\n                        int& res) {\n        String parsedValue;\n        if(!parseOption(argc, argv, pattern, &parsedValue))\n            return false;\n\n        if(type == 0) {\n            // boolean\n            const char positive[][5] = {\"1\", \"true\", \"on\", \"yes\"};  // 5 - strlen(\"true\") + 1\n            const char negative[][6] = {\"0\", \"false\", \"off\", \"no\"}; // 6 - strlen(\"false\") + 1\n\n            // if the value matches any of the positive/negative possibilities\n            for(unsigned i = 0; i < 4; i++) {\n                if(parsedValue.compare(positive[i], true) == 0) {\n                    res = 1; //!OCLINT parameter reassignment\n                    return true;\n                }\n                if(parsedValue.compare(negative[i], true) == 0) {\n                    res = 0; //!OCLINT parameter reassignment\n                    return true;\n                }\n            }\n        } else {\n            // integer\n            // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse...\n            int theInt = std::atoi(parsedValue.c_str()); // NOLINT\n            if(theInt != 0) {\n                res = theInt; //!OCLINT parameter reassignment\n                return true;\n            }\n        }\n        return false;\n    }\n} // namespace\n\nContext::Context(int argc, const char* const* argv)\n        : p(new detail::ContextState) {\n    parseArgs(argc, argv, true);\n    if(argc)\n        p->binary_name = argv[0];\n}\n\nContext::~Context() {\n    if(g_cs == p)\n        g_cs = nullptr;\n    delete p;\n}\n\nvoid Context::applyCommandLine(int argc, const char* const* argv) {\n    parseArgs(argc, argv);\n    if(argc)\n        p->binary_name = argv[0];\n}\n\n// parses args\nvoid Context::parseArgs(int argc, const char* const* argv, bool withDefaults) {\n    using namespace detail;\n\n    // clang-format off\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"source-file=\",        p->filters[0]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"sf=\",                 p->filters[0]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"source-file-exclude=\",p->filters[1]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"sfe=\",                p->filters[1]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"test-suite=\",         p->filters[2]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"ts=\",                 p->filters[2]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"test-suite-exclude=\", p->filters[3]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"tse=\",                p->filters[3]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"test-case=\",          p->filters[4]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"tc=\",                 p->filters[4]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"test-case-exclude=\",  p->filters[5]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"tce=\",                p->filters[5]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"subcase=\",            p->filters[6]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"sc=\",                 p->filters[6]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"subcase-exclude=\",    p->filters[7]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"sce=\",                p->filters[7]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"reporters=\",          p->filters[8]);\n    parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"r=\",                  p->filters[8]);\n    // clang-format on\n\n    int    intRes = 0;\n    String strRes;\n\n#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default)                                   \\\n    if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name \"=\", option_bool, intRes) ||  \\\n       parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname \"=\", option_bool, intRes))   \\\n        p->var = static_cast<bool>(intRes);                                                        \\\n    else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) ||                           \\\n            parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname))                            \\\n        p->var = true;                                                                             \\\n    else if(withDefaults)                                                                          \\\n    p->var = default\n\n#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default)                                        \\\n    if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name \"=\", option_int, intRes) ||   \\\n       parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname \"=\", option_int, intRes))    \\\n        p->var = intRes;                                                                           \\\n    else if(withDefaults)                                                                          \\\n    p->var = default\n\n#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default)                                        \\\n    if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name \"=\", &strRes, default) ||        \\\n       parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname \"=\", &strRes, default) ||       \\\n       withDefaults)                                                                               \\\n    p->var = strRes\n\n    // clang-format off\n    DOCTEST_PARSE_STR_OPTION(\"out\", \"o\", out, \"\");\n    DOCTEST_PARSE_STR_OPTION(\"order-by\", \"ob\", order_by, \"file\");\n    DOCTEST_PARSE_INT_OPTION(\"rand-seed\", \"rs\", rand_seed, 0);\n\n    DOCTEST_PARSE_INT_OPTION(\"first\", \"f\", first, 0);\n    DOCTEST_PARSE_INT_OPTION(\"last\", \"l\", last, UINT_MAX);\n\n    DOCTEST_PARSE_INT_OPTION(\"abort-after\", \"aa\", abort_after, 0);\n    DOCTEST_PARSE_INT_OPTION(\"subcase-filter-levels\", \"scfl\", subcase_filter_levels, INT_MAX);\n\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"success\", \"s\", success, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"case-sensitive\", \"cs\", case_sensitive, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"exit\", \"e\", exit, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"duration\", \"d\", duration, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"minimal\", \"m\", minimal, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"quiet\", \"q\", quiet, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-throw\", \"nt\", no_throw, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-exitcode\", \"ne\", no_exitcode, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-run\", \"nr\", no_run, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-intro\", \"ni\", no_intro, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-version\", \"nv\", no_version, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-colors\", \"nc\", no_colors, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"force-colors\", \"fc\", force_colors, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-breaks\", \"nb\", no_breaks, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-skip\", \"ns\", no_skip, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"gnu-file-line\", \"gfl\", gnu_file_line, !bool(DOCTEST_MSVC));\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-path-filenames\", \"npf\", no_path_in_filenames, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-line-numbers\", \"nln\", no_line_numbers, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-debug-output\", \"ndo\", no_debug_output, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-skipped-summary\", \"nss\", no_skipped_summary, false);\n    DOCTEST_PARSE_AS_BOOL_OR_FLAG(\"no-time-in-output\", \"ntio\", no_time_in_output, false);\n    // clang-format on\n\n    if(withDefaults) {\n        p->help             = false;\n        p->version          = false;\n        p->count            = false;\n        p->list_test_cases  = false;\n        p->list_test_suites = false;\n        p->list_reporters   = false;\n    }\n    if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"help\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"h\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"?\")) {\n        p->help = true;\n        p->exit = true;\n    }\n    if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"version\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"v\")) {\n        p->version = true;\n        p->exit    = true;\n    }\n    if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"count\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"c\")) {\n        p->count = true;\n        p->exit  = true;\n    }\n    if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"list-test-cases\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"ltc\")) {\n        p->list_test_cases = true;\n        p->exit            = true;\n    }\n    if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"list-test-suites\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"lts\")) {\n        p->list_test_suites = true;\n        p->exit             = true;\n    }\n    if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"list-reporters\") ||\n       parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX \"lr\")) {\n        p->list_reporters = true;\n        p->exit           = true;\n    }\n}\n\n// allows the user to add procedurally to the filters from the command line\nvoid Context::addFilter(const char* filter, const char* value) { setOption(filter, value); }\n\n// allows the user to clear all filters from the command line\nvoid Context::clearFilters() {\n    for(auto& curr : p->filters)\n        curr.clear();\n}\n\n// allows the user to override procedurally the bool options from the command line\nvoid Context::setOption(const char* option, bool value) {\n    setOption(option, value ? \"true\" : \"false\");\n}\n\n// allows the user to override procedurally the int options from the command line\nvoid Context::setOption(const char* option, int value) {\n    setOption(option, toString(value).c_str());\n    // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)\n}\n\n// allows the user to override procedurally the string options from the command line\nvoid Context::setOption(const char* option, const char* value) {\n    auto argv   = String(\"-\") + option + \"=\" + value;\n    auto lvalue = argv.c_str();\n    parseArgs(1, &lvalue);\n}\n\n// users should query this in their main() and exit the program if true\nbool Context::shouldExit() { return p->exit; }\n\nvoid Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; }\n\nvoid Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; }\n\nvoid Context::setCout(std::ostream* out) { p->cout = out; }\n\nstatic class DiscardOStream : public std::ostream\n{\nprivate:\n    class : public std::streambuf\n    {\n    private:\n        // allowing some buffering decreases the amount of calls to overflow\n        char buf[1024];\n\n    protected:\n        std::streamsize xsputn(const char_type*, std::streamsize count) override { return count; }\n\n        int_type overflow(int_type ch) override {\n            setp(std::begin(buf), std::end(buf));\n            return traits_type::not_eof(ch);\n        }\n    } discardBuf;\n\npublic:\n    DiscardOStream()\n            : std::ostream(&discardBuf) {}\n} discardOut;\n\n// the main function that does all the filtering and test running\nint Context::run() {\n    using namespace detail;\n\n    // save the old context state in case such was setup - for using asserts out of a testing context\n    auto old_cs = g_cs;\n    // this is the current contest\n    g_cs               = p;\n    is_running_in_test = true;\n\n    g_no_colors = p->no_colors;\n    p->resetRunData();\n\n    std::fstream fstr;\n    if(p->cout == nullptr) {\n        if(p->quiet) {\n            p->cout = &discardOut;\n        } else if(p->out.size()) {\n            // to a file if specified\n            fstr.open(p->out.c_str(), std::fstream::out);\n            p->cout = &fstr;\n        } else {\n            // stdout by default\n            p->cout = &std::cout;\n        }\n    }\n\n    FatalConditionHandler::allocateAltStackMem();\n\n    auto cleanup_and_return = [&]() {\n        FatalConditionHandler::freeAltStackMem();\n\n        if(fstr.is_open())\n            fstr.close();\n\n        // restore context\n        g_cs               = old_cs;\n        is_running_in_test = false;\n\n        // we have to free the reporters which were allocated when the run started\n        for(auto& curr : p->reporters_currently_used)\n            delete curr;\n        p->reporters_currently_used.clear();\n\n        if(p->numTestCasesFailed && !p->no_exitcode)\n            return EXIT_FAILURE;\n        return EXIT_SUCCESS;\n    };\n\n    // setup default reporter if none is given through the command line\n    if(p->filters[8].empty())\n        p->filters[8].push_back(\"console\");\n\n    // check to see if any of the registered reporters has been selected\n    for(auto& curr : getReporters()) {\n        if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive))\n            p->reporters_currently_used.push_back(curr.second(*g_cs));\n    }\n\n    // TODO: check if there is nothing in reporters_currently_used\n\n    // prepend all listeners\n    for(auto& curr : getListeners())\n        p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs));\n\n#ifdef DOCTEST_PLATFORM_WINDOWS\n    if(isDebuggerActive() && p->no_debug_output == false)\n        p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs));\n#endif // DOCTEST_PLATFORM_WINDOWS\n\n    // handle version, help and no_run\n    if(p->no_run || p->version || p->help || p->list_reporters) {\n        DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData());\n\n        return cleanup_and_return();\n    }\n\n    std::vector<const TestCase*> testArray;\n    for(auto& curr : getRegisteredTests())\n        testArray.push_back(&curr);\n    p->numTestCases = testArray.size();\n\n    // sort the collected records\n    if(!testArray.empty()) {\n        if(p->order_by.compare(\"file\", true) == 0) {\n            std::sort(testArray.begin(), testArray.end(), fileOrderComparator);\n        } else if(p->order_by.compare(\"suite\", true) == 0) {\n            std::sort(testArray.begin(), testArray.end(), suiteOrderComparator);\n        } else if(p->order_by.compare(\"name\", true) == 0) {\n            std::sort(testArray.begin(), testArray.end(), nameOrderComparator);\n        } else if(p->order_by.compare(\"rand\", true) == 0) {\n            std::srand(p->rand_seed);\n\n            // random_shuffle implementation\n            const auto first = &testArray[0];\n            for(size_t i = testArray.size() - 1; i > 0; --i) {\n                int idxToSwap = std::rand() % (i + 1); // NOLINT\n\n                const auto temp = first[i];\n\n                first[i]         = first[idxToSwap];\n                first[idxToSwap] = temp;\n            }\n        } else if(p->order_by.compare(\"none\", true) == 0) {\n            // means no sorting - beneficial for death tests which call into the executable\n            // with a specific test case in mind - we don't want to slow down the startup times\n        }\n    }\n\n    std::set<String> testSuitesPassingFilt;\n\n    bool                             query_mode = p->count || p->list_test_cases || p->list_test_suites;\n    std::vector<const TestCaseData*> queryResults;\n\n    if(!query_mode)\n        DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY);\n\n    // invoke the registered functions if they match the filter criteria (or just count them)\n    for(auto& curr : testArray) {\n        const auto& tc = *curr;\n\n        bool skip_me = false;\n        if(tc.m_skip && !p->no_skip)\n            skip_me = true;\n\n        if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive))\n            skip_me = true;\n        if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive))\n            skip_me = true;\n        if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive))\n            skip_me = true;\n        if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive))\n            skip_me = true;\n        if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive))\n            skip_me = true;\n        if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive))\n            skip_me = true;\n\n        if(!skip_me)\n            p->numTestCasesPassingFilters++;\n\n        // skip the test if it is not in the execution range\n        if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) ||\n           (p->first > p->numTestCasesPassingFilters))\n            skip_me = true;\n\n        if(skip_me) {\n            if(!query_mode)\n                DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc);\n            continue;\n        }\n\n        // do not execute the test if we are to only count the number of filter passing tests\n        if(p->count)\n            continue;\n\n        // print the name of the test and don't execute it\n        if(p->list_test_cases) {\n            queryResults.push_back(&tc);\n            continue;\n        }\n\n        // print the name of the test suite if not done already and don't execute it\n        if(p->list_test_suites) {\n            if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\\0') {\n                queryResults.push_back(&tc);\n                testSuitesPassingFilt.insert(tc.m_test_suite);\n                p->numTestSuitesPassingFilters++;\n            }\n            continue;\n        }\n\n        // execute the test if it passes all the filtering\n        {\n            p->currentTest = &tc;\n\n            p->failure_flags = TestCaseFailureReason::None;\n            p->seconds       = 0;\n\n            // reset atomic counters\n            p->numAssertsFailedCurrentTest_atomic = 0;\n            p->numAssertsCurrentTest_atomic       = 0;\n\n            p->subcasesPassed.clear();\n\n            DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc);\n\n            p->timer.start();\n            \n            bool run_test = true;\n\n            do {\n                // reset some of the fields for subcases (except for the set of fully passed ones)\n                p->should_reenter          = false;\n                p->subcasesCurrentMaxLevel = 0;\n                p->subcasesStack.clear();\n\n                p->shouldLogCurrentException = true;\n\n                // reset stuff for logging with INFO()\n                p->stringifiedContexts.clear();\n\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n                try {\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method)\nDOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable\n                    FatalConditionHandler fatalConditionHandler; // Handle signals\n                    // execute the test\n                    tc.m_test();\n                    fatalConditionHandler.reset();\nDOCTEST_MSVC_SUPPRESS_WARNING_POP\n#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS\n                } catch(const TestFailureException&) {\n                    p->failure_flags |= TestCaseFailureReason::AssertFailure;\n                } catch(...) {\n                    DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception,\n                                                      {translateActiveException(), false});\n                    p->failure_flags |= TestCaseFailureReason::Exception;\n                }\n#endif // DOCTEST_CONFIG_NO_EXCEPTIONS\n\n                // exit this loop if enough assertions have failed - even if there are more subcases\n                if(p->abort_after > 0 &&\n                   p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) {\n                    run_test = false;\n                    p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts;\n                }\n                \n                if(p->should_reenter && run_test)\n                    DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc);\n                if(!p->should_reenter)\n                    run_test = false;\n            } while(run_test);\n\n            p->finalizeTestCaseData();\n\n            DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs);\n\n            p->currentTest = nullptr;\n\n            // stop executing tests if enough assertions have failed\n            if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after)\n                break;\n        }\n    }\n\n    if(!query_mode) {\n        DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs);\n    } else {\n        QueryData qdata;\n        qdata.run_stats = g_cs;\n        qdata.data      = queryResults.data();\n        qdata.num_data  = unsigned(queryResults.size());\n        DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata);\n    }\n\n    return cleanup_and_return();\n}\n\nIReporter::~IReporter() = default;\n\nint IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); }\nconst IContextScope* const* IReporter::get_active_contexts() {\n    return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr;\n}\n\nint IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); }\nconst String* IReporter::get_stringified_contexts() {\n    return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr;\n}\n\nnamespace detail {\n    void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) {\n        if(isReporter)\n            getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c));\n        else\n            getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c));\n    }\n} // namespace detail\n\n} // namespace doctest\n\n#endif // DOCTEST_CONFIG_DISABLE\n\n#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\nDOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182\nint main(int argc, char** argv) { return doctest::Context(argc, argv).run(); }\nDOCTEST_MSVC_SUPPRESS_WARNING_POP\n#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\n\nDOCTEST_CLANG_SUPPRESS_WARNING_POP\nDOCTEST_MSVC_SUPPRESS_WARNING_POP\nDOCTEST_GCC_SUPPRESS_WARNING_POP\n\nDOCTEST_SUPPRESS_COMMON_WARNINGS_POP\n\n#endif // DOCTEST_LIBRARY_IMPLEMENTATION\n#endif // DOCTEST_CONFIG_IMPLEMENT\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(\n   VERSION 3.31\n)\ninclude(CheckIPOSupported)\n\noption(BUILD_DOC\n   \"Build LaTeX documentation\"\n   OFF\n)\n\nproject(ipr\n   VERSION 0.50\n   LANGUAGES CXX\n)\n\nset(CMAKE_CXX_STANDARD 23)\nset(CMAKE_CXX_STANDARD_REQUIRED True)\nset(CMAKE_CXX_EXTENSIONS False)\n\n# Enable link-time optimization or close approximation\ncheck_ipo_supported(RESULT ipo_supported OUTPUT ipo_disabled_msg)\nif (ipo_supported)\n   set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)\nelse()\n   message(WARNING \"LTO disabled: ${ipo_disabled_msg}\")\nendif()\n\nadd_library(${PROJECT_NAME}\n   src/impl.cxx\n   src/cxx-ipr-io.cxx\n   src/cxx-ipr-traversal.cxx\n   src/input.cxx\n   src/utility.cxx\n   src/cxx-ipr.cxx\n)\n\ntarget_sources(${PROJECT_NAME}\n   PUBLIC\n      FILE_SET CXX_MODULES FILES\n         src/cxx-ipr-vocabulary.ixx\n         src/cxx-ipr-syntax.ixx\n         src/cxx-ipr.ixx\n         src/cxx-ipr-traversal.ixx\n         src/cxx-ipr-io.ixx\n)\n\ntarget_include_directories(${PROJECT_NAME}\n   PUBLIC\n      ${PROJECT_SOURCE_DIR}/include\n)\n\ntarget_sources(${PROJECT_NAME}\n    PRIVATE\n        ${PROJECT_SOURCE_DIR}/include/ipr/impl\n        ${PROJECT_SOURCE_DIR}/include/ipr/lexer\n        ${PROJECT_SOURCE_DIR}/include/ipr/node-category\n        ${PROJECT_SOURCE_DIR}/include/ipr/utility-impl\n        ${PROJECT_SOURCE_DIR}/include/ipr/input\n        ${PROJECT_SOURCE_DIR}/3rdparty/doctest/doctest.h\n)\n\nset_target_properties(${PROJECT_NAME}\n   PROPERTIES\n      CXX_STANDARD 23\n      CXX_STANDARD_REQUIRED ON\n\t   CXX_EXTENSIONS OFF\n)\n\ntarget_compile_options(${PROJECT_NAME}\n   PUBLIC\n      $<$<CXX_COMPILER_ID:MSVC>:\n         /permissive-  # Turn on strict language conformance\n         /EHsc         # Turn on exception handling semantics\n      >\n      $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:\n         -Wno-overloaded-virtual  # Avoid bogus warnings against foundational techniques.\n      >\n   PRIVATE\n      $<$<CXX_COMPILER_ID:MSVC>:\n         /W2           # Usual warnings\n      >\n      $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:\n         -Wall         # Turn on all useful warnings\n         -pedantic     # Turn on strict language conformance\n         >\n      $<$<CXX_COMPILER_ID:Clang>:\n\t\t -Wno-delete-non-abstract-non-virtual-dtor # System headers plagued\n      >\n)\n\ntarget_compile_definitions(${PROJECT_NAME}\n   PRIVATE\n\t   $<$<PLATFORM_ID:UNIX>:\n\t\t   _FILE_OFFSET_BITS=64 # We want the ability to process large files.\n\t   >\n)\n\nset_property(SOURCE ${PROJECT_SOURCE_DIR}/src/input.cxx APPEND PROPERTY COMPILE_DEFINITIONS NDEBUG)\n\ninstall(\n   TARGETS ipr\n   LIBRARY DESTINATION lib\n   ARCHIVE DESTINATION lib\n   FILE_SET CXX_MODULES DESTINATION lib/cmake/ipr\n)\ninstall(\n   DIRECTORY include/ipr\n   DESTINATION include\n)\n\nif(BUILD_DOC)\n   include(cmake/UseLATEX.cmake)\n   add_subdirectory(doc)\nendif()\n\n# Testing\nenable_testing()\nset(DOCTEST_INCLUDE_DIR \"${PROJECT_SOURCE_DIR}/3rdparty\")\nadd_subdirectory(tests)\n\n"
  },
  {
    "path": "ChangeLog",
    "content": "2019-06-26  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* configure.ac: Check for pdflatex.\n\tRegenate build description.\n\t* CMakeLists.txt: Fix typo.\n\n2010-11-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump version to 0.47.\n\n2010-07-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump version to 0.46.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump to 0.45.\n\n2009-09-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump to 0.44.\n\n2008-05-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump to 0.40.\n\n2005-04-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac (ipr_top_builddir): Remove.\n\t(ipr_srcdir): Likewise.\n\tRequire Autoconf 2.52 or higher.\n\tBump version to 0.36.\n\tInclude \"foreign\" Automake's options.\n\n2005-03-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump version to 0.35.\n\t(ipr_top_builddir): New.\n\t(ipr_srcdir): Remove.\n\n2005-03-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.34.\n\n\t* configure.ac: Bump version.\n\n2005-02-06  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.33\n\t* configure.ac: Bump version.\n\t* configure: Regenrate.\n\n2005-02-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: Bump version.\n\t* configure: Regenerate.\n\n2005-02-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.31.\n\n\t* configure.ac: Bump version.\n\t* configure: Regenerate.\n\n2005-01-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.30.\n\n\t* configure: Regenrate.\n\t* configure.ac: Bump version.\n\n2005-01-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.29\n\t* configure.ac: Bump version.\n\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: AC_OUTPUT doc/Makefile too.\n\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.28\n\t\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* configure.ac: AC_OUTPUT include/Makefile\n\t* configure: Regenerate.\n\n\t* Makefile.am (SUBDIRS): Add include.\n\t* Makefile.in: Regenerate.\n\t* libtool: New.\n\n2005-01-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\tEnable autoconf/automake support.\n\t* aclocal.m4: New.\n\t* config.guess: Likewise.\n\t* config.sub: Likewise.\n\t* configure.ac: Likewise.\n\t* depcomp: Likewise.\n\t* install-sh: Likewise.\n\t* missing: Likewise.\n\t* Makefile.am: Likewise.\n\t* Makefile.in: Likewise.\n\n2005-01-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.27.\n\n2004-10-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.26.\n\n2004-09-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.25.\n\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.24.\n\n2004-08-30  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.23.\n\n2004-08-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.22.\n\n2004-08-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.21.\n\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.20.\n\n2004-08-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.19.\n\t\n2004-07-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.18\n\t\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.17\n\t\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.16\n\t\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* grammar/nxpr.y: Update to last version from BS.\n\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.15.\n\t\n2004-07-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.14.\n\t\n2004-07-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.13.\n\t\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.12.\n\t\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* grammar/nxpr.y: Update to changes from BS.\n\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.11.\n\t\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.10.\n\t\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* grammar/nxpr.y: Incorporate update from BS. \n\n2004-05-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.08.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.06.\n\n2004-05-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.05.\n\t\n2004-04-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.04.\n\n"
  },
  {
    "path": "INSTALL",
    "content": "IPR is using CMake as its build system. The default configuration will\nbuild the library and the tests. The tests can be invoked using the test\ntarget:\n\n> mkdir build && cd build\n> cmake ..\n> make\n> make test\n\nOr alternatively, tests can be invoked using CTest:\n> ctest\n\nThe Latex documentation is also optional. The BUILD_DOC CMake option enables\nbuilding the documentation. It required pdflatex to be available in the path.\nThe documentation can be built using the doc target.\n\n> mkdir build && cd build\n> cmake .. -DBUILD_DOC=ON\n> make doc\n\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (C) 2004-2013, Texas A&M University.\nCopyright (C) 2014-2015, Gabriel Dos Reis and Bjarne Stroustrup.\nAll rights reserved.\n\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "![Build & Test](https://github.com/GabrielDosReis/ipr/actions/workflows/main.yml/badge.svg)\n![Analysis](https://github.com/GabrielDosReis/ipr/actions/workflows/analysis.yml/badge.svg)\n![Docs](https://github.com/GabrielDosReis/ipr/actions/workflows/docs.yaml/badge.svg)\n\nThe IPR, short for *Internal Program Representation*, is an open source\nproject originally developed as the core data structures of a framework\nfor semantics-based analysis and transformation of C++ programs.  The\nfoundations of the IPR were laid down and implemented between 2004 and\n2005, as part of The Pivot research project.  An overview, the\ngeneral philosophy, and the design principles behind the IPR are\npresented in the paper [\"A Principled, Complete, and Efficient\nRepresentation of C++\"](http://www.stroustrup.com/macis09.pdf) \n<!-- Restore when axiomatic is up [\"A Principled, Complete, and Efficient\nRepresentation of C++\"](http://www.axiomatics.org/~gdr/ipr/mcs.pdf)-->.\nThat paper is a useful source of general information about the IPR\nand non-obvious challenges in representing C++ programs in their most\ngeneral forms.\n\nThe IPR library purposefully separates the interface (a collection of abstract \nclasses found in `<ipr/interface>`) from the implementation (found in `<ipr/impl`>)\nfor various reasons.  An interface class (say `ipr::Fundecl`) can admit several \nimplementations: a class for non-defining function declarations, and another class for  \nfunction definitions.  Furthermore, compilers and tools (in general) can provide their own\nspecific optimized implementations of the interface without impacting users of the\nIPR as long as those users restrict themselves to the public interface.  Such a\nseparation of concerns shields users of the library from implementation vagaries.\nThe implementation in `<ipr/impl>` is provided for exposition and reference.\n\nFor more information, bug reports, and suggestions, please visit\n\n   https://github.com/GabrielDosReis/ipr\n\nGabriel Dos Reis, Bjarne Stroustrup.\n\n\n"
  },
  {
    "path": "STYLE.md",
    "content": "# Coding Style\r\n\r\nUse good judgment, and taste. Appreciate simplicity.\r\n\r\nIn absence of the above, consider the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines).\r\n\r\n## Logical connectives\r\n\r\nUse:\r\n  - `not` for logical negation\r\n  - `and` for logical conjunction\r\n  - `or` for logical disjunction\r\n\r\n\r\n## Factory function names\r\n\r\nUse:\r\n  - `get_xxx` for factory function names that return the same output for same inputs\r\n  - `make_xxx` for factory function names that always return fresh structures\r\n\r\n\r\n## Source file extensions\r\n\r\nUse\r\n  - `.cxx` for implementation source files\r\n\r\n\r\n\r\n"
  },
  {
    "path": "cmake/UseLATEX.cmake",
    "content": "# File: UseLATEX.cmake\n# CMAKE commands to actually use the LaTeX compiler\n# Version: 2.7.0\n# Author: Kenneth Moreland <kmorel@sandia.gov>\n#\n# Copyright 2004, 2015 Sandia Corporation.\n# Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive\n# license for use of this work by or on behalf of the U.S. Government.\n#\n# This software is released under the BSD 3-Clause License.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n# 1. Redistributions of source code must retain the above copyright notice,\n# this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n# notice, this list of conditions and the following disclaimer in the\n# documentation and/or other materials provided with the distribution.\n#\n# 3. Neither the name of the copyright holder nor the names of its\n# contributors may be used to endorse or promote products derived from this\n# software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n# IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n#\n# The following function is defined:\n#\n# add_latex_document(<tex_file>\n#                    [BIBFILES <bib_files>]\n#                    [INPUTS <input_tex_files>]\n#                    [IMAGE_DIRS <image_directories>]\n#                    [IMAGES <image_files>]\n#                    [CONFIGURE <tex_files>]\n#                    [DEPENDS <tex_files>]\n#                    [MULTIBIB_NEWCITES <suffix_list>]\n#                    [USE_BIBLATEX]\n#                    [USE_INDEX]\n#                    [INDEX_NAMES <index_names>]\n#                    [USE_GLOSSARY] [USE_NOMENCL]\n#                    [FORCE_PDF] [FORCE_DVI] [FORCE_HTML]\n#                    [TARGET_NAME <name>]\n#                    [INCLUDE_DIRECTORIES <directories>]\n#                    [EXCLUDE_FROM_ALL]\n#                    [EXCLUDE_FROM_DEFAULTS])\n#       Adds targets that compile <tex_file>.  The latex output is placed\n#       in LATEX_OUTPUT_PATH or CMAKE_CURRENT_BINARY_DIR if the former is\n#       not set.  The latex program is picky about where files are located,\n#       so all input files are copied from the source directory to the\n#       output directory.  This includes the target tex file, any tex file\n#       listed with the INPUTS option, the bibliography files listed with\n#       the BIBFILES option, and any .cls, .bst, .clo, .sty, .ist, and .fd\n#       files found in the current source directory.  Images found in the\n#       IMAGE_DIRS directories or listed by IMAGES are also copied to the\n#       output directory and converted to an appropriate format if necessary.\n#       Any tex files also listed with the CONFIGURE option are also processed\n#       with the CMake CONFIGURE_FILE command (with the @ONLY flag).  Any file\n#       listed in CONFIGURE but not the target tex file or listed with INPUTS\n#       has no effect. DEPENDS can be used to specify generated files that are\n#       needed to compile the latex target.\n#\n#       The following targets are made. The name prefix is based off of the\n#       base name of the tex file unless TARGET_NAME is specified. If\n#       TARGET_NAME is specified, then that name is used for the targets.\n#\n#               name_dvi: Makes <name>.dvi\n#               name_pdf: Makes <name>.pdf using pdflatex.\n#               name_safepdf: Makes <name>.pdf using ps2pdf.  If using the\n#                       default program arguments, this will ensure all fonts\n#                       are embedded and no lossy compression has been\n#                       performed on images.\n#               name_ps: Makes <name>.ps\n#               name_html: Makes <name>.html\n#               name_auxclean: Deletes <name>.aux and other auxiliary files.\n#                       This is sometimes necessary if a LaTeX error occurs\n#                       and writes a bad aux file.  Unlike the regular clean\n#                       target, it does not delete other input files, such as\n#                       converted images, to save time on the rebuild.\n#\n#       Unless the EXCLUDE_FROM_ALL option is given, one of these targets\n#       is added to the ALL target and built by default. Which target is\n#       determined by the LATEX_DEFAULT_BUILD CMake variable. See the\n#       documentation of that variable for more details.\n#\n#       Unless the EXCLUDE_FROM_DEFAULTS option is given, all these targets\n#       are added as dependencies to targets named dvi, pdf, safepdf, ps,\n#       html, and auxclean, respectively.\n#\n#       USE_BIBLATEX enables the use of biblatex/biber as an alternative to\n#       bibtex. Bibtex remains the default if USE_BIBLATEX is not\n#       specified.\n#\n#       If the argument USE_INDEX is given, then commands to build an index\n#       are made. If the argument INDEX_NAMES is given, an index file is\n#       generated for each name in this list. See the LaTeX package multind\n#       for more information about how to generate multiple indices.\n#\n#       If the argument USE_GLOSSARY is given, then commands to\n#       build a glossary are made.  If the argument MULTIBIB_NEWCITES is\n#       given, then additional bibtex calls are added to the build to\n#       support the extra auxiliary files created with the \\newcite command\n#       in the multibib package.\n#\n#       INCLUDE_DIRECTORIES provides a list of directories in which LaTeX\n#       should look for input files. It accepts both files relative to the\n#       binary directory and absolute paths.\n#\n# History:\n#\n# 2.7.0 Add INCLUDE_DIRECTORIES parameters. (Thanks to Eric Dönges.)\n#\n# 2.6.1 Fix issue with detecting long undefined reference warnings that\n#       LaTeX \"helpfully\" split across lines (and which fowled up our\n#       regex).\n#\n# 2.6.0 Skip image conversion targets that are not used when a force option\n#       is given. This helps prevent errors for missing conversion programs\n#       that are not needed. (Thanks to Martin Wetzel.)\n#\n# 2.5.0 Parse biber output for warnings.\n#\n#       For regular bibtex, you get warnings about undefined references\n#       when you run latex. However, when using biber, biber itself prints\n#       out the said warning and latex sees nothing. Thus, when using biber\n#       the regular output is now suppressed and the log file is scanned\n#       for potential issues.\n#\n# 2.4.9 Use biblatex.cfg file if it exists and the USE_BIBLATEX option is ON.\n#\n# 2.4.8 Fix synctex issue with absolute paths not being converted.\n#\n# 2.4.7 Fix some issues with spaces in the path of the working directory where\n#       LaTeX is executed.\n#\n# 2.4.6 Fix parse issue with older versions of CMake.\n#\n# 2.4.5 Fix issues with files and paths containing spaces.\n#\n# 2.4.4 Improve error reporting message when LaTeX fails.\n#\n#       When LaTeX fails, delete the output file, which is invalid.\n#\n#       Add warnings for \"missing characters.\" These usually mean that a\n#       non-ASCII character is in the document and will not be printed\n#       correctly.\n#\n# 2.4.3 Check for warnings from the natbib package. When using natbib,\n#       warnings for missing bibliography references look different. So\n#       far, natbib seems to be quiet unless something is important, so\n#       look for all natbib warnings. (We can change this later if\n#       necessary.)\n#\n# 2.4.2 Fix an issue where new versions of ImageMagick expect the order of\n#       options in command line execution of magick/convert. (See, for\n#       example, http://www.imagemagick.org/Usage/basics/#why.)\n#\n# 2.4.1 Add ability to dump LaTeX log file when using batch mode. Batch\n#       mode suppresses most output, often including error messages. To\n#       make sure critical error messages get displayed, show the full log\n#       on failures.\n#\n# 2.4.0 Remove \"-r 600\" from the default PDFTOPS_CONVERTER_FLAGS. The -r flag\n#       is available from the Poppler version of pdftops, but not the Xpdf\n#       version.\n#\n#       Fix an issue with the flags for the different programs not being\n#       properly separated.\n#\n#       Fix an issue on windows where the = character is not allowed for\n#       ps2pdf arguments.\n#\n#       Change default arguments for latex and pdflatex commands. Makes the\n#       output more quiet and prints out the file/line where errors occur.\n#       (Thanks to Nikos Koukis.)\n#\n#       After a LaTeX build, check the log file for warnings that are\n#       indicative of problems with the build.\n#\n#       Remove support for latex2html. Instead, use the htlatex program.\n#       This is now part of TeX Live and most other distributions. It also\n#       behaves much more like the other LaTeX programs. Also fixed some\n#       nasty issues with the htlatex arguments.\n#\n# 2.3.2 Declare LaTeX input files as sources for targets so that they show\n#       up in IDEs like QtCreator.\n#\n#       Fix issue where main tex files in subdirectories were creating\n#       invalid targets for building HTML. Just disable the HTML targets in\n#       this case.\n#\n# 2.3.1 Support use of magick command instead of convert command for\n#       ImageMagick 7.\n#\n# 2.3.0 Add USE_BIBLATEX option to support the biblatex package, which\n#       requires using the program biber as a replacement for bibtex\n#       (thanks to David Tracey).\n#\n# 2.2.1 Add STRINGS property to LATEX_DEFAULT_BUILD to make it easier to\n#       select the default build in the CMake GUI.\n#\n# 2.2.0 Add TARGET_NAME option.\n#\n# 2.1.1 Support for finding bmp, ppm, and other image files.\n#\n# 2.1.0 Fix an error where the pdf target and others were defined multiple\n#       times if UseLATEX.cmake was included multiple times.\n#\n#       Added INDEX_NAMES option to support multiple indexes in a single\n#       document from the multind package (thanks to Dan Lipsa).\n#\n# 2.0.0 First major revision of UseLATEX.cmake updates to more recent features\n#       of CMake and some non-backward compatible changes.\n#\n#       Changed all function and macro names to lower case. CMake's identifiers\n#       are case insensitive, but the convention moved from all upper case to\n#       all lower case somewhere around the release of CMake 2. (The original\n#       version of UseLATEX.cmake predates that.)\n#\n#       Remove condition matching in if statements. They are no longer necessary\n#       and are even discouraged (because else clauses get confusing).\n#\n#       Use \"new\" features available in CMake such as list and argument parsing.\n#\n#       Remove some code that has been deprecated for a while.\n#\n#       Mark variables for compiler and converter executables as advanced to\n#       match the more conventional CMake behavior.\n#\n#       Changed how default builds are specified and add the ability to force\n#       a particular build.\n#\n#       Made the base targets (pdf, dvi, etc.) global. add_latex_document\n#       always mangles its target names and these base targets depend on\n#       the targets with mangled names.\n#\n# 1.10.5 Fix for Window's convert check (thanks to Martin Baute).\n#\n# 1.10.4 Copy font files to binary directory for packages that come with\n#       their own fonts.\n#\n# 1.10.3 Check for Windows version of convert being used instead of\n#       ImageMagick's version (thanks to Martin Baute).\n#\n# 1.10.2 Use htlatex as a fallback when latex2html is not available (thanks\n#       to Tomasz Grzegurzko).\n#\n# 1.10.1 Make convert program mandatory only if actually used (thanks to\n#       Julien Schueller).\n#\n# 1.10.0 Added NO_DEFAULT and DEFAULT_PS options.\n#       Fixed issue with cleaning files for LaTeX documents originating in\n#       a subdirectory.\n#\n# 1.9.6 Fixed problem with LATEX_SMALL_IMAGES.\n#       Strengthened check to make sure the output directory does not contain\n#       the source files.\n#\n# 1.9.5 Add support for image types not directly supported by either latex\n#       or pdflatex.  (Thanks to Jorge Gerardo Pena Pastor for SVG support.)\n#\n# 1.9.4 Fix issues with filenames containing multiple periods.\n#\n# 1.9.3 Hide some variables that are now cached but should not show up in\n#       the ccmake list of variables.\n#\n# 1.9.2 Changed MACRO declarations to FUNCTION declarations.  The better\n#       FUNCTION scoping will hopefully avoid some common but subtle bugs.\n#       This implicitly increases the minimum CMake version to 4.6 (although\n#       I honestly only test it with the latest 4.8 version).\n#\n#       Since we are updating the minimum CMake version, I'm going to start\n#       using the builtin LIST commands that are now available.\n#\n#       Favor using pdftops from the Poppler package to convert from pdf to\n#       eps.  It does a much better job than ImageMagick or ghostscript.\n#\n# 1.9.1 Fixed typo that caused the LATEX_SMALL_IMAGES option to fail to\n#       activate.\n#\n# 1.9.0 Add support for the multibib package (thanks to Antonio LaTorre).\n#\n# 1.8.2 Fix corner case when an argument name was also a variable containing\n#       the text of an argument.  In this case, the CMake IF was matching\n#       the argument text with the contents of the variable with the same\n#       argument name.\n#\n# 1.8.1 Fix problem where ps2pdf was not getting the appropriate arguments.\n#\n# 1.8.0 Add support for synctex.\n#\n# 1.7.7 Support calling xindy when making glossaries.\n#\n#       Improved make clean support.\n#\n# 1.7.6 Add support for the nomencl package (thanks to Myles English).\n#\n# 1.7.5 Fix issue with bibfiles being copied two different ways, which causes\n#       Problems with dependencies (thanks to Edwin van Leeuwen).\n#\n# 1.7.4 Added the DEFAULT_SAFEPDF option (thanks to Raymond Wan).\n#\n#       Added warnings when image directories are not found (and were\n#       probably not given relative to the source directory).\n#\n# 1.7.3 Fix some issues with interactions between makeglossaries and bibtex\n#       (thanks to Mark de Wever).\n#\n# 1.7.2 Use ps2pdf to convert eps to pdf to get around the problem with\n#       ImageMagick dropping the bounding box (thanks to Lukasz Lis).\n#\n# 1.7.1 Fixed some dependency issues.\n#\n# 1.7.0 Added DEPENDS options (thanks to Theodore Papadopoulo).\n#\n# 1.6.1 Ported the makeglossaries command to CMake and embedded the port\n#       into UseLATEX.cmake.\n#\n# 1.6.0 Allow the use of the makeglossaries command.  Thanks to Oystein\n#       S. Haaland for the patch.\n#\n# 1.5.0 Allow any type of file in the INPUTS lists, not just tex file\n#       (suggested by Eric Noulard).  As a consequence, the ability to\n#       specify tex files without the .tex extension is removed.  The removed\n#       function is of dubious value anyway.\n#\n#       When copying input files, skip over any file that exists in the\n#       binary directory but does not exist in the source directory with the\n#       assumption that these files were added by some other mechanism.  I\n#       find this useful when creating large documents with multiple\n#       chapters that I want to build separately (for speed) as I work on\n#       them.  I use the same boilerplate as the starting point for all\n#       and just copy it with different configurations.  This was what the\n#       separate ADD_LATEX_DOCUMENT method was supposed to originally be for.\n#       Since its external use is pretty much deprecated, I removed that\n#       documentation.\n#\n# 1.4.1 Copy .sty files along with the other class and package files.\n#\n# 1.4.0 Added a MANGLE_TARGET_NAMES option that will mangle the target names.\n#\n#       Fixed problem with copying bib files that became apparent with\n#       CMake 2.4.\n#\n# 1.3.0 Added a LATEX_OUTPUT_PATH variable that allows you or the user to\n#       specify where the built latex documents to go.  This is especially\n#       handy if you want to do in-source builds.\n#\n#       Removed the ADD_LATEX_IMAGES macro and absorbed the functionality\n#       into ADD_LATEX_DOCUMENT.  The old interface was always kind of\n#       clunky anyway since you had to specify the image directory in both\n#       places.  It also made supporting LATEX_OUTPUT_PATH problematic.\n#\n#       Added support for jpeg files.\n#\n# 1.2.0 Changed the configuration options yet again.  Removed the NO_CONFIGURE\n#       Replaced it with a CONFIGURE option that lists input files for which\n#       configure should be run.\n#\n#       The pdf target no longer depends on the dvi target.  This allows you\n#       to build latex documents that require pdflatex.  Also added an option\n#       to make the pdf target the default one.\n#\n# 1.1.1 Added the NO_CONFIGURE option.  The @ character can be used when\n#       specifying table column separators.  If two or more are used, then\n#       will incorrectly substitute them.\n#\n# 1.1.0 Added ability include multiple bib files.  Added ability to do copy\n#       sub-tex files for multipart tex files.\n#\n# 1.0.0 If both ps and pdf type images exist, just copy the one that\n#       matches the current render mode.  Replaced a bunch of STRING\n#       commands with GET_FILENAME_COMPONENT commands that were made to do\n#       the desired function.\n#\n# 0.4.0 First version posted to CMake Wiki.\n#\n\nif(__USE_LATEX_INCLUDED)\n  return()\nendif()\nset(__USE_LATEX_INCLUDED TRUE)\n\n#############################################################################\n# Find the location of myself while originally executing.  If you do this\n# inside of a macro, it will recode where the macro was invoked.\n#############################################################################\nset(LATEX_USE_LATEX_LOCATION ${CMAKE_CURRENT_LIST_FILE}\n  CACHE INTERNAL \"Location of UseLATEX.cmake file.\" FORCE\n  )\n\n#############################################################################\n# Generic helper functions\n#############################################################################\n\ninclude(CMakeParseArguments)\n\nfunction(latex_list_contains var value)\n  set(input_list ${ARGN})\n  list(FIND input_list \"${value}\" index)\n  if(index GREATER -1)\n    set(${var} TRUE PARENT_SCOPE)\n  else()\n    set(${var} PARENT_SCOPE)\n  endif()\nendfunction(latex_list_contains)\n\n# Match the contents of a file to a regular expression.\nfunction(latex_file_match variable filename regexp default)\n  # The FILE STRINGS command would be a bit better, but I'm not totally sure\n  # the match will always be to a whole line, and I don't want to break things.\n  file(READ ${filename} file_contents)\n  string(REGEX MATCHALL \"${regexp}\"\n    match_result ${file_contents}\n    )\n  if(match_result)\n    set(${variable} \"${match_result}\" PARENT_SCOPE)\n  else()\n    set(${variable} \"${default}\" PARENT_SCOPE)\n  endif()\nendfunction(latex_file_match)\n\n# A version of GET_FILENAME_COMPONENT that treats extensions after the last\n# period rather than the first.  To the best of my knowledge, all filenames\n# typically used by LaTeX, including image files, have small extensions\n# after the last dot.\nfunction(latex_get_filename_component varname filename type)\n  set(result)\n  if(\"${type}\" STREQUAL \"NAME_WE\")\n    get_filename_component(name ${filename} NAME)\n    string(REGEX REPLACE \"\\\\.[^.]*\\$\" \"\" result \"${name}\")\n  elseif(\"${type}\" STREQUAL \"EXT\")\n    get_filename_component(name ${filename} NAME)\n    string(REGEX MATCH \"\\\\.[^.]*\\$\" result \"${name}\")\n  else()\n    get_filename_component(result ${filename} ${type})\n  endif()\n  set(${varname} \"${result}\" PARENT_SCOPE)\nendfunction(latex_get_filename_component)\n\n#############################################################################\n# Functions that perform processing during a LaTeX build.\n#############################################################################\nfunction(latex_execute_latex)\n  if(NOT LATEX_WORKING_DIRECTORY)\n    message(SEND_ERROR \"Need to define LATEX_WORKING_DIRECTORY\")\n  endif()\n\n  if(NOT LATEX_FULL_COMMAND)\n    message(SEND_ERROR \"Need to define LATEX_FULL_COMMAND\")\n  endif()\n\n  if(NOT LATEX_OUTPUT_FILE)\n    message(SEND_ERROR \"Need to define LATEX_OUTPUT_FILE\")\n  endif()\n\n  if(NOT LATEX_LOG_FILE)\n    message(SEND_ERROR \"Need to define LATEX_LOG_FILE\")\n  endif()\n\n  set(full_command_original \"${LATEX_FULL_COMMAND}\")\n\n  # Chose the native method for parsing command arguments. Newer versions of\n  # CMake allow you to just use NATIVE_COMMAND.\n  if (CMAKE_VERSION VERSION_GREATER 3.8)\n    set(separate_arguments_mode NATIVE_COMMAND)\n  else()\n    if (WIN32)\n      set(separate_arguments_mode WINDOWS_COMMAND)\n    else()\n      set(separate_arguments_mode UNIX_COMMAND)\n    endif()\n  endif()\n\n  # Preps variables for use in execute_process.\n  # Even though we expect LATEX_WORKING_DIRECTORY to have a single \"argument,\"\n  # we also want to make sure that we strip out any escape characters that can\n  # foul up the WORKING_DIRECTORY argument.\n  separate_arguments(LATEX_FULL_COMMAND UNIX_COMMAND \"${LATEX_FULL_COMMAND}\")\n  separate_arguments(LATEX_WORKING_DIRECTORY_SEP UNIX_COMMAND \"${LATEX_WORKING_DIRECTORY}\")\n\n  execute_process(\n    COMMAND ${LATEX_FULL_COMMAND}\n    WORKING_DIRECTORY \"${LATEX_WORKING_DIRECTORY_SEP}\"\n    RESULT_VARIABLE execute_result\n    OUTPUT_VARIABLE ignore\n    ERROR_VARIABLE ignore\n    )\n\n  if(NOT ${execute_result} EQUAL 0)\n    # LaTeX tends to write a file when a failure happens. Delete that file so\n    # that LaTeX will run again.\n    file(REMOVE \"${LATEX_WORKING_DIRECTORY}/${LATEX_OUTPUT_FILE}\")\n\n    message(\"\\n\\nLaTeX command failed\")\n    message(\"${full_command_original}\")\n    message(\"Log output:\")\n    file(READ \"${LATEX_WORKING_DIRECTORY}/${LATEX_LOG_FILE}\" log_output)\n    message(\"${log_output}\")\n    message(FATAL_ERROR \"Executed LaTeX, but LaTeX returned an error.\")\n  endif()\nendfunction(latex_execute_latex)\n\nfunction(latex_makeglossaries)\n  # This is really a bare bones port of the makeglossaries perl script into\n  # CMake scripting.\n  message(\"**************************** In makeglossaries\")\n  if(NOT LATEX_TARGET)\n    message(SEND_ERROR \"Need to define LATEX_TARGET\")\n  endif()\n\n  set(aux_file ${LATEX_TARGET}.aux)\n\n  if(NOT EXISTS ${aux_file})\n    message(SEND_ERROR \"${aux_file} does not exist.  Run latex on your target file.\")\n  endif()\n\n  latex_file_match(newglossary_lines ${aux_file}\n    \"@newglossary[ \\t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}\"\n    \"@newglossary{main}{glg}{gls}{glo}\"\n    )\n\n  latex_file_match(istfile_line ${aux_file}\n    \"@istfilename[ \\t]*{([^}]*)}\"\n    \"@istfilename{${LATEX_TARGET}.ist}\"\n    )\n  string(REGEX REPLACE \"@istfilename[ \\t]*{([^}]*)}\" \"\\\\1\"\n    istfile ${istfile_line}\n    )\n\n  string(REGEX MATCH \".*\\\\.xdy\" use_xindy \"${istfile}\")\n  if(use_xindy)\n    message(\"*************** Using xindy\")\n    if(NOT XINDY_COMPILER)\n      message(SEND_ERROR \"Need to define XINDY_COMPILER\")\n    endif()\n  else()\n    message(\"*************** Using makeindex\")\n    if(NOT MAKEINDEX_COMPILER)\n      message(SEND_ERROR \"Need to define MAKEINDEX_COMPILER\")\n    endif()\n  endif()\n\n  foreach(newglossary ${newglossary_lines})\n    string(REGEX REPLACE\n      \"@newglossary[ \\t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}\"\n      \"\\\\1\" glossary_name ${newglossary}\n      )\n    string(REGEX REPLACE\n      \"@newglossary[ \\t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}\"\n      \"${LATEX_TARGET}.\\\\2\" glossary_log ${newglossary}\n      )\n    string(REGEX REPLACE\n      \"@newglossary[ \\t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}\"\n      \"${LATEX_TARGET}.\\\\3\" glossary_out ${newglossary}\n      )\n    string(REGEX REPLACE\n      \"@newglossary[ \\t]*{([^}]*)}{([^}]*)}{([^}]*)}{([^}]*)}\"\n      \"${LATEX_TARGET}.\\\\4\" glossary_in ${newglossary}\n      )\n\n    if(use_xindy)\n      latex_file_match(xdylanguage_line ${aux_file}\n        \"@xdylanguage[ \\t]*{${glossary_name}}{([^}]*)}\"\n        \"@xdylanguage{${glossary_name}}{english}\"\n        )\n      string(REGEX REPLACE\n        \"@xdylanguage[ \\t]*{${glossary_name}}{([^}]*)}\"\n        \"\\\\1\"\n        language\n        ${xdylanguage_line}\n        )\n      # What crazy person makes a LaTeX index generator that uses different\n      # identifiers for language than babel (or at least does not support\n      # the old ones)?\n      if(${language} STREQUAL \"frenchb\")\n        set(language \"french\")\n      elseif(${language} MATCHES \"^n?germanb?$\")\n        set(language \"german\")\n      elseif(${language} STREQUAL \"magyar\")\n        set(language \"hungarian\")\n      elseif(${language} STREQUAL \"lsorbian\")\n        set(language \"lower-sorbian\")\n      elseif(${language} STREQUAL \"norsk\")\n        set(language \"norwegian\")\n      elseif(${language} STREQUAL \"portuges\")\n        set(language \"portuguese\")\n      elseif(${language} STREQUAL \"russianb\")\n        set(language \"russian\")\n      elseif(${language} STREQUAL \"slovene\")\n        set(language \"slovenian\")\n      elseif(${language} STREQUAL \"ukraineb\")\n        set(language \"ukrainian\")\n      elseif(${language} STREQUAL \"usorbian\")\n        set(language \"upper-sorbian\")\n      endif()\n      if(language)\n        set(language_flags \"-L ${language}\")\n      else()\n        set(language_flags \"\")\n      endif()\n\n      latex_file_match(codepage_line ${aux_file}\n        \"@gls@codepage[ \\t]*{${glossary_name}}{([^}]*)}\"\n        \"@gls@codepage{${glossary_name}}{utf}\"\n        )\n      string(REGEX REPLACE\n        \"@gls@codepage[ \\t]*{${glossary_name}}{([^}]*)}\"\n        \"\\\\1\"\n        codepage\n        ${codepage_line}\n        )\n      if(codepage)\n        set(codepage_flags \"-C ${codepage}\")\n      else()\n        # Ideally, we would check that the language is compatible with the\n        # default codepage, but I'm hoping that distributions will be smart\n        # enough to specify their own codepage.  I know, it's asking a lot.\n        set(codepage_flags \"\")\n      endif()\n\n      message(\"${XINDY_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} ${language_flags} ${codepage_flags} -I xindy -M ${glossary_name} -t ${glossary_log} -o ${glossary_out} ${glossary_in}\"\n        )\n      exec_program(${XINDY_COMPILER}\n        ARGS ${MAKEGLOSSARIES_COMPILER_ARGS}\n          ${language_flags}\n          ${codepage_flags}\n          -I xindy\n          -M ${glossary_name}\n          -t ${glossary_log}\n          -o ${glossary_out}\n          ${glossary_in}\n        OUTPUT_VARIABLE xindy_output\n        )\n      message(\"${xindy_output}\")\n\n      # So, it is possible (perhaps common?) for aux files to specify a\n      # language and codepage that are incompatible with each other.  Check\n      # for that condition, and if it happens run again with the default\n      # codepage.\n      if(\"${xindy_output}\" MATCHES \"^Cannot locate xindy module for language (.+) in codepage (.+)\\\\.$\")\n        message(\"*************** Retrying xindy with default codepage.\")\n        exec_program(${XINDY_COMPILER}\n          ARGS ${MAKEGLOSSARIES_COMPILER_ARGS}\n            ${language_flags}\n            -I xindy\n            -M ${glossary_name}\n            -t ${glossary_log}\n            -o ${glossary_out}\n            ${glossary_in}\n          )\n      endif()\n\n    else()\n      message(\"${MAKEINDEX_COMPILER} ${MAKEGLOSSARIES_COMPILER_ARGS} -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}\")\n      exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKEGLOSSARIES_COMPILER_ARGS}\n        -s ${istfile} -t ${glossary_log} -o ${glossary_out} ${glossary_in}\n        )\n    endif()\n\n  endforeach(newglossary)\nendfunction(latex_makeglossaries)\n\nfunction(latex_makenomenclature)\n  message(\"**************************** In makenomenclature\")\n  if(NOT LATEX_TARGET)\n    message(SEND_ERROR \"Need to define LATEX_TARGET\")\n  endif()\n\n  if(NOT MAKEINDEX_COMPILER)\n    message(SEND_ERROR \"Need to define MAKEINDEX_COMPILER\")\n  endif()\n\n  set(nomencl_out ${LATEX_TARGET}.nls)\n  set(nomencl_in ${LATEX_TARGET}.nlo)\n\n  exec_program(${MAKEINDEX_COMPILER} ARGS ${MAKENOMENCLATURE_COMPILER_ARGS}\n    ${nomencl_in} -s \"nomencl.ist\" -o ${nomencl_out}\n    )\nendfunction(latex_makenomenclature)\n\nfunction(latex_correct_synctex)\n  message(\"**************************** In correct SyncTeX\")\n  if(NOT LATEX_TARGET)\n    message(SEND_ERROR \"Need to define LATEX_TARGET\")\n  endif()\n\n  if(NOT GZIP)\n    message(SEND_ERROR \"Need to define GZIP\")\n  endif()\n\n  if(NOT LATEX_SOURCE_DIRECTORY)\n    message(SEND_ERROR \"Need to define LATEX_SOURCE_DIRECTORY\")\n  endif()\n\n  if(NOT LATEX_BINARY_DIRECTORY)\n    message(SEND_ERROR \"Need to define LATEX_BINARY_DIRECTORY\")\n  endif()\n  message(\"${LATEX_BINARY_DIRECTORY}\")\n  message(\"${LATEX_SOURCE_DIRECTORY}\")\n\n  set(synctex_file ${LATEX_BINARY_DIRECTORY}/${LATEX_TARGET}.synctex)\n  set(synctex_file_gz ${synctex_file}.gz)\n\n  if(EXISTS ${synctex_file_gz})\n\n    message(\"Making backup of synctex file.\")\n    configure_file(${synctex_file_gz} ${synctex_file}.bak.gz COPYONLY)\n\n    message(\"Uncompressing synctex file.\")\n    exec_program(${GZIP}\n      ARGS --decompress ${synctex_file_gz}\n      )\n\n    message(\"Reading synctex file.\")\n    file(READ ${synctex_file} synctex_data)\n\n    message(\"Replacing output paths with input paths.\")\n    foreach(extension tex cls bst clo sty ist fd)\n      # Relative paths\n      string(REGEX REPLACE\n        \"(Input:[0-9]+:)([^/\\n][^\\n]\\\\.${extension}*)\"\n        \"\\\\1${LATEX_SOURCE_DIRECTORY}/\\\\2\"\n        synctex_data\n        \"${synctex_data}\"\n        )\n\n      # Absolute paths\n      string(REGEX REPLACE\n        \"(Input:[0-9]+:)${LATEX_BINARY_DIRECTORY}([^\\n]*\\\\.${extension})\"\n        \"\\\\1${LATEX_SOURCE_DIRECTORY}\\\\2\"\n        synctex_data\n        \"${synctex_data}\"\n        )\n    endforeach(extension)\n\n    message(\"Writing synctex file.\")\n    file(WRITE ${synctex_file} \"${synctex_data}\")\n\n    message(\"Compressing synctex file.\")\n    exec_program(${GZIP}\n      ARGS ${synctex_file}\n      )\n\n  else()\n\n    message(SEND_ERROR \"File ${synctex_file_gz} not found.  Perhaps synctex is not supported by your LaTeX compiler.\")\n\n  endif()\n\nendfunction(latex_correct_synctex)\n\nfunction(latex_check_important_warnings)\n  # Check for biber warnings/errors if that was run\n  set(bib_log_file ${LATEX_TARGET}.blg)\n  if(EXISTS ${bib_log_file})\n    file(READ ${bib_log_file} bib_log)\n    if(bib_log MATCHES \"INFO - This is Biber\")\n      message(\"\\nChecking ${bib_log_file} for Biber warnings/errors.\")\n\n      string(REGEX MATCHALL\n        \"[A-Z]+ - [^\\n]*\"\n        biber_messages\n        \"${bib_log}\")\n\n      set(found_error)\n      foreach(message ${biber_messages})\n        if(NOT message MATCHES  \"^INFO - \")\n          set(found_error TRUE)\n          message(\"${message}\")\n        endif()\n      endforeach(message)\n\n      if(found_error)\n        latex_get_filename_component(log_file_path ${bib_log_file} ABSOLUTE)\n        message(\"\\nConsult ${log_file_path} for more information on Biber output.\")\n      else()\n        message(\"No known important Biber output found.\")\n      endif(found_error)\n    else() # Biber output not in log file\n      message(\"Skipping biber checks (biber not used)\")\n    endif()\n  else() # No bib log file\n    message(\"Skipping bibliography checks (not run)\")\n  endif()\n\n  set(log_file ${LATEX_TARGET}.log)\n\n  message(\"\\nChecking ${log_file} for important warnings.\")\n  if(NOT LATEX_TARGET)\n    message(SEND_ERROR \"Need to define LATEX_TARGET\")\n  endif()\n\n  if(NOT EXISTS ${log_file})\n    message(\"Could not find log file: ${log_file}\")\n    return()\n  endif()\n\n  set(found_error)\n\n  file(READ ${log_file} log)\n\n  # Check for declared LaTeX warnings\n  string(REGEX MATCHALL\n    \"\\nLaTeX Warning:[^\\n]*\"\n    latex_warnings\n    \"${log}\")\n  if(latex_warnings)\n    set(found_error TRUE)\n    message(\"\\nFound declared LaTeX warnings.\")\n    foreach(warning ${latex_warnings})\n      string(STRIP \"${warning}\" warning_no_newline)\n      message(\"${warning_no_newline}\")\n    endforeach(warning)\n  endif()\n\n  # Check for natbib warnings\n  string(REGEX MATCHALL\n    \"\\nPackage natbib Warning:[^\\n]*\"\n    natbib_warnings\n    \"${log}\")\n  if(natbib_warnings)\n    set(found_error TRUE)\n    message(\"\\nFound natbib package warnings.\")\n    foreach(warning ${natbib_warnings})\n      string(STRIP \"${warning}\" warning_no_newline)\n      message(\"${warning_no_newline}\")\n    endforeach(warning)\n  endif()\n\n  # Check for overfull\n  string(REGEX MATCHALL\n    \"\\nOverfull[^\\n]*\"\n    overfull_warnings\n    \"${log}\")\n  if(overfull_warnings)\n    set(found_error TRUE)\n    message(\"\\nFound overfull warnings. These are indicative of layout errors.\")\n    foreach(warning ${overfull_warnings})\n      string(STRIP \"${warning}\" warning_no_newline)\n      message(\"${warning_no_newline}\")\n    endforeach(warning)\n  endif()\n\n  # Check for invalid characters\n  string(REGEX MATCHALL\n    \"\\nMissing character:[^\\n]*\"\n    invalid_character_warnings\n    \"${log}\")\n  if(invalid_character_warnings)\n    set(found_error TRUE)\n    message(\"\\nFound invalid character warnings. These characters are likely not printed correctly.\")\n    foreach(warning ${invalid_character_warnings})\n      string(STRIP \"${warning}\" warning_no_newline)\n      message(\"${warning_no_newline}\")\n    endforeach(warning)\n  endif()\n\n  if(found_error)\n    latex_get_filename_component(log_file_path ${log_file} ABSOLUTE)\n    message(\"\\nConsult ${log_file_path} for more information on LaTeX build.\")\n  else()\n    message(\"No known important warnings found.\")\n  endif(found_error)\nendfunction(latex_check_important_warnings)\n\n#############################################################################\n# Helper functions for establishing LaTeX build.\n#############################################################################\n\nfunction(latex_needit VAR NAME)\n  if(NOT ${VAR})\n    message(SEND_ERROR \"I need the ${NAME} command.\")\n  endif()\nendfunction(latex_needit)\n\nfunction(latex_wantit VAR NAME)\n  if(NOT ${VAR})\n    message(STATUS \"I could not find the ${NAME} command.\")\n  endif()\nendfunction(latex_wantit)\n\nfunction(latex_setup_variables)\n  set(LATEX_OUTPUT_PATH \"${LATEX_OUTPUT_PATH}\"\n    CACHE PATH \"If non empty, specifies the location to place LaTeX output.\"\n    )\n\n  find_package(LATEX)\n\n  find_program(XINDY_COMPILER\n    NAME xindy\n    PATHS ${MIKTEX_BINARY_PATH} /usr/bin\n    )\n\n  find_package(UnixCommands)\n\n  find_program(PDFTOPS_CONVERTER\n    NAMES pdftops\n    DOC \"The pdf to ps converter program from the Poppler package.\"\n    )\n\n  find_program(HTLATEX_COMPILER\n    NAMES htlatex\n    PATHS ${MIKTEX_BINARY_PATH}\n      /usr/bin\n    )\n\n  mark_as_advanced(\n    LATEX_COMPILER\n    PDFLATEX_COMPILER\n    BIBTEX_COMPILER\n    BIBER_COMPILER\n    MAKEINDEX_COMPILER\n    XINDY_COMPILER\n    DVIPS_CONVERTER\n    PS2PDF_CONVERTER\n    PDFTOPS_CONVERTER\n    LATEX2HTML_CONVERTER\n    HTLATEX_COMPILER\n    )\n\n  latex_needit(LATEX_COMPILER latex)\n  latex_wantit(PDFLATEX_COMPILER pdflatex)\n  latex_wantit(HTLATEX_COMPILER htlatex)\n  latex_needit(BIBTEX_COMPILER bibtex)\n  latex_wantit(BIBER_COMPILER biber)\n  latex_needit(MAKEINDEX_COMPILER makeindex)\n  latex_wantit(DVIPS_CONVERTER dvips)\n  latex_wantit(PS2PDF_CONVERTER ps2pdf)\n  latex_wantit(PDFTOPS_CONVERTER pdftops)\n\n  set(LATEX_COMPILER_FLAGS \"-interaction=batchmode -file-line-error\"\n    CACHE STRING \"Flags passed to latex.\")\n  set(PDFLATEX_COMPILER_FLAGS ${LATEX_COMPILER_FLAGS}\n    CACHE STRING \"Flags passed to pdflatex.\")\n  set(HTLATEX_COMPILER_TEX4HT_FLAGS \"html\"\n    CACHE STRING \"Options for the tex4ht.sty and *.4ht style files.\")\n  set(HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS \"\"\n    CACHE STRING \"Options for the text4ht postprocessor.\")\n  set(HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS \"\"\n    CACHE STRING \"Options for the t4ht postprocessor.\")\n  set(HTLATEX_COMPILER_LATEX_FLAGS ${LATEX_COMPILER_FLAGS}\n    CACHE STRING \"Flags passed from htlatex to the LaTeX compiler.\")\n  set(LATEX_SYNCTEX_FLAGS \"-synctex=1\"\n    CACHE STRING \"latex/pdflatex flags used to create synctex file.\")\n  set(BIBTEX_COMPILER_FLAGS \"\"\n    CACHE STRING \"Flags passed to bibtex.\")\n  set(BIBER_COMPILER_FLAGS \"\"\n    CACHE STRING \"Flags passed to biber.\")\n  set(MAKEINDEX_COMPILER_FLAGS \"\"\n    CACHE STRING \"Flags passed to makeindex.\")\n  set(MAKEGLOSSARIES_COMPILER_FLAGS \"\"\n    CACHE STRING \"Flags passed to makeglossaries.\")\n  set(MAKENOMENCLATURE_COMPILER_FLAGS \"\"\n    CACHE STRING \"Flags passed to makenomenclature.\")\n  set(DVIPS_CONVERTER_FLAGS \"-Ppdf -G0 -t letter\"\n    CACHE STRING \"Flags passed to dvips.\")\n  if(NOT WIN32)\n    set(PS2PDF_CONVERTER_FLAGS \"-dMaxSubsetPct=100 -dCompatibilityLevel=1.3 -dSubsetFonts=true -dEmbedAllFonts=true -dAutoFilterColorImages=false -dAutoFilterGrayImages=false -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode -dMonoImageFilter=/FlateEncode\"\n      CACHE STRING \"Flags passed to ps2pdf.\")\n  else()\n    # Most windows ports of ghostscript utilities use .bat files for ps2pdf\n    # commands. bat scripts interpret \"=\" as a special character and separate\n    # those arguments. To get around this, the ghostscript utilities also\n    # support using \"#\" in place of \"=\".\n    set(PS2PDF_CONVERTER_FLAGS \"-dMaxSubsetPct#100 -dCompatibilityLevel#1.3 -dSubsetFonts#true -dEmbedAllFonts#true -dAutoFilterColorImages#false -dAutoFilterGrayImages#false -dColorImageFilter#/FlateEncode -dGrayImageFilter#/FlateEncode -dMonoImageFilter#/FlateEncode\"\n      CACHE STRING \"Flags passed to ps2pdf.\")\n  endif()\n  set(PDFTOPS_CONVERTER_FLAGS \"\"\n    CACHE STRING \"Flags passed to pdftops.\")\n  mark_as_advanced(\n    LATEX_COMPILER_FLAGS\n    PDFLATEX_COMPILER_FLAGS\n    HTLATEX_COMPILER_TEX4HT_FLAGS\n    HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS\n    HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS\n    HTLATEX_COMPILER_LATEX_FLAGS\n    LATEX_SYNCTEX_FLAGS\n    BIBTEX_COMPILER_FLAGS\n    BIBER_COMPILER_FLAGS\n    MAKEINDEX_COMPILER_FLAGS\n    MAKEGLOSSARIES_COMPILER_FLAGS\n    MAKENOMENCLATURE_COMPILER_FLAGS\n    DVIPS_CONVERTER_FLAGS\n    PS2PDF_CONVERTER_FLAGS\n    PDFTOPS_CONVERTER_FLAGS\n    )\n\n  # Because it is easier to type, the flags variables are entered as\n  # space-separated strings much like you would in a shell. However, when\n  # using a CMake command to execute a program, it works better to hold the\n  # arguments in semicolon-separated lists (otherwise the whole string will\n  # be interpreted as a single argument). Use the separate_arguments to\n  # convert the space-separated strings to semicolon-separated lists.\n  separate_arguments(LATEX_COMPILER_FLAGS)\n  separate_arguments(PDFLATEX_COMPILER_FLAGS)\n  separate_arguments(HTLATEX_COMPILER_LATEX_FLAGS)\n  separate_arguments(LATEX_SYNCTEX_FLAGS)\n  separate_arguments(BIBTEX_COMPILER_FLAGS)\n  separate_arguments(BIBER_COMPILER_FLAGS)\n  separate_arguments(MAKEINDEX_COMPILER_FLAGS)\n  separate_arguments(MAKEGLOSSARIES_COMPILER_FLAGS)\n  separate_arguments(MAKENOMENCLATURE_COMPILER_FLAGS)\n  separate_arguments(DVIPS_CONVERTER_FLAGS)\n  separate_arguments(PS2PDF_CONVERTER_FLAGS)\n  separate_arguments(PDFTOPS_CONVERTER_FLAGS)\n\n  # Not quite done. When you call separate_arguments on a cache variable,\n  # the result is written to a local variable. That local variable goes\n  # away when this function returns (which is before any of them are used).\n  # So, copy these variables with local scope to cache variables with\n  # global scope.\n  set(LATEX_COMPILER_ARGS \"${LATEX_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(PDFLATEX_COMPILER_ARGS \"${PDFLATEX_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(HTLATEX_COMPILER_ARGS \"${HTLATEX_COMPILER_LATEX_FLAGS}\" CACHE INTERNAL \"\")\n  set(LATEX_SYNCTEX_ARGS \"${LATEX_SYNCTEX_FLAGS}\" CACHE INTERNAL \"\")\n  set(BIBTEX_COMPILER_ARGS \"${BIBTEX_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(BIBER_COMPILER_ARGS \"${BIBER_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(MAKEINDEX_COMPILER_ARGS \"${MAKEINDEX_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(MAKEGLOSSARIES_COMPILER_ARGS \"${MAKEGLOSSARIES_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(MAKENOMENCLATURE_COMPILER_ARGS \"${MAKENOMENCLATURE_COMPILER_FLAGS}\" CACHE INTERNAL \"\")\n  set(DVIPS_CONVERTER_ARGS \"${DVIPS_CONVERTER_FLAGS}\" CACHE INTERNAL \"\")\n  set(PS2PDF_CONVERTER_ARGS \"${PS2PDF_CONVERTER_FLAGS}\" CACHE INTERNAL \"\")\n  set(PDFTOPS_CONVERTER_ARGS \"${PDFTOPS_CONVERTER_FLAGS}\" CACHE INTERNAL \"\")\n\n  find_program(IMAGEMAGICK_CONVERT\n    NAMES magick convert\n    DOC \"The convert program that comes with ImageMagick (available at http://www.imagemagick.org).\"\n    )\n  mark_as_advanced(IMAGEMAGICK_CONVERT)\n\n  if(DEFINED ENV{LATEX_DEFAULT_BUILD})\n    set(default_build $ENV{LATEX_DEFAULT_BUILD})\n  else()\n    set(default_build pdf)\n  endif()\n\n  set(LATEX_DEFAULT_BUILD \"${default_build}\" CACHE STRING\n    \"Choose the default type of LaTeX build. Valid options are pdf, dvi, ps, safepdf, html\"\n    )\n  set_property(CACHE LATEX_DEFAULT_BUILD\n    PROPERTY STRINGS pdf dvi ps safepdf html\n    )\n\n  option(LATEX_USE_SYNCTEX\n    \"If on, have LaTeX generate a synctex file, which WYSIWYG editors can use to correlate output files like dvi and pdf with the lines of LaTeX source that generates them.  In addition to adding the LATEX_SYNCTEX_FLAGS to the command line, this option also adds build commands that \\\"corrects\\\" the resulting synctex file to point to the original LaTeX files rather than those generated by UseLATEX.cmake.\"\n    OFF\n    )\n\n  option(LATEX_SMALL_IMAGES\n    \"If on, the raster images will be converted to 1/6 the original size.  This is because papers usually require 600 dpi images whereas most monitors only require at most 96 dpi.  Thus, smaller images make smaller files for web distribution and can make it faster to read dvi files.\"\n    OFF)\n  if(LATEX_SMALL_IMAGES)\n    set(LATEX_RASTER_SCALE 16 PARENT_SCOPE)\n    set(LATEX_OPPOSITE_RASTER_SCALE 100 PARENT_SCOPE)\n  else()\n    set(LATEX_RASTER_SCALE 100 PARENT_SCOPE)\n    set(LATEX_OPPOSITE_RASTER_SCALE 16 PARENT_SCOPE)\n  endif()\n\n  # Just holds extensions for known image types.  They should all be lower case.\n  # For historical reasons, these are all declared in the global scope.\n  set(LATEX_DVI_VECTOR_IMAGE_EXTENSIONS .eps CACHE INTERNAL \"\")\n  set(LATEX_DVI_RASTER_IMAGE_EXTENSIONS CACHE INTERNAL \"\")\n  set(LATEX_DVI_IMAGE_EXTENSIONS\n    ${LATEX_DVI_VECTOR_IMAGE_EXTENSIONS}\n    ${LATEX_DVI_RASTER_IMAGE_EXTENSIONS}\n    CACHE INTERNAL \"\"\n    )\n\n  set(LATEX_PDF_VECTOR_IMAGE_EXTENSIONS .pdf CACHE INTERNAL \"\")\n  set(LATEX_PDF_RASTER_IMAGE_EXTENSIONS .jpeg .jpg .png CACHE INTERNAL \"\")\n  set(LATEX_PDF_IMAGE_EXTENSIONS\n    ${LATEX_PDF_VECTOR_IMAGE_EXTENSIONS}\n    ${LATEX_PDF_RASTER_IMAGE_EXTENSIONS}\n    CACHE INTERNAL \"\"\n    )\n\n  set(LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS .ai .dot .svg CACHE INTERNAL \"\")\n  set(LATEX_OTHER_RASTER_IMAGE_EXTENSIONS\n    .bmp .bmp2 .bmp3 .dcm .dcx .ico .gif .pict .ppm .tif .tiff\n    CACHE INTERNAL \"\")\n  set(LATEX_OTHER_IMAGE_EXTENSIONS\n    ${LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS}\n    ${LATEX_OTHER_RASTER_IMAGE_EXTENSIONS}\n    CACHE INTERNAL \"\"\n    )\n\n  set(LATEX_VECTOR_IMAGE_EXTENSIONS\n    ${LATEX_DVI_VECTOR_IMAGE_EXTENSIONS}\n    ${LATEX_PDF_VECTOR_IMAGE_EXTENSIONS}\n    ${LATEX_OTHER_VECTOR_IMAGE_EXTENSIONS}\n    CACHE INTERNAL \"\"\n    )\n  set(LATEX_RASTER_IMAGE_EXTENSIONS\n    ${LATEX_DVI_RASTER_IMAGE_EXTENSIONS}\n    ${LATEX_PDF_RASTER_IMAGE_EXTENSIONS}\n    ${LATEX_OTHER_RASTER_IMAGE_EXTENSIONS}\n    CACHE INTERNAL \"\"\n    )\n  set(LATEX_IMAGE_EXTENSIONS\n    ${LATEX_DVI_IMAGE_EXTENSIONS}\n    ${LATEX_PDF_IMAGE_EXTENSIONS}\n    ${LATEX_OTHER_IMAGE_EXTENSIONS}\n    CACHE INTERNAL \"\"\n    )\nendfunction(latex_setup_variables)\n\nfunction(latex_setup_targets)\n  if(NOT TARGET pdf)\n    add_custom_target(pdf)\n  endif()\n  if(NOT TARGET dvi)\n    add_custom_target(dvi)\n  endif()\n  if(NOT TARGET ps)\n    add_custom_target(ps)\n  endif()\n  if(NOT TARGET safepdf)\n    add_custom_target(safepdf)\n  endif()\n  if(NOT TARGET html)\n    add_custom_target(html)\n  endif()\n  if(NOT TARGET auxclean)\n    add_custom_target(auxclean)\n  endif()\nendfunction(latex_setup_targets)\n\nfunction(latex_get_output_path var)\n  set(latex_output_path)\n  if(LATEX_OUTPUT_PATH)\n    get_filename_component(\n      LATEX_OUTPUT_PATH_FULL \"${LATEX_OUTPUT_PATH}\" ABSOLUTE\n      )\n    if(\"${LATEX_OUTPUT_PATH_FULL}\" STREQUAL \"${CMAKE_CURRENT_SOURCE_DIR}\")\n      message(SEND_ERROR \"You cannot set LATEX_OUTPUT_PATH to the same directory that contains LaTeX input files.\")\n    else()\n      set(latex_output_path \"${LATEX_OUTPUT_PATH_FULL}\")\n    endif()\n  else()\n    if(\"${CMAKE_CURRENT_BINARY_DIR}\" STREQUAL \"${CMAKE_CURRENT_SOURCE_DIR}\")\n      message(SEND_ERROR \"LaTeX files must be built out of source or you must set LATEX_OUTPUT_PATH.\")\n    else()\n      set(latex_output_path \"${CMAKE_CURRENT_BINARY_DIR}\")\n    endif()\n  endif()\n  set(${var} ${latex_output_path} PARENT_SCOPE)\nendfunction(latex_get_output_path)\n\nfunction(latex_add_convert_command\n    output_path\n    input_path\n    output_extension\n    input_extension\n    flags\n    )\n  set(require_imagemagick_convert TRUE)\n  set(convert_flags \"\")\n  if(${input_extension} STREQUAL \".eps\" AND ${output_extension} STREQUAL \".pdf\")\n    # ImageMagick has broken eps to pdf conversion\n    # use ps2pdf instead\n    if(PS2PDF_CONVERTER)\n      set(require_imagemagick_convert FALSE)\n      set(converter ${PS2PDF_CONVERTER})\n      set(convert_flags -dEPSCrop ${PS2PDF_CONVERTER_ARGS})\n    else()\n      message(SEND_ERROR \"Using postscript files with pdflatex requires ps2pdf for conversion.\")\n    endif()\n  elseif(${input_extension} STREQUAL \".pdf\" AND ${output_extension} STREQUAL \".eps\")\n    # ImageMagick can also be sketchy on pdf to eps conversion.  Not good with\n    # color spaces and tends to unnecessarily rasterize.\n    # use pdftops instead\n    if(PDFTOPS_CONVERTER)\n      set(require_imagemagick_convert FALSE)\n      set(converter ${PDFTOPS_CONVERTER})\n      set(convert_flags -eps ${PDFTOPS_CONVERTER_ARGS})\n    else()\n      message(STATUS \"Consider getting pdftops from Poppler to convert PDF images to EPS images.\")\n      set(convert_flags ${flags})\n    endif()\n  else()\n    set(convert_flags ${flags})\n  endif()\n\n  if(require_imagemagick_convert)\n    if(IMAGEMAGICK_CONVERT)\n      string(TOLOWER ${IMAGEMAGICK_CONVERT} IMAGEMAGICK_CONVERT_LOWERCASE)\n      if(${IMAGEMAGICK_CONVERT_LOWERCASE} MATCHES \"system32[/\\\\\\\\]convert\\\\.exe\")\n        message(SEND_ERROR \"IMAGEMAGICK_CONVERT set to Window's convert.exe for changing file systems rather than ImageMagick's convert for changing image formats. Please make sure ImageMagick is installed (available at http://www.imagemagick.org). If you have a recent version of ImageMagick (7.0 or higher), use the magick program instead of convert for IMAGEMAGICK_CONVERT.\")\n      else()\n        set(converter ${IMAGEMAGICK_CONVERT})\n        # ImageMagick requires a special order of arguments where resize and\n        # arguments of that nature must be placed after the input image path.\n        add_custom_command(OUTPUT ${output_path}\n          COMMAND ${converter}\n            ARGS ${input_path} ${convert_flags} ${output_path}\n          DEPENDS ${input_path}\n          )\n      endif()\n    else()\n      message(SEND_ERROR \"Could not find convert program. Please download ImageMagick from http://www.imagemagick.org and install.\")\n    endif()\n  else() # Not ImageMagick convert\n    add_custom_command(OUTPUT ${output_path}\n      COMMAND ${converter}\n        ARGS ${convert_flags} ${input_path} ${output_path}\n      DEPENDS ${input_path}\n      )\n  endif()\nendfunction(latex_add_convert_command)\n\n# Makes custom commands to convert a file to a particular type.\nfunction(latex_convert_image\n    output_files_var\n    input_file\n    output_extension\n    convert_flags\n    output_extensions\n    other_files\n    )\n  set(output_file_list)\n  set(input_dir ${CMAKE_CURRENT_SOURCE_DIR})\n  latex_get_output_path(output_dir)\n\n  latex_get_filename_component(extension \"${input_file}\" EXT)\n\n  # Check input filename for potential problems with LaTeX.\n  latex_get_filename_component(name \"${input_file}\" NAME_WE)\n  set(suggested_name \"${name}\")\n  if(suggested_name MATCHES \".*\\\\..*\")\n    string(REPLACE \".\" \"-\" suggested_name \"${suggested_name}\")\n  endif()\n  if(suggested_name MATCHES \".* .*\")\n    string(REPLACE \" \" \"-\" suggested_name \"${suggested_name}\")\n  endif()\n  if(NOT suggested_name STREQUAL name)\n    message(WARNING \"Some LaTeX distributions have problems with image file names with multiple extensions or spaces. Consider changing ${name}${extension} to something like ${suggested_name}${extension}.\")\n  endif()\n\n  string(REGEX REPLACE \"\\\\.[^.]*\\$\" ${output_extension} output_file\n    \"${input_file}\")\n\n  latex_list_contains(is_type ${extension} ${output_extensions})\n  if(is_type)\n    if(convert_flags)\n      latex_add_convert_command(${output_dir}/${output_file}\n        ${input_dir}/${input_file} ${output_extension} ${extension}\n        \"${convert_flags}\")\n      set(output_file_list ${output_dir}/${output_file})\n    else()\n      # As a shortcut, we can just copy the file.\n      add_custom_command(OUTPUT ${output_dir}/${input_file}\n        COMMAND ${CMAKE_COMMAND}\n        ARGS -E copy ${input_dir}/${input_file} ${output_dir}/${input_file}\n        DEPENDS ${input_dir}/${input_file}\n        )\n      set(output_file_list ${output_dir}/${input_file})\n    endif()\n  else()\n    set(do_convert TRUE)\n    # Check to see if there is another input file of the appropriate type.\n    foreach(valid_extension ${output_extensions})\n      string(REGEX REPLACE \"\\\\.[^.]*\\$\" ${output_extension} try_file\n        \"${input_file}\")\n      latex_list_contains(has_native_file \"${try_file}\" ${other_files})\n      if(has_native_file)\n        set(do_convert FALSE)\n      endif()\n    endforeach(valid_extension)\n\n    # If we still need to convert, do it.\n    if(do_convert)\n      latex_add_convert_command(${output_dir}/${output_file}\n        ${input_dir}/${input_file} ${output_extension} ${extension}\n        \"${convert_flags}\")\n      set(output_file_list ${output_dir}/${output_file})\n    endif()\n  endif()\n\n  set(${output_files_var} ${output_file_list} PARENT_SCOPE)\nendfunction(latex_convert_image)\n\n# Adds custom commands to process the given files for dvi and pdf builds.\n# Adds the output files to the given variables (does not replace).\nfunction(latex_process_images dvi_outputs_var pdf_outputs_var)\n  latex_get_output_path(output_dir)\n  set(dvi_outputs)\n  set(pdf_outputs)\n  foreach(file ${ARGN})\n    if(EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/${file}\")\n      latex_get_filename_component(extension \"${file}\" EXT)\n      set(convert_flags)\n\n      # Check to see if we need to downsample the image.\n      latex_list_contains(is_raster \"${extension}\"\n        ${LATEX_RASTER_IMAGE_EXTENSIONS})\n      if(LATEX_SMALL_IMAGES)\n        if(is_raster)\n          set(convert_flags -resize ${LATEX_RASTER_SCALE}%)\n        endif()\n      endif()\n\n      # Make sure the output directory exists.\n      latex_get_filename_component(path \"${output_dir}/${file}\" PATH)\n      make_directory(\"${path}\")\n\n      # Do conversions for dvi.\n      if(NOT LATEX_FORCE_PDF)\n          latex_convert_image(output_files \"${file}\" .eps \"${convert_flags}\"\n            \"${LATEX_DVI_IMAGE_EXTENSIONS}\" \"${ARGN}\")\n          list(APPEND dvi_outputs ${output_files})\n      endif ()\n\n      # Do conversions for pdf.\n      if(NOT LATEX_FORCE_DVI AND NOT LATEX_FORCE_HTML)\n        if(is_raster)\n          latex_convert_image(output_files \"${file}\" .png \"${convert_flags}\"\n            \"${LATEX_PDF_IMAGE_EXTENSIONS}\" \"${ARGN}\")\n          list(APPEND pdf_outputs ${output_files})\n        else()\n          latex_convert_image(output_files \"${file}\" .pdf \"${convert_flags}\"\n            \"${LATEX_PDF_IMAGE_EXTENSIONS}\" \"${ARGN}\")\n          list(APPEND pdf_outputs ${output_files})\n        endif()\n      endif()\n    else()\n      message(WARNING \"Could not find file ${CMAKE_CURRENT_SOURCE_DIR}/${file}.  Are you sure you gave relative paths to IMAGES?\")\n    endif()\n  endforeach(file)\n\n  set(${dvi_outputs_var} ${dvi_outputs} PARENT_SCOPE)\n  set(${pdf_outputs_var} ${pdf_outputs} PARENT_SCOPE)\nendfunction(latex_process_images)\n\nfunction(latex_copy_globbed_files pattern dest)\n  file(GLOB file_list ${pattern})\n  foreach(in_file ${file_list})\n    latex_get_filename_component(out_file ${in_file} NAME)\n    configure_file(${in_file} ${dest}/${out_file} COPYONLY)\n  endforeach(in_file)\nendfunction(latex_copy_globbed_files)\n\nfunction(latex_copy_input_file file)\n  latex_get_output_path(output_dir)\n\n  if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file})\n    latex_get_filename_component(path ${file} PATH)\n    file(MAKE_DIRECTORY ${output_dir}/${path})\n\n    latex_list_contains(use_config ${file} ${LATEX_CONFIGURE})\n    if(use_config)\n      configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${file}\n        ${output_dir}/${file}\n        @ONLY\n        )\n      add_custom_command(OUTPUT ${output_dir}/${file}\n        COMMAND ${CMAKE_COMMAND}\n        ARGS ${CMAKE_BINARY_DIR}\n        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file}\n        )\n    else()\n      add_custom_command(OUTPUT ${output_dir}/${file}\n        COMMAND ${CMAKE_COMMAND}\n        ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${output_dir}/${file}\n        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file}\n        )\n    endif()\n  else()\n    if(EXISTS ${output_dir}/${file})\n      # Special case: output exists but input does not.  Assume that it was\n      # created elsewhere and skip the input file copy.\n    else()\n      message(\"Could not find input file ${CMAKE_CURRENT_SOURCE_DIR}/${file}\")\n    endif()\n  endif()\nendfunction(latex_copy_input_file)\n\n#############################################################################\n# Commands provided by the UseLATEX.cmake \"package\"\n#############################################################################\n\nfunction(latex_usage command message)\n  message(SEND_ERROR\n      \"${message}\\n  Usage: ${command}(<tex_file>\\n           [BIBFILES <bib_file> <bib_file> ...]\\n           [INPUTS <tex_file> <tex_file> ...]\\n           [IMAGE_DIRS <directory1> <directory2> ...]\\n           [IMAGES <image_file1> <image_file2>\\n           [CONFIGURE <tex_file> <tex_file> ...]\\n           [DEPENDS <tex_file> <tex_file> ...]\\n           [MULTIBIB_NEWCITES] <suffix_list>\\n           [USE_BIBLATEX] [USE_INDEX] [USE_GLOSSARY] [USE_NOMENCL]\\n           [FORCE_PDF] [FORCE_DVI] [FORCE_HTML]\\n           [TARGET_NAME] <name>\\n           [EXCLUDE_FROM_ALL]\\n           [EXCLUDE_FROM_DEFAULTS])\"\n    )\nendfunction(latex_usage command message)\n\n# Parses arguments to add_latex_document and ADD_LATEX_TARGETS and sets the\n# variables LATEX_TARGET, LATEX_IMAGE_DIR, LATEX_BIBFILES, LATEX_DEPENDS, and\n# LATEX_INPUTS.\nfunction(parse_add_latex_arguments command latex_main_input)\n  set(options\n    USE_BIBLATEX\n    USE_INDEX\n    USE_GLOSSARY\n    USE_NOMENCL\n    FORCE_PDF\n    FORCE_DVI\n    FORCE_HTML\n    EXCLUDE_FROM_ALL\n    EXCLUDE_FROM_DEFAULTS\n    # Deprecated options\n    USE_GLOSSARIES\n    DEFAULT_PDF\n    DEFAULT_SAFEPDF\n    DEFAULT_PS\n    NO_DEFAULT\n    MANGLE_TARGET_NAMES\n    )\n  set(oneValueArgs\n    TARGET_NAME\n    )\n  set(multiValueArgs\n    BIBFILES\n    MULTIBIB_NEWCITES\n    INPUTS\n    IMAGE_DIRS\n    IMAGES\n    CONFIGURE\n    DEPENDS\n    INDEX_NAMES\n    INCLUDE_DIRECTORIES\n    )\n  cmake_parse_arguments(\n    LATEX \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\" ${ARGN})\n\n  # Handle invalid and deprecated arguments\n  if(LATEX_UNPARSED_ARGUMENTS)\n    latex_usage(${command} \"Invalid or deprecated arguments: ${LATEX_UNPARSED_ARGUMENTS}\")\n  endif()\n  if(LATEX_USE_GLOSSARIES)\n    latex_usage(${command} \"USE_GLOSSARIES option removed in version 1.6.1. Use USE_GLOSSARY instead.\")\n  endif()\n  if(LATEX_DEFAULT_PDF)\n    latex_usage(${command} \"DEFAULT_PDF option removed in version 2.0. Use FORCE_PDF option or LATEX_DEFAULT_BUILD CMake variable instead.\")\n  endif()\n  if(LATEX_DEFAULT_SAFEPDF)\n    latex_usage(${command} \"DEFAULT_SAFEPDF option removed in version 2.0. Use LATEX_DEFAULT_BUILD CMake variable instead.\")\n  endif()\n  if(LATEX_DEFAULT_DVI)\n    latex_usage(${command} \"DEFAULT_DVI option removed in version 2.0. Use FORCE_DVI option or LATEX_DEFAULT_BUILD CMake variable instead.\")\n  endif()\n  if(LATEX_NO_DEFAULT)\n    latex_usage(${command} \"NO_DEFAULT option removed in version 2.0. Use EXCLUDE_FROM_ALL instead.\")\n  endif()\n  if(LATEX_MANGLE_TARGET_NAMES)\n    latex_usage(${command} \"MANGLE_TARGET_NAMES option removed in version 2.0. All LaTeX targets use mangled names now.\")\n  endif()\n\n  # Capture the first argument, which is the main LaTeX input.\n  latex_get_filename_component(latex_target ${latex_main_input} NAME_WE)\n  set(LATEX_MAIN_INPUT ${latex_main_input} PARENT_SCOPE)\n  set(LATEX_TARGET ${latex_target} PARENT_SCOPE)\n\n  # Propagate the result variables to the caller\n  foreach(arg_name ${options} ${oneValueArgs} ${multiValueArgs})\n    set(var_name LATEX_${arg_name})\n    set(${var_name} ${${var_name}} PARENT_SCOPE)\n  endforeach(arg_name)\nendfunction(parse_add_latex_arguments)\n\nfunction(add_latex_targets_internal)\n  latex_get_output_path(output_dir)\n\n  if(LATEX_USE_SYNCTEX)\n    set(synctex_flags ${LATEX_SYNCTEX_ARGS})\n  else()\n    set(synctex_flags)\n  endif()\n\n  # The commands to run LaTeX.  They are repeated multiple times.\n  set(latex_build_command\n    ${LATEX_COMPILER} ${LATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT}\n    )\n  if(LATEX_COMPILER_ARGS MATCHES \".*batchmode.*\")\n    # Wrap command in script that dumps the log file on error. This makes sure\n    # errors can be seen.\n    set(latex_build_command\n      ${CMAKE_COMMAND}\n        -D LATEX_BUILD_COMMAND=execute_latex\n        -D LATEX_WORKING_DIRECTORY=\"${output_dir}\"\n        -D LATEX_FULL_COMMAND=\"${latex_build_command}\"\n        -D LATEX_OUTPUT_FILE=\"${LATEX_TARGET}.dvi\"\n        -D LATEX_LOG_FILE=\"${LATEX_TARGET}.log\"\n        -P \"${LATEX_USE_LATEX_LOCATION}\"\n      )\n  endif()\n  set(pdflatex_build_command\n    ${PDFLATEX_COMPILER} ${PDFLATEX_COMPILER_ARGS} ${synctex_flags} ${LATEX_MAIN_INPUT}\n    )\n  if(PDFLATEX_COMPILER_ARGS MATCHES \".*batchmode.*\")\n    # Wrap command in script that dumps the log file on error. This makes sure\n    # errors can be seen.\n    set(pdflatex_build_command\n      ${CMAKE_COMMAND}\n        -D LATEX_BUILD_COMMAND=execute_latex\n        -D LATEX_WORKING_DIRECTORY=\"${output_dir}\"\n        -D LATEX_FULL_COMMAND=\"${pdflatex_build_command}\"\n        -D LATEX_OUTPUT_FILE=\"${LATEX_TARGET}.pdf\"\n        -D LATEX_LOG_FILE=\"${LATEX_TARGET}.log\"\n        -P \"${LATEX_USE_LATEX_LOCATION}\"\n      )\n  endif()\n\n  if(LATEX_INCLUDE_DIRECTORIES)\n    # The include directories needs to start with the build directory so\n    # that the copied files can be found. It also needs to end with an\n    # empty directory so that the standard system directories are included\n    # after any specified.\n    set(LATEX_INCLUDE_DIRECTORIES . ${LATEX_INCLUDE_DIRECTORIES} \"\")\n\n    # CMake separates items in a list with a semicolon. Lists of\n    # directories on most systems are separated by colons, so we can do a\n    # simple text replace. On Windows, directories are separated by\n    # semicolons, but we replace them with the $<SEMICOLON> generator\n    # expression to make sure CMake treats it as a single string.\n    if(CMAKE_HOST_WIN32)\n      string(REPLACE \";\" \"$<SEMICOLON>\" TEXINPUTS \"${LATEX_INCLUDE_DIRECTORIES}\")\n    else()\n      string(REPLACE \";\" \":\" TEXINPUTS \"${LATEX_INCLUDE_DIRECTORIES}\")\n    endif()\n\n    # Set the TEXINPUTS environment variable\n    set(latex_build_command\n      ${CMAKE_COMMAND} -E env TEXINPUTS=${TEXINPUTS} ${latex_build_command})\n    set(pdflatex_build_command\n      ${CMAKE_COMMAND} -E env TEXINPUTS=${TEXINPUTS} ${pdflatex_build_command})\n  endif()\n\n  if(NOT LATEX_TARGET_NAME)\n    # Use the main filename (minus the .tex) as the target name. Remove any\n    # spaces since CMake cannot have spaces in its target names.\n    string(REPLACE \" \" \"_\" LATEX_TARGET_NAME ${LATEX_TARGET})\n  endif()\n\n  # Some LaTeX commands may need to be modified (or may not work) if the main\n  # tex file is in a subdirectory. Make a flag for that.\n  get_filename_component(LATEX_MAIN_INPUT_SUBDIR ${LATEX_MAIN_INPUT} DIRECTORY)\n\n  # Set up target names.\n  set(dvi_target      ${LATEX_TARGET_NAME}_dvi)\n  set(pdf_target      ${LATEX_TARGET_NAME}_pdf)\n  set(ps_target       ${LATEX_TARGET_NAME}_ps)\n  set(safepdf_target  ${LATEX_TARGET_NAME}_safepdf)\n  set(html_target     ${LATEX_TARGET_NAME}_html)\n  set(auxclean_target ${LATEX_TARGET_NAME}_auxclean)\n\n  # Probably not all of these will be generated, but they could be.\n  # Note that the aux file is added later.\n  set(auxiliary_clean_files\n    ${output_dir}/${LATEX_TARGET}.aux\n    ${output_dir}/${LATEX_TARGET}.bbl\n    ${output_dir}/${LATEX_TARGET}.blg\n    ${output_dir}/${LATEX_TARGET}-blx.bib\n    ${output_dir}/${LATEX_TARGET}.glg\n    ${output_dir}/${LATEX_TARGET}.glo\n    ${output_dir}/${LATEX_TARGET}.gls\n    ${output_dir}/${LATEX_TARGET}.idx\n    ${output_dir}/${LATEX_TARGET}.ilg\n    ${output_dir}/${LATEX_TARGET}.ind\n    ${output_dir}/${LATEX_TARGET}.ist\n    ${output_dir}/${LATEX_TARGET}.log\n    ${output_dir}/${LATEX_TARGET}.out\n    ${output_dir}/${LATEX_TARGET}.toc\n    ${output_dir}/${LATEX_TARGET}.lof\n    ${output_dir}/${LATEX_TARGET}.xdy\n    ${output_dir}/${LATEX_TARGET}.synctex.gz\n    ${output_dir}/${LATEX_TARGET}.synctex.bak.gz\n    ${output_dir}/${LATEX_TARGET}.dvi\n    ${output_dir}/${LATEX_TARGET}.ps\n    ${output_dir}/${LATEX_TARGET}.pdf\n    )\n\n  set(image_list ${LATEX_IMAGES})\n\n  # For each directory in LATEX_IMAGE_DIRS, glob all the image files and\n  # place them in LATEX_IMAGES.\n  foreach(dir ${LATEX_IMAGE_DIRS})\n    if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${dir})\n      message(WARNING \"Image directory ${CMAKE_CURRENT_SOURCE_DIR}/${dir} does not exist.  Are you sure you gave relative directories to IMAGE_DIRS?\")\n    endif()\n    foreach(extension ${LATEX_IMAGE_EXTENSIONS})\n      file(GLOB files ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*${extension})\n      foreach(file ${files})\n        latex_get_filename_component(filename ${file} NAME)\n        list(APPEND image_list ${dir}/${filename})\n      endforeach(file)\n    endforeach(extension)\n  endforeach(dir)\n\n  latex_process_images(dvi_images pdf_images ${image_list})\n\n  set(make_dvi_command\n    ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${latex_build_command})\n  set(make_pdf_command\n    ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${pdflatex_build_command}\n    )\n\n  set(make_dvi_depends ${LATEX_DEPENDS} ${dvi_images})\n  set(make_pdf_depends ${LATEX_DEPENDS} ${pdf_images})\n  foreach(input ${LATEX_MAIN_INPUT} ${LATEX_INPUTS})\n    list(APPEND make_dvi_depends ${output_dir}/${input})\n    list(APPEND make_pdf_depends ${output_dir}/${input})\n    if(${input} MATCHES \"\\\\.tex$\")\n      # Dependent .tex files might have their own .aux files created.  Make\n      # sure these get cleaned as well.  This might replicate the cleaning\n      # of the main .aux file, which is OK.\n      string(REGEX REPLACE \"\\\\.tex$\" \"\" input_we ${input})\n      list(APPEND auxiliary_clean_files\n        ${output_dir}/${input_we}.aux\n        ${output_dir}/${input}.aux\n        )\n    endif()\n  endforeach(input)\n\n  set(all_latex_sources ${LATEX_MAIN_INPUT} ${LATEX_INPUTS} ${image_list})\n\n  if(LATEX_USE_GLOSSARY)\n    foreach(dummy 0 1)   # Repeat these commands twice.\n      set(make_dvi_command ${make_dvi_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${CMAKE_COMMAND}\n        -D LATEX_BUILD_COMMAND=makeglossaries\n        -D LATEX_TARGET=${LATEX_TARGET}\n        -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}\n        -D XINDY_COMPILER=${XINDY_COMPILER}\n        -D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS}\n        -P ${LATEX_USE_LATEX_LOCATION}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${latex_build_command}\n        )\n      set(make_pdf_command ${make_pdf_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${CMAKE_COMMAND}\n        -D LATEX_BUILD_COMMAND=makeglossaries\n        -D LATEX_TARGET=${LATEX_TARGET}\n        -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}\n        -D XINDY_COMPILER=${XINDY_COMPILER}\n        -D MAKEGLOSSARIES_COMPILER_ARGS=${MAKEGLOSSARIES_COMPILER_ARGS}\n        -P ${LATEX_USE_LATEX_LOCATION}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${pdflatex_build_command}\n        )\n    endforeach(dummy)\n  endif()\n\n  if(LATEX_USE_NOMENCL)\n    foreach(dummy 0 1)   # Repeat these commands twice.\n      set(make_dvi_command ${make_dvi_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${CMAKE_COMMAND}\n        -D LATEX_BUILD_COMMAND=makenomenclature\n        -D LATEX_TARGET=${LATEX_TARGET}\n        -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}\n        -D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS}\n        -P ${LATEX_USE_LATEX_LOCATION}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${latex_build_command}\n        )\n      set(make_pdf_command ${make_pdf_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${CMAKE_COMMAND}\n        -D LATEX_BUILD_COMMAND=makenomenclature\n        -D LATEX_TARGET=${LATEX_TARGET}\n        -D MAKEINDEX_COMPILER=${MAKEINDEX_COMPILER}\n        -D MAKENOMENCLATURE_COMPILER_ARGS=${MAKENOMENCLATURE_COMPILER_ARGS}\n        -P ${LATEX_USE_LATEX_LOCATION}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${pdflatex_build_command}\n        )\n    endforeach(dummy)\n  endif()\n\n  if(LATEX_BIBFILES)\n    set(suppress_bib_output)\n    if(LATEX_USE_BIBLATEX)\n      if(NOT BIBER_COMPILER)\n        message(SEND_ERROR \"I need the biber command.\")\n      endif()\n      set(bib_compiler ${BIBER_COMPILER})\n      set(bib_compiler_flags ${BIBER_COMPILER_ARGS})\n\n      if(NOT BIBER_COMPILER_ARGS MATCHES \".*-q.*\")\n        # Only suppress bib output if the quiet option is not specified.\n        set(suppress_bib_output TRUE)\n      endif()\n\n      if(LATEX_USE_BIBLATEX_CONFIG)\n        list(APPEND auxiliary_clean_files ${output_dir}/biblatex.cfg)\n        list(APPEND make_dvi_depends ${output_dir}/biblatex.cfg)\n        list(APPEND make_pdf_depends ${output_dir}/biblatex.cfg)\n      endif()\n    else()\n      set(bib_compiler ${BIBTEX_COMPILER})\n      set(bib_compiler_flags ${BIBTEX_COMPILER_ARGS})\n    endif() \n    if(LATEX_MULTIBIB_NEWCITES)\n      # Suppressed bib output currently not supported for multibib\n      foreach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES})\n        latex_get_filename_component(multibib_target ${multibib_auxfile} NAME_WE)\n        set(make_dvi_command ${make_dvi_command}\n          COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n          ${bib_compiler} ${bib_compiler_flags} ${multibib_target})\n        set(make_pdf_command ${make_pdf_command}\n          COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n          ${bib_compiler} ${bib_compiler_flags} ${multibib_target})\n        set(auxiliary_clean_files ${auxiliary_clean_files}\n          ${output_dir}/${multibib_target}.aux)\n      endforeach (multibib_auxfile ${LATEX_MULTIBIB_NEWCITES})\n    else()\n      set(full_bib_command\n        ${bib_compiler} ${bib_compiler_flags} ${LATEX_TARGET})\n      if(suppress_bib_output)\n        set(full_bib_command\n          ${CMAKE_COMMAND}\n          -D LATEX_BUILD_COMMAND=execute_latex\n          -D LATEX_WORKING_DIRECTORY=\"${output_dir}\"\n          -D LATEX_FULL_COMMAND=\"${full_bib_command}\"\n          -D LATEX_OUTPUT_FILE=\"${LATEX_TARGET}.bbl\"\n          -D LATEX_LOG_FILE=\"${LATEX_TARGET}.blg\"\n          -P \"${LATEX_USE_LATEX_LOCATION}\"\n          )\n      endif()\n      set(make_dvi_command ${make_dvi_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${full_bib_command})\n      set(make_pdf_command ${make_pdf_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${full_bib_command})\n    endif()\n\n    foreach (bibfile ${LATEX_BIBFILES})\n      list(APPEND make_dvi_depends ${output_dir}/${bibfile})\n      list(APPEND make_pdf_depends ${output_dir}/${bibfile})\n    endforeach (bibfile ${LATEX_BIBFILES})\n  else()\n    if(LATEX_MULTIBIB_NEWCITES)\n      message(WARNING \"MULTIBIB_NEWCITES has no effect without BIBFILES option.\")\n    endif()\n  endif()\n\n  if(LATEX_USE_INDEX)\n    if(LATEX_INDEX_NAMES)\n      set(INDEX_NAMES ${LATEX_INDEX_NAMES})\n    else()\n      set(INDEX_NAMES ${LATEX_TARGET})\n    endif()\n    foreach(idx_name ${INDEX_NAMES})\n      set(make_dvi_command ${make_dvi_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${latex_build_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx)\n      set(make_pdf_command ${make_pdf_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${pdflatex_build_command}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${MAKEINDEX_COMPILER} ${MAKEINDEX_COMPILER_ARGS} ${idx_name}.idx)\n      set(auxiliary_clean_files ${auxiliary_clean_files}\n        ${output_dir}/${idx_name}.idx\n        ${output_dir}/${idx_name}.ilg\n        ${output_dir}/${idx_name}.ind)\n    endforeach()\n  else()\n    if(LATEX_INDEX_NAMES)\n      message(WARNING \"INDEX_NAMES has no effect without USE_INDEX option.\")\n    endif()\n  endif()\n\n  set(make_dvi_command ${make_dvi_command}\n    COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${latex_build_command}\n    COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${latex_build_command})\n  set(make_pdf_command ${make_pdf_command}\n    COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${pdflatex_build_command}\n    COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${pdflatex_build_command})\n\n  # Need to run one more time to remove biblatex' warning\n  # about page breaks that have changed.\n  if(LATEX_USE_BIBLATEX)\n    set(make_dvi_command ${make_dvi_command}\n      COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n      ${latex_build_command})\n    set(make_pdf_command ${make_pdf_command}\n      COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n      ${pdflatex_build_command})\n  endif()\n\n  if(LATEX_USE_SYNCTEX)\n    if(NOT GZIP)\n      message(SEND_ERROR \"UseLATEX.cmake: USE_SYNTEX option requires gzip program.  Set GZIP variable.\")\n    endif()\n    set(make_dvi_command ${make_dvi_command}\n      COMMAND ${CMAKE_COMMAND}\n      -D LATEX_BUILD_COMMAND=correct_synctex\n      -D LATEX_TARGET=${LATEX_TARGET}\n      -D GZIP=${GZIP}\n      -D \"LATEX_SOURCE_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}\"\n      -D \"LATEX_BINARY_DIRECTORY=${output_dir}\"\n      -P ${LATEX_USE_LATEX_LOCATION}\n      )\n    set(make_pdf_command ${make_pdf_command}\n      COMMAND ${CMAKE_COMMAND}\n      -D LATEX_BUILD_COMMAND=correct_synctex\n      -D LATEX_TARGET=${LATEX_TARGET}\n      -D GZIP=${GZIP}\n      -D \"LATEX_SOURCE_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR}\"\n      -D \"LATEX_BINARY_DIRECTORY=${output_dir}\"\n      -P ${LATEX_USE_LATEX_LOCATION}\n      )\n  endif()\n\n  # Check LaTeX output for important warnings at end of build\n  set(make_dvi_command ${make_dvi_command}\n    COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${CMAKE_COMMAND}\n      -D LATEX_BUILD_COMMAND=check_important_warnings\n      -D LATEX_TARGET=${LATEX_TARGET}\n      -P ${LATEX_USE_LATEX_LOCATION}\n    )\n  set(make_pdf_command ${make_pdf_command}\n    COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n    ${CMAKE_COMMAND}\n      -D LATEX_BUILD_COMMAND=check_important_warnings\n      -D LATEX_TARGET=${LATEX_TARGET}\n      -P ${LATEX_USE_LATEX_LOCATION}\n    )\n\n  # Capture the default build.\n  string(TOLOWER \"${LATEX_DEFAULT_BUILD}\" default_build)\n\n  if((NOT LATEX_FORCE_PDF) AND (NOT LATEX_FORCE_DVI) AND (NOT LATEX_FORCE_HTML))\n    set(no_force TRUE)\n  endif()\n\n  # Add commands and targets for building pdf outputs (with pdflatex).\n  if(LATEX_FORCE_PDF OR no_force)\n    if(LATEX_FORCE_PDF)\n      set(default_build pdf)\n    endif()\n\n    if(PDFLATEX_COMPILER)\n      add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.pdf\n        COMMAND ${make_pdf_command}\n        DEPENDS ${make_pdf_depends}\n        )\n      add_custom_target(${pdf_target}\n        DEPENDS ${output_dir}/${LATEX_TARGET}.pdf\n        SOURCES ${all_latex_sources}\n        )\n      if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)\n        add_dependencies(pdf ${pdf_target})\n      endif()\n    endif()\n  endif()\n\n  # Add commands and targets for building dvi outputs.\n  if(LATEX_FORCE_DVI OR LATEX_FORCE_HTML OR no_force)\n    if(LATEX_FORCE_DVI)\n      if((NOT default_build STREQUAL dvi) AND\n          (NOT default_build STREQUAL ps) AND\n          (NOT default_build STREQUAL safepdf))\n        set(default_build dvi)\n      endif()\n    endif()\n\n    add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.dvi\n      COMMAND ${make_dvi_command}\n      DEPENDS ${make_dvi_depends}\n      )\n    add_custom_target(${dvi_target}\n      DEPENDS ${output_dir}/${LATEX_TARGET}.dvi\n      SOURCES ${all_latex_sources}\n      )\n    if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)\n      add_dependencies(dvi ${dvi_target})\n    endif()\n\n    if(DVIPS_CONVERTER)\n      add_custom_command(OUTPUT ${output_dir}/${LATEX_TARGET}.ps\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n        ${DVIPS_CONVERTER} ${DVIPS_CONVERTER_ARGS} -o ${LATEX_TARGET}.ps ${LATEX_TARGET}.dvi\n        DEPENDS ${output_dir}/${LATEX_TARGET}.dvi)\n      add_custom_target(${ps_target}\n        DEPENDS ${output_dir}/${LATEX_TARGET}.ps\n        SOURCES ${all_latex_sources}\n        )\n      if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)\n        add_dependencies(ps ${ps_target})\n      endif()\n      if(PS2PDF_CONVERTER)\n        # Since both the pdf and safepdf targets have the same output, we\n        # cannot properly do the dependencies for both.  When selecting safepdf,\n        # simply force a recompile every time.\n        add_custom_target(${safepdf_target}\n          ${CMAKE_COMMAND} -E chdir ${output_dir}\n          ${PS2PDF_CONVERTER} ${PS2PDF_CONVERTER_ARGS} ${LATEX_TARGET}.ps ${LATEX_TARGET}.pdf\n          DEPENDS ${ps_target}\n          )\n        if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)\n          add_dependencies(safepdf ${safepdf_target})\n        endif()\n      endif()\n    endif()\n  endif()\n\n  if(LATEX_FORCE_HTML OR no_force)\n    if (LATEX_FORCE_HTML)\n      set(default_build html)\n    endif()\n\n    if(HTLATEX_COMPILER AND LATEX_MAIN_INPUT_SUBDIR)\n      message(STATUS\n        \"Disabling HTML build for ${LATEX_TARGET_NAME}.tex because the main file is in subdirectory ${LATEX_MAIN_INPUT_SUBDIR}\"\n        )\n      # The code below to run HTML assumes that LATEX_TARGET.tex is in the\n      # current directory. I have tried to specify that LATEX_TARGET.tex is\n      # in a subdirectory. That makes the build targets correct, but the\n      # HTML build still fails (at least for htlatex) because files are not\n      # generated where expected. I am getting around the problem by simply\n      # disabling HTML in this case. If someone really cares, they can fix\n      # this, but make sure it runs on many platforms and build programs.\n    elseif(HTLATEX_COMPILER)\n      # htlatex places the output in a different location\n      set(HTML_OUTPUT \"${output_dir}/${LATEX_TARGET}.html\")\n      add_custom_command(OUTPUT ${HTML_OUTPUT}\n        COMMAND ${CMAKE_COMMAND} -E chdir ${output_dir}\n          ${HTLATEX_COMPILER} ${LATEX_MAIN_INPUT}\n          \"${HTLATEX_COMPILER_TEX4HT_FLAGS}\"\n          \"${HTLATEX_COMPILER_TEX4HT_POSTPROCESSOR_FLAGS}\"\n          \"${HTLATEX_COMPILER_T4HT_POSTPROCESSOR_FLAGS}\"\n          ${HTLATEX_COMPILER_ARGS}\n        DEPENDS\n          ${output_dir}/${LATEX_TARGET}.tex\n          ${output_dir}/${LATEX_TARGET}.dvi\n        VERBATIM\n        )\n      add_custom_target(${html_target}\n        DEPENDS ${HTML_OUTPUT} ${dvi_target}\n        SOURCES ${all_latex_sources}\n        )\n      if(NOT LATEX_EXCLUDE_FROM_DEFAULTS)\n        add_dependencies(html ${html_target})\n      endif()\n    endif()\n  endif()\n\n  # Set default targets.\n  if(\"${default_build}\" STREQUAL \"pdf\")\n    add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${pdf_target})\n  elseif(\"${default_build}\" STREQUAL \"dvi\")\n    add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${dvi_target})\n  elseif(\"${default_build}\" STREQUAL \"ps\")\n    add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${ps_target})\n  elseif(\"${default_build}\" STREQUAL \"safepdf\")\n    add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${safepdf_target})\n  elseif(\"${default_build}\" STREQUAL \"html\")\n    add_custom_target(${LATEX_TARGET_NAME} DEPENDS ${html_target})\n  else()\n    message(SEND_ERROR \"LATEX_DEFAULT_BUILD set to an invalid value. See the documentation for that variable.\")\n  endif()\n\n  if(NOT LATEX_EXCLUDE_FROM_ALL)\n    add_custom_target(_${LATEX_TARGET_NAME} ALL DEPENDS ${LATEX_TARGET_NAME})\n  endif()\n\n  set_directory_properties(.\n    ADDITIONAL_MAKE_CLEAN_FILES \"${auxiliary_clean_files}\"\n    )\n\n  add_custom_target(${auxclean_target}\n    COMMENT \"Cleaning auxiliary LaTeX files.\"\n    COMMAND ${CMAKE_COMMAND} -E remove ${auxiliary_clean_files}\n    )\n  add_dependencies(auxclean ${auxclean_target})\nendfunction(add_latex_targets_internal)\n\nfunction(add_latex_targets latex_main_input)\n  latex_get_output_path(output_dir)\n  parse_add_latex_arguments(ADD_LATEX_TARGETS ${latex_main_input} ${ARGN})\n\n  add_latex_targets_internal()\nendfunction(add_latex_targets)\n\nfunction(add_latex_document latex_main_input)\n  latex_get_output_path(output_dir)\n  if(output_dir)\n    parse_add_latex_arguments(add_latex_document ${latex_main_input} ${ARGN})\n\n    latex_copy_input_file(${LATEX_MAIN_INPUT})\n\n    foreach (bib_file ${LATEX_BIBFILES})\n      latex_copy_input_file(${bib_file})\n    endforeach (bib_file)\n\n    if (LATEX_USE_BIBLATEX AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/biblatex.cfg)\n      latex_copy_input_file(biblatex.cfg)\n      set(LATEX_USE_BIBLATEX_CONFIG TRUE)\n    endif()\n\n    foreach (input ${LATEX_INPUTS})\n      latex_copy_input_file(${input})\n    endforeach(input)\n\n    latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.cls ${output_dir})\n    latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.bst ${output_dir})\n    latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.clo ${output_dir})\n    latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.sty ${output_dir})\n    latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.ist ${output_dir})\n    latex_copy_globbed_files(${CMAKE_CURRENT_SOURCE_DIR}/*.fd  ${output_dir})\n\n    add_latex_targets_internal()\n  endif()\nendfunction(add_latex_document)\n\n#############################################################################\n# Actually do stuff\n#############################################################################\n\nif(LATEX_BUILD_COMMAND)\n  set(command_handled)\n\n  if(\"${LATEX_BUILD_COMMAND}\" STREQUAL execute_latex)\n    latex_execute_latex()\n    set(command_handled TRUE)\n  endif()\n\n  if(\"${LATEX_BUILD_COMMAND}\" STREQUAL makeglossaries)\n    latex_makeglossaries()\n    set(command_handled TRUE)\n  endif()\n\n  if(\"${LATEX_BUILD_COMMAND}\" STREQUAL makenomenclature)\n    latex_makenomenclature()\n    set(command_handled TRUE)\n  endif()\n\n  if(\"${LATEX_BUILD_COMMAND}\" STREQUAL correct_synctex)\n    latex_correct_synctex()\n    set(command_handled TRUE)\n  endif()\n\n  if(\"${LATEX_BUILD_COMMAND}\" STREQUAL check_important_warnings)\n    latex_check_important_warnings()\n    set(command_handled TRUE)\n  endif()\n\n  if(NOT command_handled)\n    message(SEND_ERROR \"Unknown command: ${LATEX_BUILD_COMMAND}\")\n  endif()\n\nelse()\n  # Must be part of the actual configure (included from CMakeLists.txt).\n  latex_setup_variables()\n  latex_setup_targets()\nendif()\n"
  },
  {
    "path": "doc/CMakeLists.txt",
    "content": "add_latex_document(user-guide.tex\n   INPUTS\n      ref.tex\n      macro.tex\n   BIBFILES\n      ipr.bib\n   TARGET_NAME\n      doc)"
  },
  {
    "path": "doc/ChangeLog",
    "content": "2019-06-26  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* user-guide.tex: Tidy.\n\t* ref.tex: Likewise.\n\n2019-06-26  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* Makefile.am: Generate PDF.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex: Fix various discrepancies.\n\n2005-03-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.34\n\n2005-02-18  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (subsection{Pointer to member type}): New.\n\t(subsection{Non-static data members}): Move from user-define type\n\tsection to variable section.\n\t(subsection{Selection statement}): Give examples.\n\t(section{Parameterized declarations}): Add more explanations.\n\n2005-02-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (subsection{Expression as type}): Propagate\n\trenaming of Expr_as_type to As_type.\n\t(subsubsection{Members of user-defined types}): Propagate renaming\n\tof heterogeneous_region to Region.\n\t(section{Function declarations}): Rework.\n\n2005-02-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (subsection{Primary named mappings}): Document\n\tconstruction of primary template declaration.\n\n2005-02-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (subsection{Compound statement}): Fix thinko.\n\n2005-02-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (subsection{User-defined types}): Document\n\tconstruction of user-defined types.\n\n2005-02-06  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.33\n\n\t* user-guide.tex: Add more documentations.\n\t(\\section{Generalities}): New.\n\t(\\section{Statements}): Rework.\n\t(\\section{Function declaration}): Rework.\n\t(\\section{Declarations}): Remove.\n\t* ref.tex: Remove bogus descriptions.\n\n2005-02-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ref.tex: Rewrite introductory section.  Document region and\n\tsuch. Remove needless math obfuscation.  \n\t* macro.tex (\\cxxOpt): New command.\n\t* ipr.bib: Update referneces.\n\n2005-02-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.31.\n\n2005-01-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.30.\n\n2005-01-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.29.\n\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Makefile.am: New.\n\t* Makefile.in: Likewise.\n\t\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.28.\n\n2005-01-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.27.\n\n2004-10-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.26.\n\n2004-09-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.25\n\t\n\t* user-guide.tex: Fix typos.  Document new nodes Ctor_name and\n\tDtor_name. \n\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.24.\n\t\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex: Add more documentation on declaration\n\tconstruction. \n\n2004-09-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ref.tex (subsection{Annotations}): Update diagram.  Add more\n\tdescription.\n\t(subsubsection{\\texttt{Identifier}}): Update description.  Add\n\tdiagram. \n\t(subsubsection{\\texttt{Operator}}): Likewise.\n\n\t* macro.tex: Add new macro for proper operation in Xy-pic mode.\n\n2004-09-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (section{Literals}): Clarify creation of literals.\n\n2004-08-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.23.\n\t\n2004-08-30  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex: Document more type nodes.\n\n2004-08-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex (section{Names}): Add documentations for the\n\tvarious name nodes.\n\n2004-08-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.22.\n\t\n2004-08-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.21.\n\t\n2004-08-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.bib: New file.\n\t* user-guide.tex: Use it. Document more nodes. \n\t* ref.tex: Use ipr.bib.  Update out-dated class definitions.\n\n2004-08-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* macro.tex: New file.\n\t* user-guide.tex: Use it.\n\t* ref.tex: Likewise.\n\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.20.\n\t\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex: Document statements.\n\n2004-08-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.19.\n\t\n2004-08-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex: New file.\n\n2004-07-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.18\n\t\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.17\n\t\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* user-guide.tex: New file.\n\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.16.\n\t\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.15.\n\t\n2004-07-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.14.\n\t\n2004-07-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.13.\n\t\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.12.\n\t\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.11.\n\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.10.\n\n2004-05-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ref.tex: Expand on declarations, scopes documentation.  Document\n\tthe notion of type.\n\n2004-05-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.08.\n\n2004-05-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.07.\n\n2004-05-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ref.tex: Document more interface nodes.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.06.\n\n2004-05-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.05.\n\n"
  },
  {
    "path": "doc/ipr.bib",
    "content": "%% Books\n@Book{mac-lane01:categories,\n  author = \t {Mac~Lane, S.},\n  title = \t {{Categories} {for} {the} {Working} {Mathematicians}},\n  publisher = \t {Springer},\n  year = \t 2001,\n  edition = \t {2nd}\n}\n\n@Book{gamma,\n  author =\t {Gamma, E. and al.},\n  title = \t {{Design Patterns}},\n  publisher = \t {Addison-Wesley},\n  year = \t 1994\n}\n\n%% Manuals\n@Manual{dosreis04:ipr-user-guide,\n  title = \t {{IPR} {User} {Guide}},\n  author =\t {Dos~Reis, G.},\n  year =\t 2004\n}\n\n@Manual{dosreis04:ipr-ref,\n  title = \t {{Internal Program Representation for \\ThePivot{}}},\n  author =\t {Dos~Reis, G. and Stroustrup, B.},\n  year =\t 2004\n}\n\n\n@Manual{gdr-bs05:cxx-rep,\n  title = \t {{Representing C++ Directly, Efficiently and Completely}},\n  author =\t {Dos~Reis, G. and Stroustrup, B.},\n  year =\t 2005\n}\n\n\n@Manual{stroustrup02:xti,\n  title = \t {{XTI: A simple, complete C++ Extended Type Information Library}},\n  author =\t {Stroustrup, B.},\n  year =\t 2002\n}\n\n\n@Manual{iso03,\n  title = \t {{International Standard ISO/IEC 14882.  Programming Languages --- C++}},\n  organization = {ISO},\n  edition = \t {2nd},\n  year = \t 2003\n}\n\n@Manual{iso99,\n  title = \t {{International Standard ISO/IEC 9899.  Programming Languages --- C}},\n  organization = {ISO},\n  edition = \t {2nd},\n  year = \t 1999\n}\n\n@Manual{iso98,\n  title = \t {{International Standard ISO/IEC 14882.  Programming Languages --- C++}},\n  organization = {ISO},\n  year = \t 1998\n}\n"
  },
  {
    "path": "doc/macro.tex",
    "content": "\\newcommand{\\of}[1]{\\left(#1\\right)}\n\\newcommand{\\ThePivot}{\\textit{The~Pivot}}\n\\newcommand{\\cxxRule}[1]{{\\rmfamily\\itshape #1}}\n\\newcommand{\\cxxOpt}[1]{{#1}$_{\\mathit{opt}}$}\n\\newcommand{\\cxxOptRule}[1]{\\cxxRule{#1}$_{\\mathit{opt}}$}\n\\newcommand{\\NodeClass}[1]{\\texttt{#1}}\n\\newcommand{\\bslash}{$\\backslash$}\n\\newcommand{\\ie}{\\emph{i.e.}}\n\\newcommand{\\eg}{e.g.}\n\\newcommand{\\secref}[1]{$\\S$\\ref{#1}}\n\\newcommand{\\const}{\\texttt{const}}\n\\newcommand{\\cat}[1]{\\ensuremath{\\mathfrak{#1}}}\n\\newcommand{\\code}[1]{{\\ttfamily #1}}\n\n\\newcommand{\\rel}[1]{{\\fontfamily{pzc}\\selectfont #1}}\n\\newcommand{\\xyrel}[1]{\\hbox{\\rel{#1}}}\n\\newcommand{\\xylabel}[1]{\\hbox{{\\scriptsize\\textit{#1}}}}\n\\newcommand{\\xyiprop}[1]{\\hbox{\\iprop{#1}}}\n\\newcommand{\\xycst}[1]{\\hbox{{\\scriptsize\\cst{#1}}}}\n\\newcommand{\\xycode}[1]{\\hbox{\\scriptsize\\code{#1}}}\n\n\\newcommand{\\iprop}[1]{\\textit{#1}}\n\\newcommand{\\expr}[1]{{\\ttfamily\\slshape #1}}\n\\newcommand{\\ptr}[1]{#1\\textasteriskcentered}\n\\newcommand{\\cst}[1]{\\textsf{#1}}\n\n\n\\newcommand{\\Class}[1]{\\texttt{#1}}\n\n\\newenvironment{Program}{\\begin{alltt}\\footnotesize%\n}{\\end{alltt}}\n\n\\newenvironment{Grammar}{\\begin{alltt}\\footnotesize%\n}{\\end{alltt}}\n\n\\newenvironment{Output}{\\begin{alltt}\\footnotesize%\n}{\\end{alltt}}\n\n\\newenvironment{note}{\\small\\itshape [Note: }{---end note]}\n\n%%% Local Variables: \n%%% mode: latex\n%%% End: \n"
  },
  {
    "path": "doc/ref.tex",
    "content": "\\documentclass[letter,11pt]{article}\n\\usepackage[latin1]{inputenc}\n\\usepackage[T1]{fontenc}\n\\usepackage{mathrsfs}\n%\\usepackage{lucidabr}\n%\\usepackage{yhmath}\n%\\usepackage{palatino}\n\\usepackage{amsmath,amssymb}\n%\\usepackage{graphics, psfig}\n\\usepackage[all]{xy}\n\\usepackage{alltt}\n\n\\input{macro}\n\n\n\\title{Internal Program Representation for \\ThePivot}\n\n\\author{G.~Dos~Reis \\and B.~Stroustrup}\n\\date{}\n\n\\begin{document}\n\\maketitle\n\n\\section{Introduction}\n\\label{sec:intro}\n\n\\ThePivot{} framework is a general infrastructure for transformation and\nstatic analysis of programs written in C++ programming language. This document\nserves as a refenrece manual for the internal program represenation use in the \n\\ThePivot{} framework.  A companion \ndocument~\\cite{dosreis04:ipr-user-guide} provides a user point of view.\n\n%% \\begin{alltt}\\small\n%%   \\begin{note}\n%%     Include examples on the max function.\n%%   \\end{note}\n%% \\end{alltt}\n\nThis document is structured as follows. The next subsections introduce general\nnotions of the language used to represent C++ entities. \n%% The second part\n%% \\secref{sec:intro:organization} explains how the IPR library is organized.\n Then \\secref{sec:interface-classes} go on describing the\ninterface of the various categories of nodes used in IPR. After that,\n\\secref{sec:impl} discusses the implementations of those interfaces.  Finally,\n\\secref{sec:xpr-grammar} gives a formal definition of XPR, the concrete syntax\nfor the external representation of programs in \\ThePivot{}.\n\n\n\\subsection{The problem, solutions space and design choices}\n\\label{sec:design}\n\nSee \\cite{stroustrup02:xti, gdr-bs05:cxx-rep}.\n\n\\subsection{General notions}\n\\label{sec:intro:general-notion}\n\nA program is internally represented as a graph.  The nodes represents various\nnotions, such as types, expresssions, declarations, scopes, names...\n\nA (well-formed) program written in C++ is composed of instantiation units. \nInstantiation units are obtained from translation units after template\ninstantiation requests satisfaction.  Consequently, most IPR notions are\ndriven by declarations.\n\n\\subsubsection{Declaration}\n\\label{sec:intro:general-notion:declaration}\nA \\emph{declaration} is a specification of a \\emph{type}, a set of\n\\emph{attributes}, and an optional initialier for a name.  The type dictates\nthe major mode of interpretation of the name.  The attributes or\n\\emph{declaration specifiers} supply additional interpretations or modifiers\nthe major mode.  The initializer is the expression the value of which the\nname evaluates to, until eventual assignment to another value (if permitted by\nthe type).  This notion of declaration covers a wide range of situations.\nExample:\n\n\\begin{minipage}[t]{12cm}\n  \\begin{minipage}[t]{5cm}\n    \\centering{\\textit{C++}}\n    \\begin{Program}\n  int counter = 0;\n\n  struct point \\{\n    int x;\n    int y;\n  \\};\n\n  int next(int x) \\{\n    return x + 1;\n  \\}\n\n  template<int N>\n  struct buffer \\{\n     char data[N];\n  \\};\n    \n    \\end{Program}\n  \\end{minipage}\\hfil \\vrule \\hfil\n  \\begin{minipage}[t]{5cm}\n    \\centering{\\textit{XPR}}\n    \\begin{Program}\n  counter : int = 0;\n\n  point : class = \\{\n    x : int;\n    y : int;\n  \\};\n\n  next : (x : int) int = \\{\n    return x + 1;\n  \\}\n\n  buffer : <N : int> class = \\{\n    data : [N] char;\n  \\};\n    \\end{Program}\n  \\end{minipage}\n\\end{minipage}\n\nIn this example, the same program is expressed in both standard C++ and XPR\nnotations.  All the declarations follow the same pattern (which is probably\nmore stricking in the XPR notation): a name, a type, and an initializer.  In\nparticular, the class body and the function body are the initializers for the\nclass \\texttt{point} and \\texttt{next}, repsectively.  The name \\texttt{point}\nis declared to have type \\texttt{class}.\n \nIn some regions, a declaration can be repeated many times. The first\n declaration for a name (with a given type) in a given region is \n called the \\emph{master declaration} of that name in that region.\n\n\\subsubsection{Type}\n\\label{sec:intro:general-notion:type}\n\nIn IPR, a \\emph{type} is conceived of as a collection of values or objects\nwith operations or functions.  This is not the most abstract definition of\ntype in circulation, but it is sufficiently general and close to the \ngeneral aims of the \\ThePivot{} framework.  A type in IPR is a notion similar\nto that of category~\\cite{mac-lane01:categories}, it is a notion used to\ndescribe a collection of objects with given properties.  In similar ways, the\nnotion of category can be used to talk about collection of categories, types \nin IPR are expressions that have types.  For example, the class \\texttt{ios}\nof the previous section has type \\texttt{class}, just like\nthe enumerator \\texttt{ios::dec} has type \\texttt{ios::flags} and the\nenumeration \\texttt{ios::flags} has type \\texttt{enum}.\n\n\\subsubsection{Overloading}\n\\label{sec:intro:general-notion:overloading}\nMost regions can contain different declarations with a given name.  Such\ndeclarations are either redeclarations or declarations that use\ndifferent types.  A name is said to be  \\emph{overloaded} in a given region if\nthat region contains at least two declarations specifying different types for\nthat name.  This concept of overloading is uniformly applied in IPR.  In\nparticular, any declaration can be overloaded, not just function declaration.\nSo the following fragment (in XPR notation) is valid.\n\\begin{Program}\n  pi : double = 3.141592653589793;\n  pi : float = 3.141592654f;\n\\end{Program}\n\nThat program frgament cannot be written directly in C++, as only functions\ncan be overloaded in Standard C++.  However it could be emulated, in\nsome specific cases, as a function object:\n\\begin{Program}\n  struct pi \\{\n    operator double() const \\{ return 3.141592653589793; \\}\n    operator float() const \\{ return 3.141592654f; \\}\n  \\};\n\\end{Program}\n\nGiven a name in some scope, the collection of all declarations for that name\nis called its \\emph{overload set}.\n\n\n\\subsubsection{Scope}\n\\label{sec:intro:general-notion:scope}\nA \\emph{scope} is a sequence of declarations. This notion is much more\ngeneral than that of Standard C++.  Obviously, the set of all declarations in\na given region is a scope.  So is the union of the results of looking a name\nin a collection of regions.  That notion sets an elegant way to\naccount for the base classes in a class definition or the enumerators in\nan enumeration definition.  Consider the following declarations:\n\\begin{center}\n  \\begin{minipage}[t]{6cm}\n    \\centering{C++}\n    \\begin{Program}\nstruct ios \\{\n  enum flags \\{\n    boolapha, dec, fixed,\n    // ...\n  \\};\n  // ...\n\\};\n\nstruct istream : virtual ios \\{\n  // ...\n\\};\n\nstruct ostream : virtual ios \\{\n  // ...\n\\};\n\nstruct stream : istream,\n                ostream \\{\n  // ...\n\\};\n    \\end{Program}\n  \\end{minipage}\\hfil \\vrule \\hfil\n  \\begin{minipage}[t]{6cm}\n    \\centering{XPR}\n    \\begin{Program}\nios :class \\{\n  flags :enum \\{\n    boolapha, dec, fixed,\n    // ...\n  \\};\n  // ...\n\\};\n\nistream :class (ios public virtual) \\{\n  // ...\n\\};\n\nostream :class (ios public virtual) \\{\n  // ...\n\\};\n\nstream :class (istream public,\n               ostream public) \\{\n  // ...\n\\};\n    \\end{Program}\n  \\end{minipage}\n\\end{center}\n\nThe sequence of declarations for \\texttt{ios}, \\texttt{istream},\n\\texttt{ostream} and \\texttt{stream}, appearing at toplevel, forms a scope.\nSo is the sequence of enumerators \\texttt{ios::booalpha}, \\texttt{ios::dec},\n\\texttt{ios::fixed}, ...  since they are for \\emph{emplicitly declared}\nnamed constants.  Similarly, the sequence of the base classes\n\\texttt{istream} and \\texttt{ostream} of class \\texttt{stream} is  a scope.\nIt is the sequence of \\emph{implicitly declared} subjects with the\n\\texttt{public} declaration specifier.  Finally, the declaration for classes\n\\texttt{istream} and \\texttt{ostream} says that their base scopes consist in\na single (implicit) declaration with specifiers \\texttt{public} and\n\\texttt{virtual}.\n\n\n%% A scope also supports the operation of lookup by name.  The result of that\n%% operation usually is a set of declarations that can be partitionned into \n%% subsets of declarations that specify the same type for the looked-up name.\n%% Those subsets are called \\emph{decl-sets}.  The collection of the decl-sets is \n%% known as \\emph{overload-set},  discussed in\n%% \\secref{sec:general-notion:overload-set}.  \n\n\n%% \\subsubsection{Overload set}\n%% \\label{sec:general-notion:overload-set}\n%% In general, the result of looking up a name in a given scope\n%% (\\secref{sec:intro:general-notion:scope}) is a set of \n%% declarations, called the \\emph{overload set} of that name in that scope.\n%% %(Note: an overload set is something that grows up as the scope is being filled\n%% %with declarations).\n%% Members of an overload set are distinguished by their types\n%% (\\secref{sec:intro:general-notion:type}).  So, an overload set supports lookup\n%% by types, in the same way a scope supports lookup by name.  The result\n%% os subscripting an overload-set by a type is a declaration.\n%% %is the master declaration.  \n%% \\begin{note} Mention master declaration, secondary declaration and\n%%   relationship between them. \\end{note}\n\n%% \\subsubsection{Sequence}\n%% \\label{sec:intro:general-notion:sequence}\n%% A \\emph{sequence} is a map $I\\longrightarrow T$ where the domain $I$ is a\n%% subset of set of integers $\\mathds{N}$.  Sequences considered in IPR have\n%% bounded domains.  Therefore, when we speak of a sequence it is implicitly\n%% understood to have a bounded domain. The cardinal of the domain of a sequence\n%% is its \\emph{size}.  A sequence $I\\stackrel{\\Sigma}{\\longrightarrow} T$ of\n%% size $n$ can be, canonically, decomposed into a chain of two maps\n%% $I\\stackrel{\\nu}{\\longrightarrow} [0,n)\\longrightarrow T$ where the map $\\nu$,\n%% a numbering of the domain, is an increasing function.\n\n\n%% \\subsubsection{Iterator}\n%% \\label{sec:intro:general-notion:iterator}\n%% An \\emph{iterator} is a pair of a sequence and an integer called\n%% \\emph{position}.  An iterator $(s, i)$ is \\emph{valid for indirection} if its\n%% position $i$ is in the range of the numbering domain for $s$, \\ie{} if $i$ is\n%% nonnegative and less than the size of the sequence $s$.  The distinguished\n%% iterators $(s, 0)$ and $(s, \\mathit{size}(n))$ are called \\emph{first} and\n%% \\emph{one-past-the-end} iterators, respectively. \n\n\n\n%% \\subsection{Unified type nodes}\n%% \\label{sec:into.type.unified}\n\n%% IPR represents C++ programs as set of graphs and offers an abstract interfaces\n%% and non-mutating operations on the nodes (see \\secref{sec:interface-classes}).\n%% Eevry node is constructed out of essential expressions, necessary to set up\n%% its invariants.   For example, an \\NodeClass{Identifier} node is constructed\n%% out of the string that denotes the spelling of the identifier.  That string is\n%% necessary and sufficient to determine whether two identifiers are the same or\n%% not. \n\n%% Consequently, IPR nodes\n\n\n%% \\subsubsection{Pros}\n\n\n%% \\subsubsection{Cons}\n\n\n\\subsection{Organization}\n\\label{sec:intro:organization}\n\nThe IPR library is organized into three header files:\n\\begin{enumerate}\n\\item The interface header file \\texttt{<ipr/interface>}.  This header defines\n  the abstract classes that serve as interface to the implementation classes.\n\n\\item The implementation header file \\texttt{<ipr/impl>}. \n  Implementations for abstract class in the interface header are found\n  there.  Their names are derived from the interface my appending the\n  suffix \\texttt{\\_impl}.\n\n\\item The input and ouput header file \\texttt{<ipr/io>}.  This header provides\n  functions for reading in memory IPR nodes externally represented in XPR\n  syntax, and  writing out IPR nodes in the XPR syntax.\n\\end{enumerate}\n\n\n\\section{Interface Classes}\n\\label{sec:interface-classes}\n\nAll classes describing the interface of IPR are \\emph{immutable} in the\nsense that they support only \\texttt{const} operations.  There is no way\nprograms using only the interface classes could alter the nodes.\n\nA class of IPR nodes is said \\emph{unified} if two nodes of that class have\nequal values if and only if they have the same identity (as nodes).  Some\nnodes naturally lead themselves to unification in the sense that they are\ncompletely determined by their types and the argument list used to create\nthem.  Examples of such nodes are those that represent pointer-types,\nreference-types or identifiers.  Other nodes, such as sequences, are first\ncreated then ``filled up''.  Unification for such nodes involves some degree\nof structural equality.  \n\nAs stated in the introductory section of this paper, most of the IPR notions\nare driven by the representation of declarations, with full type information.  \nDeclarations involve types and expressions (as initializers).  C++ expressions\nshare similarity with C++ types in the sense that most of them are obtained as\nthe result of sub-components compositions through unary, binary or ternary \noperators.  That observation is at the basis of the decision of viewing most\nC++ entities as \\emph{generalized expressions}, or simply expressions when the\ncontext is clear.  In particular, types, statements and declarations are\ngeneralized expressions. \n\n\n\\subsection{Structural interfaces}\n\\label{sec:interface:structure}\n\nAs observed above, there is a high degree of common structures between\nexpressions, types and statements.  Those commonality are captured in form of \nunary, binary or ternary expressions, and rendered as the following\ninterfaceo templates:\n\\begin{Program}\n         // -- Unary<> --\n   template<class Cat = Expr, class Operand = Expr>\n   struct Unary : Cat \\{\n      typedef Operand Arg_type;\n      virtual const Operand& operand() const = 0;\n   \\};\n\n         // -- Binary<> --\n   template<class Cat = Expr, class First = Expr, class Second = Expr>\n   struct Binary : Cat \\{\n      typedef First Arg1_type;\n      typedef Second Arg2_type;\n      virtual const First& first() const = 0;\n      virtual const Second& second() const = 0;\n   \\};\n\n         // -- Ternary<> --\n   template<class Cat = Expr, class First = Expr,\n            class Second = Expr, class Third = Expr>\n   struct Ternary : Cat \\{ \n      typedef First Arg1_type;\n      typedef Second Arg2_type;\n      typedef Third Arg3_type;\n      virtual const First& first() const = 0;\n      virtual const Second& second() const = 0;\n      virtual const Third& third() const = 0;\n   \\};\n\\end{Program}\n\nThe first template parameter \\code{Cat} indicates the kind of major categories\n(e.g. plain nodes, expressions, statements or declarations) the node is a\nmember of.  The remaning template parameters indicate the type if\nsub-components.   The actual node interfaces will define forwarding functions\n(with more meaningful names) to the generic selectors.\n\n\\subsection{Universal base class for nodes}\n\\label{sec:interface:node}\n\\begin{figure}[htbp]\n  \\leavevmode\n  \\centering\n  \\begin{xy}\n    \\xymatrix @W=4pc @H=1pc @R=0pc @*[F-]{%\n      *=<4pc,1pc>[F-]{\\xyrel{Node}} & *{} & *{} \\\\\n      *=<4pc,1pc>[F-]{\\xycst{node\\_id}}\\\\ \n      *=<4pc,1pc>[F-]{\\xylabel{accept}}\\\\ \n    }\n  \\end{xy}\n  \\caption{The \\cat{Node} interface}\n  \\label{fig:node.struct}\n\\end{figure}\n\nC++ programs are represented in IPR as graphs, the nodes of which denote\n(generalizations of) C++ constructs.  Any notion directly represented in IPR\nis so as an object of class derived (either directly or indirectly) from class\n\\texttt{Node}.  An informal definition of a \\texttt{Node} is anything \nof potential interest while traversing graphs of program fragments\n(through the Visitor Design Pattern~\\cite{gamma}).  This class is the root\nof the IPR class hierarchies.\n\\begin{Program}\n  struct Node \\{\n      const int node_id;\n      Node();\n     virtual void accept(Visitor&) const = 0;\n  \\};\n\\end{Program}\n\nEvery node in the IPR representation has a unique identifier (an integer\nvalue) assigned to it at its creation.  That identifier value is given by\nthe member \\code{Node::node\\_id}.  An alternative would have been to use \nthe node's address as its unique identifier, but using an identifier\nindependent of \nthe address space provides good support for persistency.  It also means that\nwe can store nodes in associative containers and use their identifiers as\nkeys, at a relatively efficient and portable fashion.\n\n\n\\subsection{Comments in programs}\n\\label{sec:interface:comment}\n\\begin{figure}[htbp]\n  \\leavevmode\n  \\centering\n  \\begin{xy}\n    \\xymatrix @W=4pc @H=1pc @R=0pc @*[F-]{%\n      *=<4pc,1pc>[F-]{\\xyrel{Comment}} & *{} & *{} \\\\\n      *=<4pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{text}} [rr]\n      \\restore \n      & *{} &\n      *=<7pc,1pc>{\\txt{\\cat{std::string}}}\n    }\n  \\end{xy}\n  \\caption{The \\cat{Comment} interface}\n  \\label{fig:comment.struct}\n\\end{figure}\n\nA comment in C++ programs (be they written in C- or BCPL-style) are\nrepresented as unary node, the operand of which is the character stream that\nmakes the comment:\n\\begin{Program}\n   struct Comment : Unary<Node, std::string> \\{\n      const std::string& text() const \\{ return operand(); \\}\n   \\};\n\\end{Program}\n\n\\subsection{Annotations}\n\\label{sec:interface:annotations}\n\\begin{figure}[htbp]\n  \\leavevmode\n  \\centering\n  \\begin{xy}\n    \\xymatrix @W=5pc @H=1pc @R=0pc @*[F-] {%\n      *=<5pc,1pc>[F-]{\\xyrel{Annotation}} & *{} & *{} \\\\\n      *=<5pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{name}} [rr]\n      \\restore \n      & *{} &\n      *=<7pc,1pc>{\\txt{\\cat{std::string}}} \\\\\n      *=<5pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{value}} [rr]\n      \\restore \n      & *{} &\n      *=<5pc,1pc>{\\txt{\\cat{Literal}}}\n    }\n  \\end{xy}\n  \\caption{\\cat{Annotation} interface}\n  \\label{fig:annotation.struct}\n\\end{figure}\n\nThe external and internal representations of C++ programs allow for \nannotations on statements.  Annotations mostly represent informations \nnot understood by IPR.  They are pairs of identifier and literal.\n\\begin{Program}\n   struct Annotation : Binary<Node, std::string, Literal> \\{\n      const std::string& name() const \\{ return first(); \\}\n      const Literal& value() const    \\{ return second(); \\}\n   \\};\n\\end{Program}\n\nThe exact interpretation of an annotation is dependent on the tool\nthat uses the IPR library.  Only statements (and therefore declarations) \ncan be directly annotated.\n\n\n\\subsection{Regions of program text}\n\\label{sec:interface:region}\n\nDeclarations appear inside regions of program texts.  Regions contribute to\ndetermine validity of name use, objects lifetime, and lexical\ncharacterizations of program fragments.  Regions nest.  Consequently, every\nregion but the global has a parent region.\n\\begin{Program}\n   struct Region : Node \\{\n      typedef std::pair<Unit_location, Unit_location> Location_span;\n      virtual const Location_span& span() const = 0;\n      virtual const Region& enclosing() const = 0;\n      virtual const Scope& bindings() const = 0;\n      virtual const Expr& owner() const = 0;\n   \\};\n\\end{Program}\nRegions can be delimitated so that they correspond to lexical extent of\nfunction or class definitions.  A region has an owner, \\ie{} C++ entities they\nare attached to.  Finally, all declarations appearing in a given region form a\nscope, available through  \\xyiprop{Region::bindings}.\n\\begin{figure}[htbp]\n  \\leavevmode\n  \\centering\n  \\begin{xy}\n    \\xymatrix @W=4pc @H=1.5pc @R=0pc @*[F-] {%\n      *=<4pc,1.5pc>[F-]{\\xyrel{Region}} & *{} & *{} \\\\\n      *=<4pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{span}} [rr]\n      \\restore \n      & *{} &\n      *=<7pc,1pc>{\\txt{\\cat{Location\\_span}}} \\\\\n      *=<4pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{enclosing}} [rr]\n      \\restore \n      & *{} &\n      *=<4pc,1pc>{\\txt{\\cat{Region}}}\\\\\n      *=<4pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{bindings}} [rr]\n      \\restore \n      & *{} &\n      *=<4pc,1pc>{\\txt{\\cat{Scope}}}\\\\\n      *=<4pc,1pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{owner}} [rr]\n      \\restore \n      & *{} &\n      *=<4pc,1pc>{\\txt{\\cat{Expr}}}\n    }\n  \\end{xy}\n  \\caption{\\cat{Region} interface}\n  \\label{fig:region.struct}\n\\end{figure}\n\n\n\\subsection{Program unit}\n\\label{sec:interface:unit}\n\nA unit is the sequence of toplevel declarations in a transltaion or\ninstantiation unit.\n\\begin{Program}\n   struct Unit : Node \\{\n      virtual const Namespace& global_namespace() const = 0;\n      virtual const Type& Void() const = 0;\n      virtual const Type& Bool() const = 0;\n      virtual const Type& Char() const = 0;\n      virtual const Type& Signed_char() const = 0;\n      virtual const Type& Unsigned_char() const = 0;\n      virtual const Type& Wchar_t() const = 0;\n      virtual const Type& Short() const = 0;\n      virtual const Type& Unsigned_short() const = 0;\n      virtual const Type& Int() const = 0;\n      virtual const Type& Unsigned_int() const = 0;\n      virtual const Type& Long() const = 0;\n      virtual const Type& Unsigned_long() const = 0;\n      virtual const Type& Long_long() const = 0;\n      virtual const Type& Unsigned_long_long() const = 0;\n      virtual const Type& Float() const = 0;\n      virtual const Type& Double() const = 0;\n      virtual const Type& Long_double() const = 0;\n      virtual const Expr& null_expr() const = 0;\n   \\};\n\\end{Program}\nIt provides access to C++ fundamental types.\n\n\n\\subsection{Generalized expressions}\n\\label{sec:interface:expr}\n\nAs explained earlier, most C++ notions are represented in IPR as generalized\nexpressions.  All IPR expressions are typed. For instance, a declatarion\n\\begin{Program}\n   struct Expr : Node \\{\n      virtual const Type& type() const = 0;\n   \\};\n\\end{Program}\nobviously has a type (which is the type specified in the declaration).  In\nparticular, a template declaration has a type (as opposed to Standard C++).\nA type in turn has a type, as explained previously.\n\n\\subsection{Overload sets}\n\\label{sec:interface:overload}\n \nThe result of looking up the totallity of declarations for a name in a given\nscope is an overload set.  An overload set is further partitioned into subsets\nof declarations or redeclarations with same type.\n\\begin{Program}\n   struct Overload : Sequence<Decl>, Expr \\{\n      using Sequence<Decl>::operator[];\n      virtual const Sequence<Decl>& operator[](const Type&) const = 0;\n   \\};\n\\end{Program}\nAn overload set is an expression, therefore has a type.  The type of an\noverload set is a Product type, that accounts for the types of all master\ndeclarations.  \n\nSelecting a particular member of an overload set, based on its type is\nsupported through the subscription-by-type operation.  The result of that\noperation is the master declaration with that type. \n\n\\subsection{Interface for scopes}\n\\label{sec:interface:scope}\n\nThere is only one interface class, \\texttt{Scope}, that represents the variety\nof scopes available in a C++ programs (function scope, function prototype\nscope, local scope, class scope, namespace scope). \n\n\nThe following are general operations supported by all scope nodes.\n\\begin{description}\n\\item[\\texttt{const Type\\& owner(const Scope scope\\&)}]\n  Returns a \\const{} reference to the \\texttt{Type} that defines\n  \\texttt{scope}.  Any scope is  associated with a given type for which it\n  represents the sequence of associated members or values.\n\n\\item[\\texttt{Scope::operator[](const Name\\& name) const}] \n  Returns a \\const{} reference to an \\texttt{Overload} that contains all\n  the master declarations of \\texttt{name} (in the calling \\texttt{Scope}\n  object). \n  This set has null size if no declaration is found. The name look up\n  considered here is the \\emph{lexical} name lookup. \n\\end{description}\n\n\\texttt{Scope}s are visitable, they have an \\texttt{accept()} member function\nthat takes a reference to any vistor whose type derives from\n\n\\subsection{Naming entities}\n\n\\subsubsection{\\texttt{Identifier}}\n\\label{sec:interface:identifier}\nAn \\emph{identifier} in IPR is anything that Standard C++ defines as\nidentifier, although the IPR library does not make any special enforcement. \n%% \\begin{displaymath}\n%%   \\xyrel{Identifier}: \\cat{Alphanumeric}\\longrightarrow\\cat{Identifier}.\n%% \\end{displaymath}\nThe string that serves to construct an \\cat{Identifier} is given by the\noperation \\iprop{string()}:\n%% \\begin{displaymath}\n%%   \\forall s \\in\\cat{Alphanumeric}\\qquad\n%%   \\iprop{string}\\of{\\xyrel{Identifier}\\of{s}} = s.\n%% \\end{displaymath}\n\nIdentifiers are expressions, and do belong to a given category.  That category\nis the value of the operation \\iprop{type()}.  Since interpretations of\nidentifiers depend on the context of use, the type of an identifier is a\n\\cat{Decltype} whose operand is the identifier in question.\n\\begin{figure}[htbp]\n  \\leavevmode\n  \\centering\n  \\begin{xy}\n    \\xymatrix @W=5pc @H=1pc @R=0pc @*[F-] {%\n      {\\xyrel{Identifier}} & *{} &\n      {\\xyrel{Delctype}} \\\\\n      *+<5pc,2pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{type}} [rr]\n      \\restore \n      & *{} &\n      *+<5pc,2pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar`r[u] +/r4pc/^{\\xylabel{expr}} \n      `[u] +/u2pc/\n      `[ll][llu]\n      \\restore\n      \\\\\n      *+<5pc,2pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{string}} [rr]\n      \\restore \n      & *{} &\n      *+=<5pc,2pc>[F-:<4pt>]{\\txt{\\cat{std::string}}}\n    }\n  \\end{xy}\n  \\caption{\\cat{Identifier} interface}\n  \\label{fig:identifier.struct}\n\\end{figure}\nThe IPR interface to the category \\cat{Identifier} of identifiers is\nimplemented by the class \\code{Identifier}:\n\\begin{Program}\n   struct Identifier : Unary<Name, std::string> \\{\n      const std::string& string() const \\{ return operand(); \\}\n   \\};\n\\end{Program}\n\n\\subsubsection{\\texttt{Operator}}\n\\label{sec:interface:operator}\nAn IPR \\emph{operator name} is any Standard C++ operator name of the form\n\\code{operator @}, where \\code{@} is a member of \\cat{OperatorName} (see\ntable ???).   \n%% \\begin{displaymath}\n%%   \\xyrel{Operator}:\\cat{OperatorName}\\longrightarrow\\cat{Operator}.\n%% \\end{displaymath}\nSimilar to an \\cat{Identifier}, the string that served to construct\nan \\cat{Operator} is given by the operation \\iprop{opname}:\n%% \\begin{displaymath}\n%%   \\forall s \\in\\cat{OperatorName}\\qquad\n%%   \\iprop{opname}\\of{\\xyrel{Operator}\\of{s}} = s.\n%% \\end{displaymath}\n\nAlso, similar to an \\cat{Identifier}, an \\cat{Operator} supports the\n\\iprop{type} operation.\n\\begin{figure}[htbp]\n  \\leavevmode\n  \\centering\n  \\begin{xy}\n    \\xymatrix @W=5pc @H=1pc @R=0pc @*[F-] {%\n      {\\xyrel{Operator}} & *{} &\n      {\\xyrel{Delctype}} \\\\\n      *+<5pc,2pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{type}} [rr]\n      \\restore \n      & *{} &\n      *+<5pc,2pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar`r[u] +/r4pc/^{\\xylabel{expr}} \n      `[u] +/u2pc/\n      `[ll][llu]\n      \\restore\n      \\\\\n      *+<5pc,2pc>[F-]{\\bullet} \n      \\save\n      * {} \\ar ^{\\xylabel{opname}} [rr]\n      \\restore \n      & *{} &\n      *+=<5pc,2pc>[F-:<4pt>]{\\txt{\\cat{std::string}}}\n    }\n  \\end{xy}\n  \\caption{\\cat{Operator} interface}\n  \\label{fig:operator.struct}\n\\end{figure}\nThe value of that operation is a \\cat{Decltype} whose\noperand is the \\cat{Operator}.\nThe IPR interface to the operator name category \\cat{Operator} is implemented\nby the class \\code{Operator}:\n\\begin{Program}\n   struct Operator : Unary<Name, std::string> \\{\n      const std::string& opname() const \\{ return operand(); \\}\n   \\};\n\\end{Program}\n\n\\subsubsection{\\texttt{Conversion}}\n\\label{sec:interface:conversion}\nA \\emph{conversion} name is any name made out of \\texttt{operator} and \na type.  Given\n%% \\begin{displaymath}\n%%   \\rel{Conversion}:\\cat{Type}\\longrightarrow\\cat{Name}\n%% \\end{displaymath}\nthe following holds:\n%% \\begin{displaymath}\n%%   \\forall t\\in\\cat{Type}\\qquad\n%%   \\mathit{target}\\of{\\rel{Conversion}\\of{t}} = t.\n%% \\end{displaymath}\n\n\nThe IPR interface to \\cat{Conversion} is\n\\begin{Program}\n   struct Conversion : Unary<Name, Type> \\{\n      const Type& target() const \\{ return operand(); \\}\n   \\};\n\\end{Program}\n\\begin{description}\n\\item[\\texttt{Conversion::target() const}] The type this conversion function\n  converts to. \n\\end{description}\n\n\\subsection{Expressions}\n\nNearly everyting is an expression in IPR.  An \\emph{expression} is understood\nas the specification of an operator and arguments for a computation.  The\noperator need not be alsways explicitly spelled out.\n\nThe various categories of expressions are described in detail in subsequent\nsections.  The interface to this notion is given by\n\\begin{Program}\n   struct Expr : Node \\{\n      virtual const Type& type() const = 0;\n   \\};\n\\end{Program}\nThus, every expression node supports the \\texttt{type()} and\n\\texttt{annotation()} operations:\n\\begin{description}\n\\item[\\texttt{Expr::type() const}] The IPR node that represent the type of\n  this expression.\n\\item[\\texttt{Expr::annotation() const}] The sequence of annotations made to\n  this expression.\n\\end{description}\n\n\n\n\\subsection{Literals}\n\n%% \\begin{displaymath}\n%%   \\rel{Literal} : \\cat{String} \\times \\cat{Type} \\longrightarrow\n%%   \\cat{Expr}\n%% \\end{displaymath}\n\n%% \\begin{align*}\n%%   \\forall s\\in\\cat{String},\\, \\forall t\\in\\cat{Type}\\qquad\n%%   &\\mathit{string}\\of{\\rel{Literal}\\of{s,\\, t}} = s\\\\\n%%   &\\mathit{type}\\of{\\rel{Literal}\\of{s,\\, t}} = t\n%% \\end{align*}\n\n\\begin{Program}\n   struct Literal : Binary<Expr, Type, std::string> \\{\n      const Type& type() const \\{ return first(); \\}\n      const std::string& string() const \\{ return second(); \\}\n   \\};\n\\end{Program}\n\n\\begin{description}\n\\item[\\texttt{Literal::string()}] \n\\end{description}\n\n\\subsection{Types in IPR}\n\\label{sec:interface:types}\n\nThe variety of C++ types are represented in IPR.  The abstract class\n\\texttt{Type} serves as a base class of that hierarchy.  A type in IPR is a\ngeneralized expression, and therefore derives from the abstract class\n\\texttt{Expr}.\n\n\\subsubsection{Reference type}\n%% \\begin{gather*}\n%%   \\rel{Reference} : \\cat{Type} \\longrightarrow \\cat{Type}\\\\\n%%   \\forall t\\in\\cat{Type}\\qquad\n%%   \\mathit{refers\\_to}\\of{\\rel{Reference}\\of{t}} = t\n%% \\end{gather*}\n\n\\begin{Program}\n  struct Reference : Unary<Type, Type> \\{\n    const Type& refers_to() const \\{ return operand(); \\}\n  \\};\n\\end{Program}\n\n\n\\subsubsection{Function type}\n%% \\begin{displaymath}\n%%   \\rel{Function} : \\cat{Signature} \\times \\cat{Type} \\times\n%%   \\cat{Sequence_{Type}} \\longrightarrow \\cat{Type}\n%% \\end{displaymath}\n%% \\begin{align*}\n%%   \\forall s\\in \\cat{Signature},\\, \\forall t\\in\\cat{Type},\\,\n%%   \\forall e\\in\\cat{Sequence_{Type}}\\qquad\n%%   &\\mathit{signature}\\of{\\rel{Function}\\of{s,\\, t,\\, e}} = s\\\\\n%%   &\\mathit{target}\\of{\\rel{Function}\\of{s,\\, t,\\, e}} = t\\\\\n%%   &\\mathit{throws}\\of{\\rel{Function}\\of{s,\\, t,\\, e}} = e\\\\\n%% \\end{align*}\n\n\\begin{Program}\n   struct Function : Ternary<Type, Product, Type, Type> \\{\n      const Product& signature() const \\{ return first(); \\}\n      const Type& target() const \\{ return second(); \\}\n      const Type& throws() const \\{ return third(); \\}\n   \\};\n\\end{Program}\n\n\\begin{description}\n\\item[\\texttt{Function::signature() const}] \n\\item[\\texttt{Function::target() const}] \n\\item[\\texttt{Function::throws() const}] \n\\end{description}\n\n\n\\subsubsection{Pointer type}\n%% \\begin{gather*}\n%%   \\rel{Pointer} : \\cat{Type} \\longrightarrow \\cat{Type}\\\\\n%%   \\forall t\\in \\cat{Type}\\qquad\n%%   \\mathit{points\\_to}\\of{\\rel{Pointer}\\of{t}} = t\n%% \\end{gather*}\n\n\\begin{Program}\n   struct Pointer : Unary<Type, Type> \\{\n      const Type& points_to() const \\{ return operand(); \\}\n   \\};\n\\end{Program}\n\\begin{description}\n\\item[\\texttt{Pointer::points\\_to() const}] \n\\end{description}\n\n\n\\subsubsection{Array type}\n%% \\begin{gather*}\n%%   \\rel{Array} : \\cat{Object\\_type}\\times\\cat{Expr}\n%%   \\longrightarrow \\cat{Object\\_type}\\\\\n%%   \\forall t\\in\\cat{Object\\_type},\\,\\forall b\\in\\cat{Expr}\\\\\n%%   \\mathit{element\\_type}\\of{\\rel{Array}\\of{t,\\, b}} = t\\\\\n%%   \\mathit{bound}\\of{\\rel{Array}\\of{t,\\, b}} = b\\\\\n%% \\end{gather*}\n\n\\begin{Program}\n   struct Array : Binary<Type, Type, Expr> \\{\n      const Type& element_type() const \\{ return first(); \\}\n      const Expr& bound() const        \\{ return second(); \\}\n   \\};\n\\end{Program}\n\n\\begin{description}\n\\item[\\texttt{Array::element\\_type() const}] \n\\item[\\texttt{Array::bound() const}] \n\\end{description}\n\n\\subsubsection{User-defined types}\n%% \\begin{gather*}\n%%   \\rel{Udt} : \\cat{String}\\times \\cat{Scope} \\times \\cat{Scope}\n%%   \\longrightarrow \\cat{Type}\\\\\n%%   \\rel{Class} = \n%%   \\rel{Udt}\\of{\\rel{Class},\\, \\bullet,\\,\\bullet}\\\\\n%%   \\rel{Union} = \n%%   \\rel{Udt}\\of{\\rel{Union},\\, \\bullet,\\,\\bullet}\\\\\n%%   \\rel{Enum} = \n%%   \\rel{Udt}\\of{\\rel{Enum},\\, \\bullet,\\,\\bullet}\\\\\n%%   \\rel{Namespace} = \n%%   \\rel{Udt}\\of{\\rel{Namespace},\\, \\bullet,\\,\\bullet}\\\\\n%% \\end{gather*}\n\n%% \\begin{align*}\n%%   \\forall b\\in\\cat{Scope},\\,\\forall m\\in\\cat{Scope}\\qquad\n%%   &\\mathit{bases}\\of{\\rel{User\\_defined\\_type}\\of{\\bullet,\\, b, m}} = b\\\\\n%%   &\\mathit{members}\\of{\\rel{User\\_defined\\_type}\\of{\\bullet,\\, b, m}} = m\\\\\n%% \\end{align*}\n\n\\begin{Program}\n   struct Udt : Type \\{\n      virtual const Scope& scope() const = 0;\n   \\};\n  \n   struct Namespace : Udt \\{\n      const Sequence<Decl>& members() const \\{ return scope().members(); \\}\n   \\};\n\n   struct Class : Udt \\{\n      const Sequence<Decl>& members() const \\{ return scope().members(); \\}\n      virtual const Sequence<Base_type>& bases() const = 0;\n      virtual const Scope& base_scope() const = 0;\n   \\};\n\n   struct Union : Udt \\{\n      const Sequence<Decl>& members() const \\{ return scope().members(); \\}\n   \\};\n\n   struct Enum : Udt \\{\n      virtual const Sequence<Enumerator>& members() const = 0;\n   \\};\n\\end{Program}\n\n\n\\subsection{Unary expressions}\n\\label{sec:interface:unary-expr}\n\n\\subsubsection{Incrementation}\n%% \\begin{gather*}\n%%   \\rel{Pre\\_increment}:\\cat{Expr}\\longrightarrow\\cat{Expr}\\\\\n%%   \\rel{Post\\_increment}:\\cat{Expr}\\longrightarrow\\cat{Expr}\n%% \\end{gather*}\n\n\\subsubsection{Decrementation}\n%% \\begin{gather*}\n%%   \\rel{Pre\\_decrement}:\\cat{Expr}\\longrightarrow\\cat{Expr}\\\\\n%%   \\rel{Post\\_decrement}:\\cat{Expr}\\longrightarrow\\cat{Expr}\n%% \\end{gather*}\n\n\\subsubsection{Conversions}\n%% \\begin{gather*}\n%%   \\rel{Dynamic\\_cast}:\\cat{Expr}\\times\\cat{Type}\\longrightarrow\\cat{Expr}\\\\\n%%   \\rel{Static\\_cast}:\\cat{Expr}\\times\\cat{Type}\\longrightarrow\\cat{Expr}\\\\\n%%   \\rel{Reinterpret\\_cast}:\\cat{Expr}\\times\\cat{Type}\n%%   \\longrightarrow\\cat{Expr}\\\\\n%%   \\rel{Const\\_cast}:\\cat{Expr}\\times\\cat{Type}\\longrightarrow\\cat{Expr}\\\\\n%%   \\rel{Cast}:\\cat{Expr}\\times\\cat{Type}\\longrightarrow\\cat{Expr}\n%% \\end{gather*}\n\n\\subsubsection{Type identification}\n\nA type identification comes in two flavors\n%% \\begin{gather*}\n%%   \\rel{Expr\\_typeid} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Type\\_typeid} : \\cat{Type} \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\n\\subsubsection{Size of object representation}\n%% \\begin{gather*}\n%%   \\rel{Expr\\_sizeof} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Type\\_sizeof} : \\cat{Type} \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\n\\subsubsection{Dereferencing}\n%% \\begin{displaymath}\n%%   \\rel{Deref}: \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\subsubsection{Taking the address of an object}\n%% \\begin{displaymath}\n%%   \\rel{Address} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\subsubsection{Unary plus}\n%% \\begin{displaymath}\n%%   \\rel{Unary\\_plus} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\subsubsection{Negation}\n%% \\begin{gather*}\n%%   \\rel{Negate} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Not} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\n\\subsubsection{Complement}\n%% \\begin{displaymath}\n%%   \\rel{Complement} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\n\\subsubsection{Deletion}\n%% \\begin{gather*}\n%%   \\rel{Delete} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Array\\_delete} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\\subsection{Binary expressions}\n\\label{sec:interface:binary-expr}\n\n\\subsubsection{Multiplicative expressions}\n%% \\begin{gather*}\n%%   \\rel{Mul} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Div} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Modulo} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%% \\end{gather*}\n\n\\subsubsection{Additive expressions}\n%% \\begin{gather*}\n%%   \\rel{Add} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Sub} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%% \\end{gather*}\n\n\n\\subsubsection{Logical expressions}\n%% \\begin{gather*}\n%%   \\rel{Less} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Greater} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Equal} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Less\\_equal} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Greater\\_equal} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Not\\_equal} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{And} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Or} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%% \\end{gather*}\n\n\n\\subsubsection{Bits arithmetic}\n%% \\begin{gather*}\n%%   \\rel{Bit\\_and} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Bit\\_xor} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Bit\\_or} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Shift\\_left} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Shift\\_right} : \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\\subsubsection{Member selection}\n%% \\begin{gather*}\n%%   \\rel{Dot\\_select} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Dot\\_star} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Arrow\\_select} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Arrow\\_star} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Scope\\_select} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\\\\\n%% \\end{gather*}\n\n\\subsubsection{Expression sequencing}\n%% \\begin{displaymath}\n%%   \\rel{Comma} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\subsubsection{Assignment}\n%% \\begin{displaymath}\n%%   \\rel{Assign} : \\cat{Expr} \\times \\cat{Expr} \n%%   \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\n\\subsection{Expressions with variable number of arguments}\n\\label{sec:interface:var-args-expr}\n\n\\subsubsection{Function call}\n%% \\begin{displaymath}\n%%   \\rel{Call} : \\cat{Expr} \\times \\cat{Sequence} \n%%   \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\n\\subsubsection{Data construction}\n%% \\begin{displaymath}\n%%   \\rel{Object\\_construction} : \\cat{Type} \\times \\cat{Sequence}\n%%   \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\n\n\\subsection{Statements}\n\n\\subsubsection{Labeled statements}\n\n%% \\begin{displaymath}\n%%   \\rel{Labeled\\_stmt} : \\cat{Expr}\\times\\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\n\\subsubsection{Expression statements}\n\n\\begin{Program}\n   struct Expr_stmt : Stmt \\{\n      virtual const Expr& expr() const = 0;\n   \\};\n\\end{Program}\n\n\\begin{Program}\n   struct Labeled_stmt : Stmt \\{\n      virtual const Expr& label() const = 0;\n      virtual const Expr& stmt() const = 0;\n   \\};\n\\end{Program}\n\n\\subsubsection{Blocks}\n\n%% \\begin{displaymath}\n%%   \\rel{Block} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\begin{Program}\n   struct Block : Stmt \\{\n      virtual const Scope& members() const = 0;\n      virtual const Sequence<Expr>& stmts() const = 0;\n      virtual const Sequence<Handler>& handlers() const = 0;\n   \\};\n\\end{Program}\n\n\\subsubsection{Ctor bodies}\n\n%% \\begin{displaymath}\n%%   \\rel{Function\\_body} : \\cat{Sequence_{Expr}} \\times\n%%   \\cat{Block} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\begin{Program}\n   struct Ctor_body : Stmt \\{\n      virtual const Expr_list& inits() const = 0;\n      virtual const Block& block() const = 0;\n   \\};\n\\end{Program}\n\n\\subsubsection{Selection statements}\n\n%% \\begin{gather*}\n%%   \\rel{If\\_then} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{If\\_then\\_else} : \\cat{Expr} \\times \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\\begin{Program}\n   struct If_then : Stmt \\{\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& then_stmt() const = 0;\n   \\};\n  \n   struct If_then_else : Stmt \\{\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& then_stmt() const = 0;\n      virtual const Expr& else_stmt() const = 0;\n   \\};\n\\end{Program}\n\n%% \\begin{displaymath}\n%%   \\rel{Switch} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{displaymath}\n\n\\begin{Program}\n   struct Switch : Stmt {\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& body() const = 0;\n   };\n\\end{Program}\n\n\n\\subsubsection{Iteration iterations}\n\n%% \\begin{gather*}\n%%   \\rel{While} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Do} : \\cat{Expr} \\times \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{For} : \\cat{Expr} \\times \\cat{Expr} \\times \\cat{Expr} \\times \\cat{Expr}\n%%   \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\\begin{Program}\n   struct While : Stmt \\{\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& body() const = 0;\n   \\};\n  \n   struct Do : Stmt \\{\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& body() const = 0;\n   \\};\n\n   struct For : Stmt \\{\n      virtual const Expr& initializer() const = 0;\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& increment() const = 0;\n      virtual const Expr& body() const = 0;\n   \\};\n\\end{Program}\n\n\n\\subsubsection{Jump statements}\n\n%% \\begin{gather*}\n%%   \\rel{Break} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Continue} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Goto} : \\cat{Expr} \\longrightarrow \\cat{Expr}\\\\\n%%   \\rel{Return} : \\cat{Expr} \\longrightarrow \\cat{Expr}\n%% \\end{gather*}\n\n\\begin{Program}\n   struct Break : Stmt \\{\n      virtual const Expr& from() const = 0;\n   \\};\n  \n   struct Continue : Stmt \\{\n      virtual const Expr& iteration() const = 0;\n   \\};\n\n   struct Goto: Stmt \\{\n      virtual const Expr& target() const = 0;\n   \\};\n\n   struct Return : Stmt \\{\n      virtual const Expr& value() const = 0;\n      const Type& type() const  { return value().type(); }\n   \\};\n\\end{Program}\n\n\n\\subsubsection{Exception handlers}\n\n\\begin{Program}\n   struct Handler : Stmt \\{\n      virtual const Decl& exception() const = 0;\n      virtual const Block& body() const = 0;\n   \\};\n\\end{Program}\n\n\\subsection{Declarations}\n\n\\begin{Program}\n   struct Decl : Stmt \\{\n      enum Specifier \\{\n         None = 0,\n         Auto       = 1 << 0,\n         Register   = 1 << 1,\n         Static     = 1 << 2,\n         Extern     = 1 << 3,\n         Mutable    = 1 << 4,\n         StorageClass  = Auto | Register | Static | Extern | Mutable,\n\n         Inline     = 1 << 5,\n         Virtual    = 1 << 6,\n         Explicit   = 1 << 7,\n         Pure       = 1 << 8,\n         FunctionSpecifier = Inline | Virtual | Explicit | Pure,\n      \n         Friend     = 1 << 9,\n         Typedef    = 1 << 10,\n\n         Public     = 1 << 11,\n         Protected  = 1 << 12,\n         Private    = 1 << 13,\n         AccessProtection = Public | Protected | Private\n      \\};\n\n      virtual Specifier specifiers() const = 0;\n      virtual const Name& name() const = 0;\n      virtual const Scope& scope() const = 0;\n\n      virtual bool has_initializer() const = 0;\n      virtual const Expr& initializer() const = 0;\n\n      const Sequence<Decl>& decl_set() const\n      \\{ return scope()[name()][type()]; \\}\n      const Decl& master() const \\{ return *decl_set().begin(); \\}\n   \\};\n\\end{Program}\n\nA declaration is a statement. It usually introduces a name in a given scope\nand attributes for its interpretation: (a) a type; (b) a set of specifiers for\naccess or storage; and (b) an optional initializer.\n\n\\subsubsection{Declaration specifiers}\n\n\n\\paragraph{Storage class specifiers}\n\n\n\\paragraph{Function specifiers}\n\n\n\\paragraph{Access control and friendship}\n\n\n\\subsubsection{Variable declarations}\n\\begin{Program}\n   struct Var : Decl \\{\n   \\};\n\\end{Program}\n\n\n\\subsubsection{Data member declarations}\n\n\\begin{Program}\n   struct Field : Decl \\{\n   \\};\n  \n   struct Bit_field : Decl \\{\n      virtual const Expr& size() const = 0;\n   \\};\n\\end{Program}\n\n\\subsubsection{Parameter declarations}\n\\begin{Program}\n   struct Parameter : Decl \\{\n      virtual int position() const = 0;\n      const Expr& default_value() const { return initializer(); }\n   \\};\n\\end{Program}\n\n\n\\subsubsection{Function declarations}\n\n\\begin{Program}\n   struct Fun_decl : Decl \\{\n      virtual const Type& target() const = 0;\n      virtual const Parameter_list& parameters() const = 0;\n      virtual const Type& throws() const = 0;\n   \\};\n\\end{Program}\n\n\n\\paragraph{Constructors}\n\\begin{Program}\n   struct Constructor : Fun_decl \\{\n      const Name& name() const \\{ return membership().name(); \\}\n      const Type& target() const \\{ return membership(); \\}\n\n      virtual const Type& membership() const = 0;\n   \\};\n\\end{Program}\n\n\n\\paragraph{Destructors}\n\n\\begin{Program}\n   struct Destructor : Fun_decl \\{\n      virtual const Type& membership() const = 0;\n   \\};\n\\end{Program}\n\n\n\\subsubsection{Alias declarations}\n\\begin{Program}\n   struct Alias : Decl \\{\n   \\};\n\\end{Program}\n\n\n\n\\subsubsection{Base-type declarations}\n\\begin{Program}\n   struct Base_type : Decl \\{\n      const Name& name() const \\{ return type().name(); \\}\n   \\};\n\\end{Program}\n\n\n\\subsubsection{Enumerator declarations}\n\n\\begin{Program}\n   struct Enumerator : Decl \\{\n      const Type& type() const \\{ return membership(); \\}\n      virtual const Enum& membership() const = 0;\n   \\};\n\\end{Program}\n\n\n\n\\subsubsection{Type declarations}\n\n\\begin{Program}\n   struct Type_decl : Decl \\{\n   \\};\n\\end{Program}\n\n\\subsection{Traversing graphs:  Visitors}\n\\begin{Program}\n   struct Visitor \\{\n      virtual void visit(const Node&) = 0;\n      virtual void visit(const Annotation&);\n\n      virtual void visit(const Expr&) = 0;\n      \n      virtual void visit(const Name&) = 0;\n      virtual void visit(const Identifier&);\n      virtual void visit(const Operator&);\n      virtual void visit(const Conversion&);\n      virtual void visit(const Type_id&);\n\n      virtual void visit(const Type&) = 0;\n      virtual void visit(const Array&);\n      virtual void visit(const Class&);\n      virtual void visit(const Enum&);\n      virtual void visit(const Expr_as_type&);\n      virtual void visit(const Function&);\n      virtual void visit(const Namespace&);\n      virtual void visit(const Pointer&);\n      virtual void visit(const Product&);\n      virtual void visit(const Reference&);\n      virtual void visit(const Template&);\n      virtual void visit(const Union&);\n      virtual void visit(const Udt&);\n\n      virtual void visit(const Expr_list&);\n      virtual void visit(const Overload&);\n      virtual void visit(const Scope&);\n\n      virtual void visit(const Address&); \n      virtual void visit(const Array_delete&); \n      virtual void visit(const Complement&); \n      virtual void visit(const Delete&); \n      virtual void visit(const Deref&);\n      virtual void visit(const Expr_sizeof&);\n      virtual void visit(const Expr_stmt&);\n      virtual void visit(const Expr_typeid&); \n      virtual void visit(const Label&);\n      virtual void visit(const Negate&); \n      virtual void visit(const Not&); \n      virtual void visit(const Post_decrement&);\n      virtual void visit(const Post_increment&); \n      virtual void visit(const Pre_decrement&); \n      virtual void visit(const Pre_increment&); \n      virtual void visit(const Throw&);\n      virtual void visit(const Type_sizeof&); \n      virtual void visit(const Type_typeid&); \n      virtual void visit(const Unary_plus&); \n\n      virtual void visit(const Add&);\n      virtual void visit(const Add_assign&);\n      virtual void visit(const And&); \n      virtual void visit(const Array_ref&);\n      virtual void visit(const Arrow_select&); \n      virtual void visit(const Arrow_star&); \n      virtual void visit(const Assign&);\n      virtual void visit(const Bitand&);\n      virtual void visit(const Bitand_assign&);\n      virtual void visit(const Bitor&);\n      virtual void visit(const Bitor_assign&);\n      virtual void visit(const Bitxor&);\n      virtual void visit(const Bitxor_assign&);\n      virtual void visit(const C_cast&); \n      virtual void visit(const Call&); \n      virtual void visit(const Comma&);\n      virtual void visit(const Const_cast&); \n      virtual void visit(const Div&);\n      virtual void visit(const Div_assign&);\n      virtual void visit(const Dot_select&);\n      virtual void visit(const Dot_star&); \n      virtual void visit(const Dynamic_cast&); \n      virtual void visit(const Equal&); \n      virtual void visit(const Greater&); \n      virtual void visit(const Greater_equal&); \n      virtual void visit(const Less&); \n      virtual void visit(const Less_equal&); \n      virtual void visit(const Literal&);\n      virtual void visit(const Member_init&);\n      virtual void visit(const Modulo&);\n      virtual void visit(const Modulo_assign&);\n      virtual void visit(const Mul&);\n      virtual void visit(const Mul_assign&);\n      virtual void visit(const Not_equal&); \n      virtual void visit(const Object_construction&); \n      virtual void visit(const Or&); \n      virtual void visit(const Reinterpret_cast&); \n      virtual void visit(const Scope_ref&);\n      virtual void visit(const Shift_left&);\n      virtual void visit(const Shift_left_assign&);\n      virtual void visit(const Shift_right&);\n      virtual void visit(const Shift_right_assign&);\n      virtual void visit(const Specialization&);\n      virtual void visit(const Static_cast&); \n      virtual void visit(const Sub&);\n      virtual void visit(const Sub_assign&);\n\n      virtual void visit(const Conditional&);\n      virtual void visit(const New&); \n\n      virtual void visit(const Stmt&) = 0;\n      virtual void visit(const Labeled_stmt&);\n      virtual void visit(const Block&);\n      virtual void visit(const Ctor_body&);\n      virtual void visit(const If_then&);\n      virtual void visit(const If_then_else&);\n      virtual void visit(const Switch&);\n      virtual void visit(const While&);\n      virtual void visit(const Do&);\n      virtual void visit(const For&);\n      virtual void visit(const Break&);\n      virtual void visit(const Continue&);\n      virtual void visit(const Goto&);\n      virtual void visit(const Return&);\n      virtual void visit(const Handler&);\n\n      virtual void visit(const Decl&) = 0;\n      virtual void visit(const Alias&);\n      virtual void visit(const Base_type&);\n      virtual void visit(const Parameter&);\n      virtual void visit(const Parameter_list&);\n      virtual void visit(const Var&);\n      virtual void visit(const Field&);\n      virtual void visit(const Bit_field&);\n      virtual void visit(const Fun_decl&);\n      virtual void visit(const Constructor&);\n      virtual void visit(const Destructor&);\n      virtual void visit(const Type_decl&);\n   \\};\n\\end{Program}\n\n\\section{Implementation Classes}\n\\label{sec:impl}\n\nEvery abstract class in the interface class hierarchy has a corresponding\nimplementation class, named after that interface and with the suffix\n\\texttt{Impl}. Those implementations classes often supports\nnon-\\texttt{const} operations too.  Every implementation class provide \nan overriding implementation for the visitor hook \n\\texttt{Node::accept()} that transfer control to the appropriate overriding\nmember function of \\texttt{Visitor::visit()}\n\nThere is only one instance of \\texttt{std::string} for any given text string\nthat might be hold in any IPR node (e.g. by names).\n\n\n\n\n\\subsection{Implementation classes for names}\n\nThe four kinds of names \\textit{identifier}, \\textit{operator name},\n\\textit{conversion-function name}  and \\textit{template instantiation name}\nare respectively implemented by \\texttt{impl::Identifer}, \n\\texttt{impl::Operator}, \\texttt{impl::Conversion} and \n\\texttt{impl::Specialization}.  They all derive from instantiations of the \nparameterized implementation class \\texttt{impl::Name<>}.  The later\nis parameterized by the interface\n\n\\subsubsection{\\texttt{impl::Identifier}}\n\n\\subsubsection{\\texttt{impl::Operator}}\n\n\\subsubsection{\\texttt{impl::Conversion}}\n\n\\section{XPR grammars}\n\\label{sec:xpr-grammar}\n\nXPR essentially retains C++'s syntax for expressions.  The differences appear\nmainly in the declaration syntax where XPR aims for a linear notation.\n\\subsection{Lexical conventions}\n\\label{sec:xpr-grammar:lexical-convention}\n\n\n\\subsubsection{Literals}\n\nXPR retains C~\\cite{iso99} and C++~\\cite{iso03}'s spelling for literals\n\\begin{Program}\n  \n\\end{Program}\n\n\n\\bibliographystyle{amsplain}\n\\bibliography{ipr}\n\n\\end{document}\n\n%%% Local Variables: \n%%% mode: latex\n%%% TeX-master: t\n%%% End: \n"
  },
  {
    "path": "doc/user-guide.tex",
    "content": "\\documentclass[11pt]{article}\n\\usepackage[latin1]{inputenc}\n\\usepackage[T1]{fontenc}\n\\usepackage{mathrsfs}\n\\usepackage{palatino}\n\\usepackage{amsmath,amssymb}\n\\usepackage{graphics}\n\\usepackage[all]{xy}\n\\usepackage{alltt}\n\n\\input{macro}\n\n\\renewcommand{\\ttdefault}{txtt}\n\n\n\n\\title{IPR User Guide\\\\{\\normalsize (for version 0.45)}}\n\\author{Gabriel Dos~Reis}\n\n\\begin{document}\n\n\\maketitle\n\n\n\\section{Introduction}\n\\label{sec:intro}\n\nThis document is a companion to the IPR Reference \nManual~\\cite{dosreis04:ipr-ref}.  It is intended to illustrate uses of the IPR\nlibrary.\n\nThe library currently consists of three components:\n\\begin{itemize}\n\\item \\emph{the interface}, available through \\code{<ipr/interface>}.  This\n  is a collection of interfaces (\\ie{} abstract classes) that provide views and\n  non-mutating operations to manipulate IPR nodes;\n\\item \\emph{the I/O component}, available through \\code{<ipr/io>}.  This\n  header file declares functions necessary to render IPR nodes in their\n  external, persistent form according to the XPR syntax;\n\\item \\emph{the implementation classes}, available through\n  \\texttt{<ipr/impl>}.  This is a collection of types that provide\n  implementations for the interface component.  They also support mutating\n  operations necessary to build   complete IPR nodes. \n\\end{itemize}\nPrograms that use the IPR library usually include \\code{<ipr/interface>}\nwhen their only interests are non-mutating manipulations of IPR nodes.  They\nneed to include \\code{<ipr/io>} if they intend to print out IPR nodes in\nXPR syntax.  Finally, they include \\code{<ipr/impl>} if\nthey do create IPR nodes, as opposed to inspecting them.\n\n\nThe interface classes reside in the namespace \\texttt{ipr}.  The\nimplementation classes are found in the sub-namespace \\code{ipr::impl}.\nIn general, an interface \\code{ipr::Xyz} has a corresponding implementation\nnamed \\code{ipr::impl::Xyz}. \n\n\n\\section{Installation}\n\\label{sec:install}\n\n\n\n\\section{Generalities}\n\\label{sec:generalities}\n\nThe IPR library provides data structures for representing programs written in\nISO Standard C++.  Programs are represented as graphs, with distinguished\nroots called \\emph{units}.  An IPR unit roughly corresponds to a translation\nunit in C++.  In fact, IPR represents a superset of Standard C++; so it can\nhandle programs using full C++  as well as incorrect or incomplete programs. \n\nThe notion of unit is directly represented by the interface class\n\\NodeClass{Unit}. An object of that type contains the sequence of top-level\ndeclarations in a given translation unit. It also provides  access to nodes\nthat represent C++ fundamental types.  The general approach is that\nevery C++ entity has a type.  In particular C++ types, being expressions in\nIPR, do have types.  For example, the following program prints out some\nIPR expression nodes and their types.\n\\begin{Program}\n#include <ipr/impl>\n#include <ipr/io>\n#include <iostream>\n\ntemplate<class E>\nvoid inspect(const E& e)        // Print a expression and its type.\n\\{\n   ipr::Printer pp(std::cout);  // Create an XPR pretty printer\n                                // tied to std::cout.\n   pp << ipr::xpr_expr(e);      // Output e in XPR notation.\n   pp << \" has type \";\n   pp << ipr::xpr_expr(e.type()); // Output type of e in XPR notation.\n   std::cout << std::endl;\n\\}\n\nint main()\n\\{\n   using namespace ipr;\n   impl::Unit unit;             // Current translation unit\n\n   // Inspect the representations of some literals.\n   inspect(*unit.make_literal(unit.get_char(), u8\"'c'\"));\n   inspect(*unit.make_literal(unit.get_int(), u8\"1024\"));\n   inspect(*unit.make_literal(unit.get_double(), u8\"3.141592653589793\"));\n\n   // Inspect the representations of some C++ fundamental types.\n   inspect(unit.get_char());\n   inspect(unit.get_int());\n   inspect(unit.get_double());\n\\}\n\\end{Program}\n\nWhen compiled and linked against the IPR library, it produces the output\n\\begin{Output}\n'c' has type char\n1024 has type int\n3.141592653589793 has type double\nchar has type  typename\nint has type  typename\ndouble has type  typename\n\\end{Output}\n\n%% Notions like \\code{class}, \\code{enum}, \\code{union} and \\code{namespace} are\n%% types in IPR: they characterize type expressions such as class-expressions,\n%% enum-expressions, union-expression and namespace-expressions.\n\nA node of type \\NodeClass{Unit} also serves to represent the notion of \n\\emph{instantiation unit}\\footnote{See clause 2 of \\cite{iso98, iso03}}.\nRecall that typical C++ translation units contain requests for template\ninstantiations.  An instantiation unit is a translation unit where all\ntemplate instantiation requests have been resolved.\n\n\nThe next sections will focus on the part of the library typically used for\nbuilding IPR nodes.  It is meant to provide support for tools that create IPR\nnodes, \\eg{} IPR generators from compilers or XPR parsers.  All IPR\nnode construction functions return pointers; usually their names start with\nthe prefix \\code{make\\_}.  \n\nType nodes, expression nodes, and statements nodes are created with\n\\NodeClass{impl::Unit} objects.  Declarations are created with their enclosing\nregions.  They are generally represented as a triple of name, type and\noptional initializer.\n\n\n\\section{Literals}\n\\label{sec:literals}\n\nLexical units (\\eg{} names, literals) of Standard C++ are directly represented\nin IPR. This section deals with literals and the next with names.\n\nISO Standard C++ defines five sub-categories of literals:\n\\begin{Grammar}\n  \\cxxRule{literal:}\n      \\cxxRule{integer-literal}\n      \\cxxRule{character-literal}\n      \\cxxRule{floating-literal}\n      \\cxxRule{string-literal}\n      \\cxxRule{boolean-literal}\n\\end{Grammar}\nThey are all uniformly represented in IPR as pairs of type and string.\nThere is no restriction on the set of types a literal can be conceived for.\nIn other words, any type node in IPR can serve to create a literal.  The\nsemantics of the resulting node is entirely up to the environment that creates\nand, or interprets such nodes. \n%% \\begin{Program}\n%%   #include <ipr/impl.H>\n%%   #include <ipr/io.H>\n%%   #include <iostream>\n%%   int main()\n%%   \\{\n%%      using namespace ipr;\n%%      impl::Unit unit;\n%%      const Literal* four = unit.make_literal(unit.Int(), u8\"4\");\n%%      const Literal* c = unit.make_literal(unit.Char(), u8\"'c'\");\n\n%%      Printer pp(std::cout);\n%%      pp << xpr_expr(*four)\n%%         << '\\bslash{n}'\n%%         << xpr_expr(*c);\n%%      std::cout << std::endl;\n%%   \\}\n%% \\end{Program}\n\nAs the example from \\secref{sec:generalities} shows, literals are made with\nthe member function \\texttt{make\\_literal()} of the implementation class\n\\NodeClass{impl::Unit}.  It takes two arguments:  the type of the literal and\nthe spelling string.  There is no mutating operations on literals.  The\nsequence of characters should include back-quotes or double-quotes for\ncharacter literals or string literals. \n\n\\section{Names}\n\\label{sec:name}\n\nNames are useful for designating data, types or any computational entity of\ninterest. IPR covers the variety of names found in Standard C++.\nAll names are unified in the sense that, two calls to the same\nname-constructor function, with the same argument list, will yield the same\nphysical node. Consequently, all name nodes are immutable.\n\nThere are eight sub-categories of names\n\\begin{Grammar}\n  \\cxxRule{name:}\n      \\cxxRule{identifier}\n      \\cxxRule{operator-function-id}\n      \\cxxRule{conversion-function-id}\n      \\cxxRule{qualified-id}\n      \\cxxRule{template-id}\n      \\cxxRule{type-id}\n      \\cxxRule{constructor-name}\n      \\cxxRule{destructor-name}\n\\end{Grammar}\naccounting for the variety of names in Standard C++.\n\n\\subsection{Plain identifiers}\n\\label{sec:name.identifier}\n\n\\begin{Grammar}\n  \\cxxRule{identifier:}\n     \\cxxRule{nondigit}\n     \\cxxRule{identifier} \\cxxRule{nondigit}\n     \\cxxRule{identifier} \\cxxRule{digit}\n\\end{Grammar}\nAn \\NodeClass{Identifier} node can be created out of a string that contains\nany character string:\n\\begin{Program}\n  \\expr{unit}.get_identifier(\\expr{string})\n\\end{Program}\nwhere \\expr{unit} is an instance of \\code{impl::Unit} and \\expr{string} is\nthe UTF-8 encoded string to make an identifier out of.  The returned value of the\nfunction \\code{make\\_identifier} has type \\code{const Identifier*}.\n\n\\subsection{Operator function names}\n\\label{sec:name.operator}\n\\begin{Grammar}\n  \\cxxRule{operator-function-id:}\n     operator \\cxxRule{operator}\n\\end{Grammar}\nAny operator-name is represented by IPR node constructed out of a string\ncontaining the spelling of that operator:\n\\begin{Program}\n  \\expr{unit}.make_operator(\\expr{string});\n\\end{Program}\nwhere \\expr{unit} is an expression of type \\code{impl::Unit} and \\expr{string}\nis a string for the operator-name.  The whole expression has type\n\\code{const Operator*}.\n\nFor usual operators like \\texttt{operator+} or \\texttt{operator==}, the string\nis \\texttt{\"+\"} or \\texttt{\"==\"}.  For the array forms of the allocating and\ndeallocating functions, the string is \\texttt{\"new[]\"} or \\texttt{\"delete[]\"}.\n\n\n\\subsection{Conversion function names}\n\\label{sec:name.conversion}\n\\begin{Grammar}\n  \\cxxRule{conversion-function-id:}\n     operator \\cxxRule{type-id}\n\\end{Grammar}\n\nIPR represents a conversion function name as a node that takes the destination\ntype as argument.  Such node is constructed as:\n\\begin{Program}\n  \\expr{unit}.make_conversion(\\expr{type})\n\\end{Program}\nwhere \\expr{unit} is an expression of type \\code{impl::Unit} and \\expr{type}\nis an expression of type derived from \\code{Type}.  The returned value is\nof type \\code{const Conversion*}.\n\n\n\\subsection{Qualified names}\n\\label{sec:name.qualified}\n\\begin{Grammar}\n  \\cxxRule{qualified-id:}\n     \\cxxOpt{::} \\cxxRule{nested-name-specifier} \\cxxRule{unqualified-name}\n     {::} \\cxxRule{name}\n\\end{Grammar}\n\n\nIPR represents qualified names as a \\NodeClass{Scope\\_ref} that takes two\narguments: (a) an expression for the qualifying scope;\nand (b) the designated name.\n\\begin{Program}\n  \\expr{unit}.make_scope_ref(\\expr{scope}, \\expr{name})\n\\end{Program}\nwhere \\expr{unit} is of type \\code{impl::Unit}, \\expr{scope} --- designating\nthe qualifying part --- is any node of type derived from \\code{Expr}, and\n\\expr{name} --- designating the name being qualified --- is also any node of\ntype derived from \\code{Expr}.  The return value is of type \n\\code{const Scope\\_ref*}.\n\n\\subsection{Template specialization names}\n\\label{sec:name.specialization}\n\\begin{Grammar}\n  \\cxxRule{template-id:}\n     \\cxxRule{unqualified-name} <\\cxxOptRule{template-argument-list}>\n\\end{Grammar}\n\nTemplate specialization names, \\NodeClass{Template\\_id} in IPR, are made out\nof two expressions, as:\n\\begin{Program}\n  \\expr{unit}.make_template_id(\\expr{template}, \\expr{arglist});\n\\end{Program}\nwhere the first argument designates the template to specialize and the second\nargument is an \\code{Expr\\_list} that denotes the template-argument\nlist.  The return value has type \\code{const Specialization*}. \n\n\\subsection{Type names}\n\\label{sec:name.type-id}\n\nAll types have names.  Type-names may be as simple as \\texttt{int} or\n\\texttt{double}; but they can also be more complicated expression, composed\nnot just a single identifier, e.g. \\texttt{int (*[256])(int)}.  Names for such\nconstructed types are represented in IPR by \\NodeClass{Type\\_id} nodes.  They\nare built as\n\\begin{Program}\n  \\expr{unit}.make_type_id(\\expr{type})\n\\end{Program}\nthat takes the to-be-named type as its sole argument.  Usually, IPR users\nshould not need to have to create a \\NodeClass{Type\\_id} nodes by themselves\nas these get created automatically for compound types that need them.\n\n\n\\subsection{Constructor name}\n\\label{sec:name.ctor-name}\n\nStandard C++ says that constructors don't have names.  However, it also says\nthat some qualified names actually designate constructors.  Which is quite\nconfusing. For example, in the program fragment\n\\begin{Program}\n  struct S \\{\n     // ...\n  \\};\n  S x = S();\n\\end{Program}\nthe declaration of the variable \\code{x}, the symbol \\code{S} refers to two\ndistinct entity: The first is the class-type and the second is the default\nconstructor (invoked through \\code{S()}).  \nSimilarly, a class with a template constructor needs ways to refer to partial\nspecializations and explicit instantiations.  \n\nIPR defines a category of name called \\code{Ctor\\_name} used to represent\nconstructor names.  A node for such type can be built as\n\\begin{Program}\n  \\expr{unit}.make_ctor_name(\\expr{type})\n\\end{Program}\nwhere \\expr{type} is the type whose constructor one wants to build a name for.\nThe resulting expression has type \\code{const Ctor\\_name*}.  \n\n\\subsection{Destructor name}\n\\label{sec:name.dtor-name}\n\nThe node class \\code{Dtor\\_name} represents a destructor name.  Say\n\\begin{Program}\n  \\expr{unit}.make_dtor_name(\\expr{type})\n\\end{Program}\nto make a destructor name for \\expr{type}.  The resulting expression has type\n\\code{const Dtor\\_name*}.\n\n\n\\section{Types}\n\\label{sec:types}\n\nIPR has a unified type system.  By that we mean that any two\ncalls to the same type node construction function with the same argument list\nwill yield the same physical node.\n\n\\subsection{CV-qualified type}\n\\label{sec:type.cv-qualified}\nAny type (in IPR sense) can be cv-qualified.  The set of cv-qualifiers\ncurrently supported consists of \\texttt{const}, \\texttt{volatile} and\n\\texttt{restrict} (C99).  They are denoted by the enumerators\n\\texttt{Type::Const}, \\texttt{Type::Volatile} and \\texttt{Type::Restrict}.\nThey can be bitor-ed.  A cv-qualified type is built with the\n\\texttt{impl::Unit} member function\n\\begin{Program}\n  const Type* make_qualified(const Type&, Type::Qualifier);\n\\end{Program}\nwhere the first parameter denotes the type to be cv-qualified and the second\nparameter denotes the set of cv-qualifier to apply. \n\n\\subsection{Pointer type}\n\\label{sec:type.pointer}\n\nA \\NodeClass{Pointer} type node can be constructed out of any IPR type node\nwith the \\NodeClass{impl::Unit} member function\n\\begin{Program}\n  const Pointer* make_pointer(const Type&);\n\\end{Program}\n\n\\subsection{Reference type}\n\\label{sec:type.reference}\n\nSimilar to pointer type nodes, a \\NodeClass{Reference} type node can be\nconstructed out of any IPR type node with the \\NodeClass{impl::Unit} member\nfunction \n\\begin{Program}\n  const Reference* make_reference(const Type&);\n\\end{Program}\n\n\n\\subsection{Array type}\n\\label{sec:type.array}\n\nAn array is made with the \\NodeClass{impl::Unit} member function\n\\begin{Program}\n  const Array* make_array(const Type&, const Expr&);\n\\end{Program}\nwhere the first argument is the array element type and the second argument\nspecifies the bound.  For example, ISO Standard C++ says that the type of the \nstring literal \\code{\"Hello World!\"} is \\code{const char[13]}, so its\ntype will be represented in IPR with a node constructed as \n\\begin{Program}\n  // Build a node for the integer literal value `13'\n  const Expr& sz = *unit.make_literal(unit.get_int(),unit.get_string(u8\"13\"));\n  // create the actual node for `const int[13]'\n  unit.make_array(*unit.make_cv_qualified(unit.get_char()), sz);\n\\end{Program}\nAs a limiting case, an array type with no specified bound, \\eg{}\n\\texttt{int[]}, may be constructed along the lines of\n\\begin{Program}\n  unit.make_array(unit.get_int(), unit.null_expr());\n\\end{Program}\nwhere \\texttt{unit.null\\_expr()} denotes here the absence of bound\nspecification. \n\n\n\\subsection{Declared type}\n\\label{sec:type.decltype}\n\nIPR has provision to represent the mechanism to query generalized expression\ntypes (see the \\texttt{auto} and \\texttt{decltype} proposals).  Such an\nexplicit request for inferred type is represented by a \\NodeClass{Decltype}\nnode, constructed with \n\\begin{Program}\n  const Decltype* make_decltype(const Expr&);\n\\end{Program}\n\n\\subsection{Expression as type}\n\\label{sec:type.as-type}\n\nIn various contexts it is useful to view an expression node as actually\ndenoting a type.  For instance, the C++ reserved identifier \\code{bool} \ndesignates the built-in boolean type.  The way that is\naccomplished in IPR is to build an \\NodeClass{As\\_type} node out of the\n\\NodeClass{Identifier} node created for \\code{bool}:\n\\begin{Program}\n  unit.make_as_type(unit.get_identifier(u8\"bool\"))\n\\end{Program}\nAll built-in C++ simple types are created that way.\n\nAnother instance of situations where an \\NodeClass{As\\_type} is helpful\nis when dealing with dependent types.  Assume that you have created a\n\\NodeClass{Parameter} node for a template-parameter \\texttt{C} and you want\nto represent the nested-type \\texttt{typename C::value\\_type}.  The natural\nanswer here is to build a \\NodeClass{Scope\\_ref} and use the resulting node as\na type (reflecting the assumption introduced by the C++ keyword\n\\texttt{typename}):\n\\begin{Program}\n  unit.make_as_type(*unit.make_scope_ref\n                        (\\expr{C}, unit.get_identifier(u8\"value_type\")))\n\\end{Program}\n\n\n\\subsection{Function type}\n\\label{sec:type.function}\n\nA function type consists of three logical parts: (a) the parameter type list;\n(b) the return type; and (c) the list of exceptions a function of that type\nmay throw.  IPR represents a function type as a \\NodeClass{Function} node.\nSuch nodes can be constructed with the \\NodeClass{impl::Unit} member functions \n\\begin{Program}\n  const Function* make_function(const Product&, const Type&);\n  const Function* make_function(const Product&, const Type&, const Sum&);\n\\end{Program}\nThe first constructor function is a convenient surrogate for the second, as it\nimplies that the function may throw any type (noted \\code{...}).\n\n\\subsection{Template type}\n\\label{sec:type.template}\n\nA template type is very similar to a function type, except that it is\nrepresented by a \\NodeClass{Template} node.  The corresponding constructor\nfunction is the member function of \\NodeClass{impl::Unit}\n\\begin{Program}\n  const Template* make_template(const Product&, const Type&);\n\\end{Program}\nThe first argument is the type of the parameter list, and the second argument\nis the type of the expression being parameterized.\n\n\n\\subsection{Pointer to member type}\n\\label{sec:type.ptro-to-member}\n\nA pointer to member type is represented as a pair: The class-type and the type\nof the member.  The corresponding construction function is\n\\begin{Program}\n  const Ptr_to_member* make_ptr_to_member(const ipr::Type&,\n                                          const ipr::Type&);\n\\end{Program}\nof the class \\NodeClass{impl::Unit}.\n\nAt the implementation level, most compilers distinguish pointer to data\nmember types from pointer to member function types. However, the internal\nrepresentation is immaterial to the actual semantics constraints. One issue\nwith our desire to have uniform syntax and representation for non-static\nmember and ordinary functions, however, is to make sure that address of\nmembers are given the right type:  this is easily solved as at anytime we do\nknow when a function declaration is a non-static member function.  See the\ndiscussion in \\ref{sec:fun-decl}.\n\n\n\\subsection{User-defined types}\n\\label{sec:type.udt}\n\nAll standard C++ user-defined types (\\eg{} class or struct, union, enum)\nas well as namespace are considered user-defined types in IPR.  They can be\nconstructed with one of the expressions\n\\begin{Program}\n  \\expr{unit}.make_class(\\expr{parent_region});\n  \\expr{unit}.make_enum(\\expr{parent_region});\n  \\expr{unit}.make_namespace(\\expr{parent_region});\n  \\expr{unit}.make_union(\\expr{parent_region});\n\\end{Program}\nThe resultinf type is \\code{impl::Class*}, \\code{impl::Enum*}, \n\\code{impl::Namespace*} and \\code{impl::Union*}, respectively.\n\nThe definitions of all user-defined types delimit a region, which is the\ndeclarative region of their members.  All, except enums, have a heterogeneous \nregion, implemented by the class \\code{impl::Region}.\nEnums' bodies are homogeneous region (\\code{impl::homogeneous\\_region})\nbecause their members are all enumerators of the same type.  For instance, an\nenumeration's body is a \\code{impl::homogeneous\\_region<Enumerator>}\n\n\nSimilarly  the sequence of declarations in a heterogeneous region is a \nheterogeneous scope (\\code{impl::Scope}), whereas in a homogeneous region,\nit is a \\code{impl::homogeneous\\_scope<T>}, where \\code{T} is the interface \ntype of the declarations.  \n\n\n\\section{Classic expressions}\n\\label{sec:expression}\n\nThe abstract language modeled by IPR nodes is expression-based.  This is to\nsay that nearly any computational entity of interest is thought of as an\nexpression.   Thus compared to Standard C++ notions, most IPR nodes may be\nconsidered as representations of \\emph{generalized expressions}.\nConsequently, the term \\emph{classic expressions} is used to designate genuine\nStandard C++ expressions.\n\nClassic expressions are generally divided into categories:\n\\begin{itemize}\n\\item \\emph{unary expressions}, e.g. \\texttt{sizeof (int)};\n\\item \\emph{binary expressions}, e.g. \\texttt{a + b};\n\\item \\emph{ternary expressions}, e.g. \\texttt{x < y ? x : y}.\n\\end{itemize}\n\nEach category contains a comprehensive list of IPR nodes specifically designed\nto cover all kinds of expressions that fall in that category.\n\nEvery expression is made by a \\texttt{impl::Unit} object.  For\nexample, the following program fragment shows how to create an IPR node for\n\\texttt{sizeof (int)}:\n\\begin{Program}\n  unit.make_type_sizeof(unit.get_int());\n\\end{Program}\n\nWhen an expression involves an identifier that refers to a declared entity,\nwe need to distinguish the \\emph{use} of that identifier from the declaration\nitself.  This is important for preserving the semantics of the input source\nprogram.  For example the fragments\n\\begin{Program}\n  if (bool b = get_answer())\n     // ...\n\\end{Program}\nand\n\\begin{Program}\n  bool b = get_answer();\n  if (b)\n     // ...\n\\end{Program}\nare in general not equivalent.  The distinction between a use of\nidentifier that denotes a declared entity from the introducing declaration is \ncaptured by the node \\code{Id\\_expr}.  In general, one says\n\\begin{Program}\n  \\expr{unit}.make_id_expr(\\expr{decl});\n\\end{Program}\nto build an \\code{Id\\_expr} out of a \\code{Decl} node.  For the occasional\nsituation where --- in a template definition --- an identifier cannot\nbe resolved to the introducing declarations, one uses a \\code{Name} node\ninstead of a \\code{Decl} node as argument to \\code{make\\_id\\_expr}.\nHere is how one can construct nodes for the expression\n\\texttt{a + b}\n\\begin{Program}\n  const Var& a = ...\n  const Var& b = ...\n  Expr* sum = unit.make_plus(*unit.make_id_expr(a), \n                             *unit.make_id_expr(b));\n\\end{Program}\n\nThe conditional expression \\texttt{x < y ? x : y} can be constructed\nas follows\n\\begin{Program}\n  const Expr& x = ...\n  const Expr& y = ...\n  const Expr& min = *unit.make_conditional(*unit.make_less(x, y), x, y);\n\\end{Program}\n\nCast-expressions are represented as binary expressions: The first operand is\nthe target type and the second operand is the source expression.\n\n\n\\subsection{User-defined operators}\n\\label{sec:expression.user-defined-operator}\n\nIn Standard C++, most operators can be overloaded and given a user-defined\nmeaning. For generality, IPR takes the approach that just about any operator\ncan be given a user-defined meaning.  Consequently, every IPR implementation\nclass for an operator has a field \\code{op\\_impl} to record the function\ndeclaration that implements that operator.  For instance, consider the\nexpression \\code{cout~<<~2} for inserting the integer value tow in the\noutput standard stream.  Assume further that the insertion function operator\ndeclaration is represented by \\code{ins}, then the IPR representation for the\nwhole expression would be constructed as\n\\begin{Program}\n  impl::Lshift* shift = unit.make_lshist(\\expr{cout}, \\expr{two});\n  shift->op_impl = ins;   // remember the insertion function\n\\end{Program}\n\nIf the member \\code{op\\_impl} is not set, then it is assumed to be a\nbuilt-in operator.\n\n\n\\subsection{Names and resolutions}\n\\label{sec:expression.name-lookup}\n\n\n\\section{Named data}\n\\label{sec:data.named}\n\nThis section describes the representation of named data, \\ie{} variables, data\nmember.  Notice that in either case, references are treated no specially from\nvariables or data members -- even though the C++ standard says that references\nare not objects. \n\nNamed data are declared at user-defined types (\\ie{} class-types,\nenumerations or namespaces) level.  Consequently, their IPR node\nrepresentations are  manufactured with a member function, prefixed by\n\\code{declare\\_}, of the enclosing user-defined type. The next subsections\ndiscuss the mapping of the variety C++ named data to IPR representation.\n\n\\subsection{Variable declaration}\n\\label{sec:decl.variable}\n\nA variable is an association of a name and a storage for data, that does not\nhave any enclosing object. The notion of variable is implemented by\n\\code{impl::Var}.  Manufacturing a node of that type requires ---\nas do most declaration nodes --- three things: (a) the name of the variable;\n(b) the type of the data to store; and (c) an optional initializer.\n\nA node for a variable is created with the member function\n\\texttt{declare\\_var()} of the implementation class for the enclosing\nuser-defined type (\\code{impl::Class}, \\code{imp::Union} or\n\\code{impl::Namespace}).  Once a \\texttt{impl::Var} is\ncreated, it must be \nassociated with its initializer (if any).  The following program\nillustrates how to build a variable declaration \n\\begin{Program}\n  static const int bufsz = 1024;\n\\end{Program}\nat the global scope and write the resulting node in XPR notation.\n\\begin{Program}\n#include <ipr/impl>\n#include <ipr/io>\n#include <iostream>\nint main()\n\\{\n   using namespace ipr;\n   impl::Unit unit;              // current translation unit\n   \n   // Build the variable's name and type\n   const Name& name = unit.get_identifier(u8\"bufsz\");\n   const Type* type = unit.make_cv_qualified(unit.get_int(), Type::Const);\n\n   // and the actual impl::Var node at global scope and initialize it\n   impl::Var* var = unit.global_ns->declare_var(name, *type);\n   var->decl_data.spec = ipr::Decl::Static;\n   var->init = unit.make_literal(unit.get_int(), u8\"1024\");\n   \n   // Print out the whole translation unit\n   Printer pp(std::cout);\n   pp << unit;\n   std::cout << '\\bslash{n}';\n\\}\n\\end{Program}\nThe output of the above program is\n\\begin{Output}\n  bufsz : static const int = 1024;\n\\end{Output}\n\nThe effort of constructing the representation of that declaration basically is\none line per significant token. \n\n\n\\subsection{Static data members}\n\\label{sec:named.data.static-member}\n\nA static data member is a global variable in disguise.  They key difference\nbetween a static data member and an ordinary variable that the former is\nsubject to access control.  Therefore, a static data member is also\nrepresented by a \\code{Var} node.  From the IPR representation point of view,\nthe steps for manufacturing a node for a static data member is pretty much\nthe same as for ordinary variable, except that one uses the enclosing\nclass-type as the manufacturer.  For instance, consider the program fragment \n\\begin{Program}\n  class nifty_counter \\{\n    // ...\n  private:\n     static int count;\n  \\};\n\\end{Program}\nwhere we are only interested in the portion relating to the representation of\nthe static data member \\code{nifty\\_counter::count}.  Here is a program that\naccomplishes that job and prints the IPR representation:\n\\begin{Program}\n#include <ipr/impl>\n#include <ipr/io>\n#include <iostream>\n\nint main()\n\\{\n   using namespace ipr;\n   impl::Unit unit;              // current translation unit\n\n   // First, build the node for the nifty_counter class\n   impl::Class* nifty_type = unit.make_class(*unit.global_region());\n   nifty_type->id = &unit.get_identifier(u8\"nifty_counter\");\n   unit.global_ns->declare_type(*nifty_type->id, unit.Class())->init\n      = nifty_type;\n   \n   // Then build the static data member\n   impl::Var* count = nifty_type->declare_var(unit.get_identifier(u8\"count\"),\n                                              unit.get_int());\n   // \"cout\" is private \n   count->decl_data.spec = Decl::Static | Decl::Private;\n   // We do not set the initializer, since there is none.\n   \n   // Print out the whole translation unit\n   Printer pp(std::cout);\n   pp << unit;\n   std::cout << '\\bslash{n}';\n\\}\n\\end{Program}\n\nA \\code{Var} node represents a static data member if and only if its\nmembership is a class-type.  Notice that the operation \\code{declare\\_var()}\nis supported by implementation classes for all user-defined types, except\nenumerations. \n\n\\subsection{Non-static data members}\n\\label{sec:named.data.nonstatic-member}\n\nA non-static data member has semantics different from that of ordinary \nvariable and static data-members.  Consequently, it is represented by a\ndistinct node (\\code{Field}).  However, the steps for manufacturing such node\nis very similar to that of a variable, except that the construction function \n\\code{declare\\_field()} is used --- instead of \\code{declare\\_var()}.\n\nConsider the following C++ program fragment\n\\begin{Program}\n  struct point \\{\n    int x;\n    int y;\n  \\};\n\\end{Program}\nthat declares a class named \\code{point} at the global scope.  That\ndeclaration can be constructed as follows\n\\begin{Program}\n#include <ipr/impl>\n#include <ipr/io>\n#include <iostream>\n\nint main()\n\\{\n   using namespace ipr;\n   impl::Unit unit;\n\n   // Make the class node, and bind it to the name \"point\".\n   impl::Class* point = unit.make_class(*unit.global_region());\n   point->id = &unit.get_identifier(u8\"point\");\n   unit.global_ns->declare_type(*point->id, unit.Class())->init = point;\n\n   // declare the public data member \"x\".\n   point->declare_field(unit.get_identifier(u8\"x\"), unit.get_int())\n      ->decl_data.spec = Decl::Public;\n\n   // Ditto for \"y\".\n   point->declare_field(unit.get_identifier(u8\"y\"), unit.get_int())\n      ->decl_data.spec = Decl::Public;\n\n   // Print the current unit.\n   Printer pp(std::cout);\n   pp << unit;\n   std::cout << std::endl;\n\\}\n\\end{Program}\n\nThe output is:\n\\begin{Program}\npoint : class \\{\n    x : public int;\n    y : public int;\n\\};\n\\end{Program}\nIn a well formed C++ programs, a \\code{Field} does not have an initializer.\nHowever, the IPR library does not enforce that rule --- an erroneous program\nmay initialize a non-static data member and we do not gain any uniformity in\nenforcing that rule in the IPR data structures. \n\n\\section{Function declarations}\n\\label{sec:fun-decl}\n\nThis sections discusses the basics for  building nodes for function\ndeclarations.  A function declaration is an association of a name with a\nmapping.  For example, the C++ declaration \n\\begin{Program}\n  int identity(int);\n\\end{Program}\ndefines a mapping from \\code{int} to \\code{int} called \\code{identity}.\nMore generally, that declaration is represented as the association of the name\n\\code{identity} with a \nunary parameterized expression, where the argument is expected to be of type\n\\code{int}, the result of type \\code{int}, and the computation of the result\nmay be abnormally ended with an exception of any type (implied by the absence\nof exception specification).  In XPR notation, it reads:\n\\begin{Program}\n  identity : (:int) int throw (...);\n\\end{Program}\n\nSimilar to the situation of named data (\\secref{sec:data.named}), C++\ndistinguishes member functions from non-member functions.  Unlike the\nnamed data case, both member functions and non-member function declarations\nare uniformly represented by \\NodeClass{Fundecl} nodes. Like in the \\code{Var}\ncase, the membership of a \\code{Fundecl} distinguishes a non-member function\n(membership is a namespace) from a member function (membership is a\nclass-type). \n\nMember functions  are further subdivided into two categories: static\nmember functions and non-static member functions.  The former are disguised\nnon-member functions with privileged access to their enclosing class-type's\nmembers (kind of friend non-member functions), and the latter have an implicit\nor implied parameter.  We do not have different kinds of function types for\nthe types of static member functions and non-static member functions. They \nall have types uniformly represented by a \\code{Function} node.\n\nA \\code{Fundecl} for a static member function differs from a \\code{Fundecl}\nfor a non-static member function in that the former has the\n\\code{Decl::Static} set and the latter not.  \n\nFurthermore, the correspondence between a non-static member function in C++\nand its ``regularized'' version in IPR makes and adjustment:  the keyword\n\\code{this} is made an explicit parameter.  For instance, the following\nmember function declarations \n\\begin{Program}\n  struct A \\{\n    // ...\n    int& f();\n    const int& f() const;\n    static double g(A*);\n    virtual void h(int) = 0;\n  \\};\n\\end{Program}\nwill be interpreted as (XPR notation)\n\\begin{Program}\n  f: public (this: *A) &int throw(...);\n  f: public (this: *const A) &const int throw(...);\n  g: public static (: *A) double throw(...);\n  h: public virtual pure (this: A*, : int) void throw(...);\n\\end{Program}\nAs a general rule, every non-static member function is adjusted to take \n\\code{this} as first parameter, of type \\code{*}\\expr{cv T} where\n\\expr{T} is the class and \\expr{cv} is the cv-qualification of the \nnon-static member function.\n\n\n\\subsection{Mapping}\n\\label{sec:fun-decl.mapping}\n\nA mapping is a parameterized expression.   The notion of mapping is general\nenough to account for both function declaration bodies and template\ndeclaration bodies.  To illustrate the generality here, consider the following \nprogram fragments in both Standard C++ and XPR notations:\n\\begin{center}\n\\begin{minipage}[t]{13cm}\n  \\begin{minipage}[t]{4cm}\n    \\centering{\\textit{C++}}\n    \\begin{Program}\nint identity(int x) \\{\n  return x;\n\\}\n\ntemplate<int N>\nstruct buffer \\{\n   char data[N];\n\\};\n    \\end{Program}\n  \\end{minipage}\\hfil \\vrule \\hfil\n  \\begin{minipage}[t]{7cm}\n    \\centering{\\textit{XPR}}\n    \\begin{Program}\nidentity : (x : int) int throw(...) = \\{\n  return x;\n\\}\n\nbuffer : <N : int> class = \\{\n  data : public [N] char;\n\\};\n    \\end{Program}\n  \\end{minipage}\n\\end{minipage}\n\\end{center}\nA feature of the XPR notation here is that it makes a clear separation\nbetween the names being declared and what they are being bound to.  The\nfunction \\code{identity} maps an \\code{int} to an \\code{int}, and the class\ntemplate \\code{buffer} maps an \\code{int} to a class-type.  Furthermore, how\nthe integer result of \\code{identity} is computed is given by \n\\code{int \\{~return x;~\\}}; similarly how the class result of \\code{buffer} is\ncomputed is given by \\code{struct \\{~char data[N];~\\}}.  The implementation \nof either map constitutes its body.\n\nA mapping consists of a parameter list and a body.  Its IPR implementation\nnode is described by the class\\NodeClass{impl::Mapping}, built with the member\nfunction \n\\begin{Program}\n  impl::Mapping* make_mapping(const ipr::Region&);\n\\end{Program}\nof the \\NodeClass{impl::Unit} class.  For example, let's assume the previous\ndeclaration for \\code{identity} appears at the global scope.  Then, its\nassociated mapping node would be made as follows:\n\\begin{Program}\nimpl::Mapping* mapping = unit.make_mapping(*unit.global_region());  \n\\end{Program}\nParameters are specified with the \\code{param()} member function\nof \\NodeClass{impl::Mapping}.  \n\\begin{Program}\nimpl::Parameter* x = mapping->param(unit.get_identifier(u8\"x\"), unit.get_int());\n\\end{Program}\n\nThe data member \\code{impl::Mapping::parameters}\nholds the list of specified parameters.  Its type is a product type, and\nrepresented by a \\NodeClass{Product} node.  It describes the domain type of\nthe mapping.  A mapping, being an expression, as a type.  That type is\nrepresented by a \\NodeClass{Function} node when it is associated with a\nfunction declaration, and a \\NodeClass{Template} node when it is associated\nwith a parameterized declaration.  So, for the case of the \\code{identity}\nfunction declaration, one would write the following\n\\begin{Program}\nconst Function* ftype = unit.make_function\n    (mapping->parameters.type(), unit.get_int());\nmapping->constraint = ftype;  \n\\end{Program}\n\nWe will discuss the case of parameterized declarations in\n\\secref{sec:decls:parameterized}. \n\n\\subsection{Naming a mapping}\n\\label{sec:fun-decl:naming}\n\nBuilding a \\NodeClass{impl::Fundecl} is very similar to the process of\nbuilding a node for a variable: one needs a name, a type and optional\ninitializer.  As explained above, the initializer for a function declaration\nis a mapping.\n\\begin{Program}\nimpl::Fundecl* f = unit.global_ns->declare_fun\n   (unit.get_identifier(u8\"identity\"), *ftype);\nf->init = mapping;                        // the named mapping\n\\end{Program}\n\nThe node for a function declaration that is not a definition is initialized\nwith an incomplete mapping.   An incomplete mapping is a mapping whose body is\nnot specified.\n\n\n\\subsection{Constructors and destructors}\n\nA constructor or destructor is represented as a non-static member function,\nsuitably adjusted to take \\code{this} as a first parameter.  Constructors and\ndestructors to not return values, consequently their return type is\n\\code{void}.\n\n\\section{Statements}\n\\label{sec:statements}\n\nThis section gives the translation of ISO Standard C++ statements to IPR\nnodes. \n\n\\subsection{Compound statement}\n\\label{sec:stmt.compound}\n\nNamed mappings are initialized with blocks in function definitions.\nAn IPR block is a statement and consists of a sequence of statements and\noptional sequence of handlers.\n\nStandard C++ defines a compound statement as any brace-enclosed sequence of\nstatements\n\\begin{Grammar}\n  \\cxxRule{compound-statement:}\n     \\{ \\cxxOptRule{statement-seq} \\}\n\n  \\cxxRule{statement-seq:}\n      \\cxxRule{statement}\n      \\cxxRule{statement-seq} \\cxxRule{statement}\n\\end{Grammar}\n\nThe corresponding concrete IPR representation is \\NodeClass{impl::Block}.\nSuch a node is built with the member function\n\\begin{Program}\n  impl::Block* make_block(const ipr::Region&);\n\\end{Program}\nof the class \\NodeClass{impl::Unit}.  Suppose that we have to create nodes for\nthe definition\n\\begin{Program}\n  int identity(int x) \\{ return x; \\}\n\\end{Program}\nThen one would first create a block node for the body of the mapping\nassociated with \\code{identity}, and then fill in that block with sequence of\nstatements as explained in sub-sections to follow.\n\\begin{Program}\nimpl::Block* body = unit.make_block(mapping->parameters, unit.get_int());\nmapping->body = body;\n// fill in the body with add_stmt() as shown below\n\\end{Program}\n\n\n\\subsection{Expression statement}\n\\label{sec:stmt.expr}\nMost statements are actually expressions statements, which Standard C++ \ndefines as\n\\begin{Grammar}\n  \\cxxRule{expression-statement:}\n      \\cxxOptRule{expression} ;\n\\end{Grammar}\n\nThey are concretely represented with \\NodeClass{impl::Expr\\_stmt}:\n\\begin{Program}\n           unit.make_expr_stmt(\\cxxRule{expr})\n\\end{Program}\nThe case of \\emph{null statement}, \\ie{} an expression statement with\nmissing expression, is handled by calling the (member) function\n\\verb=null_expr()= for the \\NodeClass{Unit} object.  An instance of null\nstatement is the following fragment\n\\begin{Program}\n  while (*dst++ = *src++)\n     ;\n\\end{Program}\nWhile statements are discussed in \\secref{sec:stmt.iteration.while}.  Here, we\njust illustrate the representation an ``empty'' body:\n\\begin{Program}\n  Stmt* stmt = unit.make_expr_stmt(unit.null_expr());\n\\end{Program}\n\n\\subsection{Selection statement}\n\\label{sec:stmt.selection}\n\nA selection statement is any of the three kind of statements as defined by \n\\begin{Grammar}\n  \\cxxRule{selection-statement:}\n      if ( \\cxxRule{condition} ) \\cxxRule{statement}\n      if ( \\cxxRule{condition} ) \\cxxRule{statement} else \\cxxRule{statement}\n      switch ( \\cxxRule{condition} ) \\cxxRule{statement}\n\\end{Grammar}\nThey are concretely represented in IPR with \\NodeClass{If\\_then},\n\\NodeClass{If\\_then\\_else} and \\NodeClass{Switch} nodes,\nrespectively. \n\nBoth \\NodeClass{impl::If\\_then} and \\NodeClass{impl::Switch} nodes are\nconstructed in similar ways. They all require two arguments: the first being\nthe condition and the second being the selected statement.  Use\n\\texttt{make\\_if\\_then()} to build a \\NodeClass{impl::If\\_then} node, and\n\\texttt{make\\_switch()} for a  \\NodeClass{impl::Switch} node.\n For instance, the fragment\n\\begin{Program}\n  if (lhs < rhs)\n     return false;\n\\end{Program}\nmay be translated as:\n\\begin{Program}\n  Expr* return_value = unit.make_literal(unit.Bool(), u8\"bool\");\n  unit.make_if_then(*unit.make_less(\\expr{lhs}, \\expr{rhs}),\n                    *unit.make_return(*return_value));\n\\end{Program}\n\n\nAn \\NodeClass{impl::If\\_then\\_else} node requires three arguments: the\ncondition, the then-branch statement and the else-branch statement.  It is\nconstructed through the (member) function \\texttt{make\\_if\\_then\\_else()} of\nclass \\NodeClass{impl::Unit}.\n\n\\subsection{Iteration statement}\n\\label{sec:stmt.iteration}\n\nStandard C++ defines an iteration statement to be \n\\begin{Grammar}\n  \\cxxRule{iteration-statement:}\n      while ( \\cxxRule{condition} ) \\cxxRule{statement}\n      do \\cxxRule{statement} while ( \\cxxRule{condition} )\n      for ( \\cxxOptRule{for-init-statement} \\cxxOptRule{condition} ; \\cxxOptRule{expression} ) \\cxxRule{statement}\n\\end{Grammar}\n\n\n\\subsubsection{While statement}\n\\label{sec:stmt.iteration.while}\n\nConstructing a \\NodeClass{impl::While} node requires the condition node and\nthe iterated statement node.  For example, the following fragment\n\\begin{Program}\n  while (n != 0)\n     n = process_line(n);\n\\end{Program}\nmay be constructed with\n\\begin{Program}\n  impl::Var* n = ...\n  impl::Fundecl* processline = ...\n  // ...\n  Expr* cond = unit.make_not_equal(n, *unit.make_literal(unit.get_int(), u8\"0\"));\n  impl::Expr_list* args = unit.make_expr_list(); // hold the arg-list.\n  args->push_back(n);  \n  Expr* call = unit.make_call(processline, *args);\n  Stmt* stmt = unit.make_expr_stmt(*uni.make_assign(n, call));\n  Stmt* while_stmt = unit.make_while(cond, stmt);\n\\end{Program}\n\n\n\\subsubsection{Do statement}\n\nA do statement is constructed similar to a while statement.  The\n(member) function to call is \\texttt{make\\_do()} with the\niterated statement and the condition expression as arguments, in that order. \n\n\n\\subsubsection{For statement}\nA for statement is a curious and interesting statement.  All its\ncomponents are optional.  A missing part is equivalent to either a null\nexpression or a null statement.\n\nA \\NodeClass{For} node is created through the (member) function\n\\texttt{make\\_for()} which takes four arguments, one for each components.\n\nLet's first look at \n\\begin{Program}\n  for (int i = 0; i < N; ++i)\n     \\cxxRule{stmt}\n\\end{Program}\nIn this case, the \\cxxRule{for-init-statement} is a declaration.  Therefore,\nwe create a sub-region (of the active region) that will contain the declaration\nand we use the scope of that sub-region as the first argument for\n\\texttt{make\\_for()}. \n\\begin{Program}\n  // the IPR node representing the for statement \n  impl::For* for_stmt = unit.make_for();\n\n  // Build the declaration for \"i\".\n  impl::Region* init_region = \\expr{active_region}->make_subregion();\n  impl::Var* i = init_region->declare_var(unit.get_identifier(u8\"i\"),\n                                          unit.get_int());\n  i->init = unit.make_literal(unit.get_int(), u8\"0\");\n\n  // set the for-init\n  for_stmt->init = &init_region.scope;\n\n  // Build the condition.\n  for_stmt->cond = unit.make_less(*i, \\expr{N});\n\n  // the incrementation\n  for_stmt->inc = unit.make_pre_increment(*i);\n  \n  // the body of the for-statement\n  for_stmt->stmt = \\expr{stmt};\n\\end{Program}\n%% Notice that, in this case, the scope for the init-declaration becomes the\n%% active scope till \\cxxRule{stmt}.\n\nIf the declaration for the variable \\texttt{i} was not limited to the\nfor statement, \\ie{} if we had\n\\begin{Program}\n  int i;\n  for (i = 0; i < N; ++i)\n    \\cxxRule{stmt}\n\\end{Program}\nthen we would not need to build a sub-scope for that variable.  Rather, we\nwould just build the declaration in the current scope:\n\\begin{Program}\n// Build a declaration for \"i\",\nVar* i = \\textit{active_region}->declare_var(unit.get_identifier(u8\"i\"), unit.get_int());\nimpl::For* for_stmt = unit.make_for();\nfor_stmt->init = unit.make_assign(*i, *unit.make_literal(unit.get_int(), u8\"0\"));\n// the condition,\nfor_stmt->cond = unit.make_less(*i, \\textit{N});\n// the incrementation,\nfor_stmt->inc = unit.make_pre_increment(*i);\n\\end{Program}\n\n\nAnother interesting case is when the \\cxxRule{condition} in the for statement\nis actually a declaration.  In that case, we build a sub-region (of the active\nregion) and use it as the second argument to \\texttt{make\\_for()}. Therefore\nthe following fragment\n\\begin{Program}\n  for (int i = 0; int j = N - i; ++i)\n     \\cxxRule{stmt}\n\\end{Program}\nmay be translated by\n\\begin{Program}\n  impl::For* for_stmt = unit.make_for();\n\n  // Build the for-initialization part\n  impl::Region* init_region = \\expr{active_region}->make_subregion();\n  for_stmt->init = &init_region->scope;\n  impl::Var* i = init_region->declare_var(unit.get_identifier(u8\"i\"),\n                                          unit.get_int());\n  i->init = unit.make_literal(unit.get_int(), u8\"0\");\n\n  // The for-condition part\n  impl::Region* cond_region = init_region->make_subregion();\n  for_stmt->cond = &cond_region->scope;\n  impl::Var* j = cond_region->declare_var(unit.get_identifier(u8\"j\"),\n                                          unit.get_int());\n  j->init = unit.make_sub(\\expr{N}, *i);\n\n  // the incrementation part,\n  for_stmt->inc = unit.make_pre_increment(*i);\n\n  // and the body of the for-statement.\n  for_stmt->stmt = \\cxxRule{stmt};\n\\end{Program}\nNotice that the region containing \\code{j} is a sub-region of the scope\ncontaining \\code{i} and is the active scope till \\cxxRule{stmt}.\n\n\n\\subsection{Labeled statement}\n\\label{sec:stmt.labeled}\n\nStandard C++ defines a labeled statement according to the grammar:\n\\begin{Grammar}\n  \\cxxRule{labeled-statement:}\n      \\cxxRule{identifier} : \\cxxRule{statement}\n      case \\cxxRule{constant-expression} : \\cxxRule{statement}\n      default : \\cxxRule{statement}\n\\end{Grammar}\n\nAll these three variants of labeled statements are uniformly represented in\nIPR through the node class \\NodeClass{Labeled\\_stmt}.  The label can be any\nIPR expression.  Since a name is an expression a statement like \n\\begin{Program}\n  id:\n     token = cursor - 1;\n     // ...\n\\end{Program}\nmay be represented in IPR as:\n\\begin{Program}\n  impl::Var cursor = ...;\n  // ...\n  impl::Minus* rhs = unit.make_minus(cursor, \n                                     *unit.make_literal(unit.get_int(), u8\"1\")));\n  impl::Assign* expr = unit.make_assign(*cursor, *rhs);\n  impl::Expr_stmt* expr_stmt = unit.make_expr_stmt(*expr);\n  auto& lbl = unit.get_identifier(u8\"id\");\n  impl::Labeled_stmt* labeled_stmt = unit.make_labeled_stmt(lbl, *expr_stmt);\n\\end{Program}\nHere a node created for the name \\texttt{id} is used as the expression\nthat labels the whole statement.\n\nFor a \\texttt{case} label, the associated constant expression is used as the\nlabeling expression.  For example, for the program fragment\n\\begin{Program}\n  int line_count = 0;\n  // ...\n  switch (*cur) \\{\n    case '{\\bslash}n':\n       ++line_count;\n       // ...\n  \\}\n\\end{Program}\none might construct\n\\begin{Program}\n  impl::Var* linecount = ...\n  // ...\n  // literal used to label the case-statement\n  impl::Literal* nl = unit.make_literal(unit.get_char(), u8\"{\\bslash\\bslash}n\");\n  impl::Labeled_stmt* stmt = unit.make_labeled_stmt\n     (*nl, *unit.make_expr_stmt(*unit.make_pre_increment(*linecount)));\n\\end{Program}\n\nThe \\texttt{default} label is represented no different from ordinary labels.\nThat is, one uses \\verb=unit.get_identifier(u8\"default\")= as the labeling\nexpression. \n\n\n\\subsection{Jump statement}\n\\label{sec:stmt.jump}\n\nA jump statement is any of\n\\begin{Grammar}\n  \\cxxRule{jump-statement:}\n      break ;\n      continue ;\n      return \\cxxOptRule{expression} ;\n      goto \\cxxRule{identifier} ;\n\\end{Grammar}\n\nReturn-statements are built with the member function \\code{make\\_return()} of \n\\code{imp::Unit}. So, continuing with the \\code{identity} function\n\\begin{Program}\nbody->add_stmt(unit.make_return(*x));  \n\\end{Program}\n\nA break-statement is built with \\code{make\\_break()}, a continue-statement\nis built with \\code{make\\_continue()}, and a goto-statement is built with\n\\code{make\\_goto()} taking the destination as argument. At the exception of\nthe return statement, IPR nodes for jump statements have room to record the\nstatements primarily affected by the control transfer.  Consider the program\nfragment \n\\begin{Program}\n  char c;\n  int line_count = 0;\n  // ...\n  switch (c) \\{\n    case '{\\bslash}n':\n      ++line_count;\n      break;\n    // ...\n  \\}\n\\end{Program}\n\nHere is a corresponding IPR nodes construction:\n\\begin{Program}\n  // Build declaration for \"c\",\n  impl::Var* c = \\expr{active_region}->declare_var(unit.get_identifier(u8\"c\"),\n                                                   unit.get_char());\n\n  // do the same for \"line_count\", \n  impl::Var* line_count = \\expr{active_region}->declare_var\n     (unit.get_identifier(u8\"line_count\"), unit.get_int());\n  line_count->init = unit.make_literal(unit.get_int(), u8\"0\");\n\n  // ...\n  // Build the Block for the switch statement.\n  impl::Block* block = unit.make_block(\\textit{active_region});\n  // Build the switch-statement node.\n  Switch* switch_stmt = unit.make_switch(*c, *block);\n\n  // Fill in the switch body,\n  Stmt* stmt = unit.make_expr_stmt(*unit.make_pre_increment(line_count));\n  Expr* lbl = unit.make_literal(unit.get_char(), u8\"{\\bslash}n\");\n  block->add_stmt(unit.make_labeled_stmt(lbl, stmt));\n\n    // Build the break statement\n  impl::Break* break_stmt = unit.make_break();\n    // record the statement we're breaking from\n  break_stmt->stmt = switch_stmt;\n\n    // put it in the body.\n  block->add_stmt(break_stmt);\n  // ...\n\\end{Program}\n\n\n\\subsection{Declaration statement}\n\\label{sec:stmt.declaration}\n\nA declaration is a statement.  As such, a declaration that appears at block\nscope shall be added to the sequence of statements that constitute the body of\nthat block.  \n\n\\subsection{Try Block}\n\\label{sec:stmt.try-block}\nTry blocks in Standard C++ come into various syntactic flavors.\n\\begin{Grammar}\n  \\cxxRule{try-block:}\n     try \\cxxRule{compound-statement} \\cxxRule{handler-seq}\n\n  \\cxxRule{function-try-block:}\n     try \\cxxOptRule{ctor-initializer} \\cxxRule{function-body} \\cxxRule{handler-seq}\n\n  \\cxxRule{handler-seq:}\n     \\cxxRule{handler} \\cxxOptRule{handler-seq}\n\n  \\cxxRule{handler:}\n     catch ( \\cxxRule{exception-declaration} ) \\cxxRule{compound-statement}\n\\end{Grammar}\n\nIn IPR, we do not have a separate node for try-block statement.  Rather, we\ntake the general approach that any block can potentially throw an exception;\ntherefore any \\NodeClass{Block} has an associated sequence of handlers.\nIf that sequence is empty then it does not come from a try-block.  \n\n\n\\section{Parameterized declarations}\n\\label{sec:decls:parameterized}\n\nIn IPR, any expression can be parameterized.  Parameterized expressions, and\nare uniformly represented with \\NodeClass{impl::Mapping} nodes (see discussion\nin \\secref{sec:fun-decl.mapping}).  Parameterized declarations, or template\ndeclarations in Standard C++ terminology, are declaration generators. \nFor instance, consider the following generalization of the function\n\\code{identity} from previous section:\n\\begin{Program}\n  template<class T>\n    T identity(T x) \n    { return x; }\n\\end{Program}\nequivalently written in XPR as\n\\begin{Program}\n  identity: <T: class> (x: T) T throws(...) = \\{\n     return x;\n  \\}\n\\end{Program}\nIt is clear that it is a named mapping which, when given a type argument\nT, produces a function declaration --- named \\code{identity<T>} -- taking a\n\\code{T} and returning a value of the same type.  In a sense, it is a mapping\nof a mapping: the result of the first mapping is compile-time, whereas the\nsecond is runtime; however the abstract representations are similar.\n\nA named mapping is a declaration (\\code{Named\\_map}).  It has type represented\nby a \\NodeClass{Template} node.  Its initializer is a mapping of type\n\\code{Template}.\n\n\n\n\\subsection{Primary declaration generators}\n\\label{sec:named-mapping:primary}\n\nC++ template declarations can be divided into two categories:\n(a) primary templates; and (b) secondary templates.\n\nA primary template is the most general form of a declaration generator.\nIt indicates the type of the declaration it generates, and the number and\nsorts of arguments it accepts.  A primary declaration generator participates\nin overload resolution (secondary declaration generators don't).\n\nThe notion of primary template declaration should not be confused with that of\nmaster declaration.  A master declaration is the first  declaration of an\nentity in a given scope.  Primary declarations, on the other hand, may be\nrepeated where permitted (for instance, at namespace scope).   \n\\begin{Program}\n  template<class T>\n     struct Array \\{                         // \\#1\n        // ...\n     \\};\n  \n  template<class T>\n     T sum(const Array<T>&);                // \\#2\n \n  template<class T> \n     struct Array;                          // \\#3\n\\end{Program}\n\\code{\\#1} is the first declaration of the template \\code{Array<>}; so it is \na master declaration.  It is also the most general form of \n\\code{Array<>} instance declaration generator;\ntherefore it is also a primary template.  In summary, \\code{\\#1} is a master\nprimary template declaration.  On the other hand, \\code{\\#3} is a\nre-declaration, therefore it is a non-master primary template declaration.\n\nA node for a primary template declaration is built with the member function  \n\\begin{Program}\n  impl::Named_map* declare_primary_map(const ipr::Name&, const ipr::Template&);\n\\end{Program}\nof the enclosing user-defined type.  A primary map does bookkeeping for\nvarious ``administrative'' information.  The program fragment below builds the\nnodes for the representation of \\code{\\#1}\n\\begin{Program}\n#include <ipr/impl>\n#include <ipr/io>\n#include <iostream>\n\nint main()\n\\{\n   using namespace ipr;\n   impl::Unit unit;\n   Printer pp(std::cout);\n\n   // make the node that contains the body of the Array template\n   impl::Mapping* mapping = unit.make_mapping(*unit.global_region());\n\n   // declare the template type-parameter \"T\".\n   impl::Parameter* T = mapping->param(unit.get_identifier(u8\"T\"),\n                                       unit.Class());\n\n   // set the type of the mapping.\n   const ipr::Template* tt = unit.make_template(mapping->parameters.type(),\n                                                unit.Class());\n   mapping->constraint = tt;\n\n   // build the decl for \"Array\", with same type.\n   impl::Named_map* array = unit.global_ns->declare_primary_map\n      (unit.get_identifier(u8\"Array\"), *tt);\n   array->init = mapping;\n\n   // \"Array\" uses the argument list \"<T>\".\n   array->args.push_back(T);\n\n   // and the body of the mapping is a class-expression\n   impl::Class* body = unit.make_class(mapping->parameters);\n   mapping->body = body;\n   // set its name.\n   body->id = unit.make_template_id(*array, array->args);\n\n   pp << unit;\n   std::cout << std::endl;\n\\}\n\\end{Program}\n\nEvery instance of \\code{Named\\_map} keeps track of the (template) argument\nlist it uses.  That argument list is needed for the purpose of determining\nthe most specialized version of a named mapping use.\n\n\\subsection{Secondary named mappings}\n\\label{sec:named-mapping:secondary}\n\nA secondary template declaration provides a specialized implementation for \ngiven sub-family of the primary template.  Therefore, it may introduce\nmore or fewer parameters than the primary template does.  However, it must\nsupply an argument list that meets the requirements (in number and kinds)\nstated by the primary template declaration. Secondary templates do not\nparticipate in overload resolution. Consider for example th previous\n\\code{Array<>} declaration, continued as follows\n\\begin{Program}\n  template<>\n    struct Array<void*> \\{                    // #4\n       // ...\n    \\};\n\n  template<class T>\n    struct Array<T*> : Array<void*> \\{        // #5\n       // ...\n    \\};\n\\end{Program}\nThe declaration \\code{\\#4} is an explicit specialization of\n\\code{Array<>}, but it is \\emph{not} a template.  Therefore, it must be\nrepresented as an ordinary class.  On the other hand, \\code{\\#5} is a\nsecondary template declaration.  It specializes \\code{\\#1}, and uses the \nargument list \\code{<T*>}.\n\nSecondary named mappings are manufactured with the member function\n\\begin{Program}\n  impl::Named_map* declare_secondar_map(const ipr::Name&, const ipr::Template&);\n\\end{Program}\nof the enclosing user-defined type.\n\n\\section{External representation}\n\\label{sec:xpr}\n\nThe persistent form of IPR nodes is expressed through the \nXPR syntax --- for \\emph{eXternal Program Representation}.  The XPR syntax is\ndefined in the Reference Manual.  \n\nThe header file \\texttt{<ipr/io>} provides access to XPR output \nfacilities.  That header file defines:\n\\begin{itemize}\n\\item a basic XPR printer \\texttt{ipr::Printer} ;\n\\item facilities to print \\emph{expressions}, \\emph{types}, \\emph{statements}\n  and \\emph{declarations}.  \n\\end{itemize}\n\nThe basic XPR printer takes a reference to an \\emph{std::ostream} --- which is\nthe stream into which it will insert the XPR syntax of whatever nodes it is\nasked to print.  A typical construction is \n\\begin{Program}\n  \\#include <ipr/impl>\n  \\#include <ipr/io>\n  \\#include <iostream>\n  int main() \n  \\{\n      ipr::impl::Unit unit;\n      // construct IPR nodes ...\n      // Print them out, starting from the global scope\n      ipr::Printer printer(std::cout);\n      printer << unit;\n      std::cout << std::endl;\n      // ...\n  \\}\n\\end{Program}\n\n\\bibliographystyle{amsalpha}\n\\bibliography{ipr}\n\n\n\\end{document}\n\n\n\n%%% Local Variables: \n%%% mode: latex\n%%% TeX-master: t\n%%% End: \n"
  },
  {
    "path": "include/ChangeLog",
    "content": "2015-12-20  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Introduce Module_name, Module_unit,\n\tInterface_unit, Module.  Rename Unit to Translation_unit.\n\tTranslation_unit is now a class hierarchy root, outside Node.\n\t* ipr/impl: Implement.\n\n2015-12-19  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Introduce ipr::Lexicon, split from ipr::Unit.\n\t* ipr/impl: Implement.\n\n2015-12-17  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Add Optional<T>.  Use it to capture commonality\n\tof optional node properties.\n\t* ipr/impl: Propagate changes.\n\n2015-12-16  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Replace Type_sizeof and Expr_sizeof with Sizeof.\n\tSimilarly, replace Type_typeid and Expr_typeid with Typeid.\n\t* ipr/impl: Propagate changes.  Implement.\n\n2015-12-15  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Add Expansion for pack expansions.\n\t* ipr/impl: Implement.\n\n2015-12-14  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Sequence<T>::begin and Sequence<T>::end no longer\n\tvirtual -- they shouldn't have been ever since get() was\n\tcustomization point.\n\n2015-12-14  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Move Decl::Specifier to toplevel.  Rename to\n\tDeclSpecifiers. Now an enum class with fixed underlying type.\n\n2015-12-14  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Add ipr::Auto type node.\n\n2015-12-14  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: 'auto' is no longer a storage-class specifier in\n\tC++11 and up.\n\n2015-12-14  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Move Type::Qualifier to toplevel.  Rename to\n\tType_qualifier. Adjust users.\n\n2015-12-14  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interface: Add TokenCategory, TokenValue, Token, Attribute,\n\tBasicAttribute, ScopedAttribute, LabeledAttribute,\n\tCalledAttribute, and Attribute::Visitor.\n\t* ipr/impl: Implement.\n\n2015-11-29  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* ipr/interfce: Modify ipr::Enum to account for scoped enumerations.\n\t* ipr/impl: Implement modifications.\n\n2015-11-22  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* Move all source header files into dedicated ipr/ directory.\n\tSimplifies build and installation setup.\n\n2015-11-19  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* impl.hxx (impl::stable_farm<>): New.\n\tUse in lieu of homegrown util::slist<T>.\n\t(util::slist<>): Remove.\n\t* traversal.hxx (ipr): Remove workarounds for ancient VC++.\n\n2010-11-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (expr_factory::make_phantom): Add overload taking a type\n\targument. \n\n2010-07-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::expr_factory::make_id_expr): Add new overload for Decl.\n\n2010-05-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Initializer_list): New.\n\t* impl.H: Provide implementation for Initializer_list.\n\n2010-04-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Unit::get_typename): Declare.\n\t* impl.H (impl::Unit::get_typename): Likewise.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (expr_factory::make_identifier): Add overloads.\n\t(expr_factory::make_operator): Likewise.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (C_linkage): Remove.\n\t(Cxx_linkage): Likewise.\n\t(Visitor::visit(const C_linkage&)): Likewise.\n\t(Visitor::visit(const Cxx_linkage&)): Likewise.\n\t* impl.H (Unit::get_linkage): Move to...\n\t(expr_factory::get_linkage): ... here.\n\t(type_factory::make_as_type): Add unary overload.\n\t(Unit::get_cxx_linkage): Simplify return type.\n\t(Unit::get_c_linkage): Likewise.\n\t(Unit::cxx_linkage): Remove.\n\t(Unit::c_linkage): Likewise.\n\t(Unit::linkages): Move to ...\n\t(expr_factory::linkages): ...here.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (expr_factory::make_literal): Add overloads for 'const\n\tchar*' and 'const std::string&'.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unit::get_string): Move to...\n\t(expr_factory::get_string): ... here.\n\n2009-09-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Rvalue_reference): New IPR node type for\n\trvalue-reference types.\n\t(Visitor::visit): Overload for Rvalue_reference.\n\t* node-category.def: Add rvalue_reference_cat.\n\t* impl.H (impl::Rvalue_reference): New type alias for\n\tipr::Rvalue_reference implementation.\n\t(type_factory::make_rvalue_reference): New.\n\n2009-06-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\tVersion 0.43\n\t* interface.H (For_in): New IPR node type.\n\t* impl.H (impl::For_in): New.\n\n2008-11-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Mapping::has_result): Remove.\n\t(Decl::Constexpr): New specifier.\n\n2008-11-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::Builtin): Simplify.\n\n2008-11-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::Builtin): Set this->id.\n\n2008-11-19  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Stmt::source_location): New.\n\t* impl.H (impl::Stmt::source_location): Implement.\n\n2008-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Datum): Now member of Classic.  The implementation\n\twas already in Classic, so this just fix a thinko.\n\n2008-09-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Classic): Now non-template.  Propogate change\n\tthroughout. \n\n2008-06-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Var::membership): Remove.\n\t* impl.H (impr::Var::membership): Likewise.\n\t(impl::Var::member_of): Likeise.\n\t(Udt<>::impl::declare_var): Don't set member_of.\n\n2008-05-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\n\t* interface.H (Decl::lexical_region): Declare.\n\t(Decl::home_region): Likewise.\n\t* impl.H (impl::Fundecl::lexical_region): Declare.\n\t(impl::Typedecl::lexical_region): Likewise.\n\t(impl::Bitfield::lexical_region): Likewise.\n\t(impl::Bitfield::home_region): Likewise.\n\t(impl::Field::lexical_region): Likewise.\n\t(impl::Field::home_region): Likewise.\n\t(impl::Var::lexical_region): Likewise.\n\t(impl::Alias::lexical_region): Likewise.\n\t(impl::Named_map::lexical_region): Likewise.\n\n2005-11-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* lexer.H: New.\n\n2005-09-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Unit::Ellipsis): Declare.\n\t(Unit::Class): Likewise.\n\t(Unit::Union): Likewise.\n\t(Unit::Enum): Likewise.\n\t(Unit::Namespace): Likewise.\n\n2005-09-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::unary_node): New.\n\t(impl::unary_expr): Use it as base class.  Refactor.\n\t(impl::unar_expr::rep): Remove, now inherited from impl::unary_node.\n\t(impl::unary_expr::operand): Remove, now implemened by\n\timpl::unar_node.\n\n\t(impl::Linkage): New; implement ipr::Linkage.\n\n\t* node-category.def (linkage_cat): New.\n\t* interface.H (Linkage): New.\n\t(Visitor::visit(const Linkage&)): New.\n\n2005-05-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::Mapping::nesting_level): New.\n\t(impl::Mapping::depth): Override ipr::Mapping::depth.\n\t(impl::Mapping::Mapping): Adjust.\n\t(impl::expr_factory::make_mapping): Take an additional \"level\"\n\tparameter.\n\t(impl::unique_decl<>::scope_pos): Remove.\n\t(impl::unique_decl<>::position): Remove.\n\t(impl::Parameter::constraint): Remove.\n\t(impl::Parameter::abstract_designator): New.\n\t(impl::Parameter::position): New.\n\t(impl::Parameter::Parameter): Adjust signature.\n\t(impl::Base_type::scope_pos): New, declare.\n\t(impl::Base_type::Base_type): Adjust signature.\n\t(impl::Base_type::position): Override ipr::Decl::position.\n\t(impl::Enumerator::scope_pos): New, declare.\n\t(impl::Enumerator::Enumerator): Adjust signature.\n\t(impl::Enumerator::position): Override ipr::Decl::position.\n\t(impl::Parameter_list::add_member): Adjust signature.\n\t(impl::expr_factory::rname_for_next_param): Rename from\n\timpl::expr_factory::make_rname.\n\t(impl::Unit::make_parameter): New.\n\n\t* interface.H (Mapping::depth): New.\n\t\n\t* io.H (Printer::operator<<(int)): Define.\n\n\t* impl.H (impl::Rname): New.\n\t(impl::expr_factory::make_rname): Likewise.\n\t(impl::expr_factory::rnames): Likewise.\n\t* interface.H (Visitor::visit(const Rname&)): New.\n\t* node-category.def (rname_cat): New.\n\t* interface.H (Rname): New.\n\n2005-04-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H (xpr_decl::needs_newline): New.\n\t(xpr_decl::xpr_decl): Take an additional parameter.\n\n2005-04-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Makefile.am: Tidy.\n\n2005-04-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::unary_expr::unary_expr): Initialize constraint.\n\t(impl::binary_expr::binary_expr): Likewise.\n\t(impl::ternary_expr::ternary_expr): Likewise.\n\n2005-03-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Makefile.am (stamp-ipr): Avoid symbolic links with relative\n\tpaths. It does not work.\n\n2005-03-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (stats:all_nodes_count): Declare.\n\t(stats::node_count): Likewise.\n\n\t* Makefile.am (ipr_srchdr): Add node-category.def\n\t(stamp-ipr): Set link for node-category.def too.\n\t(install-data-local): Install node-category too.\n\t* Makefile.in: Regenerate.\n\n\t* impl.H: Revert previous changes relating to constructor definition.\n\n2005-03-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (of_same_category): New function.\n\t(Node::Node): Make protected.\n\t(Node::kind): Remove.\n\t(Comment::Comment): Define.\n\t(Annotation::Annotation): Likewise.\n\t(Region::Region): Likewise.\n\t(Expr::Expr): Likewise.\n\t(Name::Name): Likewise.\n\t(Identifier::Identifier): Likewise.\n\t(Operator::Operator): Likewise.\n\t(Conversion::Conversion): Likewise.\n\t(Scope_ref::Scope_ref): Likewise.\n\t(Template_id::Template_id): Likewise.\n\t(Ctor_name::Ctor_name): Likewise.\n\t(Dtor_name::Dtor_name): Likewise.\n\t(Overload::Overload): Likewise.\n\t(Scope::Scope): Likewise.\n\t(Type::Type): Likewise.\n\t(Type_id::Type_id): Likewise.\n\t(Product::Product): Likewise.\n\t(Sum::Sum): Likewise.\n\t(Decltype::Decltype): Likewise.\n\t(Pointer::Pointer): Likewise.\n\t(Ptr_to_member::Ptr_to_member): Likewise.\n\t(Reference::Reference): Likewise.\n\t(Array::Array): Likewise.\n\t(As_type::As_type): Likewise.\n\t(Udt::Udt): Likewise.\n\t(Namespace::Namespace): Likewise.\n\t(Class::Class): Likewise.\n\t(Union::Union): Likewise.\n\t(Enum::Enum): Likewise.\n\t(Template::Template): Likewise.\n\t(Classic): Take additional template parameter.\n\t(Classic::Classic): Define.\n\t(Address, Array_delete, Complement, Delete, Deref, Expr_sizeof,\n\tExpr_typeid, Unary_minus, Not, Post_decrement, Post_increment,\n\tPre_decrement, Pre_increment): Have Classic the node category code\n\tas argument. \n\t(Paren_expr::Paren_expr): Define.\n\t(Expr_list::Expr_list): Likewise.\n\t(Label::Label): Likewise.\n\t\n\n2005-03-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::Overload, impl::single_overload,\n\timpl::empty_overload): Have Node<ipr::Overload,\n\tipr::overload_node> as base class. \n\t(impl::Overload::accept, impl::single_overload::accept,\n\timpl::empty_overload::accept): Remove. \n\t(impl::unary_expr<>::accept): Remove.\n\t(impl::Type<>::accept): Remove.\n\t(impl::type_sequence<>): Have Node<ipr::Product, ipr::product> as\n\tbase type.\n\t(impl::basic_expr<>::accept): Remove.\n\t(impl::conversion_expr<>::accept): Remove.\n\t(impl::ternary_expr<>::accept): Remove.\n\t(impl::Decl<>::accept): Remove.\n\t(impl::unique_decl<>::accept): Remove.\n\t(impl::homogeneous_scope<>): Have Node<ipr::Scope,\n\tipr::scope_node> as base class.\n\t(impl::homogeneous_scope<>::accept): Remove.\n\t(impl::homogeneous_region<>::accept): Remove.\n\t(impl::Comment): Have Node<ipr::Comment, ipr::comment_node> as\n\tbase class.\n\t(impl::Comment::accept): Remove.\n\t(impl::Expr_list): Have Node<ipr::Expr_list, ipr::expr_list_node>\n\tas base class.\n\t(impl::Expr_list::accept): Remove.\n\t(impl::Identifier): Have Node<ipr::Identifier,\n\tipr::identifier_node> as base class.\n\t(impl::Identifier::accept): Remove.\n\t(impl::Id_expr): Have Node<ipr::Id_expr, ipr::Id_expr_node> as\n\tbase class. \n\t(impl::Id_expr::accept): Remove.\n\t(impl::Operator): Have Node<ipr::Operator, ipr::operator_node> as\n\tbase class.\n\t(impl::Operator::accept): Remove.\n\t(impl::Paren_expr): Have Node<ipr::Paren_expr,\n\tipr::paren_expr_node> as base class.\n\t(impl::Paren_expr::accept): Remove.\n\t(impl::Region) Have Node<ipr::Region, ipr::region_node> as base class.\n\t(impl::Region::accept): Remove.\n\t(impl::Scope): Have Node<ipr::Scope, ipr::scope_node> as base class.\n\t(impl::Scope::accept): Remove.\n\t(impl::Enum): Have impl::Node<impl::Type<ipr::Enum>,\n\tipr::enum_node> as base class.\n\t(impl::Break): Have impl::Node<ipr::Break, ipr::break_node> as\n\tbase class.\n\t(impl::Break::accept): Remove.\n\t(impl::Continue): Have impl::Node<ipr::Continue,\n\tipr::continue_node> as base class.\n\t(impl::Continue::accept): Remove.\n\t(impl::Block): impl::Node<ipr::Block, ipr::block_node> as base\n\tclass.\n\t(impl::Block::accept): Remove.\n\t(impl::For): Have impl::Node<ipr::For, ipr::for_node> as base class.\n\t(impl::For:accept): Remove.\n\t(impl::Type_id::accept): Remove.\n\t(impl::Literal::accept): Remove.\n\t(impl::Mapping::accept): Remove.\n\n\t* interface.H (Node_kind): New enumeration.\n\t(Basic_node<>): New.\n\t(Node::kind): New.\n\t(Comment): Make Basic_node<Node, comment_node> a base class.\n\t(Annotation): Make Basic_node<Node, comment_node> a base class.\n\t(Region): Make Basic_node<Node, region_node> a base class.\n\t(Identifier): Make Basic_node<Name, identifier_node> a base class.\n\t(Operator): Have Basic_node<Name, operator_node> as base class.\n\t(Conversion) Have Basic_node<Name, conversion_node> as base class.\n\t(Scope_ref): Have Basic_node<Name, scope_ref_node> as base class.\n\t(Template_id): Have Basic_node<Name, template_id_node> as base class.\n\t(Ctor_name): Have Basic_node<Name, ctor_name_node> as base class.\n\t(Ctor_name): Have Basic_node<Name, dtor_name_node> as base class.\n\n\t* node-kind.def: New file.  Define Node_code enumerators.\n\n\t* impl.H (impl::Id_expr): New. Implement corresponding interface.\n\t(expr_factory::id_exprs): New.\n\t(expr_factory::make_id_expr): Declare.\n\n\t* interface.H (Id_expr): New.\n\t(Visitor::visit(const Id_expr&)): Declare.\n\n\t* impl.H (impl::Mapping::value_type): New.\n\t(impl::Mapping::result_type): Declare.\n\t* interface.H (Mapping::result_type): New.\n\n2005-03-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H (xpr_type): New.\n\t(operator<<(Printer&, xpr_type)): Likewise.\n\n2005-03-10  Peter Pirkelbauer <peter.pirkelbauer@tamu.edu>\n\n\t* impl.H (Classic<>): Change type of op_impl/impl_decl() from\n\tconst ipr::Fundecl* to const ipr::Decl*.\n  \n        * interface.H (Classic<>): Change type of impl_decl() from const\n\tipr::Fundecl* to const ipr::Decl* \n\n2005-03-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Classic<>): New.\n\n\t* Mark for 0.34\n\n2005-02-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::Unit::global_ns): Make public.\n\n2005-02-18  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Var::membership): New.\n\t(Typedecl::membership): New.\n\n\t* impl.H (impl::Class::add_base): Rename to declare_base.\n\t(impl::Var::member_of): New.\n\t(impl::Var::membership): Declare.\n\t(impl::Typedecl::member_of): New.\n\t(impl::Typedecl::membership): New.\n\n2005-02-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H: Rename Expr_as_type to As_type\n\t* impl.H: Likewise. Rename make_expr_as_type to make_as_type.\n\tRename heterogeneous_scope so Scope.\n\tRename heterogeneous_region to Region.\n\t(impl::Region::declare_bitfield): Define.\n\t\n\t* impl.H (impl::Datum): Fix thinko.\n\n2005-02-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.H (impl::util::rb_tree::container<>::find_slot): Fix thinko.\n\t(impl::util::rb_tree::container<>::find): Rework.\n\t(impl::util::rb_tree::container<>::insert): Likewise.\n\t(impl::util::rb_tree::container<>::find_slot): Remove.\n\n2005-02-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::basic_map): Remove.\n\t(impl::master_map_data): Likewise.\n\t(impl::Impl): Rename to impl::decl_rep.\n\t(impl::primary_map_data): Remove.\n\t(impl::basic_map_data): Likewise.\n\t(impl::decl_factory::decls): Make public.\n\t(impl::decl_factory::master_info): Likewise.\n\t(impl::Fundecl::init): Make non-const.\n\t(impl::heterogeneous_scope::make_secondary_map): Adjust type.\n\t(impl::heterogeneous_scope::master_primary_map_info): Remove.\n\t(impl::heterogeneous_scope::master_secondary_map_info): Likewise.\n\t(impl::heterogeneous_scope::maps): Likewise.\n\t(impl::heterogeneous_region::declare_primary_map): New.\n\t(impl::heterogeneous_region::declare_secondary_map): Likewise.\n\n2005-02-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H (Printer::operator<<): Define overloads for \n\tcharacters.\n\t(needs_newline): Remove.\n\t(newline): Likewise.\n\n\t* impl.H (impl::Fundecl::init): Make non-const.\n\n2005-02-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H (Token): Remove.\n\t(operator<<(Printer&, Printer& (*)(Printer&))): Likewise.\n\t(Printer::operator<<): Remove template declaration.  Add\n\tindividual declaration.\n\n\t* impl.H (impl::heterogeneous_region::declare_alias): New.\n\t(impl::heterogeneous_region::declare_var): Likewise.\n\t(impl::heterogeneous_region::declare_field): Likewise\n\t(impl::heterogeneous_region::declare_typedecl): Likewise.\n\t(impl::heterogeneous_region::declare_fundecl): Likewise.\n\n\t(impl::Udt<>::decl): Remove.\n\t(impl::Udt<>::id): New.\n\t(impl::Udt<>::name): Adjust.\n\t(impl::Udt<>::Udt): Likewise.\n\t(impl::Enum::decl): Remove.\n\t(impl::Enum::id): New.\n\n2005-02-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::Class::add_base): New.\n\n2005-02-06  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.33\n\n\t* io.H (xpr_decl): Rename from xpr_declaration.\n\t(xpr_stmt): Rename from xpr_statement.\n\t(xpr_expr): Rename from xpr_expression.\n\n\t* interface.H (Unit::global_members): Remove.\n\n\t* impl.H (impl::ref_sequence<>): Tidy.\n\t(impl::Decl<>): Document.\n\t(impl::unique_decl<>): Likewise.\n\t(impl::homogeneous_sequence<>): Tidy.\n\t(impl::homogeneous_sequence::push_back): New.\n\t(impl::homogeneous_scope<>): Tidy.\n\t(impl::homogeneous_scope::push_back): New.\n\t(impl::homogeneous_region::size): New.\n\t(impl::homogeneous_region::get): New.\n\t(impl::homogeneous_region::type): New.\n\t(impl::Expr_list): Make a class.  Support push_back operation.\n\t(impl::heterogeneous_scope): Tidy.  Document.\n\t(impl::Udt<>): Liekwise.\n\t(impl::type_factory): Likewise.\n\t(impl::Break): Document.\n\t(impl::Conitnue): Likewise.\n\t(impl::stmt_factory): Tidy.\n\t(impl::Fundecl::init): Rename from impl::Fundecl::expr.\n\t\n\t\n\n2005-02-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (impl::ref_sequence<>): Import members \"begin\", \"end\".\n\t(impl::Unit::make_expr_list): Take an impl::ref_sequence.\n\t(impl::Unit::make_product): Likewise.\n\t(impl::Unit::make_sum): Likewise.\n\t(impl::Unit::expr_seqs): New.\n\t(impl::Unit::type_seqs): Likewise.\n\n2005-02-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Unary<>::Category): Remove.\n\t(Binary<>::Category): Likewise.\n\t(Ternary<>::Category): Likewise.\n\n2005-02-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.31.\n\n\t* utility.H (util::rb_tree::core<>::rotate_right): Fix thinko.\n\t(util::rb_tree::container<>::insert): Likewise.\n\t(util::slist<>::push_back): New overload.\n\n\t* impl.H (impl::Type<>::constraint): Remove.\n\t(impl::Type<>::Type): Likewise.\n\t(impl::Type<>::type): Likewise.\n\t(impl::elaborated_type<>::id): Change type from impl::Type_id to\n\tipr::Name*.\n\t(impl::typed_sequence<>::constraint): New.\n\t(impl::typed_sequence<>::typed_sequence): Likewise.  \n\t(impl::homogeneous_scope<>::homogeneous_scope): Likewise.\n\t(impl::homogeneous_region<>::homogeneous_region): Take additional\n\tparameter. \n\t(impl::Parameter_list::Parameter_list): Likewise.\n\t(impl::Type_id): Make a class.\n\t(impl::Mapping::Mapping): Take additional parameter.\n\t(impl::Scope_ref): Make a typedef.\n\t(impl::expr_factory::makde_ctor_name): New.\n\t(impl::expr_factory::make_dtor_name): New.\n\t(impl::expr_factory::make_type_id): New.\n\t(impl::expr_factory::make_mapping): Take additional parameter.\n\t(impl::basic_map_data::basic_map_data): Lose the last parameter.\n\t(impl::heterogeneous_scope::heterogeneous_scope): Take additional\n\tparameter.\n\t(impl::heterogeneous_region): Move member definitions out of\n\tclass.\n\t(impl::Udt<>::constraint): New.\n\t(impl::Udt<>::Udt): Take additional parameter.\n\t(impl::Enum::constraint): New.\n\t(impl::Enum::Enum): Take additional parameter.\n\t(impl::Class::Class): Likewise.\n\t(impl::Block::Block): Likewise.\n\t(impl::stmt_factory::make_block): Likewise.\n\t(impl::Unit::global_ns): Change type to pointer.\n\n2005-01-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.30.\n\t* impl.H: Add more docuementation.\n\t(impl::Overload): Tidy.\n\t(impl::singleton_overload): New.\n\t(impl::unique_decl<>): New. \n\t(impl::Parameter): Derive from impl::unique_decl<>.\n\t(impl::Base_type): Likewise.\n\t(impl::Enumerator): Likewise.\n\t(impl::empty_overload): New.\n\t(impl::homogeneous_scope): Use it.\n\t(impl::heterogeneous_scope): Likewise.\n\t* utility.H (util::slist<>): Don't derive from std::allocator<>.\n\t(util::slist<>::allocate): New.\n\t(util::slist<>::deallocate): Likewise.\n\n2005-01-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.29\n\t* utility.H (util::rb_tree): Rework.\n\n\t* interface.H (Node::node_id): New.\n\t(Type): Tidy.\n\t(Fundecl::throws): Remove.\n\t(Fundecl::target): Likewise.\n\n\t* impl.H (impl::decl_sequence::get): Make public.\n\t(impl::overload_datum::type): Make a reference.\n\t(impl::master_decl_data::master_decl_data): Take a type as parameter.\n\t(impl::Overload::lookup): New.\n\t(impl::singleton_overload::type): Declare.\n\t(impl::basic_type::accept): Define.\n\t(impl::typed_sequence): New.\n\t(impl::conversion_expr<>::Rep): New.\n\t(impl::conversion_expr<>::conversion_expr): Use it.\n\t(impl::Parameter::overload): Rename from impl::Parameter::declseq.\n\t(impl::Base_type::overload): Rename from impl::Base_type::declseq.\n\t(impl::Enumerator::overload): Rename from\n\timpl::Enumerator::declseq.\n\t(impl::homogeneous_sequence<>): Tidy.\n\t(impl::homogeneous_scope<>): Likewise.\n\t(impl::Parameter_list::type): New.\n\t(impl::redecl<>): Tidy.\n\t(impl::first_decl<>): Likewise.\n\t(impl::type_factory): Likewise.\n\t(impl::Identifier::Less): New.\n\t(impl::Literal): Tidy.\n\t(impl::Mapping): Likewise.\n\t(impl::expr_factory): Likewise.\n\t(impl::Var): Robustify.\n\t(impl::Bitfield): Likewise.\n\t(impl::Typedecl): Likewise.\n\t(impl::Fundecl): Likewise.\n\t(impl::heterogeneous_scope): Tidy.\n\t(impl::decl_factory): Robustify.\n\t(impl::Enum::accept): Remove.\n\t(impl::type_factory): New.\n\t(impl::Block): Tidy.\n\t(impl::Break): Likewise.\n\t(impl::Continue): Likewise.\n\t(impl::stmt_factory): Likewise.\n\t(impl::Unit): Likewise.\n\n2005-01-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.H: Move red-black tree implementations to namespace\n\tipr::util::rb_tree.  Rename data types.\n\t(util::rb_tree::link::as): Remove.\n\t(util::rb_tree::core::root): Tweak.\n\n\t* interface.H (Expr_in_parens): Rename to ...\n\t(Paren_expr): ... this.\n\t(Add): Rename to ...\n\t(Plus): ... this.\n\t(Add_assign): Rename to...\n\t(Plus_assign): ... this.\n\t(C_cast): Rename to ...\n\t(Cast): ... this.\n\t(Value): Rename to ...\n\t(Datum): ... this.\n\t(Scheme): Rename to ...\n\t(Mapping): ... this.\n\t(Sub): Rename to ...\n\t(Minus): ... this.\n\t(Sub_assign): Rename to ...\n\t(Minus_assign): ... this.\n\t(Pattern): Rename to ...\n\t(Named_map): ... this.\n\t(Overload::region): Comment out.\n\t(Namespace::Member): New.\n\t(Enum::Member): Likewise.\n\t(Class::Member): Likewise.\n\t(Union::Member): Likewise.\n\t(Negate): Rename to ...\n\t(Unary_minus): ... this.\n\n\t* impl.H: Rewrite from scratch.  Move implementation classes to \n\tipr::impl.\n\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* traversal.H (physically_same): New.\n\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.28.\n\t\n2005-01-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Makefile.am: New.\n\t* Makefile.in: Likewise.\n\t* impl.H (\"ipr/interface.H\"): Change to <ipr/interface>\n\t(\"ipr/utility.H\"): Change to <ipr/utility>.\n\t* io.H (\"ipr/interface.H\"): Change to <ipr/interface>\n\t* traversal.H (\"ipr/interface.H\"): Change to <ipr/interface>.\n\n2005-01-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Move files from $ROOT/ipr to here. \n\t\n2005-01-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.27.\n\t\n2005-01-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.H (util::rb_tree<>::destroy_node): Tidy.\n\t(util::slist<>::~slist): Likewise.\n\n\t* io.H (operator<<(Printer&, const Unit&)): Declare.\n\n\t* interface.H (Type_expr): Rename to ...\n\t(Expr_ast_type): ... this.\n\t(Arrow_select): Rename to ...\n\t(Arrow): ... this.\n\t(Dot_select): Rename to ...\n\t(Dot): ... this.\n\t(Scheme): New data type.  Implemenet paramerized expressions.\n\t(Bit_field): Rename to ...\n\t(Bitfied): ... this.\n\t(Fun_decl): Rename to ...\n\t(Fundecl): ... this.\n\t(Type_decl): Rename to ...\n\t(Typedecl): ... this.\n\t(Template_decl): Rename to ...\n\t(Pattern): ... this.\n\t(Region::decls): Rename to ...\n\t(Region::bindings): ... this.\n\t(Class::base_scope): Remove.\n\t(Parameter_list): Make simple a Node that is also a\n\tSequence<Parameter>. \n\t(Visitor): Adjust member functions to reflect renaming.\n\t(Visitor::visit(const Scheme&)): New.\n\n\t* impl.H (Sequence_impl<>): Take an additional template\n\targument, in case we're implementing a derived interface\n\tof Sequence<>.\n\t(Value_sequence<>): Implement Sequence<>, but stores actual\n\tvalues, not pointers.\n\n\t(Expr_impl<>::type_impl): Remove.\n\t(Expr_impl<>::constraint): Make public.\n\n\t(Scope_impl<>::register_decl): Remove.\n\n\t(Region_impl<>::scope): Remove.\n\t(Region_impl<>::decls_impl): Likewise.\n\t(Region_impl<>::span_impl): Likewise.\n\t(Region_impl<>::owner_impl): Likewise.\n\t(Region_impl<>::owned_by): Make public.\n\t(Region_impl<>::locs): Rename to ...\n\t(Region_impl<>::extent): ... this.\n\t(Region_impl<>::decl_seq): Rename to ...\n\t(Region_impl<>::decls): ... this.\n\n\t(Udt_impl<>::decl_impl): Remove.\n\t(Udt_imp<>::region_impl): Likewise.\n\t(Udt_impl<>::scope_impl): Likewise.\n\t(Udt_impl<>::typedecl): Make public.\n\t(Udt_impl<>::body): Likewise.\n\n\t(Stmt_impl<>::loc): Rename to ...\n\t(Stmt_impl<>::unit_locus): ... this.  Make public.\n\t(Stmt_impl<>::attrs): Rename to ...\n\t(Stmt_impl<>::notes): ... this.\n\t(Stmt_impl<>::unit_location_impl): Remove.\n\t(Stmt_impl<>::annotation_impl): Likewise.\n\n\t(Decl_impl<>::spec): Make public.\n\t(Decl_impl<>::init): Likewise.\n\t(Decl_impl<>::specifiers_impl): Remove.\n\t(Decl_impl<>::scope_impl): Likewise.\n\t(Decl_impl<>::initializer_impl): Likewise.\n\t(Decl_impl<>::register_to): Likewise.\n\n\t(Decl_with_name<>::id): Make public.\n\t(Decl_with_name<>::pat): Likewise.\n\t(Decl_with_name<>::tmpl_args): Likewise.\n\n\t(Enumerator_impl::membership): Move defintion out of line.\n\t(Enumerator_impl::Enumerator_impl): Likewise.\n\n\t(Enum_impl::add_member): New member function.\n\n\t(combined_sequence<Decl>::enums): Remove.\n\t(combined_sequence<Decl>::classes): Likewise.\n\t(combined_sequence<Decl>::namespaces): Likewise.\n\t(combined_sequence<Decl>::unions): Likewise.\n\n\t(Parameter_list_impl): Derive from Node_impl<Value_sequence\n\t<Parameter_impl, Parameter_list> >.\n\n\t(Scheme_impl): New.  Implement Scheme.\n\n\t(Class_impl::base_scope): Remove.\n\t(Class_impl::bases_impl): Likewise.\n\t(Class_impl::bases): Move definition out of line.\n\t(Class_impl::Class_impl): Likewise.\n\t(Class_impl::baseobjs): Rename to ..\n\t(Class_impl::base_subobjects): ... this.\n\n\t(Block_impl::Block_impl): Move definition out of line.\n\t(Block_impl::members): Likewise.\n\t(Block_impl::body): Likewise.\n\t(Block_impl::handlers): Likewise.\n\t(Block_impl::members_impl): Remove.\n\t(Block_impl::stmts_impl): Likewise.\n\t(Block_impl::handlers_impl): Likewise.\n\t(Block_impl::zone): Rename to ...\n\t(Block_impl::region): ... this.\n\t(Block_impl::stmt_seq): Make public.\n\t(Block_impl::handler_seq): Likewise.\n\n\t(For_impl::For_impl): Move definition out of line.\n\t(For_impl::initializer): Likewise.\n\t(For_impl::condition): Likewise.\n\t(For_impl::increment): Likewise.\n\t(For_impl::body): Likewise.\n\t(Break_impl::Break_impl): Likewise.\n\t(Break_impl::from): Likewise.\n\t(Continue_impl::Continue_impl): Likewise.\n\t(Continue_impl::iteration): Likewise.\n\n\t(Fun_decl_impl): Rename to ...\n\t(Fundecl_impl): ... this.  Move all in-class definitions out of\n\tline. \n\t(Fundecl_impl::params): Remove.\n\n\t(Var_impl::Var_impl): Move definition our of line.\n\t(Var_impl::definition): Likewise.\n\t(Alias_impl::Alias_impl): Likewise.\n\t(Field_impl::Field_impl): Likewise.\n\t(Field_impl::membership): Likewise.\n\n\t(Bit_field_impl): Rename to ...\n\t(Bitfield_impl): ... this.\n\t(Bitfield_impl::Bitfield_impl): Move definition out of line.\n\t(Bitfield_impl::membership): Likewise.\n\t(Bitfield_impl::size): Rename to ...\n\t(Bitfield_impl::precision): ... this.  Move definition out of\n\tline.\n\t(Type_decl_impl): Rename to ...\n\t(Typedecl_impl): ... this.\n\t(Typedecl_impl::Typedecl_impl): Move definition out of line.\n\t(Typedecl_impl::definition): Likewise.\n\t(Template_decl_impl): Split into primary_pattern and\n\tspecialized_pattern.  Remove.\n\t(basic_pattern): New.\n\t(primary_pattern): New. Implement primary templates.\n\t(specialized_pattern): New.  Implement partial and explicit\n\tspecializations of templates.\n\n\t(Address_impl, Array_delete_impl, Complement_impl,\n\tConversion_impl, Ctor_name_impl, Dtor_name_impl, Delete_impl,\n\tDeref_impl, Expr_in_parens_impl, Expr_list_impl, Expr_sizeof_impl, \n\tExpr_typeid_impl, Identifier_impl, Negate_impl, Not_impl,\n\tOperator_impl, Pre_increment_impl, Pre_decrement_impl,\n\tPost_increment_impl, Post_decrement_impl, Throw_impl,\n\tType_id_impl, Type_sizeof_impl, Type_typeid_impl, Unary_plus_impl,\n\tAdd_impl, Add_assign_impl, And_impl, Annotation_Impl,\n\tArray_ref_impl, Arrow_impl, Arrow_star_impl, Assign_impl,\n\tBitand_impl, Bitand_assign_impl, Bitor_impl, Bitor_assign_impl,\n\tBitxor_impl, Bitxor_assign_impl, C_cast_impl, Call_impl,\n\tComma_impl, Const_cast_impl, Div_impl, Div_assign_impl, Dot_impl,\n\tDot_star_impl, Dynamic_cast_impl, Equal_impl, Greater_impl,\n\tGreater_equal_impl, Less_impl, Less_equal_impl, Literal_impl,\n\tLshift_impl, Lshift_assign_impl, Member_init_impl, Modulo_impl,\n\tModulo_assign_impl, Mul_impl, Mul_assign_impl, Not_equal_impl,\n\tOr_impl, Reinterpret_cast_impl, Rshift_impl, Rshift_assign_impl,\n\tScope_ref_impl, Static_cast_impl, Sub_impl, Sub_assign_impl,\n\tTemplate_id_impl, Value_impl, New_impl, Conditional_impl):\n\tIntroduce as typedefs for interface implementations.\n\n\t(Expr_builder): Adjust signatures of all member functions.\n\n\t(Unit_impl::global_region): Tidy.\n\t(Unit_impl::global_scope): Likewise.\n\t(Unit_impl::make_alias): Remove.\n\t(Unit_impl::make_enumerator): Likewise.\n\t(Unit_impl::make_base_type): Likewise.\n\t(Unit_impl::make_fun_decl): Likewise.\n\t(Unit_impl::make_var): Likewise.\n\t(Unit_impl::make_field): Likewise.\n\t(Unit_impl::make_bit_field): Likewise.\t\n\n2005-01-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Sequence<>::Position): Remove.\n\t(Sequence<>::get): Adjust signature.\n\t(Sequence<>::operator[]): Likewise.\n\t(Sequence<>::Iterator::Position): Remove.\n\t(Sequence<>::Iterator::index): Adjust type.\n\t(Parameter_list): Derive from Udt, instead of scope.\n\n\t* impl.H: Propagate changes in interface.H to implementation\n\tclasses.  \n\t(Empty_sequence::Position): Remove.\n\n\t(combined_sequence<Decl>::decls): New data member.\n\t(combined_sequence<Decl>::size): Define.\n\t(combined_sequence<Decl>::get): Define.\n\n\t* impl.H (Enum_impl::make_enumerator): New member function.\n\t(Unit_impl::make_enumerator): Remove.\n\t(Unit_impl::make_base_type): Remove.\n\t(Unit_impl::make_alias): Move to ...\n\t(combined_sequence<Decl>::make_alias): ... here.\n\n2004-12-30  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Expr_impl<>::Expr_impl()): Initialize constraint.\n\t(combined_sequence<>): New.\n\t(Scope_impl<>): Derive from it.\n\n2004-12-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.H (util::less): New function objects. \n\n2004-12-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.H (util::check): New function.\n\t* impl.H (Checked_ptr): Remove.\n\t(Unit_impl::String): Remove.\n\n2004-12-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* traversal.H (Missing_overrider): New function object.\n\t(missing_overrider):  Turn it into the above function object.\n\n2004-11-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* traversal.H (as): Move from interface.H.\n\t(missing_overrider): Likewise.\n\n\t* interface.H (Lshift): Rename from Shift_left.\n\t(Lshift_assign): Rename from Shift_left_assign.\n\t(Rshift): Rename from Shift_right.\n\t(Rshift_assign): Rename from Shift_right_assign.\n\t* impl.H: Make corresponding changes.\n\n2004-11-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Multi_comment_impl): Remove.\n\n\t* interface.H (Multi_comment): Remove. \n\t(Visitor::visit(const Multi_comment&)): Likewise.\n\n2004-11-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Comment_impl): typedef to instance of Unary_impl<>.\n\t(Multi_comment_impl): Likewise.\n\t(Type_builder): Inherit from table for Ptr_to_member.\n\t(Unit_impl): Inherit from Node_impl<Unit>, instead of Unit.\n\t(Unit_impl::make_ptr_to_member): Declare.\n\n\t* interface.H (Commment): New datatype.\n\t(Multi_comment): Likewise.\n\t(Ptr_to_member): Likewise.\n\t(Visitor::visit(const Comment&)): Declare.\n\t(Visitor::visit(const Multi_comment&)): Likewise.\n\t(Visitor::visit(const Ptr_to_member&)): Likewise.\n\t(Unit): Derive from Node.\n\n2004-11-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Type_expr): Rename from Expr_as_type.\n\t(Template_id): Rename from Specialization.\n\t(Basic_location): New datatype.\n\t(Source_location): Likewise.  Derive from Basic_location.\n\t(Unit_location): Likewise.\n\n\t* impl.H: Likewise.\n\n2004-11-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Decl::template_params): New.\n\t(Decl::template_args): Likewise.\n\n2004-11-06  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Asm): New Decl node.\n\t(Visitor::visit(const Asm&)): New.\n\n2004-11-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Var_impl::definition): Override.\n\t(Var_impl::definition_impl): New.\n\n\t* interface.H (Decl::definition): New.\n\n2004-10-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.26.\t\n\t\n2004-10-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Expr_stmt_impl): Make a typedef to \n\tUnary_impl<Expr_stmt, Stmt_impl<Expr_stmt> >.\n\t(Labeled_stmt_impl): Make a typedef to\n\tBinary_impl<Labeled_stmt, Stmt_impl<Labeled_stmt> >.\n\t(Ctor_body_impl): Make a typedef to\n\tBinary_impl<Ctor_body, Expr_list, Block>.\n\t(If_then_impl): Make a typedef to \n\tBinary_impl<If_then, Stmt_impl<If_then> >.\n\t(If_then_else_impl): Make a typedef to \n\tTernary_impl<If_then_else, Stmt_impl<If_then_else> >.\n\t(Switch_impl): Make a typedef to \n\tBinary_impl<Switch, Stmt_impl<Switch> >\n\t(While_impl): Make a typedef to \n\tBinary_impl<While, Stmt_impl<While> >.\n\t(Do_impl): Make a typedef to Binary_impl<Do, Stmt_impl<Do> >.\n\t(Goto_impl): Make a typedef to Unary_impl<Goto, Stmt_impl<Goto> >.\n\t(Handler_impl): Make a typedef to \n\tBinary_impl<Hander, Stmt_impl<Handler> >.\n\t(Union_impl): Make a typedef to Udt_impl<Union>.\n\t(Namespace_impl): Make a typedef to Udt_impl<Namespace>.\n\n\t* interface.H (Expr_stmt): Derive from Unary<stmt, Expr>.\n\t(Expr_stmt::expr): Forward to Unary<>::operand.\n\t(Labeled_stmt): Derive from Binary<Stmt, Expr, Expr>.\n\t(Labeled_stmt::label): Forward to Binary<>::first.\n\t(Labeled_stmt::stmt): Forward to Binary<>::second.\n\t(Ctor_body): Derive from Binary<Stmt, Expr, Expr>.\n\t(Ctor_body::inits): Forward to Binary<>::first.\n\t(Ctor_body::block): Forward to Binary<>::second.\n\t(If_then): Derive from Binary<Stmt, Expr, Expr>.\n\t(If_then::condition): Forward to Binary<>::first.\n\t(If_then::then_stmt): Forward to Binary<>::second.\n\t(If_then_else): Derive from Ternary<Stmt, Expr, Expr, Expr>.\n\t(If_then_else::condition): Forward to Binary<>::first.\n\t(If_then_else::then_stmt): Forward to Binary<>::second.\n\t(If_then_else::else_stmt): Forward to Binary<>::third.\n\t(Switch): Derive from Binary<Stmt, Expr, Expr>.\n\t(Switch::condition): Forward to Binary<>::first.\n\t(Switch::body): Forward to Binary<>::second.\n\t(While): Derive from Binary<Stmt, Expr, Expr>.\n\t(While::condition): Forward to Binary<>::first.\n\t(While::body): Forward to Binary<>::second.\n\t(Do): Derive from Binary<Stmt, Expr, Expr>.\n\t(Do::condition): Forward to Binary<>::first.\n\t(Do::body): Forward to Binary<>::second.\n\t(Goto): Derive from Unary<Stmt, Expr>.\n\t(Goto::target): Forward to Unary<>::operand.\n\t(Handler): Derive from Binary<Stmt, Decl, Block>.\n\t(Hanlder::expcetion): Forward to Binary<>::first.\n\t(Handler::body): Forward to Binary<>::second.\n\n2004-10-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unary_Factor<>::Impl): Move to enclosing scope...\n\t(Unary_impl<>): As this.\n\n2004-10-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Type_id::type): Define.  This is the type of the\n\ttype.\n\n\t* impl.H (Expr_builder): Move name nodes factories to Unit_impl.\n\t(Unit_impl): Constify return types for unified node factories.\n\t(Type_builder): Expunge almost of member functions.\n\t(Stmt_builder): Move member function deifnitions to src/ipr.C\n\t(Expr_basic_impl<>): Remove.\n\n2004-10-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unit_impl::make_specialization): Declare.\n\n2004-10-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unary_factor<>::Impl::accept()): Remove.\n\t(Binary_factor<>::Impl::accept()): Likewise.\n\t(Ternary_factor<>::Impl::accept()): Likewise.\n\t(Unary_factory): Now take Cat_impl as a template\n\ttemplate-parameter. \n\t(Unary_factory<>::Impl): Inherit from Cat_impl<Interface>.\n\t(Binary_factory): Now take Cat_impl as a template\n\ttemplate-parameter.  \n\t(Binary_factory<>::Impl): Inherit from Cat_impl<Interface>.\n\t(Ternary_factory): Now take Cat_impl as a template\n\ttemplate-parameter.  \n\t(Ternary_factory<>::Impl): Inherit from Cat_impl<Interface>.\n\t(Node_impl<>): New.\n\t(Expr_basic_impl<>): Remove.\n\t(Expr_builder): Tidy.\n\t(Type_builder): Likewise.\n\n2004-10-19  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Template_decl_impl): New.\n\n2004-10-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Template_decl): New.\n\t(Visitor::visit(const Template_decl&)): Likewise.\n\n\t* impl.H (Scope_impl<>::Overload_impl::register_decl): Take the\n\topportunity to set constraint.\n\n2004-10-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Expr_builder): Add table for Expr_in_parens.\n\t(Expr_in_parens::make_expr_in_parens): New.\n\n\t* interface.H (Expr_in_parens): New.\n\t(Visitor::visit(const Expr_in_parens&)): Declare.\n\t(Template::parameterized): Rename from parametree.\n\t(Decl::Export): New enumerator.\n\n2004-09-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.25.\n\n\t* impl.H (Constructor_impl): Remove.\n\t(Destructor): Likewise.\n\t(Unit_impl::make_constructor): Likewise.\n\t(Unit_impl::make_destructor): Likewise.\n\t(Expr_builder): Inherit also from Unary_fatctory<Ctor_name> and\n\tUnary_fatctory<Dtor_name>.\n\t(Expr_builder::make_ctor_name): New.\n\t(Expr_builder::make_dtor_name): Likewise.\n\t(Unit_impl::make_ctor_name): Likewise.\n\t(Unit_impl::make_dtor_name): Likewise.\n\n\t* interface.H (Constructor): Remove.\n\t(Destructor): Likewise.\n\t(Visitor::visit(const Constructor&)): Likewise.\n\t(Visitor::visit(const Destructor&)): Likewise.\n\t(Dtor_name): New node class. \n\t(Ctor_name): Likewise.  For consistency with destructor.\n\t(Visitor::visit(const Dtor_name&)): Declare.\n\t(Visitor::visit(const Ctor_name&)): Likewise.\n\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* traversal.H: New file.\n\n\t* interface.H (Visitor::visit(const Name&)): Don't make pure.\n\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.24\n\t\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Decl_impl<>::register_to): New.\n\n2004-09-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unit_impl::make_fun_decl): Update signature.\n\t(Unit_impl::make_constructor): Likewise.\n\t(Unit_impl::make_destructor): New.\n\n2004-09-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Type_builder): Add table for Sum too.\n\t(Type_builder::make_sum): New.\n\t(Type_builder::make_function): Update.\n\t(Unit_impl::make_sum): New.\n\t(Unit_impl::make_function): Update.\n\n\t* interface.H (Sum): New type node.\n\t(Function): Use it for exception specification list.\n\t(Visitor::visit(const Sum&)): Declare.\n\n2004-08-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.23.\n\t\n2004-08-30  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Visitor::visit(const Exnumerator&)): Add.\n\n2004-08-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Specialization): Derive from Name.\n\n2004-08-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Type_builder): Inherirt from factory for Decltype too.\n\t(Type_builder::make_decltype): New.\n\t(Unit_impl::make_decltype): New.\n\t(Expr_builder::make_identifier): Return Expr_impl<Identifier>*.\n\t(Expr_builder::make_operator): Return Expr_impl<Operator>*.\n\t(Expr_builder::make_conversion): Return Expr_impl<Conversion>*.\n\t(Expr_builder::make_scope_ref): Return Expr_impl<Scope_ref>*.\n\t(Unit_impl::make_identifier): New.\n\t(Unit_impl::make_operator): Likewise.\n\t(Unit_impl::make_conversion): Likewise.\n\t(Unit_impl::make_scope_ref): Likewise.\n\n\t* interface.H (Decltype): New node class.\n\t(Visitor::visit(const Decltype&)): New.\n\n2004-08-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.22.\n\t\n2004-08-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Alias): Add lazy evaluation of type().  It is\n\talways that of the initializer.\n\n2004-08-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Expr_builder::make_scope_ref): Adjust return-type to\n\tScope_ref*. \n\n\t* interface.H (Scope_ref): Derive from Name.\n\n2004-08-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.21.\n\t\n2004-08-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Block::stmts): Revert from previosu change.  Return\n\ta Sequence<Expr> instead of Sequence<Stmt>.\n\t(Labeled_stmt::stmt): Revert from previous change.  Return an\n\tExpr, not Stmt.\n\t(If_then::then_stmt): Likewise.\n\t(If_then_else::then_stmt, If_then_else::else_stmt): Likewise.\n\t(While::body): Likewise.\n\t(Do_while::body): Likewise.\n\t(For::body): Likewise.\n\t(Break::from, Continue::iteration): Likewise.\n\n\t* impl.H (Labeled_stmt_impl): Reflect changes in ipr/initerface.H.\n\t(Block_impl): Likewise.\n\t(If_then_impl): Likewise.\n\t(If_then_else_impl): Likewise.\n\t(Switch_impl): Likewise.\n\t(While_impl): Likewise.\n\t(Do_while_impl): Likewise.\n\t(For_impl): Likewise.\n\t(Break_impl): Likewise.\n\t(Continue_impl): Likewise.\n\t(Stmt_builder::make_do_while): Likewise.\n\t(Stmt_builder::make_if_then): Likewise.\n\t(Stmt_builder::make_switch): Likewise.\n\t(Stmt_builder::make_labeled_stmt): Likewise.\n\t(Stmt_builder::make_switch): Likewise.\n\t(Stmt_builder::make_if_then_else): Likewise.\n\t(Stmt_builder::make_for): Likewise.\n\t(Stmt_builder::make_do): Rename from make_do_while.\n\n\t* interface.H: Simplify Do_while to Do.\n\t* impl.H: Likewise.\n\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.20.\n\t\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Visitor::visit(const Udt&)): New.\n\n\t* impl.H (Block_impl::decls): Make it an integral part of the\n\tblock.\n\t(Block_impl::Block_impl): Also take a Unit_impl parameter.\n\t(Unit_impl::make_block): New.  Forward to Stmt_builder::make_block.\n\n2004-08-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Ctor_body_impl): Rename from Function_body_impl.\n\tImplement Ctor_body interface.\n\t(Quaternary_factory): Remove.\n\t(Expr_stmt_impl): New.  Implement Expr_stmt interface.\n\t(Labeled_stmt_impl): New.  Implement Labeled_stmt interface.\n\t(Block_impl): New. Implement Block interface.\n\t(If_then_impl): New.  Implement If_then interface.\n\t(If_then_else_impl): New.  Implement If_then_else interface.\n\t(Switch_impl): New.  Implement Switch interface.\n\t(While_impl): New.  Implement While interface.\n\t(Do_while_impl): New.  Implement Do_while interface.\n\t(For_impl): New.  Implement For interface.\n\t(Break_impl): New.  Implement Break interface.\n\t(Continue_impl): New.  Implement Continue interface.\n\t(Goto_impl): New.  Implement Goto interface.\n\t(Return_impl): New.  Implement Return interface.\n\t(Handler_impl):  New.  Implement Handler interface.\n\t(Stmt_builder): Rework.\n\t(Unit_impl::make_handler_seq): Remove.\n\t(Unit_impl::hander_seqs): Likewise.\n\n\t* interface.H (Ctor_body, Expr_stmt): New interfaces.\n\t(Function_body): Remove.\n\t(Labeled_stmt, Block, If_then, If_then, If_then_else, Switch,\n\tWhile, Do_while, For, Break, Continue, Goto, Return, Handler):\n\tDerive directly from Stmt.\n\t(Visitor::visit(const Function_body&)): Remove.\n\t(Visitor::visit(const Ctor_body&)): New.\n\t(Visitor::visit(const Expr_stmt&)): Likewise.\n\n2004-08-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.19\n\t\n2004-07-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.18\n\t\n2004-07-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Member_init): Add convenient functions.\n\t* impl.H (Expr_builder<>): Add factory for Member_init.\n\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.17\n\t\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Type_id): New datatype. Interface for type-ids.\n\t(Expr_list): Now a Unary<> expression.  Add subscripting operation.\n\t(Product): Add subscripting operation.\n\t(Name_as_expr): Remove.\n\t(Visitor::visit(const Name_as_expr&)): Remove.\n\t(Visitor::visit(const Type_id&)): New.\n\n\t* impl.H (Type_impl<>): Tidy.\n\t(Scope_impl<>): Temporarily remove protected copy-constructor\n\t(Expr_list_impl<>): Remove.\n\t(Decl_with_name<>): New datatype.\n\t(Parameter_impl): Derive from it.\n\t(Enumerator_impl): Likewise.\n\t(Fun_decl_impl): Likewise.\n\t(Alias_impl): Likewise.\n\t(Var_impl): Likewise.\n\t(Type_impl): All types now have names.\n\t(Type_decl_impl): Likewise.\n\t(Field_impl): Likewise.\n\t(Bit_field_impl): Likewise.\n\t(Type_builder): Add factory for Product.\n\t(Expr_builder): Adjust to make name as expressions.  Add factory\n\tfor Expr_list.\n\t(Unit_impl): Tidy.\n\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.16\n\t\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unary_fatctory<>::make): Overload with a version\n\tthat takes the type of the expression.\n\t(Binary_factor<>::make): Likewise.\n\t(Ternary_factor<>::make): Likewise.\n\t(Stmt_impl<>::annotation): Move from Expr_impl<>.\n\t(Stmt_impl<>::annotation_impl): Likewise.\n\t(Unit_impl::make_pointer): New.\n\t(Unit_impl::make_reference): Likewise.\n\t(Unit_impl::make_expr_as_type): Likewise.\n\t(Unit_impl::make_array): Likewise.\n\t(Unit_impl::make_template): Likewise.\n\t(Unit_impl::make_function): Likwise.\n\t(Unit_impl::built_in_type): Likewise.\n\t(Unit_impl::Builtin<>): Remove.\n\t(Unit_impl::CV_fiber): Tidy to work-around bugs in GCC-3.5.x\n\t(Unit_impl::Typename): New.\n\n2004-07-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Bit_field): New node.\n\t(Field): Likewise.\n\t(Visitor::visit(const Field&)): New.\n\t(Visitor::visit(const Bit_field&)): Likewise.\n\n\t* impl.H (Udt_impl<>::decl_impl): Fix const-correctness thinko.\n\t(Field_impl): New. Implement Field interface.\n\t(Bit_field): New.  Implement Bit_fiekd interface.\n\t(Unit_impl::make_field): New.\n\t(Unit_impl::make_bit_field): Likewise.\n\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H: Fix thinko in last change.\n\t(Unit_impl::make_function):  Overload to take only\n\tparameter-types and return type.\n\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.15.\n\t\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (operator|=(Type::Qualifier&, Type::Qualifier)): New.\n\t(operator^=(Type::Qualifier&, Type::Qualifier)): Likewise.\n\t(operator&=(Type::Qualifier&, Type::Qualifier)): Likewise.\n\t(operator|=(Decl::Specifier&, Decl::Specifier)): Likewise.\n\t(operator^=(Decl::Specifier&, Decl::Specifier)): Likewise.\n\t(operator&=(Decl::Specifier&, Decl::Specifier)): Likewise.\n\n\t* impl.H (Unit_impl::make_subscope): Move from Scope_impl<>.\n\t(Unit_impl::make_parameter_list): Likewise.\n\t(Scope_impl<>::enclosing_impl): Remove.\n\t(Scope_impl<>::unit_impl): Remove.\n\n2004-07-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark 0.14\n\t\n2004-07-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (as): Move from ipr.C.\n\t(Template): Use Parameter_list.\n\t(operator|(Decl::Specifier, Decl::Specifier)): New.\n\t(operator^(Decl::Specifier, Decl::Specifier)): New.\n\t(operator&(Decl::Specifier, Decl::Specifier)): New.\n\t(Unit::global_namespace): Rename from global_scope.\n\t(Unit::global_members): New.\n\n\t* impl.H (Type_builder::make_template): Take\n\tParameter_list as first argument.\n\t(Unit_impl::global_namespace): Rename from global_scope.\n\n2004-07-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.13.\n\t\n2004-07-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H: Reimplement from scratch.\n\n\t* interface.H (Conditional): New node.\n\t(Type_decl): Likewise.\n\t(Visitor::visit(const Conditional&)): New.\n\t(Visitor::visit(const Type_decl&)): Likewise.\n\n\t* impl.H (Name_builder): Merge with Expr_builder. Remove.\n\t(Expr_builder): Unify strings before making a Literal.\n\t(Unit_impl): Adjust.\n\t(Unit_impl::make_type_decl): New.\n\t(Type_decl_impl): New. Implement Type_decl interface.\n\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.12.\n\t\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Add_assign): New.\n\t(Bitand_assign): Likewise.\n\t(Bitor_assign): Likewise.\n\t(Bitxor_assign): Likewise.\n\t(Div_assign): Likewise.\n\t(Member_init): Likewise.\n\t(Modulo_assign): Likewise.\n\t(Mul_assign): Likewise.\n\t(Shift_left_assign): Likewise.\n\t(Shift_right_assign): Likewise.\n\t(Sub_assign): Likewise.\n\t(Udt<>): Simplify.\n\t(Visitor::visit(const Add_assign&)): New.\n\t(Visitor::visit(const Bitand_assign&)): Likewise.\n\t(Visitor::visit(const Bitor_assign&)): Likewise.\n\t(Visitor::visit(const Bitxor_assign&)): Likewise.\n\t(Visitor::visit(const Div_assign&)): Likewise.\n\t(Visitor::visit(const Member_init&)): Likewise.\n\t(Visitor::visit(const Modulo_assign&)): Likewise.\n\t(Visitor::visit(const Mul_assign&)): Likewise.\n\t(Visitor::visit(const Shift_left_assign&)): Likewise.\n\t(Visitor::visit(const Shift_right_assign&)): Likewise.\n\t(Visitor::visit(const Sub_assign&)): Likewise.\t\n\n\t* impl.H (Udt_impl<>): Simplify.\n\t(Class_impl): Tidy.\n\t(Union_impl): Likewise.\n\t(Namespace_Impl): Likewise.\n\t(Enum_impl): Likewise.\n\t(Destructor_impl): New. Implement Destructor interface.\n\t(Alias_impl): New. Implement Alias interface.\n\t(Name_builder::make_conversion): Fix typo.\n\t(Expr_builder): Make computed assignment nodes.\n\t(Unit_impl::GlobalNamespace::bases): Remove. \n\n\t* io.H (printer::Base): Rework.  Move common stubs from derived\n\tclasses here.  Start infrastructure for better pretty-printing.\n\t\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.11\n\t\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Specialization): Rename from Instantiation. Derive\n\tfrom Expr.\n\t(Scope_ref): Rename from Qualified.  Derive from Expr.\n\t(Object_type): Remove.\n\t(Pointer): Adjust.\n\t(Array): Likewise.\n\t(Expr_as_type): New interface.\n\t(Udt): Simplify.\n\t(Namespace): Adjust.\n\t(Class): Likewise.\n\t(Enum): Likewise.\n\t(Union): Likewise.\n\t(Scope_select): Remove.\n\t(Visitor::visit(const Instantiation&)): Remove.\n\t(Visitor::visit(const Qualified&)): Likewise.\n\t(Visitor::visit(const Scope_select&)): Likewise.\n\t(Visitor::visit(const Expr_as_type&)): New.\n\t(Unit::): Tidy.\n\n\t* impl.H (Object_type_impl): Remove.\n\t(Udt_impl): Tidy.\n\t(Enum_impl): Likewise.\n\t(Namespace_impl): Likewise.\n\t(Var_impl): New.  Implement the Var interface.\n\t(Name_builder): Rework.\n\t(Type_builder): Build Expr_as_type.  Tidy.\n\t(Expr_builder): Build Specialization and Scope_ref.\n\t(Unit_impl): Tidy.\n\n\t* io.H: Reflect changes in interface.H.\n\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H: #include <stdexcept>.\n\t(Product): New interface.\n\t(Expr_list): Likewise.\n\t(Stmt): Rename from Statement.\n\t(Scope): Derive from Expr.\n\t(Udt): Rename from User_defined_type.\n\t(Class): Adjust.\n\t(Union): Likewise.\n\t(Enum): Likewise.\n\t(Namespace): Likewise.\n\t(Function): Use Product for parameter-type-list.\n\t(Template): Likewise.\n\t(Call): Use Expr_list for argument-list.\n\t(Object_construction): Likewise.\n\t(New): Use Expr_list for placement and initializer list.\n\t(Function_body): Make an Expr.\n\t(Enumerator::value): Remove.\n\t(Alias::has_initializer): Remove.\n\t(Alias::aliasee): Likewise.\n\t(Base_type::has_initializer): Remove.\n\t(Parameter::has_default): Likewise.\n\t(Template_param): Likewise.\n\t(Constructor): New interface.\n\t(Copy_assignment): Likewise.\n\t(Visitor::visit(const Scope&)): Make non pure.\n\t(Visitor::visit(const Product&)): New.\n\t(Visitor::visit(const Expr_list&)): Likewise.\n\n\t* impl.H: #include <list>.\n\t(Expr_impl<>): Tidy.\n\t(Parameter_data): Remove.\n\t(Scope_impl<>): Simplify.\n\t(Product_impl): New datatype.  Implement Product interface.\n\t(Udt_imp<>): Rename from User_defined_type_impl<>.\n\t(Class_impl): Simplify.\n\t(Union_impl): Likewise.\n\t(Enum_impl): Likewise.\n\t(Namespace_impl): Likewise.\n\t(Expr_list_impl): New data type. Implement Expr_list interface.\n\t(Stmt_impl): Rename from Statement_impl.\n\t(Decl_impl<>): Simplify.\n\t(Fun_decl_impl): Likewise.\n\t(Enumerator_impl): New. Implement Enumerator interface.\n\t(Constructor_impl): New. Implement Constructor interface.\n\t(Parameter_list_impl): New. Implement Parameter_list interface.\n\t(Name_builder): New.\n\t(Type_builder); Likewise.\n\t(Expr_builder): Likewise.\n\t(Stmt_builder): Likewise.\n\t(Unit_impl): Reimplement.\n\n\t* io.H (printer::xpr::Declaration::visit(const Parameter_list&)): New.\n\t(printer::xpr::Declaration::visit(const Enumerator&)): New.\n\t(printer::xpr::Declaration::visit(const Base_type&)): New.\n\t(printer::xpr::Declaration::visit(const Scope&)): Remove.\n\t(printer::xpr::Expression::visit(const Product&)): New.\n\t(printer::xpr::Expression::visit(const Expr_list&)): New.\n\n2004-06-19  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H: Re-architecture.\n\t(Enumerator): New Decl node.\n\t(Base_type): Likewise.\n\t(Sequence::size): Return int.\n\t(Unary<>): New class template.\n\t(Binary<>): Likewise.\n\t(Ternary<>): Likewise.\n\t(Quaternary<>): Likewise.\n\t(Annotation): Derive from Binary<Node, std::string, Literal>.\n\t(Identifier): Derive from Unary<Name, std::string>.\n\t(Operator): Likewise.\n\t(Conversion): Derive from Unary<Name, Type>.\n\t(Instantiation): Derive from Binary<Name, Name, Sequence<Expr> >.\n\t(Qualified): Derive from Binary<Name, Name, Name>.\n\t(Pointer): Derive from Unary<Object_type, Type>.\n\t(Reference): Derive from Unary<Type, Type>.\n\t(Array): Derive from Binary<Object_type, Object_type, Expr>.\n\t(Function): Derive from Ternary<Type, Sequence<Type>, Type,\n\tSequence<Type> >.\n\t(Template): Derive from Binary<Type, Sequence<Type>, Expr>.\n\t(Literal): Derive from Binary<Expr, Type, std::string>.\n\t(Unary_expr<>): Remove.\n\t(Binary_expr<>): Likewise.\n\t(Name_expr<>): Derive from Unary<Expr, Name>.\n\t(Pre_increment): Derive from Unary<Expr, Expr>.\n\t(Post_increment): Likewise.\n\t(Pre_decrement): Likewise.\n\t(Post_decrement): Likewise.\n\t(Expr_typeid): Likewise.\n\t(Expr_sizeof): Likewise.\n\t(Type_typeid): Derive from Unary<Expr, Type>.\n\t(Type_sizeof): Likewise.\n\t(Deref): Derive from Unary<Expr, Expr>.\n\t(Address): Likewise.\n\t(Unary_plus): Likewise.\n\t(Negate): Likewise.\n\t(Not): Likewise.\n\t(Complement): Likewise.\n\t(Delete): Likewise.\n\t(Array_delete): Likewise.\n\t(Throw): Likewise.\n\t(Literal); Derive from Binary<Expr, Type, std::string>.\n\t(Cast_expr): Derive from Binary<Expr, Type, Expr>.  Make non-template.\n\t(Mul): Derive from Binary<Expr, Expr, Expr>.\n\t(Div): Likewise.\n\t(Modulo): Likewise.\n\t(Add): Likewise.\n\t(Sub): Likewise.\n\t(Shift_left): Likewise.\n\t(Shift_right): Likewise.\n\t(Less): Likewise.\n\t(Greater): Likewise.\n\t(Less_equal): Likewise.\n\t(Greater_equal): Likewise.\n\t(Equal): Likewise.\n\t(Not_equal): Likewise.\n\t(Bit_and): Likewise.\n\t(Bit_or): Likewise.\n\t(Bit_xor): Likewise.\n\t(And): Likewise.\n\t(Or): Likewise.\n\t(Comma): Likewise.\n\t(Assign): Likewise.\n\t(Call): Likewise.\n\t(Object_construction): Likewise.\n\t(Member_select): Likewise.  Make non-template.\n\t(New): Derive from Ternary<Expr, Sequence<Expr>, Object_type,\n\tSequence<Expr> >.\n\t(Labeled_stmt): Derive from Binary<Statement>.\n\t(Block): Derive from Ternary<Statement, Scope, Sequence<Expr>,\n\tSequence<Handler> >.\n\t(Function_body): Derive from Binary<Statement, Sequence<Expr>, Block>.\n\t(If_then): Derive from Binary<Statement>.\n\t(If_then_else): Derive from Ternary<Statement>.\n\t(Switch): Derive from Binary<Statement>.\n\t(While): Likewise.\n\t(Do_while): Likewise.\n\t(For): Derivee from Quaternary<Statement>.\n\t(Break): Derive from Unary<Statement>.\n\t(Continue): Likewise.\n\t(Goto): Likewise.\n\t(Return): Likewise.\n\t(Handler): Derive from Binary<Statement, Decl, Block>.\n\t(Visitor::visit(const Base_type&)): New member function.\n\n\tRemove unnecessary codes.\n\t\n\t* impl.H (Sequence_impl<>::size): Return int.\n\t(Identifier_impl): Remove again.\n\t(Operator_impl): Likewise.\n\t(Conversion_impl): Likewise.\n\t(Instantiation_impl): Likewise.\n\t(Qualified_impl): Likewise.\n\t(Scope_impl<>::operator[](const Name&)): Suspend definition.\n\t(Parameter_data): New datatype.\n\t(Scope_impl<>::make_block()): Remove.\n\t(Scope_impl<>::make_namespace()): Likewise.\n\t(Scope_Impl<>::make_parameter): Likewise.\n\t(Scope_impl<>::make_fun_decl(const Name&)): Likewise.\n\t(Scope_impl<>::Overload_impl): Move to Unit_impl.\n\t(Scope_impl<>::Binding): Remove.\n\t(Scope_Impl<>::bindings): Likewise.\n\t(Type_impl<>::Type_impl(const Type_impl&)): Implement. Make\n\tprotected.  Add FIXME-comments.\n\t(Type_impl<>::operator=(const Type_impl&)): Add FIXME-comments.\n\t(Unary_expr_impl<>): Remove.\n\t(Binary_expr_impl<>): Likewise.\n\t(New_impl): Likewise.\n\t(Block_impl): Likewise.\n\t(Unary_factor<>): New datatype.\n\t(Binary_factor<>): Likewise.\n\t(Ternary_factor<>): Likewise.\n\t(Quaternary_factor<>): Likewise.\n\t(Fun_decl_impl): Comment out.\n\t(Unit_impl::make_identifier): Reimplement.\n\t(Unit_impl::make_operator): Likewise.\n\t(Unit_impl::make_conversion): Likewise.\n\t(Unit_impl::make_instantiation): Likewise.\n\t(Unit_impl::make_qualified): Likewise.\n\t(Unit_impl::make_pointer): Likewise.\n\t(Unit_impl::make_reference): Likewise.\n\t(Unit_impl::make_array): Likewise.\n\t(Unit_impl::make_function): Likewise.\n\t(Unit_impl::make_if_then_else): Remove.\n\t(Unit_impl::make_for): Remove.\n\t(Unit_impl::make_handler): Likewise.\n\t(Unit_impl::make_literal): Reimplement.\n\t(Unit_impl::make_annotation): Likewise.\n\t(Unit_impl::make_unary_expr): Likewise.\n\t(Unit_impl::make_binary_expr): Likewise.\n\t(Unit_impl::make_ternary_expr): New.\n\t(Unit_impl::make_unary_stmt): Likewise.\n\t(Unit_impl::make_binary_stmt): New.\n\t(Unit_impl::make_ternary_stmt): New.\n\t(Unit_impl::make_quaternary_stmt): New.\n\t(Unit_impl::Overload_impl): Move from Scope_impl<>::.\n\t(Unit_impl::TypeFiber): Simplify.  Rename to CV_fiber.\n\t(Unit_impl::ids): Change type to Unary_factory<Identifier,\n\tIdentifier>.\n\t(Unit_impl::ops): Change type to Unary_factory<Operator, Operator>.\n\t(Unit_impl::convs): Change type to Unary_factory<Conversion,\n\tConversion>. \n\t(Unit_impl::insts): Change type to Binary_factory<Instantiation,\n\tInstantiation, Name, Sequence<Expr> >.\n\t(Unit_impl::quals): Change type to Binary_factory<Qualified,\n\tQualified, Name, Name>.\n\t(Unit_impl::pointers): New data member.\n\t(Unit_impl::references): Likewise.\n\t(Unit_impl::arrays): Likewise.\n\t(Unit_impl::functions): Likewise.\n\t(Unit_impl::UnaryExprs): New datatype.\n\t(Unit_impl::unary_exprs: New data member.\n\t(Unit_impl::BinaryExprs): New datatype.\n\t(Unit_impl::binary_exprs: New data member.\n\t(Unit_impl::TernaryExprs): New datatype.\n\t(Unit_impl::ternary_exprs: New data member.\n\t(Unit_impl::QuaternaryExprs): New datatype.\n\t(Unit_impl::quaternary_exprs: New data member.\n\n\t* io.H (Expression::visit(const Name_expr&)): Correct spelling.\n\t(Expression::visit(const Throw&)): New member function. \n\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.10.\n\t\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Scope_impl): Turn into a template class parameterized by\n\tthe node declaration kind, with default to Decl.  Inherit from ...\n\t(Scope_impl_base<>): ... this.  New class template.\n\t(Name_binding): Remove.\n\t(Name_binding::Overload_impl): Move to Scope_impl<>.\n\t(Name_traits): Remove.\n\t(Name_rep): Likewise.\n\t(Name_impl): Likewise.\n\t(Identifier_impl): Resurect.\n\t(Operator_impl): Likewise.\n\t(Conversion_impl): Likewise.\n\t(Instantiation_impl): Likewise.\n\t(Qualified_impl): Likewise.\n\t(Expr_type<>):  Take a second template parameter, the type of\n\tthe expression with default to Type.\n\t(Type_type<>): Likewise.\n\t(Signature_impl<>): Remove.\n\t(Statement_impl<>): Likewise.\n\t(Decl_impl<>): Likewise.\n\t(Ternay_expr<>): New class template.\n\t(Unit_impl): Tidy.\n\t(make_decl): Remove.\n\t* interface.H (Sequence<>):  Provide an STL-style looking.\n\t(Name::value): Remove.\n\t(Name::scope): Likewise.\n\t(Instantiation::scope): Likewise.\n\t(Qualified::scope): Likewise.\n\t(Scope::operator[](const Name&)): Return an Overload.\n\t(Overload::operator[](const Type&)): Return a Sequence<Decl>.\n\t(Signature): Remove.\n\t(Function::signature): Return a Sequence<Type>.\n\t(Member): Remove.\n\t(Template::signature): Return a Sequence<Type>.\n\t(Name_expr): Derived from Unary_expr<>.\n\t(New): Derive from Ternary_expr.\n\t(If_then_else): Likewise.\n\t(Return::has_value): Remove.\n\t(Decl::master): Return a Sequence<Decl>.\n\t(Member_decl): Remove.\n\t(Enumerator): New node class.\n\t(Alias::aliasee): Return an Expr, the initializer.\n\t(Fun_decl::signature): Return a Sequence<Type>.\n\t(Visitor::visit(const Signature&)): Remove.\n\t(Visitor::visit(const Member&)): Likewise.\n\t(Visitor::visit(const Member_decl&)): Likewise.\n\t(Unit::null_expr): New member function.\n\t* io.H (printer::Base::operator<<): New function.  Forward to\n\tstandard format operations.\n\n2004-06-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Signature): Remove.\n\t(Function::signature): Adjust return type.  Return Sequence<Type>.\n\t(Template::signature): Likewise.\n\t(Fun_decl::signature): Likewise.\n\t(Fun_decl::parameters): Make pure virtual.\n\t(Visitor::visit(const Signature&)): Remove.\n\t* impl.H (Scope_impl::make_fun_decl): Tidy. \n\t(Signature_impl): Likewise.\n\t(Parameter_impl): Tidy.\n\t(Fun_decl_impl::ParameterList): Lose base class Signature.\n\t(Fun_decl_impl::DeclType::signature):  Adjust return type.\n\t(Fun_decl_impl::signature): Likewise.\n\t(Unit_impl::make_signature): Remove.\n\t(Unit_impl::make_function): Tidy.\n\t(Unit_impl::sigs): Lose.\n\n2004-05-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Unary_expr<>): Take a third parameter as the\n\tcategory of the expression.  Inherit from it.\n\t(Binary_expr<>): Take Category as fourth parameter.  Inherit from it.\n\t(Labeled_stmt): Inherit from Binary_expr<>.\n\t(Block): Likewise.\n\t(Function_body): Likewise.\n\t(If_then): Likewise.\n\t(Swicth): Likewise.\n\t(While): Likewise.\n\t(Do_while): Likewise.\n\t(Break): Inherit from Unary_expr<>.\n\t(Continue): Likewise.\n\t(Goto): Likewise.\n\t(Return): Likewise.\n\t(Handler): Inherit from Binary_expr<>.\n\n\t* io.H (ipr::printer): New namespace.\n\t(Printer_base): Move there.  Rename to Base.\n\t(ipr::printer::xpr): New namespace.\n\t(Declaration_printer): Move there.  Rename to Declaration.\n\t(Statement_printer): Move there.  Rename to Statement.\n\t(Expression_printer): Move there.  Rename to Expression.\n\n\t* interface.H: Rename Progam to Unit, throughout.\n\t(Name::scope): New member function.\n\t(Instantiation): Override Name::scope.\n\t(Qualified): Likewise.\n\t(Name_expr): Document.\n\t(Binary_expr<>): Take two more template-arguments.\n\t(Call): Derive from Binary_expr<>.\n\t(Object_construction): Likewise.\n\t(Template::parameters): Remove.\n\t(Template::signature): New member function.\n\t(Visitor::visit(const Assign&)): Declare.\n\t(Template): Derived from Type instead of Expr.\n\t(Template::result): New member function.\n\t(Class_template): Remove.\n\t(Fun_decl_template): Remove.\n\t(Return::type): Override Expr::type.\n\n\t* impl.H: Likewise.\n\t(Call_impl): Remove.\n\t(Object_construction_impl): Likewise.\n\n2004-05-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.08.\n\t\n2004-05-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Type::has_name): Remove.\n\t(Type::name): Return a Name, not an Identifier.\n\t(operator|): Overload for Type::Qualifier.\n\t(operator&): Likewise.\n\t(operator^): Likewise.\n\t(Cast_expr<>): New class template. Derive from Binary_expr<>\n\t(Dynamic_cast): Derived from Cast_expr<>, not Unary_expr<>.\n\t(Static_cast): Likewise.\n\t(Const_cast): Likewise\n\t(Reinterpret_cast): Likewise.\n\t(Cast): Likewise.\n\t(Labeled_stmt::label): Return an Expr.\n\t(Function_body):  Make only a statement, not a sequence of Statements.\n\t(Block): Make a sequence of Exprs too.\n\t(Parameter::has_default): Alias for Decl::has_initializer.\n\t(Parameter::default_value): Alias for Decl::initializer.\n\n\t* impl.H (Checked_ptr<>): Tidy.\n\t(Sequence_impl<>): Likewise.\n\t(Name_binding): New class.\n\t(Name_traits<>): Likewise.\n\t(Name_rep<>): Likewise.  Use the above.\n\t(Name_impl<>): Derive from both Name_binding and Name_rep<>. Tidy.\n\t(Expr_impl<>): Tidy.\n\t(Overload_impl): Likewise.\n\t(Type_impl<>): Likewise.\n\t(Object_type_impl<>): Likewise.\n\t(User_defined_type_impl<>): Likewise.\n\t(Namespace_impl): Likewise.\n\t(Unary_plus_impl<>): Likewise.\n\t(Member_selection_impl<>): Remove.\n\t(Binary_expr_impl<>): Tidy.\n\t(New_impl): Likewise.\n\t(Statement_impl<>): Likewise.\n\t(Block_impl): Likewise.\n\t(Handler_impl): Likewise.\n\t(Decl_impl<>): Likewise.\n\t(Parameter_impl): Likewise.\n\t(Program_impl): Likewise.\n\n2004-05-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Type::All): New enumerator.  Collect all\n\ttype-qualifier values.\n\n\t* impl.H (Program_impl::TypeFiber): New class.\n\t(Program_impl::typebundle): New data member.  Cache already\n\tcomputed \"fiber\" values for types.\n\t(Program_impl::make_cv_qualified): New member function.\n\n2004-05-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.07.\n\n2004-05-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H: Rework pretty-printers. \n\n\t* interface.H (Sequence<>::Position): New nested class.\n\t(Sequence<>::operator[]): Take a Position, instead of int.\n\t(Sequence<>::Iterator::index): Change to type\n\tSequence<>::Position.\n\t(Scope): Derive also from Node.\n\t(Scope::accept): Remove, since inherited from Node.\n\t(Expr::attributes): Rename to Expr::annotation.\n\t(Member_selection<>): Derive from Binary_expr<>.\n\t(Labeled_stmt::body): Rename to ...::stmt.\n\t(Function_body): Derive from both Statement and\n\tSequence<Statement>.\n\t(Function_body::members): Remove.\n\t(For::has_initializer): Likewise.\n\t(For::has_condition): Likewise.\n\t(For::has_increment): Likewise.\n\t(Continue::iter_stmt): Rename to ...::iteration.\n\t(Goto::target): Rename an Expr.\n\t(Decl::has_name): Remove.\n\t(Fun_decl): Rework.\n\n\t* impl.H (Pointer_impl):  Remove.\n\t(Reference_impl): Likewise.\n\t(Array_impl): Likewise.\n\t(Var_impl): Likewise.\n\t(Identifier_impl): Likewise.\n\t(Conversion_impl): Likewise.\n\t(Qualified_impl): Likewise.\n\t(Literal_impl): Likewise.\n\t(Name_expr_impl): Likewise.\n\t(Pre_increment_impl): Likewise.\n\t(Post_increment_impl): Likewise.\n\t(Pre_decrement_impl): Likewise.\n\t(Post_decrement_impl): Likewise.\n\t(Dynamic_cast_impl): Likewise.\n\t(Static_cast_impl): Likewise.\n\t(Reinterpret_cast_impl): Likewise.\n\t(Const_cast_impl): Likewise.\n\t(Cast_impl): Likewise.\n\t(Expr_typeid_impl): Likewise.\n\t(Type_typeid_impl): Likewise.\n\t(Expr_sizeof_impl): Likewise.\n\t(Type_sizeof_impl): Likewise.\n\t(Deref_impl): Likewise.\n\t(Address_impl): Likewise.\n\t(Unary_plus_impl): Likewise.\n\t(Negate_impl): Likewise.\n\t(Not_impl): Likewise.\n\t(Complement_impl): Likewise.\n\t(Delete_impl): Likewise.\n\t(Array_delete_impl): Likewise.\n\t(Unary_expr_impl<>::Unary_expr_impl): Tidy signature.\n\t(Dinary_expr_impl<>::Unary_expr_impl): Likewise.\n\t(Dot_star_impl): Remove.\n\t(Arrow_star_impl): Remove.\n\t(Mul_impl): Remove.\n\t(Div_impl): Remove.\n\t(Add_impl): Remove.\n\t(Sub_impl): Remove.\n\t(Shift_left_impl): Remove.\n\t(Shift_right_impl): Remove.\n\t(Less_impl): Remove.\n\t(Greater_impl): Remove.\n\t(Less_equal_impl): Remove.\n\t(Greater_equal_impl): Remove.\n\t(Equal_impl): Remove.\n\t(Not_equal_impl): Remove.\n\t(Bit_and_impl): Remove.\n\t(Bit_xor_impl): Remove.\n\t(Bit_or_impl): Remove.\n\t(And_impl): Remove.\n\t(Or_impl): Remove.\n\t(Comma_impl): Remove.\n\t(Assign_impl): Remove.\n\t(Array_select_impl): Remove.\n\t(Dot_select_impl): Remove.\n\t(Arrow_select_impl): Remove.\n\t(Scope_select_impl): Remove.\n\t(Member_select_impl): Tidy.\n\t(Checked_ptr<>): New class.\n\t(Sequence_impl<>::get):  Adjust signature.  \n\t(Name_impl<>::value_impl):  Returns a Checked_ptr<>.\n\t(Name_Impl<>::error_if_bound): Remove.\n\t(Name_impl<>::binding):  Declare as Checked_ptr<Expr>.\n\t(Expr_impl<>::attributes): Rename to Expr_impl<>::annotation.\n\t(Expr_impl<>::constaint): Declare as Checked_ptr<const Type>.\n\t(Expr_impl<>::type_impl): Returns a Checked_ptr<const Type>&.\n\t(Scope_impl::enclosing_scope): Returns a Checked_ptr<Scope_impl>.\n\t(Scope_impl::lookup_identifier): Returns a Name_impl<Identifier>*.\n\t(Scope_impl::lookup_operator): Returns a Name_impl<Operator>*.\n\t(Scope_impl::lookup_conversion): Returns a Name_impl<Conversion>*.\n\t(Scope_impl::make_identifier): Returns a Name_impl<Identifier>*.\n\t(Scope_impl::make_operator): Returns a Name_impl<Operator>*.\n\t(Scope_impl::make_conversion): Returns a Name_impl<Conversion>*.\n\t(Scope_impl::make_instantiation): Returns a Name_impl<Instantiation>*.\n\t(Scope_impl::make_qualified): Returns a Name_impl<Qualified>*.\n\t(Scope_impl::make_block): New more overloads.\n\t(Scope_impl::make_var): New overloads.\n\t(Scope_impl::make_fun_decl): Likewise.\n\t(Scope_impl::get): Adjust type.\n\t(Signature_impl): New class.\n\t(Function_impl): Rework.\n\t(Labeled_stmt_impl): Remove.\n\t(Block_impl): Tidy.\n\t(Function_body_impl): Rework.\n\t(If_then_impl): Remove.\n\t(If_then_else_impl): Remove.\n\t(Switch_impl): Remove.\n\t(While_impl): Remove.\n\t(Do_while_impl): Remove.\n\t(For_impl): Remove.\n\t(Break_impl): Remove.\n\t(Continue_impl): Remove.\n\t(Goto_impl): Remove.\n\t(Return_impl): Remove.\n\t(Decl_impl<>::has_name): Remove.\n\t(Decl_impl<>::init): Change type to Checked_ptr<const Expr>\n\t(Var_impl): Remove.\n\t(Parameter_impl): Tidy.\n\t(Fun_decl_impl): Rework.\n\t(Program_impl::make_function): New.\n\t(Program_impl::make_labeled_stmt): Likewise.\n\t(Program_impl::make_if_then): Likewise.\n\t(Program_impl::make_if_then_else): Likewise.\n\t(Program_impl::make_switch): Likewise.\n\t(Program_impl::make_while): Likewise.\n\t(Program_impl::make_do_while): Likewise.\n\t(Program_impl::make_for): Likewise.\n\t(Program_impl::make_break): Likewise.\n\t(Program_impl::make_continue): Likewise.\n\t(Program_impl::make_goto): Likewise.\n\t(Program_impl::make_return): Likewise.\n\t(Program_impl::make_handler): Likewise.\n\t(Program_impl::make_expr_typeid): Likewise.\n\t(Program_impl::make_type_typeid): Likewise.\n\t(Program_impl::make_expr_sizeof): Likewise.\n\t(Program_impl::make_type_sizeof): Likewise.\n\t(Program_impl::make_name_expr): Likewise.\n\t(Program_impl::make_unary_expr): Likewise.\n\t(Program_impl::make_binary_expr): Likewise.\n\t(Program_impl::make_member_selection): Likewise.\n\t(Program_impl::make): Remove.\n\t(Program_impl::IdMap): Likewise.\n\t(Program_impl::Namemap): Likewise.\n\t(Name_impl<>::value): Tidy.\n\t(Name_impl<>::with): Tidy.\n\t(Expr_impl<>::type): Tidy.\n\t(make_decl): Tidy.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Fun_decl::params): New member function.\n\t(Function::domain): Rename to Function::source.\n\t(Signature): New class.\n\t(Visitor::visit(const Signature&)): New.\n\t* impl.H (Fun_decl_impl::params): Likewise.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark 0.06.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Program_impl::Class): New member function.\n\t(Program_impl::Union): Likewise.\n\t(Program_impl::Enum): Likewise.\n\t(Program_impl::Namespace): Likewise.\n\t(Program_impl::classtype): New data member.\n\t(Program_impl::uniontype): Likewise.\n\t(Program_impl::enumtype): Likewise.\n\t(Program_impl::namespacetype): Likewise.\n\n2004-05-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Name_impl<>::with): New member.  Forward to...\n\t(make_decl): ...this function.  New.\n\t(missing_overrider): Declare.\n\t(Identifier_impl<>::with): Remove.\n\t(Operator_impl<>::with): Likewise.\n\t(Conversion_impl<>::with): Likewise.\n\t(Instantiation_impl<>::with): Likewise.\n\t(Qualified_impl<>::with): Likewise.\n\t(Decl_impl<>::Decl_impl): Revert previous change.  Take declname\n\tby reference.\n\t(Program_impl::make_decl<>): New member.\n\t(Type_impl<>::has_name): Override Type::has_name. Default to false.\n\t(Program_impl::ellipsis_impl): Rename tp Program_impl::Ellipsis.\n\n2004-05-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.05.\n\t\n2004-05-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Visitor::visit(const Node&)): Make pure. \n\t(Visitor::visit(const Name&)): Likewise.\n\t(Visitor::visit(const Type&)): Likewise.\n\t(Visitor::visit(const Expr&)): Likewise.\n\t(Visitor::visit(const Statement&)): Likewise.\n\t(Visitor::visit(const Decl&)): Likewise.\n\t(Type::is_named): Rename to Type::has_name.\n\t(Decl::has_name): New member.\n\n\t* impl.H (User_defined_type_impl<>::is_named): Rename to ...::has_name.\n\t(Program_impl::Builtin<>::is_named): Likewise.\n\t(Decl_impl<>::Decl_impl): Take decl-name by pointer, not reference.\n\n2004-04-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.H (Sequence_printer): New.\n\t(Expression_printer):  Override more visit() member functions for\n\tthe purpose of pretty-printing more kinds of expression.\n\n2004-04-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.H (Type): Add members is_named(), name() to support\n\tnamed types.\n\t* impl.H (User_defined_type_impl<>): Implement.\n\t(Program_impl::Builtin<>): New. Implement built-in types.\n\n2004-03-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.H (Unary_expr_impl): Have an explicit constructor that\n\ttakes an expression as sole argument.\n\t(Pre_increment_impl): Likewise.\n\t(Post_increment_impl): Likewise.\n\t(Pre_decrement_impl): Likewise.\n\t(Post_decrement_impl): Likewise.\n\t(Expr_typeid_impl): Likewise.\n\t(Type_typeid_impl): Likewise.\n\t(Expr_sizeof_impl): Likewise.\n\t(Type_sizeof_impl): Likewise.\n\t(Deref_impl): Likewise.\n\t(Address_impl): Likewise.\n\t(Unary_plus_impl): Likewise.\n\t(Negate_impl): Likewise.\n\t(Not_impl): Likewise.\n\t(Complement_impl): Likewise.\n\t(Delete_impl): Likewise.\n\t(Array_delete_impl): Likewise.\n\t(Binary_expr_impl): Declare constructor taking two Exprs.\n\t(Dot_star_impl): Likewise.\n\t(Arrow_star_impl): Likewise.\n\t(Mul_impl): Likewise.\n\t(Div_impl): Likewise.\n\t(Modulo_impl): Likewise.\n\t(Add_impl): Likewise.\n\t(Sub_impl): Likewise.\n\t(Shift_left_impl): Likewise.\n\t(Shift_right_impl): Likewise.\n\t(Less_impl): Likewise.\n\t(Greater_impl): Likewise.\n\t(Less_equal_impl): Likewise.\n\t(Greater_equal_impl): Likewise.\n\t(Equal_impl): Likewise.\n\t(Not_equal_impl): Likewise.\n\t(Bit_and_impl): Likewise.\n\t(Bit_xor_impl): Likewise.\n\t(Bit_or_impl): Likewise.\n\t(And_impl): Likewise.\n\t(Or_impl): Likewise.\n\t(Comma_impl): Likewise.\n\t(Assign_impl): Likewise.\n\t(Member_selection_impl): Likewise.\n\t(Array_select_impl): Likewise.\n\t(Dot_select_impl): Likewise.\n\t(Arrow_select_impl): Likewise.\n\t(Scope_select_impl): Likewise.\n\n"
  },
  {
    "path": "include/ipr/impl",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n\n#ifndef IPR_IMPL_INCLUDED\n#define IPR_IMPL_INCLUDED\n\n// Consumers of this header must:\n//   1. #include all needed standard headers\n//   2. import cxx.ipr;\n//   3. #include <ipr/impl>\n\n#include <ipr/utility-impl>\n\n// -----------------\n// -- Methodology --\n// -----------------\n// This file provides implementations for the interface classes\n// defined in <ipr/interface>.  The basic rule is that every class\n// found in that header file has at least one implementation in\n// this file.  That rule applies to all abstract interfaces such as\n// \"ipr::Expr\", as well as more concrete ones like \"ipr::Address\".\n//    Implementations for the abstract interfaces usually consists in\n// providing implementations for common operations on some set of\n// interfaces.  For instance, \"impl::Expr provides implementation for\n// the ipr::Expr::type() operation.\n//    For that to work properly, without using virtual inheritance,\n// we parameterize the implementations of the abstract interfaces with\n// (set of) concrete interfaces.  That ensures, for example, that\n// impl::Unary overrides ipr::Node::accept() and forward to the right\n// ipr::Visitor::visit() hook.\n\nnamespace ipr::util {\n   // Interface nodes are neither copyable nor moveable, by virtue of being abstract classes.\n   // Similarly, implementation of those interfaces are not intended to be copyable nor moveable.\n   // This utility class captures the intent of disabling the automatic generation of the usual\n   // copy/move operations.  The class definition is more verbose than the intent.\n   struct immotile {\n      constexpr immotile() = default;\n      immotile(immotile&&) = delete;\n      immotile(const immotile&) = delete;\n      immotile& operator=(immotile&&) = delete;\n      immotile& operator=(const immotile&) = delete;\n   };\n}\n\nnamespace ipr::impl {\n                             // -- impl::Node --\n   template<class T>\n   struct Node : T {\n      using Interface = T;\n      void accept(ipr::Visitor& v) const final { v.visit(*this); }\n   };\n\n   // -- impl::immotile_node\n   template<typename T>\n   struct immotile_node : impl::Node<T>, util::immotile { };\n\n   // -- Generic implementation of ipr::Basic_unary\n   template<class Interface>\n   struct Basic_unary : Interface {\n      using typename Interface::Arg_type;\n      Arg_type rep;\n\n      explicit constexpr Basic_unary(Arg_type a) : rep{a} { }\n      constexpr Arg_type operand() const final { return rep; }\n   };\n\n   // -- impl::Unary_node: Shorthand for the implementation of generic unary nodes.\n   template<typename T>\n   using Unary_node = impl::Basic_unary<immotile_node<T>>;\n\n   // -- Generic implementation of ipr::Basic_binary --\n   template<class Interface>\n   struct Basic_binary : Interface {\n      using typename Interface::Arg1_type;\n      using typename Interface::Arg2_type;\n      struct Rep {\n         Arg1_type first;\n         Arg2_type second;\n      };\n      Rep rep;\n\n      constexpr Basic_binary(const Rep& r) : rep{r} { }\n      constexpr Basic_binary(Arg1_type f, Arg2_type s) : rep{f, s} { }\n      constexpr Arg1_type first() const final { return rep.first; }\n      constexpr Arg2_type second() const final { return rep.second; }\n   };\n\n   // -- impl::Binary_node: Short hand for implementation of generic binary nodes.\n   template<typename T>\n   using Binary_node = impl::Basic_binary<immotile_node<T>>;\n\n                           // -- impl::Ternary --\n   template<class Interface>\n   struct Ternary : Interface {\n      using typename Interface::Arg1_type;\n      using typename Interface::Arg2_type;\n      using typename Interface::Arg3_type;\n      struct Rep {\n         Arg1_type first;\n         Arg2_type second;\n         Arg3_type third;\n      };\n      Rep rep;\n\n      Ternary(const Rep& r) : rep(r) { }\n      Ternary(Arg1_type f, Arg2_type s, Arg3_type t) : rep{ f, s, t } { }\n      Arg1_type first() const final { return rep.first; }\n      Arg2_type second() const final { return rep.second; }\n      Arg3_type third() const final { return rep.third; }\n   };\n\n                           // -- impl::Quaternary --\n   template<class Interface>\n   struct Quaternary : Interface {\n      using typename Interface::Arg1_type;\n      using typename Interface::Arg2_type;\n      using typename Interface::Arg3_type;\n      using typename Interface::Arg4_type;\n      struct Rep {\n         Arg1_type first;\n         Arg2_type second;\n         Arg3_type third;\n         Arg4_type fourth;\n      };\n      Rep rep;\n\n      Quaternary(const Rep& r) : rep(r) { }\n      Quaternary(Arg1_type f, Arg2_type s, Arg3_type t, Arg4_type u) : rep{ f, s, t, u } { }\n      Arg1_type first() const final { return rep.first; }\n      Arg2_type second() const final { return rep.second; }\n      Arg3_type third() const final { return rep.third; }\n      Arg4_type fourth() const final { return rep.fourth; }\n   };\n\n   using Logogram = Basic_unary<ipr::Logogram>;\n\n   using Comment = Unary_node<ipr::Comment>;\n\n   using Identifier = Unary_node<ipr::Identifier>;\n   using Suffix = Unary_node<ipr::Suffix>;\n   using Operator = Unary_node<ipr::Operator>;\n   using Conversion = Unary_node<ipr::Conversion>;\n   using Ctor_name = Unary_node<ipr::Ctor_name>;\n   using Dtor_name = Unary_node<ipr::Dtor_name>;\n   using Guide_name = Unary_node<ipr::Guide_name>;\n   using Type_id = Unary_node<ipr::Type_id>;\n\n   // -- Generic implementarion of ipr::Transfer\n   using Transfer = impl::Basic_binary<ipr::Transfer>;\n\n   // -- Specialized implementation of ipr::Transfer\n   // An object of this class pairs a specified language linkage with the natural\n   // C++ calling convention.\n   struct Transfer_from_linkage : ipr::Transfer {\n      constexpr explicit Transfer_from_linkage(const ipr::Language_linkage& l) : link{l} { }\n      const ipr::Language_linkage& first() const final { return link; }\n      const ipr::Calling_convention& second() const final;\n   private:\n      const ipr::Language_linkage& link;\n   };\n\n   // -- Specialized implementation of ipr::Transfer\n   // An object of this class pairs the C++ language linkage with a specified calling convention.\n   struct Transfer_from_cc : ipr::Transfer {\n      constexpr explicit Transfer_from_cc(const ipr::Calling_convention& cc) : conv{cc} { }\n      const ipr::Language_linkage& first() const final;\n      const ipr::Calling_convention& second() const final { return conv; }\n   private:\n      const ipr::Calling_convention& conv;\n   };\n}\n\nnamespace ipr::util {\n   // Type for representing the hash of data (mostly character strings) used internally.\n   enum class hash_code : std::size_t { };\n}\n\nnamespace ipr::impl {\n                             // -- impl::String --\n   struct String : immotile_node<ipr::String> {\n      constexpr String(const char8_t* s) : txt{ s } { }\n      constexpr String(util::word_view w) : txt{ w } { }\n      constexpr util::word_view characters() const final { return txt; }\n   private:\n      const util::word_view txt;\n   };\n}\n\nnamespace ipr::util {\n   // String pool.  Used to intern words used for external designation of entities.\n   struct string_pool : private std::map<hash_code, std::forward_list<impl::String>> {\n      const ipr::String& intern(word_view);\n   private:\n      util::string::arena strings;\n   };\n}\n\nnamespace ipr::impl {\n   // --------------------------------------\n   // -- Implementations of ipr::Sequence --\n   // --------------------------------------\n   // The Sequence<> interface admits various implementations.\n   // Here is the list of the implementations currently in use:\n   //   (a) ref_sequence<T>\n   //   (b) obj_sequence<T>\n   //   (c) obj_list<T>\n   //   (d) empty_sequence<T>\n   // Variants exist in form of\n   //    (i) decl_sequence<T>\n   //   (ii) singleton_ref<T>\n   //  (iii) singleton_obj<T>\n\n   // -- When a class implements an interface, return that interface;\n   // -- otherwise, the type itself.\n   template<typename T>\n   concept Has_interface = requires { typename T::Interface; };\n\n   template<typename T>\n   struct abstraction {\n      using type = T;\n   };\n\n   // Remove any wrapper or implementation class.\n   template<Has_interface T>\n   struct abstraction<T> {\n      using type = typename T::Interface;\n   };\n\n   template<typename T, template<typename...> class C>\n   struct abstraction<C<T>> : abstraction<T> { };\n\n   template<typename T>\n   using projection = typename abstraction<T>::type;\n\n                          // -- impl::ref_sequence --\n   // The class ref_sequence<T> implements Sequence<T> by storing\n   // references (e.g. pointers) to data of type T, allocated\n   // somewhere else.  That for example if useful when keeping track\n   // of redeclarations in decl-sets.\n   // In general, it can be used to implement the notion of sub-sequence.\n   template<typename T>\n   struct ref_sequence : ipr::Sequence<T>, private std::vector<const void*> {\n      using Seq = Sequence<T>;\n      using Rep = std::vector<const void*>;\n      using pointer = const T*;\n      using Iterator = typename Seq::Iterator;\n      using Index = typename Seq::Index;\n      explicit ref_sequence(std::size_t n = 0) : Rep(n) { }\n      Index size() const final { return Rep::size(); }\n\n      using Seq::begin;\n      using Seq::end;\n      using Rep::resize;\n      using Rep::push_back;\n      const T& get(Index p) const final { return *pointer(this->at(p)); }\n   };\n\n                          // -- impl::Warehouse --\n   // The class Warehouse<T> is intended to be used by clients of the\n   // impl::Lexicon to temporarily accumulate a sequence of references to\n   // data of type T to assist in construction of ipr nodes such as product or sum.\n   template<typename T>\n   struct Warehouse : private ref_sequence<T> {\n      using Rep = ref_sequence<T>;\n      explicit Warehouse(std::size_t n = 0) : Rep(n) { }\n\n      Rep& rep() { return *this; }\n      const Rep& rep() const { return *this; }\n      using Rep::Seq::begin;\n      using Rep::Seq::end;\n      using Rep::size;\n      void push_back(const T& item) { Rep::push_back(&item); }\n   };\n\n   // -- stable_farm --\n   // Backing store for stable reference-producing factories.\n   template<typename T>\n   struct stable_farm : std::forward_list<T> {\n      using std::forward_list<T>::forward_list;\n      template<typename... Args>\n      T* make(Args&&... args)\n      {\n         this->emplace_front(std::forward<Args>(args)...);\n         return &this->front();\n      }\n   };\n\n                             // -- impl::obj_sequence --\n   // The class obj_sequence<T> implements the interface Sequence<T> by storing the\n   // actual values as random access sequence of objects, instead of references to\n   // values (as is the case of ref_sequence<T>).  This Sequence implementation\n   // is useful for potentially large sequence of items (e.g. enumerator lists)\n   // and for which iteration is frequent.\n   template<typename T>\n   struct obj_sequence : ipr::Sequence<projection<T>>, private std::deque<T> {\n      using Seq = ipr::Sequence<projection<T>>;\n      using Impl = std::deque<T>;\n      using Iterator = typename Seq::Iterator;\n      using Index = typename Seq::Index;\n      using Seq::begin;\n      using Seq::end;\n\n      Index size() const final { return Impl::size(); }\n      const projection<T>& get(Index p) const final\n      {\n         if (p < 0 or p >= size())\n            throw std::domain_error(\"obj_sequence::get\");\n         return backing_store()[p];\n      }\n\n      Impl& backing_store() { return *this; }\n      const Impl& backing_store() const { return *this; }\n\n      template<typename... Args>\n      T* push_back(Args&&... args)\n      {\n         return &Impl::emplace_back(std::forward<Args>(args)...);\n      }\n   };\n\n                             // -- impl::obj_list --\n   // The class obj_list<T> implements Sequence<T> by storing the actual\n   // values in a singly-linked list, instead of references to values (as is\n   // the case of ref_sequence<T>).  This Sequence implementation can be used\n   // for typically small sequence of items (e.g. parameter lists, or direct\n   // base class lists)\n   template<typename T>\n   struct obj_list : ipr::Sequence<projection<T>>, private stable_farm<T> {\n      using Seq = ipr::Sequence<projection<T>>;\n      using Impl = stable_farm<T>;\n      using Iterator = typename Seq::Iterator;\n      using Index = typename Seq::Index;\n      using Seq::begin;\n      using Seq::end;\n\n      obj_list() : mark{this->before_begin()} { }\n\n      Index size() const final\n      {\n         return std::distance(Impl::begin(), Impl::end());\n      }\n\n      Impl& backing_store() { return *this; }\n      const Impl& backing_store() const { return *this; }\n      const projection<T>& get(Index p) const final\n      {\n         if (p < 0 or p >= size())\n            throw std::domain_error(\"obj_list::get\");\n\n         auto b = Impl::begin();\n         std::advance(b, p);\n         return *b;\n      }\n\n      template<typename... Args>\n      T* push_back(Args&&... args)\n      {\n         mark = Impl::emplace_after(mark, std::forward<Args>(args)...);\n         return &*mark;\n      }\n   private:\n      typename Impl::iterator mark;\n   };\n\n                              // -- impl::empty_sequence --\n   // There are various situations where the general notion of\n   // sequence leads to consider empty sequence in implementations.\n   // We could just use the generic ref_sequence<> or obj_list<>;\n   // however, this specialization will help control data size\n   // inflation, as the general sequences need at least two words\n   // to keep track of their elements (even when they are empty).\n   template<class T>\n   struct empty_sequence : ipr::Sequence<T> {\n      using Index = typename Sequence<T>::Index;\n      Index size() const final { return 0; }\n\n      const T& get(Index) const final\n      {\n         throw std::domain_error(\"empty_sequence::get\");\n      }\n   };\n\n   // --impl::singleton\n   // A singleton container (in Standard C++ sense), providing the backing store for\n   // the implementation of a singleton sequence.  No allocator or other complications.\n   // Usual minimal requirements: begin(), end()\n   // Optionally: front().\n   // FIXME: It is a pity it takes this amount of code to provide that simple\n   //        interface, in C++20.\n   template<typename T>\n   struct singleton {\n      using iterator = T*;\n      using const_iterator = const T*;\n      template<typename... Args>\n      explicit singleton(Args&&... args) : item{std::forward<Args>(args)...} { }\n      iterator begin() { return &item; }\n      const_iterator begin() const { return &item; }\n      iterator end() { return begin() + 1; }\n      const_iterator end() const { return begin() + 1; }\n      T& front() { return item; }\n      const T& front() const { return item; }\n   private:\n      T item;\n   };\n\n   // A sequence implementation for the case of a collection consisting of exactly one element.\n   template<typename T>\n   struct singleton_obj : ipr::Sequence<projection<T>> {\n      using Index = typename Sequence<projection<T>>::Index;\n\n      template<typename... Args>\n      singleton_obj(Args&&... args) : seq{std::forward<Args>(args)...} { }\n      Index size() const final { return 1; }\n      const projection<T>& get(Index i) const final\n      {\n         if (i == 0)\n            return seq.front();\n         throw std::domain_error(\"singleton::get\");\n      }\n      const T& element() const { return seq.front(); }\n      singleton<T>& backing_store() { return seq; }\n      const singleton<T>& backing_store() const { return seq; }\n   private:\n      impl::singleton<T> seq;\n   };\n}\n\nnamespace ipr::impl {\n   // The natural C++ data and control transfer.\n   const ipr::Transfer& cxx_transfer();\n\n   // The two language linkages required of all C++ implementations.\n   const ipr::Language_linkage& c_linkage();\n   inline const ipr::Language_linkage& cxx_linkage() { return cxx_transfer().language_linkage(); }\n\n   // The type of types, including itselt.\n   // Yes, we have a ``Type: Type'' problem.\n   const ipr::Type& typename_type();\n\n   // -- impl::Classic\n   template<class Operation>\n   struct Classic : Operation {\n      Optional<ipr::Expr> op_impl { };\n      using Operation::Operation;\n\n      Optional<ipr::Expr> implementation() const final { return op_impl; }\n   };\n\n   // -- impl::Expr\n   template<class Interface>\n   struct Expr : immotile_node<Interface> {\n      Optional<ipr::Type> typing;\n      constexpr Expr(Optional<ipr::Type> t = { }) : typing{ t } { }\n      const ipr::Type& type() const final { return typing.get(); }\n   };\n\n   // -- impl::Unary_expr: Short hand for the implementation of generic unary expression nodes.\n   template<typename T>\n   using Unary_expr = Basic_unary<Expr<T>>;\n\n   // -- impl::Classic_unary_expr\n   template<typename T>\n   using Classic_unary_expr = Classic<Unary_expr<T>>;\n\n   // -- impl::Binary_expr\n   template<typename T>\n   using Binary_expr = impl::Basic_binary<Expr<T>>;\n\n   // -- impl::Classic_binary_expr\n   template<typename T>\n   using Classic_binary_expr = Classic<Binary_expr<T>>;\n\n   // -----------------------\n   // -- Generalized types --\n   // -----------------------\n   // impl::Type<T> implements the common operations supported\n   // by all type node objects.  Almost all C++ types have \"C++\" language linkage.\n   // The exceptions are handled elsewhere.\n   template<class T>\n   struct Type : impl::Node<T> {\n      const ipr::Transfer& transfer() const final { return impl::cxx_transfer(); }\n   };\n\n   // A composite type is one built from existing types and built-in type constructors.\n   // Their names are exactly the type-expressions referencing the types themselves.\n   template<typename T>\n   struct Composite : impl::Type<T> {\n      constexpr Composite() : id{*this} { }\n      const ipr::Type& type() const final { return impl::typename_type(); }\n      const ipr::Name& name() const final { return id; }\n   private:\n      impl::Type_id id;\n   };\n\n   // -- impl::Unary_type\n   template<typename T>\n   using Unary_type = impl::Basic_unary<Composite<T>>;\n\n   // -- impl::Binary_type\n   template<typename T>\n   using Binary_type = impl::Basic_binary<Composite<T>>;\n\n   // -- impl::Ternary_type\n   template<typename T>\n   using Ternary_type = Ternary<Composite<T>>;\n}\n\nnamespace ipr::impl{\n   // ----------------------------------------------------\n   // -- Scopes, sequence of declarations and overloads --\n   // ----------------------------------------------------\n   //\n   // A scope is defined to be a sequence of declarations.\n   // There may be multiple instances of a declaration in\n   // a scope.  All declarations sharing the same name\n   // form an overload set.  Consequently a scope is partitioned\n   // into overload sets, each of which is uniquely identified\n   // by its name.\n   // An overload set, in turn, is partitioned in sub-sets of\n   // (multiple) declarations with same type.  So, each decl-set\n   // within its overload set, is uniquely determined by its\n   // type.  Each decl-set has a \"standard\" representative,\n   // called the \"master declaration\".  A master declaration is\n   // the first seen declaration of a decl-set.\n   //\n   // There are few special cases of the above general description.\n   // Parameters, base-classes and enumerators cannot be multiply\n   // declared.  Therefore within a parameter-lits, a base-class\n   // list or an enumeration definition, each decl-set is\n   // singleton whose sole element is the master declaration.\n   //\n   // A scope chains declaration together.  A declaration in a\n   // Scope has a \"position\", that uniquely identifies it as a member\n   // of a sequence.  To provide a relatively fast \"subscription by position\"\n   // operation on a scope, the chain of declaration is\n   // organized as a red-back tree where the position is used as key.\n   // And alternative is a hash table, when we get there.\n\n   // The chain of declarations in a scope.\n   struct scope_datum : util::rb_tree::link<scope_datum> {\n      // The specifiers for this declaration.  S\n      ipr::Specifiers spec = { };\n\n      // Back-pointer to this declaration.  It shall be set at\n      // the declaration creation.\n      const ipr::Decl* decl = { };\n   };\n\n                              // -- impl::decl_sequence --\n   struct decl_sequence : ref_sequence<ipr::Decl> { };\n\n                              // -- impl::singleton_ref --\n   // A singleton_ref is a specialization of ref_sequence that contains\n   // exactly a single reference.  It is mostly used to support the\n   // general interface of singly-item as inherited in parameter-list or\n   // enumerator definitions or EH regions.\n   template<typename T>\n   struct singleton_ref : ipr::Sequence<T> {\n      using Index = typename Sequence<T>::Index;\n      const T& datum;\n      explicit singleton_ref(const T& t) : datum(t) { }\n      Index size() const final { return 1; }\n      const T& get(Index i) const final\n      {\n         if (i == 0)\n            return datum;\n         throw std::domain_error(\"singleton_ref::get\");\n      }\n   };\n\n   // Parameters, base-subobjects and enumerations cannot be\n   // multiply declared in a given region.  Therefore such a\n   // declaration is the sole member in its own decl-set.\n   // Furthermore, there cannot be other declaration with\n   // different type but same name.  Therefore the name for\n   // such a declaration defines an overload set with a single\n   // member.  This class implements such a special overload set.\n   template<typename T>\n   struct singleton_overload : immotile_node<ipr::Overload> {\n      T decl;                          // Really the declset, but it is a singleton.\n      template<typename... Args>\n      explicit singleton_overload(const Args&... args) : decl{args...} { }\n      const ipr::Name& name() const { return decl.name(); }\n      const ipr::Type& type() const final { return decl.type(); }\n      Optional<ipr::Decl> operator[](const ipr::Type& t) const final\n      {\n         if (physically_same(t, decl.type()))\n            return decl;\n         return { };\n      }\n      // Where needed, implicitly unwrap the singleton to reveal its content.\n      operator const T&() const { return decl; }\n   };\n}\n\nnamespace ipr::impl {\n   // Scopes, as expressions, have Product types.  Such types could\n   // be implemented directly as a separate sequence of types.\n   // However, it would require coordination from the various\n   // scope updaters to keep the types in sync.  An alternative,\n   // implemented by typed_sequence<Seq>, is to wrap sequences\n   // in \"type envelop\" and return the nth type as being the\n   // type of the nth declaration in the sequence.\n   template<class Seq>\n   struct typed_sequence : impl::Composite<ipr::Product>,\n                           ipr::Sequence<ipr::Type> {\n      using Index = typename Sequence<ipr::Type>::Index;\n      Seq seq;\n\n      typed_sequence() { }\n      explicit typed_sequence(const Seq& s) : seq(s) { }\n      template<typename... Args>\n      explicit typed_sequence(Args&&... args) : seq(std::forward<Args>(args)...) { }\n      const ipr::Sequence<ipr::Type>& operand() const final { return *this; }\n      Index size() const final { return seq.size(); }\n      const ipr::Type& get(Index i) const final\n      {\n         return seq.get(i).type();\n      }\n   };\n}\n\nnamespace ipr::impl {\n   // -- homogeneous_scope\n   // A sequence of homogenous node can be represented directly as a container\n   // of the concrete implementations classes instead of pointers to the\n   // interface nodes.  This is the case, in particular, for enumerators of\n   // an enumeration or parameters in a parameter list.\n   template<typename Member, template<typename> class Seq = obj_list>\n   struct homogeneous_scope : impl::Node<ipr::Scope>,\n                              ipr::Sequence<ipr::Decl>,\n                              ipr::Sequence<ipr::Expr> {\n      using Index = typename ipr::Sequence<ipr::Decl>::Index;\n      using Members = Seq<singleton_overload<Member>>;\n      typed_sequence<Members> decls;\n      template<typename... Args>\n      homogeneous_scope(Args&&... args) : decls{std::forward<Args>(args)...} { }\n      Index size() const final { return decls.size(); }\n      const projection<Member>& get(Index i) const final { return decls.seq.get(i); }\n      const ipr::Product& type() const final { return decls; }\n      const ipr::Sequence<ipr::Decl>& elements() const final { return *this; }\n      Optional<ipr::Overload> operator[](const Name&) const final;\n      template<typename... Args>\n      Member* push_back(const Args&... args)\n      {\n         return &decls.seq.push_back(args...)->decl;\n      }\n   };\n\n   // FIXME: Remove this linear search.\n   template<typename Member, template<typename> class Seq>\n   Optional<ipr::Overload>\n   homogeneous_scope<Member, Seq>::operator[](const ipr::Name& n) const\n   {\n      for (auto& decl : decls.seq.backing_store()) {\n         if (physically_same(decl.name(), n))\n            return { decl };\n      }\n      return { };\n   }\n\n   // -- impl::homogeneous_region:\n   template<typename Member, template<typename> class Seq = obj_list>\n   struct homogeneous_region : impl::Node<ipr::Region> {\n      using location_span = ipr::Region::Location_span;\n      const ipr::Region& parent;\n      location_span extent;\n      Optional<ipr::Expr> owned_by { };\n      homogeneous_scope<Member, Seq> scope;\n\n      explicit homogeneous_region(const ipr::Region& p) : parent(p) { }\n      template<typename... Args>\n      explicit homogeneous_region(const ipr::Region& r, Args&&... args)\n         : parent{r}, scope{r, std::forward<Args>(args)...}\n      { }\n      const ipr::Region& enclosing() const final { return parent; }\n      const ipr::Sequence<ipr::Expr>& body() const final { return scope; }\n      const ipr::Scope& bindings() const final { return scope; }\n      const location_span& span() const final { return extent; }\n      Optional<ipr::Expr> owner() const final { return owned_by; }\n      bool global() const final { return false; }\n   };\n}\n\nnamespace ipr::impl {\n   // -- impl::Directive\n   template<typename T, Phases f>\n   struct Directive : impl::Expr<T> {\n      Phases phases() const final { return f; }\n   };\n\n   template<class S>\n   struct Stmt : S {\n      ipr::Unit_location unit_locus;\n      ipr::Source_location src_locus;\n      ref_sequence<ipr::Annotation> notes;\n      ref_sequence<ipr::Attribute> attrs;\n      const ipr::Unit_location& unit_location() const final { return unit_locus; }\n      const ipr::Source_location& source_location() const final { return src_locus; }\n      const ipr::Sequence<ipr::Annotation>& annotation() const final { return notes; }\n      const ipr::Sequence<ipr::Attribute>& attributes() const final { return attrs; }\n   };\n\n   template<typename S>\n   using immotile_stmt = Stmt<immotile_node<S>>;\n}\n\nnamespace ipr::impl {\n   // -- unique_decl:\n   // Some declarations (e.g. parameters, base-classes, enumerators)\n   // cannot be redeclared in their declarative regions.  Consequently\n   // their decl-sets and overload sets are singleton, containing\n   // only the mater declarations.  Consequently, it seems\n   // heavyweight space wasteful to deploy the general representation\n   // machinery for them.  The class unique_decl<> implements the\n   // specialization of Decl<> in those cases.\n   template<class Interface>\n   struct unique_decl : immotile_stmt<Interface> {\n      unique_decl() : seq{*this} { }\n      ipr::Specifiers specifiers() const override { return { }; }\n      const ipr::Decl& master() const final { return *this; }\n      const ipr::Language_linkage& language_linkage() const final { return impl::cxx_linkage(); }\n      const ipr::Sequence<ipr::Decl>& decl_set() const final { return seq; }\n   private:\n      singleton_ref<ipr::Decl> seq;\n   };\n}\n\nnamespace ipr::impl {\n   struct Parameter_list;\n\n                              // -- impl::Parameter --\n   struct Parameter final : unique_decl<ipr::Parameter> {\n      Optional<ipr::Expr> init;\n      Parameter(const ipr::Name&, const ipr::Type&, Decl_position);\n      const ipr::Name& name() const final { return id; }\n      const ipr::Type& type() const final { return typing; }\n      const ipr::Region& home_region() const final { return where.get().region(); }\n      Mapping_level level() const final { return where.get().level(); }\n      Decl_position position() const final { return pos; }\n      Optional<ipr::Expr> initializer() const final { return init; }\n   private:\n      const ipr::Name& id;\n      const ipr::Type& typing;\n      util::ref<const ipr::Parameter_list> where;\n      const Decl_position pos;\n      friend struct Parameter_list;\n   };\n\n                              // -- impl::Parameter_list --\n   struct Parameter_list : impl::Node<ipr::Parameter_list> {\n      Parameter_list(const ipr::Region&, Mapping_level);\n      const ipr::Product& type() const final;\n      const ipr::Region& region() const final;\n      Mapping_level level() const final { return nesting; }\n      const ipr::Sequence<ipr::Parameter>& elements() const final;\n      impl::Parameter* add_member(const ipr::Name&, const ipr::Type&);\n\n      // Need access by Mapping, Lambda and whomever creates Callable_species\n      homogeneous_region<impl::Parameter> parms;\n   private:\n      const Mapping_level nesting;\n   };\n\n   // -- impl::Parameterization\n   template<typename T, typename Base>\n   struct Parameterization : Base {\n      impl::Parameter_list inputs;\n      util::ref<const T> body;\n      Parameterization(const ipr::Region& r, Mapping_level l) : inputs{r, l} { }\n      const ipr::Parameter_list& parameters() const final { return inputs; }\n      const T& result() const final { return body.get(); }\n   };\n}\n\nnamespace ipr::cxx_form::impl {\n   // -- implementation of ipr::cxx_form::Constraint\n   template<typename T>\n   struct Constraint : T, ipr::util::immotile {\n      using Interface = T;\n      void accept(Constraint_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Constraint::Monadic\n   struct Monadic_constraint : impl::Constraint<cxx_form::Constraint::Monadic> {\n      explicit Monadic_constraint(const ipr::Identifier& n) : id{n} { }\n      Monadic_constraint(const ipr::Expr& s, const ipr::Identifier& n) : outer{s}, id{n} { }\n      Optional<ipr::Expr> scope() const final { return outer; }\n      const ipr::Identifier& concept_name() const final { return id; }\n   private:\n      Optional<ipr::Expr> outer { };\n      const ipr::Identifier& id;\n   };\n\n   // -- implementation of ipr::cxx_form::Constraint::Polyadic\n   struct Polyadic_constraint : impl::Constraint<cxx_form::Constraint::Polyadic> {\n      ipr::impl::ref_sequence<ipr::Expr> args;\n      explicit Polyadic_constraint(const ipr::Identifier& n) : id{n} { }\n      Polyadic_constraint(const ipr::Expr& s, const ipr::Identifier& n) : outer{s}, id{n} { }\n      Optional<ipr::Expr> scope() const final { return outer; }\n      const ipr::Identifier& concept_name() const final { return id; }\n      const ipr::Sequence<ipr::Expr>& trailing_arguments() const final { return args; }\n   private:\n      Optional<ipr::Expr> outer { };\n      const ipr::Identifier& id;\n   };\n\n   // -- implementation of ipr::cxx_form::Requirement\n   template<typename T>\n   struct Requirement : T, ipr::util::immotile {\n      using Interface = T;\n      void accept(Requirement_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Requirement::Simple\n   struct Simple_requirement : impl::Requirement<cxx_form::Requirement::Simple> {\n      explicit Simple_requirement(const ipr::Expr& x) : pattern{x} { }\n      const ipr::Expr& expr() const final { return pattern; }\n   private:\n      const ipr::Expr& pattern;\n   };\n\n   // -- implementation of ipr::cxx_form::Requirement::Type\n   struct Type_requirement : impl::Requirement<cxx_form::Requirement::Type> {\n      explicit Type_requirement(const ipr::Name& n) : name{n} { }\n      Type_requirement(const ipr::Expr& s, const ipr::Name& n) : outer{s}, name{n} { }\n      Optional<ipr::Expr> scope() const final { return outer; }\n      const ipr::Name& type_name() const final { return name; }\n   private:\n      Optional<ipr::Expr> outer { };\n      const ipr::Name& name;\n   };\n\n   // -- implementation of ipr::cxx_form::Requirement::Compound\n   struct Compound_requirement : impl::Requirement<cxx_form::Requirement::Compound> {\n      Optional<cxx_form::Constraint> type;\n      bool has_noexcept = false;\n      explicit Compound_requirement(const ipr::Expr& x) : pattern{x} { }\n      const ipr::Expr& expr() const final { return pattern; }\n      Optional<cxx_form::Constraint> constraint() const final { return type; }\n      bool nothrow() const final { return has_noexcept; }\n   private:\n      const ipr::Expr& pattern;\n   };\n\n   // -- implementation of ipr::cxx_form::Requirement::Compound\n   struct Nested_requirement : impl::Requirement<cxx_form::Requirement::Nested> {\n      explicit Nested_requirement(const ipr::Expr& x) : cond{x} { }\n      const ipr::Expr& condition() const final { return cond; }\n   private:\n      const ipr::Expr& cond;\n   };\n\n   // -- implementation of ipr::cxx_form::Indirector\n   template<typename T>\n   struct Indirector : T {\n      using Interface = T;\n      ipr::impl::ref_sequence<ipr::Attribute> attr_seq;\n      const ipr::Sequence<ipr::Attribute>& attributes() const final { return attr_seq; }\n      void accept(Indirector_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Indirector::Pointer\n   struct Pointer_indirector : impl::Indirector<cxx_form::Indirector::Pointer> {\n      explicit Pointer_indirector(ipr::Qualifiers q) : quals{q} { }\n      ipr::Qualifiers qualifiers() const final { return quals; }\n   private:\n      ipr::Qualifiers quals;\n   };\n\n   // -- implementation of ipr::cxx_form::Indirector::Reference\n   struct Reference_indirector : impl::Indirector<cxx_form::Indirector::Reference> {\n      explicit Reference_indirector(Reference_flavor f) : how{f} { }\n      Reference_flavor flavor() const final { return how; }\n   private:\n      Reference_flavor how { };\n   };\n\n   // -- implementation of ipr::cxx_form::Indirector::Member\n   struct Member_indirector : impl::Indirector<cxx_form::Indirector::Member> {\n      Member_indirector(const ipr::Expr& s, ipr::Qualifiers q) : whole{s}, quals{q} { }\n      const ipr::Expr& scope() const final { return whole; }\n      ipr::Qualifiers qualifiers() const final { return quals; }\n   private:\n      const ipr::Expr& whole;\n      ipr::Qualifiers quals;\n   };\n\n   // -- implementation of ipr::cxx_form::Morphism\n   template<typename T>\n   struct Morphism : T {\n      using Interface = T;\n      ipr::impl::ref_sequence<ipr::Attribute> attr_seq;\n      const ipr::Sequence<ipr::Attribute>& attributes() const final { return attr_seq; }\n      void accept(Morphism_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Morphism::Function\n   struct Function_morphism : impl::Morphism<cxx_form::Morphism::Function> {\n      ipr::impl::Parameter_list inputs;\n      Optional<ipr::Expr> eh_spec;\n      ipr::Qualifiers quals { };\n      Binding_mode ref_qual { };\n      Function_morphism(const ipr::Region&, Mapping_level);\n      const ipr::Parameter_list& parameters() const final { return inputs; }\n      Optional<ipr::Expr> throws() const final { return eh_spec; }\n      ipr::Qualifiers qualifiers() const final { return quals; }\n      Binding_mode binding_mode() const final { return ref_qual; }\n   };\n\n   // -- implementation of ipr::cxx_form::Morphism::Array\n   struct Array_morphism : impl::Morphism<cxx_form::Morphism::Array> {\n      Optional<ipr::Expr> array_bound;\n      Optional<ipr::Expr> bound() const final { return array_bound; }\n   };\n\n   // -- implementation of ipr::cxx_form::Species_declarator\n   template<typename T>\n   struct Species : T {\n      using Interface = T;\n      ipr::impl::ref_sequence<cxx_form::Morphism> morphisms;\n      const ipr::Sequence<cxx_form::Morphism>& suffix() const final { return morphisms; }\n      void accept(Species_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // Provide implementation for common operations for the various classes implementing\n   // classes for instances of declarator-id.\n   template<typename T>\n   struct Id_species : impl::Species<T> {\n      ipr::impl::ref_sequence<ipr::Attribute> attr_seq;\n      const ipr::Sequence<ipr::Attribute>& attributes() const final { return attr_seq; }\n   };\n\n   // Provide implementation for common operations for the various classes implementing\n   // unqualified-id instances of declarator-id.\n   template<typename T, typename S>\n   struct Name_species : impl::Id_species<T> {\n      Name_species() = default;\n      explicit Name_species(const S& s) : id{s} { }\n      Optional<S> name() const final { return id; }\n   private:\n      Optional<S> id{ };\n   };\n\n   // -- implementation of ipr::cxx_form::Species_declarator::Unqualified_id\n   using Unqualified_id_species = Name_species<cxx_form::Species_declarator::Unqualified_id, ipr::Name>;\n\n   // -- implementation of ipr::cxx_form::Species_declarator::Pack\n   using Pack_species = Name_species<cxx_form::Species_declarator::Pack, ipr::Identifier>;\n\n   // -- implementation of ipr::cxx_form::Species_declarator::Qualified_id\n   struct Qualified_id_species : impl::Id_species<cxx_form::Species_declarator::Qualified_id> {\n      Qualified_id_species(const ipr::Expr& s, const ipr::Name& n) : outer{s}, id{n} { }\n      const ipr::Expr& scope() const final { return outer; }\n      const ipr::Name& member() const final { return id; }\n   private:\n      const ipr::Expr& outer;\n      const ipr::Name& id;\n   };\n\n   // -- implementation of ipr::cxx_form::Species_declarator::Parenthesized\n   struct Parenthesized_species : impl::Species<cxx_form::Species_declarator::Parenthesized> {\n      util::ref<const Declarator::Term> declarator;\n      const Declarator::Term& term() const final { return declarator.get(); }\n   };\n\n   // -- implementation of ipr::cxx_form::Declarator.\n   // Only the `accept()` operation is implemented here.  The other common operation, `species()`,\n   // is individually implemented by each of the derived classes.\n   template<typename T>\n   struct Declarator : T {\n      using Interface = T;\n      void accept(cxx_form::Declarator_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Declarator::Term\n   struct Term_declarator : impl::Declarator<cxx_form::Declarator::Term> {\n      ipr::impl::ref_sequence<cxx_form::Indirector> prefix;\n      util::ref<cxx_form::Species_declarator> tail;\n      const ipr::Sequence<cxx_form::Indirector>& indirectors() const final { return prefix; }\n      const Species_declarator& species() const final { return tail.get(); }\n   };\n\n   // -- implementation of ipr::cxx_form::Declarator::Targeted\n   struct Targeted_declarator : impl::Declarator<cxx_form::Declarator::Targeted> {\n      Targeted_declarator(const cxx_form::Species_declarator& s, const ipr::Type& t)\n         : domain{s}, range{t} { }\n      const cxx_form::Species_declarator& species() const final { return domain; }\n      const ipr::Type& target() const final { return range; }\n   private:\n      const cxx_form::Species_declarator& domain;\n      const ipr::Type& range;\n   };\n\n   // -- implementation of ipr::cxx_form::Initialization_provision\n   template<typename T>\n   struct Initialization_provision : T {\n      void accept(cxx_form::Provision_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Elemental_initializer\n   template<typename T>\n   struct Elemental_initializer : T {\n      using Interface = T;\n      void accept(cxx_form::Initializer_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Subobject_designator\n   template<typename T>\n   struct Subobject_designator : T {\n      using Interface = T;\n      void accept(cxx_form::Designator_visitor& v) const final { v.visit(static_cast<const T&>(*this)); }\n   };\n\n   // -- implementation of ipr::cxx_form::Field_designator\n   struct Field_designator : impl::Subobject_designator<cxx_form::Field_designator> {\n      explicit Field_designator(const ipr::Identifier& x) : id{x} { }\n      const ipr::Identifier& name() const final { return id; }\n   private:\n      const ipr::Identifier& id;\n   };\n\n   // -- implementation of ipr::cxx_form::Slot_designator\n   struct Slot_designator : impl::Subobject_designator<cxx_form::Slot_designator> {\n      explicit Slot_designator(const ipr::Expr& x) : idx{x} { }\n      const ipr::Expr& index() const final { return idx; }\n   private:\n      const ipr::Expr& idx;\n   };\n\n   // -- implementation of ipr::cxx_form::Earmarked_initializer\n   struct Earmarked_initializer : cxx_form::Earmarked_initializer {\n      using Interface = cxx_form::Earmarked_initializer;\n      Earmarked_initializer(const cxx_form::Subobject_designator& f, const cxx_form::Initialization_provision& x)\n         : sub{f}, init{x} { }\n      const cxx_form::Subobject_designator& subobject() const final { return sub; }\n      const cxx_form::Initialization_provision& initializer() const final { return init; }\n   private:\n      const cxx_form::Subobject_designator& sub;\n      const cxx_form::Initialization_provision& init;\n   };\n\n   // -- implementation of ipr::cxx_form::Classic_provision\n   struct Classic_provision : impl::Initialization_provision<ipr::cxx_form::Classic_provision> {\n      explicit Classic_provision(const ipr::cxx_form::Elemental_initializer& i) : init{i} { }\n      const ipr::cxx_form::Elemental_initializer& initializer() const final { return init; }\n   private:\n      const ipr::cxx_form::Elemental_initializer& init;\n   };\n\n   // -- implementation of ipr::cxx_form::Parenthesized_provision\n   struct Parenthesized_provision : impl::Initialization_provision<ipr::cxx_form::Parenthesized_provision> {\n      explicit Parenthesized_provision(const ipr::Expr& x) : expr{x} { }\n      const ipr::Expr& initializer() const final { return expr; }\n   private:\n      const ipr::Expr& expr;\n   };\n\n   // -- implementation of ipr::cxx_form::Braced_provision\n   struct Braced_provision : impl::Initialization_provision<impl::Elemental_initializer<ipr::cxx_form::Braced_provision>> {\n      ipr::impl::ref_sequence<cxx_form::Elemental_initializer> seq;\n      const ipr::Sequence<cxx_form::Elemental_initializer>& elements() const final { return seq; }\n   };\n\n   // -- implementation of ipr::cxx_form::Designated_list_provision\n   struct Designated_list_provision : impl::Initialization_provision<impl::Elemental_initializer<cxx_form::Designated_list_provision>> {\n      ipr::impl::obj_sequence<cxx_form::impl::Earmarked_initializer> seq;\n      const ipr::Sequence<cxx_form::Earmarked_initializer>& elements() const final { return seq; }\n   };   \n\n   // -- Factory of C++ declarator forms.\n   struct form_factory {\n      Monadic_constraint* make_monadic_constraint(const ipr::Identifier&);\n      Monadic_constraint* make_monadic_constraint(const ipr::Expr&, const ipr::Identifier&);\n      Polyadic_constraint* make_polyadic_constraint(const ipr::Identifier&);\n      Polyadic_constraint* make_polyadic_constraint(const ipr::Expr&, const ipr::Identifier&);\n      Simple_requirement* make_simple_requirement(const ipr::Expr&);\n      Type_requirement* make_type_requirement(const ipr::Name&);\n      Type_requirement* make_type_requirement(const ipr::Expr&, const ipr::Name&);\n      Compound_requirement* make_compound_requirement(const ipr::Expr&);\n      Nested_requirement* make_nested_requirement(const ipr::Expr&);\n\n      Pointer_indirector* make_pointer_indirector(ipr::Qualifiers);\n      Reference_indirector* make_reference_indirector(Reference_flavor);\n      Member_indirector* make_member_indirector(const ipr::Expr&, ipr::Qualifiers);\n      Unqualified_id_species* make_unqualified_id_species();\n      Unqualified_id_species* make_unqualified_id_species(const ipr::Name&);\n      Pack_species* make_pack_species();\n      Pack_species* make_pack_species(const ipr::Identifier&);\n      Qualified_id_species* make_qualified_id_species(const ipr::Expr&, const ipr::Name&);\n      Parenthesized_species* make_parenthesized_species();\n      Function_morphism* make_function_morphism(const ipr::Region& parent, Mapping_level level);\n      Array_morphism* make_array_morphism();\n      Term_declarator* make_term_declarator();\n      Targeted_declarator* make_targeted_declarator(const cxx_form::Species_declarator&, const ipr::Type&);\n      Classic_provision* make_classic_provision(const cxx_form::Elemental_initializer&);\n      Parenthesized_provision* make_parenthesized_provision(const ipr::Expr&);\n      Braced_provision* make_braced_provision();\n      Designated_list_provision* make_designated_provision();\n      Field_designator* make_field_designator(const ipr::Identifier&);\n      Slot_designator* make_slot_designator(const ipr::Expr&);\n\n   private:\n      ipr::impl::stable_farm<Monadic_constraint> monadic_constraints;\n      ipr::impl::stable_farm<Polyadic_constraint> polyadic_constraints;\n      ipr::impl::stable_farm<Simple_requirement> simple_reqs;\n      ipr::impl::stable_farm<Type_requirement> type_reqs;\n      ipr::impl::stable_farm<Compound_requirement> compound_reqs;\n      ipr::impl::stable_farm<Nested_requirement> nested_reqs;\n      ipr::impl::stable_farm<Pointer_indirector> pointer_indirectors;\n      ipr::impl::stable_farm<Reference_indirector> reference_indirectors;\n      ipr::impl::stable_farm<Member_indirector> member_indirectors;\n      ipr::impl::stable_farm<Unqualified_id_species> unqualified_id_species;\n      ipr::impl::stable_farm<Pack_species> pack_species;\n      ipr::impl::stable_farm<Qualified_id_species> qualified_id_species;\n      ipr::impl::stable_farm<Parenthesized_species> paren_species;\n      ipr::impl::stable_farm<Function_morphism> function_morphisms;\n      ipr::impl::stable_farm<Array_morphism> array_morphisms;\n      ipr::impl::stable_farm<Term_declarator> term_declarators;\n      ipr::impl::stable_farm<Targeted_declarator> targeted_declarators;\n      ipr::impl::stable_farm<Classic_provision> classic_provisions;\n      ipr::impl::stable_farm<Parenthesized_provision> paren_provisions;\n      ipr::impl::stable_farm<Braced_provision> braced_provisions;\n      ipr::impl::stable_farm<Designated_list_provision> designated_provisions;\n      ipr::impl::stable_farm<Field_designator> field_designators;\n      ipr::impl::stable_farm<Slot_designator> slot_designators;\n   };\n}\n\nnamespace ipr::impl {\n   struct Lexicon;\n\n   template<class T>\n   struct node_ref {\n      const T& node;\n      explicit node_ref(const T& t) : node(t) { }\n   };\n\n                              // -- impl::Token --\n   struct Token : ipr::Lexeme, ipr::Token {\n      using Interface = ipr::Token;\n      Token(const ipr::String&, const Source_location&, TokenValue, TokenCategory);\n      const ipr::String& spelling() const final { return text; }\n      const Source_location& locus() const final { return location; }\n      const ipr::Lexeme& lexeme() const final { return *this; }\n      TokenValue value() const final { return token_value; }\n      TokenCategory category() const final { return token_category; }\n\n   private:\n      const ipr::String& text;\n      Source_location location;\n      TokenValue token_value;\n      TokenCategory token_category;\n   };\n\n   // -- Parameterized implementation of ipr::Attribute.\n   // -- The type parameter is used here as a device to implement an overrider\n   // -- for ipr::Attribute::visit(), for all T implementation classes of attribute.\n   template<typename T>\n   struct Attribute : T {\n      void accept(typename T::Visitor& v) const final { v.visit(*this); }\n   };\n\n   template<typename T>\n   using Unary_attribute = impl::Basic_unary<impl::Attribute<T>>;\n   template<typename T>\n   using Binary_attribute = impl::Basic_binary<impl::Attribute<T>>;\n\n   // -- implementation of ipr::BasicAttribute\n   using BasicAttribute = Unary_attribute<ipr::BasicAttribute>;\n\n   // -- implementation of ipr::ScopedAttribute\n   using ScopedAttribute = Binary_attribute<ipr::ScopedAttribute>;\n\n   // -- implementation of ipr::LabeledAttribute\n   using LabeledAttribute = Binary_attribute<ipr::LabeledAttribute>;\n\n   // -- implementation of ipr::CalledAttribute\n   using CalledAttribute = Binary_attribute<ipr::CalledAttribute>;\n\n   // -- implementation of ipr::ExpandedAttribute\n   using ExpandedAttribute = Binary_attribute<ipr::ExpandedAttribute>;\n\n   // -- implementation of ipr::FactoredAttribute\n   using FactoredAttribute = Binary_attribute<ipr::FactoredAttribute>;\n\n   // -- implementation of ipr::ElaboratedAttribute\n   using ElaboratedAttribute = Unary_attribute<ipr::ElaboratedAttribute>;\n\n   // -- Attributes factory --\n   struct attr_factory {\n      const ipr::BasicAttribute& make_basic_attribute(const ipr::Token&);\n      const ipr::ScopedAttribute& make_scoped_attribute(const ipr::Token&, const ipr::Token&);\n      const ipr::LabeledAttribute& make_labeled_attribute(const ipr::Token&, const ipr::Attribute&);\n      const ipr::CalledAttribute& make_called_attribute(const ipr::Attribute&, const ipr::Sequence<ipr::Attribute>&);\n      const ipr::ExpandedAttribute& make_expanded_attribute(const ipr::Token&, const ipr::Attribute&);\n      const ipr::FactoredAttribute& make_factored_attribute(const ipr::Token&, const ipr::Sequence<ipr::Attribute>&);\n      const ipr::ElaboratedAttribute& make_elaborated_attribute(const ipr::Expr&);\n   private:\n      stable_farm<impl::BasicAttribute> basics;\n      stable_farm<impl::ScopedAttribute> scopeds;\n      stable_farm<impl::LabeledAttribute> labeleds;\n      stable_farm<impl::CalledAttribute> calleds;\n      stable_farm<impl::ExpandedAttribute> expandeds;\n      stable_farm<impl::FactoredAttribute> factoreds;\n      stable_farm<impl::ElaboratedAttribute> elaborateds;\n   };\n\n   // -- implementation for ipr::Capture\n   struct Capture : ipr::Capture {\n      using Interface = ipr::Capture;\n      Capture(const ipr::Decl& d, ipr::Binding_mode m) : decl{d}, md{m} { }\n      ipr::Binding_mode mode() const final { return md; }\n      const ipr::Decl& entity() const final { return decl; }\n   private:\n      const ipr::Decl& decl;\n      const ipr::Binding_mode md;\n   };\n\n   // -- Generic implementation of ipr::Capture_specification\n   template<typename T>\n   struct Capture_specification : T {\n      void accept(typename T::Visitor& v) const final { v.visit(*this); }\n   };\n\n   // -- implementation of ipr::Capture_specification::Default\n   struct Default_capture_specification : Capture_specification<ipr::Capture_specification::Default> {\n      explicit Default_capture_specification(Binding_mode m) : md{m} { }\n      Binding_mode mode() const final { return md; }\n   private:\n      const Binding_mode md;\n   };\n\n   // -- implementation of ipr::Capture_specification::Implicit_object\n   struct Implicit_object_capture_specification : Capture_specification<ipr::Capture_specification::Implicit_object> {\n      explicit Implicit_object_capture_specification(Binding_mode m) : md{m} { }\n      Binding_mode how() const final { return md; }\n   private:\n      const Binding_mode md;\n   };\n\n   // -- implementation of ipr::Capture_specification::Enclosing_local\n   struct Enclosing_local_capture_specification : Capture_specification<ipr::Capture_specification::Enclosing_local> {\n      Enclosing_local_capture_specification(const ipr::Decl& x, Binding_mode m) : decl{x}, md{m} { }\n      Binding_mode mode() const final { return md; }\n      const ipr::Identifier& name() const final;\n      const ipr::Decl& declaration() const final { return decl; }\n   private:\n      const ipr::Decl& decl;\n      const Binding_mode md;\n   };\n\n   // -- implementation of ipr::Capture_capture::Binding\n   struct Binding_capture_specification : Capture_specification<ipr::Capture_specification::Binding> {\n      Binding_capture_specification(const ipr::Identifier& n, const ipr::Expr& x, Binding_mode m) : id{n}, init{x}, md{m} { }\n      Binding_mode mode() const final { return md; }\n      const ipr::Identifier& name() const final { return id; }\n      const ipr::Expr& initializer() const final { return init; }\n   private:\n      const ipr::Identifier& id;\n      const ipr::Expr& init;\n      const Binding_mode md;\n   };\n\n   // -- implementation of ipr::Capture_specification::Expansion.\n   struct Expansion_capture_specification : Capture_specification<ipr::Capture_specification::Expansion> {\n      explicit Expansion_capture_specification(const Named& x) : cap{x} { }\n      const Named& what() const final { return cap; }\n   private:\n      const Named& cap;\n   };\n\n   // -- capture specification factory\n   struct capture_spec_factory {\n      const ipr::Capture_specification::Default& default_capture(Binding_mode);\n      const ipr::Capture_specification::Implicit_object& implicit_object_capture(Binding_mode);\n      const ipr::Capture_specification::Enclosing_local& enclosing_local_capture(const ipr::Decl&, Binding_mode);\n      const ipr::Capture_specification::Binding& binding_capture(const ipr::Identifier&, const ipr::Expr&, Binding_mode);\n      const ipr::Capture_specification::Expansion& expansion_capture(const ipr::Capture_specification::Named&);\n   private:\n      stable_farm<impl::Default_capture_specification> defaults;\n      stable_farm<impl::Implicit_object_capture_specification> implicits;\n      stable_farm<impl::Enclosing_local_capture_specification> enclosings;\n      stable_farm<impl::Binding_capture_specification> bindings;\n      stable_farm<impl::Expansion_capture_specification> expansions;\n   };\n\n                              // -- impl::Module_name --\n   struct Module_name : ipr::Module_name {\n      ref_sequence<ipr::Identifier> components;\n\n      const ipr::Sequence<ipr::Identifier>& stems() const final;\n   };\n\n\n   template<typename T,\n         typename std::enable_if_t<std::is_scalar_v<T>, int> = 0>\n   constexpr int compare(T lhs, T rhs)\n   {\n      constexpr std::less<> lt { };\n      return lt(lhs, rhs) ? -1 : (lt(rhs, lhs) ? 1 : 0);\n   }\n\n   constexpr int compare(const ipr::Node& lhs, const ipr::Node& rhs)\n   {\n      return compare(&lhs, &rhs);\n   }\n\n   constexpr int compare(const ipr::String& lhs, const ipr::String& rhs)\n   {\n      return lhs.characters().compare(rhs.characters());\n   }\n\n   inline int compare(const ipr::Logogram& lhs, const ipr::Logogram& rhs)\n   {\n      return compare(lhs.what(), rhs.what());\n   }\n\n   inline int compare(const ipr::Language_linkage& lhs, const ipr::Language_linkage& rhs)\n   {\n      return compare(lhs.language(), rhs.language());\n   }\n\n                              // -- Conversion_expr --\n   template<class Interface>\n   struct Conversion_expr : impl::Classic<Binary_node<Interface>> {\n      using Base = impl::Classic<Binary_node<Interface>>;\n      using Base::Base;\n      const ipr::Type& type() const final { return this->rep.first; }\n   };\n\n   // All declarations (except parameters, base-classes, enumerations)\n   // maintain data about their position and master declaration.  Since\n   // all declarations in a given decl-set have the same type, only\n   // the master declaration has the \"type\" information.\n   // Similarly, only the master declaration maintains the home\n   // region information.\n   //\n   // In a given decl-set, only one of the declarations is a definition.\n   // The master declaration keeps track of that definition, so all\n   // other redeclarations can refer to it through the master\n   // declaration data.\n\n   template<class> struct master_decl_data;\n   struct Overload;\n\n   // An entry in an overload set.  Part of the data that a\n   // master declaration manages.  It is determined, within\n   // an overload set, by its type.  All redeclarations must\n   // register themselves before the master declaration, at\n   // the creation time.\n\n   struct overload_entry : util::rb_tree::link<overload_entry> {\n      const ipr::Type& type;\n      ref_sequence<ipr::Decl> declset;\n      explicit overload_entry(const ipr::Type& t) : type(t) { }\n   };\n\n\n   template<class Interface>\n   struct basic_decl_data : scope_datum {\n      // Information about the master declaration.  This pointer\n      // shall be set at actual declaration creation time.\n      master_decl_data<Interface>* master_data;\n\n      explicit basic_decl_data(master_decl_data<Interface>* mdd)\n            : master_data(mdd)\n      { }\n   };\n\n   // A master declaration is the first seen introduction of\n   // a name with a given type.  Further redeclarations\n   // are represented by basic_decl_data<> and are linked to the\n   // master declaration.  That forms the declaration-set of\n   // that declaration.\n\n   template<class Interface>\n   struct master_decl_data : basic_decl_data<Interface>, overload_entry {\n      // The declaration that is considered to be the definition.\n      Optional<Interface> def { };\n      util::ref<const ipr::Language_linkage> lang_linkage { };\n\n      // The overload set that contains this master declaration.  It\n      // shall be set at the time the node for the master declaration\n      // is created.\n      impl::Overload* overload;\n      const ipr::Region* home;\n      master_decl_data(impl::Overload* ovl, const ipr::Type& t)\n            : basic_decl_data<Interface>{this},\n               overload_entry{t},\n               overload{ovl},\n               home{nullptr}\n      { }\n   };\n\n   template<>\n   struct master_decl_data<ipr::Template>\n      : basic_decl_data<ipr::Template>, overload_entry {\n      using Base = basic_decl_data<ipr::Template>;\n      // The declaration that is considered to be the definition.\n      Optional<ipr::Template> def { };\n      util::ref<const ipr::Language_linkage> lang_linkage { };\n      const ipr::Template* primary;\n      const ipr::Region* home;\n\n      // The overload set that contains this master declaration.  It\n      // shall be set at the time the node for the master declaration\n      // is created.\n      impl::Overload* overload;\n\n      // Sequence of specializations\n      decl_sequence specs;\n\n      master_decl_data(impl::Overload*, const ipr::Type&);\n   };\n\n\n   struct Overload : impl::Expr<ipr::Overload> {\n      // The name of this overload set.\n      const ipr::Name& name;\n\n      // All entries in this overload set, chained together in a\n      // red-back tree to permit fast retrieval based on type (as key).\n      // They are all master declarations.\n      util::rb_tree::chain<overload_entry> entries;\n\n      // A sequence of master declarations.  They are added as they\n      // appear in their enclosing scope.\n      std::vector<scope_datum*> masters;\n\n      explicit Overload(const ipr::Name&);\n      Optional<ipr::Decl> operator[](const ipr::Type&) const final;\n      overload_entry* lookup(const ipr::Type&) const;\n\n      template<class T>\n      void push_back(master_decl_data<T>*);\n   };\n\n   struct node_compare {\n      int operator()(const ipr::Node& lhs, const ipr::Node& rhs) const\n      {\n         return compare(lhs, rhs);\n      }\n\n      int\n      operator()(const overload_entry& e, const ipr::Type& t) const\n      {\n         return (*this)(e.type, t);\n      }\n\n      int\n      operator()(const overload_entry& l, const overload_entry& r) const\n      {\n         return (*this)(l.type, r.type);\n      }\n   };\n\n   // Capture the commonality of controlled statements such as `do-statement',\n   // `while-statement', and `switch-statement'.\n   template<typename Base>\n   struct Controlled_stmt : immotile_stmt<Base> {\n      using typename Base::Arg1_type;\n      using typename Base::Arg2_type;\n      util::ref<std::remove_reference_t<Arg1_type>> control;\n      util::ref<std::remove_reference_t<Arg2_type>> stmt;\n      Arg1_type first() const final { return control.get(); }\n      Arg2_type second() const final { return stmt.get(); }\n      const ipr::Type& type() const final { return second().type(); }\n   };\n\n   // The class template Decl<> implements common operations\n   // for most declarations nodes.  The exception cases are\n   // handled by the class template unique_decl<>.\n\n   template<class D>\n   struct Decl : immotile_stmt<D> {\n      basic_decl_data<D> decl_data;\n\n      Decl() : decl_data{ nullptr } { }\n\n      const ipr::Language_linkage& language_linkage() const final\n      {\n         return util::check(decl_data.master_data)->lang_linkage.get();\n      }\n\n      const ipr::Region& home_region() const final {\n         return *util::check(util::check(decl_data.master_data)->home);\n      }\n\n      // Set declaration specifiers for this decl.\n      using D::specifiers;\n      void specifiers(ipr::Specifiers s) {\n         decl_data.spec = s;\n      }\n   };\n\n   struct Base_type final : unique_decl<ipr::Base_type> {\n      const ipr::Type& base;\n      const ipr::Region& where;\n      const Decl_position scope_pos;\n      ipr::Specifiers spec;\n\n      Base_type(const ipr::Type&, const ipr::Region&, Decl_position);\n      const ipr::Type& type() const final { return base; }\n      // FIXME: for a base-class subobject, the home region and lexical\n      //        region are slightly different.  The home region should be that\n      //        of the class this is a base class, whereas the lexical region\n      //        should be the actual lexical region where the base type was specified.\n      const ipr::Region& lexical_region() const final { return where; }\n      const ipr::Region& home_region() const final { return where; }\n      Decl_position position() const final { return scope_pos; }\n      Optional<ipr::Expr> initializer() const final;\n      Specifiers specifiers() const final { return spec; }\n   };\n\n   struct Enumerator final : unique_decl<ipr::Enumerator> {\n      const ipr::Name& id;\n      const ipr::Enum& typing;\n      const Decl_position scope_pos;\n      util::ref<const ipr::Region> where;\n      Optional<ipr::Expr> init;\n\n      Enumerator(const ipr::Name&, const ipr::Enum&, Decl_position);\n      const ipr::Name& name() const final { return id; }\n      const ipr::Type& type() const final { return typing; }\n      const ipr::Region& lexical_region() const final { return where.get(); }\n      const ipr::Region& home_region() const final { return where.get(); }\n      Decl_position position() const final { return scope_pos; }\n      Optional<ipr::Expr> initializer() const final { return init; }\n   };\n\n   template<typename T>\n   struct decl_rep : T {\n      using Interface = typename T::Interface;\n      decl_rep(master_decl_data<Interface>* mdd)\n      {\n         this->decl_data.master_data = mdd;\n         this->decl_data.decl = this;\n         mdd->declset.push_back(this);\n      }\n\n      const ipr::Name& name() const final\n      {\n         return this->decl_data.master_data->overload->name;\n      }\n\n      ipr::Specifiers specifiers() const final\n      {\n         return this->decl_data.spec;\n      }\n\n      const ipr::Type& type() const final\n      {\n         return this->decl_data.master_data->type;\n      }\n\n      const ipr::Scope& scope() const\n      {\n         return this->decl_data.master_data->overload->where;\n      }\n\n      Decl_position position() const\n      {\n         return this->decl_data.scope_pos;\n      }\n\n      const ipr::Decl& master() const final\n      {\n         return *util::check(this->decl_data.master_data->decl);\n      }\n\n      const ipr::Sequence<ipr::Decl>& decl_set() const final\n      {\n         return this->decl_data.master_data->declset;\n      }\n\n      Optional<Interface> definition() const\n      {\n         return this->decl_data.master_data->def;\n      }\n   };\n\n   // -- impl::symbolic_type\n   // Representation of generalized built-in type.\n   // All built-in types have type \"typename\" and, of course, have C++ linkage.\n   // The type-parameter to this template is the type of identifier naming the type.\n   template<std::derived_from<ipr::Identifier> T>\n   struct symbolic_type : impl::Type<ipr::As_type> {\n      constexpr explicit symbolic_type(const T& t) : id{t} { }\n      const ipr::Name& name() const final { return id; }\n      const ipr::Type& type() const final { return impl::typename_type(); }\n      const ipr::Expr& operand() const final { return *this; }\n   private:\n      const T& id;\n   };\n\n   using extended_type = symbolic_type<ipr::Identifier>;\n   using Array = Binary_type<ipr::Array>;\n   using Decltype = Unary_type<ipr::Decltype>;\n   using As_type = Unary_type<ipr::As_type>;\n   using Tor = Binary_type<ipr::Tor>;\n   using Function = Ternary_type<ipr::Function>;\n   using Pointer = Unary_type<ipr::Pointer>;\n   using Product = Unary_type<ipr::Product>;\n   using Ptr_to_member = Binary_type<ipr::Ptr_to_member>;\n   using Qualified = Binary_type<ipr::Qualified>;\n   using Reference = Unary_type<ipr::Reference>;\n   using Rvalue_reference = Unary_type<ipr::Rvalue_reference>;\n   using Sum = Unary_type<ipr::Sum>;\n   using Forall = Binary_type<ipr::Forall>;\n\n   // -- Specialized implementation of ipr::As_type.\n   // A given core expression can be proclaimed to name a type with a specified data\n   // or control transfer. That is useful for interoperating with code fragments\n   // written in other languages.\n   struct As_type_with_transfer : immotile_node<ipr::As_type> {\n      struct Rep {\n         const ipr::Expr& expr;\n         const ipr::Transfer& xfer;\n      };\n\n      explicit As_type_with_transfer(const Rep& r) : id{*this}, rep{r} { }\n      const ipr::Name& name() const final { return id; }\n      const ipr::Type& type() const final { return impl::typename_type(); }\n      const ipr::Expr& operand() const final { return rep.expr; }\n      const ipr::Transfer& transfer() const final { return rep.xfer; }\n   private:\n      Type_id id;\n      Rep rep;\n   };\n\n   // -- Specialized implementation of ipr::Function.\n   // A function type with a specified data or control transfer (other than C++) protocol.\n   struct Function_with_transfer : immotile_node<ipr::Function> {\n      struct Rep {\n         const ipr::Product& source;\n         const ipr::Type& target;\n         const ipr::Expr& throws;\n         const ipr::Transfer& xfer;\n      };\n\n      explicit Function_with_transfer(const Rep& r) : id{*this}, rep{r} { }\n      const ipr::Name& name() const final { return id; }\n      const ipr::Type& type() const final { return impl::typename_type(); }\n      const ipr::Transfer& transfer() const final { return rep.xfer; }\n      const ipr::Product& first() const final { return rep.source; }\n      const ipr::Type& second() const final { return rep.target; }\n      const ipr::Expr& third() const final { return rep.throws; }\n   private:\n      Type_id id;\n      Rep rep;\n   };\n\n   using Phantom = Expr<ipr::Phantom>;\n   using Eclipsis = Expr<ipr::Eclipsis>;\n\n   struct Symbol final : Unary_expr<ipr::Symbol> {\n      explicit constexpr Symbol(const ipr::Name& n) : Unary_expr<ipr::Symbol>{ n } { }\n      constexpr Symbol(const ipr::Name& n, const ipr::Type& t)\n          : Unary_expr<ipr::Symbol>{ n }\n      { typing = t; }\n   };\n\n   struct Lambda : impl::Parameterization<ipr::Expr, impl::Node<ipr::Lambda>> {\n      util::ref<const ipr::Closure> typing;\n      Optional<ipr::Type> value_type;\n      Optional<ipr::Expr> decl_constraint;\n      impl::ref_sequence<ipr::Attribute> attrs;\n      impl::ref_sequence<ipr::Capture_specification> env_spec;\n      Optional<ipr::Expr> eh;\n      Lambda_specifiers lam_spec;\n\n      Lambda(const ipr::Region&, Mapping_level);\n      const ipr::Closure& type() const final { return typing.get(); }\n      Optional<ipr::Type> target() const final { return value_type; }\n      Optional<ipr::Expr> requirement() const final { return decl_constraint; }\n      const ipr::Sequence<ipr::Attribute>& attributes() const final { return attrs; }\n      Optional<ipr::Expr> eh_specification() const final { return eh; }\n      Lambda_specifiers specifiers() const final { return lam_spec; }\n      const ipr::Sequence<ipr::Capture_specification>& captures() const final { return env_spec; }\n   };\n\n   struct Requires : immotile_node<ipr::Requires> {\n      impl::Parameter_list formals;\n      impl::ref_sequence<cxx_form::Requirement> requirements;\n      Requires(const ipr::Region& r, Mapping_level l) : formals{r, l} { }\n      const ipr::Type& type() const final;\n      const ipr::Parameter_list& parameters() const final { return formals; }\n      const ipr::Sequence<cxx_form::Requirement>& body() const final { return requirements; }\n   };\n\n   using Address = Classic_unary_expr<ipr::Address>;\n   using Array_delete = Classic_unary_expr<ipr::Array_delete>;\n   using Complement = Classic_unary_expr<ipr::Complement>;\n   using Delete = Classic_unary_expr<ipr::Delete>;\n   using Demotion = Unary_expr<ipr::Demotion>;\n   using Deref = Classic_unary_expr<ipr::Deref>;\n\n   struct Asm : impl::Unary_node<ipr::Asm> {\n      explicit Asm(const ipr::String&);\n      const ipr::Type& type() const final;\n   };\n\n   struct Expr_list : immotile_node<ipr::Expr_list> {\n      typed_sequence<ref_sequence<ipr::Expr>> seq;\n\n      Expr_list();\n      explicit Expr_list(const ref_sequence<ipr::Expr>&);\n\n      const ipr::Product& type() const final;\n\n      const ipr::Sequence<ipr::Expr>& operand() const final;\n\n      void push_back(const ipr::Expr* e) { seq.seq.push_back(e); }\n   };\n\n   using Alignof = Unary_expr<ipr::Alignof>;\n   using Sizeof = Unary_expr<ipr::Sizeof>;\n   using Args_cardinality = Unary_expr<ipr::Args_cardinality>;\n   using Typeid = Unary_expr<ipr::Typeid>;\n   using Label = Unary_expr<ipr::Label>;\n\n   struct Restriction : Unary_node<ipr::Restriction> {\n      explicit Restriction(const ipr::Expr& x) : Unary_node<ipr::Restriction>{x} { }\n      const ipr::Type& type() const final;\n   };\n\n   struct Id_expr : Unary_expr<ipr::Id_expr> {\n      Optional<ipr::Expr> decls { };\n\n      explicit Id_expr(const ipr::Name&);\n      Optional<ipr::Expr> resolution() const final;\n   };\n\n   using Materialization = Unary_expr<ipr::Materialization>;\n   using Not = Classic_unary_expr<ipr::Not>;\n\n   struct Enclosure : impl::Unary_expr<ipr::Enclosure> {\n      Enclosure(ipr::Delimiter, const ipr::Expr&);\n      Delimiter delimiters() const final { return delim; }\n   private:\n      Delimiter delim;\n   };\n\n   using Pre_decrement = Classic_unary_expr<ipr::Pre_decrement>;\n   using Pre_increment = Classic_unary_expr<ipr::Pre_increment>;\n   using Post_decrement = Classic_unary_expr<ipr::Post_decrement>;\n   using Post_increment = Classic_unary_expr<ipr::Post_increment>;\n   using Promotion = Unary_expr<ipr::Promotion>;\n   using Read = Unary_expr<ipr::Read>;\n   using Throw = Classic_unary_expr<ipr::Throw>;\n\n   using Unary_minus = Classic_unary_expr<ipr::Unary_minus>;\n   using Unary_plus = Classic_unary_expr<ipr::Unary_plus>;\n   using Expansion = Classic_unary_expr<ipr::Expansion>;\n   using Construction = Classic_unary_expr<ipr::Construction>;\n   using Noexcept = Unary_expr<ipr::Noexcept>;\n\n   using Rewrite = Binary_node<ipr::Rewrite>;\n   using And = Classic_binary_expr<ipr::And>;\n   using Annotation = Binary_node<ipr::Annotation>;\n   using Array_ref = Classic_binary_expr<ipr::Array_ref>;\n   using Arrow = Classic_binary_expr<ipr::Arrow>;\n   using Arrow_star = Classic_binary_expr<ipr::Arrow_star>;\n   using Assign = Classic_binary_expr<ipr::Assign>;\n   using Bitand = Classic_binary_expr<ipr::Bitand>;\n   using Bitand_assign = Classic_binary_expr<ipr::Bitand_assign>;\n   using Bitor = Classic_binary_expr<ipr::Bitor>;\n   using Bitor_assign = Classic_binary_expr<ipr::Bitor_assign>;\n   using Bitxor = Classic_binary_expr<ipr::Bitxor>;\n   using Bitxor_assign = Classic_binary_expr<ipr::Bitxor_assign>;\n   using Call = Classic_binary_expr<ipr::Call>;\n   using Cast = Conversion_expr<ipr::Cast>;\n   using Coercion = Classic_binary_expr<ipr::Coercion>;\n   using Comma = Classic_binary_expr<ipr::Comma>;\n   using Const_cast = Conversion_expr<ipr::Const_cast>;\n   using Div = Classic_binary_expr<ipr::Div>;\n   using Div_assign = Classic_binary_expr<ipr::Div_assign>;\n   using Dot = Classic_binary_expr<ipr::Dot>;\n   using Dot_star = Classic_binary_expr<ipr::Dot_star>;\n   using Dynamic_cast = Conversion_expr<ipr::Dynamic_cast>;\n   using Equal = Classic_binary_expr<ipr::Equal>;\n   using Greater = Classic_binary_expr<ipr::Greater>;\n   using Greater_equal = Classic_binary_expr<ipr::Greater_equal>;\n   using Less = Classic_binary_expr<ipr::Less>;\n   using Less_equal = Classic_binary_expr<ipr::Less_equal>;\n   using Literal = Conversion_expr<ipr::Literal>;\n   using Lshift = Classic_binary_expr<ipr::Lshift>;\n   using Lshift_assign = Classic_binary_expr<ipr::Lshift_assign>;\n\n   struct Mapping : impl::Parameterization<ipr::Expr, impl::Expr<ipr::Mapping>> {\n      Mapping(const ipr::Region&, Mapping_level);\n      impl::Parameter* param(const ipr::Name& n, const ipr::Type& t)\n      {\n          return inputs.add_member(n, t);\n      }\n   };\n\n   using Member_init = Binary_expr<ipr::Member_init>;\n   using Minus = Classic_binary_expr<ipr::Minus>;\n   using Minus_assign = Classic_binary_expr<ipr::Minus_assign>;\n   using Modulo = Classic_binary_expr<ipr::Modulo>;\n   using Modulo_assign = Classic_binary_expr<ipr::Modulo_assign>;\n   using Mul = Classic_binary_expr<ipr::Mul>;\n   using Mul_assign = Classic_binary_expr<ipr::Mul_assign>;\n   using Narrow = Binary_expr<ipr::Narrow>;\n   using Not_equal = Classic_binary_expr<ipr::Not_equal>;\n   using Or = Classic_binary_expr<ipr::Or>;\n   using Plus = Classic_binary_expr<ipr::Plus>;\n   using Plus_assign = Classic_binary_expr<ipr::Plus_assign>;\n   using Pretend = Binary_expr<ipr::Pretend>;\n   using Qualification = Binary_expr<ipr::Qualification>;\n   using Reinterpret_cast = Conversion_expr<ipr::Reinterpret_cast>;\n   using Rshift = Classic_binary_expr<ipr::Rshift>;\n   using Rshift_assign = Classic_binary_expr<ipr::Rshift_assign>;\n   using Scope_ref = Classic_binary_expr<ipr::Scope_ref>;\n   using Static_cast = Conversion_expr<ipr::Static_cast>;\n   using Template_id = Binary_node<ipr::Template_id>;\n   using Widen = Binary_expr<ipr::Widen>;\n   // A Where node where the attendant() is not a scope.\n   using Where_no_decl = Binary_node<ipr::Where>;\n\n   struct Instantiation : immotile_node<ipr::Instantiation> {\n      Optional<ipr::Expr> result;\n      Instantiation(const ipr::Expr& e, const ipr::Substitution& s) : expr{e}, subst{s} { }\n      const ipr::Expr& pattern() const final { return expr; }\n      const ipr::Substitution& substitution() const final { return subst; }\n      Optional<ipr::Expr> instance() const final { return result; }\n   private:\n      const ipr::Expr& expr;\n      const ipr::Substitution& subst;\n   };\n\n   struct Binary_fold : Classic_binary_expr<ipr::Binary_fold> {\n      Category_code fold_op;\n\n      Binary_fold(Category_code, const ipr::Expr&, const ipr::Expr&);\n      Category_code operation() const final;\n   };\n\n   struct New : impl::Classic_binary_expr<ipr::New> {\n      bool global = false;\n\n      New(Optional<ipr::Expr_list>, const ipr::Construction&);\n      bool global_requested() const final;\n   };\n\n   using Conditional = Ternary<Classic<Expr<ipr::Conditional>>>;\n\n   // An elementary substitution is a subsitution the domain of which is a singleton.\n   struct Elementary_substitution : ipr::Substitution {\n      Elementary_substitution(const ipr::Parameter& p, const ipr::Expr& v) : parm{p}, value{v} { }\n      const ipr::Expr& operator[](const ipr::Parameter& p) const final\n      {\n         return physically_same(p, parm) ? parm : value;\n      }\n   private:\n      const ipr::Parameter& parm;\n      const ipr::Expr& value;\n   };\n\n   // A general substitution is a substitution the domain of which has cardinality greater than one.\n   struct General_substitution : ipr::Substitution {\n      const ipr::Expr& operator[](const ipr::Parameter&) const final;\n      General_substitution& subst(const ipr::Parameter&, const ipr::Expr&);\n   private:\n      std::map<const ipr::Parameter*, const ipr::Expr*> mapping;\n   };\n\n   struct Template : impl::Decl<ipr::Template> {\n      util::ref<impl::Mapping> init;\n      util::ref<const ipr::Region> lexreg;\n\n      Template();\n      const ipr::Template& primary_template() const final;\n      const ipr::Sequence<ipr::Decl>& specializations() const final;\n      const ipr::Mapping& mapping() const final { return init.get(); }\n      // FIXME: The initializer should actually be the mapping, since a Template is a\n      //        *named* mapping.  In Classic IPR, and in the current incarnation, the initializer\n      //        is the initializer of the current instantiation.\n      Optional<ipr::Expr> initializer() const final { return { mapping().result() }; }\n      const ipr::Region& lexical_region() const final { return lexreg.get(); }\n   };\n\n   template<typename T>\n   struct decl_factory {\n      using Interface = typename T::Interface;\n      stable_farm<decl_rep<T>> decls;\n      stable_farm<master_decl_data<Interface>> master_info;\n\n      // We have gotten an overload-set for a name, and we are about\n      // to enter the first declaration for that name with the type T.\n      decl_rep<T>* declare(Overload* ovl, const ipr::Type& t)\n      {\n         // Grab bookkeeping memory for this master declaration.\n         master_decl_data<Interface>* data = master_info.make(ovl, t);\n         // The actual representation for the declaration points back\n         // to the master declaration bookkeeping store.\n         decl_rep<T>* master = decls.make(data);\n         // Inform the overload-set that we have a new master declaration.\n         ovl->push_back(data);\n\n         return master;\n      }\n\n      decl_rep<T>* redeclare(overload_entry* decl)\n      {\n         return decls.make\n            (static_cast<master_decl_data<Interface>*>(decl));\n      }\n   };\n\n\n   struct Alias : impl::Decl<ipr::Alias> {\n      util::ref<const ipr::Expr> aliasee;\n\n      Alias();\n      Optional<ipr::Expr> initializer() const final { return aliasee.get(); }\n   };\n\n   struct Var : impl::Decl<ipr::Var> {\n      Optional<ipr::Expr> init;\n      util::ref<const ipr::Region> lexreg;\n\n      Var();\n      Optional<ipr::Expr> initializer() const final { return init; }\n      const ipr::Region& lexical_region() const final { return lexreg.get(); }\n   };\n\n   // FIXME: Field should use unique_decl, not impl::Decl.\n   struct Field : impl::Decl<ipr::Field> {\n      Optional<ipr::Expr> init;\n\n      Field();\n      Optional<ipr::Expr> initializer() const final { return init; }\n   };\n\n   // FIXME: Bitfield should use unique_decl, not impl::Decl\n   struct Bitfield : impl::Decl<ipr::Bitfield> {\n      util::ref<const ipr::Expr> length;\n      Optional<ipr::Expr> init;\n\n      Bitfield();\n      const ipr::Expr& precision() const final { return length.get(); }\n      Optional<ipr::Expr> initializer() const final { return init; }\n   };\n\n   struct Typedecl : impl::Decl<ipr::Typedecl> {\n      Optional<ipr::Type> init;\n      util::ref<const ipr::Region> lexreg;\n\n      Typedecl();\n      Optional<ipr::Expr> initializer() const final { return init; }\n      const ipr::Region& lexical_region() const final { return lexreg.get(); }\n   };\n\n   struct Concept : impl::Decl<ipr::Concept> {\n      impl::Parameter_list inputs;\n      util::ref<const ipr::Expr> init;\n      explicit Concept(const ipr::Region& r) : inputs{r, { }} { }\n      const ipr::Parameter_list& parameters() const final { return inputs; }\n      const ipr::Expr& result() const final { return init.get(); }\n      Optional<ipr::Expr> initializer() const final { return { *this }; }\n   };\n\n   // For a non-defining function declaration, the parameters - if any is named\n   // or has a default argument - are stored with that particular declaration.\n   // A function definition is one that specifies the initializer (Mapping) which\n   // already has room for the named parameters or the default arguments.\n   struct fundecl_data : std::variant<impl::Parameter_list*, impl::Mapping*> {\n      ipr::FunctionTraits traits { };\n      impl::Parameter_list* parameters() const { return std::get<0>(*this); }\n      impl::Mapping* mapping() const { return std::get<1>(*this); }\n   };\n\n   struct Fundecl : impl::Decl<ipr::Fundecl> {\n      fundecl_data data;\n      util::ref<const ipr::Region> lexreg;\n\n      Fundecl();\n\n      ipr::FunctionTraits traits() const final { return data.traits; }\n      const ipr::Parameter_list& parameters() const final;\n      Optional<ipr::Mapping> mapping() const final;\n      Optional<ipr::Expr> initializer() const final;\n      const ipr::Region& lexical_region() const final { return lexreg.get(); }\n   };\n\n   // A heterogeneous scope is a sequence of declarations of\n   // almost of kinds.  The omitted kinds being parameters,\n   // base-class subobjects and enumerators.   Those form\n   // a homogeneous scope, implemented by homogeneous_scope.\n\n   struct Scope : immotile_node<ipr::Scope> {\n      Scope();\n      const ipr::Type& type() const final { return decls; }\n      const ipr::Sequence<ipr::Decl>& elements() const final { return decls.seq; }\n      Optional<ipr::Overload> operator[](const ipr::Name&) const final;\n\n      impl::Alias* make_alias(const ipr::Name&, const ipr::Expr&);\n      impl::Var* make_var(const ipr::Name&, const ipr::Type&);\n      impl::Field* make_field(const ipr::Name&, const ipr::Type&);\n      impl::Bitfield* make_bitfield(const ipr::Name&, const ipr::Type&);\n      impl::Typedecl* make_typedecl(const ipr::Name&, const ipr::Type&);\n      impl::Fundecl* make_fundecl(const ipr::Name&, const ipr::Function&);\n      impl::Template* make_primary_template(const ipr::Name&, const ipr::Forall&);\n      impl::Template* make_secondary_template(const ipr::Name&, const ipr::Forall&);\n\n   private:\n      util::rb_tree::container<impl::Overload> overloads;\n      typed_sequence<decl_sequence> decls;\n      decl_factory<impl::Alias> aliases;\n      decl_factory<impl::Var> vars;\n      decl_factory<impl::Field> fields;\n      decl_factory<impl::Bitfield> bitfields;\n      decl_factory<impl::Fundecl> fundecls;\n      decl_factory<impl::Typedecl> typedecls;\n      decl_factory<impl::Template> primary_maps;\n      decl_factory<impl::Template> secondary_maps;\n\n      template<class T> inline void add_member(T*);\n   };\n\n\n   // A heterogeneous region is a region of program text that\n   // contains heterogeneous scope (as defined above).\n\n   struct Region : immotile_node<ipr::Region>, cxx_form::impl::form_factory {\n      using location_span = ipr::Region::Location_span;\n      Optional<ipr::Region> parent;\n      location_span extent;\n      Optional<ipr::Expr> owned_by { };\n      impl::Scope scope;\n      impl::ref_sequence<ipr::Expr> expr_seq;         // all the expressions making up the body.\n\n      const ipr::Region& enclosing() const final { return parent.get(); }\n      const ipr::Sequence<ipr::Expr>& body() const final { return expr_seq; }\n      const ipr::Scope& bindings() const final { return scope; }\n      const location_span& span() const final { return extent; }\n      Optional<ipr::Expr> owner() const final { return owned_by; }\n      bool global() const final { return not parent.is_valid(); }\n\n      impl::Region* make_subregion();\n\n      // Convenient functions, forwarding to those of SCOPE.\n      impl::Alias* declare_alias(const ipr::Name& n, const ipr::Type& t)\n      {\n         return scope.make_alias(n, t);\n      }\n\n      impl::Var* declare_var(const ipr::Name& n, const ipr::Type& t)\n      {\n         return scope.make_var(n, t);\n      }\n\n      impl::Field* declare_field(const ipr::Name& n, const ipr::Type& t)\n      {\n         return scope.make_field(n, t);\n      }\n\n      impl::Bitfield* declare_bitfield(const ipr::Name& n,\n                                       const ipr::Type& t)\n      {\n         return scope.make_bitfield(n, t);\n      }\n\n      Typedecl* declare_type(const ipr::Name& n, const ipr::Type& t)\n      {\n         return scope.make_typedecl(n, t);\n      }\n\n      Fundecl* declare_fun(const ipr::Name& n, const ipr::Function& t)\n      {\n         return scope.make_fundecl(n, t);\n      }\n\n      Template* declare_primary_template(const ipr::Name& n, const ipr::Forall& t)\n      {\n         return scope.make_primary_template(n, t);\n      }\n\n      Template* declare_secondary_template(const ipr::Name& n, const ipr::Forall& t)\n      {\n         return scope.make_secondary_template(n, t);\n      }\n\n      explicit Region(Optional<ipr::Region>);\n\n   private:\n      stable_farm<Region> subregions;\n   };\n\n\n   // Implement common operations for user-defined types.  The case\n   // of enums is handled separately because its body is a\n   // homogeneous region.\n\n   template<class Interface>\n   struct Udt : impl::Type<Interface> {\n      Region body;\n      Optional<ipr::Name> id;\n      explicit Udt(const ipr::Region* pr) : body(pr)\n      { \n         body.owned_by = this;\n      }\n      const ipr::Name& name() const final { return id.get(); }\n      const ipr::Region& region() const final { return body; }\n\n      impl::Alias*\n      declare_alias(const ipr::Name& n, const ipr::Type& t)\n      {\n         impl::Alias* alias = body.declare_alias(n, t);\n         return alias;\n      }\n\n      impl::Field*\n      declare_field(const ipr::Name& n, const ipr::Type& t)\n      {\n         impl::Field* field = body.declare_field(n, t);\n         return field;\n      }\n\n      impl::Bitfield*\n      declare_bitfield(const ipr::Name& n, const ipr::Type& t)\n      {\n         impl::Bitfield* field = body.declare_bitfield(n, t);\n         return field;\n      }\n\n      impl::Var*\n      declare_var(const ipr::Name& n, const ipr::Type& t)\n      {\n         impl::Var* var = body.declare_var(n, t);\n         return var;\n      }\n\n      impl::Typedecl*\n      declare_type(const ipr::Name& n, const ipr::Type& t)\n      {\n         impl::Typedecl* typedecl = body.declare_type(n, t);\n         return typedecl;\n      }\n\n      impl::Fundecl*\n      declare_fun(const ipr::Name& n, const ipr::Function& t)\n      {\n         impl::Fundecl* fundecl = body.declare_fun(n, t);\n         return fundecl;\n      }\n\n      impl::Template*\n      declare_primary_template(const ipr::Name& n, const ipr::Forall& t)\n      {\n         impl::Template* map = body.declare_primary_template(n, t);\n         return map;\n      }\n\n      impl::Template*\n      declare_secondary_template(const ipr::Name& n, const ipr::Forall& t)\n      {\n         impl::Template* map = body.declare_secondary_template(n, t);\n         return map;\n      }\n   };\n\n   struct Enum : impl::Type<ipr::Enum> {\n      Optional<ipr::Type> underlying;\n      homogeneous_region<impl::Enumerator, obj_sequence> body;\n      Optional<ipr::Name> id;\n      const Kind enum_kind;\n\n      Enum(const ipr::Region&, Kind);\n      const ipr::Name& name() const final { return id.get(); }\n      const ipr::Type& type() const final;\n      const ipr::Region& region() const final;\n      const Sequence<ipr::Enumerator>& members() const final;\n      Kind kind() const final;\n      Optional<ipr::Type> base() const final { return underlying; }\n      impl::Enumerator* add_member(const ipr::Name&);\n   };\n\n   struct Union : Udt<ipr::Union> {\n      explicit Union(const ipr::Region&);\n      const ipr::Type& type() const final;\n   };\n\n   struct Namespace : Udt<ipr::Namespace> {\n      explicit Namespace(const ipr::Region*);\n      const ipr::Type& type() const final;\n   };\n\n   struct Class : impl::Udt<ipr::Class> {\n      homogeneous_region<impl::Base_type> base_subobjects;\n      explicit Class(const ipr::Region&);\n      const ipr::Type& type() const final;\n      const ipr::Sequence<ipr::Base_type>& bases() const final;\n      impl::Base_type* declare_base(const ipr::Type&);\n   };\n\n   struct Auto : impl::Composite<ipr::Auto> {\n   };\n\n   struct Closure : impl::Udt<ipr::Closure> {\n      impl::obj_list<impl::Capture> captures;\n      explicit Closure(const ipr::Region&);\n      const ipr::Type& type() const final;\n      const ipr::Sequence<ipr::Capture>& members() const final { return captures; }\n   };\n\n   // This class is responsible for creating nodes that\n   // represent types.  It is responsible for the storage\n   // management that is implied.  Notice that the type nodes\n   // created by this class may need additional processing such\n   // as setting their types (as expressions) and their names.\n\n   struct type_factory {\n      const ipr::Transfer& get_transfer_from_linkage(const ipr::Language_linkage&);\n      const ipr::Transfer& get_transfer_from_convention(const ipr::Calling_convention&);\n      const ipr::Transfer& get_transfer(const ipr::Language_linkage&, const ipr::Calling_convention&);\n\n      // Build an IPR node for an expression that denotes a type.\n      // The transfer protocol, if not specified, is assumed to be C++.\n      const ipr::As_type& get_as_type(const ipr::Identifier&);\n      const ipr::As_type& get_as_type(const ipr::Expr&);\n      const ipr::As_type& get_as_type(const ipr::Expr&, const ipr::Transfer&);\n\n      const ipr::Array& get_array(const ipr::Type&, const ipr::Expr&);\n      const ipr::Qualified& get_qualified(ipr::Qualifiers, const ipr::Type&);\n      const ipr::Decltype& get_decltype(const ipr::Expr&);\n      const ipr::Tor& get_tor(const ipr::Product&, const ipr::Sum&);\n      const ipr::Function& get_function(const ipr::Product&, const ipr::Type&);\n      const ipr::Function& get_function(const ipr::Product&, const ipr::Type&, const ipr::Transfer&);\n      const ipr::Function& get_function(const ipr::Product&, const ipr::Type&, const ipr::Expr&);\n      const ipr::Function& get_function(const ipr::Product&, const ipr::Type&,\n                                        const ipr::Expr&, const ipr::Transfer&);\n      const ipr::Pointer& get_pointer(const ipr::Type&);\n      const ipr::Product& get_product(const ipr::Sequence<ipr::Type>&);\n      const ipr::Product& get_product(const Warehouse<ipr::Type>&);\n      const ipr::Ptr_to_member& get_ptr_to_member(const ipr::Type&, const ipr::Type&);\n      const ipr::Reference& get_reference(const ipr::Type&);\n      const ipr::Rvalue_reference& get_rvalue_reference(const ipr::Type&);\n      const ipr::Sum& get_sum(const ipr::Sequence<ipr::Type>&);\n      const ipr::Sum& get_sum(const Warehouse<ipr::Type>&);\n      const ipr::Forall& get_forall(const ipr::Product&, const ipr::Type&);\n      const ipr::Auto& get_auto();\n\n      impl::Enum* make_enum(const ipr::Region&, Enum::Kind);\n      impl::Class* make_class(const ipr::Region&);\n      impl::Union* make_union(const ipr::Region&);\n      impl::Namespace* make_namespace(const ipr::Region&);\n      impl::Closure* make_closure(const ipr::Region&);\n   private:\n      util::rb_tree::container<impl::Transfer_from_linkage> xfer_links;\n      util::rb_tree::container<impl::Transfer_from_cc> xfer_ccs;\n      util::rb_tree::container<impl::Transfer> xfers;\n\n      util::rb_tree::container<impl::extended_type> extendeds;\n      util::rb_tree::container<impl::Array> arrays;\n      util::rb_tree::container<impl::As_type> type_refs;\n      util::rb_tree::container<impl::As_type_with_transfer> type_xfers;\n      util::rb_tree::container<impl::Tor> tors;\n      util::rb_tree::container<impl::Function> functions;\n      util::rb_tree::container<impl::Function_with_transfer> fun_xfers;\n      util::rb_tree::container<impl::Pointer> pointers;\n      util::rb_tree::container<impl::Product> products;\n      util::rb_tree::container<impl::Ptr_to_member> member_ptrs;\n      util::rb_tree::container<impl::Qualified> qualifieds;\n      util::rb_tree::container<impl::Reference> references;\n      util::rb_tree::container<impl::Rvalue_reference> refrefs;\n      util::rb_tree::container<impl::Sum> sums;\n      util::rb_tree::container<impl::Forall> foralls;\n      util::rb_tree::container<ref_sequence<ipr::Type>> type_seqs;\n      stable_farm<impl::Decltype> decltypes;\n      stable_farm<impl::Enum> enums;\n      stable_farm<impl::Class> classes;\n      stable_farm<impl::Union> unions;\n      stable_farm<impl::Namespace> namespaces;\n      stable_farm<impl::Closure> closures;\n      stable_farm<impl::Auto> autos;\n   };\n\n   // -- Implementation of directives --\n   struct Specifiers_spread : impl::Directive<ipr::Specifiers_spread, Phases::Elaboration> {\n      impl::ref_sequence<cxx_form::Proclamator> proc_seq;\n      ipr::Specifiers specs { };\n\n      const ipr::Sequence<cxx_form::Proclamator>& targets() const final { return proc_seq; }\n      ipr::Specifiers specifiers() const final { return specs; }\n   };\n\n   struct Structured_binding : impl::Directive<ipr::Structured_binding, Phases::Elaboration> {\n      impl::ref_sequence<ipr::Identifier> ids;           // names in this structured binding\n      util::ref<const ipr::Expr> init;                   // initializer of this structured binding\n      impl::ref_sequence<ipr::Decl> decl_seq;            // declarations resulting from this structured binding\n      ipr::Specifiers specs { };                         // the non-type part of decl-specifier-seq in\n                                                         // this structured binding.  Note: `type()` contains the\n                                                         // the type part of the decl-specifier-seq\n      ipr::Binding_mode binding_mode { };                // the binding mode of this structured binding\n\n      ipr::Specifiers specifiers() const final { return specs; }\n      ipr::Binding_mode mode() const final { return binding_mode; }\n      const ipr::Sequence<ipr::Identifier>& names() const final { return ids; }\n      const ipr::Expr& initializer() const final { return init.get(); }\n      const ipr::Sequence<ipr::Decl>& bindings() const final { return decl_seq; }\n   };\n\n   // Implementation of ipr::Using_declaration in case where using-declarator-list is a singleton.\n   struct single_using_declaration : impl::Directive<ipr::Using_declaration, Phases::Elaboration> {\n      single_using_declaration(const ipr::Scope_ref&, Designator::Mode);\n      const ipr::Sequence<Designator>& designators() const final { return what; }\n   private:\n      singleton_obj<Designator> what;\n   };\n\n   struct Using_declaration : impl::Directive<ipr::Using_declaration, Phases::Elaboration> {\n      impl::obj_list<Designator> seq;\n\n      const ipr::Sequence<Designator>& designators() const final { return seq; }\n   };\n\n   struct Using_directive : impl::Directive<ipr::Using_directive, Phases::Elaboration> {\n      explicit Using_directive(const ipr::Scope&);\n      const ipr::Scope& nominated_scope() const final { return scope; }\n   private:\n      const ipr::Scope& scope;\n   };\n\n   // -- impl::Phased_evaluation\n   struct Phased_evaluation : immotile_node<ipr::Phased_evaluation> {\n      Phased_evaluation(const ipr::Expr& x, Phases f) : expr{x}, ph{f} { }\n      Phases phases() const final { return ph; }\n      const ipr::Expr& expression() const final { return expr; }\n   private:\n      const ipr::Expr& expr;\n      Phases ph;\n   };\n\n   struct Pragma : impl::Directive<ipr::Pragma, Phases::All> {\n      obj_list<impl::Token> tokens;\n      const ipr::Sequence<ipr::Token>& operand() const final { return tokens; }\n   };\n\n   // ----------------------------------\n   // -- Implementation of statements --\n   // ----------------------------------\n\n   using Ctor_body = impl::Basic_binary<impl::Stmt<impl::Expr<ipr::Ctor_body>>>;\n   using Do = Controlled_stmt<ipr::Do>;\n   using Expr_stmt = impl::Unary_node<impl::Stmt<ipr::Expr_stmt>>;\n   using Goto = impl::Unary_node<impl::Stmt<ipr::Goto>>;\n   using If = Ternary<Stmt<Expr<ipr::If>>>;\n   using Labeled_stmt = impl::Binary_node<impl::Stmt<ipr::Labeled_stmt>>;\n   using Return = impl::Basic_unary<impl::Stmt<impl::Expr<ipr::Return>>>;\n   using Switch = Controlled_stmt<ipr::Switch>;\n   using While = Controlled_stmt<ipr::While>;\n\n   // -- impl::EH_parameter\n   struct EH_parameter : unique_decl<ipr::EH_parameter> {\n      EH_parameter(const ipr::Region&, const ipr::Name&, const ipr::Type&);\n      const ipr::Name& name() const final { return id; }\n      const ipr::Type& type() const final { return typing; }\n      const ipr::Region& home_region() const final { return home; }\n      const ipr::Region& lexical_region() const final { return home; }\n   private:\n      const ipr::Name& id;\n      const ipr::Type& typing;\n      const ipr::Region& home;\n   };\n\n   // -- impl::handler_block\n   // The block-statement body of a handler.  It has no associated EH handlers of its own.\n   struct handler_block : impl::Stmt<impl::Expr<ipr::Block>> {\n      impl::Region lexical_region;\n      handler_block(const ipr::Region&);\n      const ipr::Region& region() const final { return lexical_region; }\n      const ipr::Sequence<ipr::Handler>& handlers() const final { return none; }\n\n      // The scope of declarations in this block\n      impl::Scope* scope() { return &lexical_region.scope; }\n      void add_stmt(const ipr::Expr& s)\n      {\n         lexical_region.expr_seq.push_back(&s);\n      }\n   private:\n      impl::empty_sequence<ipr::Handler> none;\n   };\n\n   // -- impl::eh_region\n   // The region containing the declaration of the exception parameter of a Handler.\n   // Like for function parameter region, this region encloses the region of the\n   // ipr::Block (body) associated with the Handler.\n   // Note: the enclosing() region of this eh_region is the same as the enclosing\n   //       region() of the Block with which the Handler is associated.\n   struct eh_region : homogeneous_region<impl::EH_parameter, singleton_obj> {\n      using base = homogeneous_region<impl::EH_parameter, singleton_obj>;\n      using base::base;\n      const ipr::EH_parameter& parameter() const { return scope.decls.seq.element(); }\n    };\n\n   // -- impl::Handler\n   struct Handler : immotile_stmt<ipr::Handler> {\n      Handler(const ipr::Region&, const ipr::Name&, const ipr::Type&);\n      const ipr::Type& type() const final { return block.type(); }\n      const ipr::EH_parameter& exception() const final { return eh.parameter(); }\n      const ipr::Block& body() const final { return block; }\n      impl::handler_block& body() { return block; }\n   private:\n      eh_region eh;\n      impl::handler_block block;\n   };\n\n   // A Block holds a heterogeneous region, suitable for\n   // recording the set of declarations appearing in that\n   // block.  It also holds a sequence of handlers, when the\n   // block actually represents a C++ try-block.\n   struct Block : impl::Stmt<Expr<ipr::Block>> {\n      impl::Region lexical_region;\n      explicit Block(const ipr::Region&);\n      const ipr::Region& region() const final { return lexical_region; }\n      const ipr::Sequence<ipr::Handler>& handlers() const final { return handler_seq; }\n\n      // The scope of declarations in this block\n      impl::Scope* scope() { return &lexical_region.scope; }\n      impl::Handler* new_handler(const ipr::Name&, const ipr::Type&);\n      void add_stmt(const ipr::Expr& s)\n      {\n         lexical_region.expr_seq.push_back(&s);\n      }\n   private:\n      impl::obj_list<impl::Handler> handler_seq;\n   };\n\n\n   // A for-statement node in its most general form is a quaternry\n   // expresion; for flexibility, it is made in a way that\n   // supports settings of its components after construction.\n\n   struct For : immotile_stmt<ipr::For> {\n      util::ref<const ipr::Expr> init;\n      util::ref<const ipr::Expr> cond;\n      util::ref<const ipr::Expr> inc;\n      util::ref<const ipr::Stmt> stmt;\n\n      For();\n      const ipr::Type& type() const final { return body().type(); }\n      const ipr::Expr& initializer() const final { return init.get(); }\n      const ipr::Expr& condition() const final { return cond.get(); }\n      const ipr::Expr& increment() const final { return inc.get(); }\n      const ipr::Stmt& body() const final { return stmt.get(); }\n   };\n\n   struct For_in : immotile_stmt<ipr::For_in> {\n      util::ref<const ipr::Var> var;\n      util::ref<const ipr::Expr> seq;\n      util::ref<const ipr::Stmt> stmt;\n\n      For_in();\n      const ipr::Type& type() const final { return body().type(); }\n      const ipr::Var& variable() const final { return var.get(); }\n      const ipr::Expr& sequence() const final { return seq.get(); }\n      const ipr::Stmt& body() const final { return stmt.get(); }\n   };\n\n\n   // A Break node can record the selction- of iteration-statement it\n   // transfers control out of.\n\n   struct Break : immotile_stmt<ipr::Break> {\n      util::ref<const ipr::Stmt> stmt;\n      Break();\n      const ipr::Type& type() const final;\n      const ipr::Stmt& from() const final { return stmt.get(); }\n   };\n\n   // Like a Break, a Continue node can refer back to the\n   // iteration-statement containing it.\n   struct Continue : immotile_stmt<ipr::Continue> {\n      util::ref<const ipr::Stmt> stmt;\n      Continue();\n      const ipr::Type& type() const final;\n      const ipr::Stmt& iteration() const final { return stmt.get(); }\n   };\n\n   // Type of `Where`-nodes introducing declarations in their `attendant()` expressions.\n   // Note: See impl::Where_no_decls for the degenerated case where the `attendant()`\n   //       is just a classic expression, with no declaration introduced.\n   struct Where : immotile_node<ipr::Where> {\n      impl::Region region;                            // hosts the declarations in the `attendant()`.\n      util::ref<const ipr::Expr> result;              // the `main()` expression.\n\n      explicit Where(const ipr::Region&);\n      const ipr::Expr& first() const final { return result.get(); }\n      const ipr::Scope& second() const final { return region.bindings(); }\n   };\n\n   // -- impl::Static_assert\n   struct Static_assert : impl::Binary_node<ipr::Static_assert> {\n      Static_assert(const ipr::Expr&, Optional<ipr::String>);\n      const ipr::Type& type() const final;\n   };\n\n   struct name_factory {\n      const ipr::String& get_string(util::word_view);\n      const ipr::Identifier& get_identifier(const ipr::String&);\n      const ipr::Identifier& get_identifier(util::word_view);\n      const ipr::Suffix& get_suffix(const ipr::Identifier&);\n      const ipr::Operator& get_operator(const ipr::String&);\n      const ipr::Operator& get_operator(util::word_view);\n      const ipr::Conversion& get_conversion(const ipr::Type&);\n      const ipr::Ctor_name& get_ctor_name(const ipr::Type&);\n      const ipr::Dtor_name& get_dtor_name(const ipr::Type&);\n      const ipr::Guide_name& get_guide_name(const ipr::Template&);\n      const ipr::Logogram& get_logogram(const ipr::String&);\n   private:\n      util::string_pool strings;\n      util::rb_tree::container<impl::Logogram> logos;\n      util::rb_tree::container<impl::Identifier> ids;\n      util::rb_tree::container<impl::Suffix> suffixes;\n      util::rb_tree::container<impl::Conversion> convs;\n      util::rb_tree::container<impl::Ctor_name> ctors;\n      util::rb_tree::container<impl::Dtor_name> dtors;\n      util::rb_tree::container<impl::Operator> ops;\n      util::rb_tree::container<impl::Guide_name> guide_ids;\n   };\n\n   struct expr_factory : name_factory {\n      // Returns an IPR node a language linkage.\n      const ipr::Language_linkage& get_linkage(util::word_view);\n      const ipr::Language_linkage& get_linkage(const ipr::String&);\n\n      // Rerturn an IPR for a calling convention.\n      const ipr::Calling_convention& get_calling_convention(util::word_view);\n\n      // Return a symbol with a given name and type.\n      const ipr::Symbol& get_symbol(const ipr::Name&, const ipr::Type&);\n      const ipr::Symbol& get_label(const ipr::Identifier&);\n      // Return a symbolic value for `this` with a given type.\n      const ipr::Symbol& get_this(const ipr::Type&);\n\n      Annotation* make_annotation(const ipr::String&, const ipr::Literal&);\n\n      // Build a node for a missing expression of an unspecified type.\n      Phantom* make_phantom();\n      // Build an unspecified expression node of a given type.\n      const ipr::Phantom* make_phantom(const ipr::Type&);\n\n      Eclipsis* make_eclipsis(const ipr::Type&);\n\n      // Returns an IPR node for a typed literal expression.\n      Literal* make_literal(const ipr::Type&, const ipr::String&);\n      Literal* make_literal(const ipr::Type&, util::word_view);\n\n      Address* make_address(const ipr::Expr&, Optional<ipr::Type> = {});\n      Array_delete* make_array_delete(const ipr::Expr&);\n      Complement* make_complement(const ipr::Expr&, Optional<ipr::Type> = {});\n      Delete* make_delete(const ipr::Expr&);\n      Demotion* make_demotion(const ipr::Expr&, const ipr::Type&);\n      Deref* make_deref(const ipr::Expr&, Optional<ipr::Type> = {});\n      Expr_list* make_expr_list();\n      Alignof* make_alignof(const ipr::Expr&, Optional<ipr::Type> = { });\n      Sizeof* make_sizeof(const ipr::Expr&, Optional<ipr::Type> = { });\n      Args_cardinality* make_args_cardinality(const ipr::Expr&, Optional<ipr::Type> = { });\n      Typeid* make_typeid(const ipr::Expr&, Optional<ipr::Type> = { });\n      Restriction* make_restriction(const ipr::Expr&);\n      impl::Id_expr* make_id_expr(const ipr::Name&, Optional<ipr::Type> = {});\n      Id_expr* make_id_expr(const ipr::Decl&);\n      Label* make_label(const ipr::Identifier&, Optional<ipr::Type> = {});\n      Materialization* make_materialization(const ipr::Expr&, const ipr::Type&);\n      Not* make_not(const ipr::Expr&, Optional<ipr::Type> = {});\n      Enclosure* make_enclosure(ipr::Delimiter, const ipr::Expr&, Optional<ipr::Type> = { });\n      Post_increment* make_post_increment(const ipr::Expr&, Optional<ipr::Type> = {});\n      Post_decrement* make_post_decrement(const ipr::Expr&, Optional<ipr::Type> = {});\n      Pre_increment* make_pre_increment(const ipr::Expr&, Optional<ipr::Type> = {});\n      Pre_decrement* make_pre_decrement(const ipr::Expr&, Optional<ipr::Type> = {});\n      Promotion* make_promotion(const ipr::Expr&, const ipr::Type&);\n      Read* make_read(const ipr::Expr&, const ipr::Type&);\n      Throw* make_throw(const ipr::Expr&, Optional<ipr::Type> = {});\n      Unary_minus* make_unary_minus(const ipr::Expr&, Optional<ipr::Type> = {});\n      Unary_plus* make_unary_plus(const ipr::Expr&, Optional<ipr::Type> = {});\n      Expansion* make_expansion(const ipr::Expr&, Optional<ipr::Type> = {});\n      Construction* make_construction(const ipr::Type&, const ipr::Enclosure&);\n      Noexcept* make_noexcept(const ipr::Expr&, Optional<ipr::Type> = { });\n\n      Rewrite* make_rewrite(const ipr::Expr&, const ipr::Expr&);\n      And* make_and(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Array_ref* make_array_ref(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Arrow* make_arrow(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Arrow_star* make_arrow_star(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Assign* make_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Bitand* make_bitand(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Bitand_assign* make_bitand_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Bitor* make_bitor(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Bitor_assign* make_bitor_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Bitxor* make_bitxor(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Bitxor_assign* make_bitxor_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Cast* make_cast(const ipr::Type&, const ipr::Expr&);\n      Call* make_call(const ipr::Expr&, const ipr::Expr_list&, Optional<ipr::Type> = {});\n      Coercion* make_coercion(const ipr::Expr&, const ipr::Type&, const ipr::Type&);\n      Comma* make_comma(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Const_cast* make_const_cast(const ipr::Type&, const ipr::Expr&);\n      Div* make_div(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Div_assign* make_div_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Dot* make_dot(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Dot_star* make_dot_star(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Dynamic_cast* make_dynamic_cast(const ipr::Type&, const ipr::Expr&);\n      Equal* make_equal(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Greater* make_greater(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Greater_equal* make_greater_equal(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Less* make_less(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Less_equal* make_less_equal(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Lshift* make_lshift(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Lshift_assign* make_lshift_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Member_init* make_member_init(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Minus* make_minus(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Minus_assign* make_minus_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Modulo* make_modulo(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Modulo_assign* make_modulo_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Mul* make_mul(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Mul_assign* make_mul_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Narrow* make_narrow(const ipr::Expr&, const ipr::Type&, const ipr::Type&);\n      Not_equal* make_not_equal(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Or* make_or(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Plus* make_plus(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Plus_assign* make_plus_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Pretend* make_pretend(const ipr::Expr&, const ipr::Type&, const ipr::Type&);\n      Qualification* make_qualification(const ipr::Expr&, ipr::Qualifiers, const ipr::Type&);\n      Reinterpret_cast* make_reinterpret_cast(const ipr::Type&, const ipr::Expr&);\n      Scope_ref* make_scope_ref(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Rshift* make_rshift(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Rshift_assign* make_rshift_assign(const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Template_id* make_template_id(const ipr::Expr&, const ipr::Expr_list&);\n      Static_cast* make_static_cast(const ipr::Type&, const ipr::Expr&);\n      Widen* make_widen(const ipr::Expr&, const ipr::Type&, const ipr::Type&);\n      Binary_fold* make_binary_fold(Category_code, const ipr::Expr&, const ipr::Expr&, Optional<ipr::Type> = {});\n      Where* make_where(const ipr::Region&);\n      Where_no_decl* make_where(const ipr::Expr&, const ipr::Expr&);\n      impl::Instantiation* make_instantiation(const ipr::Expr&, const ipr::Substitution&);\n      New* make_new(Optional<ipr::Expr_list>, const ipr::Construction&, Optional<ipr::Type> = {});\n      Conditional* make_conditional(const ipr::Expr&, const ipr::Expr&,\n                                    const ipr::Expr&, Optional<ipr::Type> = {});\n      Mapping* make_mapping(const ipr::Region&, Mapping_level);\n      Lambda* make_lambda(const ipr::Region&, Mapping_level);\n      Requires* make_requires(const ipr::Region&, Mapping_level);\n\n      Elementary_substitution* make_elementary_substitution(const ipr::Parameter&, const ipr::Expr&);\n      General_substitution* make_general_substitution();\n\n   protected:\n      // Note: These factory functions are not to be called directly.  See impl::Lexicon for their equivalent.\n      impl::Asm* make_asm_expr(const ipr::String&);\n      impl::Static_assert* make_static_assert_expr(const ipr::Expr&, Optional<ipr::String> = { });\n\n   private:\n      util::rb_tree::container<ipr::Language_linkage> linkages;\n      util::rb_tree::container<ipr::Calling_convention> conventions;\n\n      util::rb_tree::container<impl::Literal> lits;\n      util::rb_tree::container<impl::Template_id> template_ids;\n\n      stable_farm<impl::Phantom> phantoms;\n      stable_farm<impl::Eclipsis> eclipses;\n\n      util::rb_tree::container<impl::Symbol> symbols;\n      stable_farm<impl::Alignof> alignofs;\n      stable_farm<impl::Sizeof> sizeofs;\n      stable_farm<impl::Typeid> xtypeids;\n      stable_farm<impl::Address> addresses;\n      stable_farm<impl::Annotation> annotations;\n      stable_farm<impl::Array_delete> array_deletes;\n      stable_farm<impl::Asm> asms;\n      stable_farm<impl::Complement> complements;\n      stable_farm<impl::Delete> deletes;\n      stable_farm<impl::Demotion> demotions;\n      stable_farm<impl::Deref> derefs;\n      stable_farm<impl::Expr_list> xlists;\n      stable_farm<impl::Id_expr> id_exprs;\n      stable_farm<impl::Label> labels;\n      stable_farm<impl::Materialization> materializations;\n      stable_farm<impl::Not> nots;\n      stable_farm<impl::Enclosure> enclosures;\n      stable_farm<impl::Pre_increment> pre_increments;\n      stable_farm<impl::Pre_decrement> pre_decrements;\n      stable_farm<impl::Post_increment> post_increments;\n      stable_farm<impl::Post_decrement> post_decrements;\n      stable_farm<impl::Promotion> promotions;\n      stable_farm<impl::Read> reads;\n      stable_farm<impl::Throw> throws;\n      stable_farm<impl::Unary_minus> unary_minuses;\n      stable_farm<impl::Unary_plus> unary_pluses;\n      stable_farm<impl::Expansion> expansions;\n      stable_farm<impl::Construction> constructions;\n      stable_farm<impl::Noexcept> noexcepts;\n      stable_farm<impl::Args_cardinality> cardinalities;\n      stable_farm<impl::Restriction> restrictions;\n\n      stable_farm<impl::Rewrite> rewrites;\n      stable_farm<impl::Scope_ref> scope_refs;\n      stable_farm<impl::And> ands;\n      stable_farm<impl::Array_ref> array_refs;\n      stable_farm<impl::Arrow> arrows;\n      stable_farm<impl::Arrow_star> arrow_stars;\n      stable_farm<impl::Assign> assigns;\n      stable_farm<impl::Bitand> bitands;\n      stable_farm<impl::Bitand_assign> bitand_assigns;\n      stable_farm<impl::Bitor> bitors;\n      stable_farm<impl::Bitor_assign> bitor_assigns;\n      stable_farm<impl::Bitxor> bitxors;\n      stable_farm<impl::Bitxor_assign> bitxor_assigns;\n      stable_farm<impl::Cast> casts;\n      stable_farm<impl::Call> calls;\n      stable_farm<impl::Comma> commas;\n      stable_farm<impl::Const_cast> ccasts;\n      stable_farm<impl::Div> divs;\n      stable_farm<impl::Div_assign> div_assigns;\n      stable_farm<impl::Dot> dots;\n      stable_farm<impl::Dot_star> dot_stars;\n      stable_farm<impl::Dynamic_cast> dcasts;\n      stable_farm<impl::Equal> equals;\n      stable_farm<impl::Greater> greaters;\n      stable_farm<impl::Greater_equal> greater_equals;\n      stable_farm<impl::Less> lesses;\n      stable_farm<impl::Less_equal> less_equals;\n      stable_farm<impl::Lshift> lshifts;\n      stable_farm<impl::Lshift_assign> lshift_assigns;\n      stable_farm<impl::Member_init> member_inits;\n      stable_farm<impl::Minus> minuses;\n      stable_farm<impl::Minus_assign> minus_assigns;\n      stable_farm<impl::Modulo> modulos;\n      stable_farm<impl::Modulo_assign> modulo_assigns;\n      stable_farm<impl::Mul> muls;\n      stable_farm<impl::Mul_assign> mul_assigns;\n      stable_farm<impl::Narrow> narrows;\n      stable_farm<impl::Not_equal> not_equals;\n      stable_farm<impl::Or> ors;\n      stable_farm<impl::Plus> pluses;\n      stable_farm<impl::Plus_assign> plus_assigns;\n      stable_farm<impl::Pretend> pretends;\n      stable_farm<impl::Qualification> qualifications;\n      stable_farm<impl::Reinterpret_cast> rcasts;\n      stable_farm<impl::Rshift> rshifts;\n      stable_farm<impl::Rshift_assign> rshift_assigns;\n      stable_farm<impl::Static_cast> scasts;\n      stable_farm<impl::Widen> widens;\n      stable_farm<impl::Binary_fold> folds;\n      stable_farm<impl::Where_no_decl> where_nodecls;\n      stable_farm<impl::Where> wheres;\n      stable_farm<impl::Static_assert> asserts;\n      stable_farm<impl::Instantiation> insts;\n\n      stable_farm<impl::New> news;\n      stable_farm<impl::Coercion> coercions;\n      stable_farm<impl::Conditional> conds;\n      stable_farm<impl::Mapping> mappings;\n      stable_farm<impl::Lambda> lambdas;\n      stable_farm<impl::Requires> reqs;\n\n      stable_farm<impl::Elementary_substitution> elem_substs;\n      stable_farm<impl::General_substitution> gen_substs;\n   };\n\n   struct dir_factory {\n      impl::Specifiers_spread* make_specifiers_spread();\n      impl::Structured_binding* make_structured_binding();\n      impl::single_using_declaration* make_using_declaration(const ipr::Scope_ref&,\n                                                               ipr::Using_declaration::Designator::Mode);\n      impl::Using_declaration* make_using_declaration();\n      impl::Using_directive* make_using_directive(const ipr::Scope&, const ipr::Type&);\n      impl::Phased_evaluation* make_phased_evaluation(const ipr::Expr&, Phases);\n      impl::Pragma* make_pragma();\n   private:\n      stable_farm<impl::Specifiers_spread> spreads;\n      stable_farm<impl::Structured_binding> bindings;\n      stable_farm<impl::single_using_declaration> singles;\n      stable_farm<impl::Using_declaration> usings;\n      stable_farm<impl::Using_directive> dirs;\n      stable_farm<impl::Phased_evaluation> phaseds;\n      stable_farm<impl::Pragma> pragmas;\n   };\n\n   // This factory class takes on the implementation burden of\n   // allocating storage for statement nodes and their constructions.\n   struct stmt_factory : expr_factory, dir_factory {\n      impl::Break* make_break();\n      impl::Continue* make_continue();\n      impl::Block* make_block(const ipr::Region&, Optional<ipr::Type> = { });\n      impl::Ctor_body* make_ctor_body(const ipr::Expr_list&, const ipr::Block&);\n      impl::Expr_stmt* make_expr_stmt(const ipr::Expr&);\n      impl::Goto* make_goto(const ipr::Expr&);\n      impl::Return* make_return(const ipr::Expr&);\n      impl::Do* make_do();\n      impl::If* make_if(const ipr::Expr&, const ipr::Expr&);\n      impl::If* make_if(const ipr::Expr&, const ipr::Expr&, const ipr::Expr&);\n      impl::Switch* make_switch();\n      impl::Labeled_stmt* make_labeled_stmt(const ipr::Expr&, const ipr::Expr&);\n      impl::While* make_while();\n      impl::For* make_for();\n      impl::For_in* make_for_in();\n\n   protected:\n      stable_farm<impl::Break> breaks;\n      stable_farm<impl::Continue> continues;\n      stable_farm<impl::Block> blocks;\n      stable_farm<impl::Expr_stmt> expr_stmts;\n      stable_farm<impl::Goto> gotos;\n      stable_farm<impl::Return> returns;\n      stable_farm<impl::Ctor_body> ctor_bodies;\n      stable_farm<impl::Do> dos;\n      stable_farm<impl::If> ifs;\n      stable_farm<impl::Handler> handlers;\n      stable_farm<impl::Labeled_stmt> labeled_stmts;\n      stable_farm<impl::Switch> switches;\n      stable_farm<impl::While> whiles;\n      stable_farm<impl::For> fors;\n      stable_farm<impl::For_in> for_ins;\n   };\n\n                              // -- impl::Lexicon --\n   struct Lexicon : ipr::Lexicon, type_factory, stmt_factory {\n      Lexicon();\n      ~Lexicon();\n\n      const ipr::Language_linkage& cxx_linkage() const final;\n      const ipr::Language_linkage& c_linkage() const final;\n\n      ipr::Specifiers export_specifier() const final;\n      ipr::Specifiers static_specifier() const final;\n      ipr::Specifiers extern_specifier() const final;\n      ipr::Specifiers mutable_specifier() const final;\n      ipr::Specifiers constinit_specifier() const final;\n      ipr::Specifiers thread_local_specifier() const final;\n      ipr::Specifiers register_specifier() const final;\n      ipr::Specifiers inline_specifier() const final; \n      ipr::Specifiers constexpr_specifier() const final;\n      ipr::Specifiers consteval_specifier() const final;\n      ipr::Specifiers virtual_specifier() const final;\n      ipr::Specifiers abstract_specifier() const final;\n      ipr::Specifiers explicit_specifier() const final;\n      ipr::Specifiers friend_specifier() const final;\n      ipr::Specifiers typedef_specifier() const final;\n      ipr::Specifiers public_specifier() const final;\n      ipr::Specifiers protected_specifier() const final;\n      ipr::Specifiers private_specifier() const final;\n      ipr::Specifiers specifiers(ipr::Basic_specifier) const final;\n      std::vector<ipr::Basic_specifier> decompose(ipr::Specifiers) const final;\n\n      ipr::Qualifiers const_qualifier() const final;\n      ipr::Qualifiers volatile_qualifier() const final;\n      ipr::Qualifiers restrict_qualifier() const final;\n      ipr::Qualifiers qualifiers(ipr::Basic_qualifier) const final;\n      std::vector<ipr::Basic_qualifier> decompose(ipr::Qualifiers) const final;\n\n      const ipr::Template_id& get_template_id(const ipr::Expr&,\n                                                const ipr::Expr_list&);\n\n      const ipr::Literal& get_literal(const ipr::Type&, util::word_view);\n      const ipr::Literal& get_literal(const ipr::Type&, const ipr::String&);\n\n      const ipr::Type& void_type() const final;\n      const ipr::Type& bool_type() const final;\n\n      const ipr::Type& char_type() const final;\n      const ipr::Type& schar_type() const final;\n      const ipr::Type& uchar_type() const final;\n      const ipr::Type& wchar_t_type() const final;\n      const ipr::Type& char8_t_type() const final;\n      const ipr::Type& char16_t_type() const final;\n      const ipr::Type& char32_t_type() const final;\n\n      const ipr::Type& short_type() const final;\n      const ipr::Type& ushort_type() const final;\n\n      const ipr::Type& int_type() const final;\n      const ipr::Type& uint_type() const final;\n\n      const ipr::Type& long_type() const final;\n      const ipr::Type& ulong_type() const final;\n\n      const ipr::Type& long_long_type() const final;\n      const ipr::Type& ulong_long_type() const final;\n\n      const ipr::Type& float_type() const final;\n      const ipr::Type& double_type() const final;\n      const ipr::Type& long_double_type() const final;\n\n      const ipr::Type& ellipsis_type() const final;\n\n      const ipr::Type& typename_type() const final;\n      const ipr::Type& class_type() const final;\n      const ipr::Type& union_type() const final;\n      const ipr::Type& enum_type() const final;\n      const ipr::Type& namespace_type() const final;\n\n      const ipr::Symbol& false_value() const final;\n      const ipr::Symbol& true_value() const final;\n      const ipr::Symbol& nullptr_value() const final;\n      const ipr::Symbol& default_value() const final;\n      const ipr::Symbol& delete_value() const final;\n\n      impl::Phased_evaluation* make_asm(const ipr::String&);\n      impl::Phased_evaluation* make_static_assert(const ipr::Expr&, Optional<ipr::String>);\n\n      impl::Mapping* make_mapping(const ipr::Region&, Mapping_level = { });\n\n      const impl::Token* make_token(const ipr::String&,\n                                    const Source_location&,\n                                    TokenValue, TokenCategory);\n   private:\n      stable_farm<impl::Token> tokens;\n      util::rb_tree::container<ref_sequence<ipr::Expr>> expr_seqs;\n   };\n\n   template<typename T>\n   struct unit_base : T {\n      using Interface = T;\n      unit_base(impl::Lexicon& l)\n            : context{ l },\n               global_ns{nullptr}\n      {\n         global_ns.id = &context.get_identifier(u8\"\");\n      }\n\n      void accept(Translation_unit::Visitor& v) const override {\n         v.visit(*this);\n      }\n\n      const ipr::Namespace& global_namespace() const final {\n         return global_ns;\n      }\n\n      const ipr::Sequence<ipr::Module>& imported_modules() const final {\n         return modules_imported;\n      }\n\n      Region* global_region() { return &global_ns.body; }\n      Scope* global_scope() { return &global_ns.body.scope; }\n      ref_sequence<ipr::Module>* imports() { return &modules_imported; }\n\n   private:\n      impl::Lexicon& context;\n      impl::Namespace global_ns;\n      ref_sequence<ipr::Module> modules_imported;\n   };\n\n   template<typename T>\n   struct basic_unit : unit_base<T> {\n      const ipr::Module& parent;\n      impl::ref_sequence<ipr::Decl> owned_decls;\n\n      basic_unit(impl::Lexicon& l, const ipr::Module& m)\n            : unit_base<T>{ l }, parent{ m }\n      { }\n      const ipr::Module& parent_module() const final { return parent; }\n      const ipr::Sequence<ipr::Decl>& purview() const final {\n         return owned_decls;\n      }\n   };\n\n   using Translation_unit = unit_base<ipr::Translation_unit>;\n   using Module_unit = basic_unit<ipr::Module_unit>;\n\n   struct Interface_unit : basic_unit<ipr::Interface_unit> {\n      impl::ref_sequence<ipr::Module> modules_exported;\n      impl::ref_sequence<ipr::Decl> decls_exported;\n\n      Interface_unit(impl::Lexicon&, const ipr::Module&);\n      const ipr::Sequence<ipr::Module>& exported_modules() const final;\n      const ipr::Sequence<ipr::Decl>& exported_declarations() const final;\n   };\n\n   struct Module : ipr::Module {\n      using ImplUnits = impl::obj_list<impl::Module_unit>;\n      impl::Lexicon& lexicon;\n      impl::Module_name stems;\n      impl::Interface_unit iface;\n      ImplUnits units;\n\n      Module(impl::Lexicon&);\n      const ipr::Module_name& name() const final;\n      const ipr::Interface_unit& interface_unit() const final;\n      const ipr::Sequence<ipr::Module_unit>& implementation_units() const final;\n      impl::Module_unit* make_unit();\n   };\n}\n\n#endif\n"
  },
  {
    "path": "include/ipr/input",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n\n#include <cstddef>\n#include <span>\n#include <vector>\n#include <filesystem>\n\nnamespace ipr::input {\n    // Type for the error code values used by the host OS.\n#ifdef _WIN32\n    using ErrorCode = DWORD;\n#else\n    using ErrorCode = int;\n#endif\n\n    // String type preferred by the host OS to specify pathnames.\n    using SystemPath = std::filesystem::path::string_type;\n\n    // Exception type used to signal inability of the host OS to access a file.\n    struct AccessError {\n        SystemPath path;\n        ErrorCode error_code;\n    };\n\n    // Exception type used to signal the file designated by th `path` is not a regular file.\n    struct RegularFileError {\n        SystemPath path;\n    };\n\n    // Exception type used to signal inability of the host OS to memory-map a file.\n    struct FileMappingError {\n        SystemPath path;\n        ErrorCode error_code;\n    };\n\n    // Abstract number of items in a non-empty collection.\n    enum class Multiplicity : std::uint8_t {\n        One = 0x0,\n        Many = 0x1\n    };\n\n    // A morsel is a piece of source text either as contiguous sequence of bytes (isle),\n    // or as a sequence of isles (archipelago).\n    struct Isle;\n    struct Archipelago;\n\n    struct Morsel {\n        Multiplicity multiplicity() const { return static_cast<Multiplicity>(tag); }\n        auto start() const { return where; }\n        auto size() const { return extent; }\n    private:\n        Morsel(std::uint64_t w, std::uint64_t e, std::uint64_t t)\n            : where{w}, extent{e}, tag{t}\n        { }\n        std::uint64_t where : 47;           // where to find items in this morsel.\n        std::uint64_t extent : 16;          // number of items in this morsel.\n        const std::uint64_t tag : 1;        // discriminant between isle and achipelago.\n        friend Isle;\n        friend Archipelago;\n    };\n\n    static_assert(sizeof(Morsel) == sizeof(std::uint64_t));\n\n    // An isle of text is contiguous morsel, coded over 63-bit out of the 64-bit precision of a morsel. \n    struct Isle {\n        std::uint64_t offset : 47;              // offset from the beginning of containing text\n        std::uint64_t length : 16;              // number of bytes from the start\n        const std::uint64_t tag : 1 = 0;        // discriminant between isle and archipelago.  Always 0.\n        operator Morsel() const { return { offset, length, tag }; }\n    };\n\n    static_assert(sizeof(Isle) == sizeof(Morsel));\n\n    // An archipelago of text is a collection of isles, coded over 63-bit of the 64-bit precision of a morsel.\n    struct Archipelago {\n        std::uint64_t start : 47;               // index of the first isle in this archipelago.\n        std::uint64_t count : 16;               // number of isles in this archipelago.\n        const std::uint64_t tag : 1 = 1;        // discriminant between isle and archipelago.  Always 1.\n        operator Morsel() const { return { start, count, tag }; }\n    };\n\n    static_assert(sizeof(Archipelago) == sizeof(Morsel));\n\n    // Descriptor for a physical line from an input source file.\n    struct PhysicalLine {\n        Isle isle { };\n        std::uint64_t number : 48 { };\n        std::uint64_t indent : 16 { };\n\n        bool empty() const { return isle.length == 0; }\n    };\n\n    static_assert(sizeof(PhysicalLine) == 2 * sizeof(Morsel));\n\n    // A logical line is either a simple phyiscal line or a composite of multiple\n    // physical lines spliced together.\n    enum class LineSort : std::uint8_t {\n        Simple = 0x00,          // A simple, non-continuating physical line.\n        Composite = 0x01,       // Result of spliced multiple physical lines.\n    };\n\n    // Classification of input logical lines.\n    enum class LineSpecies : std::uint8_t {\n        Unknown = 0x00,\n        Text,                               // text line\n        SolitaryHash,                       // `#` by itself on a line\n        If,                                 // `#if` line\n        Ifdef,                              // `#ifdef` line\n        Ifndef,                             // `#ifndef` line\n        Elif,                               // `#elif` line\n        Elifdef,                            // `#elifdef` line\n        Elifndef,                           // `#elifndef` line\n        Else,                               // `#else` line\n        Endif,                              // `#endif` line\n        Include,                            // `#include` line\n        Export,                             // `export` line\n        Import,                             // `import` line\n        Embed,                              // `#embed` line\n        Define,                             // `#define` line\n        Undef,                              // `#undef` line\n        Line,                               // `#line` line\n        Error,                              // `#error` line\n        Warning,                            // `#warning` line\n        Pragma,                             // `#pragma` line\n        ExtendedDirective,                  // Some other `#` directive\n    };\n\n    // This predicate holds if its argument designates an explicitly listed enumerator.\n    bool valid_species(LineSpecies);\n\n    // A physical line that is a logical line by itself, e.g. not ending with a backslash.\n    struct SimpleLine {\n        PhysicalLine line;\n    };\n\n    // An aggregate of physical lines spliced to form a logical line.\n    struct CompositeLine {\n        std::vector<PhysicalLine> lines;\n    };\n\n    // A descriptor for a logical line:\n    //    (a) whether it is simple or composite\n    //    (b) preprocessing line classification\n    //    (c) index into the appropriate table to retrieve its physical location\n    // Note: a line descritptor is designed to fit in a 64-bit integer storage.\n    struct LineDescriptor {\n        LineDescriptor(LineSort, LineSpecies, std::uint64_t);\n        LineSort sort() const { return static_cast<LineSort>(srt); }\n        LineSpecies species() const { return static_cast<LineSpecies>(spc); }\n        std::uint64_t index() const { return idx; }\n    private:\n        std::uint64_t srt : 1;\n        std::uint64_t spc : 5;\n        std::uint64_t idx : 58;\n    };\n\n    static_assert(sizeof(LineDescriptor) == sizeof(std::uint64_t));\n\n    // Input source file mapped to memory as sequence of raw bytes.\n    // UTF-8 is assumed as the encoding of the text.\n    struct SourceFile {\n        using View = std::span<const char8_t>;\n        struct LineRange;\n        \n        explicit SourceFile(const SystemPath&);\n        SourceFile(SourceFile&&) noexcept;\n        ~SourceFile();\n        LineRange lines() const noexcept;\n        View contents() const noexcept { return view; }\n        View contents(Isle m) const noexcept;\n    private:\n        View view;\n    };\n\n    // A source file line range is an input_range of isles, each representing a physical \n    // line in the input source file.\n    struct SourceFile::LineRange {\n        using difference_type = std::ptrdiff_t;\n        struct iterator;\n        explicit LineRange(const SourceFile&);\n        iterator begin() noexcept;\n        iterator end() noexcept;\n    private:\n        const SourceFile* src;\n        const char8_t* ptr;\n        PhysicalLine cache { };\n        void next_line() noexcept;\n    };\n\n    // An iterator for input source file line range.\n    struct SourceFile::LineRange::iterator {\n        using difference_type = std::ptrdiff_t;\n        using value_type = Isle;\n        using iterator_category = std::input_iterator_tag;\n\n        explicit iterator(LineRange* r) noexcept : range{r} { }\n        PhysicalLine operator*() const noexcept;\n        iterator& operator++() noexcept;\n        void operator++(int) noexcept { ++(*this); }\n        bool operator==(const iterator& that) const noexcept { return range == that.range; }\n        bool operator!=(const iterator& that) const noexcept = default;\n    private:\n        LineRange* range;\n    };\n\n    inline SourceFile::LineRange SourceFile::lines() const noexcept\n    {\n        return LineRange{*this};\n    }\n\n    inline SourceFile::LineRange::iterator SourceFile::LineRange::begin() noexcept\n    {\n        return iterator{this};\n    }\n\n    inline SourceFile::LineRange::iterator SourceFile::LineRange::end() noexcept\n    {\n        return iterator{nullptr};\n    }\n\n    // A depot of lines read from an input source file.\n    struct LineDepot {\n        std::vector<SimpleLine> simples;\n        std::vector<CompositeLine> composites;\n        std::vector<LineDescriptor> indices;\n    };\n\n    // An input source listing is a source file with its lines read into logical lines.\n    struct SourceListing : SourceFile {\n        explicit SourceListing(const SystemPath&);\n        const SimpleLine& simple_line(LineDescriptor) const;\n        const CompositeLine& composite_line(LineDescriptor) const;\n        const std::vector<LineDescriptor>& logical_lines() const { return depot.indices; }\n    private:\n        LineDepot depot;\n    };\n}"
  },
  {
    "path": "include/ipr/lexer",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n\n#ifndef IPR_XPR_LEXER_INCLUDED\n#define IPR_XPR_LEXER_INCLUDED\n\n#include <string>\n#include <fstream>\n#include <set>\n#include <deque>\n\n#include <ipr/impl>\n\nnamespace xpr {\n\n   struct Token {\n      enum Kind {\n         Unknown,\n         LeftBrace          = '{',\n         RightBrace         = '}',\n         LeftParen          = '(',\n         RightParen         = ')',\n         LeftBracket        = '[',\n         RightBracket       = ']',\n         Dot                = '.',\n         Question           = '?',\n         Colon              = ':',\n         Bar                = '|',\n         Plus               = '+',\n         Minus              = '-',\n         Star               = '*',\n         Slash              = '/',\n         Percent            = '%',\n         LeftAngle          = '<',\n         RightAngle         = '>',\n         Not                = '!',\n         Assign             = '=',\n         Semicolon          = ';',\n         Comma              =',',\n         Complement         = '~',\n         At                 = '@',\n         Ampersand          = '&',\n         Dollar             = '$',\n         Hash               = '#',\n         ColonColon         = ':' + 256 * ':',\n         HashHash           = '#' + 256 * '#',\n         PercentPercent     = '%' + 256 * '%',\n         AmpersandAmpersand = '&' + 256 * '&',\n         BarBar             = '|' + 256 * '|',\n         LeftShift          = '<' + 256 * '<',\n         RightShift         = '>' + 256 * '>',\n         PlusPlus           = '+' + 256 * '+',\n         MinusMinus         = '-' + 256 * '-',\n         AssignAssign       = '=' + 256 * '=',\n         PlusAssign         = '+' + 256 * '=',\n         MinusAssign        = '-' + 256 * '=',\n         StarAssign         = '*' + 256 * '=',\n         SlashAssign        = '/' + 256 * '=',\n         PercentAssign      = '%' + 256 * '=',\n         Le                 = '<' + 256 * '=',\n         Ge                 = '>' + 256 * '=',\n         NotAssign          = '!' + 256 * '=',\n         BarAssign          = '|' + 256 * '=',\n         AmpersandAssign    = '&' + 256 * '=',\n         Arrow              = '-' + 256 * '>',\n         LeftSpec           = '[' + 256 * '<',\n         RightSpec          = '>' + 256 * ']',\n         DotStar            = '.' + 256 * '*',\n         Get                = '<' + 256 * '-',\n         LeftShiftAssign    = LeftShift + 256 * 256 * '=',\n         RightShiftAssign   = RightShift + 256 * 256 * '=',\n         ArrowStar          = Arrow + 256 * 256 * '*',\n         Boolean,            // boolean literal\n         Integer,            // integer literal\n         FloatingPoint,      // floating-poitn literal\n         Character = '\\'',   // character literal\n         String = '\"',       // string literal\n         Identifier,\n         Comment,            // well, for comments\n\n         Auto,               // \"auto\"\n         Class,              // \"class\"\n         Union,              // \"union\"\n         Enum,               // \"enum\"\n         Namespace,          // \"namespace\"\n         Concept,            // \"concept\"\n\n         Virtual,            // \"virtual\"\n         Const,              // \"const\"\n         Volatile,           // \"volatile\"\n         Restrict,           // \"restrict\"\n\n         Public,             // \"public\"\n         Protected,          // \"protected\"\n         Private,            // \"private\"\n         Inline,             // \"inline\"\n         Explicit,           // \"explicit\"\n         Friend,             // \"friend\"\n         Export,             // \"export\"\n         Extern,             // \"extern\"\n         Static,             // \"static\"\n         Register,           // \"register\"\n\n         Sizeof,             // \"sizeof\"\n         Typeid,             // \"typeid\"\n         Throw,              // \"throw\"\n         StaticCast,         // \"static_cast\"\n         DynamicCast,        // \"dynamic_cast\"\n         ConstCast,          // \"const_cast\"\n         ReinterpretCast,    // \"reinterpret_cast\"\n         New,                // \"new\"\n         Delete,             // \"delete\"\n\n         For,                // \"for\"\n         If,                 // \"if\"\n         Else,               // \"else\"\n         Switch,             // \"switch\"\n         Continue,           // \"continue\"\n         Break,              // \"break\"\n         Return,             // \"return\"\n         Goto,               // \"goto\"\n         Case,               // \"case\"\n         Default,            // \"default\"\n         While,              // \"while\n         Do,                 // \"do\"\n         Catch,              // \"catch\"\n\n         EndOfInput          // end of character input stream\n      };\n\n      // Comparator function object type, useful for inserting\n      // tokens in an associative containers.\n      struct Compare {\n         bool operator()(const Token& lhs, const Token& rhs) const\n         {\n            return lhs.text < rhs.text;\n         }\n      };\n\n      Token() : kind() { }\n      Token(Kind k, const char* s = 0) : kind(k), text(s) { }\n\n      Kind kind;\n      ipr::Source_location location;\n      std::string text;\n   };\n\n   struct Lexer {\n      explicit Lexer(ipr::impl::Unit&);\n\n      Token& peek(int = 0);\n      void discard() { tokens.pop_front(); }\n\n      void input_file(const char*);\n      void syntax_error();\n\n   protected:\n      ipr::impl::Unit& unit;\n\n   private:\n      using Keyword_set = std::set<Token, Token::Compare>;\n      struct Token_stream : std::deque<Token> {\n      };\n\n      Token_stream tokens;\n      Keyword_set keywords;\n      ipr::Source_location locus;\n      std::string line;\n      std::ifstream input;\n      const char* cursor;\n      const char* end_of_line;\n\n      void insert_keyword(Token::Kind, const char*);\n      std::istream& read_line();\n      void read_quoted_text(std::string&);\n      inline bool next_char_is(char);\n      inline Token::Kind if_duplicate_char(Token::Kind, Token::Kind);\n      inline bool escape_sequence() const;\n      void identifier(Token&);\n      void number(Token&);\n      void unknown(Token&);\n         inline const Token* keyword(const std::string&) const;\n   };\n}\n\n#endif // IPR_XPR_LEXER_INCLUDED\n"
  },
  {
    "path": "include/ipr/node-category",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n\n\n// The existence of these enumerators reflect a weakness in the implementation\n// language (C++), for their purposes is only to convert types to runtime \n// values, and vice versa, while supporting constant time dispatch.\n\nUnknown,                            // ipr::Node    -- abstract\nAnnotation,                         // ipr::Annotation\nRegion,                             // ipr::Region\nComment,                            // ipr::Comment\nString,                             // ipr::String\nParameter_list,                     // ipr::Parameter_list\n\nOverload,                           // ipr::Overload\n\nArray,                              // ipr::Array\nClass,                              // ipr::Class\nDecltype,                           // ipr::Decltype\nAs_type,                            // ipr::As_type\nEnum,                               // ipr::Enum\nTor,                                // ipr::Tor\nFunction,                           // ipr::Function\nNamespace,                          // ipr::Namespace\nPointer,                            // ipr::Pointer\nPtr_to_member,                      // ipr::Ptr_to_member\nProduct,                            // ipr::Product\nQualified,                          // ipr::Qualified\nReference,                          // ipr::Reference\nRvalue_reference,                   // ipr::Rvalue_reference\nSum,                                // ipr::Sum\nForall,                             // ipr::Forall\nUnion,                              // ipr::Union\nAuto,                               // ipr::Auto\nClosure,                            // ipr::Closure\n\nIdentifier,                         // ipr::Identifier\nOperator,                           // ipr::Operator\nSuffix,                             // ipr::Suffix\nConversion,                         // ipr::Conversion\nTemplate_id,                        // ipr::Template_id\nType_id,                            // ipr::Type_id\nCtor_name,                          // ipr::Ctor_name\nDtor_name,                          // ipr::Dtor_name\nGuide_name,                         // ipr::Guide_name\n\nPhantom,                            // ipr::Phantom\nEclipsis,                           // ipr::Eclipsis\nLambda,                             // ipr::Lambda\nRequires,                           // ipr::Requires\n\nSymbol,                             // ipr::Symbol\nAddress,                            // ipr::Address\nArray_delete,                       // ipr::Array_delete\nAsm,                                // ipr::Asm\nComplement,                         // ipr::Complement\nDelete,                             // ipr::Delete\nDemotion,                           // ipr::Demotion\nDeref,                              // ipr::Deref\nExpr_list,                          // ipr::Expr_list\nAlignof,                            // ipr::Alignof\nSizeof,                             // ipr::Sizeof\nTypeid,                             // ipr::Typeid\nId_expr,                            // ipr::Id_expr\nLabel,                              // ipr::Label\nMaterialization,                    // ipr::Materialization\nNot,                                // ipr::Not\nEnclosure,                          // ipr::Enclosure\nPost_decrement,                     // ipr::Post_decrement\nPost_increment,                     // ipr::Post_increment\nPre_decrement,                      // ipr::Pre_decrement\nPre_increment,                      // ipr::Pre_increment\nPromotion,                          // ipr::Promotion\nRead,                               // ipr::Read\nThrow,                              // ipr::Throw\nUnary_minus,                        // ipr::Unary_minus\nUnary_plus,                         // ipr::Unary_plus\nExpansion,                          // ipr::Expansion\nNoexcept,                           // ipr::Noexcept\nArgs_cardinality,                   // ipr::Args_cardinality\nRestriction,                        // ipr::Restriction\n\nRewrite,                            // ipr::Rewrite\nScope_ref,                          // ipr::Scope_ref\nPlus,                               // ipr::Plus\nPlus_assign,                        // ipr::Plus_assign\nAnd,                                // ipr::And\nArray_ref,                          // ipr::Array_ref\nArrow,                              // ipr::Arrow\nArrow_star,                         // ipr::Arrow_star\nAssign,                             // ipr::Assign\nBitand,                             // ipr::Bitand\nBitand_assign,                      // ipr::Bitand_assign\nBitor,                              // ipr::Bitor\nBitor_assign,                       // ipr::Bitor_assign\nBitxor,                             // ipr::Bitxor\nBitxor_assign,                      // ipr::Bitxor_assign\nCall,                               // ipr::Call\nCast,                               // ipr::Cast\nCoercion,                           // ipr::Coercion\nComma,                              // ipr::Comma\nConst_cast,                         // ipr::Const_cast\nConstruction,                       // ipr::Construction\nDiv,                                // ipr::Div\nDiv_assign,                         // ipr::Div_assign\nDot,                                // ipr::Dot\nDot_star,                           // ipr::Dot_star\nDynamic_cast,                       // ipr::Dynamic_cast\nEqual,                              // ipr::Equal\nGreater,                            // ipr::Greater\nGreater_equal,                      // ipr::Greater_equal\nLess,                               // ipr::Less\nLess_equal,                         // ipr::Less_equal\nLiteral,                            // ipr::Literal\nLshift,                             // ipr::Lshift\nLshift_assign,                      // ipr::Lshift_assign\nMapping,                            // ipr::Mapping\nMember_init,                        // ipr::Member_init\nModulo,                             // ipr::Modulo\nModulo_assign,                      // ipr::Modulo_assign\nMul,                                // ipr::Mul\nMul_assign,                         // ipr::Mul_assign\nNarrow,                             // ipr::Narrow\nNot_equal,                          // ipr::Not_equal\nOr,                                 // ipr::Or\nPretend,                            // ipr::Pretend\nQualification,                      // ipr::Qualification\nReinterpret_cast,                   // ipr::Reinterpret_cast\nRshift,                             // ipr::Rshift,\nRshift_assign,                      // ipr::Rshift_assign\nStatic_cast,                        // ipr::Static_cast\nWiden,                              // ipr::Widen\nMinus,                              // ipr::Minus\nMinus_assign,                       // ipr::Minus_assign\nBinary_fold,                        // ipr::Binary_fold\nWhere,                              // ipr::Where\nStatic_assert,                      // ipr::Static_assert\nInstantiation,                      // ipr::Instantiation\n\nNew,                                // ipr::New\nConditional,                        // ipr::Conditional\nScope,                              // ipr::Scope\n\nDeduction_guide,                    // ipr::Deduction_guide\nSpecifiers_spread,                  // ipr::Specifiers_spread\nStructured_binding,                 // ipr::Structured_binding\nUsing_declaration,                  // ipr::Using_declaration\nUsing_directive,                    // ipr::Using_directive\nPhased_evaluation,                  // ipr::Phased_evaluation\nPragma,                             // ipr::Pragma\n\nBlock,                              // ipr::Block\nBreak,                              // ipr::Break\nContinue,                           // ipr::Continue\nCtor_body,                          // ipr::Ctor_body\nDo,                                 // ipr::Do\nExpr_stmt,                          // ipr::Expr_stmt,\nFor,                                // ipr::For\nFor_in,                             // ipr::For_in\nGoto,                               // ipr::Goto\nHandler,                            // ipr::Handler\nIf,                                 // ipr::If\nLabeled_stmt,                       // ipr::Labeled_stmt\nReturn,                             // ipr::Return\nSwitch,                             // ipr::Switch\nWhile,                              // ipr::While\n\nAlias,                              // ipr::Alias\nBase_type,                          // ipr::Base_type\nEnumerator,                         // ipr::Enumerator\nField,                              // ipr::Field\nBitfield,                           // ipr::Bitfield\nFundecl,                            // ipr::Fundecl\nTemplate,                           // ipr::Template\nConcept,                            // ipr::Concept\nParameter,                          // ipr::Parameter\nTypedecl,                           // ipr::Typedecl\nVar,                                // ipr::Var\nEH_parameter,                       // ipr::EH_parameter\n\nUnit,                               // ipr::Unit\n\nlast_code_cat\n\n"
  },
  {
    "path": "include/ipr/std-preamble",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Standard library preamble for translation units that use `import cxx.ipr;`\n// followed by `#include <ipr/impl>` (or other IPR project headers).\n//\n// TEMPORARY: This header exists because the implementation layer (<ipr/impl>)\n// is not yet modularized.  MSVC requires all standard #includes to appear\n// before `import cxx.ipr;` to avoid redefinition errors.  Once <ipr/impl>\n// becomes a module, this preamble is no longer needed.\n//\n// Usage:\n//     #include <ipr/std-preamble>\n//     import cxx.ipr;\n//     #include <ipr/impl>\n\n#ifndef IPR_STD_PREAMBLE_INCLUDED\n#define IPR_STD_PREAMBLE_INCLUDED\n\n#include <algorithm>\n#include <concepts>\n#include <cstddef>\n#include <cstdint>\n#include <deque>\n#include <forward_list>\n#include <functional>\n#include <iosfwd>\n#include <iterator>\n#include <list>\n#include <map>\n#include <memory>\n#include <new>\n#include <ostream>\n#include <stdexcept>\n#include <string>\n#include <string_view>\n#include <type_traits>\n#include <utility>\n#include <variant>\n#include <vector>\n\n#endif // IPR_STD_PREAMBLE_INCLUDED\n"
  },
  {
    "path": "include/ipr/utility-impl",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Implementation-only utilities for <ipr/impl> and <ipr/io>.\n// The interface-facing subset of the old <ipr/utility> is now\n// part of the cxx.ipr module.\n\n#ifndef IPR_UTILITY_IMPL_INCLUDED\n#define IPR_UTILITY_IMPL_INCLUDED\n\n// Standard headers required by this file must be included by the consumer\n// BEFORE including this header, to avoid clashes with import cxx.ipr.\n\nnamespace ipr::util {\n   // At various places in the implementation of the IPR interface, certain logical\n   // references are stored as pointers because of implementation necessity, or sometimes convenience.\n   // This wrapper class ensures that when the data behind those logical references are\n   // access the implementation pointer is not null.  Note that the role served by this\n   // class is not the same as ipr::Optional (which is a genuine representation of optional information),\n   // or std::reference_wrapper (which assumes existence of reference to begin with).\n   template<typename T>\n   struct ref {\n      ref(T* p = { }) : ptr{p} { }\n      T& get() const { return *util::check(ptr); }\n   private:\n      T* ptr;\n   };\n\n   // --------------------\n   // -- Red-back trees --\n   // --------------------\n\n   // The implementation found here is based on ideas in\n   // T. H. Cormen, C. E. Leiserson, R. L. Rivest and C. Strein:\n   //     \"Introduction to Algorithms\", 2nd edition.\n\n   // One reason why we (re-)implement our own \"set\" data structures\n   // instead of using the standard ones is because standard sets\n   // do not allow for in-place modification.  That puts an\n   // unreasonable burden on how we can write the codes for IPR.\n   // Another reason is that, while the standard set is really a\n   // a red-lack tree in disguise, there is no way one can have\n   // access to that structure.  Furthermore, we use red-black\n   // trees in both \"intrusive\" and \"non-intrusive\" forms.\n\n   namespace rb_tree {\n      // Marker used to designate a tree node as either 'black' or 'red'.\n      enum class Color { Black, Red };\n\n      // The type of the links used to chain together data in\n      // a red-black tree.\n      template<class Node>\n      struct link {\n         enum Dir { Left, Right, Parent };\n\n         Node*& parent() { return arm[Parent]; }\n         Node*& left() { return arm[Left]; }\n         Node*& right() { return arm[Right]; }\n\n         Node* arm[3] { };\n         Color color = Color::Red;\n      };\n\n      template<class Node>\n      struct core {\n         std::ptrdiff_t size() const { return count; }\n\n      protected:\n         Node* root { };\n         std::ptrdiff_t count { };\n\n         // Do a left rotation about X.  X->left() is assumed nonnull,\n         // which after the manoeuvre becomes X's parent.\n         void rotate_left(Node*);\n\n         // Same as rotate_left, except that the rotation does right.\n         void rotate_right(Node*);\n\n         // After raw insertion, the tree is unbalanced again; this\n         // function re-balance the tree, fixing up properties destroyed.\n         void fixup_insert(Node*);\n      };\n\n      template<class Node>\n      void\n      core<Node>::rotate_left(Node* x)\n      {\n         Node* y = x->right();\n         // Make y's left a subtree of x's right subtree.\n         x->right() = y->left();\n         if (y->left() != nullptr)\n            y->left()->parent() = x;\n\n         // Update y's parent and its left or right arms.\n         y->parent() = x->parent();\n         if (x->parent() == nullptr)\n            // x was the root of the tree; make y the new root.\n            this->root = y;\n         else if (x->parent()->left() == x)\n            x->parent()->left() = y;\n         else\n            x->parent()->right() = y;\n\n         // Now, x must go on y's left.\n         y->left() = x;\n         x->parent() = y;\n      }\n\n      template<class Node>\n      void\n      core<Node>::rotate_right(Node* x)\n      {\n         Node* y = x->left();\n\n         x->left() = y->right();\n         if (y->right() != nullptr)\n            y->right()->parent() = x;\n\n         y->parent() = x->parent();\n         if (x->parent() == nullptr)\n            this->root = y;\n         else if (x->parent()->right() == x)\n            x->parent()->right() = y;\n         else\n            x->parent()->left() = y;\n\n         y->right() = x;\n         x->parent() = y;\n      }\n\n      template<class Node>\n      void\n      core<Node>::fixup_insert(Node* z)\n      {\n         while (z != root and z->parent()->color == Color::Red) {\n            if (z->parent() == z->parent()->parent()->left()) {\n               Node* y = z->parent()->parent()->right();\n               if (y != nullptr and y->color == Color::Red) {\n                  z->parent()->color = Color::Black;\n                  y->color = Color::Black;\n                  z->parent()->parent()->color = Color::Red;\n                  z = z->parent()->parent();\n               } else {\n                  if (z->parent()->right() == z) {\n                     z = z->parent();\n                     rotate_left(z);\n                  }\n                  z->parent()->color = Color::Black;\n                  z->parent()->parent()->color = Color::Red;\n                  rotate_right(z->parent()->parent());\n               }\n            } else {\n               Node* y = z->parent()->parent()->left();\n               if (y != nullptr and y->color == Color::Red) {\n                  z->parent()->color = Color::Black;\n                  y->color = Color::Black;\n                  z->parent()->parent()->color = Color::Red;\n                  z = z->parent()->parent();\n               } else {\n                  if (z->parent()->left() == z) {\n                     z = z->parent();\n                     rotate_right(z);\n                  }\n                  z->parent()->color = Color::Black;\n                  z->parent()->parent()->color = Color::Red;\n                  rotate_left(z->parent()->parent());\n               }\n            }\n         }\n\n         root->color = Color::Black;\n      }\n\n      // A chain is an rb-tree that supports search and insertion, with\n      // the comparison object passed as a parameter instead of being built\n      // into the tree type directly.  The comparison object `cmp` is always\n      // invoked as `cmp(data, key)` where `data` designates an existing\n      // object stored at a node in the chain, and `key` is the parameter by which\n      // the tree is searched.\n      template<class Node>\n      struct chain : core<Node> {\n         template<class Comp>\n         Node* insert(Node*, Comp);\n\n         template<typename Key, class Comp>\n         Node* find(const Key&, Comp) const;\n      };\n\n      template<class Node>\n      template<typename Key, class Comp>\n      Node*\n      chain<Node>::find(const Key& key, Comp comp) const\n      {\n         bool found = false;\n         Node* result = this->root;\n         while (result != nullptr and not found) {\n            auto ordering = comp(*result, key) ;\n            if (ordering < 0)\n               result = result->left();\n            else if (ordering > 0)\n               result = result->right();\n            else\n               found = true;\n         }\n\n         return result;\n      }\n\n      template<class Node>\n      template<class Comp>\n      Node*\n      chain<Node>::insert(Node* z, Comp comp)\n      {\n         Node** slot = &this->root;\n         Node* up = nullptr;\n\n         bool found = false;\n         while (not found and *slot != nullptr) {\n            auto ordering = comp(**slot, *z);\n            if (ordering < 0) {\n               up = *slot;\n               slot = &up->left();\n            }\n            else if (ordering > 0) {\n               up = *slot;\n               slot = &up->right();\n            }\n            else\n               found = true;\n         }\n\n         if (this->root == nullptr) {\n            // This is the first time we're inserting into the tree.\n            this->root = z;\n            z->color = Color::Black;\n         }\n         else if (*slot == nullptr) {\n            // key is not present, do what we're asked to do.\n            *slot = z;\n            z->parent() = up;\n            z->color = Color::Red;\n            this->fixup_insert(z);\n         }\n\n         ++this->count;\n         return z;\n      }\n\n      template<typename T>\n      struct node : link<node<T>> {\n         T data;\n      };\n\n      template<typename T>\n      struct container : core<node<T>>, private std::allocator<node<T>> {\n         template<typename Key, class Comp>\n         T* find(const Key&, Comp) const;\n\n         // We want to insert a node constructed out of a Key, using\n         // an admissible comparator LESS.  Returns a pointer to the\n         // newly created node, if successfully inserted, or the old\n         // one if the Key is already present.\n         template<class Key, class Comp>\n         T* insert(const Key&, Comp);\n\n      private:\n         template<class U>\n         node<T>* make_node(const U& u) {\n            node<T>* n = this->allocate(1);\n            new (&n->data) T(u);\n            n->left() = nullptr;\n            n->right() = nullptr;\n            n->parent() = nullptr;\n            return n;\n         }\n\n         void destroy_node(node<T>* n) {\n            if (n != nullptr) {\n               n->data.~T();\n               this->deallocate(n, 1);\n            }\n         }\n      };\n\n      template<typename T>\n      template<typename Key, class Comp>\n      T*\n      container<T>::find(const Key& key, Comp comp) const\n      {\n         for (node<T>* x = this->root; x != nullptr; ) {\n            auto ordering = comp(x->data, key);\n            if (ordering < 0)\n               x = x->left();\n            else if (ordering > 0)\n               x = x->right();\n            else\n               return &x->data;\n         }\n\n         return nullptr;\n      }\n\n      template<typename T>\n      template<typename Key, class Comp>\n      T*\n      container<T>::insert(const Key& key, Comp comp)\n      {\n         if (this->root == nullptr) {\n            // This is the first time we're inserting into the tree.\n            this->root = make_node(key);\n            this->root->color = Color::Black;\n            ++this->count;\n            return &this->root->data;\n         }\n\n         node<T>** slot = &this->root;\n         node<T>* parent = nullptr;\n         node<T>* where = nullptr;\n         bool found = false;\n\n         for (where = this->root; where != nullptr and not found; where = *slot) {\n            auto ordering = comp(where->data, key);\n            if (ordering < 0) {\n               parent = where;\n               slot = &where->left();\n            }\n            else if (ordering > 0) {\n               parent = where;\n               slot = &where->right();\n            }\n            else\n               found = true;\n         }\n\n         if (where == nullptr) {\n            // key is not present, do what we're asked to do.\n            where = *slot = make_node(key);\n            where->parent() = parent;\n            where->color = Color::Red;\n            ++this->count;\n            this->fixup_insert(where);\n         }\n\n         return &where->data;\n      }\n   }\n\n   // -- helper for implementing permanent string objects.  They uniquely\n   // -- represent their contents throughout their lifetime.  Ideally,\n   // -- they are allocated from a pool.\n   struct string {\n      struct arena;\n\n      using size_type = std::ptrdiff_t; // integer type that string length\n\n      // number of characters directly contained in this header\n      // of the string.  Taken to be the number of bytes in size_type.\n      static constexpr size_type padding_count = sizeof (size_type);\n\n      size_type size() const { return length; }\n      char operator[](size_type) const;\n\n      const char8_t* begin() const { return data; }\n      const char8_t* end() const { return begin() + length; }\n\n      size_type length;\n      char8_t data[padding_count];\n   };\n\n   struct string::arena {\n      arena();\n      ~arena();\n\n      const string* make_string(const char8_t*, size_type);\n\n   private:\n      util::string* allocate(size_type);\n      auto remaining_header_count() const\n      {\n         return mem->storage + bufsz - next_header;\n      }\n\n      struct pool;\n\n      static constexpr size_type headersz = sizeof (util::string);\n      static constexpr size_type bufsz = headersz << (20 - sizeof (pool*));\n\n      struct pool {\n         pool* previous;\n         util::string storage[bufsz];\n      };\n\n      static constexpr size_type poolsz = sizeof (pool);\n\n      pool* mem;\n      string* next_header;\n   };\n\n   struct lexicographical_compare {\n      template<typename In1, typename In2, class Compare>\n      int operator()(In1 first1, In1 last1, In2 first2, In2 last2,\n                     Compare compare) const\n      {\n         for (; first1 != last1 and first2 != last2; ++first1, ++first2)\n            if (auto cmp = compare(*first1, *first2))\n               return cmp;\n\n         return first1 == last1 ? (first2 == last2 ? 0 : -1) : 1;\n      }\n   };\n}\n\n#endif // IPR_UTILITY_IMPL_INCLUDED\n"
  },
  {
    "path": "infra/Analysis.ruleset",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RuleSet Name=\"IPR Ruleset\" Description=\"Warnings to enable for the Microsoft C++ Code Analysis for IPR repository.\" ToolsVersion=\"10.0\">\n   <!-- Default rules available in Visual Studio -->\n  <Include Path=\"NativeRecommendedRules.ruleset\" Action=\"Default\" />\n  <!-- Enforcement of the C++ Core Guidelines -->\n  <Include Path=\"CppCoreCheckRules.ruleset\" Action=\"Default\" />\n\n  <Rules AnalyzerId=\"Microsoft.Analyzers.NativeCodeAnalysis\" RuleNamespace=\"Microsoft.Rules.Native\">\n    <!-- Excluded warnings -->\n    <Rule Id=\"C26440\" Action=\"None\" /> <!-- Declare noexcept -->\n    <Rule Id=\"C26455\" Action=\"None\" /> <!-- Declare noexcept (ctor) -->\n    <Rule Id=\"C26436\" Action=\"None\" /> <!-- Virtual dtors -->\n    <Rule Id=\"C26481\" Action=\"None\" /> <!-- No pointer arithmetic -->\n    <Rule Id=\"C26485\" Action=\"None\" /> <!-- No pointer decay -->\n    <Rule Id=\"C26445\" Action=\"None\" /> <!-- No reference for views -->\n    <!-- Const -->\n    <Rule Id=\"C26496\" Action=\"None\" /> <!-- Mark var const -->\n    <Rule Id=\"C26462\" Action=\"None\" /> <!-- Mark pointer var const -->\n    <Rule Id=\"C26463\" Action=\"None\" /> <!-- Mark array const -->\n    <Rule Id=\"C26464\" Action=\"None\" /> <!-- Mark array of pointers const -->\n    <Rule Id=\"C26814\" Action=\"None\" /> <!-- Mark var constexpr -->\n    <!-- Memory management -->\n    <Rule Id=\"C26409\" Action=\"None\" /> <!-- No new/delete -->\n    <Rule Id=\"C26401\" Action=\"None\" /> <!-- Do not delete non-owner pointer -->\n    <Rule Id=\"C26406\" Action=\"None\" /> <!-- No allocation to non-owner pointer -->\n    <!-- Usage of GSL -->\n    <Rule Id=\"C26429\" Action=\"None\" /> <!-- Use gsl::not_null -->\n    <Rule Id=\"C26446\" Action=\"None\" /> <!-- Use gsl::at -->\n    <Rule Id=\"C26482\" Action=\"None\" /> <!-- Only index with constant expr -->\n    <!-- False positives, re-enabled if fixed -->\n    <Rule Id=\"C26434\" Action=\"None\" /> <!-- Hides non-virtual -->\n  </Rules>\n</RuleSet>"
  },
  {
    "path": "src/ChangeLog",
    "content": "2015-11-29  Gabriel Dos Reis  <gdr@axiomatics.org>\n\n\t* impl.cxx: Implement modifications to ipr::Enum.\n\n2010-07-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::expr_factory::make_id_expr): Define new overload.\n\n2010-05-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C: Pretty print Initializer_list.\n\n2010-05-11  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_initializer)): Print declarations\n\ttoo. \n\n2010-04-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Unit::get_typename): Define.\n\n2010-04-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (xpr::Decl): Print function specifiers.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (expr_factory::make_identifier(const char*)): Define.\n\t(expr_factory::make_identifier(const std::string&)): Likewise.\n\t(expr_factory::make_operator(const char*)): Likewise.\n\t(expr_factory::make_operator(const std::string&)): Likewise.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (expr_factory::get_linkage): Define.\n\t(Unit::get_cxx_linkage): Define in terms of expr_factory::get_linkage.\n\t(Unit::get_c_linkage): Likewise.\n\t(Unit::Unit): Call get_cxx_linkage iin lieu of cxx_linkage.\n\t* traversal.C (Visitor::visit(const C_linkage&)): Remove.\n\t(Visitor::visit(const Cxx_linkage&)): Linkage.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (expr_factory::make_literal): Define new overloads.\n\n2010-03-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (ipr): Reflect changes from Unit::get_string to\n\texpr_factory::get_string. \n\n2009-09-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (type_factory::make_rvalue_reference): Define.\n\t(Unit::get_rvalue_reference): Likewise.\n\n2009-07-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::For_in::type): Define.\n\n2009-06-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C: Define For_in members.\n\t* io.C: Define printer for For_in nodes.\n\n2008-11-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Mapping::has_result): Remove.\n\t* io.C (impl::xpr_mapping_expression_visitor): Tidy.\n\n2008-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* traversal.C (Visitor::visit(const Datm&)): Forward as Classic.\n\n2008-09-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* traversal.C (Visitor::visit(const Classic&)): Implement.\n\tPropagate forwarding visitor functions.\n\n2008-06-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Var::membership): Remove.\n\t(impl::Var::Var): Don't initialize member_of.\n\n2008-05-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (Var::lexical_region): Define.\n\t(Typedecl::lexical_region): Likewise.\n\t(Parameter::lexical_region): Likewise.\n\t(Parameter::home_region): Likewise.\n\t(Named_map::lexical_region): Likewise.\n\t(Fundecl::lexical_region): Likewise.\n\t(Field::lexical_region): Likewise.\n\t(Field::home_region): Likewise.\n\t(Enumerator::lexical_region): Likewise.\n\t(Enumerator::home_region): Likewise.\n\t(Base_type::lexical_region): Likewise.\n\t(Base_type::home_region): Likewise.\n\t(Bitfield::lexical_region): Likewise.\n\t(Bitfield::home_region): Likewise.\n\t(Alias::lexical_region): Likewise.\n\n2005-11-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.C: New.\n\n2005-09-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Linkage::Linkage): Define.\n\n\t* traversal.C (Visitor::visit(const Linkage&)): Define.\n\n2005-07-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_type)::Impl::visit(const\n\tPtr_to_member&)):  New.\n\t(operator<<(Printer&, xpr_type_expr)::Impl::visit(const\n\tPtr_to_member&&)):  Likewise.\n\n2005-06-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* utility.C:New.\n\n\t* impl.C (impl::Enumerator::Enumerator): Don't forget initization\n\tof impl::Enumerator::init.\n\n2005-05-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::expr_factory::make_mapping): Adjust parameter list.\n\t(impl::Parameter::Parameter): Tidy.\n\t(impl::Parameter::type): Likewise.\n\t(impl::Parameter::position): Define.\n\n\t* io.C (xpr::Name::visit(const ipr::Rname&))): Define.\n\n\t* impl.C (impl::Rname::Rname): Define.\n\t(impl::Rname::type): Likewise.\n\t(impl::Rname::position): Likewise.\n\t(impl::Rname::level): Likewise.\n\n\t* traversal.C (Visitor::visit(const Rname&)): Define.\n\n2005-04-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_decl)): Print semi-colon if\n\tneeded. \n\t(xpr::Decl::visit(const Scope&)): Tidy.\n\t(operator<<(Printer&, xpr_expr)::Impl::visit(const Scope&)): Tidy.\n\t(operator<<(Printer&, xpr_expr)::Impl::visit(const Decl&)): New.\n\t(xpr::Decl::visit(const Scope&)): Remove.\n\t(xpr::Stmt::visit(const Decl&)): New.\n\t(xpr::Stmt): Derive from xpr::Assignment_expr.\n\n2005-03-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (xpr_quote): Remove.\n\t(operator<<(Printer&, xpr_quote)): Move body to...\n\t(xpr::Primary_expr::visit(const Literal&)): ... here.  Define outline.\n\n\t* interface.C (stats::node_usage_counts): New local data.\n\t(stats::all_nodes_count): Define.\n\t(stats::node_count): Likewise.\n\t(Node::Node): Increment usage count.\n\n\t* io.C (new_style_cast): Make a template.\n\t(offset_with_pm): Likewise.\n\t(xpr::Initializer::visit(const Expr&)): New.\n\t(xpr::Initializer::visit(const Stmt&)): Likewise.\n\t(xpr::Stmt): New.\n\t(operator<<(Printer&, xpr_stmt)): Use it.  Move local class\n\tdefinition to xpr::Stmt.\n\t(xpr::Decl): New.\n\t(operator<<(Printer&, xpr_decl)): Use it.  Move local class\n\tdefinition to xpr::Decl.\n\t(operator<<(Printer&, const Decl&)): Remove.\n\t(insert_xtoken): Remove.\n\t(Token_helper<>): New.\n\t(token<>): Likewise.\n\t(operator<<(Printer&, Token_helper<>)): Likewise.\n\n2005-03-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* interface.C (Node::Node): Adjust.\n\n2005-03-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::expr_factory::make_id_expr): Define.\n\t(impl::Overload::accept): Remove.\n\t(impl::singleton_overload::accept): Likewise.\n\t(impl::empty_overload::accept): Likewise.\n\t(impl::Break::accept): Likewise.\n\t(impl::Continue::accept): Likewise.\n\t(impl::Comment::accept): Likewise.\n\t(impl::Expr_list::accept): Likewise.\n\t(impl::Identifier::accept): Likewise.\n\t(impl::Id_expr::accept): Likewise.\n\t(impl::Literal::accept): Likewise.\n\t(impl::Mapping::accept): Likewise.\n\t(impl::Operator::accept): Likewise.\n\t(impl::Paren_expr::accept): Likewise.\n\t(impl::Scope::accept): Likewise.\n\t(impl::Region::accept): Likewise.\n\t(impl::Unit::accept): Likewise.\n\t(impl::Block::accept): Likewise.\n\t(impl::For::accept): Likewise.\n\t(impl::Literal::accept): Likewise.\n\n\t* io.C (xpr::Primary_expr::visit(const Id_expr&)): Defie.\n\n\t* traversal.C (Visitor::visit(const Id_expr&)): Define.\n\n\t* impl.C (impl::Id_expr::Id_expr): Define.\n\t(impl::Id_expr::type): Likewise.\n\t(impl::Id_expr::operand): Likewise.\n\t(impl::Id_expr::resolution): Likewise.\n\t(impl::Id_accept): Likewise.\n\n\t* io.C (xpr_initializer): New.\n\t(operator<<(Printer&, xpr_initializer): New.\n\t(operator<<(Printer&, xpr_mapping_expression): Use it.\n\n\t* impl.C (impl::Mapping::Mapping): Initialize member value_type.\n\t(impl::Mapping::result_type): Define.\n\n2005-03-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, const Expr&)): Remove.\n\t(operator<<(Printer&, const Type&)): Likewise.\n\t(operator<<(Printer&, const Decl&)): Likewise.\n\t(print_sequence): Likewise.\n\t(operator<<(Printer&, const Product&)): Likewise.\n\t(operator<<(Printer&, const Sum&)): Likewise.\n\n\t(operator<<(Printer&, const Expr_list&): Tidy.\n\t(operator<<(Printer&, const Sequence<Type>&): Likewise.\n\t(operator<<(Printer&, const Parameter_list&): Likewise.\n\t(operator<<(Printer&, const Conversion&): Likewise.\n\t(operator<<(Printer&, const Type_id&): Likewise.\n\t(operator<<(Printer&, const Datum&): Likewise.\n\t(operator<<(Printer&, const Cast_expr&): Likewise.\n\t(new_style_cast): Likewise.\n\t(operator<<(Printer&, const Cast&): Likewise.\n\t(operator<<(Printer&, xpr_exception_spec): Likewise.\n\t(operator<<(Printer&, xpr_base_classes): Likewise.\n\t(operator<<(Printer&, const Decltype&): Likewise.\n\t(operator<<(Printer&, const Reference&): Likewise.\n\t(operator<<(Printer&, const Pointer&): Likewise.\n\t(operator<<(Printer&, const Array&): Likewise.\n\t(operator<<(Printer&, xpr_type): Likewise.\n\t(operator<<(Printer&, const Base_type&): Likewise.\n\t(operator<<(Printer&, const Typedecl&): Likewise.\n\n\t(xpr::Name): New.\n\t(operator<<(Printer&, const Name&)): Use it.\n\n\t(xpr::Primary_expr): New.\n\t(operator<<(Printer&, xpr_primary_expr): Use it. \n\n\t(xpr::Postfix_expr): New.\n\t(operator<<(Printer&, xpr_postfix_expr): Use it. \n\n\t(xpr::Unary_expr): New.\n\t(unary_operation): Use it. \n\t(operator<<(Printer&, xpr_unary_expr): Tidy. \n\n\t(xpr::Cast_expr): New.\n\t(operator<<(Printer&, xpr_cast_expr): Use it. \n\n\t(xpr::Pm_expr): New.\n\t(operator<<(Printer&, xpr_pm_expr): Use it. \n\n\t(xpr::Mul_expr): New.\n\t(operator<<(Printer&, xpr_mul_expr): Use it. \n\n\t(xpr::Shift_expr): New.\n\t(operator<<(Printer&, xpr_shift_expr): Use it. \n\n\t(xpr::Add_expr): New.\n\t(operator<<(Printer&, xpr_add_expr): Use it. \n\n\t(xpr::Rel_expr): New.\n\t(operator<<(Printer&, xpr_rel_expr): Use it. \n\n\t(xpr::Eq_expr): New.\n\t(operator<<(Printer&, xpr_eq_expr): Use it. \n\n\t(xpr::And_expr): New.\n\t(operator<<(Printer&, xpr_and_expr): Use it. \n\n\t(xpr::Xor_expr): New.\n\t(operator<<(Printer&, xpr_xor_expr): Use it. \n\n\t(xpr::Ior_expr): New.\n\t(operator<<(Printer&, xpr_ior_expr): Use it. \n\n\t(xpr::Land_expr): New.\n\t(operator<<(Printer&, xpr_land_expr): Use it. \n\n\t(xpr::Cond_expr): New.\n\t(operator<<(Printer&, xpr_cond_expr): Use it. \n\n\t(xpr::Assignment_expr): New.\n\t(operator<<(Printer&, xpr_assignment_expr): Use it. \n\n2005-03-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, const xpr_decl)::Impl::visit(const\n\tNamed_map)):  Fix thinko.\n\n2005-03-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (ipr::operator<<(Printer&, xpr_mapping_expression)): Fix\n\tthinko. \n\t(ipr::operator<<(Printer&, xpr_decl)): Fix thinko.\n\n2005-03-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.34\n\n2005-02-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (ipr): Rename Expr_as_type to As_type.\n\t* traversal.C: Likewise.\n\t* impl.C: Likewise.  Rename make_expr_as_type to make_as_type.\t\n\tRename heterogeneous_scope ro Scope.\n\tRename heterogeneous_region to Region.\n\n2005-02-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::heterogeneous_scope::operator[]): Tidy.\n\n2005-02-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Unit::make_template_id): Define.\n\t(impl::Enum::add_member): Define.\n\t(impl::Named_map::Named_map): Tidy.\n\t(impl::Named_map::primary_named_map): Likewise.\n\t(impl::Named_map::specializations): Likewise.\n\t(impl::Named_map::mapping): Likewise.\n\t(impl::Named_map::has_initializer): Likewise.\n\t(impl::Named_map::initializer): Likewise.\n\t(impl::Enum::add_member): Define.\n\t(impl::heterogeneous_scope::make_primary_map): Rework.\n\t(impl::heterogeneous_scope::make_secondary_map): Likewise.\n\t(impl::Unit::make_template_id): Define.\n\n2005-02-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (Printer::operator<<): Remove definitions of overloads for\n\tcharacters.\n\n2005-02-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Unit::make_ctor_name): Define.\n\t(impl::Unit::make_dtor_name): Likewise.\n\n2005-02-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (impl::Class::add_base): Define.\n\t(impl::Class::Class): Set\n\timpl::Class::base_subobjects::scope::owned_by.\n\n2005-02-06  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.33.\n\n\t* io.C (xpr_exception_spec): Tidy.\n\t(operator<<(Printer&, xpr_mapping_expression): Define.\n\n\t* impl.C (impl::Fundecl::Fundecl): Propagate changes.\n\t(impl::Expr_list): Define all member functions.\n\t(impl::Mapping::param): Define.\n\t(impl::stmt_factory::make_for): Likewise.\n\t(impl::heterogeneous_region::make_subregion): Likewise.\n\t(impl::Unit::make_function): Likewise.\n\t(Unit::make_expr_list): Remove.\n\n2005-02-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* impl.C (unary_less()): Compare ref_sequence<>s too.\n\t(impl::Unit::make_product): Define.\n\t(impl::Unit:make_sum): Likewise.\n\t(impl::Unit::make_expr_list): Likewise.\t\n\n2004-12-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C: #include \"ipr/travsersal.H\".\n\tPropogate renaming in \"ipr/interface.H\".\n\n2004-11-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Lshift): Rename from Shift_left.\n\t(Lshift_assign): Rename from Shift_left_assign.\n\t(Rshift): Rename from Shift_right.\n\t(Rshift_assign): Rename from Shift_right_assign.\n\n2004-11-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Multi_comment&)): Remove.\n\n2004-11-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Comment&)): Define.\n\t(Visitor::visit(const Multi_comment&)): Likewise.\n\t(Visitor::visit(const Unit&)): Likewise.\n\n2004-11-09  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C: Replace Expr_as_type with Type_expr.\n\tReplace Specialization with Template_id.\n\t* io.C: Likewise.\n\n2004-11-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Asm&)): Define.\n\n2004-10-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.26.\n\t\n2004-10-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Stmt_builder::make_expr_stmt): Tidy.\n\t(Stmt_builder::make_labeled_stmt): Likewise.\n\t(Stmt_builder::make_ctor_body): Likewise.\n\t(Stmt_builder::make_if_then): Likewise.\n\t(Stmt_builder::make_if_then_else): Likewise.\n\t(Stmt_builder::make_goto): Likewise.\n\n2004-10-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Stmt_builder::make_break): Define here.\n\t(Stmt_builder::make_continue): Likewise.\n\t(Stmt_builder::make_block): Likewise.\n\t(Stmt_builder::make_ctor_body): Likewise.\n\t(Stmt_builder::make_expr_stmt): Likewise.\n\t(Stmt_builder::make_goto): Likewise.\n\t(Stmt_builder::make_return): Likewise.\n\t(Stmt_builder::make_do): Likewise.\n\t(Stmt_builder::make_if_then): Likewise.\n\t(Stmt_builder::make_switch): Likewise.\n\t(Stmt_builder::make_handler): Likewise.\n\t(Stmt_builder::make_labeled_stmt): Likewise.\n\t(Stmt_builder::make_while): Likewise.\n\t(Stmt_builder::make_if_then_else): Likewise.\n\t(Stmt_builder::make_for): Likewise.\n\n2004-10-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_specialization): define.\n\n2004-10-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&,\n\txpr_primary_expression)::Impl::visit(const Expr_in_parens&)): Define.\n\n\t* ipr.C (Visitor::visit(const Expr_in_parens&)): Define.\n\n2004-09-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.25.\n\n\t* ipr.C (Unit_impl::make_ctor_name): Define.\n\t(Unit_impl::make_dtor_name): Likewise..\n\n\t* io.C (operator<<(Printer&, xpr_declaration)::Impl::visit(const\n\tConstructor&)):  Remove.\n\t(operator<<(Printer&, xpr_declaration)::Impl::visit(const\n\tDestructor&)):  Remove.\t\n\t(operator<<(Printer&, xpr_name)::Impl::visit(const Ctor_name&)):\n\tDefine. \n\t(operator<<(Printer&, xpr_name)::Impl::visit(const Dtor_name&)):\n\tLikewise. \n\t(operator<<(Printer&, xpr_type_expr)::Impl::visit(const Udt&)): Tidy.\n\n\t* ipr.C (Visitor::visit(const Dtor_name&)): Define.\n\t(Visitor::visit(const Ctor_name&)): Likewise.\n\t(Visitor::visit(const Constructor&)): Remove.\n\t(Visitor::visit(const Destructor&)): Likewise.\n\t(Unit_impl::make_constructor): Likewise.\n\t(Unit_impl::make_destructor): Likewise.\n\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Name&)): Define.\n\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.24\n\t\n2004-09-20  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Parameter_list_impl::add_param): Use\n\tDcl_impl<>::register_to. \n\n2004-09-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (view): New.\n\t(Unit_impl::make_expr_as_type): Use it.\n\n2004-09-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_fun_decl): Tidy.\n\t(Unit_impl::make_destructor): Define.\n\n2004-09-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&,\n\txpr_expression_list)::Impl::visit(const Sum&)): Define.\n\t(operator<<(Printer&, xpr_type)::Impl::visit(const Sum&)): Define.\n\n\t* ipr.C (Visitor::visit(const Sum&)): Define.\n\t(Unit_impl::make_sum): Define.\n\t(Unit_impl::make_function): Update. Tidy.\n\n2004-09-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_quote)): Tidy.\n\n2004-08-30  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.23.\n\t\n2004-08-31  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_expr_as_type): Ensure idempotency.\n\n\t* io.C (operator<<(Printer&, xpr_quote)): New.\n\t(operator<<(Printer&, xpr_primary_expression)::Impl::visit(const\n\tLiteral&)): Use it.\n\n2004-08-30  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Enumerator&)): Define.\n\n2004-08-28  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Enum&)): Fallthrough to Udt.\n\n2004-08-27  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_name)::Impl::visit(const\n\tSpecialization&)):  Move from operator<<(Printer&,\n\txpr_primary_expression). \n\t(operator<<(Printer&, xpr_type_expr)::Impl::visit(const Template&)): \n\tTidy.\n\t(operator<<(Printer&, xpr_type_expr)::Impl:visit(const\n\tDecltype&)): New.\t\n\t(pp_base::visit(const Type&)): Fallthrough to Expr.\n\n\t* ipr.C (Visitor::visit(const Specialization&)): Fallthrough to Name.\n\n2004-08-26  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_operator): Define.\n\t(Unit_impl::make_identifier): Likewise.\n\t(Unit_impl::make_conversion): Likewise.\n\t(Unit_impl::make_scope_ref): Likewise.\n\n\t* io.C (operator<<(Printer&, xpr_name)): Handle Scope_ref.\n\t(at): New helper function.\n\n\t* ipr.C (Visitor::visit(const Scope_ref&)): Fallthrough to Name.\n\t(Visitor::visit(const Union&)): Fallthrough to Udt.\n\t(Visitor::visit(const Namespace&)): Likewise.\n\t(Visitor::visit(const Class&)): Likewise.\n\t(Visitor::visit(const Decltype&)): Fallthrough to Type.\n\t(Unit_impl::make_decltype): Define.\n\n2004-08-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.22.\n\t\n2004-08-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_alias): Don't set type_impl() here.\n\n2004-08-24  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Scope_ref&)): Tidy.\n\n2004-08-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* gnu-tu.H: New file.\n\t* gnu-tu.C: Likewise.\n\n2004-08-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.21.\n\t\n2004-08-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, Decl::Specifier)): Fix typo.\n\n2004-08-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C: Simplify Do_while to Do.\n\t* io.C: Likewise.\n\t(operator<<(Printer&, xpr_statement)): Tidy.\n\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.20.\n\t\n2004-08-10  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_type_expr)): Collapse printing\n\tfor Union and Enum into one place that handles Udt by default.\n\n\t* ipr.C (Visitor::visit(const Udt&)): Define.\n\n2004-08-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Ctor_body&)): Define.\n\t(Visitor::visit(const Expr_stmt&)): Likewise.\n\t(Unit_impl::make_handler_seq): Remove.\n\n\t* io.C (operator<<(Printer&, xpr_expression)): Don't print\n\tFunction_body.\n\t(operator<<(Printer&, xpr_statement)): Handle Ctor_body.\n\n2004-08-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.19.\n\t\n2004-08-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_handler_seq): \n\t* io.C (operator<<(Printer&, xpr_unary_expression)): Don't forget\n\tto print Unary_plus.\n\t(operator<<(Printer&, xpr_type_expr)): Print parameter-list in\n\tparenthesis.\n\t(operator<<(Printer&, xpr_declaration)): Likewise.\n\n2004-07-18  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_type)): Fix thinko.\n\n2004-07-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.18.\n\t\n2004-07-16  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_expression)): Handle Member_init \n\tand member-initializer list in constructor body.\n\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.17.\n\t\n2004-07-15  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Type_id&)): Define.\n\t(Visitor::visit(const Name_as_expr&)): Remove.\n\t(Unit_impl::make_product): Tidy.\n\t(Unit_impl::make_expr_list): Likewise.\n\t(CV_type<>): New helper class.\n\t(CV_unary<>): Likewise.\n\t(CV_binary<>): Likewise.\n\t(CV_ternary<>): Likewise.\n\t(CV_udt<>): Likewise.\n\t(Unit_impl::make_cv_qualified): Rework.  Build names for\n\tcv-qualified types too.\n\t(Unit_impl::make_class): Tidy.\n\t(Unit_impl::make_union): Tidy.\n\t(Unit_impl::make_enum): Tidy.\n\t(Unit_impl::make_namespace): Tidy.\n\t(Unit_impl::make_var): Move here from impl.H.\n\n\t* io.C (pp_base::visit(const Name&)): Visit as an expression. \n\t(operator<<(Printer&, xpr_expression)): Handle Expr_list.\n\t(operator<<(Printer&, xpr_name)): Render Type_id too.\n\t(operator<<(Printer&, xpr_primary_expression)): Remove case for\n\tName_as_expr.\n\t(operator<<(Printer&, Type::Qualifier)): New.\n\t(operator<<(Printer&, xpr_type_expr)): Handle Expr_as_type.\n\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.16\n\t\n2004-07-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr_type)): Uncomment out the case\n\tfor template printing.\n\t(operator<<(Printer&, xpr_declaration)): Handle Bit_field.\n\t(hash): New.\n\t(xpr_base_classes): New.\n\t(operator<<(Printer&, xpr_base_classes)): Handle base classes.\n\n2004-07-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_field): Define.\n\t(Unit_impl::make_bit_field): Likewise.\n\t(Visitor::visit(const Field&)): Likewise.\n\t(Visitor::visit(const Bit_field&)): Likewise.\n\n2004-07-06  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (operator<<(Printer&, xpr::statement)::Impl\n\t::visit(const For&)): Fix thinko.\n\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C: Tidy.\n\t(operator<<(Printer&, xpr_expression)::Impl): Print Scope here.\n\n2004-07-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.15.\n\t\n2004-07-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.14.\n\t\n2004-07-04  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Field&)): New.\n\t* io.C (newline): Tidy.\n\t(pp_base::visit(const Decl&)): Call visit(const Expr&).\n\n2004-07-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.13.\n\t\n2004-07-02  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Conditional&)): Define.\n\t(Visitor::visit(const Type_decl&)): Likewise.\n\t(Unit_impl::make_type_decl): Likewise.\n\n\t* io.C: Reimplement from scratch.\n\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.12.\n\t\n2004-07-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_alias): Define.\n\n\t* io.C (printer::Base::visit(const Node&)): Define.\n\t(printer::Base::visit(const Name&)): Likewise.\n\t(printer::Base::visit(const Expr&)): Likewise.\n\t(printer::Base::visit(const Type&)): Likewise.\n\t(printer::Base::visit(const Stmt&)): Likewise.\n\t(printer::Base::visit(const Decl&)): Likewise.\n\t(printer::whitespace): Likewise.\n\t(printer::left_paren): Likewise.\n\t(printer::right_paren): Likewise.\n\t(printer::left_brace): Likewise.\n\t(printer::right_brace): Likewise.\n\t(printer::left_bracket): Likewise.\n\t(printer::right_bracket): Likewise.\n\t(printer::xpr::Expression::visit(const Add_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Bitand_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Bitor_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Bitxor_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Div_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Mul_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Shift_left_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Shift_right_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Sub_assign&)): Likewise.\n\t(printer::xpr::Expression::visit(const Destructor&)): Likewise.\n\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.11.\n\t\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit(const Instantiation&)): Remove.\n\t(Visitor::visit(const Qualified&)): Remove.\n\t(Visitor::visit(const Object_type&)): Remove.\n\t(Visitor::visit(const Expr_as_type&)): Define.\n\t(Visitor::visit(const Specialization&)): Likewise.\n\t(Unit_impl::make_cv_qualified::Builder): Simplify.\n\t(Unit_impl::Unit_impl): Tidy.\n\t\n2004-06-29  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C: Clean up.\n\t(Visitor::visit(const Product&)): Define.\n\t(Visitor::visit(const Scope&)): Likewise.\n\t(Visitor::visit(const Expr_list&)): Likewise.\n\t(Class_impl::): Remove.\n\t(Union_impl::): Remove.\n\t(Enum_impl::): Remove.\n\t(Parameter_impl::): Remove.\n\t(Parameter_list_impl::add_param): Define.\n\t(Unit_impl::make_expr_list): Rename from Unit_impl::make_sequence.\n\t(Unit_impl::make_product): Likewise.\n\t(Unit_impl::make_fun_decl): Define.\n\t(Unit_impl::make_enumerator): Likewise.\n\t(Unit_impl::make_base_type): Liekwise.\n\t(Unit_impl::make_constructor): Likewise.\n\n\t* io.C (printer::xpr::Expression::visit(const Scope&)):\n\tReimplement.\n\t(printer::xpr::Expression::visit(const Function&)): Tidy.\n\t(printer::xpr::Expression::visit(const Product&)): Define.\n\t(printer::xpr::Expression::visit(const Expr_list&)): Likewise.\n\t(printer::xpr::Expression::visit(const Function_body&)): Likewise.\n\t(printer::xpr::Declaration::visit(const Parameter_list&)): Likewise.\n\t(printer::xpr::Declaration::visit(const Enumerator&)): Likewise.\n\t(printer::xpr::Declaration::visit(const Base_type&)): Likewise.\n\n2004-06-19  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C: Reflect changes as fallout of removal of unnecessary codes\n\tin ipr/interface.H.\n\t(printer::xpr::Expression::visit(const Throw&)): Define.\n\t* ipr.C (Visitor::visit(const Throw&)): Define.\n\t(Visitor::visit(const Base_type&)): Likewise.\n\t(New_impl::): Remove.\n\t(Function_body_impl::): Comment out.\n\t(Unit_impl::make_pointer): Remove.\n\t(Unit_impl::make_reference): Remove.\n\t(Unit_impl::make_array): Remove.\n\t(Unit_impl::make_funuction): Remove.\n\t(Unit_impl::make_if_then_else): Remove.\n\t(Unit_impl::make_for): Remove.\n\t(Unit_impl::make_literal): Remove.\n\t(Unit_impl::make_annotation): Remove.\n\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.10.\n\t\n2004-06-12  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C: Throught replace direct formatting to Base::stream with\n\tan operation on printers. \n\t(print_namable): Remove.\n\t(printer::xpr::Statement::visit(const Signature&)): Remove.\n\t(printer::xpr::Declaration::visit(const Signature&)): Remove.\n\t* ipr.C (validate_index): Remove.\n\t(error): Likewise.\n\t(default_to): Likewise.\n\t(as): New function.  Throughout Visitor member functions, replace\n\tdefault_to<> with a call to visit(as<>()).\n\t(scope_impl): Remove.\n\t(Instantiation_impl::name): Remove.\n\t(Instantiation_impl::scope_impl): Likewise.\n\t(Instantiation_impl::args): Likewise.\n\t(Overload_impl::size): Likewise.\n\t(Overload_impl::get): Likewise.\n\t(Overload_impl::operator[]): Likewise.\n\t(Overload_impl::accept): Likewise.\n\t(Overload_impl::register_decl): Likewise.\n\t(Signature): Remove all member definitions.\n\t(Function_impl): Likewise.\n\t(Member_impl): Likewise.\n\t(Block_impl): Likewise.\n\t(Handler_impl): Likewise.\n\t(Member_decl_impl): Likewise.\n\t(Fun_decl_impl): Likewise.\n\n2004-06-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Unit_impl::make_signature): Remove.\n\t(Signature_impl): Remove.\n\t(Unit_impl::make_function): Tidy.\n\n2004-05-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Call_impl): Remove.\n\t(Object_construction_impl): Likewise.\n\t(Unit_impl::make_labeled_stmt): Remove.\n\t(Unit_impl::make_if_then): Likewise.\n\t(Unit_impl::make_switch): Likewise.\n\t(Unit_impl::make_while): Likewise.\n\t(Unit_impl::make_do_while): Likewise.\n\t(Unit_impl::make_break): Likewise.\n\t(Unit_impl::make_continue): Likewise.\n\t(Unit_impl::make_goto): Likewise.\n\t(Unit_impl::make_return): Likewise.\n\t(Unit_impl::make_handler): Likewise.\n\t(Unit_impl::make_expr_sizeof): Likewise.\n\t(Unit_impl::make_type_sizeof): Likewise.\n\t(Unit_impl::make_expr_typeid): Likewise.\n\t(Unit_impl::make_type_typeid): Likewise.\n\n\t* io.C: Match renaming in ipr/interface.H\n\t(ipr::printer::xpr::Statement::visit(const Labeled_stmt&)): Tidy.\n\n\t* ipr.C: Replace \"Program\" with \"Unit\", throughout.\n\t(Scope_impl::make_identifier::Impl::scope): Override Name::scope.\n\t(Scope_impl::make_operator::Impl::scope): Likewise.\n\t(Scope_impl::make_conversion::Impl::scope): Likewise.\n\t(Function_body_impl::members): Remove.\n\t(Function_body_impl::handlers): Likewise.\n\t(Visitor::visit(const Assign&)): Define.\n\t(Visitor::visit(const Class_template&)): Remove.\n\t(Visitor::visit(const Fun_decl_template&)): Likewise.\n\t(Visitor::visit(const Template&)): Default to Visitor::visit(const\n\tType&).\n\n2004-05-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.08.\n\t\n2004-05-17  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (Expression_printer::visit(const Type&)): Handle\n\tconstructed types.\n\n2004-05-14  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Program_impl::make_pointer): Cache computed value.\n\t(Program_impl::make_reference): Likewise.\n\t(Program_impl::make_cv_qualified): Define.\n\t(make_array): Cache computed value.\n\n2004-05-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.07.\n\n2004-05-13  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit): Rework defaults.  Remove definitions\n\tfor classes removed from ipr/impl.H.  See ipr/ChangeLog.\n\t(Scope_impl::make_block): Make node out of local class impl.\n\t(Scope_impl::make_identifier): Likewise.\n\t(Scope_impl::make_operator): Likewise.\n\t(Scope_impl::make_conversion): Likewise.\n\t(Scope_impl::make_qualified): Likewise.\n\t(Scope_impl::make_instantiation): Likewise.\n\t(Program_impl::make_pointer): Likewise.\n\t(Program_impl::make_reference): Likewise.\n\t(Program_impl::make_array): Likewise.\n\t(Program_impl::make_function): Likewise.\n\t(Program_impl::make_if_then): Likewise.\n\t(Program_impl:make_if_then_else): Likewise.\n\t(Program_impl::make_switch): Likewise.\n\t(Program_impl::make_while): Likewise.\n\t(Program_impl::make_do_while): Likewise.\n\t(Program_impl::make_for): Likewise.\n\t(Program_impl::make_break): Likewise.\n\t(Program_impl::make_continue): Likewise.\n\t(Program_impl::make_goto): Likewise.\n\t(Program_impl::make_return): Likewise.\n\t(Program_impl::make_handler): Likewise.\n\t(Program_impl::make_annotation): Likewise.\n\n\t* io.C: Rework pretty-printers.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.06.\n\n2004-05-05  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Program_impl::Program_impl): Initialize members\n\tclasstype, uniontype, enumtype and namespacetype.\n\n2004-05-03  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (missing_overrider): Don't make static.\n\t(print_namable): Make member of namespace ipr.\n\t(missing_overrider): Move from here to...\n\t* ipr.C (missing_overrider): ...there.\n\t(Parameter_impl::Parameter_impl): Rervet previous changes. \n\t(Var_impl::Var_impl): Likewise.\n\n2004-05-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* Mark for 0.05.\n\t\n2004-05-01  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (missing_overrider): New.\n\t(print_namable): Likewise.\n\t(Expression_printer::visit(const Node&)): Implement.  Default to\n\tmissing_overrider.\n\t(Expression_printer::visit(const Name&)): Likewise.\n\t(Expression_printer::visit(const Expr&)): Likewise.\n\t(Expression_printer::visit(const Statement&)): Define.\n\t(Expression_printer::visit(const Type&)): Implement in terms of\n\tprint_namable.\n\t(Expression_printer::visit(const Decl&)): Likewise.\n\t(Statement_printer::visit(const Node&)): Define. Default to\n\tmissing_overrider.\n\t(Statement_printer::visit(const Name&)): Likewise.\n\t(Statement_printer::visit(const Expr&)): Likewise.\n\t(Statement_printer::visit(const Type&)): Likewise.\n\t(Statement_printer::visit(const Statement&)): Likewise.\n\t(Statement_printer::visit(const Decl&)): Likewise.\n\t(Declaration_printer::visit(const Node&)): Likewise.\n\t(Declaration_printer::visit(const Name&)): Likewise.\n\t(Declaration_printer::visit(const Expr&)): Likewise.\n\t(Declaration_printer::visit(const Type&)): Likewise.\n\t(Declaration_printer::visit(const Statement&)): Likewise.\n\t(Sequence_printer::visit(const Node&)): Likewise.\n\t(Sequence_printer::visit(const Name&)): Likewise.\n\t(Sequence_printer::visit(const Expr&)): Likewise.\n\t(Sequence_printer::visit(const Type&)): Likewise.\n\t(Sequence_printer::visit(const Statement&)): Likewise.\n\t(Sequence_printer::visit(const Decl&)): Likewise.\n\n\t* ipr.C (Visitor::visit(const Node&)): Don't implement.\n\t(Visitor::visit(const Name&)): Likewise.\n\t(Visitor::visit(const Type&)): Likewise.\n\t(Visitor::visit(const Expr&)): Likewise.\n\t(Visitor::visit(const Statement&)): Likewise.\n\t(Visitor::visit(const Decl&)): Likewise.\n\n\t(Program_impl::Builtin<>::is_named): Rename to ...::has_name.\n\t(Visitor::visit(const Bit_xor&)): Tidy.\n\n\t(Fun_decl_impl): Adjust call to Decl_impl<>.\n\t(Var_impl): Likewise.\n\t\n2004-04-25  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* io.C (ipr::Expression::visit): Implement more expression\n\tpretty-printer routines. \n\t(::accept): Remove.\n\n2004-04-21  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Visitor::visit): Try to make room for reasonable defaults.\n\t* io.C (Declaration_printer): New.  Implement basic functionalities.\n\t(Expression_printer): Same.\n\n2004-04-08  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Program_impl::Program_impl): Initializer built-in type\n\tobjects. \n\n2004-03-23  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Mul_impl): Implement constructor taking two Expr.\n\t(Div_impl): Likewise.\n\t(Modulo_impl): Likewise.\n\t(Add_impl): Likewise.\n\t(Sub_impl): Likewise.\n\t(Shift_left_impl): Likewise.\n\t(Shift_right_impl): Likewise.\n\t(Less_impl): Likewise.\n\t(Greater_impl): Likewise.\n\t(Less_equal_impl): Likewise.\n\t(Greater_equal_impl): Likewise.\n\t(Equal_impl): Likewise.\n\t(Not_equal_impl): Likewise.\n\t(Bit_and_impl): Likewise.\n\t(Bit_xor_impl): Likewise.\n\t(Bit_or_impl): Likewise.\n\t(And_impl): Likewise.\n\t(Or_impl): Likewise.\n\t(Comma_impl): Likewise.\n\t(Assign_impl): Likewise.\n\t(Array_select_impl): Likewise.\n\t(Dot_select_impl): Likewise.\n\t(Arrow_select_impl): Likewise.\n\t(Scope_select_impl): Likewise.\n\n2004-03-22  Gabriel Dos Reis  <gdr@cs.tamu.edu>\n\n\t* ipr.C (Name_expr_impl): Implement explicit constructor.\n\t(Pre_increment_impl): Likewise.\n\t(Post_increment_impl): Likewise.\n\t(Pre_decrement_impl): Likewise.\n\t(Post_decrement_impl): Likewise.\n\t(Expr_typeid_impl): Likewise.\n\t(Type_typeid_impl): Likewise.\n\t(Expr_sizeof_impl): Likewise.\n\t(Type_sizeof_impl): Likewise.\n\t(Deref_impl): Likewise.\n\t(Address_impl): Likewise.\n\t(Unary_plus_impl): Likewise.\n\t(Negate_impl): Likewise.\n\t(Not_impl): Likewise.\n\t(Complement_impl): Likewise.\n\t(Delete_impl): Likewise.\n\t(Array_delete_impl): Likewise.\n\t(Dot_star_impl): Likewise.\n\t(Arrow_star_impl): Likewise.\n\n"
  },
  {
    "path": "src/builtin.def",
    "content": "//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copright and license notices.\n//\n\nBUILTIN_TYPE(Typename, u8\"typename\")\nBUILTIN_TYPE(Class, u8\"class\")\nBUILTIN_TYPE(Union, u8\"union\")\nBUILTIN_TYPE(Enum, u8\"enum\")\nBUILTIN_TYPE(Namespace, u8\"namespace\")\nBUILTIN_TYPE(Auto, u8\"auto\")\nBUILTIN_TYPE(Void, u8\"void\")\nBUILTIN_TYPE(Bool, u8\"bool\")\nBUILTIN_TYPE(Char, u8\"char\")\nBUILTIN_TYPE(Schar, u8\"signed char\")\nBUILTIN_TYPE(Uchar, u8\"unsigned char\")\nBUILTIN_TYPE(Wchar_t, u8\"wchar_t\")\nBUILTIN_TYPE(Char8_t, u8\"char8_t\")\nBUILTIN_TYPE(Char16_t, u8\"char16_t\")\nBUILTIN_TYPE(Char32_t, u8\"char32_t\")\nBUILTIN_TYPE(Short, u8\"short\")\nBUILTIN_TYPE(Ushort, u8\"unsigned short\")\nBUILTIN_TYPE(Int, u8\"int\")\nBUILTIN_TYPE(Uint, u8\"unsigned int\")\nBUILTIN_TYPE(Long, u8\"long\")\nBUILTIN_TYPE(Ulong, u8\"unsigned long\")\nBUILTIN_TYPE(Long_long, u8\"long long\")\nBUILTIN_TYPE(Ulong_long, u8\"unsigned long long\")\nBUILTIN_TYPE(Float, u8\"float\")\nBUILTIN_TYPE(Double, u8\"double\")\nBUILTIN_TYPE(Long_double, u8\"long double\")\nBUILTIN_TYPE(Ellipsis, u8\"...\")\n"
  },
  {
    "path": "src/cxx-ipr-io.cxx",
    "content": "//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module implementation unit for cxx.ipr.io.\n// Contains the XPR pretty-printer visitor hierarchies and\n// definitions of Printer member functions.\n\nmodule;\n\n#include <ipr/std-preamble>\n#include <assert.h>\n#include <cctype>\n#include <iostream>\n#include <typeinfo>\n\nmodule cxx.ipr.io;\n\nimport cxx.ipr.traversal;\n\nnamespace ipr {\n   // Format a sequence of items via a transformer.\n   template<typename F, typename T>\n   static Printer& sequenced(Printer& pp, const Sequence<T>& s, F f)\n   {\n      std::for_each(s.begin(), s.end(), f);\n      return pp;\n   }\n\n   // Format a comma-separated sequence of items\n   template<typename F, typename T>\n   static Printer& comma_separated(Printer& pp, const Sequence<T>& s)\n   {\n      auto worker = [&pp, first = true](auto& x) mutable {\n         if (not first)\n            pp << \", \";\n         pp << F(x);\n         first = false;\n      };\n      std::for_each(s.begin(), s.end(), worker);\n      return pp;\n   }\n\n   Printer& operator<<(Printer& p, Mapping_level x)\n   {\n      auto n = static_cast<std::size_t>(x);\n      p.channel() << n;\n      return p;\n   }\n\n   Printer& operator<<(Printer& p, Decl_position x)\n   {\n      auto n = static_cast<std::size_t>(x);\n      p.channel() << n;\n      return p;\n   }\n\n   struct pp_base : Constant_visitor<Missing_overrider> {\n      explicit pp_base(Printer& p) : pp(p) { }\n      using Visitor::visit;\n      void visit(const Type& t) override { visit(as<Expr>(t)); }\n      void visit(const Decl& d) override { visit(as<Expr>(d)); }\n\n   protected:\n      Printer& pp;\n   };\n\n   Printer::Printer(const Lexicon& lex, std::ostream& os)\n      : lexicon{lex}, \n        stream{os},\n        pad{Padding::None},\n        emit_newline{false},\n        pending_indentation{0}\n   { }\n\n   Printer&\n   Printer::operator<<(const char8_t* s)\n   {\n      write(s);\n      return *this;\n   }\n\n   void\n   Printer::write(util::word_view w)\n   {\n      // FIXME: workaround lack of standard support for insertion of\n      // sequence of utf-8 code units.\n      std::copy(w.begin(), w.end(), std::ostream_iterator<char>(this->stream));\n   }\n\n   template<typename T>\n   struct Token_helper {\n      T const value;\n      Token_helper(T t) : value(t) { }\n   };\n\n   template<typename T>\n   inline Token_helper<T>\n   token(T t)\n   {\n      return Token_helper<T>(t);\n   }\n\n   template<typename T>\n   inline Printer&\n   operator<<(Printer& printer, Token_helper<T> t)\n   {\n      return printer << t.value << Printer::Padding::None;\n   }\n\n   inline Printer&\n   insert_xtoken(Printer& printer, const char* s)\n   {\n      return printer << s << Printer::Padding::None;\n   }\n\n   struct needs_newline { };\n\n   inline Printer&\n   operator<<(Printer& printer, needs_newline)\n   {\n      printer.needs_newline(true);\n      return printer;\n   }\n\n   struct newline { };\n\n   Printer&\n   operator<<(Printer& printer, newline)\n   {\n      printer << token('\\n');\n      const int n = printer.indent();\n      for (int i = 0; i < n; ++i)\n         printer << ' ';\n      printer.needs_newline(false);\n      return printer;\n   }\n\n   // -- An Expr_list is mostly a expression-seq.  See print_sequence().\n   static inline Printer&\n   operator<<(Printer& pp, const Expr_list& l)\n   {\n      return comma_separated<xpr_expr>(pp, l.elements());\n   }\n\n\n   // -- Print out a sequence of type.\n   static inline Printer&\n   operator<<(Printer& pp, const Sequence<Type>& s)\n   {\n      return comma_separated<xpr_type>(pp, s);\n   }\n\n\n   // -- A Parameter_list is mostly a Parameter-seq.  See print_sequence().\n   static inline Printer&\n   operator<<(Printer& pp, const Parameter_list& l)\n   {\n      return comma_separated<xpr_decl>(pp, l.elements());\n   }\n\n   struct xpr_initializer {\n      const ipr::Expr& expr;\n      explicit xpr_initializer(const ipr::Expr& e) : expr(e) { }\n   };\n\n   static Printer& operator<<(Printer&, xpr_initializer);\n\n   struct indentation {\n      const int amount;\n      indentation(int n) : amount(n) { }\n   };\n\n   inline Printer&\n   operator<<(Printer& printer, indentation i)\n   {\n      printer.indent(i.amount);\n      return printer;\n   }\n\n   struct newline_and_indent {\n      const int indentation;\n      newline_and_indent(int n = 0) : indentation(n) { }\n   };\n\n   inline Printer&\n   operator<<(Printer& printer, newline_and_indent m)\n   {\n      printer << indentation(m.indentation) << newline();\n      return printer;\n   }\n\n   struct xpr_primary_expr {\n      const Expr& expr;\n      explicit xpr_primary_expr(const Expr& e) : expr(e) { }\n   };\n   static Printer& operator<<(Printer&, xpr_primary_expr);\n\n   struct xpr_cast_expr {\n   const Expr& expr;\n      xpr_cast_expr(const Expr& e) : expr(e) { }\n   };\n   static Printer& operator<<(Printer&, xpr_cast_expr);\n\n   struct xpr_assignment_expression {\n      const Expr& expr;\n      xpr_assignment_expression(const Expr& e) : expr(e) { }\n   };\n   static Printer& operator<<(Printer&, xpr_assignment_expression);\n\n\n   struct xpr_exception_spec {\n      const Expr& spec;\n   };\n   static Printer& operator<<(Printer&, xpr_exception_spec);\n\n   // Pretty-print identifiers.\n   struct xpr_identifier {\n      util::word_view txt;\n\n      explicit xpr_identifier(const ipr::String& s) : txt{s.characters()} { }\n\n      template<int N>\n      explicit xpr_identifier(const char8_t (&s)[N]) : txt{s} { }\n   };\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_identifier id)\n   {\n      if (printer.padding() == Printer::Padding::Before)\n         printer << ' ';\n      printer.write(id.txt);\n\n      return printer <<  Printer::Padding::Before;\n   }\n\n   Printer&\n   operator<<(Printer& pp, const Identifier& id)\n   {\n      return pp << xpr_identifier(id.string());\n   }\n\n   Printer& operator<<(Printer& pp, const Logogram& l)\n   {\n      return pp << xpr_identifier(l.what());\n   }\n\n   // ------------------------------\n   // -- Pretty printing of names --\n   // ------------------------------\n\n   // -------------------------------------------\n   // -- Pretty-printing of classic expression --\n   // -------------------------------------------\n\n   // -- name:\n   //       identifier\n   //       operator-function-id\n   //       conversion-function-id\n   //       type-id\n   //       scope-ref\n   //       template-id\n   //       ctor-name\n   //       dtor-name\n   //       template-parameter-canonical-name\n\n   namespace xpr {\n      struct Name : pp_base {\n         explicit Name(Printer& p) : pp_base(p) { }\n\n         void visit(const Identifier& id) final\n         {\n            pp << id;\n         }\n\n         // -- operator-function-id:\n         //         operator operator-name\n         //\n         //    operator-name: one of\n         //          +  ++  -=  -  --  -=  =  ==  !  !=  %   %=\n         //          *  *=  /  /=  ^  ^=  &  &&  &=  |  ||  |=\n         //          ~   ,  ()  []  <   <<  <<=   <=  >   >>\n         //          >>=  >=  new  new[]   delete   delete[]\n         void visit(const Operator& o) final\n         {\n            pp << xpr_identifier(u8\"operator\");\n\n            const ipr::String& s = o.opname();\n            if (not std::isalpha(*s.begin()))\n               {\n                  pp.write(s.characters());\n                  pp << Printer::Padding::None;\n               }\n            else\n               pp << xpr_identifier(s);\n         }\n\n         // -- conversion-function-id:\n         //        operator  type-id\n         // -- NOTE: This production is very different from ISO Standard\n         // --        production for conversion-function-id.\n         void visit(const Conversion& c) final\n         {\n            // For now only regular cast, later we'll add support for overloading\n            // dynamic_cast, reinterpret_cast, const_cast and static_cast\n            pp << xpr_identifier(u8\"operator\")\n               << xpr_identifier(u8\"cast\")\n               << token(\"<|\") << xpr_type(c.target()) << token(\"|>\");\n         }\n\n         // Suffix is a user defined literal, as in operator\"\"_km.\n         // We display it as operator \"_km\".\n         void visit(const Suffix& s) final\n         {\n             pp << xpr_identifier(u8\"operator\")\n                << token('\"')\n                << s.name()\n                << token('\"');\n         }\n\n         // A type-id is just the spelling of the type expression.\n         void visit(const Type_id& n) final\n         {\n            pp << xpr_type(n.type_expr());\n         }\n\n         // -- A Scope_ref corresponds to Standard C++ notion of\n         // -- qualified-id.  Here, it takes the production of\n         //    scope-ref:\n         //       @ name ( identifier )\n         void visit(const Scope_ref& n) final\n         {\n            pp << xpr_expr(n.scope()) << token(\"::\") << xpr_expr(n.member());\n         }\n\n         // -- template-id:\n         //       primary-expression < expression-seq >\n         void visit(const Template_id& n) final\n         {\n            n.template_name().accept(*this);\n            pp << token(\"<|\") << n.args() << token(\"|>\");\n         }\n\n         // -- ctor-name:\n         //        # ctor\n         void visit(const Ctor_name&) final\n         {\n            pp << xpr_identifier(u8\"#ctor\");\n         }\n\n         // -- dtor-name\n         //    # dtor\n         void visit(const Dtor_name&) final\n         {\n            pp << xpr_identifier(u8\"#dtor\");\n         }\n      };\n   }\n\n   struct xpr_name {\n      const Name& name;\n      explicit xpr_name(const Name& n) : name(n) { }\n      explicit xpr_name(const Decl& d) : name(d.name()) { }\n   };\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_name x)\n   {\n      xpr::Name pp { printer };\n      x.name.accept(pp);\n      return printer;\n   }\n\n   // -- primary-expression:\n   //      name\n   //      label\n   //      type\n   //      ( expression )\n   //      { expression-seq }\n\n   namespace xpr {\n      struct Primary_expr : xpr::Name {\n         Primary_expr(Printer& pp) : xpr::Name(pp) { }\n\n         void visit(const Label& l) final { xpr::Name::visit(l.name()); }\n         void visit(const Id_expr& id) final { pp << xpr_name{ id.name() }; }\n         void visit(const Literal&) final;\n         void visit(const Symbol& s) final { pp << xpr_name{ s.name() }; }\n         void visit(const As_type& t) final\n         {\n            if (denote_builtin_type(t))\n               pp << xpr_name(t.name());\n            else\n               pp << xpr_primary_expr(t.expr());\n         }\n         void visit(const Phantom&) final { } // nothing to print\n         void visit(const Enclosure& e) final\n         {\n            static constexpr const char* syntax[] = { \"\\0\\0\", \"()\", \"{}\", \"[]\", \"<>\" };\n            const auto delimiters = syntax[util::rep(e.delimiters())];\n            pp << token(delimiters[0]) << xpr_expr(e.expr()) << token(delimiters[1]);\n         }\n         void visit(const Expr& e) override\n         {\n            pp << token('(') << xpr_expr(e) << token(')');\n         }\n         void visit(const Decl& d) override { d.name().accept(*this); }\n      };\n\n      void\n      Primary_expr::visit(const ipr::Literal& l)\n      {\n         const String& s = l.string();\n         String::iterator cur = s.begin();\n         String::iterator end = s.end();\n         for (; cur != end; ++cur)\n            switch (*cur)\n               {\n               default:\n                  pp << static_cast<char>(*cur);\n                  break;\n\n               case '\\n':\n                  pp << \"\\\\n\";\n                  break;\n\n               case '\\r':\n                  pp << \"\\\\r\";\n                  break;\n\n               case '\\f':\n                  pp << \"\\\\f\";\n                  break;\n\n               case '\\t':\n                  pp << \"\\\\t\";\n                  break;\n\n               case '\\v':\n                  pp << \"\\\\v\";\n                  break;\n\n               case '\\b':\n                  pp << \"\\\\b\";\n                  break;\n\n               case '\\a':\n                  pp << \"\\\\a\";\n                  break;\n\n               case '\\\\':\n                  pp << \"\\\\\\\\\";\n                  break;\n\n//               case '\\'':\n//                  pp << \"\\\\'\";\n//                  break;\n\n               case '\\0':\n                  pp << \"\\\\0\";\n                  break;\n\n               case '\\1':\n               case '\\2':\n               case '\\3':\n                  pp << \"\\\\0\" << std::oct << static_cast<int>(*cur);\n                  break;\n               }\n      }\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_primary_expr x)\n   {\n\n      xpr::Primary_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   struct xpr_postfix_expr {\n      const Expr& expr;\n      explicit xpr_postfix_expr(const Expr& e) : expr(e) { }\n   };\n\n   static Printer& operator<<(Printer&, xpr_postfix_expr);\n\n   template<Category_code code, int N>\n   void\n   new_style_cast(Printer& pp, const Cast_expr<code>& e, const char8_t (&op)[N])\n   {\n      pp << xpr_identifier(op)\n         << token(\"<|\") << xpr_type(e.type()) << token(\"|>\")\n         << token('(') << xpr_expr(e.expr()) << token(')');\n   }\n\n   namespace xpr {\n      // -- postfix-expression:\n      //        primary-expression\n      struct Postfix_expr : xpr::Primary_expr {\n         Postfix_expr(Printer& pp) : xpr::Primary_expr(pp) { }\n\n         //        postfix-expression [ expression ]\n         void visit(const Array_ref& e) final\n         {\n            pp << xpr_postfix_expr(e.base())\n               << token('[') << xpr_expr(e.member()) << token(']');\n         }\n\n         //        postfix-expression . primary-expression\n         void visit(const Dot& e) final\n         {\n            pp << xpr_postfix_expr(e.base()) << token('.')\n               << xpr_primary_expr(e.member());\n         }\n\n         //        postfix-expression -> primary-expression\n         void visit(const Arrow& e) final\n         {\n            pp << xpr_postfix_expr(e.base()) << token(\"->\")\n               << xpr_primary_expr(e.member());\n         }\n\n         //        postfix-expression ( expression-list )\n         void visit(const Call& e) final\n         {\n            pp << xpr_postfix_expr(e.function())\n               << token('(') << e.args() << token(')');\n         }\n\n         void visit(const Construction& e) final\n         {\n            pp << xpr_type(e.type())\n               << xpr_primary_expr(e.arguments());\n         }\n\n         //        postfix-expression --\n         void visit(const Post_decrement& e) final\n         {\n            pp << xpr_postfix_expr(e.operand()) << token(\"--\");\n         }\n\n         //        postfix-expression ++\n         void visit(const Post_increment& e) final\n         {\n            pp << xpr_postfix_expr(e.operand()) << token(\"++\");\n         }\n\n         //        dynamic_cast < type > ( expression )\n         void visit(const Dynamic_cast& e) final\n         {\n            new_style_cast(pp, e, u8\"dynamic_cast\");\n         }\n\n         //        static_cast < type > ( expression )\n         void visit(const Static_cast& e) final\n         {\n            new_style_cast(pp, e, u8\"static_cast\");\n         }\n\n         //        const_cast < type > ( expression )\n         void visit(const Const_cast& e) final\n         {\n            new_style_cast(pp, e, u8\"const_cast\");\n         }\n\n         //        reinterpret_cast < type > ( expression )\n         void visit(const Reinterpret_cast& e) final\n         {\n            new_style_cast(pp, e, u8\"reinterpret_cast\");\n         }\n\n         //        typeid ( expression )\n         void visit(const Typeid& e) final\n         {\n            pp << xpr_identifier(u8\"typeid\")\n               << token('(') << xpr_expr(e.operand()) << token(')');\n         }\n\n         //       noexcept '(' expression ')'\n         void visit(const Noexcept& e) final\n         {\n            pp << xpr_identifier(u8\"noexcept\")\n               << token('(') << xpr_expr(e.operand()) << token(')');\n         }\n      };\n   }\n\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_postfix_expr x)\n   {\n      xpr::Postfix_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // -- unary-expression:\n   //         -- cast-expression\n   //         ++ cast-expression\n   //         & cast-expression\n   //         ~ cast-expression\n\n   template<class T>\n   inline void\n   unary_operation(Printer& pp, const Unary<T>& e, const char* op)\n   {\n      pp << token(op) << xpr_cast_expr(e.operand());\n   }\n\n   namespace xpr {\n      struct Unary_expr : xpr::Postfix_expr {\n         Unary_expr(Printer& pp) : xpr::Postfix_expr(pp) { }\n\n         void visit(const Pre_decrement& e) final { unary_operation(pp, e, \"--\"); }\n\n         void visit(const Pre_increment& e) final { unary_operation(pp, e, \"++\"); }\n\n         void visit(const Address& e) final { unary_operation(pp, e, \"&\"); }\n\n         void visit(const Complement& e) final { unary_operation(pp, e, \"~\"); }\n\n         void visit(const Deref& e) final { unary_operation(pp, e, \"*\"); }\n\n         void visit(const Unary_minus& e) final { unary_operation(pp, e, \"-\"); }\n\n         void visit(const Not& e) final { unary_operation(pp, e, \"!\"); }\n\n         void visit(const Sizeof& e) final\n         {\n            pp << xpr_identifier(u8\"sizeof\")\n               << token(' ') << xpr_expr(e.operand());\n         }\n\n         void visit(const Args_cardinality& e) final\n         {\n            pp << xpr_identifier(u8\"sizeof\") << token(\"...\")\n               << token('(') << xpr_expr(e.operand()) << token(')');\n         }\n\n         void visit(const Unary_plus& e) final\n         {\n            pp << token('+') << xpr_expr(e.operand());\n         }\n\n         void visit(const New& e) final\n         {\n            pp << xpr_identifier(u8\"new\") << token(' ');\n            if (auto p = e.placement())\n               pp << token('(') << p.get() << token(\") \");\n            // Note: The following does not exactly conform to the ISO C++ grammar (because of ambiguity).\n            pp << xpr_expr(e.initializer());\n         }\n\n         void visit(const Delete& e) final\n         {\n            pp << xpr_identifier(u8\"delete\")\n               << token(' ')\n               << xpr_cast_expr(e.storage());\n         }\n\n         void visit(const Array_delete& e) final\n         {\n            pp << xpr_identifier(u8\"delete[]\")\n               << token(' ')\n               << xpr_cast_expr(e.storage());\n         }\n      };\n   }\n\n   static Printer& operator<<(Printer&, xpr_cast_expr);\n\n   namespace xpr {\n      struct Cast_expr : xpr::Unary_expr {\n         Cast_expr(Printer& p) : xpr::Unary_expr(p) { }\n\n         // -- cast-expression\n         //       unary-expression\n         //       \"(\" type \")\" cast-expression\n         void visit(const Cast& e) final\n         {\n            new_style_cast(pp, e, u8\"cast\");\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_cast_expr x)\n   {\n      xpr::Cast_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // -- pm-expression:\n   //      cast-expression\n   //      pm-expression \".*\" cast-expression\n   //      pm-expression \"->*\" cast-expression\n\n   struct xpr_pm_expr {\n      const Expr& expr;\n      explicit xpr_pm_expr(const Expr& e) : expr(e) { }\n   };\n\n   static Printer& operator<<(Printer&, xpr_pm_expr);\n\n   template<Category_code code>\n   static void\n   offset_with_pm(Printer& pp, const Member_selection<code>& e, const char* op)\n   {\n      pp << xpr_pm_expr(e.base())\n         << op\n         << xpr_cast_expr(e.member());\n   }\n\n   namespace xpr {\n      struct Pm_expr : xpr::Cast_expr {\n         Pm_expr(Printer& p) : xpr::Cast_expr(p) { }\n\n         void visit(const Dot_star& e) final { offset_with_pm(pp, e, \".*\"); }\n         void visit(const Arrow_star& e) final { offset_with_pm(pp, e, \"->*\"); }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_pm_expr x)\n   {\n      xpr::Pm_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // -- Print a binary expression.  Instantiated by the relevant\n   // -- grammar production, with precedence built-in.\n   template<class Left, class Right, class E, class Op>\n   inline void\n   binary_expression(Printer& pp, const E& e, Op op)\n   {\n      pp << Left(e.first())\n         << token(' ') << op << token(' ')\n         << Right(e.second());\n   }\n\n   // -- multiplicative-expression:\n   //          pm-expression\n   //          multiplicative-expression * pm-expression\n   //          multiplicative-expression / pm-expression\n   //          multiplicative-expression % pm-expression\n\n   struct xpr_mul_expr {\n      const Expr& expr;\n      explicit xpr_mul_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Mul_expr : xpr::Pm_expr {\n         Mul_expr(Printer& p) : xpr::Pm_expr(p) { }\n\n         void visit(const Mul& e) final\n         {\n            binary_expression<xpr_mul_expr, xpr_pm_expr>(pp, e, '*');\n         }\n         void visit(const Div& e) final\n         {\n            binary_expression<xpr_mul_expr, xpr_pm_expr>(pp, e, '/');\n         }\n         void visit(const Modulo& e) final\n         {\n            binary_expression<xpr_mul_expr, xpr_pm_expr>(pp, e, '%');\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_mul_expr x)\n   {\n      xpr::Mul_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // -- additive-expression:\n   //         multiplicative-expression\n   //         additive-expression + multiplicative-expression\n   //         additive-expression - multiplicative-expression\n\n   struct xpr_add_expr {\n      const Expr& expr;\n      explicit xpr_add_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Add_expr : xpr::Mul_expr {\n         Add_expr(Printer& p) : xpr::Mul_expr(p) { }\n\n         void visit(const Plus& e) final\n         {\n            binary_expression<xpr_add_expr, xpr_mul_expr>(pp, e, '+');\n         }\n\n         void visit(const Minus& e) final\n         {\n            binary_expression<xpr_add_expr, xpr_mul_expr>(pp, e, '-');\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_add_expr x)\n   {\n      xpr::Add_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- shift-expression:\n   //         additive-expression\n   //         shift-expression << additive-expression\n   //         shift-expression >> additive-expression\n\n   struct xpr_shift_expr {\n      const Expr& expr;\n      explicit xpr_shift_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Shift_expr : xpr::Add_expr {\n         Shift_expr(Printer& p) : xpr::Add_expr(p) { }\n\n         void visit(const Lshift& e) final\n         {\n            binary_expression<xpr_shift_expr, xpr_add_expr>(pp, e, \"<<\");\n         }\n\n         void visit(const Rshift& e) final\n         {\n            binary_expression<xpr_shift_expr, xpr_add_expr>(pp, e, \">>\");\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_shift_expr x)\n   {\n      xpr::Shift_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- relational-expression\n   //        shift-expression\n   //        relational-expression < shift-expression\n   //        relational-expression > shift-expression\n   //        relational-expression <= shift-expression\n   //        relational-expression >= shift-expression\n\n   struct xpr_rel_expr {\n      const Expr& expr;\n      explicit xpr_rel_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Rel_expr : xpr::Shift_expr {\n         Rel_expr(Printer& p) : xpr::Shift_expr(p) { }\n\n         void visit(const Less& e) final\n         {\n            binary_expression<xpr_rel_expr, xpr_shift_expr>(pp, e, '<');\n         }\n\n         void visit(const Less_equal& e) final\n         {\n            binary_expression<xpr_rel_expr, xpr_shift_expr>(pp, e, \"<=\");\n         }\n\n         void visit(const Greater& e) final\n         {\n            binary_expression<xpr_rel_expr, xpr_shift_expr>(pp, e, '>');\n         }\n\n         void visit(const Greater_equal& e) final\n         {\n            binary_expression<xpr_rel_expr, xpr_shift_expr>(pp, e, \">=\");\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_rel_expr x)\n   {\n      xpr::Rel_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // -- equality-expression\n   //          relational-expression\n   //          equality-expression == relational-expression\n   //          equality-expression != relational-expression\n\n   struct xpr_eq_expr {\n      const Expr& expr;\n      explicit xpr_eq_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Eq_expr : xpr::Rel_expr {\n         Eq_expr(Printer& p) : xpr::Rel_expr(p) { }\n\n         void visit(const Equal& e) final\n         {\n            binary_expression<xpr_eq_expr, xpr_rel_expr>(pp, e, \"==\");\n         }\n\n         void visit(const Not_equal& e) final\n         {\n            binary_expression<xpr_eq_expr, xpr_rel_expr>(pp, e, \"!=\");\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_eq_expr x)\n   {\n      xpr::Eq_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- and-expression\n   //          equality-expression\n   //          and-expression & equality-expression\n\n   struct xpr_and_expr {\n      const Expr& expr;\n      explicit xpr_and_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct And_expr : xpr::Eq_expr {\n         And_expr(Printer& p) : xpr::Eq_expr(p) { }\n\n         void visit(const Bitand& e) final\n         {\n            binary_expression<xpr_and_expr, xpr_eq_expr>(pp, e, '&');\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_and_expr x)\n   {\n      xpr::And_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // -- exclusive-or-expression\n   //          and-expression\n   //          exclusive-or-expression ^ and-expression\n\n   struct xpr_xor_expr {\n      const Expr& expr;\n      explicit xpr_xor_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Xor_expr : xpr::And_expr {\n         Xor_expr(Printer& p) : xpr::And_expr(p) { }\n\n         void visit(const Bitxor& e) final\n         {\n            binary_expression<xpr_xor_expr, xpr_and_expr>(pp, e, '^');\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_xor_expr x)\n   {\n      xpr::Xor_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- inclusive-or-expression\n   //         exclusive-or-exclusive\n   //         inclusive-or-expression | exclusive-or-expression\n\n   struct xpr_ior_expr {\n      const Expr& expr;\n      explicit xpr_ior_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Ior_expr : xpr::Xor_expr {\n         Ior_expr(Printer& p) : xpr::Xor_expr(p) { }\n\n         void visit(const Bitor& e) final\n         {\n            binary_expression<xpr_ior_expr, xpr_xor_expr>(pp, e, '|');\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_ior_expr x)\n   {\n      xpr::Ior_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- logical-and-expression\n   //           inclusive-or-expression\n   //           logical-and-expression && inclusive-or-expression\n\n   struct xpr_land_expr {\n      const Expr& expr;\n      explicit xpr_land_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Land_expr : xpr::Ior_expr {\n         Land_expr(Printer& p) : xpr::Ior_expr(p) { }\n\n         void visit(const And& e) final\n         {\n            binary_expression<xpr_land_expr, xpr_ior_expr>(pp, e, \"&&\");\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_land_expr x)\n   {\n      xpr::Land_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- logical-or-expression\n   //         logical-and-expression\n   //         logical-or-expression || logical-and-expression\n\n   struct xpr_lor_expr {\n      const Expr& expr;\n      explicit xpr_lor_expr(const Expr& e) : expr(e) { }\n   };\n\n   namespace xpr {\n      struct Lor_expr : xpr::Land_expr {\n         Lor_expr(Printer& p) : xpr::Land_expr(p) { }\n\n         void visit(const Or& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_land_expr>(pp, e, \"||\");\n         }\n      };\n   }\n\n   static inline Printer&\n   operator<<(Printer& printer, xpr_lor_expr x)\n   {\n      xpr::Lor_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n\n   // -- conditional-expression\n   //          logical-or-expression\n   //          logical-or-expression ? expression : assignment-expression\n\n   namespace xpr {\n      struct Cond_expr : xpr::Lor_expr {\n         Cond_expr(Printer& p) : xpr::Lor_expr(p) { }\n\n         void visit(const Conditional& e) final\n         {\n            pp << xpr_lor_expr(e.condition())\n               << token(\" ? \")\n               << xpr_expr(e.then_expr())\n               << token(\" : \")\n               << xpr_assignment_expression(e.else_expr());\n         }\n      };\n   }\n\n   struct xpr_mapping_expression {\n      const Mapping& mapping;\n      explicit xpr_mapping_expression(const Mapping& m) : mapping(m) { }\n   };\n\n   // >>>> Yuriy Solodkyy: 2006/05/31\n   // MSVC 7.1 has problem with calling same function from its local class.\n   // Therefore this class was moved from being a local class of subsequent\n   // function to being just a regular class, which that function uses.\n   struct xpr_mapping_expression_visitor : pp_base {\n      const ipr::Mapping& map;\n      xpr_mapping_expression_visitor(Printer& p, const ipr::Mapping& m) : pp_base(p), map(m) { }\n\n      void visit(const Function& t) final\n      {\n         pp << token('(');\n         pp << map.parameters();\n         pp << token(')');\n         pp << xpr_exception_spec{ t.throws() };\n\n         pp << xpr_initializer(map.result());\n      }\n\n      void visit(const Forall&) final\n      {\n         pp << token('<');\n         pp << map.parameters();\n         pp << token('>');\n         pp << xpr_initializer(map.result());\n      }\n   };\n   // <<<< Yuriy Solodkyy: 2006/05/31\n\n   Printer&\n   operator<<(Printer& pp, xpr_mapping_expression e)\n   {\n      xpr_mapping_expression_visitor impl(pp, e.mapping);\n      e.mapping.type().accept(impl);\n      return pp;\n   }\n\n   // -- assignment-expression:\n   //         conditional-expression\n   //         logical-or-expression assignment-operator assignment-expression\n   //         throw expression\n   //\n   //    assignment-operator: one of\n   //         =   *=  /=  %=  +=  -=  >>=  <<=  &=  ^=  |=\n\n   namespace xpr {\n      struct Assignment_expr : xpr::Cond_expr {\n         Assignment_expr(Printer& p) : xpr::Cond_expr(p) { }\n\n         void visit(const Assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, '=');\n         }\n         void visit(const Plus_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"+=\");\n         }\n         void visit(const Bitand_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"&=\");\n         }\n         void visit(const Bitor_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"|=\");\n         }\n         void visit(const Bitxor_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"^=\");\n         }\n         void visit(const Div_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"/=\");\n         }\n         void visit(const Modulo_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"%=\");\n         }\n         void visit(const Mul_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"*=\");\n         }\n         void visit(const Lshift_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"<<=\");\n         }\n         void visit(const Rshift_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \">>=\");\n         }\n         void visit(const Minus_assign& e) final\n         {\n            binary_expression<xpr_lor_expr, xpr_assignment_expression>\n               (pp, e, \"-=\");\n         }\n         void visit(const Throw& e) final\n         {\n            pp << xpr_identifier(u8\"throw\") << token(' ')\n               << xpr_assignment_expression(e.operand());\n         }\n\n         void visit(const Mapping& m) final\n         {\n            pp << xpr_mapping_expression (m);\n         }\n      };\n   }\n\n   Printer&\n   operator<<(Printer& printer, xpr_assignment_expression x)\n   {\n      xpr::Assignment_expr pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   // >>>> Yuriy Solodkyy: 2006/05/31\n   // MSVC 7.1 has problem with calling same function from its local class.\n   // Therefore this class was moved from being a local class of subsequent\n   // function to being just a regular class, which that function uses.\n   struct xpr_expr_visitor : pp_base {\n      xpr_expr_visitor(Printer& p) : pp_base(p) { }\n\n      void visit(const Comma& e) final\n      {\n         pp << xpr_expr(e.first()) << token(\"@, \")\n            << xpr_assignment_expression(e.second());\n      }\n\n      void visit(const Scope& s) final\n      {\n         sequenced(pp, s.elements(), [&pp = pp](auto& d) { pp << xpr_decl(d, true) << newline(); });\n      }\n\n      void visit(const Expr_list& e) final { pp << e; }\n\n      void visit(const Member_init& e) final\n      {\n         pp << xpr_expr(e.member())\n            << token('(') << xpr_expr(e.initializer()) << token(')');\n      }\n\n      void visit(const Type& t) final { pp << xpr_type(t); }\n      void visit(const Expr& e) final { pp << xpr_assignment_expression(e); }\n      void visit(const Stmt& s) final { pp << xpr_stmt(s); }\n      void visit(const Decl& d) final\n      {\n         // A declaration used as an expression must have appeared\n         // as a primary-expression.\n         pp << xpr_primary_expr(d);\n      }\n   };\n   // <<<< Yuriy Solodkyy: 2006/05/31\n\n   Printer&\n   operator<<(Printer& printer, xpr_expr x)\n   {\n      xpr_expr_visitor impl(printer);\n      x.expr.accept(impl);\n      return printer;\n   }\n\n   //  -- Types --\n\n   static Printer&\n   operator<<(Printer& printer, xpr_exception_spec x)\n   {\n      struct Visitor : pp_base {\n         Visitor(Printer& p) : pp_base{ p } { }\n\n         void visit(const Type& t) final\n         {\n            pp << xpr_identifier(u8\"throw\")\n               << token('(') << xpr_type(t) << token(')');\n         }\n\n         void visit(const Expr& e) final\n         {\n            pp << xpr_identifier(u8\"noexcept\")\n               << token('(') << xpr_expr(e) << token(')');\n         }\n      };\n\n      printer << token(' ');\n      Visitor v { printer };\n      x.spec.accept(v);\n      return printer;\n   }\n\n   struct xpr_base_classes {\n      const ipr::Sequence<ipr::Base_type>& bases;\n      explicit xpr_base_classes(const ipr::Sequence<ipr::Base_type>& b)\n            : bases(b) { }\n   };\n\n   static Printer&\n   operator<<(Printer& pp, xpr_base_classes x)\n   {\n      const Sequence<Base_type>& bases = x.bases;\n      if (not bases.empty()) {\n         pp << token('(');\n         comma_separated<xpr_decl>(pp, bases);\n         pp << token(')');\n      }\n      return pp;\n   }\n\n   Printer& Printer::operator<<(Qualifiers quals)\n   {\n      for (auto q : lexicon.decompose(quals))\n         *this << q.logogram();\n      return *this;\n   }\n\n   struct xpr_type_expr {\n      const Expr& type;\n      explicit xpr_type_expr(const Expr& t) : type(t) { }\n   };\n\n   template<typename T>\n   static Printer& operator<<(Printer& pp, const ipr::Udt<T>& t)\n   {\n      return pp << token(' ')\n            << token('{')\n            << newline_and_indent(3)\n            << xpr_expr(t.scope())\n            << newline_and_indent(-3)\n            << token('}')\n            << needs_newline();\n   }\n\n   // >>>> Yuriy Solodkyy: 2006/05/31\n   // MSVC 7.1 has problem with calling same function from its local class.\n   // Therefore this class was moved from being a local class of subsequent\n   // function to being just a regular class, which that function uses.\n   static Printer&\n   operator<<(Printer& printer, xpr_type_expr x);\n\n   struct xpr_type_expr_visitor : pp_base {\n      xpr_type_expr_visitor(Printer& p) : pp_base(p) { }\n\n      void visit(const Array& a) final\n      {\n         pp << token('[') << xpr_expr(a.bound()) << token(']')\n            << xpr_type(a.element_type());\n      }\n\n      void visit(const As_type& t) final\n      {\n         pp << xpr_expr(t.expr());\n      }\n\n      void visit(const Class& c) final\n      {\n         pp << xpr_base_classes(c.bases())\n            << token(' ')\n            << token('{')\n            << newline_and_indent(3)\n            << xpr_expr(c.scope())\n            << newline_and_indent(-3)\n            << token('}')\n            << needs_newline();\n      }\n\n      void visit(const Decltype& t) final\n      {\n         pp << xpr_identifier(u8\"decltype\") << token(' ')\n            << token('(') << xpr_expr(t.expr()) << token(')');\n      }\n\n      void visit(const Function& f) final\n      {\n         pp << token('(') << f.source().operand() << token(')')\n            << xpr_exception_spec{ f.throws() }\n            << xpr_type(f.target());\n      }\n\n      void visit(const Pointer& t) final\n      {\n         pp << token('*') << xpr_type(t.points_to());\n      }\n\n      void visit(const Ptr_to_member& t) final\n      {\n         pp << token('*')\n            << token('[')\n            << xpr_type(t.containing_type())\n            << token(']') << token(',')\n            << xpr_type(t.member_type());\n      }\n\n      void visit(const Qualified& t) final\n      {\n         pp << t.qualifiers()\n            << xpr_type(t.main_variant());\n      }\n\n      void visit(const Reference& t) final\n      {\n         pp << token('&') << xpr_type(t.refers_to());\n      }\n\n      void visit(const Rvalue_reference& t) final\n      {\n         pp << token('&') << token('&') << xpr_type(t.refers_to());\n      }\n\n      void visit(const Forall& t) final\n      {\n         pp << token('<') << t.source().operand() << token('>')\n            << token(' ')\n            << xpr_type_expr(t.target());\n      }\n\n      void visit(const Union& t) final { pp << t; }\n      void visit(const Enum& t) final { pp << t; }\n      void visit(const Namespace& t) final { pp << t; }\n   };\n   // <<<< Yuriy Solodkyy: 2006/05/31\n\n   static Printer&\n   operator<<(Printer& printer, xpr_type_expr x)\n   {\n      xpr_type_expr_visitor impl(printer);\n      x.type.accept(impl);\n      return printer;\n   }\n\n   // >>>> Yuriy Solodkyy: 2006/05/31\n   // MSVC 7.1 has problem with calling same function from its local class.\n   // Therefore this class was moved from being a local class of subsequent\n   // function to being just a regular class, which that function uses.\n   struct xpr_type_visitor : pp_base {\n      xpr_type_visitor(Printer& p) : pp_base(p) { }\n\n      void visit(const As_type& t) final\n      {\n         if (denote_builtin_type(t))\n            pp << xpr_name(t.name());\n         else\n            pp << xpr_expr(t.expr());\n      }\n\n      void visit(const Array& a) final\n      { pp << xpr_type_expr(a); }\n\n      void visit(const Function& f) final\n      { pp << xpr_type_expr(f); }\n\n      void visit(const Pointer& t) final\n      { pp << xpr_type_expr(t); }\n\n      void visit(const Ptr_to_member& t) final\n      { pp << xpr_type_expr(t); }\n\n      void visit(const Qualified& t) final\n      { pp << xpr_type_expr(t); }\n\n      void visit(const Reference& t) final\n      { pp << xpr_type_expr(t); }\n\n      void visit(const Rvalue_reference& t) final\n      { pp << xpr_type_expr(t); }\n\n      void visit(const Forall& t) final\n      { pp << xpr_type_expr(t); }\n\n      void visit(const Type& t) final\n      {\n         // FIXME: Check.\n         pp << xpr_name(t.name());\n      }\n\n      void visit(const Product& t) final\n      {\n         pp << t.operand();\n      }\n\n      void visit(const Sum& t) final\n      {\n         pp << t.operand();\n      }\n   };\n   // <<<< Yuriy Solodkyy: 2006/05/31\n\n   Printer&\n   operator<<(Printer& printer, xpr_type x)\n   {\n      xpr_type_visitor impl(printer);\n      x.type.accept(impl);\n      return printer;\n   }\n\n   // Initializer expressions.\n\n   static Printer&\n   operator<<(Printer& printer, xpr_initializer x)\n   {\n      struct V : xpr::Assignment_expr {\n         V(Printer& p) : xpr::Assignment_expr(p) { }\n\n         void visit(const ipr::Type& t) final\n         {\n            pp << xpr_type_expr(t);\n         }\n\n         void visit(const ipr::Expr& e) final\n         {\n            pp << xpr_expr(e);\n         }\n\n         void visit(const ipr::Stmt& e) final\n         {\n            pp << xpr_stmt(e);\n         }\n\n         void visit(const ipr::Decl& e) final\n         {\n            pp << xpr_decl(e);\n         }\n      };\n      V pp(printer);\n      x.expr.accept(pp);\n      return printer;\n   }\n\n   //  -- Statements --\n   namespace xpr {\n      struct Stmt : xpr::Assignment_expr {\n         Stmt(Printer& p) : xpr::Assignment_expr(p) { }\n\n         void visit(const Expr_stmt& e) final\n         {\n            pp << xpr_expr(e.expr())\n               << token(';')\n               << needs_newline();\n         }\n\n         void visit(const Labeled_stmt& s) final\n         {\n            if (pp.needs_newline())\n               pp << newline_and_indent(-3);\n            else\n               pp << indentation(-3);\n\n            pp << xpr_identifier(u8\"label\")\n               << token(' ')\n               << xpr_expr(s.label())\n               << token(':')\n               << indentation(3) << needs_newline()\n               << xpr_stmt(s.stmt())\n               << needs_newline();\n         }\n\n         void visit(const Block& s) final\n         {\n            pp << token('{')\n               << needs_newline() << indentation(3);\n            sequenced(pp, s.body(), [&pp = pp](auto& e) { pp << xpr_stmt(e) << needs_newline(); });\n            pp << newline_and_indent(-3)\n               << token('}')\n               << needs_newline();\n            sequenced(pp, s.handlers(), [&pp = pp](auto& h) { pp << xpr_stmt(h, false); });\n         }\n\n         void visit(const Ctor_body& b) final\n         {\n            const Expr_list& inits = b.inits();\n            if (inits.size() > 0)\n               pp << token(\" : \")\n                  << inits << needs_newline();\n\n            pp << needs_newline() << xpr_stmt(b.block());\n         }\n\n         void visit(const If& s) final\n         {\n            pp << xpr_identifier(u8\"if\")\n               << token(' ')\n               << token('(') << xpr_expr(s.condition()) << token(')')\n               << newline_and_indent(3)\n               << xpr_stmt(s.consequence());\n            if (auto alt = s.alternative()) {\n               pp << newline_and_indent(-3)\n                  << xpr_identifier(u8\"else\")\n                  << newline_and_indent(3)\n                  << xpr_stmt(alt.get());\n            }\n            pp << indentation(-3) << needs_newline();\n         }\n\n         void visit(const Return& s) final\n         {\n            pp << xpr_identifier(u8\"return\")\n               << token(' ')\n               << xpr_expr(s.value())\n               << token(';')\n               << needs_newline();\n         }\n\n         void visit(const Switch& s) final\n         {\n            pp << xpr_identifier(u8\"switch\")\n               << token(' ')\n               << token('(') << xpr_expr(s.condition()) << token(')')\n               << newline_and_indent(3)\n               << xpr_stmt(s.body())\n               << newline_and_indent(-3);\n         }\n\n         void visit(const While& s) final\n         {\n            pp << xpr_identifier(u8\"while\")\n               << token(' ')\n               << token('(') << xpr_expr(s.condition()) << token(')')\n               << newline_and_indent(3)\n               << xpr_stmt(s.body())\n               << needs_newline() << indentation(-3);\n         }\n\n         void visit(const Do& s) final\n         {\n            pp << xpr_identifier(u8\"do\")\n               << newline_and_indent(3)\n               << xpr_stmt(s.body())\n               << newline_and_indent(-3)\n               << xpr_identifier(u8\"while\")\n               << token(' ')\n               << token('(') << xpr_expr(s.condition()) << token(')')\n               << token(';') << needs_newline();\n         }\n\n         void visit(const For& s) final\n         {\n            pp << xpr_identifier(u8\"for\")\n               << token(\" (\")\n               << xpr_expr(s.initializer())\n               << token(\"; \")\n               << xpr_expr(s.condition())\n               << token(\"; \")\n               << xpr_expr(s.increment())\n               << token(')')\n               << newline_and_indent(3)\n               << xpr_stmt(s.body())\n               << indentation(-3) << needs_newline();\n         }\n\n         void visit(const For_in& s) final\n         {\n            pp << xpr_identifier(u8\"for\")\n               << token(\" (\")\n               << xpr_decl(s.variable())\n               << token(\" <- \")\n               << xpr_expr(s.sequence())\n               << token(')')\n               << newline_and_indent(3)\n               << xpr_stmt(s.body())\n               << indentation(-3) << needs_newline();\n         }\n\n         void visit(const Break&) final\n         {\n            pp << xpr_identifier(u8\"break\")\n               << token(';')\n               << needs_newline();\n         }\n\n         void visit(const Continue&) final\n         {\n            pp << xpr_identifier(u8\"continue\")\n               << token(';')\n               << needs_newline();\n         }\n\n         void visit(const Goto& s) final\n         {\n            pp << xpr_identifier(u8\"goto\")\n               << token(' ')\n               << xpr_expr(s.target())\n               << token(';')\n               << needs_newline();\n         }\n\n         void visit(const Handler& s) final\n         {\n            pp << xpr_identifier(u8\"catch\")\n               << token(' ')\n               << token('(')\n               << xpr_decl(s.exception())\n               << token(')')\n               << newline_and_indent(3)\n               << xpr_stmt(s.body())\n               << newline_and_indent(-3);\n         }\n\n         void visit(const Decl& d) override\n         {\n            // These are declaration statements, so they end up\n            // with a semicolon.\n            pp << xpr_decl(d, true);\n         }\n      };\n\n      struct Location_printer\n      {\n         Printer* pp;\n\n         // Location is only present on nodes derived from ipr::Stmt.\n         // Nothing to print for other types of nodes at the moment.\n         void operator()(const ipr::Node&) {}\n\n         void operator()(const ipr::Stmt& stmt)\n         {\n            auto& locus = stmt.source_location();\n            if (locus.file != File_index{})\n            {\n               *pp << token(\"F\") << util::rep(locus.file) << token(':')\n                   << util::rep(locus.line);\n               if (locus.column != Column_number{})\n                  *pp << token(':') << util::rep(locus.column);\n               *pp << token(' ');\n            }\n         }\n         static void print(Printer& printer, const ipr::Node& node)\n         {\n            if (printer.print_locations)\n            {\n               Constant_visitor<xpr::Location_printer> location_printer;\n               location_printer.pp = &printer;\n               node.accept(location_printer);\n            }\n         }\n      };\n   }\n\n   Printer&\n   operator<<(Printer& printer, xpr_stmt x)\n   {\n      if(printer.needs_newline())\n         printer << newline_and_indent();\n      \n      xpr::Location_printer::print(printer, x.stmt);\n      xpr::Stmt impl(printer);\n      x.stmt.accept(impl);\n      return printer;\n   }\n\n\n   Printer& Printer::operator<<(Specifiers spec)\n   {\n      for (auto s : lexicon.decompose(spec))\n         *this << s.logogram();\n\n      return *this;\n   }\n\n\n   // -- Declarations --\n\n   namespace xpr {\n      struct Decl : xpr::Stmt {\n         Decl(Printer& p) : xpr::Stmt(p) { }\n\n            void visit(const ipr::Alias& d) final\n            {\n               pp << ipr::xpr_name(d)\n                  << token(\" : \")\n                  << d.specifiers()\n                  << token(\" typedef \")\n                  << xpr_expr(d.initializer().get());\n            }\n\n         void visit(const ipr::Decl& d) override\n         {\n            pp << ipr::xpr_name(d)\n               << token(\" : \")\n               << d.specifiers()\n               << xpr_type(d.type());\n\n            if (auto init = d.initializer())\n               {\n                  pp << token('(')\n                     << xpr_expr(init.get())\n                     << token(')');\n               }\n         }\n\n         void visit(const Typedecl& d) final\n         {\n            pp << ipr::xpr_name(d)\n               << token(\" : \")\n               << xpr_type(d.type());\n\n            if (auto init = d.initializer())\n               pp << xpr_type_expr(init.get());\n         }\n\n         void visit(const Enumerator& e) final\n         {\n            e.name().accept(*this);\n            if (auto init = e.initializer())\n               pp << token('(') << xpr_expr(init.get()) << token(')');\n         }\n\n         void visit(const Bitfield& b) final\n         {\n            b.name().accept(*this);\n            pp << token(\" : #\")\n               << xpr_identifier(u8\"bitfield\")\n               << token('(') << xpr_expr(b.precision()) << token(')')\n               << xpr_type(b.type());\n         }\n\n         void visit(const Base_type& b) final\n         {\n            pp << b.specifiers() << xpr_type(b.type());\n         }\n\n         void visit(const Fundecl& f) final\n         {\n            pp << ipr::xpr_name(f)\n               << token(\" : \")\n               << f.specifiers() << ' '\n               << token('(') << f.parameters() << token(')');\n\n            const Function* pfn = util::view<Function>(f.type());\n            if (pfn)\n                pp << xpr_type(pfn->target()); // dump result type\n\n            if (auto init = f.initializer())\n               pp << needs_newline()\n                  << xpr_stmt(init.get());\n         }\n\n         void visit(const Template& m) final\n         {\n            m.name().accept(*this);\n            pp << token(\" : \")\n               << xpr_mapping_expression(m.mapping());\n         }\n      };\n   }\n\n   Printer&\n   operator<<(Printer& printer, xpr_decl x)\n   {\n      if (printer.needs_newline())\n         printer << newline_and_indent();\n\n      xpr::Location_printer::print(printer, x.decl);\n      xpr::Decl impl(printer);\n      x.decl.accept(impl);\n      if (x.needs_semicolon)\n        printer << token(';');\n      return printer;\n   }\n\n   Printer&\n   operator<<(Printer& pp, const Translation_unit& unit)\n   {\n      return pp << xpr_expr(unit.global_namespace().scope());\n   }\n\n} // of namespace ipr\n"
  },
  {
    "path": "src/cxx-ipr-io.ixx",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module interface: cxx.ipr.io\n// The XPR pretty-printer for the IPR node hierarchy.\n\nmodule;\n\n#include <ipr/std-preamble>\n\nexport module cxx.ipr.io;\n\nimport cxx.ipr;\n\nnamespace ipr::util {\n   // A predicate for types with values that can be inserted into standard streams.\n   template<typename T>\n   concept std_insertable = requires(std::ostream& os, const T& t) {\n      os << t;\n   };\n}\n\nnamespace ipr\n{\n   // FIXME: Remove these data structures.\n   // A data structure used to map different uses of a name to the\n   // corresponding declaration. It is used by XPR printer to print name\n   // disambiguation information. A similar but a bit more elaborated structure\n   // is used by XPR parser to relink uses of names to appropriate declarations.\n   // The key of the map is the node_id of the name used, while the value\n   // is the information about corresponding declaration.\n   export struct disambiguation_map_type : std::map<const ipr::Name*, std::vector<const ipr::Decl*>>\n   {\n      using declarations = std::vector<const ipr::Decl*>;\n      using size_type = std::ptrdiff_t;\n\n      // Given a name and a declaration that corresponds to it, looks up\n      // or allocates a disambiguation id for them.\n      size_type get_disambiguation(const ipr::Name& name, const ipr::Decl& declaration)\n      {\n         declarations& decls = (*this)[&name];\n         declarations::const_iterator p = std::find(decls.begin(), decls.end(), &declaration);\n\n         if (p == decls.end())\n         {\n            decls.push_back(&declaration);\n            return decls.size();                         // Because disambiguations are 1-based\n         }\n         return (p - decls.begin()) + 1;                 // Because disambiguations are 1-based\n      }\n   };\n\n   export struct Printer {\n      enum class Padding {\n         None, Before, After\n      };\n\n      Printer(const Lexicon&, std::ostream&);\n\n      Padding padding() const { return pad; }\n\n      bool needs_newline() const { return emit_newline; }\n      void needs_newline(bool b) { emit_newline = b; }\n\n      void indent(int n) { pending_indentation += n; }\n      int indent() const { return pending_indentation; }\n      std::ostream& channel() { return stream; }\n\n      Printer& operator<<(const char8_t*);\n      Printer& operator<<(Specifiers);\n      Printer& operator<<(Qualifiers);\n      template<typename T> requires util::std_insertable<T>\n      Printer& operator<<(T t) { stream << t; return *this; }\n\n      // Setting padding flags\n      Printer& operator<<(Padding p) { pad = p; return *this; }\n\n      void write(util::word_view);\n\n\n   private:\n      const Lexicon& lexicon;\n      std::ostream& stream;\n      Padding pad;\n      bool emit_newline;\n      int pending_indentation;\n\n   public:\n      disambiguation_map_type disambiguation_map;\n      bool print_locations = false;\n   };\n\n\n   export struct xpr_decl {\n      const Expr& decl;\n      const bool needs_semicolon; // false, in most cases.\n      xpr_decl(const Expr& d, bool add_semicolon = false)\n            : decl(d), needs_semicolon(add_semicolon)\n      { }\n   };\n\n   export struct xpr_stmt {\n      const Expr& stmt;\n      const bool needs_semicolon; // false, in most cases.\n      explicit xpr_stmt(const Expr& s, bool add_semicolon = true)\n            : stmt(s), needs_semicolon(add_semicolon)\n      { }\n   };\n\n   export struct xpr_type {\n      const Type& type;\n      explicit xpr_type(const Type& e) : type(e) { }\n   };\n\n   export struct xpr_expr {\n      const Expr& expr;\n      explicit xpr_expr(const Expr& e) : expr(e) { }\n   };\n\n   export Printer& operator<<(Printer&, xpr_decl);\n   export Printer& operator<<(Printer&, xpr_stmt);\n   export Printer& operator<<(Printer&, xpr_type);\n   export Printer& operator<<(Printer&, xpr_expr);\n   export Printer& operator<<(Printer&, const Translation_unit&);\n\n   export Printer& operator<<(Printer&, const Identifier&);\n   export Printer& operator<<(Printer&, const Logogram&);\n   export Printer& operator<<(Printer&, Mapping_level);\n   export Printer& operator<<(Printer&, Decl_position);\n}\n"
  },
  {
    "path": "src/cxx-ipr-syntax.ixx",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module partition: cxx.ipr:syntax\n// C++ syntactic forms: tokens, attributes, declarators, constraints,\n// initialization provisions, and designators.\n//\n// -- The IPR focuses primarily on capturing the semantics of C++, not mimic - with\n// -- high fidelity - the ISO C++ source-level syntax minutiae, grammars, and other obscurities.\n// -- The IPR model of declaration reflects that semantics-oriented view.  Occasionally, it\n// -- is necessary to bridge the gap between the generalized semantics model and the\n// -- irregularities and other grammatical hacks via IPR directives.  Some of those\n// -- directives need to refer to some form of input source level constructs, especially in\n// -- cases of templated declarations involving non-ground types.\n// -- This partition defines interfaces for some syntactic forms, i.e. abstractions of syntactic\n// -- input, to aid complete embedding of the ISO C++ specification.\n// -- Note: There is no effort here to reify the parse trees of the ISO C++ grammar.\n\nmodule;\n\n#include <ipr/std-preamble>\n\nexport module cxx.ipr:syntax;\nimport :vocabulary;\n\n// -----------------------------------\n// -- Basic syntactic units: Tokens --\n// -----------------------------------\n// The IPR focuses primarily on semantic aspects of C++ constructs.\n// Certain constructs, such as uninstantiated template definitions,\n// are primarily syntactic with minimal semantic processing.  IPR nodes\n// can fully represent those structurally well-defined syntactic entities.\n// However, C++11 added attributes which are essentially token soups.  These\n// attributes make the IPR interface less abstract than wanted.\n\nnamespace ipr {\n    // General classification of tokens, e.g. identifier, number, space, comment, etc.\n    export enum class TokenCategory : std::uint8_t { };\n\n    // A numerical value associated with each token.\n    export enum class TokenValue : std::uint16_t { };\n\n    export struct Lexeme {\n        virtual const String& spelling() const = 0;\n        virtual const Source_location& locus() const = 0;\n    };\n\n    export struct Token {\n        virtual const Lexeme& lexeme() const = 0;\n        virtual TokenValue value() const = 0;\n        virtual TokenCategory category() const = 0;\n    };\n\n    export struct Attribute {\n        struct Visitor;\n        virtual void accept(Visitor&) const = 0;\n    };\n\n    // A simple token used as attribute.\n    export struct BasicAttribute : Unary<Attribute, const Token&> {\n        const Token& token() const { return operand(); }\n    };\n\n    // An attribute of the form `token1 :: token2'\n    export struct ScopedAttribute : Binary<Attribute, const Token&, const Token&> {\n        const Token& scope() const { return first(); }\n        const Token& member() const { return second(); }\n    };\n\n    // An attribute of the form `token : attribute'.\n    export struct LabeledAttribute : Binary<Attribute, const Token&, const Attribute&> {\n        const Token& label() const { return first(); }\n        const Attribute& attribute() const { return second(); }\n    };\n\n    // An attribute of the form `f(args)'.\n    export struct CalledAttribute : Binary<Attribute, const Attribute&,\n                                          const Sequence<Attribute>&> {\n        const Attribute& function() const { return first(); }\n        const Sequence<Attribute>& arguments() const { return second(); }\n    };\n\n    // An attribute of the form `attribute...'\n    export struct ExpandedAttribute : Binary<Attribute, const Token&, const Attribute&> {\n        const Token& expander() const { return first(); }\n        const Attribute& operand() const { return second(); }\n    };\n\n    // An attribute of the form `[[using check: memory(3), type(2)]]'\n    export struct FactoredAttribute : Binary<Attribute, const Token&,\n                                             const Sequence<Attribute>&> {\n        const Token& factor() const { return first(); }\n        const Sequence<Attribute>& terms() const { return second(); }\n    };\n\n    // An attribute of the form `[[ expr ]]', where `expr' is the elaboration result\n    // of parsing and semantics analysis of the enclosed token sequence.  This is a \n    // common non-standard form of attribute.\n    export struct ElaboratedAttribute : Unary<Attribute, const Expr&> {\n        const Expr& elaboration() const { return operand(); }\n    };\n\n    struct Attribute::Visitor {\n        virtual void visit(const BasicAttribute&) = 0;\n        virtual void visit(const ScopedAttribute&) = 0;\n        virtual void visit(const LabeledAttribute&) = 0;\n        virtual void visit(const CalledAttribute&) = 0;\n        virtual void visit(const ExpandedAttribute&) = 0;\n        virtual void visit(const FactoredAttribute&) = 0;\n        virtual void visit(const ElaboratedAttribute&) = 0;\n    };\n}\n\n// -- C++ syntactic forms --\n\nnamespace ipr::cxx_form {\n    // -- Syntactic constraints.\n    // -- C++ Concepts, as supported since C++20, focus primarily on the syntactic requirements\n    // -- on combinations of template arguments. The semantics counterpart is not yet supported by\n    // -- the base language.\n    // -- A constraint generally applies a concept to a compile-time argument list.  Hence the syntax\n    // -- uses the \"template specialization\" syntax for the application.  The result is a Boolean\n    // -- expression indicating whether the syntactic constraints contained in the body if the \n    // -- concept are satisfied or not.  Given a monadic concept (a concept with exactly one parameter),\n    // -- the concept name, as a predicate, can be viewed as a type for a template-type parameter.  \n    // -- That is known as the \"short-hand notation\" . Similar notational convenience for non-type\n    // -- template parameter isn't as straightforward.\n    // -- Given a polyadic concept (a concept with more N parameters, N > 1), a constraint can be formed\n    // -- by applying the concept name to N-1 compile-time arguments (the \"trailing arguments\"). \n\n    export struct Constraint_visitor;\n\n    export struct Constraint {\n        struct Monadic;                                         // -> C;\n        struct Polyadic;                                        // -> C<e1, e2>;\n        virtual void accept(Constraint_visitor&) const = 0;\n    };\n\n    // An object of this type corresponds to an instance of the first alternative of the ISO C++\n    // grammar production for type-constraint\n    //          nested-name-specifier_opt concept-name\n    struct Constraint::Monadic : Constraint {\n        virtual Optional<Expr> scope() const = 0;\n        virtual const Identifier& concept_name() const = 0;\n    };\n\n    // An object of this type corresponds to an instance of the second alternative of the ISO C++\n    // grammar production for type-constraint\n    //          nested-name-specifier_opt concept-name `< template-argument--list_opt `>`\n    struct Constraint::Polyadic : Constraint {\n        virtual Optional<Expr> scope() const = 0;\n        virtual const Identifier& concept_name() const = 0;\n        virtual const Sequence<Expr>& trailing_arguments() const = 0;\n    };\n\n    export struct Constraint_visitor {\n        virtual void visit(const Constraint::Monadic&) = 0;\n        virtual void visit(const Constraint::Polyadic&) = 0;\n    };\n\n    // Base class for navigation of requirements.\n    export struct Requirement_visitor;\n\n    // -- Typically, the definition of a concept is expressed in terms of syntactic requirements.\n    // -- Those requirements are formulated as proof obliggations for the validity of stylized\n    // -- expressions (usage patterns).\n    export struct Requirement {\n        struct Simple;                                  // *p = t;\n        struct Type;                                    // typename C::iterator;\n        struct Compound;                                // { &*p } -> same_as<T*>;\n        struct Nested;                                  // requires Trivial<C::iterator>;\n        virtual void accept(Requirement_visitor&) const = 0;\n    };\n\n    // An object of this type corresponds to an instance of the ISO C++ grammar production\n    // for simple-requirement:\n    //          expression `;`\n    struct Requirement::Simple : Requirement {\n        virtual const Expr& expr() const = 0;\n    };\n\n    // An object of this type corresponds to an instance of the ISO C++ grammar production\n    // for type-requirement:\n    //      `typename` nested-name-specifier_opt type-namexpression `;`\n    struct Requirement::Type : Requirement {\n        virtual Optional<Expr> scope() const = 0;\n        virtual const Name& type_name() const = 0;\n    };\n\n    // An object of this type corresponds to an instance of the ISO C++ grammar production\n    // for compound-requirement:\n    //      `{` expression `}` `noexcept`_opt return-type-requirement_opt `;`\n    // where the grammar production for return-type-requirement is\n    //     `->` type-constraint\n    struct Requirement::Compound : Requirement {\n        virtual const Expr& expr() const = 0;\n        virtual Optional<Constraint> constraint() const = 0;\n        virtual bool nothrow() const = 0;\n    };\n\n    // An object of this type corresponds to an instance of the ISO C++ grammar production\n    // for nested-requirement:\n    //      `requires` constant-expression `;`\n    struct Requirement::Nested : Requirement {\n        virtual const Expr& condition() const = 0;\n    };\n\n    export struct Requirement_visitor {\n        virtual void visit(const Requirement::Simple&) = 0;\n        virtual void visit(const Requirement::Type&) = 0;\n        virtual void visit(const Requirement::Compound&) = 0;\n        virtual void visit(const Requirement::Nested&) = 0;\n    };\n\n    // -- Abstraction of ISO C++ Declarators:\n    // -- The C and C++ languages have tortuous grammars for declarations, whereby\n    // -- declarations are structured to mimic use (operator precedence).  A declaration\n    // -- is made of two essential pieces (decl-specifiers-seq and declarator), with an\n    // -- an optional component representing the initializer.  The decl-specifier-seq\n    // -- is a soup made of decl-specifier such as `static`, `extern`, etc. and simple-type\n    // -- names such as `int`, and type qualifiers.  Compound types are made with\n    // -- type-constructors such as `*` (pointer) or `&` (reference), `[N]` (array), etc.  \n    // -- The type-constructors (which really imply some form of data indirection) are specified\n    // -- along with the name being introduced, making up the declarator.\n    // -- Pointer-style type-constructors are modeled by `Indirector`.\n    // -- Mapping-style type constructors (functions, arrays) are modeled by classes in\n    // -- `Morphism` hierarchy.\n    // -- Complete declarators that have mapping-style type contructors are modelled in the\n    // -- `Species_declarator` class hierarchy.\n\n    export struct Indirector_visitor;      // Base class of visitors for traversing `Indirector`s.\n\n    // Base class for objects representing ptr-operator (C++ grammar).\n    // While the source-level grammar of ISO C++ does not allow attributes on\n    // reference-style ptr-operator, the representation adopted here makes room for that possibility.\n    // Hence all `Indirector` objects have an `attributes()` operation.\n    // At the input source level, `Indirector`s precede the name being declared in the declarator.\n    export struct Indirector {\n        struct Pointer;             // pointer indirector\n        struct Reference;           // reference indirector\n        struct Member;              // non-static member indirector\n        virtual const Sequence<Attribute>& attributes() const = 0;\n        virtual void accept(Indirector_visitor&) const = 0;\n    };\n\n    // A `Pointer` indirector object is a simple possibly cv-qualified pointer indirection.\n    // And object of this type corresponds to the instance of the ptr-operator C++ grammar:\n    //      `*` attribute-specifier-seq_opt cv-qualifier-seq_opt\n    struct Indirector::Pointer : Indirector {\n        virtual Qualifiers qualifiers() const = 0;\n    };\n\n    // Syntactic indication of reference binding flavor.\n    export enum class Reference_flavor {\n        Lvalue,                     // \"&\" ptr-operator in an indirector\n        Rvalue                      // \"&&\" ptr-operator in an indirector\n    };\n\n    // A `Reference` indirector object is a reference indirection.\n    // An object of this type corresponds to an instance of any of the following alternatives\n    // of the ptr-operator C++ grammar production:\n    //     `&` attribute-specifier-seq_opt\n    //     `&&` attribute-specifier-seq_opt\n    struct Indirector::Reference : Indirector {\n        virtual Reference_flavor flavor() const = 0;\n    };\n\n    // A member `Indirector` object represents a ptr-operator that specifies a pointer to member.\n    // An object of this type corresponds to an instance of the following alternative of the\n    // ptr-operator C++ grammar production:\n    //     nested-named-specifier `*` attribute-specifier-seq_opt cv-qualifier-seq_opt\n    struct Indirector::Member : Indirector {\n        virtual const Expr& scope() const = 0;\n        virtual Qualifiers qualifiers() const = 0;\n    };\n\n    // Traversal of Indirector objects is facilitated by visitor classes deriving\n    // from this interface.\n    export struct Indirector_visitor {\n        virtual void visit(const Indirector::Pointer&) = 0;\n        virtual void visit(const Indirector::Reference&) = 0;\n        virtual void visit(const Indirector::Member&) = 0;\n    };\n\n    // -- Species and Morphisms\n    // A species declarator introduces a name along with typical usage of a named being declared.\n    // This usage pattern is captured by a suffix of `Morphism`s.  A `Morphism` is a form that\n    // specifies the type constuctor from the declared entity to the type of typical uses of that \n    // entity in expressions.\n    //   - Function: a callable expression, the entity is typically called\n    //   - Array: a table expression, the entity is typically indexed\n\n    // -- Morphism and navigation\n    export struct Morphism_visitor;\n\n    export struct Morphism {\n        struct Function;                            // -- (T, int) & noexcept\n        struct Array;                               // -- [34][] [[S::A]]\n        virtual const Sequence<Attribute>& attributes() const = 0;\n        virtual void accept(Morphism_visitor&) const = 0;\n    };\n\n    export struct Morphism_visitor {\n        virtual void visit(const Morphism::Function&) = 0;\n        virtual void visit(const Morphism::Array&) = 0;\n    };\n\n    // -- Species and navigation\n    export struct Species_visitor;\n\n    // A species declarator is either a name (possibly a pack), or a parenthesized term declarator, followed\n    // by a possibly empty sequence of morphisms.  For instance, in the declaration\n    //        bool (*pfs[8])(int)\n    // that declares pfs as an array of 8 pointers to functions taking an `int` returning a `bool`, the complete\n    // declarator `(*pfs[8])(int)` is a parenthesized species (`(*pfs[8])`) with the suffix consisting exactly of\n    // the singleton sequence of function morphism `(int)`.\n    // The term declarator `*pfs[8]` in turn has the indirectors is comprised of the single pointer indirector `*`,\n    // and of the id species `pfs` with array suffix `[8]`.\n    export struct Species_declarator {\n        struct Unqualified_id;                      // -- int p;\n        struct Pack;                                // -- Ts... xs\n        struct Qualified_id;                        // -- int X<T>::count;\n        struct Parenthesized;                       // parenthesized term declarator -- (*p)\n        virtual const Sequence<Morphism>& suffix() const = 0;\n        virtual void accept(Species_visitor&) const = 0;\n    };\n\n    // Base class for representing instances of the C++ production id-expression in the C++\n    // grammar for declarator-id.\n    export struct Declarator_id : Species_declarator {\n        virtual const Sequence<Attribute>& attributes() const = 0;\n    };\n\n    // Representation of an unqualified-id in an instance of the C++ grammar production for declarator-id.\n    // The operation `name()` returns an optional value for use in representing instances of the C++\n    // grammar production for noptr-abstract-declarator.\n    struct Species_declarator::Unqualified_id : Declarator_id {\n        virtual Optional<ipr::Name> name() const = 0;\n    };\n\n    // Representation of a pack parameter in an instance of the C++ grammar production for declarator-id\n    // The operation `name()` returns an optional value for use in representing instances of the C++\n    // grammar production for noptr-abstract-abstract-declarator.\n    // Example:\n    //     ... x\n    struct Species_declarator::Pack : Declarator_id {\n        virtual Optional<ipr::Identifier> name() const = 0;\n    };\n\n    // Representation of a qualified-id in an instance of the C++ grammar production for declarator-id\n    // Such qualified-id are used in the out-of-class definition of an entity.\n    struct Species_declarator::Qualified_id : Declarator_id {\n        virtual const ipr::Expr& scope() const = 0;\n        virtual const ipr::Name& member() const = 0;\n    };\n\n    // -- Declarator.\n    // -- A declarator is either a term, or a species with a target type.\n    // -- A term is a sequence of indirectors followed by a species.\n    // -- A species indicates the typical usage syntactic structure of the named being declared.\n\n    export struct Declarator_visitor;\n\n    export struct Declarator {\n        struct Term;                                // *p or (&a)[42]\n        struct Targeted;                            // f(T& p) -> int\n        virtual const Species_declarator& species() const = 0;\n        virtual void accept(Declarator_visitor&) const = 0;\n    };\n\n    // A term declarator is a sequence of `Indirector`s followed by a species declarator.\n    // An object of this type represents an instance of the first alternative of the C++ \n    // grammar production for declarator:\n    //     ptr-declarator\n    // Examples:\n    //     (&a)[42]\n    //     *f(T) noexcept\n    struct Declarator::Term : Declarator {\n        virtual const Sequence<Indirector>& indirectors() const = 0;\n    };\n\n    // A targeted declarator is a species declarator with a trailing return type,\n    // given by the `target()` operation.\n    // An object of this type represents an instance of the second alternative of the C++\n    // grammar production for declarator:\n    //     noptr-declarator paramters-and-qualifiers trailing-return-type\n    // In particular, the `species()` of a targeted declarator has a function Morphism as \n    // last element in its `suffix()`.  Furthermore, a targeted declarator lacks indirectors.\n    // Examples:\n    //    f(T a, U b) -> decltype(a + b)\n    struct Declarator::Targeted : Declarator {\n        virtual const Type& target() const = 0;\n    };\n\n    // Traversal of declarator objects is facilitated by visitor classes deriving\n    // from this interface.\n    export struct Declarator_visitor {\n        virtual void visit(const Declarator::Term&) = 0;\n        virtual void visit(const Declarator::Targeted&) = 0;\n    };\n\n    // A term declarator requiring parentheses to obey operator precedence rules, or just\n    // a redundant parentheses. An object of this type represents an instance of the fourth\n    // alternative of the C++ grammar for noptr-declarator:\n    //      `(` ptr-declarator `)`\n    // Example:\n    //      (a)\n    //      (*p)\n    struct Species_declarator::Parenthesized : Species_declarator {\n        virtual const Declarator::Term& term() const = 0;\n    };\n\n    // -- Function Morphism\n    // A morphism for a declarator indicating something that can be called.\n    // An object of this type captures the components introduced by an instance the second \n    // alternative of the C++ grammar of noptr-delarator:\n    //    noptr-declarator parameters-and-qualifiers\n    struct Morphism::Function : Morphism {\n        virtual const Parameter_list& parameters() const = 0;\n        virtual Qualifiers qualifiers() const = 0;\n        virtual Binding_mode binding_mode() const = 0;\n        virtual Optional<Expr> throws() const = 0;\n    };\n\n    // -- Array Morphism\n    // A morphism for a declarator indicating something that can be indexed.\n    // An object of this type captures the components introduced by an instance the third\n    // alternative of the C++ grammar of noptr-delarator:\n    //    noptr-declarator `[` constant-expression_opt `]` attribute-specifier-seq_opt\n    struct Morphism::Array : Morphism {\n        virtual Optional<Expr> bound() const = 0;\n    };\n\n    // Traversal of species objects is facilitated by visitor classes deriving\n    // from this interface.\n    export struct Species_visitor {\n        virtual void visit(const Species_declarator::Unqualified_id&) = 0;\n        virtual void visit(const Species_declarator::Pack&) = 0;\n        virtual void visit(const Species_declarator::Qualified_id&) = 0;\n        virtual void visit(const Species_declarator::Parenthesized&) = 0;\n    };\n\n    // -- Proclamator.\n    // A proclamator is a complete declarator along with an initializer, or with a constraint.\n    // A proclamator represents an instance of the C++ grammar for init-declarator.  Furtermore,\n    // a proclamator holds the result of elaborating its declarator with a decl-specifier-seq that\n    // preceds it in a declaration.\n\n    // -- Initialization provision.\n    // -- An initialization provision is an initializer form that stipulates how an entity\n    // -- (the name of which is introduced by a declarator) shall be initialized. Choices range from\n    // -- classic provision introduced by the `=` sign, to recent innovations such as parenthesized\n    // -- expression list or brace enclosed initializer list for uniform initialization.\n\n    export struct Provision_visitor;\n\n    // Base class of initialization provision classes.  They don't share much in common other than\n    // appearing in top-level init-declarators.\n    export struct Initialization_provision {\n        virtual void accept(Provision_visitor&) const = 0;\n    };\n\n    // Base for navigating elemental initializers.\n    export struct Initializer_visitor;\n\n    // Base class of initializer form (other than earmarked initializer) that can appear in a\n    // brace-enclosed initilizer form. \n    export struct Elemental_initializer {\n        virtual void accept(Initializer_visitor&) const = 0;\n    };\n\n    // Initialization provision of the form\n    //     `=` initializer-clause\n    export struct Classic_provision : Initialization_provision {\n        virtual const Elemental_initializer& initializer() const = 0;\n    };\n\n    // Initialization provision of the form\n    //    `(` expression-list `)`;\n    export struct Parenthesized_provision : Initialization_provision {\n        virtual const Expr& initializer() const = 0;\n    };\n\n    // Embedding of an expression in an elemental initializer hierarchy.\n    // Note that the expression here can be either\n    //      expression\n    // in general, or an\n    //     expression-list_opt\n    export struct Expr_initializer : Elemental_initializer {\n        virtual const Expr& expression() const = 0;\n    };\n\n    // Initialization provision of the form\n    //    `{` initializer-list_opt `}`\n    export struct Braced_provision : Initialization_provision, Elemental_initializer {\n        virtual const Sequence<Elemental_initializer>& elements() const = 0;\n    };\n\n    // An earmarked initializer is a form that specifies an initializer for a specific subobject\n    // of a structure or an array, in a designated-initializer-list.  Strictly speaking, ISO C++\n    // (unlike C99) currently supports only designated-initializer-list for structures, but not\n    // arrays.  But since the C99 designated-initialization for arrays is in practice accepted\n    // by major compilers as extensions, and that extension fits the general model here, the form\n    // data structures below make room for them.\n    export struct Earmarked_initializer;\n\n    // An initializer provision of the form\n    //    `{` designated-initializer-list_opt `}`\n    export struct Designated_list_provision : Initialization_provision, Elemental_initializer {\n        virtual const Sequence<Earmarked_initializer>& elements() const = 0;\n    };\n\n    // Base class for navigation of initialization provisions.\n    export struct Provision_visitor {\n        virtual void visit(const Classic_provision&) = 0;\n        virtual void visit(const Parenthesized_provision&) = 0;\n        virtual void visit(const Braced_provision&) = 0;\n        virtual void visit(const Designated_list_provision&) = 0;\n    };\n\n    // -- Designator.\n    // A designator is a form that identifies an immediate subobject of a structure (by name),\n    // or an array (by slot index).  For example, in designated-initializer-list, the element\n    //     .galaxy { \"Milky Way\"}\n    // provides a braced-initializer for the field named `galaxy`.  Similarly the element\n    //     [4] = \"Tau'ri\"\n    // provides a classic-initializer for the fifth slot of the array being initialized.\n    export struct Designator_visitor;\n\n    export struct Subobject_designator {\n        virtual void accept(Designator_visitor&) const = 0;\n    };\n\n    // Designator of a field.\n    // Example:\n    //     . location\n    export struct Field_designator : Subobject_designator {\n        virtual const Identifier& name() const = 0;\n    };\n\n    // Designator of an array slot.\n    // Example:\n    //    [ 13 ]\n    export struct Slot_designator : Subobject_designator {\n        virtual const Expr& index() const = 0;\n    };\n\n    export struct Designator_visitor {\n        virtual void visit(const Field_designator&) = 0;\n        virtual void visit(const Slot_designator&) = 0;\n    };\n\n    // An earmarked initializer is an element of a designated-initializer-list that provides\n    // an initialier for a direct subobject of a structure or an array.\n    // Example:\n    //    .galaxy { \"Milky Way\" }\n    //    [4] = \"Tau'ri\"\n    export struct Earmarked_initializer {\n        virtual const Subobject_designator& subobject() const = 0;\n        virtual const Initialization_provision& initializer() const = 0;\n    };\n\n    // Base class for navigation of elemental initializers.\n    export struct Initializer_visitor {\n        virtual void visit(const Expr_initializer&) = 0;\n        virtual void visit(const Braced_provision&) = 0;\n        virtual void visit(const Designated_list_provision&) = 0;\n    };\n\n    export struct Proclamator_visitor;\n\n    export struct Proclamator {\n        struct Initialized;                         // int ary[] { 1, 2, 3 };\n        struct Constrained;\n        virtual const Declarator& declarator() const = 0;\n        virtual Decl& result() const = 0;\n        virtual void accept(Proclamator_visitor&) const = 0;\n    };\n\n    struct Proclamator::Initialized : Proclamator {\n        virtual Optional<Initialization_provision> initializer() const = 0;\n    };\n\n    struct Proclamator::Constrained : Proclamator {\n        virtual const Expr& constraint() const = 0;\n    };\n\n    export struct Proclamator_visitor {\n        virtual void visit(const Proclamator::Initialized&) = 0;\n        virtual void visit(const Proclamator::Constrained&) = 0;\n    };\n}\n"
  },
  {
    "path": "src/cxx-ipr-traversal.cxx",
    "content": "//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module implementation unit for cxx.ipr.traversal.\n// Contains out-of-line definitions: structurally_same template overloads\n// for Unary<>, Binary<>, Ternary<>, and Missing_overrider::operator().\n\nmodule;\n\n#include <ipr/std-preamble>\n#include <typeinfo>\n\nmodule cxx.ipr.traversal;\n\nnamespace ipr {\n\n   template<class Cat, class Op>\n   inline bool\n   structurally_same(const Unary<Cat, Op>& lhs, const Unary<Cat, Op>& rhs)\n   {\n      return physically_same(lhs, rhs)\n         or structurally_same(lhs.operand(), rhs.operand());\n   }\n\n   template<class Cat, class Op1, class Op2>\n   inline bool\n   structurally_same(const Binary<Cat, Op1, Op2>& lhs,\n                     const Binary<Cat, Op1, Op2>& rhs)\n   {\n      return physically_same(lhs, rhs)\n         or (structurally_same(lhs.first(), rhs.first())\n             and structurally_same(lhs.second(), rhs.second()));\n   }\n\n   template<class Cat, class Op1, class Op2, class Op3>\n   inline bool\n   structurally_same(const Ternary<Cat, Op1, Op2, Op3>& lhs,\n                     const Ternary<Cat, Op1, Op2, Op3>& rhs)\n   {\n      return physically_same(lhs, rhs)\n         or (structurally_same(lhs.first(), rhs.first())\n             and structurally_same(lhs.second(), rhs.second())\n             and structurally_same(lhs.third(), rhs.third()));\n   }\n}\n\nvoid\nipr::Missing_overrider::operator()(const ipr::Node& n) const\n{\n   throw std::logic_error(std::string(\"missing overrider for \")\n                          + typeid(n).name());\n}\n"
  },
  {
    "path": "src/cxx-ipr-traversal.ixx",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module interface: cxx.ipr.traversal\n// Utility functions and visitor adapters for traversing the IPR node hierarchy.\n\nmodule;\n\n#include <ipr/std-preamble>\n\nexport module cxx.ipr.traversal;\n\nimport cxx.ipr;\n\nnamespace ipr {\n   // This collection of routines implements structural equality\n   // of Nodes.  They are, for example, useful in determining\n   // when two (type-) expressions are same, from structural\n   // point of view in context like dependent types.\n\n   export bool structurally_same(const Node&, const Node&);\n\n   // -- builtin types\n   // This predicate holds for representation of built types: they are\n   // the fix points of the As_type functor.\n   export inline bool denote_builtin_type(const As_type& t)\n   {\n      return physically_same(t, t.expr());\n   }\n\n   // This visitor class applies the same function to all major nodes.\n   // A typical example of use is to throw an exception or do nothing.\n   export template<class F>\n   struct Constant_visitor : Visitor, F {\n      void visit(const Node& n) override { (*this)(n); }\n      void visit(const Name& n) override { (*this)(n); }\n      void visit(const Expr& n) override { (*this)(n); }\n      void visit(const Type& n) override { (*this)(n); }\n      void visit(const Directive& n) override { (*this)(n); }\n      void visit(const Stmt& n) override { (*this)(n); }\n      void visit(const Decl& n) override { (*this)(n); }\n   };\n\n   // This function object class implement \"no-op\" semantics.  Useful\n   // with the above Visitor.\n   export struct No_op {\n      void operator()(const Node&) const { }\n   };\n\n   // This function object type throw an exception indicating that a\n   // Visitor::visit() is missing for a particular IPR node type.\n   export struct Missing_overrider {\n      void operator()(const Node&) const;\n   };\n\n   namespace util {\n      // This helper function returns a pointer to its argument, if that\n      // node is from the category indicated by the template parameter.\n      // This is a cheap, specialized version of dynamic cast.\n      export template<class T>\n      inline const T*\n      view(const Node& n)\n      {\n         struct visitor : Constant_visitor<No_op> {\n            const T* result = nullptr;\n            void visit(const T& n) final { result = &n; }\n         };\n\n         visitor vis { };\n         n.accept(vis);\n         return vis.result;\n      }\n   }\n}\n"
  },
  {
    "path": "src/cxx-ipr-vocabulary.ixx",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module partition: cxx.ipr:vocabulary\n// Foundational types for the IPR interface: structural templates,\n// strong enums, source locations, sequences, and optionals.\n\nmodule;\n\n#include <ipr/std-preamble>\n\nexport module cxx.ipr:vocabulary;\n\n// -- Utility subset: only the symbols needed by the interface --\n\nnamespace ipr::util {\n    // Predicate to detect enumeration types.\n    export template<typename T>\n    concept EnumType = std::is_enum_v<T>;\n\n    // The underlying type of an enumeration\n    export template<EnumType T>\n    using raw = std::underlying_type_t<T>;\n\n    // Return the value representation of an enumeration value.\n    export template<typename T> requires EnumType<T>\n    constexpr auto rep(T t)\n    {\n        return static_cast<raw<T>>(t);\n    }\n\n    // Type of view over words as stored internally.\n    export using word_view = std::u8string_view;\n\n    // -- Check for nonnull pointer.\n    export template<typename T>\n    inline T* check(T* ptr)\n    {\n        if (ptr == nullptr)\n            throw std::logic_error(\"attempt to dereference a null pointer\");\n        return ptr;\n    }\n}\n\n// -- Forward declarations for the entire node hierarchy --\n// These are needed by ancillary types (Sequence<T>, Optional<T>, etc.)\n// and by the :syntax partition.\n\nnamespace ipr {\n    export struct Node;                  // universal base class for all IPR nodes\n    export struct Visitor;               // base class for all IPR visitor classes\n    export struct Annotation;            // node annotations\n    export struct Region;                // declarative region\n    export struct Comment;               // C-style and BCPL-style comments\n    export struct String;                // literal string\n    export struct Language_linkage;       // general language linkage\n    export struct Expr;                  // general expressions\n    export struct Name;                  // general names\n    export struct Type;                  // general types\n    export struct Directive;             // general directives\n    export struct Stmt;                  // general statements\n    export struct Decl;                  // general declarations\n    export struct Scope;                 // declarations in a region\n    export struct Overload;              // overload set\n    export struct Parameter_list;        // function/template parameter list\n\n    // -------------------------------------------\n    // -- results of type constructor constants --\n    // -------------------------------------------\n    export struct Array;                 // array type\n    export struct As_type;               // use-expression as type\n    export struct Class;                 // user-defined type - declared as \"class\" or \"struct\"\n    export struct Decltype;              // strict type of a declaration/expression\n    export struct Enum;                  // user-defined type - declared as \"enum\" or \"class enum\"\n    export struct Tor;                   // types of constructors and destructors\n    export struct Function;              // function type\n    export struct Namespace;             // user-defined type - declared as \"namespace\"\n    export struct Pointer;               // pointer type\n    export struct Ptr_to_member;         // pointer-to-member type\n    export struct Product;               // product type - not ISO C++ type\n    export struct Qualified;             // cv-qualified types\n    export struct Reference;             // reference type\n    export struct Rvalue_reference;      // rvalue-reference type\n    export struct Sum;                   // sum type - not ISO C++ type\n    export struct Forall;                // universally quantified type\n    export struct Union;                 // user-defined type - declared as \"union\"\n    export struct Auto;                  // \"auto\" -- each occurrence is generative\n    export struct Closure;               // closure type -- type of lambda expression\n\n    // ------------------------------------------\n    // -- results of name constructor constants --\n    // ------------------------------------------\n    export struct Identifier;            // identifier                          foo\n    export struct Suffix;                // Literal operator suffix       \"Plato\"sv\n    export struct Operator;              // C++ operator name             operator+\n    export struct Conversion;            // conversion function name   operator int\n    export struct Template_id;           // C++ template-id                  S<int>\n    export struct Type_id;               // C++ type-id                  const int*\n    export struct Ctor_name;             // constructor name                   T::T\n    export struct Dtor_name;             // destructor name                   T::~T\n    export struct Guide_name;            // deduction guide name \n\n    // --------------------------------------------------------\n    // -- results of nullary expression constructor constants --\n    // --------------------------------------------------------\n    export struct Phantom;               // placeholder for arrays of unknown bounds,\n                                         // rethrow, empty parts of a For, etc...\n    export struct Eclipsis;              // the `...' in a unary fold\n    export struct Lambda;                // Lambda expression\n    export struct Requires;              // requires-expression\n\n    // -------------------------------------------------------\n    // -- results of unary expression constructor constants --\n    // -------------------------------------------------------\n    export struct Symbol;                // self-evaluating symbolic values\n    export struct Address;               // address-of                          &a\n    export struct Array_delete;          // array delete-expression     delete[] p\n    export struct Asm;                   // asm-declaration\n    export struct Complement;            // bitwise complement                  ~m\n    export struct Delete;                // delete-expression             delete p\n    export struct Demotion;              // inverse of an integral/floating-point\n                                         // promotion -- implicit conversion\n    export struct Deref;                 // dereference expression              *p\n    export struct Expr_list;             // comma-separated expression list\n    export struct Alignof;               // alignment query                  alignof(T)\n    export struct Sizeof;                // sizeof expression\n    export struct Typeid;                // typeid expression\n    export struct Id_expr;               // use of a name as an expression\n    export struct Label;                 // a label - target of a goto-statement\n                                         //         or entry of a switch-statement\n    export struct Materialization;       // temporary materialization\n    export struct Not;                   // logical negation                 !cond\n    export struct Enclosure;             // expression in paired delimiters\n    export struct Post_decrement;        // post-decrement                     p--\n    export struct Post_increment;        // post-increment                     p++\n    export struct Pre_decrement;         // pre-decrement                      --p\n    export struct Pre_increment;         // pre-increment                      ++p\n    export struct Promotion;             // integral or floating-point promotion\n    export struct Read;                  // lvalue to rvalue conversion\n    export struct Throw;                 // throw expression               throw a\n    export struct Unary_minus;           // unary minus                         -a\n    export struct Unary_plus;            // unary plus                          +a\n    export struct Expansion;             // pack expansion                    t...\n    export struct Noexcept;              // noexcept expression        noexcept(e)\n    export struct Args_cardinality;      // sizeof...(args)\n    export struct Restriction;           // requires-clause\n\n    // --------------------------------------------------------\n    // -- results of binary expression constructor constants --\n    // --------------------------------------------------------\n    export struct Plus;                  // addition                       a + b\n    export struct Plus_assign;           // in-place addition              a += b\n    export struct And;                   // logical and                    a && b\n    export struct Array_ref;             // array member selection         a[i]\n    export struct Arrow;                 // indirect member selection      p->m\n    export struct Arrow_star;            // indirect member indirection    p->*m\n    export struct Assign;                // assignment                     a = b\n    export struct Bitand;                // bitwise and                    a & b\n    export struct Bitand_assign;         // in-place bitwise and           a &= b\n    export struct Bitor;                 // bitwise or                     a | b\n    export struct Bitor_assign;          // in-place bitwise or            a |= b\n    export struct Bitxor;                // bitwise exclusive or           a ^ b\n    export struct Bitxor_assign;         // in-place bitwise exclusive or  a ^= b\n    export struct Call;                  // function call                  f(u, v)\n    export struct Cast;                  // C-style cast                   (T) e\n    export struct Coercion;              // generalized type conversion\n    export struct Comma;                 // comma-operator                 a, b\n    export struct Const_cast;            // const_cast-expression\n    export struct Construction;          // object construction            T(v)\n    export struct Div;                   // division                       a / b\n    export struct Div_assign;            // in-place division              a /= b\n    export struct Dot;                   // direct member selection        x.m\n    export struct Dot_star;              // direct member indirection      x.*pm\n    export struct Dynamic_cast;          // dynamic_cast-expression\n    export struct Equal;                 // equality comparison            a == b\n    export struct Greater;               // greater comparison             a > b\n    export struct Greater_equal;         // greater-or-equal comparison    a >= b\n    export struct Less;                  // less comparison                a < b\n    export struct Less_equal;            // less-equal comparison          a <= b\n    export struct Literal;               // literal expressions            3.14\n    export struct Lshift;                // left shift                     a << b\n    export struct Lshift_assign;         // in-place left shift            a <<= b\n    export struct Member_init;           // member initialization          : m(v)\n    export struct Minus;                 // subtraction                    a - b\n    export struct Minus_assign;          // in-place subtraction           a -= b\n    export struct Modulo;                // modulo arithmetic              a % b\n    export struct Modulo_assign;         // in-place modulo arithmetic     a %= b\n    export struct Mul;                   // multiplication                 a * b\n    export struct Mul_assign;            // in-place multiplication        a *= b\n    export struct Narrow;                // checked base to derived conversion\n    export struct Not_equal;             // not-equality comparison        a != b\n    export struct Or;                    // logical or                     a || b\n    export struct Pretend;               // generalization of bitcast/reinterpret cast\n    export struct Qualification;         // cv-qualification conversion\n    export struct Reinterpret_cast;      // reinterpret_cast-expression\n    export struct Rshift;                // right shift                    a >> b\n    export struct Rshift_assign;         // in-place right shift           a >>= b\n    export struct Scope_ref;             // qualified name                N::f\n    export struct Static_cast;           // static_cast-expression\n    export struct Widen;                 // derived to base class conversion\n    export struct Binary_fold;           // primary expression (a op ... op b)\n    export struct Mapping;               // function\n    export struct Rewrite;               // semantics by translation\n    export struct Where;                 // expression with local bindings\n    export struct Static_assert;         // static-assert declaration\n    export struct Instantiation;         // substitution into parameterized expression\n\n    // --------------------------------------------------------\n    // -- result of trinary expression constructor constants --\n    // --------------------------------------------------------\n    export struct New;                   // new-expression              new (p) T(v)\n    export struct Conditional;           // conditional                   p ? a : b\n\n    // -----------------------------------------------\n    // -- result of statement constructor constants --\n    // -----------------------------------------------\n    export struct Block;                 // brace-enclosed statement sequence\n    export struct Break;                 // break-statement\n    export struct Continue;              // continue-statement\n    export struct Ctor_body;             // constructor-body\n    export struct Do;                    // do-statement\n    export struct Expr_stmt;             // expression-statement\n    export struct For;                   // for-statement\n    export struct For_in;                // structured for-statement\n    export struct Goto;                  // goto-statement\n    export struct Handler;               // exception handler statement\n    export struct If;                    // if-statement\n    export struct Labeled_stmt;          // labeled-statement\n    export struct Return;                // return-statement\n    export struct Switch;                // switch-statement\n    export struct While;                 // while-statement\n\n    // -----------------------------------------------\n    // -- result of directive constructor constants --\n    // -----------------------------------------------\n    export struct Specifiers_spread;     // spread of decl-specifier-seq over a sequence of declarators\n    export struct Structured_binding;    // structured-binding declaration\n    export struct Using_declaration;     // using-declaration\n    export struct Using_directive;       // using-directive\n    export struct Phased_evaluation;     // evaluation at designated phases of translation\n    export struct Pragma;                // language-level pragma directive\n\n    // -------------------------------------------------\n    // -- result of declaration constructor constants --\n    // -------------------------------------------------\n    export struct Template;              // parameterized declaration\n    export struct Enumerator;            // classic enumerator\n    export struct Alias;                 // alias declaration (typedef, namespace-alias, etc.)\n    export struct Base_type;             // base-specifier\n    export struct Parameter;             // parameter declaration\n    export struct EH_parameter;          // exception handler parameter\n    export struct Fundecl;               // function declaration\n    export struct Concept;               // concept declaration\n    export struct Var;                   // variable declaration\n    export struct Field;                 // nonstatic data member\n    export struct Bitfield;              // bit-field data member\n    export struct Typedecl;              // type declaration\n\n    // ------------------------\n    // -- distinguished node --\n    // ------------------------\n    export struct Translation_unit;\n    export struct Module_unit;\n    export struct Interface_unit;\n    export struct Module;\n    export struct Lexicon;\n}\n\n                                // -- Various Location Types --\n// C++ constructs span locations.  There are at least four flavours of\n// locations:\n//       (a) physical source location;\n//       (b) logical source location;\n//       (c) physical unit location; and\n//       (d) logical unit location.\n// Physical and logical source locations are locations as witnessed\n// at translation phase 2 (see ISO C++, §2.1/1).\n// Physical and logical unit locations are locations as manifest when\n// looking at a translation unit, at translation phase 4.\n//\n// Many IPR nodes will have a source and unit locations.  Instead of\n// storing a source file and unit name as a string in every\n// location data type, we save space by mapping file-names and\n// unit-names to IDs (integers).  That mapping is managed by the Unit\n// instance.\n\nnamespace ipr {\n    export enum class Line_number : std::uint32_t { };\n    export enum class Column_number : std::uint32_t { };\n\n    export struct Basic_location {\n        Line_number line = { };\n        Column_number column = { };\n    };\n\n    export enum class File_index : std::uint32_t { };\n\n    export struct Source_location : Basic_location {\n        File_index file = { };    // ID of the file\n    };\n\n    export enum class Unit_index : std::uint32_t { };\n\n    export struct Unit_location : Basic_location {\n        Unit_index unit = { };    // ID of the unit\n    };\n}\n\n// -- Ancillary types --\n\nnamespace ipr {\n    // ---------------------------\n    // -- Phases of translation --\n    // ---------------------------\n    // A bitmask type for the various phases of C++ program translation.\n    export enum class Phases {\n        Unknown              = 0x0000,   // Unknown translation phase\n        Reading              = 0x0001,   // Opening and reading an input source\n        Lexing               = 0x0002,   // Lexical decomposition of input source\n        Preprocessing        = 0x0004,   // Macro expansion and friends\n        Parsing              = 0x0008,   // Grammatical decomposition of the input source\n        Name_resolution      = 0x0010,   // Name lookup\n        Typing               = 0x0020,   // Type assignment of expressions\n        Evaluation           = 0x0040,   // Compile-time evaluation\n        Instantiation        = 0x0080,   // Template instantiation phase\n        Code_generation      = 0x0100,   // Code generation phase\n        Linking              = 0x0200,   // Linking phase\n        Loading              = 0x0400,   // Program loading phase\n        Execution            = 0x0800,   // Runtime execution\n\n        Elaboration          = Name_resolution | Typing | Evaluation | Instantiation,\n        All                  = ~0x0,\n    };\n\n    // -- Qualifiers --\n    // Abstract data type capturing compositions of standard and extended type qualifiers.\n    // Composition of type qualifiers is commutative.\n    export enum class Qualifiers : std::uintptr_t { };\n\n                                // -- Binding_mode --\n    // Mode of binding of a object value to a name (parameter, variable, alias, etc).\n    export enum class Binding_mode : std::uint8_t {\n        Copy,                         // by copy operation; default binding mode of C and C++\n        Reference,                    // by ref; the parameter or varable has an lvalue reference type\n        Move,                         // by move operation; transfer of ownership\n        Default = Copy,\n    };\n\n                                 // -- Delimiter --\n    // Enclosure delimiters of expressions\n    export enum class Delimiter {\n        Nothing,                   // no delimiter\n        Paren,                     // \"()\"\n        Brace,                     // \"{}\"\n        Bracket,                   // \"[]\"\n        Angle,                     // \"<>\"\n    };\n}\n\n// -- Vocabulary-level predicates --\n\nnamespace ipr {\n    // Returns true if both operands share the same physical storage.\n    export constexpr bool physically_same(const Node& lhs, const Node& rhs)\n    {\n        return &lhs == &rhs;\n    }\n\n    // Helper function, for implicit conversion Derived -> Base.\n    // It lets view a node, from a more concrete node category (Derived),\n    // as a member of more abstract node category (Base).\n    export template<class T, class U>\n    inline const T& as(const U& u) { return u; }\n}\n\n// -- Structural base templates --\n\nnamespace ipr {\n                                // -- Basic_unary --\n    // A structure entirely determined by its sole component, the `operand()`.\n    export template<typename Operand>\n    struct Basic_unary {\n        using Arg_type = Operand;\n        virtual Operand operand() const = 0;\n    };\n\n                                // -- Unary<> --\n    // A unary-expression is a specification of an operation that takes\n    // only one operand, an expression.  By extension, a unary-node is a\n    // node category that is essentially determined only by one node,\n    // its \"operand\".  Usually, such an operand node is a classic expression.\n    // Occasionally, it can be a type (e.g. sizeof (T)), we don't want to\n    // loose that information, therefore we add a template-parameter\n    // (the second) to indicate the precise type of the operand.  The first\n    // template-parameter designates the actual node subcategory this class\n    // provides an interface for.\n    export template<class Cat, class Operand = const Expr&>\n    struct Unary : Cat, Basic_unary<Operand> { };\n\n                                // -- Basic_binary --\n    // A structure entirely determined by its two components, the `first()`\n    // and `second()`.\n    export template<typename First, typename Second>\n    struct Basic_binary {\n        using Arg1_type = First;\n        using Arg2_type = Second;\n        virtual First first() const = 0;\n        virtual Second second() const = 0;\n    };\n\n                                // -- Binary<> --\n    // In full generality, a binary-expression is an expression that\n    // consists in (a) an operator, and (b) two operands.  In Standard\n    // C++, the two operands often are of the same type (and if they are not,\n    // they are implicitly converted).  In IPR, they need not be\n    // of the same type.  This generality allows representations of\n    // cast-expressions which are conceptually binary-expressions -- they\n    // take a type and an expression.  Also, a function call is\n    // conceptually a binary-expression that applies a function to\n    // a list of arguments.  By extension, a binary node is any node that\n    // is essentially dermined by two nodes, its \"operands\".\n    // As for Unary<> nodes, we indicate the operands' type information\n    // through the template-parameters First and Second.\n    export template<class Cat, class First = const Expr&, class Second = const Expr&>\n    struct Binary : Cat, Basic_binary<First, Second> { };\n\n                                // -- Ternary<> --\n    // Similar to Unary<> and Binary<> categories.  This is for\n    // ternary-expressions, or more generally for ternary nodes.\n    // An example of a ternary node is a Conditional node.\n    export template<class Cat, class First = const Expr&,\n             class Second = const Expr&, class Third = const Expr&>\n    struct Ternary : Cat {\n        using Arg1_type = First;\n        using Arg2_type = Second;\n        using Arg3_type = Third;\n        virtual First first() const = 0;\n        virtual Second second() const = 0;\n        virtual Third third() const = 0;\n    };\n}\n\n// -- Sequence and Optional --\n\nnamespace ipr {\n                                // -- Sequence<> --\n    // Often, we use a notion of sequence to represent intermediate\n    // abstractions like base-classes, enumerators, catch-clauses,\n    // parameter-type-list, etc.  A \"Sequence\" is a collection abstractly\n    // described by its \"begin()\" and \"end()\" iterators.  It is made\n    // abstract because it may admit different implementations depending\n    // on concrete constraints.  For example, a scope (a sequence of\n    // declarations, that additionally supports look-up by name) may\n    // implement this interface either as a associative-array that maps\n    // Names to Declarations (with no particular order) or as\n    // vector<Declaration*> (in order of their appearance in programs), or\n    // as a much more elaborated data structure.\n    export template<class T>\n    struct Sequence {\n        struct Iterator;          // An iterator is a pair of (sequence,\n                                  // position).  The position indicates\n                                  // the particular value referenced in\n                                  // the sequence.\n\n        // Provide STL-style interface, for use with some STL algorithm\n        // helper classes.  Sequence<> is an immutable sequence.\n        using value_type = T;\n        using reference = const T&;\n        using pointer = const T*;\n        using Index = std::size_t;\n        using iterator = Iterator;\n\n        virtual Index size() const = 0;\n        bool empty() const { return not (size() > 0); }\n        Iterator begin() const;\n        Iterator end() const;\n        Iterator position(Index) const;\n\n    protected:\n        virtual const T& get(Index) const = 0;\n    };\n\n                                // -- Sequence<>::Iterator --\n    // This iterator class is as abstract as it could be, for useful\n    // purposes.  It forwards most operations to the \"Sequence\" class\n    // it provides a view for.\n    template<class T>\n    struct Sequence<T>::Iterator {\n        using self_type = Sequence<T>::Iterator;\n        using value_type = const T;\n        using reference = const T&;\n        using pointer = const T*;\n        using difference_type = ptrdiff_t;\n        using Index = typename Sequence<T>::Index;\n        using iterator_category = std::bidirectional_iterator_tag;\n\n        Iterator() {}\n        Iterator(const Sequence* s, Index i) : seq{ s }, index{ i } { }\n\n        const T& operator*() const\n        { return seq->get(index); }\n\n        const T* operator->() const\n        { return &seq->get(index); }\n\n        Iterator& operator++()\n        {\n            ++index;\n            return *this;\n        }\n\n        Iterator& operator--()\n        {\n            --index;\n            return *this;\n        }\n\n        Iterator operator++(int)\n        {\n            Iterator tmp = *this;\n            ++index;\n            return tmp;\n        }\n\n        Iterator operator--(int)\n        {\n            Iterator tmp = *this;\n            --index;\n            return tmp;\n        }\n\n        bool operator==(Iterator other) const\n        { return seq == other.seq and index == other.index; }\n\n        bool operator!=(Iterator other) const\n        { return not(*this == other); }\n\n    private:\n        const Sequence* seq { };\n        Index index { };\n    };\n\n    template<class T>\n    inline typename Sequence<T>::Iterator\n    Sequence<T>::position(Index i) const\n    { return { this, i }; }\n\n    template<class T>\n    inline typename Sequence<T>::Iterator\n    Sequence<T>::begin() const\n    { return { this, 0 }; }\n\n    template<class T>\n    inline typename Sequence<T>::Iterator\n    Sequence<T>::end() const\n    { return { this, size() }; }\n\n                                // -- Optional<> --\n    // Occasionally, a node has an optional property (e.g. a variable\n    // has an optional initializer).  This class template captures\n    // that commonality and provides a checked access.\n    export template<typename T>\n    struct Optional {\n        constexpr Optional(const T* p = nullptr) : ptr{p} { }\n        constexpr Optional(const T& t) requires std::is_abstract_v<T> : ptr{&t} { }\n        const T& get() const { return *util::check(ptr); }\n        bool is_valid() const { return ptr != nullptr; }\n        explicit operator bool() const { return is_valid(); }\n        template<typename U, bool = std::is_base_of_v<T, U>>\n        operator Optional<U>() const { return { ptr }; }\n    private:\n        const T* ptr;\n    };\n}\n"
  },
  {
    "path": "src/cxx-ipr.cxx",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Module implementation unit for cxx.ipr.\n// Contains out-of-line definitions of functions declared in the module\n// interface whose definitions depend on implementation types from <ipr/impl>.\n//\n// TEMPORARY: This file exists because the implementation layer (<ipr/impl>)\n// is not yet modularized.  Once <ipr/impl> becomes a module, these definitions\n// should move to its module implementation unit.\n\nmodule;\n\n#include <ipr/std-preamble>\n\nmodule cxx.ipr;\n\n// Minimal replica of impl::Node<T> — just enough to define\n// String::empty_string().  The full <ipr/impl> is not included here to\n// avoid duplicate definitions with impl.cxx.\n// TEMPORARY: This workaround disappears when <ipr/impl> is modularized.\nnamespace ipr::impl {\n    template<typename T>\n    struct Node : T {\n        using Interface = T;\n        void accept(ipr::Visitor& v) const final { v.visit(*this); }\n    };\n}\n\nnamespace ipr {\n    const String& String::empty_string()\n    {\n        struct Empty_string final : impl::Node<String> {\n            constexpr util::word_view characters() const final { return u8\"\"; }\n        };\n\n        static constexpr Empty_string empty { };\n        return empty;\n    }\n}\n\n// -- ipr::Visitor --\n// Because Name is a very high-level interface to\n// Identifier, Operator, Conversion, Instantiation and\n// Qualified and these share common very high-level\n// semantics, it is convenient to have the implementation\n// of the corresponding Visitor::visit() functions forward to\n// Visitor::visit(const Name&).  That way, code duplication\n// can be substantially reduced.  The same goes for other\n// sub-hierarchies.\nvoid ipr::Visitor::visit(const Annotation& a) { visit(as<Node>(a)); }\nvoid ipr::Visitor::visit(const Region& r) { visit(as<Node>(r)); }\nvoid ipr::Visitor::visit(const Comment& c) { visit(as<Node>(c)); }\nvoid ipr::Visitor::visit(const String& s) { visit(as<Node>(s)); }\nvoid ipr::Visitor::visit(const Classic& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Identifier& id) { visit(as<Name>(id)); }\nvoid ipr::Visitor::visit(const Suffix& s) { visit(as<Name>(s)); }\nvoid ipr::Visitor::visit(const Operator& op) { visit(as<Name>(op)); }\nvoid ipr::Visitor::visit(const Conversion& conv) { visit(as<Name>(conv)); }\nvoid ipr::Visitor::visit(const Template_id& e) { visit(as<Name>(e)); }\nvoid ipr::Visitor::visit(const Type_id& n) { visit(as<Name>(n)); }\nvoid ipr::Visitor::visit(const Ctor_name& n) { visit(as<Name>(n)); }\nvoid ipr::Visitor::visit(const Dtor_name& n) { visit(as<Name>(n)); }\nvoid ipr::Visitor::visit(const Guide_name& n) { visit(as<Name>(n)); }\n\n// -- Types visiting hooks --\nvoid ipr::Visitor::visit(const Array& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Class& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Closure& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Decltype& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Enum& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const As_type& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Tor& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Function& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Namespace& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Pointer& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Product& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Ptr_to_member& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Qualified& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Reference& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Rvalue_reference& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Sum& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Forall& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Auto& t) { visit(as<Type>(t)); }\nvoid ipr::Visitor::visit(const Union& t) { visit(as<Type>(t)); }\n// -- Expressions visiting hooks --\nvoid ipr::Visitor::visit(const Expr_list& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Overload& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Scope& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Phantom& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Eclipsis& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Lambda& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Requires& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Symbol& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Address& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Array_delete& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Asm& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Complement& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Delete& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Demotion& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Deref& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Enclosure& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Alignof& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Sizeof& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Args_cardinality& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Restriction& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Typeid& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Id_expr& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Label& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Unary_minus& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Materialization& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Not& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Post_decrement& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Post_increment& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Pre_decrement& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Pre_increment& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Promotion& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Read& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Throw& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Unary_plus& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Expansion& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Noexcept& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Rewrite& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Scope_ref& n) { visit(as<Classic>(n)); }\nvoid ipr::Visitor::visit(const Plus& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Plus_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const And& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Array_ref& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Arrow& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Arrow_star& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Bitand& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Bitand_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Bitor& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Bitor_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Bitxor& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Bitxor_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Cast& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Call& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Coercion& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Comma& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Const_cast& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Div& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Div_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Dot& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Dot_star& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Dynamic_cast& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Equal& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Greater& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Greater_equal& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Less& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Less_equal& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Literal& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Member_init& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Modulo& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Modulo_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Mul& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Mul_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Narrow& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Not_equal& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Construction& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Or& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Pretend& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Qualification& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Reinterpret_cast& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Lshift& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Lshift_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Rshift& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Rshift_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Static_cast& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Widen& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Minus& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Minus_assign& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Binary_fold& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Where& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Static_assert& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Instantiation& e) { visit(as<Expr>(e)); }\nvoid ipr::Visitor::visit(const Conditional& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const New& e) { visit(as<Classic>(e)); }\nvoid ipr::Visitor::visit(const Mapping& s) { visit(as<Expr>(s)); }\n\n// -- Directives visiting hooks --\nvoid ipr::Visitor::visit(const Specifiers_spread& d) { visit(as<Directive>(d)); }\nvoid ipr::Visitor::visit(const Structured_binding& d) { visit(as<Directive>(d)); }\nvoid ipr::Visitor::visit(const Using_declaration& d) { visit(as<Directive>(d)); }\nvoid ipr::Visitor::visit(const Using_directive& d) { visit(as<Directive>(d)); }\nvoid ipr::Visitor::visit(const Phased_evaluation& d) { visit(as<Directive>(d)); }\nvoid ipr::Visitor::visit(const Pragma& d) { visit(as<Directive>(d)); }\n\n// -- Statements visiting hooks --\nvoid ipr::Visitor::visit(const Labeled_stmt& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Block& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Ctor_body& e) { visit(as<Stmt>(e)); }\nvoid ipr::Visitor::visit(const Expr_stmt& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const If& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Switch& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const While& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Do& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const For& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const For_in& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Break& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Continue& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Goto& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Return& s) { visit(as<Stmt>(s)); }\nvoid ipr::Visitor::visit(const Handler& s) { visit(as<Stmt>(s)); }\n\n// Forward Visitor::visit() that operates on nodes\n// derived from Decl to whatever derived visitors do\n// for general declarations.\nvoid ipr::Visitor::visit(const Alias& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Base_type& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Bitfield& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Enumerator& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Field& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Fundecl& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Concept& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Parameter& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Parameter_list& l) { visit(as<Node>(l)); }\nvoid ipr::Visitor::visit(const Typedecl& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Template& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const Var& d) { visit(as<Decl>(d)); }\nvoid ipr::Visitor::visit(const EH_parameter& d) { visit(as<Decl>(d)); }\n\n// -- Translation_unit::Visitor --\nvoid ipr::Translation_unit::Visitor::visit(const Module_unit& u) { visit(as<Translation_unit>(u)); }\nvoid ipr::Translation_unit::Visitor::visit(const Interface_unit& u) { visit(as<Translation_unit>(u)); }\n"
  },
  {
    "path": "src/cxx-ipr.ixx",
    "content": "// -*- C++ -*-\n//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n// Primary module interface: cxx.ipr\n// The semantic node hierarchy for the Internal Program Representation.\n\nmodule;\n\n#include <ipr/std-preamble>\n\nexport module cxx.ipr;\nexport import :vocabulary;\nexport import :syntax;\n\nnamespace ipr {\n   // IPR is designed to be regular, fully general enough to\n   //    (1) represent programs written in full Standard C++\n   //        -- except macros -- Standard C, and possibly Fortran\n   //        and other C-like languages;\n   //    (2) be at the basis of semantics-based program analyses\n   //        and transformations;\n   //    (3) be ahead of time, i.e. accommodate future possible\n   //        extensions to C++, e.g. \"concepts\";\n   //    (4) be compiler-neutral, i.e. not the reflection of internal \n   //        data structures of any particular compiler, no matter how popular.\n   //\n   // The \"meta-language\" implemented by IPR is expression-based.  It\n   // does not try to mimic the barnacles that the ISO C++ specification\n   // has grown over decades -- that way lies unwarranted complexity. Rather,\n   // the IPR aims for a regular, general semantics language within which the \n   // various restrictions and irregularities of ISO C++ are accounted for.\n   // The focus is on semantics because that is where the essence of C++ lies.\n   //\n   // IPR nodes \"climbing\" is based on the Visitor Design Pattern.\n   //\n   // IPR class nodes come in two flavors:\n   //     (a) the interface classes, found in this header;\n   //     (b) the implementation classes, found in <ipr/impl>.\n   // The primary reason for this separation is, we don't want consumers of\n   // the library to critically depend on the particular implementations\n   // details of the moment.  Also, it is our intent that the interfaces\n   // could be implemented in various ways depending on the particular\n   // constraints of the target tools.  Furthermore, a given interface class\n   // can admit several implementation classes.\n   //\n   // A third header file <ipr/traversal> offers a set of traversal\n   // facilities.  At the moment, it contains only trivial visitor classes.\n   // A fourth header, <ipr/io>, contains interfaces to input/output\n   // operations.  At the moment, only output in form of XPR is supported.\n   // FIXME: the XPR grammar is out-of-date and is no longer known to capture IPR.\n   //\n   // The interface classes are non-mutating, i.e. there is no way\n   // a client program could modify a node through its interface.\n   // In particular, all member functions of the interface classes\n   // are const member functions.\n   //\n   // There is an additional requirement on IPR nodes:  type nodes\n   // shall have maximal sharing, i.e. be unified.  The design choices\n   // behind that decision are discussed in the paper \"Representing\n   // C++ Directly, Compactly and Efficiently.\"\n   //\n   // Warning:  If you add any new \"leaf\" node type, you need to update\n   //           \"ipr/node-category\" for the numerical mapping.\n\n                                // -- Category_node --\n   // A list of numerical codes in one-to-one correspondence with\n   // IPR node \"interface types\".  In a sufficiently expressive and\n   // efficient type system, we would not need to manually maintain\n   // this list.  This can be seen as an optimization of the traditional\n   // double-dispatch process for determining the dynamic type of a node.\n   export enum class Category_code {\n#include <ipr/node-category>\n   };\n\n   // -- General structural utility types and functions.\n\n   // -- General node category class.\n   export template<Category_code Cat, class T = Expr>\n   struct Category : T {\n   protected:\n      constexpr Category() : T{ Cat } { }\n   };\n\n   // Nesting level of a mapping\n   export enum class Mapping_level : std::size_t { };\n\n   // Position of a declaration in its declarative region\n   export enum class Decl_position : std::size_t { };\n\n   // A parameterization is an abstraction over an entity, charted by a collection of parameters.\n   export template<typename T>\n   struct Parameterization {\n      virtual const Parameter_list& parameters() const = 0;\n      virtual const T& result() const = 0;\n   };\n\n   // -- Logogram --\n   // A class of words (from a C++ input source) standing for themselves, with no particular elaboration.\n   export struct Logogram : Basic_unary<const String&> {\n      const String& what() const { return operand(); }\n      bool operator==(const Logogram& x) const { return &what() == &x.what(); }\n      bool operator!=(const Logogram&) const = default;\n   };\n\n   // -- Calling_convention --\n   // The ISO C++ standards does not explicitly acknowledge function calling conventions, as they\n   // are considered low-level implementation details (beyond the fact that a language linkage is a thing).\n   // However, in practice, those implementation details bubble up (leaky abstraction) into\n   // the system system used by such implementations, in unpleasant ways.  As illustration, just have\n   // a look at the chaos introduced by language linkage in function types.\n   // Note: language linkage is represented separately; see `Linkage`.\n   // An object of this type provides a symbolic representation of a calling convention via an logogram\n   // given by the `name()` operation.\n   export struct Calling_convention {\n      explicit constexpr Calling_convention(const Logogram& l) : conv{l} { }\n      const Logogram& name() const { return conv; }\n      bool operator==(const Calling_convention& x) const { return conv == x.conv; }\n      bool operator!=(const Calling_convention&) const = default;\n   private:\n      const Logogram& conv;\n   };\n\n                                // -- Language_linkage --\n   // An object of this type represents language linkage, e.g., \"C\" in `extern \"C\"'.\n   // The ISO standard mandates at least two language linkages: \"C\" and\n   // \"C++\".  If those were the only language linkages used in practice,\n   // then, we would have just used a 2-valued enum.  However, some C++\n   // implementations do have support for things like \"Java\" language\n   // linkage and whatnot.  Consequently, the most general representation\n   // is adopted in the form of a logogram.  From ISO C++ point of view, language \n   // linkage applies only to function names, variable names, and function types.  \n   // Furthermore, a language linkage applied to a function type is a calling convention.\n   export struct Language_linkage {\n      explicit constexpr Language_linkage(const Logogram& l) : lang{l} { }\n      const Logogram& language() const { return lang; }\n      bool operator==(const Language_linkage& x) const { return lang == x.lang; }\n      bool operator!=(const Language_linkage&) const = default;\n   private:\n      const Logogram& lang;\n   };\n\n   // -- Transfer --\n   // A summary of characteristics of data or control tranfer.  Both language linkage and \n   // calling convention affect how data are transferred to subroutines in function calls.\n   // Furthermore, language linkage also affects linking across translation units.\n   export struct Transfer : Basic_binary<const Language_linkage&, const Calling_convention&> {\n      const Language_linkage& language_linkage() const { return first(); }\n      const Calling_convention& convention() const { return second(); }\n      bool operator==(const Transfer& t) const\n      {\n         return language_linkage() == t.language_linkage() and convention() == t.convention();\n      }\n      bool operator!=(const Transfer&) const = default;\n   };\n\n   // -- Basic_specifier --\n   // A symbolic semantic denotation of an instance of a the C++ grammar for decl-specifier \n   // that is not a defining-type-specifier.  This type is intended to capture the result of\n   // semantic elaboration, not mirror of a syntactic construct.\n   // Note: This symbolic form allows for extensions of decl-specifier beyond those explicitly\n   // listed in the C++ standards.\n   export struct Basic_specifier {\n      constexpr Basic_specifier(const Logogram& l) : spec{&l} { }\n      constexpr const Logogram& logogram() const { return *spec; }\n      constexpr bool operator==(const Basic_specifier&) const = default;\n   private:\n      const Logogram* spec;\n   };\n\n   // -- Specifiers --\n   // An algebraic denotation of sets of basic specifiers.\n   // ISO C++ requires that decl-specifiers can appear in any order in the decl-specifier-seq\n   // of a declaration in the input source program.  Furthermore, any such decl-specifier\n   // can appear at most once. Taken together, those requirements mean that a decl-specifier-seq\n   // is in fact a set of basic specifiers. Therefore, the set of standard basic specifiers act\n   // as a basis of the space of decl-specifier-seqs, and the coordinates or a decl-specifier-seq\n   // are numbers drown from ZZ/2ZZ.  The space of those coordinates is represented by `Specifiers`.\n   // This space is kept abstract to allow extensions beyond the restricted set of speecifiers\n   // listed in the ISO C++ standards.  For example, from the IPR model perspective the ISO C++\n   // access control label `public`, `protected`, `private` are basic specifiers.\n   export enum class Specifiers : std::uintptr_t { };\n\n   // -- Basic_qualifier --\n   // Symbolic semantic denotation of a type qualifier.  Note that a type qualifier is a monadic\n   // type constructor.  The set of ISO C++ type qualifiers is { `const`, `volatile` }.  In practice,\n   // C++ implementations support more type qualifiers, including ISO C's `restrict`.  The name\n   // of the qualifier is indicated by the `logogram()` operation.\n   export struct Basic_qualifier {\n      constexpr Basic_qualifier(const Logogram& l) : qual{&l} { }\n      constexpr const Logogram& logogram() const { return *qual; }\n      constexpr bool operator==(const Basic_qualifier&) const = default;\n   private:\n      const Logogram* qual;\n   };\n\n   // Algebraic operations on symbolic denotations expressed as bitwise operations (i.e. ZZ/2ZZ).\n   export template<util::EnumType T>\n   constexpr T operator|(T a, T b)\n   {\n      return T{util::rep(a) | util::rep(b)};\n   }\n\n   export template<util::EnumType T>\n   constexpr T& operator|=(T& a, T b)\n   {\n      return a = a | b;\n   }\n\n   export template<util::EnumType T>\n   constexpr T operator&(T a, T b)\n   {\n      return T{util::rep(a) & util::rep(b)};\n   }\n\n   export template<util::EnumType T>\n   constexpr T& operator&=(T& a, T b)\n   {\n      return a = a & b;\n   }\n\n   export template<util::EnumType T>\n   constexpr T operator^(T a, T b)\n   {\n      return T{util::rep(a) ^ util::rep(b)};\n   }\n\n   export template<util::EnumType T>\n   constexpr T& operator^=(T& a, T b)\n   {\n      return a = a ^ b;\n   }\n\n   export template<util::EnumType T>\n   constexpr bool implies(T a, T b)\n   {\n      return (a & b) == b;\n   }\n\n                                 // -- Lambda_specifiers --\n   // Declaration specifiers that can appear in a lambda expression.\n   export enum class Lambda_specifiers : std::uint32_t {\n      None = 0,\n      Mutable    = 1 << 0,                   // `mutable` lambda\n      Constexpr  = 1 << 1,                   // `constexpr` lambda\n      Consteval  = 1 << 2,                   // `consteval` lambda\n      ExplicitObject = 1 << 3,               // explicit object parameter `this`.\n   };\n\n                                // -- Module_name --\n   export struct Module_name {\n      virtual const Sequence<Identifier>& stems() const = 0;\n   };\n\n                                // -- Node --\n   // Universal base class of all IPR nodes, in the traditional\n   // OO design sense.  Its primary purpose is to provide a hook\n   // for the Visitor Design Pattern.\n   export struct Node {\n       // the category the complete node object belongs to. In a sufficiently\n       // expressive and efficient type system, we would not need this member,\n       // for it could be read directly from the type of the object.\n      const Category_code category;\n      // Hook for visitor classes.\n      virtual void accept(Visitor&) const = 0;\n   protected:\n      // It is an error to create a complete object of this type.\n      constexpr Node(Category_code c) : category{ c } { }\n      // This class does not have a declared virtual destructor\n      // because we don't plan to have Nodes manage resources, and\n      // therefore no deletion through pointers to this base class.\n      ~Node() = default;\n   };\n\n                                // -- String --\n   // Strings in IPR are immutable, and therefore unified.\n   export struct String : Category<Category_code::String, Node> {\n      using iterator = util::word_view::const_iterator;\n      using Index = std::size_t;\n      virtual util::word_view characters() const = 0;\n      bool operator==(const String& s) const { return this == &s; }\n      bool operator!=(const String&) const = default;\n      Index size() const { return characters().size(); }\n      iterator begin() const { return characters().begin(); }\n      iterator end() const { return characters().end(); }\n      static const String& empty_string();            // dedicated node for an empty string\n   };\n\n                                // -- Comment --\n   // This node represents comments, either C-style or BCPL-style.  Notice\n   // that the comment delimiters are part of Comment::text.\n   export struct Comment : Unary<Category<Category_code::Comment, Node>, const String&> {\n      Arg_type text() const { return operand(); }\n   };\n\n                                // -- Annotation --\n   // A pair \"(name, value)\" used to communicate information\n   // between external tools that use IPR.\n   export struct Annotation : Binary<Category<Category_code::Annotation, Node>,\n                              const String&, const Literal&> {\n      Arg1_type name() const { return first(); }\n      Arg2_type value() const { return second(); }\n   };\n\n                                // -- Region --\n   // A Region node represents a region of program text processed into a sequence\n   // of expressions or directives.  It is mostly useful for capturing the notion of\n   // declarative region, and of scope (in Standard C++ sense).  As such, a genrative\n   // entity that can contain declarations has a region: that region is said to be\n   // owned by that entity.  On the other hand, not all regions are associated with\n   // generative entities.  For example, in\n   //      int phi(int (*f)(double x));\n   // the declarative region of the parameter scope of the function `phi` is owned by \n   // the Decl for `phi`.  However, the declarative region of the parameter scope of\n   // the function parameter (of type 'point to function') is not owned by any entity,\n   // not even the type `int (double)` since types are not generative (types are\n   // unified in the IPR semantics graph!).\n   //\n   // In IPR, we're using a generalized notion of Scope (a sequence of\n   // declarations).  The  notion of Region helps make precise when\n   // some implicit actions like cleanup-ups happen, or nesting of scopes.\n   // The sequence of (generalized) expressions appearing in a Region makes up the\n   // (compile-time) body of that region.  Evaluating that body usually produces the\n   // bindings of that Region.\n   export struct Region : Category<Category_code::Region, Node> {\n      using Location_span = std::pair<Unit_location, Unit_location>;\n      virtual const Location_span& span() const = 0;\n      virtual const Region& enclosing() const = 0;\n      virtual Optional<Expr> owner() const = 0;\n      virtual const Sequence<Expr>& body() const = 0;\n      virtual const Scope& bindings() const = 0;\n      virtual bool global() const = 0;                   // is this region the global region?\n   };\n\n                                // -- Expr --\n   // An expression is a sequence of operators and operands that specifies\n   // a computation.  Such a computation can be static (constant,\n   // object, function, type, template, namespace, concept) or dynamic\n   // (object, function).  Every expression has a type.\n   export struct Expr : Node {\n      virtual const Type& type() const = 0;\n\n   protected:\n      constexpr Expr(Category_code c) : Node{ c } { }\n   };\n\n                                // -- Classic --\n   // Classic expressions are those constructed with operators\n   // directly expressible in standard C++.  Most of those operators\n   // can be overloaded and given user-defined implementation. For\n   // instance,  cout << 2, involves a user-defined operator.  The IPR\n   // representation is not a function call but, something like\n   //\n   //                        << ---> implementation\n   //                       /  \\.\n   //                    cout   2\n   //\n   // where we record the fact that the left-shift operator has a\n   // user-defined meaning.  In IPR, we take the general approach that\n   // all operators can be given user-defined meanings.  Consequently,\n   // we define this class to represent the idea that an expression\n   // can have a user-supplied meaning.\n   //\n   // IPR defines a language that is a superset of C++. The term classic\n   // refers to the C++ language.\n   export struct Classic : Expr {\n      // For an operation that is given a user-supplied meaning, retrieve\n      // the implementation. In non-templated context this returns a\n      // user-supplied declaration. In templated contexts it might return\n      // an overload set.\n      virtual Optional<Expr> implementation() const = 0;\n\n   protected:\n      constexpr Classic(Category_code c) : Expr{ c } { }\n   };\n\n                                // -- Name --\n   // Standard C++ says that 'a name is a use of identifier to designate\n   // an entity'.  In IPR we take the view that a name is a symbol\n   // (or combination thereof) interpreted in their most abstract sense,\n   // i.e. whose meaning depends on binding contexts (Scopes).\n   // That definition accounts for the following (in the standard C++ sense)\n   //    - unqualified-id                    -- Identifier\n   //    - operator-function-id              -- Operator\n   //    - conversion-function-id            -- Conversion\n   //    - template-id                       -- Template_id\n   //    - type-id                           -- Type_id\n   //\n   // Most names are introduced by declarations into a Region.\n   export struct Name : Node {\n      // At the moment, this class is empty because there is no\n      // interesting operation that could be provided here without\n      // imposing too much of implementation details.\n\n   protected:\n      constexpr Name(Category_code c) : Node{ c } { }\n   };\n\n                                // -- Identifier --\n   // An identifier is a sequence of alphanumeric characters starting\n   // with either a letter or an underbar ('_').\n   export struct Identifier : Unary<Category<Category_code::Identifier, Name>, const String&> {\n      // The character sequence of this identifier\n      Arg_type string() const { return operand(); }\n   };\n\n                                // -- Suffix --\n   // The suffix of a user-defined literal is essential just an identifier\n   // with a distinguished interpretation.\n   export struct Suffix : Unary<Category<Category_code::Suffix, Name>, const Identifier&> {\n      Arg_type name() const { return operand(); }\n   };\n\n                                // -- Operator --\n   // For a function operator \"operator @\", \"opname()\" is the \"@\"\n   // sub-part.  Notice that for the array forms of allocation\n   // and deallocation operator functions, this is respectively\n   // \"new[]\" and \"delete[]\", with no space before, between, or after\n   // the square brackets.\n   export struct Operator : Unary<Category<Category_code::Operator, Name>, const String&> {\n      Arg_type opname() const { return operand(); }\n   };\n\n                                // -- Conversion --\n   // A conversion-function-id is the name of a user-defined\n   // conversion function.\n   export struct Conversion : Unary<Category<Category_code::Conversion, Name>, const Type&> {\n      // The type this conversion-function converts values to.\n      Arg_type target() const { return operand(); }\n   };\n\n                                // -- Template_id --\n   // A Template_id is a name of the form\n   //    template-expr<template-argument-list>\n   // which 'applies' a template to a template-argument list.\n   export struct Template_id : Binary<Category<Category_code::Template_id, Name>,\n                               const Expr&, const Expr_list&> {\n      Arg1_type template_name() const { return first(); }\n      Arg2_type args() const { return second(); }\n   };\n\n\n                                // -- Ctor_name --\n   // Standard C++ is not very consistent about constructor\n   // name. On one hand, it says constructors do not have names;\n   // but on another hand, there are clearly cases where they\n   // act as if they had name.  For example, \"S::S\" designates\n   // constructors of class S.  Similarly, if class S has a template\n   // constructor then explicit or partial specializations need ways\n   // to refer to particular set of specializations.  By consistency\n   // with other declarations, and symmetry with destrcutors, we have\n   // introduced this node class.\n   export struct Ctor_name : Unary<Category<Category_code::Ctor_name, Name>, const Type&> {\n      Arg_type object_type() const { return operand(); }\n   };\n\n                                // -- Dtor_name --\n   // This node represent a destructor name of the form \"~T\", where T\n   // is a type.\n   export struct Dtor_name : Unary<Category<Category_code::Dtor_name, Name>, const Type&> {\n      Arg_type object_type() const { return operand(); }\n   };\n                                // -- Guide_name --\n   // This interface class represents the name of a deduction guide.\n   // Deduction guides do not have names in Standard C++, and they cannot\n   // be found by name lookup.  Yet, they are entities (like templates)\n   // that generate compiler-internal instructions (their initializers)\n   // that when executed yield deduced template-arguments.  As such, they\n   // fit the IPR model of a declaration being an introduction of a name\n   // in a scope, with a type and optional initializer.\n   export struct Guide_name : Unary<Category<Category_code::Guide_name, Name>, const Template&> {\n      Arg_type mapping_decl() const { return operand(); }\n   };\n\n                                // -- Type_id --\n   // This node is used for elaborated expressions that designate types.\n   // For example, \"const T*\" is a Type_id , so is \"int (T&)\".\n   export struct Type_id : Unary<Category<Category_code::Type_id, Name>, const Type&> {\n      Arg_type type_expr() const { return operand(); }\n   };\n\n                                // -- Overload --\n   // An overload-set is an expression whose value is the set of all\n   // declarations for a name in a given scope.  An overload-set supports\n   // look-up by type.  The result of such lookup is the canonical declaration\n   // of all declarations with that given type, in that scope.\n   export struct Overload : Category<Category_code::Overload> {\n      virtual Optional<Decl> operator[](const Type&) const = 0;\n   };\n\n                                // -- Scope --\n   // A \"declaration\" is a type specification for a name. A \"Scope\" is\n   // a \"sequence\" of declarations, that additionally supports \"lookup\"\n   // by \"Name\".  A name may have more than one declarations in a given\n   // scope; such a name is said \"overloaded\".  The result of\n   // looking up a name in a scope is a set of all declarations, called\n   // an \"overload set\", for that name in that scope.  An \"overload set\"\n   // is a \"sequence\" of declarations, that additionally supports\n   // lookup by \"Type\".\n   export struct Scope : Category<Category_code::Scope> {\n      using Iterator = Sequence<Decl>::Iterator;\n\n      // The sequence of declarations this scope contain.\n      virtual const Sequence<Decl>& elements() const = 0;\n\n      // Look-up by name returns the overload-set of all declarations,\n      // for the subscripting name, contained in this scope.\n      virtual Optional<Overload> operator[](const Name&) const = 0;\n\n      // How may declarations are there in this Scope.\n      auto size() const { return elements().size(); }\n\n      Iterator begin() const { return elements().begin(); }\n      Iterator end() const { return elements().end(); }\n   };\n\n                                // -- General types --\n   // A type is a collection of constraints and operations that preserve\n   // some invariants.  Since a Type is also an Expression, it has a type.\n   // A type of a type is an instance of a concept - a constraint.  A type \n   // in IPR has a much broader significance than Standard C++ types \n   // (henceforth called \"classic type\").  In particular, in IPR, \"namespace\"\n   // is a type. Similarly, an overload-set has a type.\n   // Some C++ implementations define \"extended built-in\" types with\n   // language linkage, e.g. `extern \"Java\"' or `extern \"Fortran\"', for\n   // interoperating with other languages.  The current representation\n   // includes language linkage as integral part of Type.\n   // Almost all types have \"C++\" language linkage.  The exceptions are: \n   //   a. As_type built with explicit language specification or more generally\n   //      data or control transfer\n   //   b. Function built with explicit language specification or more generally\n   //      data or control transfer\n   export struct Type : Expr {\n      virtual const Name& name() const = 0;\n      virtual const Transfer& transfer() const = 0;\n   protected:\n      constexpr Type(Category_code c) : Expr{ c } { }\n   };\n\n                                // -- Array --\n   // An array-type describes object expressions that designate C-style\n   // homogenous object containers that meet the random-access\n   // requirements.  When an array-type is declared with unspecified\n   // bound, \"bound()\" returns a null-expression.\n   // An alternate design choice would have been to have a predicate\n   // \"has_unknown_bound()\", which when true would make \"bound()\" throw\n   // an exception if accessed.\n   export struct Array : Binary<Category<Category_code::Array, Type>, const Type&> {\n      Arg1_type element_type() const { return first(); }\n      Arg2_type bound() const        { return second(); }\n   };\n\n                                // -- As_type --\n   // This node represents the use of a general expression as\n   // a type.  Such situation arises in cases where a declaration\n   // node can be used to designate a type, as in:\n   //    struct S;\n   //    typedef int count;\n   //    typename T::size_type s = 90;\n   //    template<typename T, T t> ...\n   export struct As_type : Unary<Category<Category_code::As_type, Type>> {\n      Arg_type expr() const { return operand(); }\n   };\n\n                                // -- Decltype --\n   // This node represents query for the \"generalized declared type\"\n   // of an expression.\n   export struct Decltype : Unary<Category<Category_code::Decltype, Type>, const Expr&> {\n      Arg_type expr() const { return operand(); }\n   };\n\n                                // -- Tor --\n   // A node of this class represents a Type for either a constructor or a destructor.\n   // Formally, ISO C++ does not assign types to those special functions; however, a\n   // type-based representation of C++ semantics must assign types to such declarations.\n   // Although a low-level (e.g. ABI-level) representation of a contructor and a destructor\n   // may look at them as just some regular function, and assign them a Function type,\n   // the higher level semantics of C++ is best served by a dedicated type to abstract\n   // over ABI interpretation.\n   export struct Tor : Binary<Category<Category_code::Tor, Type>, const Expr&, const Type&> {\n      // The parameter-list to a tor type.  Always empty for a Standard C++ destructor.\n      Arg1_type source() const { return first(); }\n      // The exception-specification for this tor type.\n      Arg2_type throws() const { return second(); }\n   };\n\n                                // -- Function --\n   // This node class represents a Type that describes an expression\n   // that refers to a function.  In full generality, a template\n   // is a also a function (it describes Type-valued functions);\n   // however, we've made a special node for template.  ISO C++ specifies\n   // that function types have language linkages and two function types\n   // with different language linkages are different.\n   // Furthermore, low-level implementation details such as calling conventions\n   // are accounted for through `Type::transfer()`.\n   export struct Function : Ternary<Category<Category_code::Function, Type>,\n                              const Product&, const Type&, const Expr&> {\n      // Parameter-type-list of a function of this type.  In full\n      // generality, this also describes template signature.\n      Arg1_type source() const { return first(); }\n\n      // return-type\n      Arg2_type target() const { return second(); }\n\n      // Either a boolean expression indicating when values of this type can throw,\n      // or a list of exception types a function of this type may throw.\n      Arg3_type throws() const { return third(); }\n   };\n\n                                // -- Pointer --\n   // A pointer-type is type that describes an Address node.\n   export struct Pointer : Unary<Category<Category_code::Pointer, Type>, const Type&> {\n      // The type of the entity whose address an object of this\n      // type may hold.\n      Arg_type points_to() const { return operand(); }\n   };\n\n                                // -- Product --\n   // A Product represents a Cartesian product of Types.  Pragmatically,\n   // it may be viewed as a Sequence of Types.  It is a Type.\n   export struct Product : Unary<Category<Category_code::Product, Type>, const Sequence<Type>&> {\n      using Index = std::size_t;\n      Arg_type elements() const { return operand(); }\n      auto size() const { return elements().size(); }\n      const Type& operator[](Index i) const { return *elements().position(i); }\n   };\n\n                                // -- Ptr_to_member --\n   // This is for pointer-to-member type, e.g. int A::* or void (A::*)().\n   // A pointer to member really is not a pointer type, it is much closer\n   // a pair of a type and offset that usual pointer types.\n   export struct Ptr_to_member : Binary<Category<Category_code::Ptr_to_member, Type>,\n                                 const Type&, const Type&> {\n      Arg1_type containing_type() const { return first(); }\n      Arg2_type member_type() const { return second(); }\n   };\n\n                                // -- Qualified --\n   // A cv-qualified type.  Representing a cv-qualified type with all\n   // available information attainable in at most one indirection is\n   // very tricky. Consequently, we currently represents a cv-qualified\n   // type with a separate node as a binary operator.  Notice that we\n   // maintain the invariant\n   //     Qualified(cv2, Qualified(cv1, T)) = Qualified(cv1 | cv2, T)\n   // In particular, the Qualified::main_variant is never a Qualified node.\n   // We also maintain the invariant that Qualified::qualifiers is never\n   // Type::None, consequently it is an error to attempt to create such a node.\n   export struct Qualified : Binary<Category<Category_code::Qualified, Type>,\n                             ipr::Qualifiers, const Type&> {\n      Arg1_type qualifiers() const { return first(); }\n      Arg2_type main_variant() const { return second(); }\n   };\n\n                                // -- Reference --\n   // A reference-type describes an expression that acts like an alias\n   // for a object or function.  However, unlike a pointer-type, it is\n   // not an object-type.\n    export struct Reference : Unary<Category<Category_code::Reference, Type>, const Type&> {\n       // The type of the object or function an expression of this\n       // type refers to.\n       Arg_type refers_to() const { return operand(); }\n    };\n\n                                // -- Rvalue_reference --\n   // An rvalue-reference-type to support move semantics.\n    export struct Rvalue_reference : Unary<Category<Category_code::Rvalue_reference, Type>,\n                                    const Type&> {\n       // The type of the object or function an expression of this\n       // type refers to.\n       Arg_type refers_to() const { return operand(); }\n    };\n\n                                // -- Sum --\n   // A Sum type represents a distinct union of types.  This is currently\n   // used only for dynamic exception specification in Function type.\n   export struct Sum : Unary<Category<Category_code::Sum, Type>, const Sequence<Type>&> {\n      using Index = std::size_t;\n      Arg_type elements() const { return operand(); }\n      auto size() const { return elements().size(); }\n      const Type& operator[](Index i) const { return *elements().position(i); }\n   };\n\n                                // -- Forall --\n   // This represents a universally quantified type, parameterized by any compile-time sort;\n   // that is, all values for the parameters must designate compile-time entities.\n   // It is useful for representing the type of a template declaration, and more.  In the near future,\n   // when \"concepts\" are integrated, it will become a Ternary node where the\n   // third operand will represent the \"where-clause\".\n   export struct Forall : Binary<Category<Category_code::Forall, Type>,\n                            const Product&, const Type&> {\n      // The constraints or types of the template-parameters.\n      const Product& source() const { return first(); }\n      // The type of the instantiation result.\n      const Type& target() const { return second(); }\n   };\n\n                                // -- Udt --\n   // Base class for user-defined types Nodes -- factor out common properties.\n   export template<typename T>\n   struct Udt : Type {\n      // The general interface to members of this user-defined type.\n      using Member = T;\n      // The region delimited by the definition of this Udt.\n      virtual const Region& region() const = 0;\n      const Scope& scope() const { return region().bindings(); }\n      virtual const Sequence<Member>& members() const = 0;\n\n   protected:\n      // It is an error to create a node of this type.\n      constexpr Udt(Category_code c) : Type{ c } { }\n   };\n\n                                // -- Namespace --\n   // A Standard C++ namespace is a compile-time accumulative singleton variable\n   // that is initialized with a sequence of declarations.  The type of \n   // such a variable is given by an IPR \"namespace\" type.\n   export struct Namespace : Category<Category_code::Namespace, Udt<Decl>> {\n      const Sequence<Decl>& members() const final { return scope().elements(); }\n   };\n\n                                // -- Class --\n   export struct Class : Category<Category_code::Class, Udt<Decl>> {\n      const Sequence<Decl>& members() const final { return scope().elements(); }\n      virtual const Sequence<Base_type>& bases() const = 0;\n   };\n\n                                // -- Union --\n   export struct Union : Category<Category_code::Union, Udt<Decl>> {\n      const Sequence<Decl>& members() const final { return scope().elements(); }\n   };\n\n                                // -- Enum --\n   // An enumeration is an object-type whose members are named constants\n   // the definitions of which as part of the definition of the enumeration\n   // itself.  By historical accident, enumerators are not \"properly scoped\".\n   // The underlying type of the enumeration is given by `base()`, when explicitly\n   // specified or inferred from the enumerator list.\n   export struct Enum : Category<Category_code::Enum, Udt<Enumerator>> {\n      enum class Kind : std::uint8_t {     // The kind of enum.\n         Legacy,                      // traditional C-style enum\n         Scoped                       // scoped enum (C++11)\n      };\n      virtual Kind kind() const = 0;\n      virtual Optional<Type> base() const = 0;\n   };\n\n                                // -- Auto --\n   export struct Auto : Category<Category_code::Auto, Type> {\n   };\n\n\n   // A capture is a description of how a local entity is referenced in a lambda expression.\n   // It is essentially a pair (Binding_mode, Decl) where the first component tells how the \n   // entity is referenced (by value or by reference), and a declaration that specifies the \n   // declarative semantic properties of the captured entity.\n   // Note: A Capture should not be confused with a Capture_specification: the specification\n   //       is a prescription of how an entity should be captured (either explicitly or implicitly) \n   //       in a lambda, whereas a capture is a result of executing that prescription.\n   export struct Capture {\n      virtual Binding_mode mode() const = 0;\n      virtual const Decl& entity() const = 0;\n   };\n\n                                // -- Closure --\n   // A closure type is the type of a lambda expression, which ISO C++ confusingly requires\n   // to be a non-union class type.  The logical representation in the IPR has it as a distinct\n   // (generative) user-defined type whose members are captures.   Each lambda expression has\n   // its own unique type, even if its members would be otherwise the same.\n   export struct Closure : Category<Category_code::Closure, Udt<Capture>> { };\n\n                                // -- Phantom --\n   // This nodes represents a missing expression, as in the \"bound\" of an array type with\n   // unknown bound, e.g. in \"unsigned char charset[];\", or in an empty expression-statement.\n   // We do not unify Phantom expressions, as two arrays with\n   // unknown bounds may not designate the same type.\n   export struct Phantom : Category<Category_code::Phantom> { };\n\n\n                                // -- Eclipsis --\n   // Representation of the `...' in a unary fold, e.g. `... + e'.\n   // Note: that `...' is not the pack expansion operator.  There is no operand to the `...' here.\n   // While the syntax looks the same, the meaning is really different.  It stands for something\n   // was omitted, hence the name.\n   export struct Eclipsis : Category<Category_code::Eclipsis> { };\n\n   // Semantic description of the variety of lambda capture specifications:\n   //   - default captures: indicated by the squiggles \"=\" (by value), and \"&\" (by reference) at source level\n   //   - implicit object: indicated by \"this\" (by reference), and \"*this\" (by value) at source level\n   //   - named symbols: local enclosing variable, and locally introduced variable (with initializer) at source level\n   export struct Capture_specification {\n      struct Default;                           // default lambda capture specification\n      struct Implicit_object;                   // capture mode of implicit object\n      struct Named;                             // named simple capture; base of Simple and With_initializer\n      struct Enclosing_local;                   // simply named captured local entity\n      struct Binding;                           // capture with initialization\n      struct Expansion;                         // expansion of a lambda capture\n\n      struct Visitor;\n      virtual void accept(Visitor&) const = 0;\n   };\n\n                                // -- Lambda --\n   export struct Lambda : Category<Category_code::Lambda>, Parameterization<Expr> {\n      virtual const Closure& type() const override = 0;           // a lambda is of a (unique) closure type\n      virtual Optional<Type> target() const = 0;                  // return type, optionally specified at source level\n      virtual Optional<Expr> requirement() const = 0;             // declaration constraint possibly involving parameters\n      virtual const Sequence<Attribute>& attributes() const = 0;  // optional attribute-list applying to the lambda\n      virtual Optional<Expr> eh_specification() const = 0;\n      virtual Lambda_specifiers specifiers() const = 0;\n      virtual const Sequence<Capture_specification>& captures() const = 0;\n   };\n\n   // Default lambda capture specification\n   struct Capture_specification::Default : Capture_specification {\n      virtual Binding_mode mode() const = 0;\n   };\n\n   // Lambda capture specification of the implicit object in a non-static member context.\n   // The designation of the capture is defined by how(), where:\n   //   - Binding_mode::Reference means 'this'\n   //   - Binding_mode::Copy means '*this'\n   //   - anything else is invalid at this point.\n   // Note: an alternative design is to introduced a distinct enum for representing the\n   //       designation of the implicit object (say 'This' and 'Self), but that would\n   //       have just obscured the fundamental semantics correspondence.\n   struct Capture_specification::Implicit_object : Capture_specification {\n      virtual Binding_mode how() const = 0;\n   };\n\n   // Base of lambda captures designated by an given name.\n   struct Capture_specification::Named : Capture_specification {\n      virtual const Identifier& name() const = 0;\n      virtual Binding_mode mode() const = 0;\n   };\n\n   // Lambda capture referencing a local entity from the enclosing context.\n   struct Capture_specification::Enclosing_local : Capture_specification::Named {\n      virtual const Decl& declaration() const = 0;\n   };\n\n   // Lambda capture introducing an alias bound to the result of evaluating\n   // an expression in the (local) context of the lambda body.\n   struct Capture_specification::Binding : Capture_specification::Named {\n      virtual const Expr& initializer() const = 0;\n   };\n\n   // Lambda capture expansion of either an enclosing variable pack, or a local binding pack.\n   struct Capture_specification::Expansion : Capture_specification {\n      virtual const Named& what() const = 0;\n   };\n\n   struct Capture_specification::Visitor {\n      virtual void visit(const Default&) = 0;\n      virtual void visit(const Implicit_object&) = 0;\n      virtual void visit(const Enclosing_local&) = 0;\n      virtual void visit(const Binding&) = 0;\n      virtual void visit(const Expansion&) = 0;\n   };\n\n                                // -- Symbol --\n   // Representation of self-evaluating (generalized) expressions, i.e. irreducible expressions.\n   // That includes builtin types, as well as designated special values such as `nullptr'.\n   // Note: A symbol is uniquely identified by the pair (name, type), so a symbol can be `overloaded'.\n   // Symbol nodes are unified, as they are self-evaluating, e.g. core values.\n   export struct Symbol : Unary<Category<Category_code::Symbol>, const Name&> {\n      const Name& name() const { return operand(); }\n   };\n\n                                // -- Address --\n   // Address-of expression -- \"&expr\"\n   export struct Address : Unary<Category<Category_code::Address, Classic>> { };\n\n                                // -- Array_delete --\n   // Array-form of delete-expression --  \"delete[] p\"\n   export struct Array_delete : Unary<Category<Category_code::Array_delete, Classic>> {\n      const Expr& storage() const { return operand(); }\n   };\n\n                                // -- Asm --\n   // An ISO C++ asm-declaration, an expression in IPR.\n   // When evaluated, this expression produces executable instructions or \n   // affects linking behavior. Its type is `void`.\n   // Note: A node of this type is typically an operand of `Phased_evaluation`.\n   export struct Asm : Unary<Category<Category_code::Asm>, const String&> {\n      const String& text() const { return operand(); }\n   };\n\n                                // -- Complement --\n   // Complement-expression -- \"~expr\"\n   export struct Complement : Unary<Category<Category_code::Complement, Classic>> { };\n\n                                // -- Delete --\n   // Delete-expression -- \"delete p\"\n   export struct Delete : Unary<Category<Category_code::Delete, Classic>> {\n      const Expr& storage() const { return operand(); }\n   };\n\n                                // -- Demotion --\n   // Integral or floating point conversion\n   export struct Demotion : Unary<Category<Category_code::Demotion>> { };\n\n                                // -- Deref --\n   // Dereference-expression -- \"*expr\"\n   export struct Deref : Unary<Category<Category_code::Deref, Classic>> { };\n\n                                // -- Enclosure --\n   // Expresion enclosed in matching pair of delimiters.  This might seem purely\n   // syntactical but it also has semantic implications, like when an\n   // argument-dependent lookup should be done or not, or order of evaluation,the accuracy\n   // of an expression evaluation.\n   // Note: an empty brace-init translates to a brace enclosure of a Phantom node.\n   export struct Enclosure : Unary<Category<Category_code::Enclosure>> {\n      virtual Delimiter delimiters() const = 0;\n      const Expr& expr() const { return operand(); }\n   };\n\n                                // -- Expr_list --\n   // A sequence of expressions \"e1, e2, ..., eN\".  This form of expression\n   // is a tuple of expressions.  In particular, an Expr_list is different\n   // from a Comma expression -- where each sub-expression is evaluated,\n   // discarded except the last one.  The type of an Expr_list\n   // is a Product.\n   export struct Expr_list : Unary<Category<Category_code::Expr_list>, const Sequence<Expr>&> {\n      using Index = std::size_t;\n      Arg_type elements() const { return operand(); }\n      auto size() const { return elements().size(); }\n   };\n\n                                // -- Alignof --\n   //  Alignment query of a type, or any expression.\n   export struct Alignof : Unary<Category<Category_code::Alignof>> { };\n\n                                // -- Sizeof --\n   // sizeof-expression -- \"sizeof expr\" or \"sizeof (int)\"\n   export struct Sizeof : Unary<Category<Category_code::Sizeof>> { };\n\n                                // -- Args_cardinality --\n   export struct Args_cardinality : Unary<Category<Category_code::Args_cardinality>> { };\n\n                                // -- Restriction --\n   // Representation of what ISO C++ calls \"requires-clause\", an expression of the form\n   //      `requires` constant-expression\n   // at the input source level.  Not to be confusion with \"requires-expression\".\n   export struct Restriction : Unary<Category<Category_code::Restriction>> { };\n\n                                // -- Noexcept --\n   export struct Noexcept : Unary<Category<Category_code::Noexcept>> { };\n\n                                // -- Typeid --\n   // typeid-expression -- \"typeid (expr)\", or \"typeid (int)\"\n   export struct Typeid : Unary<Category<Category_code::Typeid>> { };\n\n                                // -- Id_expr --\n   // This node represents use of a name to designate an entity.\n   // In general, names are introduced by a declaration.  In a well-formed\n   // fully elaborated program, a use of name refers to exactly one declaration.\n   // However, in a partially elaborated program (e.g. a template definition)\n   // a dependent name may refer to zero, one, or many (overloaded) declarations.\n   export struct Id_expr : Unary<Category<Category_code::Id_expr, Expr>, const Name&> {\n      // The set of declarations the name refers to, at the elaboration point.\n      virtual Optional<Expr> resolution() const = 0;\n\n      Arg_type name() const { return operand(); }\n   };\n\n                                // -- Label --\n   // label-expression.  Appears in goto-statements.\n   export struct Label : Unary<Category<Category_code::Label>, const Identifier&> {\n      Arg_type name() const { return operand(); }\n   };\n\n                                // -- Materialization --\n   // Temporary materialization\n   export struct Materialization : Unary<Category<Category_code::Materialization>> { };\n\n                                // -- Not --\n   // logical-not-expression -- \"!expr\"\n   export struct Not : Unary<Category<Category_code::Not, Classic>> { };\n\n                                // -- Post_decrement --\n   // post-decrement-expression -- \"expr--\".\n   export struct Post_decrement : Unary<Category<Category_code::Post_decrement, Classic>> { };\n\n                                // -- Post_increment --\n   // post-increment-expression -- \"expr++\".\n   export struct Post_increment : Unary<Category<Category_code::Post_increment, Classic>> { };\n\n                                // -- Pre_decrement --\n   // pre-decrement-expression -- \"--expr\".\n   export struct Pre_decrement : Unary<Category<Category_code::Pre_decrement, Classic>> { };\n\n                                // -- Pre_increment --\n   // pre-increment-expression -- \"++expr\".\n   export struct Pre_increment : Unary<Category<Category_code::Pre_increment, Classic>> { };\n\n                                // -- Promotion --\n   // Integral or floating point promotion -- \"(int)'2'\"\n   export struct Promotion : Unary<Category<Category_code::Promotion>> { };\n\n                                // -- Construction --\n   // An expression of the form \"T(e1, e2, .. en)\" or \"T{e1, e2, .. en}\"\n   // where \"T\" is a type and \"ei\"s are expressions.  This is not a function\n   // call -- although syntactically it looks like so.  \"T\" will\n   // be the `type()' of this expression.\n   // The contructor selected for the construction operation is indicated\n   // by implementation, which is inherited from Classic. When the enclosure\n   // is a singleton, the node can also denote a functional cast expression.\n   export struct Construction : Unary<Category<Category_code::Construction, Classic>,\n                               const Enclosure&> {\n      // The sequence of arguments used for this construction\n      Arg_type arguments() const { return operand(); }\n   };\n\n                                // -- Read --\n   // Lvalue-to-rvalue conversion -- \"= var\"\n   export struct Read : Unary<Category<Category_code::Read>> { };\n\n                                // -- Throw --\n   // A node that represents a C++ expression of the form `throw ex'.\n   // As a special case, when exception() is a null-expression, then\n   // this node represents the flow-control \"throw;\", which actually\n   // could be represented by a dedicated statement node, Rethrow for\n   // instance.\n   export struct Throw : Unary<Category<Category_code::Throw, Classic>> {\n      const Expr& exception() const { return operand(); }\n   };\n\n                                // -- Unary_minus --\n   // unary-minus-expression -- \"-expr\"\n   export struct Unary_minus : Unary<Category<Category_code::Unary_minus, Classic>> { };\n\n                                // -- Unary_plus --\n   // unary-plus-expression -- \"+expr\"\n   export struct Unary_plus : Unary<Category<Category_code::Unary_plus, Classic>> { };\n\n                                // -- Expansion --\n   // Pack expansion.  The operand can be both a classic expression\n   // or a type.  Standard C++ does not permit overloading of expansion\n   // operator, but the general IPR model here allows it.\n   export struct Expansion : Unary<Category<Category_code::Expansion, Classic>> { };\n\n                                // -- Rewrite --\n   // Various ISO C++ syntactic constructs are defined - unwwisely -\n   // via translation to more elaborate sequences of tokens or parse trees.\n   // The `source()` is the construct as written in the input source code, and the\n   // `target()` is the internal expression giving meaning to the source.\n   export struct Rewrite : Binary<Category<Category_code::Rewrite>> {\n      const Expr& source() const { return first(); }\n      const Expr& target() const { return second(); }\n      const Type& type() const final { return second().type(); }\n   };\n\n                                // -- Member_selection<> --\n   // This class factorizes the commonalities of various object member\n   // selection operation.\n   export template<Category_code Cat>\n   struct Member_selection : Binary<Category<Cat, Classic>> {\n      const Expr& base() const { return this->first(); }\n      const Expr& member() const { return this->second(); }\n   };\n\n                                // -- Cast_expr<> --\n   // This classes factorizes the commonalities of various cast-expressions\n   export template<Category_code Cat>\n   struct Cast_expr : Binary<Category<Cat, Classic>, const Type&> {\n      // The type() of a cast expression is its first() operand.  However,\n      // we do not define (override) that member here, as it implies two\n      // indirections to get the information.  Therefore, it is better\n      // to define it at the implementation side where we have all the bits\n      // necessary to make it a single indirection.\n\n      const Expr& expr() const { return this->second(); }\n   };\n\n                                // -- Scope_ref --\n   // A qualified name of the form \"scope::member\".\n   // Although the scope resolution operator ('::') in this expression\n   // cannot be overloaded in standard C++ (yet), it is conceptually\n   // dual to the dot operator, for which overloading has been\n   // suggested multiple time with an operational model.  Consequently,\n   // a qualified name is modelled as a classic expression.\n   export struct Scope_ref : Binary<Category<Category_code::Scope_ref, Classic>> {\n      Arg1_type scope() const  { return first(); }\n      Arg2_type member() const { return second(); }\n   };\n\n                                // -- Plus --\n   // Addition-expression -- \"a + b\"\n   export struct Plus : Binary<Category<Category_code::Plus, Classic>> { };\n\n                                // -- Plus_assign --\n   // In-place addition-expression -- \"a += b\"\n   export struct Plus_assign : Binary<Category<Category_code::Plus_assign, Classic>> { };\n\n                                // -- And --\n   // Logical-and-expression -- \"a && b\"\n   export struct And : Binary<Category<Category_code::And, Classic>> { };\n\n                                // -- Array_ref --\n   // This is for an expression that designate a particular slot\n   // in an array expression `array[slot]'.\n   export struct Array_ref : Member_selection<Category_code::Array_ref> { };\n\n                                // -- Arrow --\n   // This node type models object member selection, based on pointer,\n   // using the arrow-notation.  See `Dot'.\n   export struct Arrow : Member_selection<Category_code::Arrow> { };\n\n                                // -- Arrow_star --\n   // Member selection through pointer to member -- \"p->*\"\n   export struct Arrow_star : Member_selection<Category_code::Arrow_star> { };\n\n                                // -- Assign --\n   // Assignment-expression -- \"a = b\"\n   export struct Assign : Binary<Category<Category_code::Assign, Classic>> { };\n\n                                // -- Bitand --\n   // Bit-and-expression -- \"a & b\"\n   export struct Bitand : Binary<Category<Category_code::Bitand, Classic>> { };\n\n                                // -- Bitand_assign --\n   // In-place bit-and-expression -- \"a &= b\"\n   export struct Bitand_assign : Binary<Category<Category_code::Bitand_assign, Classic>> { };\n\n                                // -- Bitor --\n   // Bit-or expression -- \"a | b\"\n   export struct Bitor : Binary<Category<Category_code::Bitor, Classic>> { };\n\n                                // -- Bitor_assign --\n   // In-place bit-or-expression -- \"a |= b\"\n   export struct Bitor_assign : Binary<Category<Category_code::Bitor_assign, Classic>> { };\n\n                                // -- Bitxor --\n   // Exclusive bit-or-expression -- \"a ^ b\"\n   export struct Bitxor : Binary<Category<Category_code::Bitxor, Classic>> { };\n\n                                //  -- Bitxor_assign --\n   // In-place exclusive bit-or-expression -- \"a ^= b\"\n   export struct Bitxor_assign : Binary<Category<Category_code::Bitxor_assign, Classic>> { };\n\n                                //  -- Cast --\n   // An expression of the form \"(type) expr\", representing the\n   // old-style/C-style cast.\n   export struct Cast : Cast_expr<Category_code::Cast> { };\n\n                                // -- Call --\n   // A function call with an argument list.  Notice that in the abstract\n   // this is not really different from an Template_id.  However, having\n   // a separate node means less clutter in codes.\n   export struct Call : Binary<Category<Category_code::Call, Classic>,\n                         const Expr&, const Expr_list&> {\n      Arg1_type function() const  { return first(); }\n      Arg2_type args() const { return second(); }\n   };\n\n                                // -- Coercion --\n   // A generalized type conversion either built-in to the language or\n   // programmatically defined by either constructors or conversion\n   // functions.\n   export struct Coercion : Binary<Category<Category_code::Coercion, Classic>, const Expr&, const Type&> {\n      Arg1_type expr() const { return first(); }\n      Arg2_type target() const { return second(); }\n   };\n\n                                // -- Comma --\n   // comma-expression -- \"a, b\"\n   export struct Comma : Binary<Category<Category_code::Comma, Classic>> { };\n\n                                // -- Const_cast --\n   // const_cast-expression -- \"const_cast<type>(expr)\".\n   export struct Const_cast : Cast_expr<Category_code::Const_cast> { };\n\n                                // -- Div --\n   // Division-expression -- \"a / b\"\n   export struct Div : Binary<Category<Category_code::Div, Classic>> { };\n\n                                //  -- Div_assign --\n   // In-place division-expression -- \"a /= b\"\n   export struct Div_assign : Binary<Category<Category_code::Div_assign, Classic>> { };\n\n                                // -- Dot --\n   // This node type represents a member selection on object using\n   // the dot-notation \"object.member\": both \"object\" and \"member\"\n   // can be general expressions.\n   export struct Dot : Member_selection<Category_code::Dot> { };\n\n                                // -- Dot_star --\n   // An expression of the form \"object.*pm\".\n   export struct Dot_star : Member_selection<Category_code::Dot_star> { };\n\n                                // -- Dynamic_cast --\n   // An expression of the from \"dynamic_cast<type>(expr)\".\n   export struct Dynamic_cast : Cast_expr<Category_code::Dynamic_cast> { };\n\n                                // -- Equal --\n   // Equality-comparison-expression -- \"a == b\"\n   export struct Equal : Binary<Category<Category_code::Equal, Classic>> { };\n\n                                // -- Greater --\n   // greater-comparison-expression -- \"a > b\"\n   export struct Greater : Binary<Category<Category_code::Greater, Classic>> { };\n\n                                // -- Greater_equal --\n   // greater-or-equal-comparison-expression -- \"a >= b\"\n   export struct Greater_equal : Binary<Category<Category_code::Greater_equal, Classic>> { };\n\n                                // -- Less --\n   // less-comparison-expression -- \"a < b\"\n   export struct Less : Binary<Category<Category_code::Less, Classic>> { };\n\n                                // -- Less_equal --\n   // less-equal-comparison-expression -- \"a <= b\"\n   export struct Less_equal : Binary<Category<Category_code::Less_equal, Classic>> { };\n\n                                // -- Literal --\n   // An IPR literal is just like a standard C++ literal.\n   export struct Literal : Binary<Category<Category_code::Literal, Classic>,\n                           const Type&, const String&> {\n      // See comments for the cast operators regarding type().\n\n      // The textual representation of this literal as it appears\n      // in the program text.\n      Arg2_type string() const { return second(); }\n   };\n\n                                // -- Binary_fold --\n   // Representation of a binary fold expression, e.g. `(x + ... + y)'.\n   // The first() operand designates `x', and the second() operand designates `y'.\n   // The operation() is the category code for the operation being folded.\n   export struct Binary_fold : Binary<Category<Category_code::Binary_fold, Classic>> {\n      virtual Category_code operation() const = 0;\n   };\n\n                                // -- Mapping --\n   // This node represents a parameterized expression.\n   // Its type is a Function in case of parameterized classic expression,\n   // and Forall otherwise.\n   export struct Mapping : Category<Category_code::Mapping>, Parameterization<Expr> {\n   };\n\n                                // -- Member_init --\n   // Node that represent a member initialization, in constructor\n   // definition.\n   export struct Member_init : Binary<Category<Category_code::Member_init>> {\n      Arg1_type member() const { return first(); }\n      Arg2_type initializer() const { return second(); }\n   };\n\n                                // -- Minus --\n   // Subtraction-expression -- \"a - b\"\n   export struct Minus : Binary<Category<Category_code::Minus, Classic>> { };\n\n                                //  -- Minus_assign --\n   // In-place subtraction-expression -- \"a -= b\".\n   export struct Minus_assign : Binary<Category<Category_code::Minus_assign, Classic>> { };\n\n                                // -- Modulo --\n   // Modulo-expression -- \"a % b\"\n   export struct Modulo : Binary<Category<Category_code::Modulo, Classic>> { };\n\n                                // -- Modulo_assign --\n   // In-place modulo-expression -- \"a %= b\"\n   export struct Modulo_assign : Binary<Category<Category_code::Modulo_assign, Classic>> { };\n\n                                // -- Mul --\n   // Multiplication-expression -- \"a * b\"\n   export struct Mul : Binary<Category<Category_code::Mul, Classic>> { };\n\n                                // -- Mul_assign --\n   // In-place multiplication-expression -- \"a *= b\"\n   export struct Mul_assign : Binary<Category<Category_code::Mul_assign, Classic>> { };\n\n                                   // -- Narrow --\n   // Checked base to derived class conversion. This is always a non-implicit\n   // conversion and exists to add additional semantic context to otherwise\n   // explicit conversion nodes.\n   export struct Narrow : Binary<Category<Category_code::Narrow>, const Expr&, const Type&> {\n\n      Arg1_type expr() const { return first(); }\n      Arg2_type derived() const { return second(); }\n   };\n\n                                // -- Not_equal --\n   // Inequality-comparison-expression -- \"a != b\"\n   export struct Not_equal : Binary<Category<Category_code::Not_equal, Classic>> { };\n\n                                // -- Or --\n   // logical-or-expression -- \"a || b\"\n   export struct Or : Binary<Category<Category_code::Or, Classic>> { };\n\n                                // -- Pretend --\n   // Generalization of bitcast and reinterpret cast\n   export struct Pretend : Binary<Category<Category_code::Pretend>, const Expr&, const Type&> {\n      Arg1_type expr() const { return first(); }\n      Arg2_type target() const { return second(); }\n   };\n\n                                // -- Qualification --\n   // A conversion that add cv-qualifiers\n   export struct Qualification : Binary<Category<Category_code::Qualification>, const Expr&, Qualifiers> {\n      Arg1_type expr() const { return first(); }\n      Arg2_type qualifiers() const { return second(); }\n   };\n\n                                // -- Reinterpret_cast --\n   // An expression of the form \"reinterpret_cast<type>(expr)\"\n   export struct Reinterpret_cast : Cast_expr<Category_code::Reinterpret_cast> { };\n\n                                // -- Lshift --\n   // left-shift-expression -- \"a << b\"\n   export struct Lshift : Binary<Category<Category_code::Lshift, Classic>> { };\n\n                                // -- Lshift_assign --\n   // In-place left-shift-expression -- \"a <<= b\".\n   export struct Lshift_assign : Binary<Category<Category_code::Lshift_assign, Classic>> { };\n\n                                // -- Rshift --\n   // Right-shift-expression -- \"a >> b\"\n   export struct Rshift : Binary<Category<Category_code::Rshift, Classic>> { };\n\n                                // -- Rshift_assign --\n   // In-place right-shift-expression -- \"a >>= b\"\n   export struct Rshift_assign : Binary<Category<Category_code::Rshift_assign, Classic>> { };\n\n                                // -- Static_cast --\n   // An expression of the form \"static_cast<type>(expr)\".\n   export struct Static_cast : Cast_expr<Category_code::Static_cast> { };\n\n                                // -- Widen --\n   // Derived to base class conversion\n   export struct Widen : Binary<Category<Category_code::Widen>, const Expr&, const Type&> {\n      Arg1_type expr() const { return first(); }\n      Arg2_type base() const { return second(); }\n   };\n\n                                // -- Where --\n   // An expression referencing declarations or restrictions, local to that expression.\n   // The expressions or declarations in `attendant()` are evaluated first, and then\n   // `main()` is evaluated in the dynamic evaluation cone established by `attendant()`.\n   // As usual, variables declared by bindings in `attendant()` are destructed in reverse \n   // order of declarations at the end of their scopes, which occur after the complete\n   // evaluation of `main()`.\n   // Note: An `attendant()` of type `Scope` indicates that the where-expression introduces\n   //       local bindings.\n   export struct Where : Binary<Category<Category_code::Where>> {\n      const Expr& main() const { return first(); }\n      const Expr& attendant() const { return second(); }\n      const Type& type() const final { return main().type(); }\n   };\n\n                                // -- Static_assert --\n   // A static assertion: failure of the `condition()` halts the elaboration phase.\n   // No runtime code is ever generated.  Its type is `bool`.\n   // Note: A node of this type is typically an operand of `Phased_evaluation`.\n   export struct Static_assert : Binary<Category<Category_code::Static_assert>,\n                                 const Expr&, Optional<String>> {\n      const Expr& condition() const { return first(); }\n      virtual Optional<String> message() const { return second(); }\n   };\n\n                                // -- Substitution --\n   // A \"Substitution\" is a mapping of a parameter to an expression (its value). \n   export struct Substitution {\n      virtual const Expr& operator[](const Parameter&) const = 0;\n   };\n\n                                // -- Instantiation --\n   // An instantiation is a computation that substitutes parameters into an expression.\n   // While an implicit specialization of a template is a notorious example of an instantiation,\n   // just about any expression can be instantiated.  For example, a hidden friend function \n   // defined in a class template is typically instantiated, even though it is not itself a \n   // function template; the branches of a `constexpr if` are instantiated.  Consequently,\n   // an Instantiarion is different from a Template_id (a Name).\n   // The result of an instantiation may be cached on the side, or directly stored in this node.\n   export struct Instantiation : Category<Category_code::Instantiation> {\n      virtual const Expr& pattern() const = 0;\n      virtual const Substitution& substitution() const = 0;\n      virtual Optional<Expr> instance() const  = 0;\n      const Type& type() const final { return instance().get().type(); }\n   };\n\n                                // -- Requires --\n   // Representation of a requires-expression.  Despite the presence of `parameters()`, this expression\n   // is not a parameterization of expressions in the conventional sense.  In particular the type of\n   // a requires-expression is never a mapping in any sense.  It is always `bool`.\n   export struct Requires : Category<Category_code::Requires> {\n      virtual const Parameter_list& parameters() const = 0;\n      virtual const Sequence<cxx_form::Requirement>& body() const = 0;\n   };\n\n                                // -- New --\n   // This node represents a new-expression:\n   //    ::_opt new new-placement_opt new-type-id new-initializer_opt\n   //    ::_opt new new-placement_opt ( type-id ) new-initializer_opt\n   // Semantically, this has a binary structure where the first operand\n   // is the placement-list, and the second operand is a construction expression\n   // that indicates the new-type-id or the type-id coupled with the new-initializer if any.\n   // When the new-initializer is missing, the Enclosure of the Contruction has no delimiter\n   // and the arguments of the Enclosure is a Phantom node.\n   // The allocator function is indicated by the implementation().\n   export struct New : Binary<Category<Category_code::New, Classic>,\n                       Optional<Expr_list>, const Construction&> {\n      // This predicate holds if the new-expression explicitly requested a global allocator.\n      virtual bool global_requested() const = 0;\n      Optional<Expr_list> placement() const { return first(); }\n      const Construction& initializer() const { return second(); }\n   };\n\n                                // -- Conditional --\n   // This represents the C++ ternary operator ?:.  In principle, it is redundant\n   //  with both If and Switch nodes from semantics point of view.  However, \n   // it is necessary for representing templated code\n   export struct Conditional : Ternary<Category<Category_code::Conditional, Classic>> {\n      Arg1_type condition() const { return first(); }\n      Arg2_type then_expr() const { return second(); }\n      Arg3_type else_expr() const { return third(); }\n   };\n\n                                // -- Parameter_list --\n   // The sequence of parameter declarations to an abstraction (mapping).  A parameter-list\n   // has a declarative region that covers the entirety of the abstraction it is associated with.\n   // While a parameter-list node is essentially a container, viewing like an expression allows\n   // an operation such as `type()`, yielding a `Product`, that can be useful in constructing the type\n   // of the mapping being parameterized.\n   export struct Parameter_list : Category<Category_code::Parameter_list> {\n      virtual const Region& region() const = 0;\n      virtual Mapping_level level() const = 0;\n      const Product& type() const override = 0;\n      virtual const Sequence<Parameter>& elements() const = 0;\n      auto begin() const { return elements().begin(); }\n      auto end() const { return elements().end(); }\n      auto size() const { return elements().size(); }\n   };\n\n                                // -- Directive --\n   // Standard C++ has grammar hacks where certain constructs are\n   // classified as declarations, by they don't actually declare any name.\n   // Rather, the modify the behavior of the implementation in certain ways.\n   // For example, a using-declaration does not declare a name: it changes\n   // the usual name lookup rules to consider new scopes.  A static-assert\n   // does not declare anything: it halts translation when a certain condition\n   // does not hold; otherwise a no-op.\n   // These constructs are generally known as directives.  They were made\n   // declarations in Standard C++, so that they could appear at non-local \n   // scopes -- where general declarations live. \n   export struct Directive : Expr {\n      virtual Phases phases() const = 0;\n   protected:\n      constexpr Directive(Category_code c) : Expr{ c } { }\n   };\n\n\n                                // -- Directive --\n   // Certain expressions are evaluated at designated phased of translation of a C++ program.\n   // For example, static_assert-declaration (a declaration in ISO C++, but an expression\n   // in IPR) is evaluated at compile-time.  On the other hand, an asm-declaration (again a\n   // declaration in ISO C++, but an expression in the IPR) is generally evaluated at \n   // code-generation time.\n   export struct Phased_evaluation : Category<Category_code::Phased_evaluation, Directive> {\n      const Type& type() const final { return expression().type(); }\n      virtual const Expr& expression() const = 0;\n   };\n\n                                // -- Specifiers_spread --\n   // A directive to spread a decl-specifier-seq over a collection of init-declarators.\n   // - The init-declarators are given by the `targets()` operation.\n   // - The type component of the decl-specifier-seq is given by `type()`.\n   // - The non-type component of the decl-specifier-seq is given by `specifiers()`.\n   export struct Specifiers_spread : Category<Category_code::Specifiers_spread, Directive> {\n      virtual Specifiers specifiers() const = 0;\n      virtual const Sequence<cxx_form::Proclamator>& targets() const = 0;\n   };\n\n                                // -- Structured_binding --\n   // A structured binding is a directive to the compiler to introduce a set of names\n   // (either an Alias or a Var) in the current binding environment by taking apart\n   // the object value designated by the initializer.\n   export struct Structured_binding : Category<Category_code::Structured_binding, Directive> {\n      virtual Specifiers specifiers() const = 0;\n      virtual Binding_mode mode() const = 0;\n      virtual const Sequence<Identifier>& names() const = 0;\n      virtual const Expr& initializer() const = 0;\n      virtual const Sequence<Decl>& bindings() const = 0;\n   };\n\n                                // -- Using_declaration --\n   // A using-declaration is directive that instructs the C++ translator to look up\n   // a set of names ('designator'), and for each declaration in the qualified lookup \n   // result of a designator create a synonymous declaration, subject to constraints.\n   export struct Using_declaration : Category<Category_code::Using_declaration, Directive> {\n      struct Designator;\n      virtual const Sequence<Designator>& designators() const = 0;\n   };\n\n   // A using-declarator: a qualified name, along with a denomination mode.\n   struct Using_declaration::Designator {\n      enum class Mode {\n         Normal      = 0x00,              // Normal interpretation of qualified name lookup\n         Type        = 0x01,              // The qualified name is assumed to name a type\n         Expansion   = 0x02,              // The designator needs expansion\n      };\n\n      Designator(const Scope_ref& p, Mode m) : sr{&p}, md{m} { }\n      const Scope_ref& path() const { return *sr; }\n      Mode mode() const { return md; }\n   private:\n      const Scope_ref* sr;\n      Mode md;\n   };\n\n                                // -- Using_directive --\n   // A standard C++ using-directive or a using-enum-declaration \n   // (nominating additional scopes) for elaboration purposes.\n   // Its type should be \"namespace\" if it nominates a namespace,\n   // or \"enum\" or \"enum class\" if it nominates an enumeration.\n   export struct Using_directive : Category<Category_code::Using_directive, Directive> {\n      virtual const Scope& nominated_scope() const = 0;\n   };\n\n\n                                // -- Pragma --\n   export struct Pragma : Unary<Category<Category_code::Pragma, Directive>, const Sequence<Token>&> {\n      const Sequence<Token>& incantation() const { return operand(); }\n   };\n\n                                // -- Stmt --\n   // The view that a statement is kind of expression does not follow from\n   // Standard C++ specification.  It is a design choice we made based on\n   // the following facts:\n   //    1. We need to have an IPR node that can represent both a\n   //       declaration and an expression.  That need is exemplified\n   //       by constructs like\n   //            if (std::cin >> c) { /* .... */ }\n   //       and\n   //            if (Call* c = dynamic_cast<Call*>(e)) { /* ... */ }\n   //       In the first case we have an expression and in the second\n   //       case we have a declaration.  Therefore, we have a diagram\n   //       that loooks like\n   //\n   //              ,----> E.D. <----,\n   //              |                |\n   //          Expression      Declaration\n   //\n   //\n   //    2. Standard C++ says some declarations are statements, and when\n   //       a declaration declares a variable with initialization, the\n   //       initializer usually requests code execution.  Therefore, we\n   //       chose to say that a declaration is a statement and we get\n   //       a similar diagram\n   //\n   //              ,----> D.S. <----,\n   //              |                |\n   //         Declaration       Statement\n   //\n   //    3. In general, IPR is an expression-based language.\n   //\n   //\n   // When combined, the two diagrams yield\n   //\n   //              ,----> E.D. <---- ----> D.S <----,\n   //              |                |               |\n   //          Expression      Declaration      Statement\n   //\n   //\n   // Somehow, we have to satisfy that equation.  In a previous design\n   // we chose what seemed to be the simplest, i.e. deriving a Statement\n   // from an Expr and a Declaration from a Statement.  Doing so\n   // however led to numerous questions about some very basic operations on\n   // expressions like `arity()' or `type()'.\n   //\n   // In a second design, we derived a Statement from Node and a\n   // Decl from both Expr and Statement.  This led to complications in the\n   // class hierarchy and unnecessary complexities.  Therefore, we're back to\n   // the view that a statement is an expression, with some simplifications.\n   export struct Stmt : Expr {\n      // The location of this statement in its unit.\n      virtual const Unit_location& unit_location() const = 0;\n      virtual const Source_location& source_location() const = 0;\n      virtual const Sequence<Annotation>& annotation() const = 0;\n      virtual const Sequence<Attribute>& attributes() const = 0;\n\n   protected:\n      constexpr Stmt(Category_code c) : Expr{ c } { }\n   };\n\n                                // -- Expr_stmt --\n   // This node class represents an expression statement, e.g.\n   //    std::cout << \"Hello World\" << std::endl;\n   // \"expr()\" is the Expression to evaluate.\n   // The type of the entire statement is the type of the expresion.\n   export struct Expr_stmt : Unary<Category<Category_code::Expr_stmt, Stmt>> {\n      const Type& type() const final { return expr().type(); }\n      Arg_type expr() const { return operand(); }\n   };\n\n                                // -- Labeled_stmt --\n   // This node is for labeled-statement:\n   //   a. identifier : statement\n   //   b. case constant-expression : statement\n   //   c. default : statement\n   // IPR represents that `label() as an expression so that it can\n   // handle \"identifier\", \"case cst-expr\" and \"default\", where cst-expr\n   // is an arbitrary constant-expression.\n   // In scenario (a), the `label()` is a Symbol whose `name()` is the identifier.\n   // The Symbol's `type()` is `void`.\n   // In scenario (b), the `label()` is represented directly by the constant-expression.\n   // In scenario (c), the `label()` is should be `Lexicon::default_value()`. \n   export struct Labeled_stmt : Binary<Category<Category_code::Labeled_stmt, Stmt>,\n                                const Expr&, const Expr&> {\n      const Type& type() const final { return stmt().type(); }\n      const Expr& label() const { return first(); }\n      const Expr& stmt() const { return second(); }\n   };\n\n                                // -- Block --\n   // A Block is any sequence of general expressions bracketed by curly braces.\n   // A block may additionally have exception handlers, in which case it corresponds\n   // to Standard C++ syntax heavy try-block.  Conventional, plain blocks carry\n   // no handlers.\n   export struct Block : Category<Category_code::Block, Stmt> {\n      virtual const Region& region() const = 0;\n      const Sequence<Expr>& body() const { return region().body(); }\n      virtual const Sequence<Handler>& handlers() const = 0;\n      bool plain_block() const { return handlers().size() == 0; }\n   };\n\n                                // -- Ctor_body --\n   // This node represents a constructor \"body\" consisting of:\n   //      (a) member-initializer list, if present; and\n   //      (b) the actual body of the constructor\n   export struct Ctor_body : Binary<Category<Category_code::Ctor_body, Stmt>,\n                             const Expr_list&, const Block&> {\n      Arg1_type inits() const { return first(); }\n      Arg2_type block() const { return second(); }\n   };\n\n                                // -- If\n   // A classic if-statement.\n   export struct If : Ternary<Category<Category_code::If, Stmt>,\n                       const Expr&, const Expr&, Optional<Expr>> {\n      Arg1_type condition() const { return first(); }\n      Arg2_type consequence() const { return second(); }\n      Arg3_type alternative() const { return third(); }\n   };\n\n                                // -- Switch --\n   // A classic switch-statement.\n   export struct Switch : Binary<Category<Category_code::Switch, Stmt>,\n                          const Expr&, const Expr&> {\n      Arg1_type condition() const { return first(); }\n      Arg2_type body() const { return second(); }\n   };\n\n                                // -- While --\n   // A classic while-statement\n   export struct While : Binary<Category<Category_code::While, Stmt>,\n                         const Expr&, const Expr&> {\n      Arg1_type condition() const { return first(); }\n      Arg2_type body() const { return second(); }\n   };\n\n                                // -- Do --\n   // A classic do-statement\n   export struct Do : Binary<Category<Category_code::Do, Stmt>, const Expr&, const Expr&> {\n      Arg1_type condition() const { return first(); }\n      Arg2_type body() const { return second(); }\n   };\n\n                                // -- For --\n   // A classic for-statement\n   export struct For : Category<Category_code::For, Stmt> {\n      virtual const Expr& initializer() const = 0;\n      virtual const Expr& condition() const = 0;\n      virtual const Expr& increment() const = 0;\n      virtual const Expr& body() const = 0;\n   };\n\n                                // -- For_in --\n   export struct For_in : Category<Category_code::For_in, Stmt> {\n      virtual const Var& variable() const = 0;\n      virtual const Expr& sequence() const = 0;\n      virtual const Expr& body() const = 0;\n   };\n\n                                // -- Break --\n   // A classic break-statement.\n   // It has type `void`.\n   export struct Break : Category<Category_code::Break, Stmt> {\n      virtual const Stmt& from() const = 0;\n   };\n\n                                // -- Continue --\n   // A classic continue-statement.\n   // It has type `void`.\n   export struct Continue : Category<Category_code::Continue, Stmt> {\n      virtual const Stmt& iteration() const = 0;\n   };\n\n                                // -- Goto --\n   // A classic goto-statement.\n   // The type of the entire statement is the `type()` of the operand.\n   export struct Goto : Unary<Category<Category_code::Goto, Stmt>> {\n      const Type& type() const final { return target().type(); }\n      Arg_type target() const { return operand(); }\n   };\n\n                                // -- Return --\n   // A classic return-statement.\n   export struct Return : Unary<Category<Category_code::Return, Stmt>> {\n      Arg_type value() const { return operand(); }\n   };\n\n                                // -- Handler --\n   // This represents a catch-clause.  Notice that there is no node\n   // for \"try\" as every Block is implicitly a try-block.  Ideally, we\n   // should have every expression as a \"try-block\".\n   export struct Handler : Category<Category_code::Handler, Stmt> {\n      virtual const EH_parameter& exception() const = 0;\n      virtual const Block& body() const = 0;\n   };\n\n                                // -- Decl --\n   // Only declaration-statements are statements from Standard C++ perspective.\n   // However, we find it simpler just to take the general rule that a declaration\n   //  is a statement. Furthermore, it should be observed that declarations like\n   //   (a) function-definition\n   //   (b) template-declaration\n   //   (c) explicit-instantiation\n   //   (d) explicit-specialization\n   //   (e) linkage-specification\n   //   (f) namespace-definition\n   // are not statement in Standard C++ sense.\n   //\n   // We take the view that all declarations can be parameterized.\n   // Therefore, declaration nodes potentially are instantiations of a\n   // a template given by \"pattern()\", with a set of template-arguments,\n   // given by \"substitutions()\".  A declaration for which we have\n   // an empty substitutions() is either\n   //     (a) a primary template; or\n   //     (b) a non-template declaration.\n   export struct Decl : Stmt {\n      virtual Specifiers specifiers() const = 0;\n      virtual const Language_linkage& language_linkage() const = 0;\n\n      virtual const Name& name() const = 0;\n\n      // The region where the declaration really belongs to.\n      virtual const Region& home_region() const = 0;\n\n      // The region where this declaration appears -- purely lexical.\n      // For many declarations, this is the same as the home region.\n      // Exceptions are invisible friends, member functions defined\n      // outside of their enclosing class or namespaces.\n      virtual const Region& lexical_region() const = 0;\n\n      virtual Optional<Expr> initializer() const = 0;\n\n      // This is the first seen declaration for name() in a given\n      // translation unit.  The master declaration is therefore the\n      // first element of the declaration-set.\n      virtual const Decl& master() const = 0;\n\n      virtual const Sequence<Decl>& decl_set() const = 0;\n\n   protected:\n      constexpr Decl(Category_code c) : Stmt{ c } { }\n   };\n\n                                // -- Template --\n   // This represents a parameterized declaration.  If its\n   // template-parameter list is empty, that means that it is\n   // either an explicit specialization -- if result() has a\n   // non-empty substitutions() -- or a really non-template\n   // declaration  -- if result().substitutions() is empty.\n   // The list of specializations of this template (either\n   // partial or explicit) is given by specializations().\n   export struct Template : Category<Category_code::Template, Decl> {\n      virtual const Template& primary_template() const = 0;\n      virtual const Sequence<Decl>& specializations() const = 0;\n      virtual const Mapping& mapping() const = 0;\n\n      const Parameter_list& parameters() const { return mapping().parameters(); }\n      const Expr& result() const { return mapping().result(); }\n\n      virtual Optional<Template> definition() const = 0;\n   };\n\n                                // -- Enumerator --\n   // This represents a classic enumerator.\n   export struct Enumerator : Category<Category_code::Enumerator, Decl> {\n      virtual Decl_position position() const = 0;\n   };\n\n                                // - Alias --\n   // This represent a alias declaration (e.g. typedef, namespace-alias,\n   // template alias, a binding in a structured binding, etc).\n   // An alias is always initialized -- with what it is an alias for.\n   // The type of an Alias expression is that of its initializer.\n   export struct Alias : Category<Category_code::Alias, Decl> {\n      const Region& lexical_region() const final { return home_region(); }\n   };\n\n                                // -- Base_type --\n   // Each base-specifier in a base-clause morally declares an unnamed\n   // subobject.  We represent that subobject declaration by a Base_type.\n   // For consistency with other non-static members, the name of that\n   // subobject is pretended to be the same as that of the base-class\n   // so that when it appears in a member-initializer list, it can\n   // conveniently be thought of as initialization of that subobject.\n   export struct Base_type : Category<Category_code::Base_type, Decl> {\n      // A base-object is, by definition, unnamed.  However, it\n      // is convenient to refer to it by the name of the corresponding\n      // type -- in C++ tradition.\n      const Name& name() const final { return type().name(); }\n      virtual Decl_position position() const = 0;\n   };\n\n                                // -- Parameter --\n   // A parameter is uniquely characterized by its position in\n   // a parameter list.\n   export struct Parameter : Category<Category_code::Parameter, Decl> {\n      virtual Mapping_level level() const = 0;\n      virtual Decl_position position() const = 0;\n      const Region& lexical_region() const final { return home_region(); }\n      Optional<Expr> default_value() const { return initializer(); }\n   };\n\n                                // -- EH_parameter --\n   // Parameter to an exception handler block.  In many aspects, it functions\n   // like a function parameter, except its initialization is not lexical the\n   // way functional parameters are.  Futhermore, they cannot have default values,\n   // and there is exactly one parameter per handler (unlike functions).\n   export struct EH_parameter : Category<Category_code::EH_parameter, Decl> {\n      Optional<Expr> initializer() const final { return { }; }\n   };\n\n   // -- Semantic traits of a function declaration.\n   export enum class FunctionTraits : std::uint32_t {\n      Nothing  = 0x0,                     // No particular traits\n      Pure     = 1 << 0,                  // pure virtual function\n      Virtual  = 1 << 1,                  // virtual function\n      Static   = 1 << 2,                  // static member-function, NOT linkage\n      Inline   = 1 << 3,                  // inline function\n      Explicit = 1 << 4,                  // function declared `explicit`\n      Constexpr = 1 << 5,                 // constexpr function\n      Consteval = 1 << 6,                 // consteval function\n      ExplicitObject = 1 << 7,            // function with explicit object parameter.\n   };\n\n                                // -- Fundecl --\n   // This node represents a function declaration. Notice that the\n   // exception specification is actually made part of the function type.\n   export struct Fundecl : Category<Category_code::Fundecl, Decl> {\n      virtual FunctionTraits traits() const = 0;\n      virtual Optional<Mapping> mapping() const = 0;\n      virtual const Parameter_list& parameters() const = 0;\n      virtual Optional<Fundecl> definition() const = 0;\n   };\n\n                                // -- Concept --\n   export struct Concept : Category<Category_code::Concept, Decl>, Parameterization<Expr> {\n   };\n\n                                // -- Var --\n   // This represents a variable declaration.  It is also used to\n   // represent a static data member.\n   export struct Var : Category<Category_code::Var, Decl> {\n      virtual Optional<Var> definition() const = 0;\n   };\n\n                                // -- Field --\n   // This node represents a nonstatic data member.\n   export struct Field : Category<Category_code::Field, Decl> {\n      const Region& lexical_region() const final { return home_region(); }\n   };\n\n                                // -- Bitfield --\n   // A bit-field data member.\n   export struct Bitfield : Category<Category_code::Bitfield, Decl> {\n      virtual const Expr& precision() const = 0;\n      const Region& lexical_region() const final { return home_region(); }\n   };\n\n                                // -- Typedecl --\n   // This node class represents a declaration of a user-defined type.\n   export struct Typedecl : Category<Category_code::Typedecl, Decl> {\n      virtual Optional<Typedecl> definition() const = 0;\n   };\n\n                                // -- Translation_unit --\n   export struct Translation_unit {\n      struct Visitor;\n      virtual void accept(Visitor&) const = 0;\n      virtual const ipr::Namespace& global_namespace() const = 0;\n      virtual const Sequence<Module>& imported_modules() const = 0;\n   };\n\n                                // -- Module_unit --\n   export struct Module_unit : Translation_unit {\n      virtual const Module& parent_module() const = 0;\n      virtual const Sequence<Decl>& purview() const = 0;\n   };\n\n                                // -- Interface_unit --\n   export struct Interface_unit : Module_unit {\n      virtual const Sequence<Module>& exported_modules() const = 0;\n      virtual const Sequence<Decl>& exported_declarations() const = 0;\n   };\n\n                                // -- Module --\n   export struct Module {\n      virtual const Module_name& name() const = 0;\n      virtual const Interface_unit& interface_unit() const = 0;\n      virtual const Sequence<Module_unit>& implementation_units() const = 0;\n   };\n\n                                // -- Lexicon --\n   // This class is intended to capture the set of values for the parameters\n   // of the C++ abstract machine.  The most prominent such parameters are\n   // the built-int types of the implementation.  It is expected that a given\n   // tool can inherit from this class and provide access to the full range of\n   // extended types and values that it implements.\n   export struct Lexicon {\n      virtual const Type& void_type() const = 0;               // \"void\"\n      virtual const Type& bool_type() const = 0;               // \"bool\"\n      virtual const Type& char_type() const = 0;               // \"char\"\n      virtual const Type& schar_type() const = 0;              // \"signed char\"\n      virtual const Type& uchar_type() const = 0;              // \"unsigned char\"\n      virtual const Type& wchar_t_type() const = 0;            // \"wchar_t\"\n      virtual const Type& char8_t_type() const = 0;            // \"char8_t\"\n      virtual const Type& char16_t_type() const = 0;           // \"char16_t\"\n      virtual const Type& char32_t_type() const = 0;           // \"char32_t\"\n      virtual const Type& short_type() const = 0;              // \"short\"\n      virtual const Type& ushort_type() const = 0;             // \"unsigned short\"\n      virtual const Type& int_type() const = 0;                // \"int\"\n      virtual const Type& uint_type() const = 0;               // \"unsigned int\"\n      virtual const Type& long_type() const = 0;               // \"long\"\n      virtual const Type& ulong_type() const = 0;              // \"unsigned long\"\n      virtual const Type& long_long_type() const = 0;          // \"long long\"\n      virtual const Type& ulong_long_type() const = 0;         // \"unsigned long long\"\n      virtual const Type& float_type() const = 0;              // \"float\"\n      virtual const Type& double_type() const = 0;             // \"double\"\n      virtual const Type& long_double_type() const = 0;        // \"long double\"\n      virtual const Type& ellipsis_type() const = 0;           // \"...\"\n      virtual const Type& typename_type() const = 0;           // \"typename\"\n      virtual const Type& class_type() const = 0;              // \"class\" or \"struct\"\n      virtual const Type& union_type() const = 0;              // \"union\"\n      virtual const Type& enum_type() const = 0;               // \"enum\" or \"enum class\"\n      virtual const Type& namespace_type() const = 0;          // \"namespace\"\n\n      virtual const Symbol& false_value() const = 0;           // Boolean symbolic constant 'false'\n      virtual const Symbol& true_value() const = 0;            // Boolean symbolic constant 'true'\n      \n      virtual const Symbol& nullptr_value() const = 0;         // \"nullptr\"      -- technically not a parameter\n                                                               // to the C++ abstract machine, but provided as\n                                                               // example of symbolic value representation.\n      virtual const Symbol& default_value() const = 0;         // \"default\" - as initializer for defaulted definition\n                                                               //             and as default value for case in labeled statements.\n      virtual const Symbol& delete_value() const = 0;          // \"delete\" - as initializer in deleted function definitions.\n\n      virtual const Language_linkage& cxx_linkage() const = 0;          // constant for 'extern \"C++\"'\n      virtual const Language_linkage& c_linkage() const = 0;            // constant for 'extern \"C\"'\n\n      virtual Specifiers export_specifier() const = 0;         // `export` specifier.\n      virtual Specifiers static_specifier() const = 0;         // `static` standard specifier.\n      virtual Specifiers extern_specifier() const = 0;         // `extern` standard specifier.\n      virtual Specifiers mutable_specifier() const = 0;        // `mutable` standard specifier.\n      virtual Specifiers constinit_specifier() const = 0;      // `constinit` standard specifier.\n      virtual Specifiers thread_local_specifier() const = 0;   // `thread_local` standard specifier.\n      virtual Specifiers register_specifier() const = 0;       // `register` standard specifier -- banned from C++17 and up.\n      virtual Specifiers inline_specifier() const = 0;         // `inline` standard specifier.\n      virtual Specifiers constexpr_specifier() const = 0;      // `constexpr` standard specifier.\n      virtual Specifiers consteval_specifier() const = 0;      // `consteval` standard specifier.\n      virtual Specifiers virtual_specifier() const = 0;        // `virtual` standard specifier.\n      virtual Specifiers abstract_specifier() const = 0;       // for \" = 0\" virtual functions.\n      virtual Specifiers explicit_specifier() const = 0;       // `explicit` standard specifier.\n      virtual Specifiers friend_specifier() const = 0;         // `friend` standard specifier.\n      virtual Specifiers typedef_specifier() const = 0;        // `typedef` standard specifier.\n      virtual Specifiers public_specifier() const = 0;         // `public` specifier.\n      virtual Specifiers protected_specifier() const = 0;      // `protected` specifier.\n      virtual Specifiers private_specifier() const = 0;        // `private` specifier.\n      virtual Specifiers specifiers(Basic_specifier) const = 0;   // convert a basic specifier to its `Specifiers` coordinates.\n      virtual std::vector<Basic_specifier> decompose(Specifiers) const = 0;   // return the constituents of Specifiers.\n\n      virtual Qualifiers const_qualifier() const = 0;             // `const` cv-qualifier.\n      virtual Qualifiers volatile_qualifier() const = 0;          // `volatile` cv-qualifier.\n      virtual Qualifiers restrict_qualifier() const = 0;          // `restrict` cv-qualifier.\n      virtual Qualifiers qualifiers(Basic_qualifier) const = 0;   // retrieve the algebraic coordinate of a named qualifier.\n      virtual std::vector<Basic_qualifier> decompose(Qualifiers) const = 0;   // retrieve the constituents of Qualifiers.\n   };\n\n                                // -- Visitor --\n   export struct Visitor {\n      virtual void visit(const Node&) = 0;\n\n      virtual void visit(const Annotation&);\n      virtual void visit(const Region&);\n      virtual void visit(const Comment&);\n      virtual void visit(const String&);\n\n      virtual void visit(const Expr&) = 0;\n      virtual void visit(const Classic&);\n\n      virtual void visit(const Name&) = 0;\n      virtual void visit(const Identifier&);\n      virtual void visit(const Suffix&);\n      virtual void visit(const Operator&);\n      virtual void visit(const Conversion&);\n      virtual void visit(const Template_id&);\n      virtual void visit(const Type_id&);\n      virtual void visit(const Ctor_name&);\n      virtual void visit(const Dtor_name&);\n      virtual void visit(const Guide_name&);\n\n      virtual void visit(const Type&) = 0;\n      virtual void visit(const Array&);\n      virtual void visit(const Class&);\n      virtual void visit(const Closure&);\n      virtual void visit(const Decltype&);\n      virtual void visit(const Enum&);\n      virtual void visit(const As_type&);\n      virtual void visit(const Tor&);\n      virtual void visit(const Function&);\n      virtual void visit(const Namespace&);\n      virtual void visit(const Pointer&);\n      virtual void visit(const Ptr_to_member&);\n      virtual void visit(const Product&);\n      virtual void visit(const Qualified&);\n      virtual void visit(const Reference&);\n      virtual void visit(const Rvalue_reference&);\n      virtual void visit(const Sum&);\n      virtual void visit(const Forall&);\n      virtual void visit(const Union&);\n      virtual void visit(const Auto&);\n\n      virtual void visit(const Expr_list&);\n      virtual void visit(const Overload&);\n      virtual void visit(const Scope&);\n      virtual void visit(const Phantom&);\n      virtual void visit(const Eclipsis&);\n      virtual void visit(const Lambda&);\n      virtual void visit(const Requires&);\n\n      virtual void visit(const Symbol&);\n      virtual void visit(const Address&);\n      virtual void visit(const Array_delete&);\n      virtual void visit(const Asm&);\n      virtual void visit(const Complement&);\n      virtual void visit(const Delete&);\n      virtual void visit(const Demotion&);\n      virtual void visit(const Deref&);\n      virtual void visit(const Enclosure&);\n      virtual void visit(const Alignof&);\n      virtual void visit(const Sizeof&);\n      virtual void visit(const Args_cardinality&);\n      virtual void visit(const Restriction&);\n      virtual void visit(const Expr_stmt&);\n      virtual void visit(const Typeid&);\n      virtual void visit(const Id_expr&);\n      virtual void visit(const Label&);\n      virtual void visit(const Not&);\n      virtual void visit(const Materialization&);\n      virtual void visit(const Post_decrement&);\n      virtual void visit(const Post_increment&);\n      virtual void visit(const Pre_decrement&);\n      virtual void visit(const Pre_increment&);\n      virtual void visit(const Promotion&);\n      virtual void visit(const Read&);\n      virtual void visit(const Throw&);\n      virtual void visit(const Unary_minus&);\n      virtual void visit(const Unary_plus&);\n      virtual void visit(const Expansion&);\n      virtual void visit(const Noexcept&);\n\n      virtual void visit(const Rewrite&);\n      virtual void visit(const Scope_ref&);\n      virtual void visit(const And&);\n      virtual void visit(const Array_ref&);\n      virtual void visit(const Arrow&);\n      virtual void visit(const Arrow_star&);\n      virtual void visit(const Assign&);\n      virtual void visit(const Bitand&);\n      virtual void visit(const Bitand_assign&);\n      virtual void visit(const Bitor&);\n      virtual void visit(const Bitor_assign&);\n      virtual void visit(const Bitxor&);\n      virtual void visit(const Bitxor_assign&);\n      virtual void visit(const Cast&);\n      virtual void visit(const Call&);\n      virtual void visit(const Coercion&);\n      virtual void visit(const Comma&);\n      virtual void visit(const Const_cast&);\n      virtual void visit(const Construction&);\n      virtual void visit(const Div&);\n      virtual void visit(const Div_assign&);\n      virtual void visit(const Dot&);\n      virtual void visit(const Dot_star&);\n      virtual void visit(const Dynamic_cast&);\n      virtual void visit(const Equal&);\n      virtual void visit(const Greater&);\n      virtual void visit(const Greater_equal&);\n      virtual void visit(const Less&);\n      virtual void visit(const Less_equal&);\n      virtual void visit(const Literal&);\n      virtual void visit(const Lshift&);\n      virtual void visit(const Lshift_assign&);\n      virtual void visit(const Member_init&);\n      virtual void visit(const Minus&);\n      virtual void visit(const Minus_assign&);\n      virtual void visit(const Modulo&);\n      virtual void visit(const Modulo_assign&);\n      virtual void visit(const Mul&);\n      virtual void visit(const Mul_assign&);\n      virtual void visit(const Narrow&);\n      virtual void visit(const Not_equal&);\n      virtual void visit(const Or&);\n      virtual void visit(const Plus&);\n      virtual void visit(const Plus_assign&);\n      virtual void visit(const Pretend&);\n      virtual void visit(const Qualification&);\n      virtual void visit(const Reinterpret_cast&);\n      virtual void visit(const Rshift&);\n      virtual void visit(const Rshift_assign&);\n      virtual void visit(const Static_cast&);\n      virtual void visit(const Widen&);\n      virtual void visit(const Binary_fold&);\n      virtual void visit(const Where&);\n      virtual void visit(const Static_assert&);\n      virtual void visit(const Instantiation&);\n\n      virtual void visit(const Conditional&);\n      virtual void visit(const New&);\n      virtual void visit(const Mapping&);\n\n      virtual void visit(const Directive&) = 0;\n      virtual void visit(const Specifiers_spread&);\n      virtual void visit(const Structured_binding&);\n      virtual void visit(const Using_declaration&);\n      virtual void visit(const Using_directive&);\n      virtual void visit(const Phased_evaluation&);\n      virtual void visit(const Pragma&);\n\n      virtual void visit(const Stmt&) = 0;\n      virtual void visit(const Labeled_stmt&);\n      virtual void visit(const Block&);\n      virtual void visit(const Ctor_body&);\n      virtual void visit(const If&);\n      virtual void visit(const Switch&);\n      virtual void visit(const While&);\n      virtual void visit(const Do&);\n      virtual void visit(const For&);\n      virtual void visit(const For_in&);\n      virtual void visit(const Break&);\n      virtual void visit(const Continue&);\n      virtual void visit(const Goto&);\n      virtual void visit(const Return&);\n      virtual void visit(const Handler&);\n\n      virtual void visit(const Decl&) = 0;\n      virtual void visit(const Alias&);\n      virtual void visit(const Base_type&);\n      virtual void visit(const Bitfield&);\n      virtual void visit(const Enumerator&);\n      virtual void visit(const Field&);\n      virtual void visit(const Fundecl&);\n      virtual void visit(const Template&);\n      virtual void visit(const Concept&);\n      virtual void visit(const Parameter&);\n      virtual void visit(const Parameter_list&);\n      virtual void visit(const Typedecl&);\n      virtual void visit(const Var&);\n      virtual void visit(const EH_parameter&);\n   };\n\n                                // -- Translation_unit::Visitor --\n   struct Translation_unit::Visitor {\n      virtual void visit(const Translation_unit&) = 0;\n      virtual void visit(const Module_unit&);\n      virtual void visit(const Interface_unit&);\n   };\n}\n\n"
  },
  {
    "path": "src/impl.cxx",
    "content": "//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copyright and license notices.\n//\n\n#include <ipr/std-preamble>\n#include <array>\n#include <bit>\n#include <cassert>\n#include <cstring>\n#include <typeinfo>\n\nimport cxx.ipr;\nimport cxx.ipr.traversal;   // for util::view\n\n#include <ipr/impl>\n\n// -- invisible logogram\n// A invisible logogram is a logogram designated by the empty string.\nnamespace ipr::impl {\n   namespace {\n      struct Invisible_logogram : ipr::Logogram {\n         const ipr::String& operand() const final { return String::empty_string(); }\n      };\n\n      constexpr Invisible_logogram invisible_logo { };\n      \n      // The natural calling convention of a C++ function.\n      constexpr ipr::Calling_convention natural_cc { invisible_logo };\n   }\n}\n\n// -- Known, standard names.\nnamespace ipr::impl {\n    namespace {\n       // Representation of standard names (mostly identifiers) used in\n       // in the internals of the IPR, with standard semantics.\n       struct std_identifier : impl::Node<ipr::Identifier>, ipr::Logogram {\n          constexpr std_identifier(const char8_t* p) : str{p} { }\n          constexpr const impl::String& operand() const final { return str; }\n          constexpr auto text() const { return str.characters(); }\n       private:\n          impl::String str;\n       };\n\n        // A table of statically reserved words used in the internal representation.\n        constexpr std_identifier known_words[] {\n           u8\"...\",\n           u8\"=0\",\n           u8\"C\",\n           u8\"C++\",\n           u8\"auto\",\n           u8\"bool\",\n           u8\"char\",\n           u8\"char16_t\",\n           u8\"char32_t\",\n           u8\"char8_t\",\n           u8\"class\",\n           u8\"const\",\n           u8\"consteval\",\n           u8\"constexpr\",\n           u8\"constinit\",\n           u8\"default\",\n           u8\"delete\",\n           u8\"double\",\n           u8\"enum\",\n           u8\"explicit\",\n           u8\"export\",\n           u8\"extern\",\n           u8\"false\",\n           u8\"float\",\n           u8\"friend\",\n           u8\"inline\",\n           u8\"int\",\n           u8\"long\",\n           u8\"long double\",\n           u8\"long long\",\n           u8\"mutable\",\n           u8\"namespace\",\n           u8\"nullptr\",\n           u8\"private\",\n           u8\"protected\",\n           u8\"public\",\n           u8\"register\",\n           u8\"restrict\",\n           u8\"short\",\n           u8\"signed char\",\n           u8\"static\",\n           u8\"this\",\n           u8\"thread_local\",\n           u8\"true\",\n           u8\"typedef\",\n           u8\"typename\",\n           u8\"union\",\n           u8\"unsigned char\",\n           u8\"unsigned int\",\n           u8\"unsigned long\",\n           u8\"unsigned long long\",\n           u8\"unsigned short\",\n           u8\"virtual\",\n           u8\"void\",\n           u8\"volatile\",\n           u8\"wchar_t\",\n        };\n\n        // Lexicographical less-than comparison between two known words.\n        constexpr bool word_less(const std_identifier& x, const std_identifier& y)\n        {\n           return x.text() < y.text();\n        }\n\n        // Ensure the table of statically known words is lexicographically sorted.\n        static_assert(std::is_sorted(std::begin(known_words), std::end(known_words), word_less));\n\n        // less-than comparator for known words (which are all constexpr data)\n        constexpr auto word_lt = [](auto& x, auto& y) { return x.text() < y; };\n\n        constexpr const auto* word_if_known(util::word_view w)\n        {\n            auto place = std::lower_bound(std::begin(known_words), std::end(known_words), w, word_lt);\n            return place >= std::end(known_words) or place->text() != w ? nullptr : &*place;\n        }\n\n        // Return the String representation for a known word.\n        // Raise an exception otherwise.\n        constexpr const std_identifier& known_word(const char8_t* s)\n        {\n            auto place = word_if_known(s);\n            return place == nullptr \n               ? throw std::domain_error(\"unknown word\")\n               : *place;\n        }\n\n        constexpr auto& internal_string(const char8_t* p) { return known_word(p).operand(); }\n\n        // Known language linkages to all C++ implementations.\n        constexpr Language_linkage c_link { known_word(u8\"C\") };\n        constexpr Language_linkage cxx_link { known_word(u8\"C++\") };\n    }\n\n    const ipr::Language_linkage& c_linkage() { return impl::c_link; }\n}\n\n// -- Standard basic specifiers and qualifiers\nnamespace ipr::impl {\n   namespace {\n      constexpr ipr::Basic_specifier std_specifiers[] {\n         known_word(u8\"=0\"),\n         known_word(u8\"export\"),\n         known_word(u8\"public\"),\n         known_word(u8\"protected\"),\n         known_word(u8\"private\"),\n         known_word(u8\"consteval\"),\n         known_word(u8\"constexpr\"),\n         known_word(u8\"constinit\"),\n         known_word(u8\"explicit\"),\n         known_word(u8\"extern\"),\n         known_word(u8\"friend\"),\n         known_word(u8\"inline\"),\n         known_word(u8\"mutable\"),\n         known_word(u8\"register\"),\n         known_word(u8\"static\"),\n         known_word(u8\"thread_local\"),\n         known_word(u8\"typedef\"),\n         known_word(u8\"virtual\"),\n      };\n\n      // Ensure all basic specifiers are representable with the precision declared for ipr::Specifiers.\n      static_assert(std::size(std_specifiers) < std::bit_width(~util::raw<ipr::Specifiers>{}));\n\n      constexpr ipr::Basic_qualifier std_qualifiers[] {\n         known_word(u8\"const\"),\n         known_word(u8\"volatile\"),\n         known_word(u8\"restrict\"),\n      };\n\n      // Ensure all basic qualifiers are representable with the precision declared for ipr::Qualifiers.\n      static_assert(std::size(std_qualifiers) < std::bit_width(~util::raw<ipr::Qualifiers>{}));\n   }\n}\n\n// -- Natural transfer: C++ language linkage, and natural calling convention.\nnamespace ipr::impl {\n   namespace {\n      struct Natural_transfer : ipr::Transfer {\n         const ipr::Language_linkage& first() const final { return impl::cxx_link; }\n         const ipr::Calling_convention& second() const final { return impl::natural_cc; }\n      };\n\n      constexpr Natural_transfer natural_xfer { };\n   }\n\n   const ipr::Transfer& cxx_transfer() { return natural_xfer; }\n}\n\n// -- Definitions of member functions for specialized implementations of ipr::Transfer.\nnamespace ipr::impl {\n   const ipr::Calling_convention& Transfer_from_linkage::second() const { return impl::natural_cc; }\n\n   const ipr::Language_linkage& Transfer_from_cc::first() const { return impl::cxx_link; }\n}\n\nnamespace ipr::impl {\n   namespace {\n      // Representation of generalized built-in types.  All built-in types have type\n      // \"typename\" and, of course, have C++ linkage.  Because they are known to all\n      // implementations as elementary, they can be directly represented as constants,\n      // therefore reducing initialization or startup time.\n      using Builtin = symbolic_type<std_identifier>;\n\n      enum class Fundamental {\n#define BUILTIN_TYPE(S,N)  S,\n#include \"builtin.def\"\n#undef  BUILTIN_TYPE\n      };\n\n      constexpr Builtin builtins[] {\n#define BUILTIN_TYPE(S,N) Builtin{ known_word(N) },\n#include \"builtin.def\"\n#undef BUILTIN_TYPE\n      };\n\n      constexpr const Builtin& builtin(Fundamental t)\n      {\n         return builtins[static_cast<int>(t)];\n      }\n\n      // Truth value symbolic constants.\n      constexpr Symbol false_cst { known_word(u8\"false\"), builtin(Fundamental::Bool) };\n      constexpr Symbol true_cst { known_word(u8\"true\"), builtin(Fundamental::Bool) };\n\n      // Universal defaulter constant.\n      constexpr Symbol default_cst { known_word(u8\"default\"), builtin(Fundamental::Auto) };\n\n      // Universal deleted constant.  Nothing ever comes out.  Void.\n      constexpr Symbol delete_cst { known_word(u8\"delete\"), builtin(Fundamental::Void) };\n   }\n\n   const ipr::Type& typename_type() { return builtin(Fundamental::Typename); }\n}\n\nnamespace ipr::impl {\n   namespace {\n      // Representation of the `nullptr` symbolic constant.  It defines its own\n      // type as it is a singleton. The type of `nullptr` is defined as the irreducible\n      // type expression `decltype(nullptr)`.  Note that std::nullptr_t is just an\n      // alias for that type, i.e. `std::nullptr_t` is a Decl, not a type.\n      struct Nullptr : impl::Node<ipr::Symbol> {\n         constexpr Nullptr() : typing{*this} { }\n         const ipr::Name& operand() const final { return known_word(u8\"nullptr\"); }\n         const ipr::Decltype& type() const final { return typing; }\n      private:\n         impl::Decltype typing;\n      };\n\n      constexpr Nullptr nullptr_cst { };\n   }\n}\n\nnamespace ipr::util {\n    const ipr::String& string_pool::intern(word_view w)\n    {\n       if (w.empty())\n         return ipr::String::empty_string();\n\n        // For statically known words, just return the statically allocated address.\n        if (const auto p = impl::word_if_known(w))\n            return p->string();\n\n        // Dynamically allocated words are slotted by their hash codes into singly-linked lists.\n        const hash_code h { std::hash<word_view>{ }(w) };\n        auto& bucket = (*this)[h];\n        const auto eq = [&w](auto& x) { return x.characters() == w; };\n        if (const auto p = std::find_if(bucket.begin(), bucket.end(), eq); p != bucket.end())\n            return *p;\n        const auto fresh = strings.make_string(w.data(), w.length());\n        bucket.emplace_front(util::word_view(fresh->data, fresh->length));\n        return bucket.front();\n    }\n}\n\nnamespace ipr::cxx_form::impl {\n   Function_morphism::Function_morphism(const ipr::Region& parent, Mapping_level level)\n      : inputs{ parent, level }\n   { }\n\n   Monadic_constraint* form_factory::make_monadic_constraint(const ipr::Identifier& n)\n   {\n      return monadic_constraints.make(n);\n   }\n\n   Monadic_constraint* form_factory::make_monadic_constraint(const ipr::Expr& s, const ipr::Identifier& n)\n   {\n      return monadic_constraints.make(s, n);\n   }\n\n   Polyadic_constraint* form_factory::make_polyadic_constraint(const ipr::Identifier& n)\n   {\n      return polyadic_constraints.make(n);\n   }\n\n   Polyadic_constraint* form_factory::make_polyadic_constraint(const ipr::Expr& s, const ipr::Identifier& n)\n   {\n      return polyadic_constraints.make(s, n);\n   }\n\n   Simple_requirement* form_factory::make_simple_requirement(const ipr::Expr& x)\n   {\n      return simple_reqs.make(x);\n   }\n\n   Type_requirement* form_factory::make_type_requirement(const ipr::Name& n)\n   {\n      return type_reqs.make(n);\n   }\n\n   Type_requirement* form_factory::make_type_requirement(const ipr::Expr& s, const ipr::Name& n)\n   {\n      return type_reqs.make(s, n);\n   }\n\n   Compound_requirement* form_factory::make_compound_requirement(const ipr::Expr& x)\n   {\n      return compound_reqs.make(x);\n   }\n\n   Nested_requirement* form_factory::make_nested_requirement(const ipr::Expr& x)\n   {\n      return nested_reqs.make(x);\n   }\n\n   Pointer_indirector* form_factory::make_pointer_indirector(ipr::Qualifiers q)\n   {\n      return pointer_indirectors.make(q);\n   }\n\n   Reference_indirector* form_factory::make_reference_indirector(Reference_flavor f)\n   {\n      return reference_indirectors.make(f);\n   }\n\n   Member_indirector* form_factory::make_member_indirector(const ipr::Expr& s, ipr::Qualifiers q)\n   {\n      return member_indirectors.make(s, q);\n   }\n\n   Unqualified_id_species* form_factory::make_unqualified_id_species()\n   {\n      return unqualified_id_species.make();\n   }\n\n   Unqualified_id_species* form_factory::make_unqualified_id_species(const ipr::Name& id)\n   {\n      return unqualified_id_species.make(id);\n   }\n\n   Pack_species* form_factory::make_pack_species()\n   {\n      return pack_species.make();\n   }\n\n   Pack_species* form_factory::make_pack_species(const ipr::Identifier& id)\n   {\n      return pack_species.make(id);\n   }\n\n   Qualified_id_species* form_factory::make_qualified_id_species(const ipr::Expr& s, const ipr::Name& n)\n   {\n      return qualified_id_species.make(s, n);\n   }\n\n   Function_morphism* form_factory::make_function_morphism(const ipr::Region& parent, Mapping_level level)\n   {\n      return function_morphisms.make(parent, level);\n   }\n\n   Array_morphism* form_factory::make_array_morphism()\n   {\n      return array_morphisms.make();\n   }\n\n   Parenthesized_species* form_factory::make_parenthesized_species()\n   {\n      return paren_species.make();\n   }\n\n   Term_declarator* form_factory::make_term_declarator()\n   {\n      return term_declarators.make();\n   }\n\n   Targeted_declarator* form_factory::make_targeted_declarator(const cxx_form::Species_declarator& s, const ipr::Type& t)\n   {\n      return targeted_declarators.make(s, t);\n   }\n\n   Classic_provision* form_factory::make_classic_provision(const cxx_form::Elemental_initializer& x)\n   {\n      return classic_provisions.make(x);\n   }\n\n   Parenthesized_provision* form_factory::make_parenthesized_provision(const ipr::Expr& x)\n   {\n      return paren_provisions.make(x);\n   }\n\n   Braced_provision* form_factory::make_braced_provision()\n   {\n      return braced_provisions.make();\n   }\n\n   Designated_list_provision* form_factory::make_designated_provision()\n   {\n      return designated_provisions.make();\n   }\n\n   Field_designator* form_factory::make_field_designator(const ipr::Identifier& x)\n   {\n      return field_designators.make(x);\n   }\n\n   Slot_designator* form_factory::make_slot_designator(const ipr::Expr& x)\n   {\n      return slot_designators.make(x);\n   }\n}\n\nnamespace ipr::impl {\n      Token::Token(const ipr::String& s, const Source_location& l,\n                   TokenValue v, TokenCategory c)\n            : text{ s }, location{ l }, token_value{ v }, token_category{ c }\n      { }\n\n      const ipr::BasicAttribute&\n      attr_factory::make_basic_attribute(const ipr::Token& t)\n      {\n         return *basics.make(t);\n      }\n\n      const ipr::ScopedAttribute&\n      attr_factory::make_scoped_attribute(const ipr::Token& s, const ipr::Token& m)\n      {\n         return *scopeds.make(s, m);\n      }\n\n      const ipr::LabeledAttribute&\n      attr_factory::make_labeled_attribute(const ipr::Token& l, const ipr::Attribute& a)\n      {\n         return *labeleds.make(l, a);\n      }\n\n      const ipr::CalledAttribute&\n      attr_factory::make_called_attribute(const ipr::Attribute& f, const ipr::Sequence<ipr::Attribute>& s)\n      {\n         return *calleds.make(f, s);\n      }\n\n      const ipr::ExpandedAttribute&\n      attr_factory::make_expanded_attribute(const ipr::Token& t, const ipr::Attribute& a)\n      {\n         return *expandeds.make(t, a);\n      }\n\n      const ipr::FactoredAttribute&\n      attr_factory::make_factored_attribute(const ipr::Token& t, const ipr::Sequence<ipr::Attribute>& s)\n      {\n         return *factoreds.make(t, s);\n      }\n\n      const ipr::ElaboratedAttribute&\n      attr_factory::make_elaborated_attribute(const ipr::Expr& x)\n      {\n         return *elaborateds.make(x);\n      }\n\n      const ipr::Identifier&\n      Enclosing_local_capture_specification::name() const\n      {\n         return *util::check(util::view<ipr::Identifier>(decl.name()));\n      }\n\n      // -- impl::capture_spec_factory --\n      const ipr::Capture_specification::Default&\n      capture_spec_factory::default_capture(Binding_mode m)\n      {\n         return *defaults.make(m);\n      }\n\n      const ipr::Capture_specification::Implicit_object&\n      capture_spec_factory::implicit_object_capture(Binding_mode m)\n      {\n         return *implicits.make(m);\n      }\n\n      const ipr::Capture_specification::Enclosing_local&\n      capture_spec_factory::enclosing_local_capture(const ipr::Decl& d, Binding_mode m)\n      {\n         return *enclosings.make(d, m);\n      }\n\n      const ipr::Capture_specification::Binding&\n      capture_spec_factory::binding_capture(const ipr::Identifier& n, const ipr::Expr& x, Binding_mode m)\n      {\n         return *bindings.make(n, x, m);\n      }\n\n      const ipr::Capture_specification::Expansion&\n      capture_spec_factory::expansion_capture(const ipr::Capture_specification::Named& c)\n      {\n         return *expansions.make(c);\n      }\n\n      const ipr::Sequence<ipr::Identifier>& Module_name::stems() const {\n         return components;\n      }\n\n      // -- impl::New --\n      New::New(Optional<ipr::Expr_list> where, const ipr::Construction& expr)\n            : Classic_binary_expr<ipr::New>{ where, expr }\n      { }\n\n      bool New::global_requested() const { return global; }\n\n      // -------------------------------------\n      // -- master_decl_data<ipr::Template> --\n      // -------------------------------------\n\n      master_decl_data<ipr::Template>::\n      master_decl_data(impl::Overload* ovl, const ipr::Type& t)\n            : Base{this}, overload_entry{t},\n              primary{}, home{}, overload{ovl}\n      { }\n\n      // --------------------\n      // -- impl::Overload --\n      // --------------------\n\n      Overload::Overload(const ipr::Name& n)\n            : name{n}\n      { }\n\n      Optional<ipr::Decl>\n      Overload::operator[](const ipr::Type& t) const\n      {\n         if (auto entry = lookup(t))\n            return { entry->declset.get(0) };                     // Note: first decl is canonical\n         return { };\n      }\n\n      impl::overload_entry*\n      Overload::lookup(const ipr::Type& t) const {\n         return  entries.find(t, node_compare());\n      }\n\n      template<class T>\n      void\n      Overload::push_back(master_decl_data<T>* data) {\n         entries.insert(data, node_compare());\n         masters.push_back(data);\n      }\n\n      // -- Directives --\n      single_using_declaration::single_using_declaration(const ipr::Scope_ref& s, Designator::Mode m)\n         : what{s, m}\n      { }\n\n      Using_directive::Using_directive(const ipr::Scope& s) : scope{s} { }\n\n      namespace {\n         // Helper function for building expression nodes with type assignment.\n         template<typename T, typename... Args>\n         auto make(stable_farm<T>& factory, const Args&... args)\n         {\n            struct Holder {\n               explicit Holder(T* x) : impl{ x } { }\n\n               T* with_type(const ipr::Type& t)\n               {\n                  impl->typing = &t;\n                  return impl;\n               }\n\n               T* with_type(Optional<ipr::Type> t)\n               {\n                  impl->typing = t;\n                  return impl;\n               }\n\n            private:\n               T* impl;\n            };\n\n            return Holder{ factory.make(args...) };\n         }\n      }\n\n      // -----------------\n      // -- impl::Alias --\n      // -----------------\n\n      Alias::Alias() : aliasee{nullptr}\n      { }\n\n      // --------------------\n      // -- impl::Bitfield --\n      // --------------------\n\n      Bitfield::Bitfield() : length{}, init{}\n      { }\n\n      // ---------------------\n      // -- impl::Base_type --\n      // ---------------------\n\n      Base_type::Base_type(const ipr::Type& t, const ipr::Region& r, Decl_position p)\n            : base(t), where(r), scope_pos(p), spec{ }\n      { }\n\n      Optional<ipr::Expr>\n      Base_type::initializer() const {\n         throw std::domain_error(\"impl::Base_type::initializer\");\n      }\n\n      // ----------------------\n      // -- impl::Enumerator --\n      // ----------------------\n\n      Enumerator::Enumerator(const ipr::Name& n, const ipr::Enum& t, Decl_position p)\n            : id{n}, typing{t}, scope_pos{p}, where{}, init{}\n      { }\n\n      // -----------------\n      // -- impl::Field --\n      // -----------------\n\n      Field::Field() : init{}\n      { }\n\n      // -------------------\n      // -- impl::Fundecl --\n      // -------------------\n\n      Fundecl::Fundecl()\n            : data{}, lexreg{}\n      { }\n\n      const ipr::Parameter_list& Fundecl::parameters() const {\n         if (data.index() == 0)\n            return *util::check(data.parameters());\n         return util::check(data.mapping())->parameters();\n      }\n\n      Optional<ipr::Mapping> Fundecl::mapping() const {\n         if (data.index() == 0)\n            return { };\n         return { data.mapping() };\n      }\n\n      Optional<ipr::Expr> Fundecl::initializer() const {\n         if (data.index() == 0)\n            return { };\n         return { data.mapping() };\n      }\n\n      // --------------------\n      // -- impl::Template --\n      // --------------------\n\n      Template::Template() : init{}, lexreg{} { }\n\n      const ipr::Template&\n      Template::primary_template() const {\n         return *util::check(util::check(decl_data.master_data)->primary);\n      }\n\n      const ipr::Sequence<ipr::Decl>&\n      Template::specializations() const {\n         return util::check(decl_data.master_data)->specs;\n      }\n\n      // ---------------------\n      // -- impl::Parameter --\n      // ---------------------\n\n      Parameter::Parameter(const ipr::Name& n, const ipr::Type& t, Decl_position p)\n            :id{n}, typing{t}, pos{p}\n      { }\n\n      // -- impl::EH_parameter\n      EH_parameter::EH_parameter(const ipr::Region& r, const ipr::Name& n, const ipr::Type& t)\n         : id{n}, typing{t}, home{r}\n      { }\n\n      // -- impl::handler_block\n      handler_block::handler_block(const ipr::Region& r) : lexical_region{&r} { }\n\n      // -- impl::Handler\n      Handler::Handler(const ipr::Region& r, const ipr::Name& n, const ipr::Type& t)\n         : eh{r, n, t}, block{eh}\n      { }\n\n      // --------------------\n      // -- impl::Typedecl --\n      // --------------------\n\n      Typedecl::Typedecl() : init{}, lexreg{}\n      { }\n\n      // ---------------\n      // -- impl::Var --\n      // ---------------\n\n      Var::Var() : init{}, lexreg{}\n      { }\n\n      // -----------------\n      // -- impl::Block --\n      // -----------------\n\n      Block::Block(const ipr::Region& pr)\n            : lexical_region(&pr)\n      {\n         lexical_region.owned_by = this;\n      }\n\n      impl::Handler* Block::new_handler(const ipr::Name& n, const ipr::Type& t)\n      {\n         return handler_seq.push_back(lexical_region.enclosing(), n, t);\n      }\n\n      // ---------------\n      // -- impl::For --\n      // ---------------\n\n      For::For() : init{}, cond{}, inc{}, stmt{}\n      { }\n\n      // ------------------\n      // -- impl::For_in --\n      // ------------------\n      For_in::For_in() : var{}, seq{}, stmt{}\n      { }\n\n      // -- impl::Break\n      Break::Break() : stmt{} { }\n\n      const ipr::Type& Break::type() const\n      {\n         return impl::builtin(Fundamental::Void);\n      }\n\n      // -- impl::Continue\n      Continue::Continue() : stmt{} { }\n\n      const ipr::Type& Continue::type() const\n      {\n         return impl::builtin(Fundamental::Void);\n      }\n\n      // -- impl::dir_factory --\n      impl::Specifiers_spread* dir_factory::make_specifiers_spread()\n      {\n         return spreads.make();\n      }\n\n      impl::Structured_binding*\n      dir_factory::make_structured_binding()\n      {\n         return bindings.make();\n      }\n\n      impl::single_using_declaration*\n      dir_factory::make_using_declaration(const ipr::Scope_ref& s, ipr::Using_declaration::Designator::Mode m)\n      {\n         return singles.make(s, m);\n      }\n\n      impl::Using_declaration* dir_factory::make_using_declaration()\n      {\n         return usings.make();\n      }\n\n      impl::Using_directive* dir_factory::make_using_directive(const ipr::Scope& s, const ipr::Type& t)\n      {\n         return make(dirs, s).with_type(t);\n      }\n\n      impl::Phased_evaluation* dir_factory::make_phased_evaluation(const ipr::Expr& e, Phases f)\n      {\n         return phaseds.make(e, f);\n      }\n\n      impl::Pragma* dir_factory::make_pragma()\n      {\n         return pragmas.make();\n      }\n\n      // ------------------------\n      // -- impl::stmt_factory --\n      // ------------------------\n\n      impl::Break* stmt_factory::make_break()\n      {\n         return breaks.make();\n      }\n\n      impl::Continue* stmt_factory::make_continue()\n      {\n         return continues.make();\n      }\n\n      impl::Block*\n      stmt_factory::make_block(const ipr::Region& pr, Optional<ipr::Type> t) {\n         return make(blocks, pr).with_type(t);\n      }\n\n      impl::Ctor_body*\n      stmt_factory::make_ctor_body(const ipr::Expr_list& m,\n                                   const ipr::Block& b) {\n         return ctor_bodies.make(m, b);\n      }\n\n      impl::Expr_stmt*\n      stmt_factory::make_expr_stmt(const ipr::Expr& e) {\n         return expr_stmts.make(e);\n      }\n\n      impl::Goto*\n      stmt_factory::make_goto(const ipr::Expr& e) {\n         return gotos.make(e);\n      }\n\n      impl::Return*\n      stmt_factory::make_return(const ipr::Expr& e) {\n         return returns.make(e);\n      }\n\n      impl::Do* stmt_factory::make_do()\n      {\n         return dos.make();\n      }\n\n      impl::If* stmt_factory::make_if(const ipr::Expr& c, const ipr::Expr& s)\n      {\n         return ifs.make(c, s, nullptr);\n      }\n\n      impl::If*\n      stmt_factory::make_if(const ipr::Expr& c, const ipr::Expr& t, const ipr::Expr& f)\n      {\n         return ifs.make(c, t, &f);\n      }\n\n      impl::Switch* stmt_factory::make_switch()\n      {\n         return switches.make();\n      }\n\n      impl::Labeled_stmt* stmt_factory::make_labeled_stmt(const ipr::Expr& l, const ipr::Expr& s)\n      {\n         return labeled_stmts.make(l, s);\n      }\n\n      impl::While* stmt_factory::make_while()\n      {\n         return whiles.make();\n      }\n\n      impl::For*\n      stmt_factory::make_for() {\n         return fors.make();\n      }\n\n      impl::For_in*\n      stmt_factory::make_for_in() {\n         return for_ins.make();\n      }\n\n      // ----------------\n      // -- impl::Enum --\n      // ----------------\n\n      Enum::Enum(const ipr::Region& r, Kind k)\n            : body(r), enum_kind(k)\n      {\n         body.owned_by = this;\n      }\n\n      const ipr::Type& Enum::type() const { return impl::builtin(Fundamental::Enum); }\n\n      const ipr::Region&\n      Enum::region() const {\n         return body;\n      }\n\n      const ipr::Sequence<ipr::Enumerator>&\n      Enum::members() const {\n         return body.scope.decls.seq;\n      }\n\n      Enum::Kind Enum::kind() const { return enum_kind; }\n\n      impl::Enumerator*\n      Enum::add_member(const ipr::Name& n) {\n         Decl_position pos { members().size() };\n         impl::Enumerator* e = body.scope.push_back(n, *this, pos);\n         e->where = &body;\n         return e;\n      }\n\n      // -- impl::Union\n      Union::Union(const ipr::Region& r) : Udt<ipr::Union>{&r} { }\n\n      const ipr::Type& Union::type() const\n      {\n         return impl::builtin(Fundamental::Union);\n      }\n\n      // -- impl::Namespace\n      Namespace::Namespace(const ipr::Region* r) : Udt<ipr::Namespace>{r} { }\n\n      const ipr::Type& Namespace::type() const\n      {\n         return impl::builtin(Fundamental::Namespace);\n      }\n\n      // -- impl::Class --\n      Class::Class(const ipr::Region& pr)\n            : impl::Udt<ipr::Class>(&pr),\n              base_subobjects(pr)\n      {\n         base_subobjects.owned_by = this;\n      }\n\n      const ipr::Type& Class::type() const\n      {\n         return impl::builtin(Fundamental::Class);\n      }\n\n      const ipr::Sequence<ipr::Base_type>&\n      Class::bases() const {\n         return base_subobjects.scope.decls.seq;\n      }\n\n      impl::Base_type*\n      Class::declare_base(const ipr::Type& t) {\n         Decl_position pos { bases().size() };\n         return base_subobjects.scope.push_back(t, base_subobjects, pos);\n      }\n\n      // -- impl::Closure --\n      Closure::Closure(const ipr::Region& r)\n         : impl::Udt<ipr::Closure>(&r)\n      { }\n\n      const ipr::Type& Closure::type() const\n      {\n         return impl::builtin(Fundamental::Class);\n      }\n\n      // --------------------------\n      // -- impl::Parameter_list --\n      // --------------------------\n\n      Parameter_list::Parameter_list(const ipr::Region& p, Mapping_level l)\n            : parms(p), nesting{ l }\n      { }\n\n      const ipr::Product& Parameter_list::type() const { return parms.scope.type(); }\n\n      const ipr::Region& Parameter_list::region() const { return parms; }\n\n      const ipr::Sequence<ipr::Parameter>&\n      Parameter_list::elements() const {\n         return parms.scope.decls.seq;\n      }\n\n      impl::Parameter*\n      Parameter_list::add_member(const ipr::Name& n, const ipr::Type& t)\n      {\n         Decl_position pos { parms.scope.size() } ;\n         impl::Parameter* param = parms.scope.push_back(n, t, pos);\n         param->where = this;\n         return param;\n      }\n\n      // -- Named comparison function for implementation details purposes.\n      inline int compare(const ipr::Calling_convention& x, const ipr::Calling_convention& y)\n      {\n         return impl::compare(x.name(), y.name());\n      }\n\n      inline int compare(const ipr::Transfer& x, const ipr::Transfer& y)\n      {\n         if (auto cmp = impl::compare(x.language_linkage(), y.language_linkage()))\n            return cmp;\n         return impl::compare(x.convention(), y.convention());\n      }\n\n      // ------------------------\n      // -- impl::type_factory --\n      // ------------------------\n\n      struct unary_compare {\n         int operator()(const ipr::Node& lhs, const ipr::Node& rhs) const\n         {\n            return impl::compare(lhs, rhs);\n         }\n\n         template<class T>\n         int operator()(const node_ref<T>& lhs, const ipr::Node& rhs) const\n         {\n            return impl::compare(lhs.node, rhs);\n         }\n\n         template<class T>\n         int operator()(const ipr::Node& lhs, const node_ref<T>& rhs) const\n         {\n            return impl::compare(lhs, rhs.node);\n         }\n\n         template<class T>\n         int operator()(const impl::Basic_unary<T>& lhs,\n                        const typename ipr::Basic_unary<T>::Arg_type& rhs) const\n         {\n            return impl::compare(lhs.rep, rhs);\n         }\n\n         template<class T>\n         int operator()(const typename ipr::Basic_unary<T>::Arg_type& lhs,\n                        const impl::Basic_unary<T>& rhs) const\n         {\n            return impl::compare(lhs, rhs.rep);\n         }\n      };\n\n      struct unary_lexicographic_compare {\n         template<class T>\n         int operator()(const impl::Basic_unary<T>& lhs,\n                        const ipr::Sequence<ipr::Type>& rhs) const\n         {\n            return util::lexicographical_compare()\n               (lhs.rep.begin(), lhs.rep.end(),\n                rhs.begin(), rhs.end(), unary_compare());\n         }\n\n         template<class T>\n         int operator()(const ipr::Sequence<ipr::Type>& lhs,\n                        const impl::Basic_unary<T>& rhs) const\n         {\n            return util::lexicographical_compare()\n               (lhs.begin(), lhs.end(),\n                rhs.rep.begin(), rhs.rep.end(), unary_compare());\n         }\n\n         template<class T>\n         int operator()(const ref_sequence<T>& lhs,\n                        const ref_sequence<T>& rhs) const\n         {\n            return util::lexicographical_compare()\n               (lhs.begin(), lhs.end(),\n                rhs.begin(), rhs.end(), unary_compare());\n         }\n      };\n\n\n      inline bool\n      operator==(const ipr::Node& lhs, const ipr::Node& rhs)\n      {\n         return &lhs == &rhs;\n      }\n\n      struct binary_compare {\n         template<class T>\n         int operator()(const impl::Basic_binary<T>& lhs,\n                        const typename impl::Basic_binary<T>::Rep& rhs) const\n         {\n            if (int cmp = impl::compare(lhs.rep.first, rhs.first))\n               return cmp;\n            return impl::compare(lhs.rep.second, rhs.second);\n         }\n\n         template<class T>\n         int operator()(const typename impl::Basic_binary<T>::Rep lhs,\n                         const impl::Basic_binary<T>& rhs) const\n         {\n            if (int cmp = compare(lhs.first, rhs.rep.first))\n               return cmp;\n            return impl::compare(lhs.second, rhs.rep.second);\n         }\n      };\n\n      struct id_compare\n      {\n          int operator()(const ipr::Identifier& lhs, const ipr::String& rhs) const\n          {\n              return impl::compare(lhs.string(), rhs);\n          }\n\n          int operator()(const ipr::String& lhs, const ipr::Identifier& rhs) const\n          {\n              return impl::compare(lhs, rhs.string());\n          }\n      };\n\n\n      // >>>> Yuriy Solodkyy: 2008/07/10\n      // This comparison would be used to unify Unary nodes: on LHS we would be\n      // called with a type for which Pointer (Reference/sizeof etc.) is created,\n      // on RHS we would be called with already allocated Pointer types. Thus we\n      // have to check whether any of the existing Pointer types does not already\n      // have a points_to (its operand()) equal to the type in LHS.\n      struct unified_type_compare\n      {\n          template<class Cat, class Operand>\n          int operator()(const ipr::Unary<Cat,Operand>& lhs, const ipr::Type& rhs) const\n          {\n              return impl::compare(lhs.operand(), rhs);\n          }\n      };\n      // <<<< Yuriy Solodkyy: 2008/07/10\n\n      const ipr::Transfer& type_factory::get_transfer_from_linkage(const ipr::Language_linkage& l)\n      {\n         constexpr auto cmp = [](auto& x, auto& y) { return impl::compare(x.language_linkage(), y); };\n         return *xfer_links.insert(l, cmp);\n      }\n\n      const ipr::Transfer& type_factory::get_transfer_from_convention(const ipr::Calling_convention& c)\n      {\n         constexpr auto cmp = [](auto& x, auto& y) { return impl::compare(x.convention(), y); };\n         return *xfer_ccs.insert(c, cmp);\n      }\n\n      const ipr::Transfer& type_factory::get_transfer(const ipr::Language_linkage& l, const ipr::Calling_convention& c)\n      {\n         if (l == impl::cxx_link)\n            return get_transfer_from_convention(c);\n         else if (c == impl::natural_cc)\n            return get_transfer_from_linkage(l);\n\n         using Rep = impl::Transfer::Rep;\n         return *xfers.insert(Rep{l, c}, binary_compare{});\n      } \n\n      const ipr::Array& type_factory::get_array(const ipr::Type& t, const ipr::Expr& b)\n      {\n         using rep = impl::Array::Rep;\n         return *arrays.insert(rep{ t, b }, binary_compare());\n      }\n\n      const ipr::Qualified&\n      type_factory::get_qualified(ipr::Qualifiers q, const ipr::Type& t)\n      {\n         // It is an error to call this function if there is no real\n         // qualified.\n         if (q == ipr::Qualifiers{})\n            throw std::domain_error\n               (\"type_factoy::get_qualified: no qualifier\");\n\n         using rep = impl::Qualified::Rep;\n         return *qualifieds.insert(rep{ q, t }, binary_compare());\n      }\n\n      const ipr::Decltype& type_factory::get_decltype(const ipr::Expr& e)\n      {\n         if (physically_same(e, impl::nullptr_cst))\n            return impl::nullptr_cst.type();\n         return *decltypes.make(e);\n      }\n\n      const ipr::As_type& type_factory::get_as_type(const ipr::Identifier& id)\n      {\n         for (auto& t : impl::builtins) {\n            if (physically_same(t.name(), id))\n               return t;\n         }\n         return *extendeds.insert(id, unary_compare());\n      }\n\n      const ipr::As_type& type_factory::get_as_type(const ipr::Expr& e)\n      {\n         return *type_refs.insert(e, unary_compare());\n      }\n\n      const ipr::As_type&\n      type_factory::get_as_type(const ipr::Expr& e, const ipr::Transfer& t)\n      {\n         if (t == impl::cxx_transfer())\n            return get_as_type(e);\n\n         using T = impl::As_type_with_transfer;\n         struct Comparator {\n            int operator()(const T& x, const T::Rep& y) const\n            {\n               if (auto cmp = impl::compare(x.expr(), y.expr))\n                  return cmp;\n               return impl::compare(x.transfer(), y.xfer);\n            }\n\n            int operator()(const T::Rep& x, const T& y) const\n            {\n               return -(*this)(y, x);\n            }\n         };\n         return *type_xfers.insert(T::Rep{e, t}, Comparator{ });\n      }\n\n      struct ternary_compare {\n         template<class T>\n         int operator()(const Ternary<T>& lhs,\n                        const typename Ternary<T>::Rep& rhs) const\n         {\n            if (int cmp = impl::compare(lhs.rep.first, rhs.first))\n               return cmp;\n            if (int cmp = impl::compare(lhs.rep.second, rhs.second))\n               return cmp;\n            return compare(lhs.rep.third, rhs.third);\n         }\n\n         template<class T>\n         int operator()(const typename Ternary<T>::Rep& lhs,\n                        const Ternary<T>& rhs) const\n         {\n            if (int cmp = impl::compare(lhs.first, rhs.rep.first))\n               return cmp;\n            if (int cmp = impl::compare(lhs.second, rhs.rep.second))\n               return cmp;\n            return impl::compare(lhs.third, rhs.rep.third);\n         }\n      };\n\n      const ipr::Tor& type_factory::get_tor(const ipr::Product& s, const ipr::Sum& e)\n      {\n         using rep = impl::Tor::Rep;\n         return *tors.insert(rep{ s, e }, binary_compare());\n      }\n\n      const ipr::Function& type_factory::get_function(const ipr::Product& s, const ipr::Type& t)\n      {\n         return get_function(s, t, impl::false_cst);\n      }\n\n      const ipr::Function&\n      type_factory::get_function(const ipr::Product& s, const ipr::Type& t, const ipr::Transfer& l)\n      {\n         return get_function(s, t, impl::false_cst, l);\n      }\n\n      const ipr::Function&\n      type_factory::get_function(const ipr::Product& s, const ipr::Type& t,\n                                 const ipr::Expr& e)\n      {\n         using rep = impl::Function::Rep;\n         return *functions.insert(rep{ s, t, e }, ternary_compare());\n      }\n\n      const ipr::Function&\n      type_factory::get_function(const ipr::Product& s, const ipr::Type& t,\n                                 const ipr::Expr& e, const ipr::Transfer& l)\n      {\n         if (l == impl::cxx_transfer())\n            return get_function(s, t, e);\n\n         using T = impl::Function_with_transfer;\n         struct Comparator {\n            int operator()(const T& x, const T::Rep& y) const\n            {\n               if (auto cmp = impl::compare(x.source(), y.source))\n                  return cmp;\n               if (auto cmp = impl::compare(x.target(), y.target))\n                  return cmp;\n               if (auto cmp = impl::compare(x.throws(), y.throws))\n                  return cmp;\n               return compare(x.transfer(), y.xfer);\n            }\n\n            int operator()(const T::Rep& x, const T& y) const\n            {\n               return -(*this)(y, x);\n            }\n         };\n\n         return *fun_xfers.insert(T::Rep{ s, t, e, l }, Comparator{ });\n      }\n\n      const ipr::Pointer& type_factory::get_pointer(const ipr::Type& t)\n      {\n         // >>>> Yuriy Solodkyy: 2008/07/10\n         // Fixed pointer comparison for unification\n         return *pointers.insert(t, unified_type_compare());\n         // <<<< Yuriy Solodkyy: 2008/07/10\n      }\n\n      const ipr::Product& type_factory::get_product(const ipr::Sequence<ipr::Type>& seq)\n      {\n         return *products.insert(seq, unary_lexicographic_compare());\n      }\n\n      const ipr::Product& type_factory::get_product(const Warehouse<ipr::Type>& seq)\n      {\n         return get_product(*type_seqs.insert(seq.rep(), unary_lexicographic_compare()));\n      }\n\n      const ipr::Ptr_to_member&\n      type_factory::get_ptr_to_member(const ipr::Type& c, const ipr::Type& t)\n      {\n         using rep = impl::Ptr_to_member::Rep;\n         return *member_ptrs.insert(rep{ c, t }, binary_compare());\n      }\n\n      const ipr::Reference& type_factory::get_reference(const ipr::Type& t)\n      {\n         return *references.insert(t, unified_type_compare());\n      }\n\n      const ipr::Rvalue_reference& type_factory::get_rvalue_reference(const ipr::Type& t)\n      {\n         return *refrefs.insert(t, unified_type_compare());\n      }\n\n      const ipr::Sum& type_factory::get_sum(const ipr::Sequence<ipr::Type>& seq)\n      {\n         return *sums.insert(seq, unary_lexicographic_compare());\n      }\n\n      const ipr::Sum& type_factory::get_sum(const Warehouse<ipr::Type>& seq)\n      {\n         return get_sum(*type_seqs.insert(seq.rep(), unary_lexicographic_compare()));\n      }\n\n      const ipr::Forall& type_factory::get_forall(const ipr::Product& s, const ipr::Type& t)\n      {\n         using rep = impl::Forall::Rep;\n         return *foralls.insert(rep{ s, t }, binary_compare());\n      }\n\n      const ipr::Auto& type_factory::get_auto()\n      {\n         return *autos.make();\n      }\n\n      impl::Enum* type_factory::make_enum(const ipr::Region& pr, Enum::Kind k)\n      {\n         return enums.make(pr, k);\n      }\n\n      impl::Class* type_factory::make_class(const ipr::Region& pr)\n      {\n         return classes.make(pr);\n      }\n\n      impl::Union* type_factory::make_union(const ipr::Region& pr)\n      {\n         return unions.make(pr);\n      }\n\n      impl::Namespace* type_factory::make_namespace(const ipr::Region& pr)\n      {\n         return namespaces.make(&pr);\n      }\n\n      impl::Closure* type_factory::make_closure(const ipr::Region& r)\n      {\n         return closures.make(r);\n      }\n\n      // -- impl::Asm\n      Asm::Asm(const ipr::String& s) : impl::Unary_node<ipr::Asm>{s} { }\n\n      const ipr::Type& Asm::type() const { return impl::builtin(Fundamental::Void); }\n\n      // ---------------------\n      // -- impl::Expr_list --\n      // ---------------------\n\n      Expr_list::Expr_list()\n      { }\n\n      Expr_list::Expr_list(const ref_sequence<ipr::Expr>& s) : seq(s)\n      { }\n\n      const ipr::Product&\n      Expr_list::type() const {\n         return seq;\n      }\n\n      const ipr::Sequence<ipr::Expr>&\n      Expr_list::operand() const {\n         return seq.seq;\n      }\n\n      // -------------\n      // -- Id_expr --\n      // -------------\n\n      Id_expr::Id_expr(const ipr::Name& n)\n            : impl::Basic_unary<impl::Expr<ipr::Id_expr>>(n)\n      { }\n\n      Optional<ipr::Expr>\n      Id_expr::resolution() const {\n         return decls;\n      }\n\n      // -- impl::Restriction --\n      const ipr::Type& Restriction::type() const { return impl::builtin(Fundamental::Bool); }\n\n      // ---------------\n      // -- Enclosure --\n      // ---------------\n      Enclosure::Enclosure(ipr::Delimiter d, const ipr::Expr& e)\n         : impl::Unary_expr<ipr::Enclosure>{ e }, delim{ d}\n      { }\n\n      // -----------------\n      // -- Binary_fold --\n      // -----------------\n      Binary_fold::Binary_fold(Category_code op, const ipr::Expr& x, const ipr::Expr& y)\n         : Classic{x, y}, fold_op{ op }\n      { }\n\n      Category_code Binary_fold::operation() const { return fold_op; }\n\n      // -- impl::General_substitution\n      const ipr::Expr& General_substitution::operator[](const ipr::Parameter& p) const\n      {\n         if (auto where = mapping.find(&p); where != mapping.end())\n            return *where->second;\n         return p;\n      }\n\n      General_substitution& General_substitution::subst(const ipr::Parameter& p, const ipr::Expr& v)\n      {\n         mapping.insert_or_assign(&p, &v);\n         return *this;\n      }\n\n      // -- impl::Mapping\n      Mapping::Mapping(const ipr::Region& pr, Mapping_level d)\n            : impl::Parameterization<ipr::Expr, impl::Expr<ipr::Mapping>>{pr, d}\n      {\n         inputs.parms.owned_by = this;\n      }\n\n      // -- impl::Lambda\n      Lambda::Lambda(const ipr::Region& r, Mapping_level l)\n         : impl::Parameterization<ipr::Expr, impl::Node<ipr::Lambda>>{r, l}, lam_spec{}\n      {\n         inputs.parms.owned_by = this;\n      }\n\n      // -- impl::Requires\n      const ipr::Type& Requires::type() const { return impl::builtin(Fundamental::Bool); }\n\n      // -------------------------------\n      // -- impl::Scope --\n      // -------------------------------\n      Scope::Scope() { }\n\n      Optional<ipr::Overload> Scope::operator[](const ipr::Name& n) const\n      {\n         if (impl::Overload* ovl = overloads.find(n, node_compare()))\n            return { ovl };\n         return { };\n      }\n\n      template<class T>\n      inline void\n      Scope::add_member(T* decl)\n      {\n         decls.seq.push_back(decl);\n      }\n\n      impl::Alias*\n      Scope::make_alias(const ipr::Name& n, const ipr::Expr& i) {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(i.type());\n\n         if (master == nullptr) {\n            impl::Alias* decl = aliases.declare(ovl, i.type());\n            decl->aliasee = &i;\n            add_member(decl);\n            return decl;\n         }\n         else {\n            impl::Alias* decl = aliases.redeclare(master);\n            decl->aliasee = &i;\n            add_member(decl);\n            return decl;\n         }\n      }\n\n      impl::Var*\n      Scope::make_var(const ipr::Name& n, const ipr::Type& t) {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(t);\n\n         if (master == nullptr) {\n            impl::Var* var = vars.declare(ovl, t);\n            add_member(var);\n            return var;\n         }\n         else {\n            impl::Var* var = vars.redeclare(master);\n            add_member(var);\n            return var;\n         }\n      }\n\n      impl::Field*\n      Scope::make_field(const ipr::Name& n, const ipr::Type& t) {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(t);\n\n         if (master == nullptr) {\n            impl::Field* field = fields.declare(ovl, t);\n            add_member(field);\n            return field;\n         }\n         else {\n            impl::Field* field = fields.redeclare(master);\n            add_member(field);\n            return field;\n         }\n      }\n\n      impl::Bitfield*\n      Scope::make_bitfield(const ipr::Name& n, const ipr::Type& t) {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(t);\n\n         if (master == nullptr) {\n            impl::Bitfield* field = bitfields.declare(ovl, t);\n            add_member(field);\n            return field;\n         }\n         else {\n            impl::Bitfield* field = bitfields.redeclare(master);\n            add_member(field);\n            return field;\n         }\n      }\n\n      // Make a node for a type-declaration with name N and type T.\n      impl::Typedecl*\n      Scope::make_typedecl(const ipr::Name& n, const ipr::Type& t)\n      {\n         // Get the overload-set for this name.\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n\n         // Does the overload-set already contain a decl with that type?\n         overload_entry* master = ovl->lookup(t);\n         impl::Typedecl* decl = master == nullptr ?\n            typedecls.declare(ovl, t) : // no, this is the first declaration\n            typedecls.redeclare(master); // just re-declare.\n         add_member(decl);      // remember we saw a declaration.\n         return decl;\n      }\n\n      impl::Fundecl*\n      Scope::make_fundecl(const ipr::Name& n, const ipr::Function& t)\n      {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(t);\n\n         if (master == nullptr) {\n            impl::Fundecl* decl = fundecls.declare(ovl, t);\n            add_member(decl);\n            return decl;\n         }\n         else {\n            impl::Fundecl* decl = fundecls.redeclare(master);\n            add_member(decl);\n            return decl;\n         }\n      }\n\n      impl::Template*\n      Scope::make_primary_template(const ipr::Name& n, const ipr::Forall& t)\n      {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(t);\n\n         if (master == nullptr) {\n            impl::Template* decl = primary_maps.declare(ovl, t);\n            decl->decl_data.master_data->primary = decl;\n            add_member(decl);\n            return decl;\n         }\n         else {\n            impl::Template* decl = primary_maps.redeclare(master);\n            // FIXME: set the primary field.\n            add_member(decl);\n            return decl;\n         }\n      }\n\n      impl::Template*\n      Scope::make_secondary_template(const ipr::Name& n, const ipr::Forall& t)\n      {\n         impl::Overload* ovl = overloads.insert(n, node_compare());\n         overload_entry* master = ovl->lookup(t);\n\n         if (master == nullptr) {\n            impl::Template* decl = secondary_maps.declare(ovl, t);\n            // FXIME: record this a secondary map and set its primary.\n            add_member(decl);\n            return decl;\n         }\n         else {\n            impl::Template* decl = secondary_maps.redeclare(master);\n            // FIXME: set primary info.\n            add_member(decl);\n            return decl;\n         }\n      }\n\n      // --------------------------------\n      // -- impl::Region --\n      // --------------------------------\n\n      Region::Region(Optional<ipr::Region> pr)\n            : parent{pr}\n      { }\n\n\n      Region*\n      Region::make_subregion() {\n         return subregions.make(this);\n      }\n\n      Where::Where(const ipr::Region& parent) : region{&parent} { }\n\n      // -- impl::Static_assert\n      Static_assert::Static_assert(const ipr::Expr& e, Optional<ipr::String> s)\n         : Binary_node<ipr::Static_assert>{e, s}\n      { }\n\n      const ipr::Type& Static_assert::type() const\n      {\n         return impl::builtin(Fundamental::Bool);\n      }\n\n      // -- impl::name_factory\n\n      const ipr::Logogram& name_factory::get_logogram(const ipr::String& s)\n      {\n         if (s.size() == 0)\n            return invisible_logo;\n         else if (auto logo = word_if_known(s.characters()))\n            return *logo;\n         constexpr auto lt = [](auto& x, auto& y) { return compare(x.what(), y); };\n         return *logos.insert(s, lt);\n      }\n\n      const ipr::String& name_factory::get_string(util::word_view w)\n      {\n         return strings.intern(w);\n      }\n\n      const ipr::Identifier& name_factory::get_identifier(const ipr::String& s)\n      {\n         return *ids.insert(s, id_compare());\n      }\n\n      const ipr::Identifier& name_factory::get_identifier(util::word_view w)\n      {\n         return get_identifier(get_string(w));\n      }\n\n      const ipr::Suffix& name_factory::get_suffix(const ipr::Identifier& s)\n      {\n         return *suffixes.insert(s, unary_compare());\n      }\n\n      const ipr::Operator& name_factory::get_operator(const ipr::String& s)\n      {\n         return *ops.insert(s, unary_compare());\n      }\n\n      const ipr::Operator& name_factory::get_operator(util::word_view w)\n      {\n         return get_operator(get_string(w));\n      }\n\n      const ipr::Ctor_name& name_factory::get_ctor_name(const ipr::Type& t)\n      {\n         return *ctors.insert(t, unary_compare());\n      }\n\n      const ipr::Dtor_name& name_factory::get_dtor_name(const ipr::Type& t)\n      {\n         return *dtors.insert(t, unary_compare());\n      }\n\n      const ipr::Conversion& name_factory::get_conversion(const ipr::Type& t)\n      {\n         return *convs.insert(t, unary_compare());\n      }\n\n      const ipr::Guide_name& name_factory::get_guide_name(const ipr::Template& m)\n      {\n         return *guide_ids.insert(m, unary_compare());\n      }\n\n      // ------------------------\n      // -- impl::expr_factory --\n      // ------------------------\n\n      // -- Language linkage\n      const ipr::Language_linkage& expr_factory::get_linkage(util::word_view w)\n      {\n         if (w == u8\"C\")\n            return impl::c_link;\n         else if (w == u8\"C++\")\n            return impl::cxx_link;\n         return get_linkage(get_string(w));\n      }\n\n      const ipr::Language_linkage& expr_factory::get_linkage(const ipr::String& lang)\n      {\n         if (physically_same(lang, internal_string(u8\"C\")))\n            return impl::c_link;\n         else if (physically_same(lang, internal_string(u8\"C++\")))\n            return impl::cxx_link;\n         constexpr auto cmp = [](auto& x, auto& y) { return compare(x.language(), y); };\n         return *linkages.insert(get_logogram(lang), cmp);\n      }\n\n      const ipr::Calling_convention& expr_factory::get_calling_convention(util::word_view w)\n      {\n         auto& name = get_logogram(get_string(w));\n         constexpr auto cmp = [](auto& x, auto& y) { return compare(x.name(), y); };\n         return *conventions.insert(name, cmp);\n      }\n\n      const ipr::Symbol&\n      expr_factory::get_symbol(const ipr::Name& n, const ipr::Type& t)\n      {\n         const auto comparator = [&t](auto& x, auto& y) {\n            if (auto cmp = compare(x.name(), y))\n               return cmp;\n            return compare(x.type(), t);\n         };\n\n         auto sym = symbols.insert(n, comparator);\n         sym->typing = &t;\n         return *sym;\n      }\n\n      const ipr::Symbol& expr_factory::get_label(const ipr::Identifier& n)\n      {\n         if (physically_same(n, known_word(u8\"default\")))\n            return impl::default_cst;\n         return get_symbol(n, impl::builtin(Fundamental::Void));\n      }\n\n      const ipr::Symbol& expr_factory::get_this(const ipr::Type& t)\n      {\n         return get_symbol(known_word(u8\"this\"), t);\n      }\n\n      impl::Phantom*\n      expr_factory::make_phantom() {\n         return phantoms.make();\n      }\n\n      const ipr::Phantom*\n      expr_factory::make_phantom(const ipr::Type& t) {\n         return phantoms.make(&t);\n      }\n\n      impl::Eclipsis* expr_factory::make_eclipsis(const ipr::Type& t)\n      {\n         return eclipses.make(&t);\n      }\n\n      impl::Address*\n      expr_factory::make_address(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(addresses, e).with_type(t);\n      }\n\n      impl::Array_delete*\n      expr_factory::make_array_delete(const ipr::Expr& e) {\n         return array_deletes.make(e);\n      }\n      impl::Asm* expr_factory::make_asm_expr(const ipr::String& s)\n      {\n         return asms.make(s);\n      }\n\n      impl::Complement*\n      expr_factory::make_complement(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(complements, e).with_type(t);\n      }\n\n      impl::Delete*\n      expr_factory::make_delete(const ipr::Expr& e) {\n         return deletes.make(e);\n      }\n\n      impl::Demotion*\n      expr_factory::make_demotion(const ipr::Expr& e, const ipr::Type& t)\n      {\n         return make(demotions, e).with_type(t);\n      }\n\n      impl::Deref*\n      expr_factory::make_deref(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(derefs, e).with_type(t);\n      }\n\n      impl::Expr_list*\n      expr_factory::make_expr_list() {\n         return xlists.make();\n      }\n\n      impl::Id_expr*\n      expr_factory::make_id_expr(const ipr::Name& n, Optional<ipr::Type> t)\n      {\n         return make(id_exprs, n).with_type(t);\n      }\n\n      impl::Id_expr*\n      expr_factory::make_id_expr(const ipr::Decl& d)\n      {\n         auto x = make(id_exprs, d.name()).with_type(d.type());\n         x->decls = &d;\n         return x;\n      }\n\n      impl::Label*\n      expr_factory::make_label(const ipr::Identifier& n, Optional<ipr::Type> t)\n      {\n         return make(labels, n).with_type(t);\n      }\n\n      Materialization*\n      expr_factory::make_materialization(const ipr::Expr& e, const ipr::Type& t)\n      {\n         return make(materializations, e).with_type(t);\n      }\n\n      impl::Not*\n      expr_factory::make_not(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(nots, e).with_type(t);\n      }\n\n      impl::Enclosure*\n      expr_factory::make_enclosure(ipr::Delimiter d, const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(enclosures, d, e).with_type(t);\n      }\n\n      impl::Post_increment*\n      expr_factory::make_post_increment(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(post_increments, e).with_type(t);\n      }\n\n      impl::Post_decrement*\n      expr_factory::make_post_decrement(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(post_decrements, e).with_type(t);\n      }\n\n      impl::Pre_increment*\n      expr_factory::make_pre_increment(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(pre_increments, e).with_type(t);\n      }\n\n      impl::Pre_decrement*\n      expr_factory::make_pre_decrement(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(pre_decrements, e).with_type(t);\n      }\n\n      impl::Promotion*\n      expr_factory::make_promotion(const ipr::Expr& e, const ipr::Type& t)\n      {\n         return make(promotions, e).with_type(t);\n      }\n\n      impl::Read*\n      expr_factory::make_read(const ipr::Expr& e, const ipr::Type& t)\n      {\n         return make(reads, e).with_type(t);\n      }\n\n      impl::Throw*\n      expr_factory::make_throw(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(throws, e).with_type(t);\n      }\n\n      impl::Alignof* expr_factory::make_alignof(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(alignofs, e).with_type(t);\n      }\n\n      impl::Sizeof*\n      expr_factory::make_sizeof(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(sizeofs, e).with_type(t);\n      }\n\n      impl::Args_cardinality*\n      expr_factory::make_args_cardinality(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(cardinalities, e).with_type(t);\n      }\n\n      impl::Restriction* expr_factory::make_restriction(const ipr::Expr& e)\n      {\n         return restrictions.make(e);\n      }\n\n      impl::Typeid*\n      expr_factory::make_typeid(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(xtypeids, e).with_type(t);\n      }\n\n      impl::Unary_minus*\n      expr_factory::make_unary_minus(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(unary_minuses, e).with_type(t);\n      }\n\n      impl::Unary_plus*\n      expr_factory::make_unary_plus(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(unary_pluses, e).with_type(t);\n      }\n\n      impl::Expansion*\n      expr_factory::make_expansion(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(expansions, e).with_type(t);\n      }\n\n      impl::Construction*\n      expr_factory::make_construction(const ipr::Type& t, const ipr::Enclosure& e)\n      {\n         return make(constructions, e).with_type(t);\n      }\n\n      impl::Noexcept*\n      expr_factory::make_noexcept(const ipr::Expr& e, Optional<ipr::Type> t)\n      {\n         return make(noexcepts, e).with_type(t);\n      }\n\n      impl::Rewrite* expr_factory::make_rewrite(const ipr::Expr& s, const ipr::Expr& t)\n      {\n         return rewrites.make(s, t);\n      }\n\n      impl::And*\n      expr_factory::make_and(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(ands, l, r).with_type(t);\n      }\n\n      impl::Array_ref*\n      expr_factory::make_array_ref(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(array_refs, l, r).with_type(t);\n      }\n\n      impl::Arrow*\n      expr_factory::make_arrow(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(arrows, l, r).with_type(t);\n      }\n\n      impl::Arrow_star*\n      expr_factory::make_arrow_star(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(arrow_stars, l, r).with_type(t);\n      }\n\n      impl::Assign*\n      expr_factory::make_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(assigns, l, r).with_type(t);\n      }\n\n      impl::Bitand*\n      expr_factory::make_bitand(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(bitands, l, r).with_type(t);\n      }\n\n      impl::Bitand_assign*\n      expr_factory::make_bitand_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(bitand_assigns, l, r).with_type(t);\n      }\n\n      impl::Bitor*\n      expr_factory::make_bitor(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(bitors, l, r).with_type(t);\n      }\n\n      impl::Bitor_assign*\n      expr_factory::make_bitor_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(bitor_assigns, l, r).with_type(t);\n      }\n\n      impl::Bitxor*\n      expr_factory::make_bitxor(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(bitxors, l, r).with_type(t);\n      }\n\n      impl::Bitxor_assign*\n      expr_factory::make_bitxor_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(bitxor_assigns, l, r).with_type(t);\n      }\n\n      impl::Cast*\n      expr_factory::make_cast(const ipr::Type& t, const ipr::Expr& e) {\n         return casts.make(t, e);\n      }\n\n      impl::Call*\n      expr_factory::make_call(const ipr::Expr& l, const ipr::Expr_list& r, Optional<ipr::Type> t)\n      {\n         return make(calls, l, r).with_type(t);\n      }\n\n      impl::Coercion*\n      expr_factory::make_coercion(const ipr::Expr& l, const ipr::Type& r, const ipr::Type& t)\n      {\n         return make(coercions, l, r).with_type(t);\n      }\n\n      impl::Comma*\n      expr_factory::make_comma(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(commas, l, r).with_type(t);\n      }\n\n      impl::Const_cast*\n      expr_factory::make_const_cast(const ipr::Type& t, const ipr::Expr& e) {\n         return ccasts.make(t, e);\n      }\n\n      impl::Div*\n      expr_factory::make_div(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(divs, l, r).with_type(t);\n      }\n\n      impl::Div_assign*\n      expr_factory::make_div_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(div_assigns, l, r).with_type(t);\n      }\n\n      impl::Dot*\n      expr_factory::make_dot(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(dots, l, r).with_type(t);\n      }\n\n      impl::Dot_star*\n      expr_factory::make_dot_star(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(dot_stars, l, r).with_type(t);\n      }\n\n      impl::Dynamic_cast*\n      expr_factory::make_dynamic_cast(const ipr::Type& t, const ipr::Expr& e)\n      {\n         return dcasts.make(t, e);\n      }\n\n      impl::Equal*\n      expr_factory::make_equal(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(equals, l, r).with_type(t);\n      }\n\n      impl::Greater*\n      expr_factory::make_greater(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(greaters, l, r).with_type(t);\n      }\n\n      impl::Greater_equal*\n      expr_factory::make_greater_equal(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(greater_equals, l, r).with_type(t);\n      }\n\n      impl::Less*\n      expr_factory::make_less(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(lesses, l, r).with_type(t);\n      }\n\n      impl::Less_equal*\n      expr_factory::make_less_equal(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(less_equals, l, r).with_type(t);\n      }\n\n      impl::Literal*\n      expr_factory::make_literal(const ipr::Type& t, const ipr::String& s) {\n         using rep = impl::Literal::Rep;\n         return lits.insert(rep{ t, s }, binary_compare());\n      }\n\n      impl::Literal*\n      expr_factory::make_literal(const ipr::Type& t, util::word_view w) {\n         return make_literal(t, get_string(w));\n      }\n\n      impl::Lshift*\n      expr_factory::make_lshift(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(lshifts, l, r).with_type(t);\n      }\n\n      impl::Lshift_assign*\n      expr_factory::make_lshift_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(lshift_assigns, l, r).with_type(t);\n      }\n\n      impl::Member_init*\n      expr_factory::make_member_init(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(member_inits, l, r).with_type(t);\n      }\n\n      impl::Minus*\n      expr_factory::make_minus(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(minuses, l, r).with_type(t);\n      }\n\n      impl::Minus_assign*\n      expr_factory::make_minus_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(minus_assigns, l, r).with_type(t);\n      }\n\n      impl::Modulo*\n      expr_factory::make_modulo(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(modulos, l, r).with_type(t);\n      }\n\n      impl::Modulo_assign*\n      expr_factory::make_modulo_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(modulo_assigns, l, r).with_type(t);\n      }\n\n      impl::Mul*\n      expr_factory::make_mul(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(muls, l, r).with_type(t);\n      }\n\n      impl::Mul_assign*\n      expr_factory::make_mul_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(mul_assigns, l, r).with_type(t);\n      }\n\n      impl::Narrow*\n      expr_factory::make_narrow(const ipr::Expr& e, const ipr::Type& t, const ipr::Type& result) {\n         return make(narrows, e, t).with_type(result);\n      }\n\n      impl::Not_equal*\n      expr_factory::make_not_equal(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(not_equals, l, r).with_type(t);\n      }\n\n      impl::Or*\n      expr_factory::make_or(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(ors, l, r).with_type(t);\n      }\n\n      impl::Plus*\n      expr_factory::make_plus(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(pluses, l, r).with_type(t);\n      }\n\n      impl::Plus_assign*\n      expr_factory::make_plus_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(plus_assigns, l, r).with_type(t);\n      }\n\n      impl::Pretend*\n      expr_factory::make_pretend(const ipr::Expr& e, const ipr::Type& t, const ipr::Type& result) {\n         return make(pretends, e, t).with_type(result);\n      }\n\n      impl::Qualification*\n      expr_factory::make_qualification(const ipr::Expr& e, ipr::Qualifiers q, const ipr::Type& t)\n      {\n         return make(qualifications, e, q).with_type(t);\n      }\n\n      impl::Reinterpret_cast*\n      expr_factory::make_reinterpret_cast(const ipr::Type& t,\n                                          const ipr::Expr& e) {\n         return rcasts.make(t, e);\n      }\n\n      impl::Scope_ref*\n      expr_factory::make_scope_ref(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(scope_refs, l, r).with_type(t);\n      }\n\n      impl::Rshift*\n      expr_factory::make_rshift(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(rshifts, l, r).with_type(t);\n      }\n\n      impl::Rshift_assign*\n      expr_factory::make_rshift_assign(const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(rshift_assigns, l, r).with_type(t);\n      }\n\n      impl::Template_id*\n      expr_factory::make_template_id(const ipr::Expr& n, const ipr::Expr_list& args) {\n         using Rep = impl::Template_id::Rep;\n         return template_ids.insert(Rep{ n, args }, binary_compare());\n      }\n\n      impl::Static_cast*\n      expr_factory::make_static_cast(const ipr::Type& t, const ipr::Expr& e) {\n         return scasts.make(t, e);\n      }\n\n      impl::Widen*\n      expr_factory::make_widen(const ipr::Expr& e, const ipr::Type& t, const ipr::Type& result) {\n         return make(widens, e, t).with_type(result);\n      }\n\n      impl::Binary_fold*\n      expr_factory::make_binary_fold(Category_code op, const ipr::Expr& l, const ipr::Expr& r, Optional<ipr::Type> t)\n      {\n         return make(folds, op, l, r).with_type(t);\n      }\n\n      impl::Where*\n      expr_factory::make_where(const ipr::Region& parent)\n      {\n         return wheres.make(parent);\n      }\n\n      impl::Where_no_decl*\n      expr_factory::make_where(const ipr::Expr& main, const ipr::Expr& attendant)\n      {\n         return where_nodecls.make(main, attendant);\n      }\n\n      impl::Static_assert* expr_factory::make_static_assert_expr(const ipr::Expr& e, Optional<ipr::String> s)\n      {\n         return asserts.make(e, s);\n      }\n\n      impl::Instantiation*\n      expr_factory::make_instantiation(const ipr::Expr& e, const ipr::Substitution& s)\n      {\n         return insts.make(e, s);\n      }\n\n      impl::New*\n      expr_factory::make_new(Optional<ipr::Expr_list> where, const ipr::Construction& expr, Optional<ipr::Type> t)\n      {\n         return make(news, where, expr).with_type(t);\n      }\n\n      impl::Conditional*\n      expr_factory::make_conditional(const ipr::Expr& expr, const ipr::Expr& then,\n                                     const ipr::Expr& alt, Optional<ipr::Type> t)\n      {\n         return make(conds, expr, then, alt).with_type(t);\n      }\n\n      impl::Mapping*\n      expr_factory::make_mapping(const ipr::Region& r, Mapping_level l) {\n         return mappings.make(r, l);\n      }\n\n      impl::Lambda* expr_factory::make_lambda(const ipr::Region& r, Mapping_level l)\n      {\n         return lambdas.make(r, l);\n      }\n\n      impl::Requires* expr_factory::make_requires(const ipr::Region& r, Mapping_level l)\n      {\n         return reqs.make(r, l);\n      }\n\n      impl::Elementary_substitution*\n      expr_factory::make_elementary_substitution(const ipr::Parameter& p, const ipr::Expr& v)\n      {\n         return elem_substs.make(p, v);\n      }\n\n      impl::General_substitution* expr_factory::make_general_substitution()\n      {\n         return gen_substs.make();\n      }\n\n      // -- impl::Lexicon --\n\n      const ipr::Language_linkage& Lexicon::c_linkage() const { return impl::c_link; }\n      const ipr::Language_linkage& Lexicon::cxx_linkage() const { return impl::cxx_link; }\n\n      namespace {\n         struct UnknownLogogramError { \n            util::word_view what;\n            UnknownLogogramError(util::word_view w) : what{w} { }\n            UnknownLogogramError(Basic_specifier s) : what{s.logogram().what().characters()} { }\n            UnknownLogogramError(Basic_qualifier q) : what{q.logogram().what().characters()} { }\n         };\n\n         // Helper function used to precompose known values of symbolic denotations.\n         constexpr auto project(auto s, auto& table, auto pred)\n         {\n            auto pos = 0;\n            for (auto& x : table) {\n               if (pred(x, s))\n                  return 1u << pos;\n               ++pos;\n            }\n            throw UnknownLogogramError{s};\n         }\n\n         // Representation of a family of basic symbolic denotations taken as basis\n         // for expressing combinations of elements of said family.\n         template<typename T, auto& table>\n         struct Basis {\n            consteval T operator[](const char8_t* s) const\n            { \n               constexpr auto has_name = [](auto& x, auto& y) { return x.logogram().operand().characters() == y; };\n               return T{impl::project(s, table, has_name)};\n            }\n\n            template<typename S>\n            T operator()(S s) const\n            {\n               return T{impl::project(s, table, std::equal_to<>{})};\n            }\n\n            template<typename S>\n            static std::vector<S> decompose(T element)\n            {\n               std::vector<S> result;\n               int pos = 0;\n               for (auto& b : table) {\n                  if (ipr::implies(element, T{1u << pos}))\n                     result.push_back(b);\n                  ++pos;\n               }\n               return result;\n            }\n         };\n\n         constexpr Basis<ipr::Specifiers, impl::std_specifiers> specifier_basis { };\n         constexpr Basis<ipr::Qualifiers, impl::std_qualifiers> qualifier_basis { };\n      }\n\n      ipr::Specifiers Lexicon::export_specifier() const { return impl::specifier_basis[u8\"export\"]; }\n      ipr::Specifiers Lexicon::static_specifier() const { return impl::specifier_basis[u8\"static\"]; }\n      ipr::Specifiers Lexicon::extern_specifier() const { return impl::specifier_basis[u8\"extern\"]; }\n      ipr::Specifiers Lexicon::mutable_specifier() const { return impl::specifier_basis[u8\"mutable\"]; }\n      ipr::Specifiers Lexicon::constinit_specifier() const { return impl::specifier_basis[u8\"constinit\"]; }\n      ipr::Specifiers Lexicon::thread_local_specifier() const { return impl::specifier_basis[u8\"thread_local\"]; }\n      ipr::Specifiers Lexicon::register_specifier() const { return impl::specifier_basis[u8\"register\"]; }\n      ipr::Specifiers Lexicon::inline_specifier() const { return impl::specifier_basis[u8\"inline\"]; }\n      ipr::Specifiers Lexicon::consteval_specifier() const { return impl::specifier_basis[u8\"consteval\"]; }\n      ipr::Specifiers Lexicon::constexpr_specifier() const { return impl::specifier_basis[u8\"constexpr\"]; }\n      ipr::Specifiers Lexicon::virtual_specifier() const { return impl::specifier_basis[u8\"virtual\"]; }\n      ipr::Specifiers Lexicon::abstract_specifier() const { return impl::specifier_basis[u8\"=0\"]; }\n      ipr::Specifiers Lexicon::explicit_specifier() const { return impl::specifier_basis[u8\"explicit\"]; }\n      ipr::Specifiers Lexicon::friend_specifier() const { return impl::specifier_basis[u8\"friend\"]; }\n      ipr::Specifiers Lexicon::typedef_specifier() const { return impl::specifier_basis[u8\"typedef\"]; }\n      ipr::Specifiers Lexicon::public_specifier() const { return impl::specifier_basis[u8\"public\"]; }\n      ipr::Specifiers Lexicon::protected_specifier() const { return impl::specifier_basis[u8\"protected\"]; }\n      ipr::Specifiers Lexicon::private_specifier() const { return impl::specifier_basis[u8\"private\"]; }\n\n      ipr::Specifiers Lexicon::specifiers(ipr::Basic_specifier s) const\n      {\n         return impl::specifier_basis(s);\n      }\n\n      // Return the decomposition of a specifier in terms of its basic specifiers.\n      std::vector<ipr::Basic_specifier> Lexicon::decompose(ipr::Specifiers specs) const\n      {\n         return impl::specifier_basis.decompose<ipr::Basic_specifier>(specs);\n      }\n\n      ipr::Qualifiers Lexicon::const_qualifier() const { return impl::qualifier_basis[u8\"const\"]; }\n      ipr::Qualifiers Lexicon::volatile_qualifier() const { return impl::qualifier_basis[u8\"volatile\"]; }\n      ipr::Qualifiers Lexicon::restrict_qualifier() const { return impl::qualifier_basis[u8\"restrict\"]; }\n\n      ipr::Qualifiers Lexicon::qualifiers(ipr::Basic_qualifier q) const\n      {\n         return impl::qualifier_basis(q);\n      }\n\n      std::vector<ipr::Basic_qualifier> Lexicon::decompose(ipr::Qualifiers quals) const\n      {\n         return impl::qualifier_basis.decompose<ipr::Basic_qualifier>(quals);\n      }\n\n      Lexicon::Lexicon() { }\n      Lexicon::~Lexicon() { }\n\n      const ipr::Literal&\n      Lexicon::get_literal(const ipr::Type& t, util::word_view w) {\n         return get_literal(t, get_string(w));\n      }\n\n      const ipr::Literal&\n      Lexicon::get_literal(const ipr::Type& t, const ipr::String& s) {\n         return *make_literal(t, s);\n      }\n\n      const ipr::Type& Lexicon::void_type() const {  return impl::builtin(Fundamental::Void);  }\n      const ipr::Type& Lexicon::bool_type() const { return impl::builtin(Fundamental::Bool); }\n      const ipr::Type& Lexicon::char_type() const { return impl::builtin(Fundamental::Char); }\n      const ipr::Type& Lexicon::schar_type() const { return impl::builtin(Fundamental::Schar); }\n      const ipr::Type& Lexicon::uchar_type() const { return impl::builtin(Fundamental::Uchar); }\n      const ipr::Type& Lexicon::wchar_t_type() const { return impl::builtin(Fundamental::Wchar_t); }\n      const ipr::Type& Lexicon::char8_t_type() const { return impl::builtin(Fundamental::Char8_t); }\n      const ipr::Type& Lexicon::char16_t_type() const { return impl::builtin(Fundamental::Char16_t); }\n      const ipr::Type& Lexicon::char32_t_type() const { return impl::builtin(Fundamental::Char32_t); }\n      const ipr::Type& Lexicon::short_type() const { return impl::builtin(Fundamental::Short); }\n      const ipr::Type& Lexicon::ushort_type() const { return impl::builtin(Fundamental::Ushort); }\n      const ipr::Type& Lexicon::int_type() const { return impl::builtin(Fundamental::Int); }\n      const ipr::Type& Lexicon::uint_type() const { return impl::builtin(Fundamental::Uint); }\n      const ipr::Type& Lexicon::long_type() const { return impl::builtin(Fundamental::Long); }\n      const ipr::Type& Lexicon::ulong_type() const { return impl::builtin(Fundamental::Ulong); }\n      const ipr::Type& Lexicon::long_long_type() const { return impl::builtin(Fundamental::Long_long); }\n      const ipr::Type& Lexicon::ulong_long_type() const { return impl::builtin(Fundamental::Ulong_long); }\n      const ipr::Type& Lexicon::float_type() const { return impl::builtin(Fundamental::Float); }\n      const ipr::Type& Lexicon::double_type() const { return impl::builtin(Fundamental::Double); }\n      const ipr::Type& Lexicon::long_double_type() const { return impl::builtin(Fundamental::Long_double); }\n      const ipr::Type& Lexicon::ellipsis_type() const { return impl::builtin(Fundamental::Ellipsis); }\n      const ipr::Type& Lexicon::typename_type() const { return impl::builtin(Fundamental::Typename); }\n      const ipr::Type& Lexicon::class_type() const { return impl::builtin(Fundamental::Class); }\n      const ipr::Type& Lexicon::union_type() const { return impl::builtin(Fundamental::Union); }\n      const ipr::Type& Lexicon::enum_type() const { return impl::builtin(Fundamental::Enum); }\n      const ipr::Type& Lexicon::namespace_type() const { return impl::builtin(Fundamental::Namespace); }\n\n      const ipr::Symbol& Lexicon::false_value() const { return impl::false_cst; }\n      const ipr::Symbol& Lexicon::true_value() const { return impl::true_cst; }\n      const ipr::Symbol& Lexicon::nullptr_value() const { return impl::nullptr_cst; }\n      const ipr::Symbol& Lexicon::default_value() const { return impl::default_cst; }\n      const ipr::Symbol& Lexicon::delete_value() const { return impl::delete_cst; }\n\n      const ipr::Template_id&\n      Lexicon::get_template_id(const ipr::Expr& t, const ipr::Expr_list& a) {\n         return *expr_factory::make_template_id(t, a);\n      }\n\n      impl::Phased_evaluation* Lexicon::make_asm(const ipr::String& s)\n      {\n         return make_phased_evaluation(*make_asm_expr(s), Phases::Code_generation);\n      }\n\n      impl::Phased_evaluation* Lexicon::make_static_assert(const ipr::Expr& e, Optional<ipr::String> s)\n      {\n         return make_phased_evaluation(*make_static_assert_expr(e, s), Phases::Elaboration);\n      }\n\n      impl::Mapping*\n      Lexicon::make_mapping(const ipr::Region& r, Mapping_level l) {\n         return expr_factory::make_mapping(r, l);\n      }\n\n      // -- impl::Interface_unit --\n      Interface_unit::Interface_unit(impl::Lexicon& l, const ipr::Module& m)\n            : basic_unit<ipr::Interface_unit>{ l, m }\n      { }\n\n      const ipr::Sequence<ipr::Module>&\n      Interface_unit::exported_modules() const {\n         return modules_exported;\n      }\n\n      const ipr::Sequence<ipr::Decl>&\n      Interface_unit::exported_declarations() const {\n         return decls_exported;\n      }\n\n                                // -- impl::Module --\n      Module::Module(impl::Lexicon& l) : lexicon{ l }, iface{l, *this }\n      { }\n\n      const ipr::Module_name& Module::name() const { return stems; }\n\n      const ipr::Interface_unit& Module::interface_unit() const {\n         return iface;\n      }\n\n      const ipr::Sequence<ipr::Module_unit>&\n      Module::implementation_units() const { return units; }\n\n      impl::Module_unit* Module::make_unit() {\n         return units.push_back(lexicon, *this);\n      }\n}\n\n\n/*\n#include <ipr/impl>\n#include <ipr/io>\n#include <iostream>\n\nint main()\n{\n   using namespace ipr;\n   impl::Lexicon lexicon { };\n   impl::Translation_unit unit { lexicon };   // current translation unit\n\n   impl::Scope* global_scope = unit.global_scope();\n\n   // Build the variable's name,\n   auto& name = lexicon.get_identifier(u8\"bufsz\");\n   // then its type,\n   auto& type = lexicon.get_qualified(lexicon.const_qualifier(), lexicon.int_type());\n   // and the actual impl::Var node,\n   impl::Var* var = global_scope->make_var(name, type);\n   // set its initializer,\n   var->init = lexicon.make_literal(lexicon.int_type(), u8\"1024\");\n   // and inject it into its scope.\n\n   // Print out the whole translation unit\n   Printer pp { std::cout };\n   pp << unit;\n   std::cout << std::endl;\n\n}\n\n*/\n"
  },
  {
    "path": "src/input.cxx",
    "content": "//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copright and license notices.\n//\n\n#ifdef _WIN32\n#  include <windows.h>\n#else\n#  include <sys/stat.h>\n#  include <sys/mman.h>\n#  include <fcntl.h>\n#  include <unistd.h>\n#endif\n\n#include <assert.h>\n#include <iostream>\n#include <utility>\n#include <string_view>\n#include <algorithm>\n#include \"ipr/input\"\n\nnamespace ipr::input {\n    namespace {\n        // A cap on valid index values.\n        constexpr std::uint64_t index_watermark { std::uint64_t{1} << 58 }; \n\n        // A valid input line is either simple or composite.\n        bool valid_category(LineSort k)\n        {\n            return k == LineSort::Simple or k == LineSort::Composite; \n        }\n    }\n\n    bool valid_species(LineSpecies s)\n    {\n        switch (s) {\n        case LineSpecies::Text:\n        case LineSpecies::SolitaryHash:\n        case LineSpecies::If:\n        case LineSpecies::Ifdef:\n        case LineSpecies::Ifndef:\n        case LineSpecies::Elif:\n        case LineSpecies::Elifdef:\n        case LineSpecies::Elifndef:\n        case LineSpecies::Else:\n        case LineSpecies::Endif:\n        case LineSpecies::Include:\n        case LineSpecies::Export:\n        case LineSpecies::Import:\n        case LineSpecies::Embed:\n        case LineSpecies::Define:\n        case LineSpecies::Undef:\n        case LineSpecies::Line:\n        case LineSpecies::Error:\n        case LineSpecies::Warning:\n        case LineSpecies::Pragma:\n        case LineSpecies::ExtendedDirective:\n            return true;\n        default:\n            return false;\n        }\n    }\n\n    LineDescriptor::LineDescriptor(LineSort k, LineSpecies s, std::uint64_t i)\n        : srt{(assert(valid_category(k)), std::to_underlying(k))},\n          spc{(assert(valid_species(s)), std::to_underlying(s))},\n          idx{(assert(i < index_watermark), i)}\n    {\n    }\n\n\n\n#ifdef _WIN32\n    // Helper type for automatically closing a handle on scope exit.\n    struct SystemHandle {\n        SystemHandle(HANDLE h) : handle{h} { }\n        bool valid() const { return handle != INVALID_HANDLE_VALUE; }\n        auto get_handle() const { return handle; }\n        ~SystemHandle()\n        {\n            if (valid())\n                CloseHandle(handle);\n        }\n    private:\n        HANDLE handle;\n    };\n#endif\n\n    SourceFile::SourceFile(const SystemPath& path)\n    {\n#ifdef _WIN32\n        // FIXME: Handle the situation of large files in a 32-bit program.\n        static_assert(sizeof(LARGE_INTEGER) == sizeof(std::size_t));\n\n        SystemHandle file = CreateFileW(path.c_str(), GENERIC_READ, 0, nullptr,\n                                        OPEN_EXISTING,\n                                        FILE_ATTRIBUTE_NORMAL, nullptr);\n        if (not file.valid())\n            throw AccessError{ path, GetLastError() };\n        LARGE_INTEGER s { };\n        if (not GetFileSizeEx(file.get_handle(), &s))\n            throw AccessError{ path, GetLastError() };\n        if (s.QuadPart == 0)\n            return;\n        SystemHandle mapping = CreateFileMapping(file.get_handle(), nullptr, PAGE_READONLY, 0, 0, nullptr);\n        if (mapping.get_handle() == nullptr)\n            throw FileMappingError{ path, GetLastError() };\n        auto start = MapViewOfFile(mapping.get_handle(), FILE_MAP_READ, 0, 0, 0);\n        view = { reinterpret_cast<const char8_t*>(start), static_cast<View::size_type>(s.QuadPart) };\n#else\n        struct stat s { };\n        errno = 0;\n        if (stat(path.c_str(), &s) < 0)\n            throw AccessError{ path, errno };\n        else if (not S_ISREG(s.st_mode))\n            throw RegularFileError{ path };\n\n        // Don't labor too hard with empty files.\n        if (s.st_size == 0)\n            return;\n        \n        auto fd = open(path.c_str(), O_RDONLY);\n        if (fd < 0)\n            throw AccessError{ path, errno };\n        auto start = mmap(nullptr, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n        close(fd);\n        if (start == MAP_FAILED)\n            throw FileMappingError{ path };\n        view = { reinterpret_cast<const char8_t*>(start), static_cast<View::size_type>(s.st_size) };\n#endif\n    }\n\n    SourceFile::SourceFile(SourceFile&& src) noexcept : view{src.view}\n    {\n        src.view = { };\n    }\n\n    SourceFile::~SourceFile()\n    {\n        if (not view.empty())\n        {\n#ifdef _WIN32\n            UnmapViewOfFile(view.data());\n#else\n            munmap(const_cast<char8_t*>(view.data()), view.size());\n#endif\n        }\n    }\n\n    SourceFile::View SourceFile::contents(Isle m) const noexcept\n    {\n        assert(m.length < view.size());\n        return { view.data() + m.offset, m.length };\n    }\n\n    // All code fragments directly indexable must have offsets and extents less than these limits.\n    constexpr auto max_offset = std::uint64_t{1} << 47;\n    constexpr auto max_extent = std::uint64_t{1} << 16;\n\n    // Characters from a raw input source file marking new lines: either CR+LR or just LF.\n    constexpr char8_t carriage_return = 0x0D;    // '\\r';\n    constexpr char8_t line_feed = 0x0A;          // '\\n';\n\n    static inline bool white_space(char8_t c)\n    {\n        switch (c)\n        {\n        case u' ': case u8'\\t': case u8'\\v': case u8'\\f':\n            return true;\n        default:\n            return false;\n        }\n    }\n\n    void SourceFile::LineRange::next_line() noexcept\n    {\n        const auto offset = static_cast<std::uint64_t>(ptr - src->view.data());\n        assert(offset < max_offset);\n        const auto limit = src->view.size();\n        std::uint64_t idx = 0;\n        while (idx < limit and ptr[idx] != carriage_return and ptr[idx] != line_feed)\n            ++idx;\n        assert(idx < max_extent);\n        cache.isle.offset = offset;\n        cache.isle.length = idx;\n        ++cache.number;\n        for (cache.indent = 0; cache.indent < idx and white_space(ptr[cache.indent]); ++cache.indent)\n            ;\n\n        // Skip the new line marker.\n        if (idx < limit)\n        {\n            if (ptr[idx] == carriage_return and idx+1 < limit and ptr[idx+1] == line_feed)\n                ++idx;\n            ++idx;\n        }\n        ptr += idx;\n    }\n\n    SourceFile::LineRange::LineRange(const SourceFile& src) : src{&src}, ptr{src.view.data()}\n    {\n        // Skip a possible misguided UTF-8 BOM.\n        if (src.view.size() >= 3 and ptr[0] == 0xEF and ptr[1] == 0xBB and ptr[2] == 0xBF)\n            ptr += 3;\n        next_line();\n    }\n\n    PhysicalLine SourceFile::LineRange::iterator::operator*() const noexcept\n    {\n        assert(range != nullptr);\n        return range->cache;\n    }\n\n    SourceFile::LineRange::iterator& SourceFile::LineRange::iterator::operator++() noexcept\n    {\n        assert(range != nullptr);\n        if (range->ptr >= range->src->view.data() + range->src->view.size())\n            range = nullptr;\n        else\n            range->next_line();\n\n        return *this;\n    }\n\n    namespace {\n        // A mapping of a preprocessing directive to an algebraic value.\n        struct StandardDirective {\n            const char8_t* name;\n            LineSpecies species;\n        };\n\n        constexpr auto cmp_dir_by_name = [](auto& x, auto& y) constexpr {\n            return std::u8string_view{x.name} < std::u8string_view{y.name};\n        };\n\n        // A mapping of standard directive spelling to line species.\n        // Note: This table is stored in alphabetic order of the spelling.\n        constexpr StandardDirective standard_directives[] {\n            {u8\"define\", LineSpecies::Define},\n            {u8\"elif\", LineSpecies::Elif},\n            {u8\"elifdef\", LineSpecies::Elifdef},\n            {u8\"elifndef\", LineSpecies::Elifndef},\n            {u8\"else\", LineSpecies::Else},\n            {u8\"embed\", LineSpecies::Embed},\n            {u8\"endif\", LineSpecies::Endif},\n            {u8\"error\", LineSpecies::Error},\n            {u8\"export\", LineSpecies::Export},\n            {u8\"if\", LineSpecies::If},\n            {u8\"ifdef\", LineSpecies::Ifdef},\n            {u8\"ifndef\", LineSpecies::Ifndef},\n            {u8\"import\", LineSpecies::Import},\n            {u8\"include\", LineSpecies::Include},\n            {u8\"line\", LineSpecies::Line},\n            {u8\"pragma\", LineSpecies::Pragma},\n            {u8\"undef\", LineSpecies::Undef},\n            {u8\"warning\", LineSpecies::Warning},\n        };\n\n        static_assert(std::ranges::is_sorted(standard_directives, cmp_dir_by_name));\n\n        // If the argument for `s` is the spelling of a standard preprocessing directive,\n        // return a pointer to the corresponding precomputed map entry.  Otherwise, return null.\n        const StandardDirective* get_standard_directive(std::u8string_view s)\n        {\n            auto where = std::ranges::lower_bound(standard_directives, s, { }, &StandardDirective::name);\n            if (where == std::end(standard_directives) or where->name > s)\n                return nullptr;\n            return where;\n        }\n\n        // This predicate holds if the argument for `c` denotes the first character of a standard\n        // preprocessing directive.\n        inline bool may_begin_standard_directive(char8_t c)\n        {\n            switch (c) {\n            case u8'd': case u8'e': case u8'i': case u8'l':\n            case u8'p': case u8'u': case u8'w':\n                return true;\n            default:\n                return false;\n            }\n        }\n\n        // Quick and simple predicate for constitutents of a narrow identifier.\n        inline bool narrow_letter_or_digit(char8_t c)\n        {\n            return (c >= u8'A' and c <= u8'Z')\n                or (c >= u8'z' and c <= u8'z')\n                or (c >= u8'0' and c <= u8'9')\n                or c == u8'_';\n        }\n\n        // Advance the argument bound to `cursor` past the next consecutive whitespace characters.\n        inline void skip_blank(const char8_t*& cursor, const char8_t* end)\n        {\n            while (cursor < end and white_space(*cursor))\n                ++cursor;\n        }\n\n        // Return the species of a logical line.\n        LineSpecies species(SourceFile::View line)\n        {\n            auto cursor = line.data();\n            const auto line_end = cursor + line.size();\n            skip_blank(cursor, line_end);\n            if (cursor == line_end)\n                return LineSpecies::Unknown;\n            else if (*cursor != u8'#')\n                return LineSpecies::Text;\n\n            skip_blank(++cursor, line_end);\n            if (cursor == line_end)\n                return LineSpecies::SolitaryHash;\n            if (not may_begin_standard_directive(*cursor))\n                return LineSpecies::ExtendedDirective;\n            \n            const auto directive_start = cursor;\n            while (cursor < line_end and narrow_letter_or_digit(*cursor))\n                ++cursor;\n            if (auto directive = get_standard_directive({directive_start, cursor}))\n                return directive->species;\n            return LineSpecies::ExtendedDirective;\n        }\n\n        // Return the species of a composite logical line.\n        LineSpecies species(const SourceFile& src, const CompositeLine& composite)\n        {\n            // FIXME: Building a buffer is not strictly needed in most practical cases.\n            std::u8string buffer;\n            for (auto& line : composite.lines)\n            {\n                auto chars = src.contents(line.isle);\n                buffer.append(chars.data(), chars.size());\n            }\n            return species(buffer);\n        }\n\n        LineDepot read_lines(const SourceFile& src)\n        {\n            LineDepot depot { };\n            const auto file_start = src.contents().data();\n\n            CompositeLine composite { };\n            for (auto line: src.lines())\n            {\n                if (line.empty())\n                    continue;\n                // Trim any trailing whitespace character when determining logical line continuation.\n                const auto line_start = file_start + line.isle.offset + line.indent;\n                auto extent = line.isle.length;\n                while (--extent > line.indent and white_space(line_start[extent]))\n                    ;\n                if (line_start[extent] == u8'\\\\')\n                {\n                    line.isle.length = extent;\n                    composite.lines.push_back(line);\n                    continue;\n                }\n                else if (not composite.lines.empty())\n                {\n                    composite.lines.push_back(line);\n                    auto idx = depot.composites.size();\n                    depot.composites.push_back(composite);\n                    auto spc = species(src, composite);\n                    depot.indices.emplace_back(LineSort::Composite, spc, idx);\n                    composite.lines.clear();\n                }\n                else if (extent == line.indent)\n                    continue;               // skip entirely blank logical lines.\n                else\n                {\n                    auto idx = depot.simples.size();\n                    auto spc = species({line_start, extent});\n                    depot.indices.emplace_back(LineSort::Simple, spc, idx);\n                    depot.simples.emplace_back(line);\n                }\n            }\n\n            return depot;\n        }\n    }\n\n    SourceListing::SourceListing(const SystemPath& path) \n        : SourceFile{path}, depot{read_lines(*this)}\n    { }\n\n    const SimpleLine& SourceListing::simple_line(LineDescriptor line) const\n    {\n        assert(idx.sort() == LineSort::Simple);\n        auto n = line.index();\n        assert(n < depot.simples.size());\n        return depot.simples[n];\n    }\n\n    const CompositeLine& SourceListing::composite_line(LineDescriptor line) const\n    {\n        assert(idx.sort() == LineSort::Composite);\n        auto n = line.index();\n        assert(n < depot.composites.size());\n        return depot.composites[n];\n    }\n}"
  },
  {
    "path": "src/utility.cxx",
    "content": "//\n// This file is part of The Pivot framework.\n// Written by Gabriel Dos Reis.\n// See LICENSE for copright and license notices.\n//\n\n#include <ipr/std-preamble>\n\nimport cxx.ipr;\n\n#include <ipr/utility-impl>\n\nchar\nipr::util::string::operator[](size_type i) const\n{\n   if (i < 0 or i >= length)\n      throw std::domain_error(\"invalid index for util::string::operator[]\");\n   return data[i];\n}\n\nipr::util::string::arena::arena()\n      : mem(static_cast<pool*>(operator new(poolsz))),\n        next_header(mem->storage)\n{\n   mem->previous = nullptr;\n}\n\nipr::util::string::arena::~arena()\n{\n   while (mem != nullptr) {\n      pool* cur = mem;\n      mem = mem->previous;\n      operator delete (cur);\n   }\n}\n\n// Allocate storage sufficient to hold an immutable string of length \"n\".\n\nipr::util::string*\nipr::util::string::arena::allocate(size_type n)\n{\n   const auto m = (n - string::padding_count + headersz - 1) / headersz + 1;\n   string* header{};\n\n   // If we have enough space left, juts grab it.\n   if (m <= remaining_header_count()) {\n      header = next_header;\n      next_header += m;\n   }\n   // If we need to allocate storage more than what can possibly fit\n   // in a fresh pool object, just allocate that string on its own\n   else if (n > bufsz) {\n      pool* new_pool = static_cast<pool*>\n         (operator new(poolsz + (n - bufsz)));\n      header = new_pool->storage;\n\n      new_pool->previous = mem->previous;\n      mem->previous = new_pool;\n   }\n   // Not enough space left.  Take the bet that, there does not\n   // remain sufficient room in the buffer.  This is likely so if\n   // the buffer is allocated sufficiently large to start with.\n   else {\n      pool* new_pool = static_cast<pool*>(operator new(poolsz));\n      new_pool->previous = mem;\n      mem = new_pool;\n\n      header = mem->storage;\n      next_header = header + m;\n   }\n\n   return header;\n}\n\nconst ipr::util::string*\nipr::util::string::arena::make_string(const char8_t* s, size_type n)\n{\n   string* header = allocate(n);\n   header->length = n;\n   std::copy(s, s + n, &header->data[0]);\n   return header;\n}\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "add_subdirectory(unit-tests)\n"
  },
  {
    "path": "tests/unit-tests/CMakeLists.txt",
    "content": "set(TEST_BINARY unittests)\n\nadd_executable(${TEST_BINARY}\n   main.cxx\n   conversions.cxx\n   simple.cxx\n   words.cxx\n   region-owner.cxx\n   warehouse.cxx\n   phased-eval.cxx\n   specifiers.cxx\n   lines.cxx\n)\n\ntarget_link_libraries(${TEST_BINARY}\n   ${PROJECT_NAME}\n)\n\ntarget_include_directories(${TEST_BINARY}\n  SYSTEM PRIVATE ${DOCTEST_INCLUDE_DIR}\n)\n\ntarget_compile_options(${TEST_BINARY}\n   PRIVATE\n      $<$<CXX_COMPILER_ID:MSVC>:\n         /W2           # Usual warnings\n         /permissive-  # Turn on strict language conformance\n         /EHsc         # Turn on exception handling semantics\n      >\n      $<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:\n         -Wall         # Turn on all useful warnings\n         -pedantic     # Turn on strict language conformance\n      >\n      $<$<CXX_COMPILER_ID:Clang>:\n\t\t -Wno-overloaded-virtual                   # Too many false positives\n\t\t -Wno-delete-non-abstract-non-virtual-dtor # System headers plagued\n      >\n)\n\nadd_test(simple ${TEST_BINARY})\n\n"
  },
  {
    "path": "tests/unit-tests/conversions.cxx",
    "content": "#include <doctest/doctest.h>\n\n#include <ipr/std-preamble>\n\nimport cxx.ipr;\n\n#include <ipr/impl>\n\nTEST_CASE(\"C++ Standard Conversions\") {\n  using namespace ipr;\n  impl::Lexicon lexicon{};\n  impl::Module module{lexicon};\n  impl::Interface_unit unit{lexicon, module};\n\n  INFO(\"static_cast<long long>(4);\");\n  // Integral Promotion            (Promotion)\n  lexicon.make_promotion(\n    *lexicon.make_literal(lexicon.int_type(), u8\"4\"),\n    lexicon.long_long_type()\n  );\n\n  INFO(\"(float)2.2;\");\n  // Floating-Point Conversion     (Demotion)\n  lexicon.make_demotion(\n    *lexicon.make_literal(lexicon.double_type(), u8\"2.2\"),\n    lexicon.float_type()\n  );\n\n  INFO(\"int* const ptr = 0;\");\n  // Pointer Conversion            (Coercion)\n  const auto& ptr_type = lexicon.get_qualified(\n    lexicon.const_qualifier(), lexicon.get_pointer(lexicon.int_type()));\n  auto& ptr = *unit.global_region()->declare_var(lexicon.get_identifier(u8\"ptr\"), ptr_type);\n  ptr.init = lexicon.make_coercion(\n    *lexicon.make_literal(lexicon.int_type(), u8\"0\"),\n    ptr_type,\n    ptr_type\n  );\n\n  INFO(\"if (ptr) double(6);\");\n  // Boolean Conversion            (Coercion)\n  // Lvalue-to-Rvalue              (Read)\n  // Integral-Floating Conversion  (Coercion)\n  const auto& condition = *lexicon.make_coercion(\n    *lexicon.make_read(\n      *lexicon.make_id_expr(ptr),\n      lexicon.get_pointer(lexicon.int_type()) // != ptr.type() (see 7.2.2/2)\n    ),\n    lexicon.bool_type(),\n    lexicon.bool_type()\n  );\n  const auto& then_expr = *lexicon.make_coercion(\n      *lexicon.make_literal(lexicon.int_type(), u8\"6\"),\n      lexicon.double_type(),\n      lexicon.double_type()\n  );\n  lexicon.make_if(condition, *lexicon.make_expr_stmt(then_expr));\n\n}\n\nTEST_CASE(\"Class Conversions\") {\n  using namespace ipr;\n  impl::Lexicon lexicon{};\n  impl::Module module{lexicon};\n  impl::Interface_unit unit{lexicon, module};\n\n  INFO(\"struct Base {};\");\n  INFO(\"struct Derived : Base {};\");\n  auto& base = *lexicon.make_class(*unit.global_region());\n  auto& derived = *lexicon.make_class(*unit.global_region());\n  derived.declare_base(base);\n\n  INFO(\"Base* b;\");\n  INFO(\"Derived* d;\");\n  auto& base_ptr = lexicon.get_pointer(base);\n  auto& derived_ptr = lexicon.get_pointer(derived);\n  auto& b = *unit.global_region()->declare_var(lexicon.get_identifier(u8\"b\"), base_ptr);\n  auto& d = *unit.global_region()->declare_var(lexicon.get_identifier(u8\"d\"), derived_ptr);\n\n  // Derived-to-base conversion\n  INFO(\"b = d;\");\n  lexicon.make_assign(\n    *lexicon.make_id_expr(b),\n    *lexicon.make_widen(\n      *lexicon.make_id_expr(d),\n      base,\n      base_ptr\n  ));\n\n  // Checked base-to-derived conversion\n  INFO(\"dynamic_cast<Derived*>(b);\");\n  lexicon.make_narrow(\n    *lexicon.make_id_expr(b),\n    derived,\n    derived_ptr\n  );\n\n  // Unchecked base-to-derived conversion has no abstract\n  // representation in IPR so keep explicit cast.\n  INFO(\"(Derived*)b;\");\n  lexicon.make_cast(\n    derived_ptr,\n    *lexicon.make_id_expr(b)\n  );\n}\n\nTEST_CASE(\"CV Conversions\") {\n  using namespace ipr;\n  impl::Lexicon lexicon{};\n  impl::Module module{lexicon};\n  impl::Interface_unit unit{lexicon, module};\n\n  // Standard C++ CV qualification\n  INFO(\"(int) -> (volatile int)\");\n  lexicon.make_qualification(\n    *lexicon.make_literal(lexicon.int_type(), u8\"7\"),\n    lexicon.volatile_qualifier(),\n    lexicon.int_type() // prvalue can be adjusted to remove qualifiers (see 7.2.2/2)\n  );\n\n  INFO(\"const int* ptr;\");\n  const auto& ptr_type = lexicon.get_qualified(\n    lexicon.const_qualifier(), lexicon.get_pointer(lexicon.int_type()));\n  auto& ptr = *unit.global_region()->declare_var(lexicon.get_identifier(u8\"ptr\"), ptr_type);\n\n  // Removal of const is a non-implicit conversion\n  INFO(\"const_cast<int* const>(ptr);\");\n  lexicon.make_const_cast(\n    lexicon.get_qualified(lexicon.const_qualifier(), lexicon.get_pointer(lexicon.int_type())),\n    *lexicon.make_id_expr(ptr)\n  );\n\n  INFO(\"int** ptr_ptr\");\n  const auto& ptr_ptr_type = lexicon.get_pointer(lexicon.get_pointer(lexicon.int_type()));\n  auto& ptr_ptr = *unit.global_region()->declare_var(\n    lexicon.get_identifier(u8\"ptr_ptr\"), ptr_ptr_type);\n\n  INFO(\"(int**) -> (int* const* const)\");\n  lexicon.make_qualification(\n    *lexicon.make_qualification(\n      *lexicon.make_id_expr(ptr_ptr),\n      lexicon.const_qualifier(),\n      lexicon.get_qualified(lexicon.const_qualifier(), ptr_ptr.type())\n    ),\n    lexicon.const_qualifier(),\n    lexicon.get_pointer(lexicon.get_qualified(lexicon.const_qualifier(),\n      lexicon.get_pointer(lexicon.int_type())))\n      // prvalue can be adjusted to remove qualifier on top-level (see 7.2.2/2)\n  );\n\n  INFO(\"const int var = 0;\");\n  auto& var = *unit.global_region()->declare_var(lexicon.get_identifier(u8\"var\"), \n    lexicon.get_qualified(lexicon.const_qualifier(), lexicon.int_type()));\n\n  // Pretend can be used to explicitly reperesent automatic type adjustment as detailed\n  // in (7.2.2/2). Compilers are likely to just apply this adjustment on constraints without\n  // explicitly providing this node.\n  INFO(\"&var;\");\n  // Automatic-adjustment         (Pretend)\n  lexicon.make_pretend(\n    *lexicon.make_address(\n      *lexicon.make_id_expr(var),\n      &lexicon.get_qualified(lexicon.const_qualifier(), lexicon.int_type())\n    ),\n    lexicon.int_type(),\n    lexicon.int_type()\n  );\n}\n"
  },
  {
    "path": "tests/unit-tests/lines.cxx",
    "content": "#include \"doctest/doctest.h\"\n#ifdef _WIN32\n#  include <windows.h>\n#  define WIDEN_(S) L ## S\n#  define WIDEN(S) WIDEN_(S)\n#else\n#  define WIDEN(S) S\n#endif\n\n#define  DUP(S) \\\n    S ## S\n\n#include <iostream>\n#include \"ipr/input\"\n\nTEST_CASE(\"echo input file\") {\n    ipr::input::SystemPath path = WIDEN(__FILE__);\n    ipr::input::SourceListing file{path};\n    std::cout << \"file.size: \" << file.contents().size() << std::endl;\n    std::uint32_t last_line_number = 0;\n    for (auto line : file.lines())\n    {\n        std::cout << '[' << line.number << ']'\n                << \" -> {offset: \" << line.isle.offset\n                << \", length: \" << line.isle.length << \"}\\n\";\n        last_line_number = line.number;\n    }\n    CHECK(last_line_number == 29); // Adjust this number based on the actual number of lines in the file\n}\n"
  },
  {
    "path": "tests/unit-tests/main.cxx",
    "content": "#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN\n#include <doctest/doctest.h>\n"
  },
  {
    "path": "tests/unit-tests/phased-eval.cxx",
    "content": "#include \"doctest/doctest.h\"\n\n#include <ipr/std-preamble>\n\nimport cxx.ipr;\n\n#include <ipr/impl>\n\nTEST_CASE(\"asm-declaration\")\n{\n    using namespace ipr;\n    impl::Lexicon lexicon { };\n\n    auto& s = lexicon.get_string(u8\"yo!\");\n    auto insn = lexicon.make_asm(s);\n    CHECK(physically_same(insn->type(), lexicon.void_type()));\n}\n\nTEST_CASE(\"static_assert-declaration\")\n{\n    using namespace ipr;\n    impl::Lexicon lexicon { };\n    auto cond = lexicon.make_not(lexicon.false_value(), lexicon.bool_type());\n    auto assert = lexicon.make_static_assert(*cond, lexicon.get_string(u8\"wait! what?\"));\n    CHECK(physically_same(assert->type(), lexicon.bool_type()));\n}\n"
  },
  {
    "path": "tests/unit-tests/region-owner.cxx",
    "content": "#include \"doctest/doctest.h\"\r\n\r\n#include <ipr/std-preamble>\r\n\r\nimport cxx.ipr;\r\nimport cxx.ipr.traversal;\r\n\r\n#include <ipr/impl>\r\n#include <ipr/utility-impl>\r\n\r\nconst ipr::Region& nearest_namespace_or_block_region(const ipr::Region& current_region)\r\n{\r\n    using namespace ipr;\r\n    auto* region = &current_region;\r\n    for (;;)\r\n    {\r\n        auto& owner = region->owner().get();\r\n\r\n        if (auto* block = ipr::util::view<Block>(owner))\r\n            return block->region();\r\n        if (auto* ns = ipr::util::view<Namespace>(owner))\r\n            return ns->region();\r\n\r\n        // keep going up\r\n        region = &region->enclosing();\r\n    }\r\n}\r\n\r\nTEST_CASE(\"Region-owner user\") {\r\n  using namespace ipr;\r\n  impl::Lexicon lexicon{};\r\n  impl::Module module{lexicon};\r\n  impl::Interface_unit unit{lexicon, module};\r\n\r\n  // the helper above does not consider namespace to be udt type\r\n  auto& r1 = nearest_namespace_or_block_region(*unit.global_region());\r\n  CHECK(&r1 == unit.global_region());\r\n\r\n  auto& clazz = *lexicon.make_class(*unit.global_region());\r\n  auto& r2 = nearest_namespace_or_block_region(clazz.region());\r\n  CHECK(&r2 == unit.global_region());\r\n}\r\n\r\nTEST_CASE(\"Function morphisms\")\r\n{\r\n  using namespace ipr;\r\n  impl::Lexicon lexicon{};\r\n  impl::Module module{lexicon};\r\n  impl::Interface_unit unit{lexicon, module};\r\n\r\n  auto& region = *unit.global_region();\r\n  auto nesting = Mapping_level{0};\r\n\r\n  auto& spread = *lexicon.make_specifiers_spread();\r\n  auto& callable = *region.make_function_morphism(region, nesting);\r\n  callable.inputs.parms.owned_by = &spread;\r\n  spread.proc_seq.push_back(&callable);\r\n\r\n  auto& r = nearest_namespace_or_block_region(callable.inputs.region());\r\n  CHECK(&r == unit.global_region());\r\n}\r\n"
  },
  {
    "path": "tests/unit-tests/simple.cxx",
    "content": "#include <doctest/doctest.h>\n\n#include <ipr/std-preamble>\n#include <sstream>\n\nimport cxx.ipr;\nimport cxx.ipr.io;\n\n#include <ipr/impl>\n\nTEST_CASE(\"global constant variable can be printed\") {\n  using namespace ipr;\n  impl::Lexicon lexicon{};\n  impl::Module m{lexicon};\n  impl::Interface_unit unit{lexicon, m};\n\n  impl::Scope* global_scope = unit.global_scope();\n\n  auto& name = lexicon.get_identifier(u8\"bufsz\");\n  auto& type = lexicon.get_qualified(lexicon.const_qualifier(), lexicon.int_type());\n  impl::Var* var = global_scope->make_var(name, type);\n  var->init = lexicon.make_literal(lexicon.int_type(), u8\"1024\");\n\n  std::stringstream ss;\n  Printer pp{lexicon, ss};\n  pp << unit;\n  CHECK(!ss.str().empty());\n}\n\nTEST_CASE(\"Can create and print line numbers\")\n{\n  using namespace ipr;\n  impl::Lexicon lexicon{};\n  impl::Module m{lexicon};\n  impl::Interface_unit unit{lexicon, m};\n\n  impl::Scope* global_scope = unit.global_scope();\n\n  auto& name = lexicon.get_identifier(u8\"bufsz\");\n  auto& type = lexicon.get_qualified(lexicon.const_qualifier(), lexicon.int_type());\n  impl::Var* var = global_scope->make_var(name, type);\n  var->init = lexicon.make_literal(lexicon.int_type(), u8\"1024\");\n\n  Source_location loc{ Line_number{1}, Column_number{2}, File_index{1} };\n  var->src_locus = loc;\n\n  std::stringstream ss;\n  Printer pp{lexicon, ss};\n  pp << unit;\n  // By default location printing is off\n  CHECK(ss.str().find(\"F1:1:2\") == std::string::npos);\n  pp.print_locations = true;\n  pp << unit;\n  // Now we should see a location printed.\n  // File name is printed as a file index for brevity\n  CHECK(ss.str().find(\"F1:1:2\") != std::string::npos);\n}\n\nTEST_CASE(\"linkages are deduplicated\") {\n  using namespace ipr;\n  impl::Lexicon lexicon{};\n  auto& l1 = lexicon.cxx_linkage();\n  auto& l2 = lexicon.cxx_linkage();\n  CHECK(&l1 == &l2);\n}\n\nTEST_CASE(\"nullptr defines its own type\") {\n  using namespace ipr;\n  impl::Lexicon lexicon { };\n  auto& null = lexicon.nullptr_value();\n  auto& type = lexicon.get_decltype(null);\n  CHECK(physically_same(type, null.type()));\n}\n\nTEST_CASE(\"Truth values have type bool\") {\n  using namespace ipr;\n  impl::Lexicon lexicon { };\n  auto& vrai = lexicon.true_value();\n  auto& faux = lexicon.false_value();\n  CHECK(physically_same(vrai.type(), lexicon.bool_type()));\n  CHECK(physically_same(faux.type(), lexicon.bool_type()));\n}\n\nTEST_CASE(\"User-defined types have defined types\") {\n  using namespace ipr;\n  impl::Lexicon lexicon { };\n  impl::Translation_unit unit { lexicon };\n  auto& global = unit.global_namespace();\n  auto union_udt = lexicon.make_union(global.region());\n  CHECK(physically_same(union_udt->type(), lexicon.union_type()));\n  auto class_udt = lexicon.make_class(global.region());\n  CHECK(physically_same(class_udt->type(), lexicon.class_type()));\n  auto enum_udt = lexicon.make_enum(global.region(), Enum::Kind::Legacy);\n  CHECK(physically_same(enum_udt->type(), lexicon.enum_type()));\n  auto namespace_udt = lexicon.make_namespace(global.region());\n  CHECK(physically_same(namespace_udt->type(), lexicon.namespace_type()));\n}\n\n"
  },
  {
    "path": "tests/unit-tests/specifiers.cxx",
    "content": "#include <doctest/doctest.h>\n\n#include <ipr/std-preamble>\n#include <ctime>\n#include <ranges>\n#include <sstream>\n\nimport cxx.ipr;\n\n#include <ipr/impl>\n#include <ipr/utility-impl>\n\nconst std::vector<std::u8string_view> specs {\n    u8\"export\",\n    \n    u8\"public\",\n    u8\"protected\",\n    u8\"private\",\n\n    u8\"static\",\n    u8\"extern\",\n    u8\"mutable\",\n    u8\"thread_local\",\n    u8\"register\",\n\n    u8\"virtual\",\n    u8\"explicit\",\n\n    u8\"friend\",\n    u8\"inline\",\n    u8\"consteval\",\n    u8\"constexpr\",\n    u8\"constinit\",\n\n    u8\"typedef\",\n};\n\nTEST_CASE(\"individual basic specifier\") {\n    using namespace ipr;\n    impl::Lexicon lexicon { };\n    impl::Module m {lexicon};\n    impl::Interface_unit unit {lexicon, m};\n\n    for (auto w : specs) {\n        auto& logo = lexicon.get_logogram(lexicon.get_string(w));\n        CHECK(logo.what().characters() == w);\n        auto spec = lexicon.specifiers(ipr::Basic_specifier{logo});\n        CHECK(spec != ipr::Specifiers{});\n\n        auto vec = lexicon.decompose(spec);\n        CHECK(vec.size() == 1);\n        CHECK(vec[0].logogram().what().characters() == w);\n  }\n}\n\nTEST_CASE(\"random combination of basic specifiers\") {\n    using namespace ipr;\n    impl::Lexicon lexicon { };\n\n    std::srand(std::time(nullptr));\n    const auto spec_count = specs.size();\n    const auto sample_size = 1 + std::rand() % spec_count;\n    std::vector<std::u8string_view> test;\n    ipr::Specifiers specifiers { };\n    for (auto i[[maybe_unused]] : std::views::iota(0u, sample_size)) {\n        auto w = specs[std::rand() % sample_size];\n        // Only add new specifier.\n        if (std::find(test.begin(), test.end(), w) < test.end())\n            continue;\n        test.push_back(w);\n        auto& logo = lexicon.get_logogram(lexicon.get_string(w));\n        specifiers |= lexicon.specifiers(ipr::Basic_specifier{logo});\n    }\n    CHECK(test.size() == std::popcount(util::rep(specifiers)));\n\n    auto elements = lexicon.decompose(specifiers);\n    CHECK(elements.size() == test.size());\n\n    std::ranges::sort(test);\n    constexpr auto cmp = [](auto& x, auto& y) { \n        return x.logogram().what().characters() < y.logogram().what().characters(); \n    };\n    std::ranges::sort(elements, cmp);\n    for (auto i = 0u; i < test.size(); ++i) {\n        CHECK(test[i] == elements[i].logogram().what().characters());\n    }\n}"
  },
  {
    "path": "tests/unit-tests/warehouse.cxx",
    "content": "#include \"doctest/doctest.h\"\n\n#include <ipr/std-preamble>\n\nimport cxx.ipr;\n\n#include <ipr/impl>\n\nTEST_CASE(\"warehouse\") {\n    ipr::impl::Lexicon lexicon{};\n\n    union FragileWarehouse\n    {\n        using Type_list = ipr::impl::Warehouse<ipr::Type>;\n        Type_list types;\n        char mem[sizeof(types)];\n        FragileWarehouse() : types() {}\n        ~FragileWarehouse()\n        {\n            // destruct the Warehouse\n            types.~Type_list();\n            // wipe the memory\n            std::fill(std::begin(mem), std::end(mem), 255);\n        }\n    };\n\n    const ipr::Product* product{ };\n    const ipr::Sum* sum{ };\n\n    {\n        FragileWarehouse warehouse;\n        warehouse.types.push_back(lexicon.int_type());\n        warehouse.types.push_back(lexicon.char_type());\n        product = &lexicon.get_product(warehouse.types);\n        sum = &lexicon.get_sum(warehouse.types);\n\n        CHECK(warehouse.types.size() == 2);\n        CHECK(product->size() == 2);\n        CHECK(sum->size() == 2);\n\n        // verify that begin / end works\n        size_t count = 0;\n        for ([[maybe_unused]] auto& type: warehouse.types)\n            ++count;\n        CHECK(count == 2);\n    }\n\n    CHECK(product->size() == 2);  // BOOM if not copied into lexicon type_seq\n    CHECK(sum->size() == 2); // BOOM if not copied into lexicon type_seq\n}\n"
  },
  {
    "path": "tests/unit-tests/words.cxx",
    "content": "#include \"doctest/doctest.h\"\r\n\r\n#include <ipr/std-preamble>\r\n\r\nimport cxx.ipr;\r\n\r\n#include <ipr/impl>\r\n\r\nTEST_CASE(\"words are unified\")\r\n{\r\n    ipr::util::string_pool pool { };\r\n\r\n    auto& int1 = pool.intern(u8\"int\");\r\n    auto& int2 = pool.intern(u8\"int\");\r\n    CHECK(ipr::physically_same(int1, int2));\r\n\r\n    auto& foo1 = pool.intern(u8\"fhoo\");\r\n    auto& foo2 = pool.intern(u8\"fhoo\");\r\n    CHECK(ipr::physically_same(foo1, foo2));\r\n}\r\n"
  }
]