[
  {
    "path": ".clang-format",
    "content": "# the official .clang-format style for https://github.com/taocpp\n#\n# clang-format -i -style=file $(find . -name '[^.]*.[hc]pp')\n\nLanguage: Cpp\nStandard: Latest\n\nAccessModifierOffset: -3\nAlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlinesLeft: false\nAlignOperands: true\nAlignTrailingComments: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: Empty\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: Yes\nBinPackArguments: false\nBinPackParameters: false\nBraceWrapping:\n    AfterClass: true\n    AfterControlStatement: false\n    AfterEnum : true\n    AfterFunction : true\n    AfterNamespace : true\n    AfterStruct : true\n    AfterUnion : true\n    AfterExternBlock: true\n    BeforeCatch : true\n    BeforeElse : true\n    IndentBraces : false\n    SplitEmptyFunction: false\n    SplitEmptyRecord: false\n    SplitEmptyNamespace: false\nBreakBeforeBinaryOperators: All\nBreakBeforeBraces: Custom\nBreakBeforeTernaryOperators: false\nBreakConstructorInitializers: BeforeColon\nBreakInheritanceList: BeforeColon\nBreakStringLiterals: false\nColumnLimit: 0\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nConstructorInitializerIndentWidth: 3\nContinuationIndentWidth: 3\nCpp11BracedListStyle: false\nDerivePointerAlignment: false\nDisableFormat: false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nIncludeBlocks: Preserve\nIndentCaseLabels: true\nIndentPPDirectives: None\nIndentWidth: 3\nIndentWrappedFunctionNames: false\nKeepEmptyLinesAtTheStartOfBlocks: false\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: All\nPointerAlignment: Left\nReflowComments: false\nSortIncludes: true\nSortUsingDeclarations: false\nSpaceAfterCStyleCast: false\nSpaceAfterTemplateKeyword: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCpp11BracedList: false\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: Never\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 2\nSpacesInAngles: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: true\nSpacesInSquareBrackets: true\nTabWidth: 8\nUseTab: Never\n"
  },
  {
    "path": ".cmake/taocpp-config-config.cmake.in",
    "content": "@PACKAGE_INIT@\n\ninclude(CMakeFindDependencyMacro)\nfind_dependency(taocpp-json @TAOCPP_CONFIG_JSON_MIN_VERSION@ CONFIG)\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake\")\n"
  },
  {
    "path": ".codecov.yml",
    "content": "ignore:\n  - src/example/**/*\n"
  },
  {
    "path": ".github/workflows/clang-analyze.yml",
    "content": "name: clang-analyze\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  clang-analyze:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: sudo apt-get install -yq clang-tools\n\n    - run: scan-build cmake -E make_directory build\n\n    - working-directory: build/\n      run: scan-build cmake $GITHUB_WORKSPACE\n\n    - working-directory: build/\n      run: scan-build cmake --build .\n"
  },
  {
    "path": ".github/workflows/clang-format.yml",
    "content": "name: clang-format\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  clang-format:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - uses: DoozyX/clang-format-lint-action@v0.13\n      with:\n        source: './include ./src'\n        extensions: 'hpp,cpp'\n        clangFormatVersion: 13\n"
  },
  {
    "path": ".github/workflows/clang-tidy.yml",
    "content": "name: clang-tidy\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  clang-tidy:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: sudo apt-get install -yq clang-tidy\n\n    - run: find include/ -src/ name '*.hpp' | xargs -I '{}' clang-tidy --quiet '{}' -- --std=c++17 -Iinclude -Iexternal/json/include -Iexternal/PEGTL/include\n"
  },
  {
    "path": ".github/workflows/code-coverage.yml",
    "content": "name: Code Coverage\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  code-coverage:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_CXX_FLAGS=\"-coverage\"\n\n    - working-directory: build/\n      run: cmake --build .\n\n    - working-directory: build/\n      run: ctest --output-on-failure\n\n    - working-directory: build/\n      run: bash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ main ]\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ main ]\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  schedule:\n    - cron: '31 6 * * 0'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'cpp' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]\n        # Learn more:\n        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v2\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v2\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v2\n"
  },
  {
    "path": ".github/workflows/linux.yml",
    "content": "name: Linux\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  linux:\n    strategy:\n      fail-fast: false\n      matrix:\n        compiler:\n          - g++-9\n          - g++-10\n          - g++-11\n          - g++-12\n          - clang++-13\n          - clang++-14\n        build_type: [Debug, Release]\n\n    runs-on: ubuntu-latest\n\n    env:\n      CXX: ${{ matrix.compiler }}\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: cmake --build .\n\n    - working-directory: build/\n      run: ctest --output-on-failure\n\n  linux-old:\n    strategy:\n      fail-fast: false\n      matrix:\n        compiler:\n          - clang++-11\n          - clang++-12\n        build_type: [Debug, Release]\n\n    runs-on: ubuntu-latest\n\n    env:\n      CXX: ${{ matrix.compiler }}\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: sudo apt-get update\n\n    - run: sudo apt-get install -y ${{ matrix.compiler }}\n\n    - run: cmake -E make_directory build\n\n    - working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: cmake --build .\n\n    - working-directory: build/\n      run: ctest --output-on-failure\n\n  linux-clang-extra:\n    strategy:\n      fail-fast: false\n      matrix:\n        build_type: [Debug, Release]\n\n    runs-on: ubuntu-latest\n\n    env:\n      CXX: clang++\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_CXX_FLAGS=\"-fms-extensions\"\n\n    - working-directory: build/\n      run: cmake --build .\n\n    - working-directory: build/\n      run: ctest --output-on-failure\n"
  },
  {
    "path": ".github/workflows/macos.yml",
    "content": "name: macOS\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  xcode:\n    strategy:\n      fail-fast: false\n      matrix:\n        xcode: ['13', '14']\n        build_type: [Debug, Release]\n\n    runs-on: macos-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - uses: maxim-lobanov/setup-xcode@v1\n      with:\n        xcode-version: ${{ matrix.xcode }}\n\n    - run: cmake -E make_directory build\n\n    - working-directory: build/\n      run: cmake $GITHUB_WORKSPACE\n\n    - working-directory: build/\n      run: cmake --build . --config ${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: ctest --config ${{ matrix.build_type }} --output-on-failure\n"
  },
  {
    "path": ".github/workflows/sanitizer.yml",
    "content": "name: Sanitizer\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  sanitizer:\n    strategy:\n      fail-fast: false\n      matrix:\n        cxx: [g++, clang++]\n        sanitizer: [address, undefined]\n\n    runs-on: ubuntu-latest\n\n    env:\n      CXX: ${{ matrix.cxx }}\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_CXX_FLAGS=\"-fsanitize=${{ matrix.sanitizer }}\"\n\n    - working-directory: build/\n      run: cmake --build .\n\n    - working-directory: build/\n      run: ctest --output-on-failure\n"
  },
  {
    "path": ".github/workflows/windows.yml",
    "content": "name: Windows\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n\njobs:\n  vs2022:\n    strategy:\n      fail-fast: false\n      matrix:\n        build_type: [Debug, Release]\n\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - shell: bash\n      working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -G \"Visual Studio 17 2022\"\n\n    - working-directory: build/\n      run: cmake --build . --config ${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: ctest -C ${{ matrix.build_type }} --output-on-failure\n\n  vs2022-clang:\n    strategy:\n      fail-fast: false\n      matrix:\n        build_type: [Debug, Release]\n\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - shell: bash\n      working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -G \"Visual Studio 17 2022\" -T ClangCL\n\n    - working-directory: build/\n      run: cmake --build . --config ${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: ctest -C ${{ matrix.build_type }} --output-on-failure\n\n  vs2019:\n    strategy:\n      fail-fast: false\n      matrix:\n        build_type: [Debug, Release]\n\n    runs-on: windows-2019\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - shell: bash\n      working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -G \"Visual Studio 16 2019\"\n\n    - working-directory: build/\n      run: cmake --build . --config ${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: ctest -C ${{ matrix.build_type }} --output-on-failure\n\n  vs2019-clang:\n    strategy:\n      fail-fast: false\n      matrix:\n        build_type: [Debug, Release]\n\n    runs-on: windows-2019\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        submodules: recursive\n\n    - run: cmake -E make_directory build\n\n    - shell: bash\n      working-directory: build/\n      run: cmake $GITHUB_WORKSPACE -G \"Visual Studio 16 2019\" -T ClangCL\n\n    - working-directory: build/\n      run: cmake --build . --config ${{ matrix.build_type }}\n\n    - working-directory: build/\n      run: ctest -C ${{ matrix.build_type }} --output-on-failure\n"
  },
  {
    "path": ".gitignore",
    "content": "*~\nbuild\nprivate\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"external/json\"]\n\tpath = external/json\n\turl = https://github.com/taocpp/json\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.8...3.19)\n\nproject(taocpp-config VERSION 1.0.0 LANGUAGES CXX)\n\nset(TAOCPP_CONFIG_IS_MAIN_PROJECT OFF)\nif(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)\n  set(TAOCPP_CONFIG_IS_MAIN_PROJECT ON)\nendif()\n\n# installation directories\ninclude(GNUInstallDirs)\n\nset(TAOCPP_CONFIG_INSTALL_DOC_DIR \"${CMAKE_INSTALL_DOCDIR}/tao/config\" CACHE STRING \"The installation doc directory\")\nset(TAOCPP_CONFIG_INSTALL_CMAKE_DIR \"${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake\" CACHE STRING \"The installation cmake directory\")\n\n# define a header-only library\nadd_library(taocpp-config INTERFACE)\nadd_library(taocpp::config ALIAS taocpp-config)\ntarget_include_directories(taocpp-config INTERFACE\n  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>\n  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\n)\n\n# require C++17\ntarget_compile_features(taocpp-config INTERFACE cxx_std_17)\n\n# find a suitable taoJSON\nset(TAOCPP_CONFIG_JSON_MIN_VERSION 1.0.0)\nfind_package(taocpp-json ${TAOCPP_CONFIG_JSON_MIN_VERSION} QUIET CONFIG)\nif(NOT taocpp-json_FOUND)\n  # if a compatible version of taoJSON is not already installed, build and install it from the submodule directory\n  message(STATUS \"Adding taoJSON as submodule from external/json\")\n  set(TAOCPP_JSON_INSTALL ON)\n  set(TAOCPP_JSON_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING \"Override taoJSON include install directory\")\n  set(TAOCPP_JSON_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_DATAROOTDIR}/json/cmake CACHE STRING \"Override taoJSON cmake install directory\")\n  add_subdirectory(external/json)\nendif()\n\n# add taoJSON as a dependency\ntarget_link_libraries(taocpp-config INTERFACE taocpp-json)\n\n# testing\noption(TAOCPP_CONFIG_BUILD_TESTS \"Build test programs\" ${TAOCPP_CONFIG_IS_MAIN_PROJECT})\nif(TAOCPP_CONFIG_BUILD_TESTS)\n  enable_testing()\n  add_subdirectory(src/test/config)\nendif()\n\n# examples\noption(TAOCPP_CONFIG_BUILD_EXAMPLES \"Build example programs\" ${TAOCPP_CONFIG_IS_MAIN_PROJECT})\nif(TAOCPP_CONFIG_BUILD_EXAMPLES)\n  add_subdirectory(src/example/config)\nendif()\n\noption(TAOCPP_CONFIG_INSTALL \"Generate the install target\" ${TAOCPP_CONFIG_IS_MAIN_PROJECT})\nif(TAOCPP_CONFIG_INSTALL)\n  include(CMakePackageConfigHelpers)\n\n  # Make package findable\n  configure_package_config_file(.cmake/taocpp-config-config.cmake.in ${PROJECT_NAME}-config.cmake\n    INSTALL_DESTINATION ${TAOCPP_CONFIG_INSTALL_CMAKE_DIR}\n    NO_CHECK_REQUIRED_COMPONENTS_MACRO\n    NO_SET_AND_CHECK_MACRO\n  )\n\n  # Ignore pointer width differences since this is a header-only library\n  unset(CMAKE_SIZEOF_VOID_P)\n\n  # Enable version checks in find_package\n  write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake COMPATIBILITY SameMajorVersion)\n\n  # keep taocpp::config target compatibility\n  set_target_properties(taocpp-config PROPERTIES EXPORT_NAME config)\n\n  # install and export target\n  install(TARGETS taocpp-config taocpp-json EXPORT ${PROJECT_NAME}-targets)\n  install(FILES\n    ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake\n    ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake\n    DESTINATION ${TAOCPP_CONFIG_INSTALL_CMAKE_DIR}\n  )\n  install(EXPORT ${PROJECT_NAME}-targets\n    NAMESPACE taocpp::\n    DESTINATION ${TAOCPP_CONFIG_INSTALL_CMAKE_DIR}\n  )\n\n  install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\n  install(FILES LICENSE DESTINATION ${TAOCPP_CONFIG_INSTALL_DOC_DIR})\nendif()\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018-2023 Dr. Colin Hirsch and Daniel Frey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# The Art of C++\n# Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n# Please see LICENSE for license or visit https://github.com/taocpp/config\n\n.SUFFIXES:\n.SECONDARY:\n\nCXXSTD = -std=c++17\nCPPFLAGS ?= -pedantic -Iinclude -Iexternal/json/include -Iexternal/json/external/PEGTL/include\nCXXFLAGS ?= -Wall -Wextra -Werror -O3\n\nHEADERS := $(shell find include -name \"*.hpp\")\nSOURCES := $(shell find src -name '*.cpp')\nDEPENDS := $(SOURCES:src/%.cpp=build/dep/%.d)\nBINARIES := $(SOURCES:src/%.cpp=build/bin/%)\n\nUNIT_TESTS := $(filter build/bin/test/%,$(BINARIES))\n\n.PHONY: all\nall: compile check\n\n.PHONY: compile\ncompile: $(BINARIES)\n\n.PHONY: check\ncheck: $(UNIT_TESTS)\n\techo $(UNIT_TESTS)\n\t@set -e; for T in $(UNIT_TESTS); do echo $$T; TAO_CONFIG_VAR=hello $$T; done\n\n.PHONE: clean\nclean:\n\t@rm -rf build/*\n\t@find . -name '*~' -delete\n\nbuild/dep/%.d: src/%.cpp Makefile\n\t@mkdir -p $(@D)\n\t$(CXX) $(CXXSTD) $(CPPFLAGS) -MM -MQ $@ $< -o $@\n\nbuild/bin/%: src/%.cpp build/dep/%.d\n\t@mkdir -p $(@D)\n\t$(CXX) $(CXXSTD) $(CPPFLAGS) $(CXXFLAGS) $< -o $@\n\nifeq ($(findstring $(MAKECMDGOALS),clean),)\n-include $(DEPENDS)\nendif\n"
  },
  {
    "path": "README.md",
    "content": "# The Art of C++ / Config\n\n[![Windows CI](https://github.com/taocpp/config/workflows/Windows/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3AWindows)\n[![macOS CI](https://github.com/taocpp/config/workflows/macOS/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3AmacOS)\n[![Linux CI](https://github.com/taocpp/config/workflows/Linux/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3ALinux)\n<br>\n[![clang-analyze](https://github.com/taocpp/config/workflows/clang-analyze/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3Aclang-analyze)\n[![clang-tidy](https://github.com/taocpp/config/workflows/clang-tidy/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3Aclang-tidy)\n[![Sanitizer](https://github.com/taocpp/config/workflows/Sanitizer/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3ASanitizer)\n[![CodeQL](https://github.com/taocpp/config/workflows/CodeQL/badge.svg)](https://github.com/taocpp/config/actions?query=workflow%3ACodeQL)\n[![Code Coverage](https://codecov.io/gh/taocpp/config/branch/main/graph/badge.svg?token=ykWa8RRdyk)](https://codecov.io/gh/taocpp/config)\n\n[The Art of C++] / Config is a C++ header-only library that reads config files in a format based on [JSON] and [JAXN] and produces a single [JSON Value] as result.\n\n## Documentation\n\n * [Changelog](doc/Changelog.md)\n * [Version 1.x](doc/README.md) (requires C++17)\n\n## Contact\n\nFor questions and suggestions regarding The Art of C++ / Config, success or failure stories, and any other kind of feedback, please feel free to open a [discussion](https://github.com/taocpp/config/discussions), an [issue](https://github.com/taocpp/config/issues) or a [pull request](https://github.com/taocpp/config/pulls) on GitHub or contact the authors at `taocpp(at)icemx.net`.\n\n## Introduction\n\n * [JAXN] syntax with extensions (backward compatible with [JSON]).\n * [JAXN] data model ([JSON] extended with binary data and non-finites).\n * Meta data; all sub-values are annotated with filename and position.\n * Copy via [reference](Writing-Config-Files.md#references), [overwrite](Writing-Config-Files.md#overwrite) and [delete](Writing-Config-Files.md#delete) anything in the data structure.\n * [Include](doc/Writing-Config-Files.md#include-files) other config files into any position in the data structure.\n * And more, the complete list of features is documented on the [Writing Config Files](doc/Writing-Config-Files.md) page.\n * The function [`tao::config::from_file()`](doc/Parsing-Config-Files.md) is all you need to get going.\n\nEvery JSON file with a top-level object can be used as [config file](doc/Writing-Config-Files.md).\n\n```\n{\n   \"ip\": \"127.0.0.2\",\n   \"port\": 27960,\n   \"maps\": [ \"ztn\", \"dm13\", \"t9\" ]\n}\n```\n\nThis small example can be rendered differently using some of the additional syntactic possibilities of the [config file](doc/Writing-Config-Files.md) format.\n\n```\n#!/usr/local/bin/q3s\n\nip = \"127.0.0.2\"\nport = 27960\nmaps = [ \"ztn\" \"dm13\" \"t9\" ]  // Add dm6 or t4?\n```\n\nSemantic features like [deleting](doc/Writing-Config-Files.md#delete) and [referencing](doc/Writing-Config-Files.md#references) values, or [including files](doc/Writing-Config-Files.md#include-files) and [reading environment variables](doc/All-Config-Functions.md#env), usually only make sense with larger, non-trivial real-world examples.\n\nThese features can be used to manage situations that go beyond single deployments with a single config, for example providing the tools to manage configuration templates that are adapted to different environments.\n\n[Parsing](doc/Parsing-Config-Files.md) a [config file](doc/Writing-Config-Files.md) is as simple as calling the appropriate `from_file()` function with the filename.\n\n```\n#include <tao/config.hpp>\n\nconst tao::config::value config = tao::config::from_file( \"foo.cfg\" );\n```\n\nThe resulting value is a [JSON Value] from [taoJSON] with a custom taoCONFIG traits class that annotates every sub-value with the filename and position it was parsed from.\nIt can be inspected -- and manipulated -- using all the facilities of the [taoJSON] library.\n\n## License\n\n<a href=\"https://opensource.org/licenses/MIT\"><img align=\"right\" src=\"https://opensource.org/files/OSIApproved.png\" width=\"150\" hspace=\"20\" alt=\"Open Source Initiative\"></a>\n\nThe Art of C++ / Config is certified [Open Source] software.\nIt may be used for any purpose, including commercial purposes, at absolutely no cost.\nIt is distributed under the terms of the [MIT license] reproduced here.\n\n> Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n>\n> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n>\n> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n>\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[JAXN]: https://github.com/stand-art/jaxn/\n[JSON]: https://tools.ietf.org/html/rfc8259\n[JSON Value]: https://github.com/taocpp/json/\n[MIT license]: http://www.opensource.org/licenses/mit-license.html\n[Open Source]: http://www.opensource.org/docs/definition.html\n[taoJSON]: https://github.com/taocpp/json/\n[The Art of C++]: https://taocpp.github.io/\n"
  },
  {
    "path": "doc/All-Config-Functions.md",
    "content": "# All Config Functions\n\n * [binary](#binary)\n * [default](#default)\n * [env](#env)\n * [jaxn](#jaxn)\n * [parse](#parse)\n * [print](#print)\n * [read](#read)\n * [shell](#shell)\n * [split](#split)\n * [string](#string)\n\nThis page is the reference documentation for all included config functions.\n\nThe [general information on functions and how to use them can be found here.](Writing-Config-Files.md#functions)\n\n\n## binary\n\nThe `binary` function explicitly transforms a string value into a binary value.\nOnly the type is changed, the sequence of bytes stays the same.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (binary \"Hello, world!\")\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   foo: $48656C6C6F2C20776F726C6421\n}\n```\n\n\n## default\n\nThe `default` function takes one or more arguments and returns the first one that is not a JSON `null`.\nIt is an error if all arguments are `null`.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (default 1 2)\nbar = (default null false true)\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   bar: false,\n   foo: 1\n}\n```\n\n\n## env\n\nThe `env` functions obtain the value of an environment variable as string.\nFor plain `env` it is an error when the environment variable does not exist, the `env?` alternative form returns a default value.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (env \"USER\")\nbar = (env? \"GRMBLFX\" \"default\")\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   bar: \"default\",\n   foo: \"colin\"\n}\n```\n\n\n## jaxn\n\nThe `jaxn` function parses string (or binary) data as [JAXN] and returns the resulting value.\nIn the case of binary data the input is automatically converted to a string, including a check for valid UTF-8.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (jaxn '[Infinity, $ff]')\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   foo: [\n      Infinity,\n      $FF\n   ]\n}\n```\n\nNote that `jaxn` is frequently combined with `read` as in `foo = (jaxn (read \"filename.jaxn\"))`.\n\n\n## parse\n\nThe `parse` function parses the given string as a single config value just \"as if\" the config file contained the string instead of the invocation of `parse`.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (parse \"null\")\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   foo: null\n}\n```\n\nThis can be useful when combined with [`env`](#env) for environment variables that contain numeric values as in `foo = (parse (env \"MYVAR\"))`.\n\nNote that the value described in the string is *not* allowed to use addition/concatenation, however references and functions *are* allowed.\nFurther, the `parse` function can **only** be used on \"top-level\", not inside of arguments to other functions.\n\nFor example `foo = (parse (default ...))` is allowed, but `foo = (default (parse ...) ...)` is not.\n\n\n## print\n\nThe `print` function takes a part of the config and turns it back into a JAXN string (which is the same as a JSON string as long as the JAXN extension to the JSON data model, binary data and non-finite floating point numbers, are **not** used).\n\n#### Example taoCONFIG Input File\n\n```\n(temporary foo)\n\nfoo\n{\n    b1 = true\n    b2 = \"Hello, Test!\"\n    b3 = [ $00, $deadbeef ]\n    b4 = 42\n}\n\nstr = (print (foo))\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   str: \"{b1:true,b2:\\\"Hello, Test!\\\",b3:[$00,$DEADBEEF],b4:42}\"\n}\n```\n\n\n## read\n\nThe `read` function returns the contents of a file as binary data.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (read \"tests/doc_value_read.config\")\nbar = (string (read \"tests/doc_value_read.config\"))\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   bar: \"foo = (read \\\"tests/doc_value_read.config\\\")\\nbar = (string (read \\\"tests/doc_value_read.config\\\"))\\n\",\n   foo: $666F6F203D202872656164202274657374732F646F635F76616C75655F726561642E636F6E66696722290A626172203D2028737472696E67202872656164202274657374732F646F635F76616C75655F726561642E636F6E6669672229290A\n}\n```\n\nNote that `read` can be combined with `string` to validate the data as UTF-8 and transform it into a string.\n\nNote that the conversion from `binary` to `string` is automatic when the binary data is passed to a function that expects a string.\nLike [`string`](#string), the automatic conversion checks whether the binary data is a valid UTF-8 sequence and throws an exception if that is not the case.\n\n\n## shell\n\nThe `shell` function executes the given string as shell script and returns its output.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (shell \"uname -s\")\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   foo: \"Darwin\\n\"\n}\n```\n\nNote that availability and behaviour of the `shell` function are inherently system dependent.\nCurrently it is only supported on Unix-style operating systems that are sufficiently POSIX compliant, most prominently Linux and macOS.\n\n\n## split\n\nThe `split` function splits a string into its space-separated components and returns an array of them.\nHere \"space\" is a non-empty sequence of `' ', '\\n', '\\r', '\\t', '\\v' and/or '\\f'` characters.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (split \"a b c \")\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   foo: [\n      \"a\",\n      \"b\",\n      \"c\"\n   ]\n}\n```\n\n\n## string\n\nThe `string` function transforms a binary value into a string value and leaves string values unchanged.\nIt validates that the binary data is valid UTF-8 and produces an error if that is not the case.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = (string $48656C6C6F2C20776F726C6421)\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   foo: \"Hello, world!\"\n}\n```\n\nNote that the conversion from `binary` to `string` is automatic when the binary data is passed to a function that expects a string argument.\nThe automatic conversion, too, checks whether the binary data is a valid UTF-8 sequence and throws an exception if that is not the case.\n\n\n\nCopyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n\n[CBOR]: http://cbor.io\n[JAXN]: https://github.com/stand-art/jaxn\n[JSON]: https://tools.ietf.org/html/rfc8259\n[MsgPack]: http://msgpack.org\n[taoCONFIG]: https://github.com/taocpp/config\n[taoJSON]: https://github.com/taocpp/json\n[UBJSON]: http://ubjson.org\n"
  },
  {
    "path": "doc/Changelog.md",
    "content": "# Changelog\n\n## 1.0.0\n\n**Not yet released**\n\n## Milestones\n\nPre-1.0.0 milestones in rough reverse chronological order.\n\n* Restrict some phase 1 features[^1].\n* Make functions[^2] a phase 2 features.\n* Remove schema support (temporarily?).\n* Reduce member extensions to the essentials.\n* Remove the minus token from config keys.\n* Change the semantics of star and move evaluation to phase two.\n* Refactor everything in order to simplify the implementation.\n* Syntactically turn `delete` into a literal pseudo-value.\n* More intuitive semantics requires less knowledge of implementation details.\n* Change the semantics to perform nested additions by default.\n* Get the interactions between references and additions correct for both arrays and objects.\n\n## History\n\nDevelopment of taoCONFIG started in September 2018 to provide a more expressive config file syntax for [JSON] (or [JAXN]) config files.\n\n\n\nCopyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n\n[^1]: Previously \"member extensions\".\n[^2]: Previously \"value extensions\".\n[JAXN]: https://github.com/stand-art/jaxn\n[JSON]: https://tools.ietf.org/html/rfc8259\n"
  },
  {
    "path": "doc/Parsing-Config-Files.md",
    "content": "# Parsing Config Files\n\n*  [Parsing](#parsing)\n*  [Inspecting](#inspecting)\n*  [Annotations](#annotations)\n*  [Custom Traits](#custom-traits)\n*  [Builtin Schema](#builtin-schema)\n\nThis library requires decent C++17 support.\nMinimum supported compiler versions are GCC 9 and Clang 11.\n\nThe following assumes that the [PEGTL], [taoJSON] and [taoCONFIG] are all available to your compiler, i.e. the include paths are set up correctly.\nWhen checking out [taoCONFIG] via git this can be achieved by (recursively!) initialising and updating all git submodules.\n\nTo access the facilities of this library simply include `<tao/config.hpp>` in your source(s).\n\n## Parsing\n\nThe following functions read and parse one or more config files.\nThe return value is a single [taoJSON] Object in the form of a `tao::config::value` aka. `tao::json::basic_value< tao::config::traits >`.\n\n```c++\ntao::config::value tao::config::from_file( const std::filesystem::path& );\ntao::config::value tao::config::from_files( const std::vector< std::filesystem::path >& files );\n```\n\nWhen more than one file is passed to `from_files()` it behaves (mostly) like parsing a single file with the concatenated contents (the only difference being that while individual files may optionally contain top-level curly braces for the implicit top-level JSON Object it would produce an error if the hypothetical concatenated file would contain multiple top-level objects).\n\nThe config can also be parsed from a `std::string` instead of a file.\nThe second parameter, `source`, should be a string that describes the source of the data.\nIt is used in error messages to indicate not just the line and column numbers.\nSee the [PEGTL] documentation for more details.\n\n```c++\ntao::config::value tao::config::from_string( const std::string& data, const std::string& source );\n```\n\n## Inspecting\n\nSince the parsed config is returned as single [taoJSON] value object, a `tao::json::basic_value< tao::config::traits >`, all facilities from the [taoJSON] library can be used to inspect and operate on such an in-memory config representation.\n\n## Annotations\n\nBy default, i.e. when using the included `tao::config::traits` for `tao::json::basic_value`, the [taoJSON] annotation feature is used to store the \"config Key\", as well as the filename (or, more generally, the source) and line and column numbers where they occurred in the parsed input.\n\nThe config Key is conceptually a kind of strongly typed JSON Pointer.\nThat is, unlike in a JSON Pointer, the string \"2\" and the integer 2 are distinguished.\nStrings can only be used to index objects, and integers can only be used to index arrays.\n\nThe annotation feature sets up `tao::config::annotation` as public base class of every `tao::config::value` object, whereby the public data members of `tao::config::annotation` are available as public data members of every `tao::config::value`, the returned one and all of its sub-values.\n\nThese public data members are:\n\n```c++\n   tao::config::key key;\n   tao::json::position position;  // From tao/json/contrib/position.hpp\n```\n\n## Custom Traits\n\nThe parsing functions are also available in a \"basic\" version that takes the traits for the returned [taoJSON] value as template parameter.\n\n```c++\ntemplate< template< typename... > class Traits >\ntao::json:basic_value< Traits > tao::config::basic_from_file( const std::filesystem::path& );\n\ntemplate< template< typename... > class Traits >\ntao::json:basic_value< Traits > tao::config::basic_from_files( const std::vector< std::filesystem::path >& );\n\ntemplate< template< typename... > class Traits >\ntao::json::basic_value< Traits > tao::config::basic_from_string( const std::string& data, const std::string& source );\n```\n\nBeyond the possibilities given to the traits by the [taoJSON] library this also gives control over the annotation.\n\nThe type `tao::config::annotation` implements the following non-static member functions that are used by the library to set the corresponding annotations.\n\n```c++\n   void set_key( tao::config::key&& );\n   void set_position( const tao::pegtl::position& );\n```\n\nHowever these functions are only called when they are available, so a custom traits class template can choose to omit the annotations by either not setting up a public base class for the [taoJSON] values or by not implementing either or both of these functions in the public base.\n\n\n\nCopyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n\n[PEGTL]: https://github.com/taocpp/PEGTL\n[taoCONFIG]: https://github.com/taocpp/config\n[taoJSON]: https://github.com/taocpp/json\n"
  },
  {
    "path": "doc/README.md",
    "content": "# taoCONFIG Documentation\n\n * [Project](https://github.com/taocpp/config)\n * [Writing Config Files](Writing-Config-Files.md)\n * [All Config Functions](All-Config-Functions.md)\n * [Parsing Config Files](Parsing-Config-Files.md)\n * [Changelog](Changelog.md)\n\n\n\nCopyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n"
  },
  {
    "path": "doc/Writing-Config-Files.md",
    "content": "# Writing Config Files\n\nThe config file syntax is based on [JSON] and is completely backwards compatible:\n\n> **Every [JSON]** (or [JAXN]) **file** with a top-level [JSON] object **is a valid [taoCONFIG] file**.\n\nThe data model is also based on [JSON] and corresponds exactly to the [JAXN] data model as implemented by the [taoJSON] library.\nWe assume that the reader is somewhat familiar with [JSON] and its terminology.\n\n * [General Syntax](#general-syntax)\n   - [Example](#example)\n   - [Comments](#comments)\n   - [Member Names](#member-names)\n   - [Implicit Object](#implicit-object)\n   - [Implicit Commas](#implicit-commas)\n   - [Trailing Commas](#trailing-commas)\n   - [Equality Sign](#equality-sign)\n * [Atomic Values](#atomic-values)\n   - [Literal Names](#literal-names)\n   - [Number Values](#number-values)\n   - [String Values](#string-values)\n   - [Binary Values](#binary-values)\n * [Additional Features](#additional-features)\n   - [Additions](#additions)\n   - [Overwrite](#overwrite)\n   - [Delete](#delete)\n   - [Asterisks](#asterisks)\n   - [References](#references)\n   - [Functions](#functions)\n   - [Dotted Names](#dotted-names)\n   - [Temporaries](#temporaries)\n   - [Include Files](#include-files)\n * [Advanced Considerations](#advanced-considerations)\n\n\n\n# General Syntax\n\nThis first section is in tutorial form.\nIt starts with a simple config file example in JSON form and successively introduces the main syntactic features of taoCONFIG by changing the example to use these features.\n\n\n## Example\n\nThe config file syntax is based on [JSON] and is completely backwards compatible:\n**Every [JSON]** or [JAXN] **file** with a top-level [JSON] object **is a valid [taoCONFIG] file**.\n\nIn particular curly braces and square brackets have the same role as in [JSON], namely defining objects (key-value mappings where the keys are strings) and arrays, respectively.\n\nThe following very simple example [JSON] file will be transformed by using the syntactic possibilities of [taoCONFIG] in the order they are introduced below.\n\n#### Example JSON Config File\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"port\": 27960,\n   \"maps\": [ \"ztn\", \"dm13\", \"t9\" ]\n}\n```\n\n\n## Comments\n\nAll comments that are allowed in [JAXN] can be used in config files, namely\n\n* \"shell-style\" until-end-of-line with `#`,\n* \"C++-style\" until-end-of-line with `//`,\n* and \"C-style\" non-nesting block comments with `/*` and `*/`.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n{\n   \"ip\": \"127.0.0.2\",\n   \"port\": 27960,\n   \"maps\": [ \"ztn\", \"dm13\", \"t9\" ]  // Add dm6 or t4?\n}\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\n\n## Member Names\n\nMember names can use single quotation marks instead of the standard [JSON] double quotation marks.\n\nMember names that are C-style identifiers (non-empty sequences of ASCII characters, digits and underscores that do not start with a digit) can be written without quotation marks.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n{\n   ip: \"127.0.0.2\",\n   \"port\": 27960,\n   'maps': [ \"ztn\", \"dm13\", \"t9\" ]  // Add dm6 or t4?\n}\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\n\n## Implicit Object\n\nThe curly braces for the top-level object are optional and can be omitted.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n\nip: \"127.0.0.2\",\nport: 27960,\nmaps: [ \"ztn\", \"dm13\", \"t9\" ]  // Add dm6 or t4?\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\n\n## Implicit Commas\n\nThe commas separating array elements and object members are also optional and can be omitted.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n\nip: \"127.0.0.2\"\nport: 27960\nmaps: [ \"ztn\" \"dm13\" \"t9\" ]  // Add dm6 or t4?\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\nNote that every single separating comma is individually optional.\n\n\n## Trailing Commas\n\nA single trailing comma is permitted after the last array element or last object member, including after the last member of the implicit top-level object.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n\nip: \"127.0.0.2\",\nport: 27960,\nmaps: [ \"ztn\",\n        \"dm13\",\n        \"t9\", ],  // Add dm6 or t4?\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\n\n## Equality Sign\n\nThe equality sign `=` can be used instead of the standard [JSON] colon `:` to separate the name and value of an object member.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n\nip = \"127.0.0.2\"\nport = 27960\nmaps = [ \"ztn\" \"dm13\" \"t9\" ]  // Add dm6 or t4?\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\n\n\n# Atomic Values\n\nAtomic values are just as in [JSON] and [JAXN].\n\n\n## Literal Names\n\nThe three literal names `null`, `true` and `false` are carred over from [JSON].\n\n#### Example taoCONFIG Input File\n\n```\na = null\nb = true\nc = false\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"a\": null,\n   \"b\": true,\n   \"c\": false\n}\n```\n\nNote that `null`, `true` and `false` as member names are shortcuts for `\"null\"`, `\"true\"` and `\"false\"`, respectively.\n\n\n## Number Values\n\nNumbers are like in [JAXN], i.e. [JSON] numbers with [extensions](https://github.com/stand-art/jaxn/blob/main/Specification.md#numbers).\n\n\n## String Values\n\nStrings are like in [JAXN], i.e. [JSON] strings with [extensions](https://github.com/stand-art/jaxn/blob/main/Specification.md#strings).\n\n\n## Binary Values\n\n[Binary data](https://github.com/stand-art/jaxn/blob/main/Specification.md#binary-data) is also exactly like in [JAXN].\n\n\n\n# Additional Features\n\nFeatures that extend the syntax and/or semantics beyond simple syntactic sugar for [JSON].\n\n\n## Additions\n\nValues of certain types can be added together explicitly or, in some cases, implicitly.\n\n#### Numbers\n\nFor numbers the addition must be explicit and performs the usual addition, however:\n\nGiven that there are three data types for numeric values, signed integer, unsigned integer, and floating point, each with 64bits, the following rules are applied.\n\n * Integer values of the same signedness yield an integer with that signedness as result.\n * Integer values of mixed signedness are converted to signed integers before adding and yield a signed integer as result.\n * Floating-point values can only be added to other floating-point values and yield a floating-point value as result.\n\nThe order in which the additions are performed is undefined, e.g. `foo = 1 + 2 + 3` can be evaluated as either `(1 + 2) + 3` or `1 + (2 + 3)`.\n\n```\nfoo = 42 + 10\nfoo += 3\n// foo is 55\n```\n\n#### Strings\n\nFor strings the addition must be explicit and performs concatenation.\n\n```\nfoo = \"a\" + \"b\"\nfoo += \"c\"\n// foo is \"abc\"\n```\n\nLike in [JAXN] the same concatenations can be performed for binary data, and strings and binary data can **not** be mixed.\n\n#### Arrays\n\nFor arrays the addition can be explicit or implicit and performs concatenation.\n\nThe implicit form is obtained by omitting a `+=` after a name.\n\n```\nfoo = [ 1 2 ] + [ 3 ]\nfoo += [ 4 5 ]\nfoo [ 6 7 ]\n// foo is [ 1 2 3 4 5 6 7 ]\n```\n\n#### Objects\n\nFor objects the addition can be explicit or implicit and performs an object \"merge\" operation.\n\nFor keys that exist only in one of the two objects being merged the result of the merge will contain that object member unchanged.\n\nFor keys that exist in both of the objects being merged the value of the member in the result will depend on whether the second object used a `=` or a `+=` to define the member.\nIn the case of `=` the member from the second object overwrites the member of the first, in the case of `+=` the corresponding values are recursively merged.\n\n#### Example taoCONFIG Input File\n\n```\nfoo\n{\n    a = 1\n    b = 2\n    c = 3\n}\nfoo\n{\n    a = 10\n    b += 20\n    d = 40\n}\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   foo: {\n      a: 10,\n      b: 22,\n      c: 3,\n      d: 40\n   }\n}\n```\n\n\n## Overwrite\n\nA named object member can be assigned-to multiple times with the final assignment \"winning\".\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n\nport = \"TODO!\"\nip = \"127.0.0.2\"\nport = 27960\nmaps = [ \"ztn\" \"dm13\" \"t9\" ]  // Add dm6 or t4?\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"maps\": [\n      \"ztn\",\n      \"dm13\",\n      \"t9\"\n   ],\n   \"port\": 27960\n}\n```\n\nNote that overwriting earlier values can be done on top-level or in any arbitrarily deeply nested part of the config.\n\n\n## Delete\n\nPreviously defined values can be deleted with the literal pseudo-value `delete`.\n\n#### Example taoCONFIG Input File\n\n```\n#!/usr/local/bin/qs\n\nip = \"127.0.0.2\"\nport = 27960\nmaps = [ \"ztn\" \"dm13\" \"t9\" ]\nmaps = delete  // Changed our minds, no maps.\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   \"ip\": \"127.0.0.2\",\n   \"port\": 27960\n}\n```\n\nDeleted values can subsequently be assigned new values or added-to in which case they behave \"as if\" anything that was assigned or added prior to the `delete` never happened.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = 42\nfoo = delete\nfoo += 44\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   foo: 44\n}\n```\n\nNote that `delete` may not be an operand of an addition, i.e. `42 + delete` or similar are **not** allowed.\n\n\n## Asterisks\n\nThe asterisk can be used as special name to designate all array or object members.\nIt is frequently used in conjunction with [dotted names](#dotted-names) to form a pattern for an assignment or addition.\n\n#### Example taoCONFIG Input File\n\n```\nservers\n{\n    primary\n    {\n\tport = 443\n    }\n    secondary\n    {\n        port = 8888\n    }\n}\nservers.*.port = 7000  // Testing\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   servers: {\n      primary: {\n         port: 7000\n      },\n      secondary: {\n         port: 7000\n      }\n   }\n}\n```\n\nAssignments using asterisks **can** be combined with the literal pseudo-value `delete`.\n\n\n## References\n\nReferences are (nested) dotted names written in parentheses that refer to other parts of the config.\nDuring processing of the config file they copy the referenced value.\n\n```\nfoo = 42\nbar = (foo)\n// bar is 42\n```\n\nReferences are resolved relative to the array or object scope in which they syntactically occur, similar to how name lookups from within nested namespaces are handled in the C++ programming language.\n\n#### Example taoCONFIG Input File\n\n```\nr = (a.b.x)\n\na\n{\n    b\n    {\n        c\n        {\n            i = (x)\n            j = (b.x)\n            k = (a.x)\n\n            x = 4\n\t}\n        x = 3\n    }\n    x = 2\n}\nx = 1\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   a: {\n      b: {\n         c: {\n            i: 4,\n            j: 3,\n            k: 2,\n            x: 4\n         },\n         x: 3\n      },\n      x: 2\n   },\n   r: 3,\n   x: 1\n}\n```\n\nIt is an error if there is no order in which all additions, functions and references can be resolved due cyclic references!\n\n#### Example Broken Input Files\n\nCyclic references are an error for obvious reasons.\n\n```\na = (b)\nb = (a)\n```\n\nIt is also an error when a reference can't be resolved due to the first component of the reference \"anchoring\" the lookup to the \"wrong\" place.\nConsider the following example:\n\n```\na\n{\n    a\n    {\n        c = (a.b)\n    }\n    b = 1\n}\n```\n\nThe lookup of `a.b` starts by attempting to find `a` inside of `a.a`.\nThis fails because there is only `c` within `a.a`, not another `a` that could be matched to the `a` in `a.b`.\nNext the lookup steps outside of `a.a` and attempts to find the `a` from `a.b` within `a`.\nThis succeeds, anchoring the lookup of `a.b` to `a.a`.\nMore precisely, the second component of `a.a` is matched with the first component of `a.b`.\nNow the example generates an error because there is no `b` within `a.a`.\n\nThe search is not continued inside the top-level `a` because once the lookup is anchored no backtracking is performed.\nThis is similar to the name lookup rules in the C++ programming language.\n\n\n### Nested References\n\nReferences can be arbitrarily **nested**, that is parts of a reference can themselves be a reference!\nFor this to work the \"inner\" reference must refer to a value that can natuarlly occur as part of a reference, namely a string or an integer.\n\n#### Example taoCONFIG Input File\n\n```\nfoo = [ 10 11 12 13 14 ]\nbar = 3\nbaz = (foo.(bar))\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   bar: 3,\n   baz: 13,\n   foo: [\n      10,\n      11,\n      12,\n      13,\n      14\n   ]\n}\n```\n\n### References vs. Temporary\n\nWhen referencing values marked as [temporary](Member-Extensions.md#temporary) the copied value will **not** be marked as [temporary](#temporaries), however any sub-values will retain their temporary status.\n\n#### Example taoCONFIG Input File\n\n```\n(temporary foo)\n(temporary foo.baz)\n\nfoo\n{\n    bar\n    {\n        a = 1\n    }\n    baz\n    {\n        b = 2\n    }\n}\n\nttt = (foo)\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   ttt: {\n      bar: {\n         a: 1\n      }\n   }\n}\n```\n\n\n## Functions\n\nThis library contains [a set of config functions](All-Config-Functions.md).\nThese functions can be used in config files to perform operations on values.\nApplications can also add custom functions.\n\nFunctions are syntactically similar to references in taoCONFIG, and to lists or function calls in Scheme and LISP.\nA function call has one or more arguments, wherefore `(foo)` is parsed as a reference rather than a call to a nullary function.\n\nFor example the following config file assigns the value of the environment (shell) variable `$USER` to the config key `foo`.\n\n```\nfoo = (env \"USER\")\n```\n\nFunctions can occur anywhere a value can occur.\nA function's arguments can be literal values, other function calls, additions, references, or any combination or nesting of these.\n\nThe next example does the same as the previous one, albeit in a slightly contrived manner that shows a composed function argument with reference.\n\n```\nbar = \"ER\"\nfoo = (env \"US\" + (bar))\n```\n\nThe config functions supplied with this library are listed and explained on [a separate page](All-Config-Functions.md).\n\nTo add custom functions to a config parser and make them available to your config files please consult `src/test/config/custom.cpp` or contact the developers of this library.\n\n\n## Dotted Names\n\nWherever the name of an object member is expected it is also possible to use a name with multiple dot-separated components.\n\nDotted names can contain multiple kinds of components.\n\n1.  Strings, intended to index objects.\n2.  Unsigned integers, intended to index arrays.\n4.  The [asterisk](#asterisks), intended to index objects or arrays.\n\nThe asterisk indexes into all object members or array elements.\n\n#### Example taoCONFIG Input File\n\n```\nfoo\n{\n    bar.baz += 1\n}\nfoo.bar\n{\n    baz += 1\n}\nfoo.bar.baz += 1\n```\n\n#### Resulting JSON Config Data\n\n```javascript\n{\n   foo: {\n      bar: {\n         baz: 3\n      }\n   }\n}\n```\n\nJust as for single-component names, integers, and other strings that are not C-style identifiers can be used with (single or double) quotes.\nFor example the dotted name `foo.\"1.2.3\".bar` consists of three components, the strings `\"foo\"`, `\"1.2.3\"` and `\"bar\"`.\n\nDotted names can be thought of as strongly-typed JSON Pointers; there is no ambiguity about whether an integer is intended to index an array or an object.\n\n\n## Include Files\n\nThe `include` feature reads the named file relative to the current working directory and parses it \"as if\" the contents of that file were present instead of the `include`.\nFor plain `include` it is an error when the file does not exist, the `include?` alternative form silently ignores this case.\n\nThe filename has to be supplied as non-empty string in double quotes and can contain arbitrary characters except for the double quote itself.\nConsequently, and unlike all other quoted strings in this library, *no escape sequences* are recognised.\n\nFiles can be included anywhere an object member can be defined.\nThe top-level definitions of the included file will appear in the same place of the JSON hierarchy as the `include`.\n\n#### Example taoCONFIG Input File\n\n```\n// Include the file whose contents are shown below.\n(include \"tests/doc_include.inc\")\n\nfoo\n{\n    // Include the same file again, this time within an object.\n    (include \"tests/doc_include.inc\")\n}\n\n// Use include? with a non-existing file, not an error.\n(include? \"tests/non_existing_file_is_no_error_with_include?\")\n```\n\n#### Example taoCONFIG Include File\n\n```\nbar = 42\nbaz = [ true, false ]\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   bar: 42,\n   baz: [\n      true,\n      false\n   ],\n   foo: {\n      bar: 42,\n      baz: [\n         true,\n         false\n      ]\n   }\n}\n```\n\n\n## Temporaries\n\nSometimes parts of the configuration that are required during config file parsing, for example in order to be [referenced](#references), are not themselves considered part of the actual config.\nIn these cases the `temporary` feature can be used to exclude any part of the JSON hierarchy from the final config parsing result.\n\nLike `include` the `temporary` statement can occur anywhere an object member can be defined.\nIt takes a single config key, which can include [asterisks](#asterisks) and be any [dotted name](#dotted-names), as argument.\n\nThe argument is always interpreted relative to the position of the `temporary` in the object hierarchy.\nFor example a `(temporary c.d)` within an object at `a.b` would mark `a.b.c.d` as temporary, independent of whether that node exists (yet).\n\n#### Example taoCONFIG Input File\n\n```\n(temporary template)  // Can occur before...\n\ntemplate\n{\n    host = \"127.0.0.1\"\n    port = 6000\n    version = 42\n}\n\nfoo = (template) +\n{\n    host = \"127.0.0.2\"\n}\n\nbar = (template) +\n{\n    port = 6001\n}\n\n(temporary template)  // ...and/or after.\n\n```\n\n#### Resulting JAXN Config Data\n\n```javascript\n{\n   bar: {\n      host: \"127.0.0.1\",\n      port: 6001,\n      version: 42\n   },\n   foo: {\n      host: \"127.0.0.2\",\n      port: 6000,\n      version: 42\n   }\n}\n```\n\nSimilarly the `permanent` feature can be used to restore any part of the JSON hierarchy that was marked as `temporary` to the default behaviour of being part of the final result data.\n\n\n\n# Advanced Considerations\n\nFor technical reasons reading a configuration is performed in multiple steps.\nAuthors of config files need to be aware of the two main phases in order to fully understand the semantics of their configs.\n\n### Phase One\n\nThe first phase does the reading and parsing of all configuration files.\n\nDuring this phase all assignments, additions and deletions are recorded in their order of occurrence.\nThe same goes for included files, their assignments, additions and deletions are performed when and where the include was encountered during parsing.\n\n### Phase Two\n\nThe second phase successively replaces all functions, references and additions with the result of their evaluation.\n\nDuring this phase the order in which things were parsed is no longer relevant.\n\n * Functions are eliminated as soon as their arguments are \"plain\" values, i.e. they are free from functions, references and additions, by replacing the function with the result of calling said function.\n * References are eliminated as soon as the referenced value is \"plain\", by replacing the reference with a (deep) copy of the referenced value.\n * Additions are eliminated as soon as both operands are \"plain\", again by replacing the two operands with the result of the addition (which can be a concatenation, or, for objects, a merge).\n\n### Why Phases?\n\nThe semantics of `delete`, `+=` and `=`, and, by extension, `include`, depends on the order in which they are processed.\nThis is due to the combination of features being non-monotonic, which requires linear processing for predictable behaviour.\n\nHowever for references this would be too limiting as only previously defined values could be referenced, and delta[^1] config files might not be able to make the required modifications.\nWith references that can \"point\" both forwards and backwards this problem does not arise.\n\n#### Example taoCONFIG Input File\n\n```\nhosts\n{\n    arctic\n    {\n        foo = 42\n    }\n    mystic\n    {\n        foo = 23\n    }\n}\nhost = (env \"HOST\")\n\n(temporary host)\n(temporary hosts)\n\nconfig\n{\n    mode = \"FOBBLE\"\n    size = (hosts.(host).foo)\n}\n\n(include? \"test_delta_config.cfg\")\n```\n\nThis example shows a configuration with parameters that depend on the name of the host machine.\n\n#### Example taoCONFIG Delta File\n\n```\nhosts.test01.foo = 3\n```\n\nIf references were resolved when encountered then the delta config would have no effect -- the `foo` value for the additional host `test01` would be available only *after* the refernce for `config.size` was resolved.\n\nLuckily this is not how taoCONFIG works, the references are resolved during the second phase, and everything will work as expected.\n\n\n\nCopyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n\n[^1]: A \"delta\" config is typically a configuration file that is optionally included at the end of a full configuration file. The full configuration file usually configures an application for an operational environment; the delta config can optionally modify the full configuration, e.g. for a test environment that might be funcionally identical to the operational environment but have minor differences like using different hostnames.\n\n[CBOR]: http://cbor.io\n[JAXN]: https://github.com/stand-art/jaxn\n[JSON]: https://tools.ietf.org/html/rfc8259\n[MsgPack]: http://msgpack.org\n[taoCONFIG]: https://github.com/taocpp/config\n[taoJSON]: https://github.com/taocpp/json\n[UBJSON]: http://ubjson.org\n"
  },
  {
    "path": "include/tao/config/access.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_ACCESS_HPP\n#define TAO_CONFIG_ACCESS_HPP\n\n#include <cassert>\n#include <stdexcept>\n\n#include \"key.hpp\"\n#include \"value.hpp\"\n\n#include \"internal/json.hpp\"\n#include \"internal/string_utility.hpp\"\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   [[nodiscard]] const json::basic_value< Traits >& access( const json::basic_value< Traits >& v, const key& k );\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] const json::basic_value< Traits >& access_name( const json::basic_value< Traits >& v, const std::string& k, const key& p )\n   {\n      if( !v.is_object() ) {\n         throw std::runtime_error( internal::strcat( \"attempt to index non-object with \\\"\", k, \"\\\"\" ) );\n      }\n      const auto j = v.get_object().find( k );\n\n      if( j == v.get_object().end() ) {\n         throw std::runtime_error( internal::strcat( \"object index \\\"\", k, \"\\\" not found\" ) );\n      }\n      return access( j->second, p );\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] const json::basic_value< Traits >& access_index( const json::basic_value< Traits >& v, const std::size_t n, const key& p )\n   {\n      if( !v.is_array() ) {\n         throw std::runtime_error( internal::strcat( \"attempt to index non-array with \", n ) );\n      }\n      if( v.get_array().size() <= n ) {\n         throw std::runtime_error( internal::strcat( \"array index \", n, \" out of bounds \", v.get_array().size() ) );\n      }\n      return access( v.get_array()[ n ], p );\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] const json::basic_value< Traits >& access( const json::basic_value< Traits >& v, const key& k )\n   {\n      if( k.empty() ) {\n         return v;\n      }\n      switch( k[ 0 ].kind() ) {\n         case key_kind::name:\n            return access_name( v, k[ 0 ].get_name(), pop_front( k ) );\n         case key_kind::index:\n            return access_index( v, k[ 0 ].get_index(), pop_front( k ) );\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/annotation.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_ANNOTATION_HPP\n#define TAO_CONFIG_ANNOTATION_HPP\n\n#include <ostream>\n\n#include <tao/json.hpp>\n#include <tao/json/contrib/position.hpp>\n\n#include <tao/pegtl/position.hpp>\n\n#include \"key.hpp\"\n\nnamespace tao::config\n{\n   struct annotation\n   {\n      config::key key;\n      json::position position;  // TODO: json::position, pegtl::position or TBD config::position?\n\n      annotation() = default;\n\n      annotation( annotation&& ) = default;\n      annotation& operator=( annotation&& ) = default;\n\n      annotation( const annotation& ) = default;\n      annotation& operator=( const annotation& ) = default;\n\n      void set_key( config::key k ) noexcept\n      {\n         key = std::move( k );\n      }\n\n      void set_position( json::position p ) noexcept\n      {\n         position = std::move( p );\n      }\n\n      void set_position( const pegtl::position& pos )\n      {\n         position.set_position( pos );\n      }\n\n      void append_message_extension( std::ostream& o ) const\n      {\n         to_stream( o, key );\n         o << ' ';\n         position.append_message_extension( o );\n      }\n   };\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/assign.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_ASSIGN_HPP\n#define TAO_CONFIG_ASSIGN_HPP\n\n#include <cassert>\n#include <stdexcept>\n\n#include \"key.hpp\"\n#include \"value.hpp\"\n\n#include \"internal/json.hpp\"\n#include \"internal/string_utility.hpp\"\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const key& k );\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const std::string& k, const key& p )\n   {\n      if( !v.is_object() ) {\n         throw std::runtime_error( internal::strcat( \"attempt to index non-object with \\\"\", k, \"\\\"\" ) );\n      }\n      const auto t = v.get_object().try_emplace( k, json::empty_object );  // TODO: Detect empty_array vs. empty_object?\n      return assign( t.first->second, p );\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const std::size_t n, const key& p )\n   {\n      if( !v.is_array() ) {\n         throw std::runtime_error( internal::strcat( \"attempt to index non-array with \", n ) );\n      }\n      if( v.get_array().size() <= n ) {\n         throw std::runtime_error( internal::strcat( \"array index \", n, \" out of bounds \", v.get_array().size() ) );\n      }\n      return assign( v.get_array()[ n ], p );\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const key& k )\n   {\n      if( k.empty() ) {\n         return v;\n      }\n      switch( k[ 0 ].kind() ) {\n         case key_kind::name:\n            return assign( v, k[ 0 ].get_name(), pop_front( k ) );\n         case key_kind::index:\n            return assign( v, k[ 0 ].get_index(), pop_front( k ) );\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/contrib/rot13.hpp",
    "content": "// Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_CONTRIB_ROT13_HPP\n#define TAO_CONFIG_CONTRIB_ROT13_HPP\n\n#include <string>\n\n#include \"../internal/atom.hpp\"\n#include \"../internal/pegtl.hpp\"\n\nnamespace tao::config\n{\n   [[nodiscard]] inline internal::string_t rot13( const pegtl::position& pos, const std::string& in )\n   {\n      internal::string_t out( in, pos );\n\n      for( char& c : out.value ) {\n         if( ( ( 'a' <= c ) && ( c <= 'm' ) ) || ( ( 'A' <= c ) && ( c <= 'M' ) ) ) {\n            c += 13;\n         }\n         else if( ( ( 'n' <= c ) && ( c <= 'z' ) ) || ( ( 'N' <= c ) && ( c <= 'Z' ) ) ) {\n            c -= 13;\n         }\n      }\n      return out;\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/from_file.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_FROM_FILE_HPP\n#define TAO_CONFIG_FROM_FILE_HPP\n\n#include <filesystem>\n#include <utility>\n\n#include \"internal/config_parser.hpp\"\n#include \"value.hpp\"\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > basic_from_file( const std::filesystem::path& path )\n   {\n      internal::config_parser c;\n      c.parse( path );\n      return c.finish< Traits >();\n   }\n\n   [[nodiscard]] inline value from_file( const std::filesystem::path& path )\n   {\n      return basic_from_file< traits >( path );\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/from_files.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_FROM_FILES_HPP\n#define TAO_CONFIG_FROM_FILES_HPP\n\n#include <filesystem>\n#include <utility>\n#include <vector>\n\n#include \"internal/config_parser.hpp\"\n#include \"value.hpp\"\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > basic_from_files( const std::vector< std::filesystem::path >& paths )\n   {\n      internal::config_parser c;\n      for( const auto& path : paths ) {\n         c.parse( path );\n      }\n      return c.finish< Traits >();\n   }\n\n   [[nodiscard]] inline value from_files( const std::vector< std::filesystem::path >& paths )\n   {\n      return basic_from_files< traits >( paths );\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/from_input.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_FROM_INPUT_HPP\n#define TAO_CONFIG_FROM_INPUT_HPP\n\n#include <utility>\n\n#include \"internal/config_parser.hpp\"\n#include \"internal/pegtl.hpp\"\n#include \"value.hpp\"\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > basic_from_input( pegtl_input_t&& in )\n   {\n      internal::config_parser c;\n      c.parse( std::move( in ) );\n      return c.finish< Traits >();\n   }\n\n   [[nodiscard]] inline value from_input( pegtl_input_t&& in )\n   {\n      return basic_from_input< traits >( std::move( in ) );\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/from_string.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_FROM_STRING_HPP\n#define TAO_CONFIG_FROM_STRING_HPP\n\n#include <string>\n#include <string_view>\n#include <utility>\n\n#include \"internal/config_parser.hpp\"\n#include \"value.hpp\"\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > basic_from_string( const char* data, const std::size_t size, const std::string& source )\n   {\n      internal::config_parser c;\n      c.parse( data, size, source );\n      return c.finish< Traits >();\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > basic_from_string( const std::string_view data, const std::string& source )\n   {\n      return basic_from_string< Traits >( data.data(), data.size(), source );\n   }\n\n   [[nodiscard]] inline value from_string( const char* data, const std::size_t size, const std::string& source )\n   {\n      return basic_from_string< traits >( data, size, source );\n   }\n\n   [[nodiscard]] inline value from_string( const std::string_view data, const std::string& source )\n   {\n      return from_string( data.data(), data.size(), source );\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/array.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_ARRAY_HPP\n#define TAO_CONFIG_INTERNAL_ARRAY_HPP\n\n#include <list>\n#include <string>\n\n#include \"forward.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename C >\n   struct basic_array\n   {\n      using data_t = std::list< C >;\n\n      basic_array() = delete;\n\n      explicit basic_array( const pegtl::position& p )\n         : position( p )\n      {}\n\n      explicit basic_array( const std::string& f, const pegtl::position& p )\n         : function( f ),\n           position( p )\n      {}\n\n      basic_array( basic_array&& ) = default;\n      basic_array( const basic_array& ) = default;\n\n      ~basic_array() = default;\n\n      basic_array& operator=( basic_array&& ) = default;\n      basic_array& operator=( const basic_array& ) = default;\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         return position;\n      }\n\n      std::string function;\n      std::list< C > array;\n      pegtl::position position;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/atom.hpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_ATOM_HPP\n#define TAO_CONFIG_INTERNAL_ATOM_HPP\n\n#include <cstdint>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   struct null\n   {\n      explicit null( const pegtl::position& pos )\n         : position( pos )\n      {}\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         return position;\n      }\n\n      pegtl::position position;\n   };\n\n   template< typename T >\n   struct atom\n   {\n      template< typename V >\n      atom( V&& v, const pegtl::position& pos )\n         : value( std::forward< V >( v ) ),\n           position( pos )\n      {}\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         return position;\n      }\n\n      T value;\n      pegtl::position position;\n   };\n\n   using boolean = atom< bool >;\n   using string_t = atom< std::string >;\n   using binary_t = atom< std::vector< std::byte > >;\n\n   using signed_t = atom< std::int64_t >;\n   using unsigned_t = atom< std::uint64_t >;\n   using double_t = atom< double >;\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/change_action_and_states.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Distributed under the Boost Software License, Version 1.0.\n// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)\n\n#ifndef TAO_CONFIG_INTERNAL_CHANGE_ACTION_AND_STATES_HPP\n#define TAO_CONFIG_INTERNAL_CHANGE_ACTION_AND_STATES_HPP\n\n#include <cstddef>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< template< typename... > class NewAction, typename... NewStates >\n   struct change_action_and_states\n      : pegtl::maybe_nothing\n   {\n      template< typename Rule,\n                pegtl::apply_mode A,\n                pegtl::rewind_mode M,\n                template< typename... >\n                class Action,\n                template< typename... >\n                class Control,\n                std::size_t... Ns,\n                typename ParseInput,\n                typename... States >\n      [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st )\n      {\n         auto t = std::tie( st... );\n         const auto pos = in.position();\n         if( Control< Rule >::template match< A, M, NewAction, Control >( in, std::get< Ns >( t )... ) ) {\n            if constexpr( A == pegtl::apply_mode::action ) {\n               Action< Rule >::success( pos, st... );\n            }\n            return true;\n         }\n         return false;\n      }\n\n      template< typename Rule,\n                pegtl::apply_mode A,\n                pegtl::rewind_mode M,\n                template< typename... >\n                class Action,\n                template< typename... >\n                class Control,\n                typename ParseInput,\n                typename... States >\n      [[nodiscard]] static bool match( ParseInput& in, States&&... st )\n      {\n         static_assert( !std::is_same_v< Action< void >, NewAction< void > >, \"old and new action class templates are identical\" );\n         return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/concat.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_CONCAT_HPP\n#define TAO_CONFIG_INTERNAL_CONCAT_HPP\n\n#include <cstddef>\n#include <cstdint>\n#include <iterator>\n#include <list>\n#include <stdexcept>\n#include <string>\n#include <utility>\n\n#include \"constants.hpp\"\n#include \"entry_kind.hpp\"\n#include \"forward.hpp\"\n#include \"json.hpp\"\n#include \"key1.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename E >\n   struct basic_concat\n   {\n      using data_t = std::list< E >;\n      using iterator_t = typename std::list< E >::iterator;\n\n      basic_concat() = delete;\n\n      explicit basic_concat( const pegtl::position& p )\n         : position( p )\n      {}\n\n      basic_concat( basic_concat&& ) = default;\n      basic_concat( const basic_concat& ) = default;\n\n      ~basic_concat() = default;\n\n      basic_concat& operator=( basic_concat&& ) = default;\n      basic_concat& operator=( const basic_concat& ) = default;\n\n      [[nodiscard]] bool omit_from_final_result() const noexcept\n      {\n         return implicit || temporary || concat.empty();\n      }\n\n      template< typename T >\n      void back_ensure_init( const T k, const pegtl::position& p )\n      {\n         if( concat.empty() ) {\n            concat.emplace_back( k, p );\n         }\n         else if( concat.back().kind() != T::kind ) {\n            concat.emplace_back( k, p );\n         }\n      }\n\n      void back_emplace_func( const std::string& name, const pegtl::position& p )\n      {\n         back_ensure_init( array_init, p );\n         concat.back().get_array().function = name;\n      }\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         return position;\n      }\n\n      bool remove = false;     // Whether generated by += (false) or by = (true), because in the latter case everything that comes before must be removed.\n      bool implicit = false;   // Whether implicitly generated by a delete, e.g. a.b.c = delete when a.b doesn't even exist, so it's implicitly generated to set the remove flag on a.b.c.\n      bool temporary = false;  // Whether flagged as temporary by the user, i.e. this is not to be included in the final result and will be omitted by phase3.\n\n      std::uint64_t generation = 0;\n\n      std::list< E > concat;\n      pegtl::position position;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/config_action.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_CONFIG_ACTION_HPP\n#define TAO_CONFIG_INTERNAL_CONFIG_ACTION_HPP\n\n#include <cassert>\n#include <cerrno>\n#include <string>\n#include <system_error>\n#include <utility>\n#include <vector>\n\n#include \"concat.hpp\"\n#include \"config_grammar.hpp\"\n#include \"constants.hpp\"\n#include \"entry_kind.hpp\"\n#include \"forward.hpp\"\n#include \"json.hpp\"\n#include \"key1.hpp\"\n#include \"key1_action.hpp\"\n#include \"key1_guard.hpp\"\n#include \"pegtl.hpp\"\n#include \"phase1_append.hpp\"\n#include \"string_utility.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename Rule >\n   struct config_action\n      : pegtl::nothing< Rule >\n   {};\n\n   template<>\n   struct config_action< rules::assign_head >\n   {\n      template< typename State >\n      static void apply0( State& st, const function_map& /*unused*/ )\n      {\n         const auto f = []( concat& c ) { c.concat.clear(); c.remove = true; };\n         phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::implicit );\n      }\n   };\n\n   template<>\n   struct config_action< json::jaxn::internal::rules::begin_array >\n   {\n      template< typename Input, typename State >\n      static void apply( Input& in, State& st, const function_map& /*unused*/ )\n      {\n         const auto p = in.position();\n         const auto f = [ & ]( concat& c ) { c.back_ensure_init( array_init, p ); };\n         phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );\n      }\n   };\n\n   template<>\n   struct config_action< json::jaxn::internal::rules::begin_object >\n   {\n      template< typename Input, typename State >\n      static void apply( Input& in, State& st, const function_map& /*unused*/ )\n      {\n         const auto p = in.position();\n         const auto f = [ & ]( concat& c ) { c.back_ensure_init( object_init, p ); };\n         phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );\n      }\n   };\n\n   template<>\n   struct config_action< rules::function_name >\n   {\n      template< typename Input, typename State >\n      static void apply( Input& in, State& st, const function_map& /*unused*/ )\n      {\n         const auto s = in.string();\n         const auto p = in.position();\n         const auto f = [ & ]( concat& c ) { c.back_emplace_func( s, p ); };\n         phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );\n      }\n   };\n\n   template<>\n   struct config_action< rules::value_list >\n   {\n      template< typename State >\n      static void apply0( State& st, const function_map& /*unused*/ )\n      {\n         assert( !st.suffix.empty() );\n\n         st.suffix.back().set_generation( ++st.generation );\n      }\n   };\n\n   template<>\n   struct config_action< rules::element_list >\n      : pegtl::instantiate< key1_guard >\n   {};\n\n   template<>\n   struct config_action< rules::extension_list >\n      : pegtl::instantiate< key1_guard >\n   {};\n\n   template<>\n   struct config_action< rules::key1_rule >\n      : pegtl::change_action_and_state< key1_action, std::vector< key1_part > >\n   {\n      template< typename Input, typename State >\n      static void success( const Input& /*unused*/, std::vector< key1_part >& s, State& st, const function_map& /*unused*/ )\n      {\n         assert( st.member.empty() );\n         std::swap( st.member.vector(), s );\n      }\n   };\n\n   template<>\n   struct config_action< rules::temporary_extension >\n   {\n      template< typename State >\n      static void apply0( State& st, const function_map& /*unused*/ )\n      {\n         assert( !st.member.empty() );\n         const auto f = []( concat& c ) { c.temporary = true; };\n         phase1_append( st.root, st.prefix + st.suffix + st.member, f, phase1_mode::implicit );\n         st.member.vector().clear();\n      }\n   };\n\n   template<>\n   struct config_action< rules::permanent_extension >\n   {\n      template< typename State >\n      static void apply0( State& st, const function_map& /*unused*/ )\n      {\n         assert( !st.member.empty() );\n         const auto f = []( concat& c ) { c.temporary = false; };\n         phase1_append( st.root, st.prefix + st.suffix + st.member, f, phase1_mode::implicit );\n         st.member.vector().clear();\n      }\n   };\n\n   template<>\n   struct config_action< rules::include >\n   {\n      template< typename State >\n      static void apply0( State& st, const function_map& /*unused*/ )\n      {\n         st.include_is_optional = false;\n      }\n   };\n\n   template<>\n   struct config_action< rules::inc_if >\n   {\n      template< typename State >\n      static void apply0( State& st, const function_map& /*unused*/ )\n      {\n         st.include_is_optional = true;\n      }\n   };\n\n   template<>\n   struct config_action< rules::inc_fn >\n   {\n      template< typename Input, typename State >\n      static void apply( const Input& ai, State& st, const function_map& fm )\n      {\n         try {\n            pegtl::file_input in( ai.string() );\n            pegtl::parse_nested< rules::config_file, config_action >( ai.position(), static_cast< pegtl_input_t& >( in ), st, fm );\n         }\n         catch( const std::system_error& e ) {\n            if( !st.include_is_optional ) {\n               throw pegtl::parse_error( strcat( \"include error: \", e.what() ), ai.position() );\n            }\n            if( e.code().value() != ENOENT ) {\n               throw pegtl::parse_error( strcat( \"include optional error: \", e.what() ), ai.position() );\n            }\n         }\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/config_grammar.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_CONFIG_GRAMMAR_HPP\n#define TAO_CONFIG_INTERNAL_CONFIG_GRAMMAR_HPP\n\n#include \"forward.hpp\"\n#include \"jaxn_action.hpp\"\n#include \"jaxn_to_entry.hpp\"\n#include \"json.hpp\"\n#include \"key1_grammar.hpp\"\n#include \"key1_guard.hpp\"\n#include \"parse_utility.hpp\"\n#include \"pegtl.hpp\"\n#include \"phase1_append.hpp\"\n#include \"reference2.hpp\"\n\nnamespace tao::config::internal::rules\n{\n   struct jaxn_value\n   {\n      using rule_t = jaxn_value;\n      using subs_t = pegtl::type_list< json::jaxn::internal::rules::sor_single_value >;\n\n      template< pegtl::apply_mode A,\n                pegtl::rewind_mode M,\n                template< typename... >\n                class Action,\n                template< typename... >\n                class Control,\n                typename State >\n      [[nodiscard]] static bool match( pegtl_input_t& in, State& st, const function_map& /*unused*/ )\n      {\n         jaxn_to_entry consumer;\n         pegtl::parse< pegtl::must< json::jaxn::internal::rules::sor_single_value >, jaxn_action, json::jaxn::internal::errors >( in, consumer );\n         // assert( consumer.value.has_value() );\n         const auto f = [ &e = *consumer.value ]( concat& c ) { c.concat.emplace_back( std::move( e ) ); };\n         phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );\n         return true;\n      }\n   };\n\n   struct reference_value\n   {\n      using rule_t = reference_value;\n      using subs_t = pegtl::type_list< reference2_rest >;\n\n      template< pegtl::apply_mode A,\n                pegtl::rewind_mode M,\n                template< typename... >\n                class Action,\n                template< typename... >\n                class Control,\n                typename State >\n      [[nodiscard]] static bool match( pegtl_input_t& in, State& st, const function_map& /*unused*/ )\n      {\n         const auto r = parse_reference2( in );\n         const auto f = [ & ]( concat& c ) { c.concat.emplace_back( r ); };\n         phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );\n         return true;\n      }\n   };\n\n   struct array;\n   struct object;\n\n   struct extension_list;\n\n   // clang-format off\n   struct remove : pegtl::keyword< 'd', 'e', 'l', 'e', 't', 'e' > {};\n\n   struct function_name : pegtl::seq< ident, pegtl::opt< pegtl::one< '?' > > > {};\n   struct extension_value : pegtl::seq< function_name, wsp, extension_list > {};\n   struct bracketed_value : pegtl::if_must< pegtl::one< '(' >, wss, pegtl::if_must_else< pegtl::at< reference2_rest >, reference_value, extension_value > > {};\n\n   struct value_part : pegtl::sor< array, object, bracketed_value, jaxn_value > {};\n   struct value_list : pegtl::list< value_part, pegtl::one< '+' >, jaxn::ws > {};\n\n   struct assign_head : pegtl::one< ':', '=' > {};\n   struct assign_member : pegtl::if_must< assign_head, wss, pegtl::sor< remove, value_list > > {};\n\n   struct append_head : pegtl::sor< pegtl::string< '+', '=' >, pegtl::at< pegtl::one< '{', '[' > > > {};\n   struct append_member : pegtl::if_must< append_head, wss, value_list > {};\n\n   struct key_member : pegtl::sor< assign_member, append_member > {};\n\n   struct member_key\n   {\n      using rule_t = member_key;\n      using subs_t = pegtl::type_list< key1_rule, pegtl::must< wss, key_member > >;\n\n      template< pegtl::apply_mode A,\n                pegtl::rewind_mode M,\n                template< typename... >\n                class Action,\n                template< typename... >\n                class Control,\n                typename State >\n      [[nodiscard]] static bool match( pegtl_input_t& in, State& st, const function_map& fm )\n      {\n         const key1_guard kg( st, parse_key1( in ) );\n         return Control< pegtl::must< wss, key_member > >::template match< A, M, Action, Control >( in, st, fm );\n      }\n   };\n\n   struct inc_if : pegtl::one< '?' > {};\n   struct opt_if : pegtl::opt< inc_if > {};\n   struct inc_fn : pegtl::plus< pegtl::not_one< '\"' > > {};  // TODO: Do we want/need to allow JSON escape sequences in filenames?\n\n   struct include : pegtl::string< 'i', 'n', 'c', 'l', 'u', 'd', 'e' > {};\n   struct permanent : pegtl::string< 'p', 'e', 'r', 'm', 'a', 'n', 'e', 'n', 't' > {};\n   struct temporary : pegtl::string< 't', 'e', 'm', 'p', 'o', 'r', 'a', 'r', 'y' > {};\n\n   struct filename : pegtl::seq< pegtl::one< '\"' >, inc_fn, pegtl::one< '\"' > > {};\n\n   struct include_extension : pegtl::if_must< include, opt_if, wsp, filename > {};\n   struct permanent_extension : pegtl::if_must< permanent, wsp, key1_rule > {};\n   struct temporary_extension : pegtl::if_must< temporary, wsp, key1_rule > {};\n\n   struct extension_member : pegtl::if_must< pegtl::one< '(' >, wss, pegtl::sor< include_extension, temporary_extension, permanent_extension >, wss, pegtl::one< ')' > > {};\n\n   struct member : pegtl::sor< extension_member, member_key > {};\n\n   struct opt_comma : pegtl::opt< pegtl::one< ',' >, wss > {};\n\n   template< typename U > struct member_list_impl : pegtl::until< U, member, wss, opt_comma > {};\n   template< typename U > struct element_list_impl : pegtl::until< U, value_list, wss, opt_comma > {};\n\n   struct element_list : element_list_impl< jaxn::end_array > {};\n   struct extension_list : element_list_impl< pegtl::one< ')' > > {};\n   struct array : pegtl::if_must< jaxn::begin_array, element_list > {};\n   struct member_list : member_list_impl< jaxn::end_object > {};\n   struct object : pegtl::if_must< jaxn::begin_object, member_list > {};\n   struct compat_file : pegtl::must< member_list, wss, pegtl::eof > {};\n   struct config_list : member_list_impl< pegtl::eof > {};\n   struct begin_compat : pegtl::disable< jaxn::begin_object > {};\n   struct config_file : pegtl::must< wss, pegtl::if_must_else< begin_compat, compat_file, config_list > > {};\n   struct value : pegtl::must< wss, value_part, wss, pegtl::eof > {};\n   // clang-format on\n\n}  // namespace tao::config::internal::rules\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/config_parser.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_CONFIG_PARSER_HPP\n#define TAO_CONFIG_INTERNAL_CONFIG_PARSER_HPP\n\n#include <cstdint>\n#include <filesystem>\n#include <string>\n#include <string_view>\n#include <utility>\n\n#include \"config_action.hpp\"\n#include \"config_grammar.hpp\"\n#include \"forward.hpp\"\n#include \"function_implementations.hpp\"\n#include \"function_wrapper.hpp\"\n#include \"json.hpp\"\n#include \"pegtl.hpp\"\n#include \"phase2_everything.hpp\"\n#include \"phase3_remove.hpp\"\n#include \"phase5_repack.hpp\"\n#include \"state.hpp\"\n\nnamespace tao::config::internal\n{\n   struct config_parser\n   {\n      config_parser()\n         : fm( { { \"binary\", wrap( binary_function ) },\n                 { \"default\", wrap( default_function ) },\n                 { \"env\", wrap( env_function ) },\n                 { \"env?\", wrap( env_if_function ) },\n                 { \"jaxn\", wrap( jaxn_function ) },\n                 { \"print\", wrap( print_function ) },\n                 { \"read\", wrap( read_function ) },\n                 { \"shell\", wrap( shell_function ) },\n                 { \"split\", wrap( split_function ) },\n                 { \"string\", wrap( string_function ) } } )\n      {}\n\n      config_parser( config_parser&& ) = delete;\n      config_parser( const config_parser& ) = delete;\n\n      void operator=( config_parser&& ) = delete;\n      void operator=( const config_parser& ) = delete;\n\n      state st;\n      function_map fm;\n\n      void parse( pegtl_input_t&& in )\n      {\n         pegtl::parse< rules::config_file, config_action >( in, st, fm );\n      }\n\n      void parse( const std::filesystem::path& path )\n      {\n         parse( pegtl::file_input( path ) );\n      }\n\n      void parse( const char* data, const std::size_t size, const std::string& source )\n      {\n         parse( pegtl_input_t( data, size, source ) );\n      }\n\n      void parse( const std::string_view data, const std::string& source )\n      {\n         parse( data.data(), data.size(), source );\n      }\n\n      template< template< typename... > class Traits >\n      [[nodiscard]] json::basic_value< Traits > finish()\n      {\n         phase2_everything( st, fm );\n         phase3_remove( st.root );\n         return phase5_repack< Traits >( st.root );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/constants.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_CONSTANTS_HPP\n#define TAO_CONFIG_INTERNAL_CONSTANTS_HPP\n\n#include \"entry_kind.hpp\"\n\nnamespace tao::config::internal\n{\n   struct part_asterisk_t\n   {\n      explicit constexpr part_asterisk_t( int /*unused*/ ) {}\n   };\n\n   struct part_vector_t\n   {\n      explicit constexpr part_vector_t( int /*unused*/ ) {}\n   };\n\n   constexpr part_asterisk_t part_asterisk{ 0 };\n   constexpr part_vector_t part_vector{ 0 };\n\n   [[nodiscard]] constexpr bool operator<( const part_asterisk_t, const part_asterisk_t ) noexcept\n   {\n      return false;\n   }\n\n   struct array_init_t\n   {\n      explicit constexpr array_init_t( int /*unused*/ ) {}\n\n      static constexpr entry_kind kind = entry_kind::ARRAY;\n   };\n\n   struct object_init_t\n   {\n      explicit constexpr object_init_t( int /*unused*/ ) {}\n\n      static constexpr entry_kind kind = entry_kind::OBJECT;\n   };\n\n   struct asterisk_init_t\n   {\n      explicit constexpr asterisk_init_t( int /*unused*/ ) {}\n\n      static constexpr entry_kind kind = entry_kind::ASTERISK;\n   };\n\n   constexpr array_init_t array_init{ 0 };\n   constexpr object_init_t object_init{ 0 };\n   constexpr asterisk_init_t asterisk_init{ 0 };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/debug_traits.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_DEBUG_TRAITS_HPP\n#define TAO_CONFIG_INTERNAL_DEBUG_TRAITS_HPP\n\n#include <stdexcept>\n#include <string>\n#include <vector>\n\n#include <tao/json/contrib/variant_traits.hpp>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"json.hpp\"\n#include \"key1.hpp\"\n#include \"object.hpp\"\n#include \"pegtl.hpp\"\n#include \"reference2.hpp\"\n\n#include \"../annotation.hpp\"\n#include \"../key.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename T >\n   struct debug_traits\n      : json::traits< T >\n   {};\n\n   template<>\n   struct debug_traits< void >\n      : json::traits< void >\n   {};\n\n   template<>\n   struct debug_traits< key_kind >\n   {\n      TAO_JSON_DEFAULT_KEY( \"key_kind\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const key_kind k )\n      {\n         switch( k ) {\n            case key_kind::name:\n               c.string( \"name\" );\n               return;\n            case key_kind::index:\n               c.string( \"index\" );\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n   };\n\n   template<>\n   struct debug_traits< key_part >\n   {\n      TAO_JSON_DEFAULT_KEY( \"key_part\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const key_part& p )\n      {\n         c.begin_object( 2 );\n         c.key( \"key_kind\" );\n         json::events::produce< Traits >( c, p.kind() );\n         c.member();\n         c.key( \"key_data\" );\n         json::events::produce< Traits >( c, p.data );\n         c.member();\n         c.end_object( 2 );\n      }\n   };\n\n   template<>\n   struct debug_traits< key >\n      : json::traits< std::vector< key_part > >\n   {\n      TAO_JSON_DEFAULT_KEY( \"key\" );\n   };\n\n   template<>\n   struct debug_traits< annotation >\n      : json::binding::object< TAO_JSON_BIND_REQUIRED( \"key\", &annotation::key ),\n                               TAO_JSON_BIND_REQUIRED( \"position\", &annotation::position ) >\n   {\n      TAO_JSON_DEFAULT_KEY( \"annotation\" );\n   };\n\n   template<>\n   struct debug_traits< json::position >\n   {\n      TAO_JSON_DEFAULT_KEY( \"position\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const json::position& p )\n      {\n         c.string( p.source() + ':' + std::to_string( p.line() ) + ':' + std::to_string( p.column() ) );\n      }\n   };\n\n   template<>\n   struct debug_traits< pegtl::position >\n   {\n      TAO_JSON_DEFAULT_KEY( \"position\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const pegtl::position& p )\n      {\n         c.string( p.source + ':' + std::to_string( p.line ) + ':' + std::to_string( p.column ) );\n      }\n   };\n\n   template<>\n   struct debug_traits< part_asterisk_t >\n   {\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const part_asterisk_t /*unused*/ )\n      {\n         c.string( \"asterisk\" );\n      }\n   };\n\n   template<>\n   struct debug_traits< key1_kind >\n   {\n      TAO_JSON_DEFAULT_KEY( \"key1_kind\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const key1_kind k )\n      {\n         switch( k ) {\n            case key1_kind::name:\n               c.string( \"name\" );\n               return;\n            case key1_kind::index:\n               c.string( \"index\" );\n               return;\n            case key1_kind::asterisk:\n               c.string( \"asterisk\" );\n               return;\n            case key1_kind::append:\n               c.string( \"append\" );\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n   };\n\n   template<>\n   struct debug_traits< key1_part >\n   {\n      TAO_JSON_DEFAULT_KEY( \"key1_part\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const key1_part& p )\n      {\n         c.begin_object( 3 );\n         c.key( \"key1_kind\" );\n         json::events::produce< Traits >( c, p.kind() );\n         c.member();\n         c.key( \"key1_data\" );\n         json::events::produce< Traits >( c, p.data );\n         c.member();\n         c.key( \"position\" );\n         json::events::produce< Traits >( c, p.position );\n         c.member();\n         c.end_object( 3 );\n      }\n   };\n\n   template<>\n   struct debug_traits< key1 >\n      : json::traits< std::vector< key1_part > >\n   {\n      TAO_JSON_DEFAULT_KEY( \"key1\" );\n   };\n\n   template<>\n   struct debug_traits< reference2_kind >\n   {\n      TAO_JSON_DEFAULT_KEY( \"reference2_kind\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const reference2_kind k )\n      {\n         switch( k ) {\n            case reference2_kind::name:\n               c.string( \"name\" );\n               return;\n            case reference2_kind::index:\n               c.string( \"index\" );\n               return;\n            case reference2_kind::vector:\n               c.string( \"reference\" );\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n   };\n\n   template<>\n   struct debug_traits< reference2_part >\n   {\n      TAO_JSON_DEFAULT_KEY( \"reference2_part\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const reference2_part& p )\n      {\n         c.begin_object( 3 );\n         c.key( \"reference2_kind\" );\n         json::events::produce< Traits >( c, p.kind() );\n         c.member();\n         c.key( \"reference2_data\" );\n         json::events::produce< Traits >( c, p.data );\n         c.member();\n         c.key( \"position\" );\n         json::events::produce< Traits >( c, p.position );\n         c.member();\n         c.end_object( 3 );\n      }\n   };\n\n   template<>\n   struct debug_traits< reference2 >\n      : json::traits< std::vector< reference2_part > >\n   {\n      TAO_JSON_DEFAULT_KEY( \"reference2\" );\n   };\n\n   template<>\n   struct debug_traits< entry_kind >\n   {\n      TAO_JSON_DEFAULT_KEY( \"entry_kind\" );\n\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const entry_kind k )\n      {\n         switch( k ) {\n            case entry_kind::NULL_:\n               c.string( \"null\" );\n               return;\n            case entry_kind::BOOLEAN:\n               c.string( \"boolean\" );\n               return;\n            case entry_kind::STRING:\n               c.string( \"string\" );\n               return;\n            case entry_kind::BINARY:\n               c.string( \"binary\" );\n               return;\n            case entry_kind::SIGNED:\n               c.string( \"signed\" );\n               return;\n            case entry_kind::UNSIGNED:\n               c.string( \"unsigned\" );\n               return;\n            case entry_kind::DOUBLE:\n               c.string( \"double\" );\n               return;\n            case entry_kind::ARRAY:\n               c.string( \"array\" );\n               return;\n            case entry_kind::OBJECT:\n               c.string( \"object\" );\n               return;\n            case entry_kind::ASTERISK:\n               c.string( \"asterisk\" );\n               return;\n            case entry_kind::REFERENCE:\n               c.string( \"reference\" );\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n   };\n\n   template<>\n   struct debug_traits< entry >\n   {\n      template< template< typename... > class Traits, typename Consumer >\n      static void produce( Consumer& c, const entry& v )\n      {\n         c.begin_object();\n         c.key( \"type\" );\n         json::events::produce< Traits >( c, v.kind() );\n         c.member();\n         switch( v.kind() ) {\n            case entry_kind::NULL_:\n               c.end_object();\n               return;\n            case entry_kind::BOOLEAN:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_boolean() );\n               break;\n            case entry_kind::STRING:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_string() );\n               break;\n            case entry_kind::BINARY:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_binary() );\n               break;\n            case entry_kind::SIGNED:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_signed() );\n               break;\n            case entry_kind::UNSIGNED:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_unsigned() );\n               break;\n            case entry_kind::DOUBLE:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_double() );\n               break;\n            case entry_kind::ARRAY:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_array() );\n               break;\n            case entry_kind::OBJECT:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_object() );\n               break;\n            case entry_kind::ASTERISK:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_asterisk() );\n               break;\n            case entry_kind::REFERENCE:\n               c.key( \"data\" );\n               json::events::produce< Traits >( c, v.get_reference() );\n               break;\n         }\n         c.member();\n         c.end_object();\n      }\n   };\n\n   template<>\n   struct debug_traits< concat >\n      : json::binding::object< TAO_JSON_BIND_REQUIRED( \"remove\", &concat::remove ),\n                               TAO_JSON_BIND_REQUIRED( \"implicit\", &concat::implicit ),\n                               TAO_JSON_BIND_REQUIRED( \"temporary\", &concat::temporary ),\n                               TAO_JSON_BIND_REQUIRED( \"position\", &concat::position ),\n                               TAO_JSON_BIND_REQUIRED( \"concat_list\", &concat::concat ) >\n   {};\n\n   template<>\n   struct debug_traits< array >\n      : json::binding::object< TAO_JSON_BIND_REQUIRED( \"position\", &array::position ),\n                               TAO_JSON_BIND_OPTIONAL( \"function\", &array::function ),\n                               TAO_JSON_BIND_REQUIRED( \"array_data\", &array::array ) >\n   {};\n\n   template<>\n   struct debug_traits< object >\n      : json::binding::object< TAO_JSON_BIND_REQUIRED( \"position\", &object::position ),\n                               TAO_JSON_BIND_REQUIRED( \"object_data\", &object::object ) >\n   {};\n\n   template< typename T >\n   struct debug_traits< const T* >\n   {\n      template< template< typename... > class Traits >\n      static void assign( json::basic_value< Traits >& v, const T* p )\n      {\n         v.set_opaque_ptr( p );\n      }\n   };\n\n   template< typename T >\n   struct debug_traits< T* >\n      : debug_traits< const T* >\n   {};\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/entry.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_ENTRY_HPP\n#define TAO_CONFIG_INTERNAL_ENTRY_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <stdexcept>\n#include <string>\n#include <utility>\n#include <variant>\n\n#include \"array.hpp\"\n#include \"atom.hpp\"\n#include \"concat.hpp\"\n#include \"constants.hpp\"\n#include \"entry_kind.hpp\"\n#include \"forward.hpp\"\n#include \"object.hpp\"\n#include \"pegtl.hpp\"\n#include \"reference2.hpp\"\n\nnamespace tao::config::internal\n{\n   struct entry\n   {\n      using data_t = std::variant< null, boolean, string_t, binary_t, signed_t, unsigned_t, double_t, array, object, concat, reference2 >;\n\n      explicit entry( const null& n )\n         : m_data( n )\n      {}\n\n      explicit entry( const boolean& b )\n         : m_data( b )\n      {}\n\n      explicit entry( const string_t& s )\n         : m_data( s )\n      {}\n\n      explicit entry( const binary_t& b )\n         : m_data( b )\n      {}\n\n      explicit entry( const signed_t& s )\n         : m_data( s )\n      {}\n\n      explicit entry( const unsigned_t& u )\n         : m_data( u )\n      {}\n\n      explicit entry( const double_t& d )\n         : m_data( d )\n      {}\n\n      explicit entry( const reference2& r )\n         : m_data( r )\n      {\n         assert( !r.empty() );\n      }\n\n      entry( const std::string& n, const pegtl::position& p )\n         : m_data( std::in_place_type_t< array >(), n, p )\n      {}\n\n      entry( const array_init_t /*unused*/, const pegtl::position& p )\n         : m_data( std::in_place_type_t< array >(), p )\n      {}\n\n      entry( const object_init_t /*unused*/, const pegtl::position& p )\n         : m_data( std::in_place_type_t< object >(), p )\n      {}\n\n      entry( const asterisk_init_t /*unused*/, const pegtl::position& p )\n         : m_data( std::in_place_type_t< concat >(), p )\n      {}\n\n      entry( entry&& ) noexcept = default;\n      entry( const entry& ) = default;\n\n      ~entry() = default;\n\n      entry& operator=( entry&& ) noexcept = default;\n      entry& operator=( const entry& ) = default;\n\n      [[nodiscard]] entry_kind kind() const noexcept\n      {\n         return entry_kind( m_data.index() );\n      }\n\n      [[nodiscard]] bool is_null() const noexcept\n      {\n         return std::holds_alternative< null >( m_data );\n      }\n\n      [[nodiscard]] bool is_string() const noexcept\n      {\n         return std::holds_alternative< string_t >( m_data );\n      }\n\n      [[nodiscard]] bool is_binary() const noexcept\n      {\n         return std::holds_alternative< binary_t >( m_data );\n      }\n\n      [[nodiscard]] bool is_array() const noexcept\n      {\n         return std::holds_alternative< array >( m_data );\n      }\n\n      [[nodiscard]] bool is_object() const noexcept\n      {\n         return std::holds_alternative< object >( m_data );\n      }\n\n      [[nodiscard]] bool is_asterisk() const noexcept\n      {\n         return std::holds_alternative< concat >( m_data );\n      }\n\n      [[nodiscard]] bool is_reference() const noexcept\n      {\n         return std::holds_alternative< reference2 >( m_data );\n      }\n\n      template< typename T >\n      void set_value( atom< T >&& t )\n      {\n         m_data.emplace< atom< T > >( std::move( t ) );\n      }\n\n      void set_array( pegtl::position p )\n      {\n         m_data.emplace< std::size_t( entry_kind::ARRAY ) >( std::move( p ) );\n      }\n\n      void set_object( pegtl::position p )\n      {\n         m_data.emplace< std::size_t( entry_kind::OBJECT ) >( std::move( p ) );\n      }\n\n      [[nodiscard]] bool get_boolean() const noexcept\n      {\n         return std::get< boolean >( m_data ).value;\n      }\n\n      [[nodiscard]] boolean& get_boolean_atom() noexcept\n      {\n         return std::get< boolean >( m_data );\n      }\n\n      [[nodiscard]] const boolean& get_boolean_atom() const noexcept\n      {\n         return std::get< boolean >( m_data );\n      }\n\n      [[nodiscard]] std::string& get_string() noexcept\n      {\n         return std::get< string_t >( m_data ).value;\n      }\n\n      [[nodiscard]] const std::string& get_string() const noexcept\n      {\n         return std::get< string_t >( m_data ).value;\n      }\n\n      [[nodiscard]] string_t& get_string_atom() noexcept\n      {\n         return std::get< string_t >( m_data );\n      }\n\n      [[nodiscard]] const string_t& get_string_atom() const noexcept\n      {\n         return std::get< string_t >( m_data );\n      }\n\n      [[nodiscard]] std::vector< std::byte >& get_binary() noexcept\n      {\n         return std::get< binary_t >( m_data ).value;\n      }\n\n      [[nodiscard]] const std::vector< std::byte >& get_binary() const noexcept\n      {\n         return std::get< binary_t >( m_data ).value;\n      }\n\n      [[nodiscard]] binary_t& get_binary_atom() noexcept\n      {\n         return std::get< binary_t >( m_data );\n      }\n\n      [[nodiscard]] const binary_t& get_binary_atom() const noexcept\n      {\n         return std::get< binary_t >( m_data );\n      }\n\n      [[nodiscard]] std::int64_t get_signed() const noexcept\n      {\n         return std::get< signed_t >( m_data ).value;\n      }\n\n      [[nodiscard]] signed_t& get_signed_atom() noexcept\n      {\n         return std::get< signed_t >( m_data );\n      }\n\n      [[nodiscard]] const signed_t& get_signed_atom() const noexcept\n      {\n         return std::get< signed_t >( m_data );\n      }\n\n      [[nodiscard]] std::uint64_t get_unsigned() const noexcept\n      {\n         return std::get< unsigned_t >( m_data ).value;\n      }\n\n      [[nodiscard]] unsigned_t& get_unsigned_atom() noexcept\n      {\n         return std::get< unsigned_t >( m_data );\n      }\n\n      [[nodiscard]] const unsigned_t& get_unsigned_atom() const noexcept\n      {\n         return std::get< unsigned_t >( m_data );\n      }\n\n      [[nodiscard]] double get_double() const noexcept\n      {\n         return std::get< double_t >( m_data ).value;\n      }\n\n      [[nodiscard]] double_t& get_double_atom() noexcept\n      {\n         return std::get< double_t >( m_data );\n      }\n\n      [[nodiscard]] const double_t& get_double_atom() const noexcept\n      {\n         return std::get< double_t >( m_data );\n      }\n\n      [[nodiscard]] array& get_array() noexcept\n      {\n         return std::get< array >( m_data );\n      }\n\n      [[nodiscard]] const array& get_array() const noexcept\n      {\n         return std::get< array >( m_data );\n      }\n\n      [[nodiscard]] object& get_object() noexcept\n      {\n         return std::get< object >( m_data );\n      }\n\n      [[nodiscard]] const object& get_object() const noexcept\n      {\n         return std::get< object >( m_data );\n      }\n\n      [[nodiscard]] concat& get_asterisk() noexcept\n      {\n         return std::get< concat >( m_data );\n      }\n\n      [[nodiscard]] const concat& get_asterisk() const noexcept\n      {\n         return std::get< concat >( m_data );\n      }\n\n      [[nodiscard]] reference2& get_reference() noexcept\n      {\n         return std::get< reference2 >( m_data );\n      }\n\n      [[nodiscard]] const reference2& get_reference() const noexcept\n      {\n         return std::get< reference2 >( m_data );\n      }\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         return std::visit( []( const auto& v ) -> const pegtl::position& { return v.get_position(); }, m_data );\n      }\n\n   private:\n      data_t m_data;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/entry_kind.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_ENTRY_KIND_HPP\n#define TAO_CONFIG_INTERNAL_ENTRY_KIND_HPP\n\n#include <cassert>\n#include <cstdlib>\n#include <ostream>\n#include <string_view>\n\nnamespace tao::config::internal\n{\n   enum class entry_kind : char\n   {\n      NULL_ = 0,\n      BOOLEAN = 1,\n      STRING = 2,\n      BINARY = 3,\n      SIGNED = 4,\n      UNSIGNED = 5,\n      DOUBLE = 6,\n      ARRAY = 7,\n      OBJECT = 8,\n      ASTERISK = 9,\n      REFERENCE = 10\n   };\n\n   [[nodiscard]] constexpr std::string_view to_string( const entry_kind k ) noexcept\n   {\n      switch( k ) {\n         case entry_kind::NULL_:\n            return \"null\";\n         case entry_kind::BOOLEAN:\n            return \"boolean\";\n         case entry_kind::STRING:\n            return \"string\";\n         case entry_kind::BINARY:\n            return \"binary\";\n         case entry_kind::SIGNED:\n            return \"signed\";\n         case entry_kind::UNSIGNED:\n            return \"unsigned\";\n         case entry_kind::DOUBLE:\n            return \"double\";\n         case entry_kind::ARRAY:\n            return \"array\";\n         case entry_kind::OBJECT:\n            return \"object\";\n         case entry_kind::ASTERISK:\n            return \"asterisk\";\n         case entry_kind::REFERENCE:\n            return \"reference\";\n      }\n      std::abort();\n   }\n\n   inline std::ostream& operator<<( std::ostream& o, const entry_kind k )\n   {\n      return o << to_string( k );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/events_from_value.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_EVENTS_FROM_VALUE_HPP\n#define TAO_CONFIG_INTERNAL_EVENTS_FROM_VALUE_HPP\n\n#include \"debug_traits.hpp\"\n#include \"json.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename Consumer, template< typename... > class Traits >\n   void events_from_value( Consumer& c, const json::basic_value< Traits >& v )\n   {\n      c.begin_object( 2 );\n      c.key( \"meta\" );\n      json::events::produce< debug_traits >( c, v.public_base() );\n      c.member();\n      c.key( \"data\" );\n      json::events::from_value< events_from_value< Consumer, Traits > >( c, v );\n      c.member();\n      c.end_object( 2 );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/forward.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_FORWARD_HPP\n#define TAO_CONFIG_INTERNAL_FORWARD_HPP\n\n#include <functional>\n#include <map>\n#include <string>\n\nnamespace tao::config::internal\n{\n   struct entry;\n   struct state;\n\n   template< typename E >\n   struct basic_concat;\n\n   using concat = basic_concat< entry >;\n\n   template< typename C >\n   struct basic_array;\n   template< typename C >\n   struct basic_object;\n\n   using array = basic_array< concat >;\n   using object = basic_object< concat >;\n\n   template< typename, typename >\n   struct function_traits;\n\n   using function = std::function< bool( entry& ) >;\n   using function_map = std::map< std::string, function >;\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/function_implementations.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_FUNCTION_IMPLEMENTATIONS_HPP\n#define TAO_CONFIG_INTERNAL_FUNCTION_IMPLEMENTATIONS_HPP\n\n#include <cstddef>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"jaxn_action.hpp\"\n#include \"jaxn_to_entry.hpp\"\n#include \"json.hpp\"\n#include \"pegtl.hpp\"\n#include \"phase5_repack.hpp\"\n#include \"statistics.hpp\"\n#include \"system_utility.hpp\"\n\n#include \"../key.hpp\"\n\nnamespace tao::config::internal\n{\n   [[nodiscard]] inline binary_t binary_function( const pegtl::position& p, const std::string& s )\n   {\n      const auto* const d = reinterpret_cast< const std::byte* >( s.data() );\n      return binary_t( std::vector< std::byte >( d, d + s.size() ), p );\n   }\n\n   [[nodiscard]] inline bool default_function( entry& e )\n   {\n      array& a = e.get_array();\n      if( a.array.size() < 1 ) {\n         throw pegtl::parse_error( \"default function requires at least one argument\", a.position );\n      }\n      for( concat& c : a.array ) {\n         if( c.concat.size() != 1 ) {\n            return false;\n         }\n         entry& f = c.concat.front();\n\n         switch( f.kind() ) {\n            case entry_kind::NULL_:\n               continue;\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::BOOLEAN:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               break;\n            case entry_kind::ARRAY:\n               if( !f.get_array().function.empty() ) {\n                  return false;\n               }\n               break;\n            case entry_kind::OBJECT:\n               break;\n            case entry_kind::ASTERISK:\n               return false;\n            case entry_kind::REFERENCE:\n               return false;\n         }\n         // Both f and a are sub-objects of e.\n         entry t = std::move( f );\n         e = std::move( t );\n         return true;\n      }\n      throw pegtl::parse_error( \"default function requires at least one non-null argument\", a.position );\n   }\n\n   [[nodiscard]] inline string_t env_function( const pegtl::position& p, const std::string& s )\n   {\n      return string_t( getenv_throws( p, s ), p );\n   }\n\n   [[nodiscard]] inline string_t env_if_function( const pegtl::position& p, const std::string& s, const std::string& d )\n   {\n      const auto r = getenv_nothrow( s );\n      return string_t( r ? ( *r ) : d, p );\n   }\n\n   [[nodiscard]] inline entry jaxn_function( const pegtl::position& /*unused*/, const std::string& s )\n   {\n      jaxn_to_entry consumer;\n      pegtl::memory_input in( s, \"TODO\" );\n      pegtl::parse< json::jaxn::internal::grammar, jaxn_action, json::jaxn::internal::errors >( static_cast< pegtl_input_t& >( in ), consumer );\n      return std::move( consumer.value ).value();\n   }\n\n   [[nodiscard]] inline binary_t read_function( const pegtl::position& p, const std::string& filename )\n   {\n      const std::string d = read_file_throws( filename );\n      const std::byte* x = reinterpret_cast< const std::byte* >( d.data() );\n      return binary_t( std::vector< std::byte >( x, x + d.size() ), p );\n   }\n\n   [[nodiscard]] inline bool print_function( entry& e )\n   {\n      array& a = e.get_array();\n      if( a.array.size() != 1 ) {\n         throw pegtl::parse_error( \"print function requires exactly one argument\", a.position );\n      }\n      concat& c = a.array.front();\n      if( statistics( c ).is_primitive() ) {\n         const tao::json::value v = phase5_repack< json::traits >( c );  // TODO: Optimise away this intermediate data structure.\n         std::string s = json::jaxn::to_string( v );\n         pegtl::position p = c.position;\n         e = entry( string_t( std::move( s ), std::move( p ) ) );\n         return true;\n      }\n      return false;\n   }\n\n   [[nodiscard]] inline string_t shell_function( const pegtl::position& p, [[maybe_unused]] const std::string& script )\n   {\n#if defined( _MSC_VER )\n      throw pegtl::parse_error( \"shell extension not supported on this platform\", p );\n#else\n      return string_t( shell_popen_throws( p, script ), p );\n#endif\n   }\n\n   // clang-format off\n   struct split_star_ws : pegtl::star< pegtl::space > {};\n   struct split_string : pegtl::plus< pegtl::invert< pegtl::space > > {};\n   struct split_rule : pegtl::must< split_star_ws, pegtl::star< split_string, split_star_ws >, pegtl::eof > {};\n   // clang-format on\n\n   template< typename Rule >\n   struct split_action\n      : pegtl::nothing< Rule >\n   {};\n\n   template<>\n   struct split_action< split_string >\n   {\n      template< typename Input >\n      static void apply( const Input& in, entry& result, const pegtl::position& p )\n      {\n         concat& c = result.get_array().array.emplace_back( p );\n         c.concat.emplace_back( string_t( in.string(), in.position() ) );\n      }\n   };\n\n   [[nodiscard]] inline entry split_function( const pegtl::position& p, const std::string& s )\n   {\n      entry result( array_init, p );\n      pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl_input_t::eol_t, const char* > in( s, __FUNCTION__ );\n      pegtl::parse_nested< split_rule, split_action >( p, in, result, p );\n      return result;\n   }\n\n   [[nodiscard]] inline string_t string_function( const pegtl::position& p, const std::string& s )\n   {\n      return string_t( s, p );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/function_traits.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_FUNCTION_TRAITS_HPP\n#define TAO_CONFIG_INTERNAL_FUNCTION_TRAITS_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <iterator>\n#include <stdexcept>\n#include <string>\n#include <vector>\n\n#include \"array.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"json.hpp\"\n#include \"key1.hpp\"\n#include \"parse_utility.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   struct arguments_unready\n   {};\n\n   template< typename, typename = void >\n   struct function_traits;\n\n   template<>\n   struct function_traits< entry >\n   {\n      static void put( entry& e, entry&& f )\n      {\n         e = std::move( f );\n      }\n\n      static void put( entry& e, const entry& f )\n      {\n         e = f;\n      }\n   };\n\n   template< typename T >\n   struct function_traits< atom< T > >\n   {\n      static void put( entry& e, atom< T >&& v )\n      {\n         e.set_value( std::move( v ) );\n      }\n\n      static void put( entry& e, const atom< T >& v )\n      {\n         e.set_value( v );\n      }\n   };\n\n   [[nodiscard]] inline const entry& function_traits_entry( array& f, const std::size_t i )\n   {\n      assert( f.array.size() > i );\n\n      auto p = f.array.begin();\n      std::advance( p, i );\n\n      assert( !p->concat.empty() );\n\n      if( p->concat.size() != 1 ) {\n         throw arguments_unready();\n      }\n      return p->concat.front();\n   }\n\n   template<>\n   struct function_traits< std::string >\n   {\n      [[nodiscard]] static std::string get( array& f, const std::size_t i )\n      {\n         const entry& e = function_traits_entry( f, i );\n\n         if( e.is_string() ) {\n            return e.get_string();\n         }\n         if( e.is_binary() ) {\n            const std::vector< std::byte >& b = e.get_binary();\n            const std::string s( reinterpret_cast< const char* >( b.data() ), b.size() );\n            if( !json::internal::validate_utf8_nothrow( s ) ) {\n               throw pegtl::parse_error( \"invalid utf-8 in binary data used as string\", e.get_position() );\n            }\n            return s;\n         }\n         throw pegtl::parse_error( \"invalid type for string argument\", e.get_position() );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/function_wrapper.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_FUNCTION_WRAPPER_HPP\n#define TAO_CONFIG_INTERNAL_FUNCTION_WRAPPER_HPP\n\n#include <cstddef>\n#include <type_traits>\n#include <utility>\n\n#include \"forward.hpp\"\n#include \"function_traits.hpp\"\n#include \"json.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   [[nodiscard]] inline function wrap( bool ( *x )( entry& e ) )\n   {\n      return function( [ x ]( entry& e ) {\n         try {\n            return x( e );\n         }\n         catch( const arguments_unready& ) {\n            return false;\n         }\n      } );\n   }\n\n   template< typename R, typename A >\n   [[nodiscard]] function wrap( R ( *x )( const pegtl::position&, A ) )\n   {\n      static_assert( !std::is_pointer_v< R > );\n      static_assert( !std::is_reference_v< R > );\n      static_assert( !std::is_same_v< R, void > );\n\n      return function( [ x ]( entry& e ) {\n         try {\n            array& f = e.get_array();\n            function_traits< std::decay_t< R > >::put( e, x( f.position, function_traits< std::decay_t< A > >::get( f, 0 ) ) );\n         }\n         catch( const arguments_unready& ) {\n            return false;\n         }\n         return true;\n      } );\n   }\n\n   template< typename R, typename A, typename B >\n   [[nodiscard]] function wrap( R ( *x )( const pegtl::position&, A, B ) )\n   {\n      static_assert( !std::is_pointer_v< R > );\n      static_assert( !std::is_reference_v< R > );\n      static_assert( !std::is_same_v< R, void > );\n\n      return function( [ x ]( entry& e ) {\n         try {\n            array& f = e.get_array();\n            function_traits< std::decay_t< R > >::put( e, x( f.position, function_traits< std::decay_t< A > >::get( f, 0 ), function_traits< std::decay_t< B > >::get( f, 1 ) ) );\n         }\n         catch( const arguments_unready& ) {\n            return false;\n         }\n         return true;\n      } );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/jaxn_action.hpp",
    "content": "// Copyright (c) 2017-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_JAXN_ACTION_HPP\n#define TAO_CONFIG_INTERNAL_JAXN_ACTION_HPP\n\n#include <algorithm>\n#include <cstring>\n#include <string>\n#include <string_view>\n#include <utility>\n#include <vector>\n\n#include \"change_action_and_states.hpp\"\n#include \"json.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename Rule >\n   struct jaxn_action\n      : pegtl::nothing< Rule >\n   {};\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::kw_null >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.null( in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::kw_true >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.boolean( true, in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::kw_false >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.boolean( false, in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::identifier >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.key( std::string_view( in.begin(), in.size() ), in.position() );\n      }\n   };\n\n   template< bool NEG >\n   struct jaxn_action< json::jaxn::internal::rules::hexnum< NEG > >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         std::uint64_t value = 0;\n         for( char c : in ) {\n            if( value & 0xF000000000000000 ) {\n               throw pegtl::parse_error( \"JAXN hexadecimal number too large\", in );\n            }\n            value <<= 4;\n            value += json::internal::hex_char_to_integer< std::uint8_t >( c );\n         }\n         if constexpr( NEG ) {\n            if( value < 9223372036854775808ULL ) {\n               consumer.number( -static_cast< std::int64_t >( value ), in.position() );\n            }\n            else if( value == 9223372036854775808ULL ) {\n               consumer.number( static_cast< std::int64_t >( -9223372036854775807LL - 1 ), in.position() );\n            }\n            else {\n               throw pegtl::parse_error( \"JAXN hexadecimal number too large to negate\", in );\n            }\n         }\n         else {\n            consumer.number( value, in.position() );\n         }\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::array::begin >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.begin_array( in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::array::element >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.element( in.position() );  // TODO: Position needed here?\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::array::end >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.end_array( in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::object::begin >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.begin_object( in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::object::element >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.member( in.position() );  // TODO: Position needed here?\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::object::end >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.end_object( in.position() );  // TODO: Position needed here?\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::zero< false > >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.number( std::uint64_t( 0 ), in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::zero< true > >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.number( std::int64_t( 0 ), in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::kw_nan >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.number( NAN, in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::kw_infinity< false > >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.number( INFINITY, in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::kw_infinity< true > >\n   {\n      template< typename Input, typename Consumer >\n      static void apply( const Input& in, Consumer& consumer )\n      {\n         consumer.number( -INFINITY, in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::esign >\n   {\n      template< typename Input, bool NEG >\n      static void apply( const Input& in, json::internal::number_state< NEG >& result )\n      {\n         result.eneg = ( in.peek_char() == '-' );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::idigits >\n   {\n      template< typename Input, bool NEG >\n      static void apply( const Input& in, json::internal::number_state< NEG >& result )\n      {\n         const auto s = in.size();\n\n         if( s == 1 && in.peek_char() == '0' ) {\n            return;\n         }\n\n         if( s > ( 1 << 20 ) ) {\n            throw pegtl::parse_error( \"JSON number with 1 megabyte digits\", in );\n         }\n\n         const auto c = ( std::min )( s, json::internal::max_mantissa_digits );\n         std::memcpy( result.mantissa, in.begin(), c );\n         result.exponent10 += static_cast< typename json::internal::number_state< NEG >::exponent10_t >( s - c );\n         result.msize = static_cast< typename json::internal::number_state< NEG >::msize_t >( c );\n\n         for( std::size_t i = c; i < s; ++i ) {\n            if( in.peek_char( i ) != '0' ) {\n               result.drop = true;\n               return;\n            }\n         }\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::fdigits >\n   {\n      template< typename Input, bool NEG >\n      static void apply( const Input& in, json::internal::number_state< NEG >& result )\n      {\n         result.isfp = true;\n\n         const auto* b = in.begin();\n         const auto* e = in.end();\n\n         while( ( e > b ) && ( e[ -1 ] == '0' ) ) {\n            --e;\n         }\n         if( !result.msize ) {\n            while( ( b < e ) && ( b[ 0 ] == '0' ) ) {\n               ++b;\n               --result.exponent10;\n            }\n         }\n         const auto c = ( std::min )( std::size_t( e - b ), json::internal::max_mantissa_digits - result.msize );\n         std::memcpy( result.mantissa + result.msize, b, c );\n         result.exponent10 -= static_cast< typename json::internal::number_state< NEG >::exponent10_t >( c );\n         result.msize += static_cast< typename json::internal::number_state< NEG >::msize_t >( c );\n\n         for( const auto* r = b + c; r < e; ++r ) {\n            if( *r != '0' ) {\n               result.drop = true;\n               return;\n            }\n         }\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::edigits >\n   {\n      template< typename Input, bool NEG >\n      static void apply( const Input& in, json::internal::number_state< NEG >& result )\n      {\n         result.isfp = true;\n\n         const char* b = in.begin();\n\n         while( ( b < in.end() ) && ( b[ 0 ] == '0' ) ) {\n            ++b;\n         }\n         if( ( in.end() - b ) > 9 ) {\n            throw pegtl::parse_error( \"JSON exponent has more than 9 significant digits\", in );\n         }\n         int exponent10 = 0;\n\n         while( b < in.end() ) {\n            exponent10 = ( exponent10 * 10 ) + ( b[ 0 ] - '0' );\n            ++b;\n         }\n         result.exponent10 += ( result.eneg ? -exponent10 : exponent10 );\n      }\n   };\n\n   template< bool NEG >\n   struct jaxn_action< json::jaxn::internal::rules::number< NEG > >\n      : pegtl::change_states< json::internal::number_state< NEG > >\n   {\n      template< typename Input, typename Consumer >\n      static void success( const Input& in, json::internal::number_state< NEG >& state, Consumer& consumer )\n      {\n         state.success( consumer, in.position() );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::single_string >\n      : change_action_and_states< json::jaxn::internal::unescape_action, std::string >\n   {\n      template< typename Consumer >\n      static void success( const pegtl::position& pos, std::string& unescaped, Consumer& consumer )\n      {\n         consumer.string( std::move( unescaped ), pos );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::string >\n      : change_action_and_states< json::jaxn::internal::unescape_action, std::string >\n   {\n      template< typename Consumer >\n      static void success( const pegtl::position& pos, std::string& unescaped, Consumer& consumer )\n      {\n         consumer.string( std::move( unescaped ), pos );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::key >\n      : change_action_and_states< json::jaxn::internal::unescape_action, std::string >\n   {\n      template< typename Consumer >\n      static void success( const pegtl::position& pos, std::string& unescaped, Consumer& consumer )\n      {\n         consumer.key( std::move( unescaped ), pos );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::single_binary >\n      : change_action_and_states< json::jaxn::internal::bunescape_action, std::vector< std::byte > >\n   {\n      template< typename Consumer >\n      static void success( const pegtl::position& pos, std::vector< std::byte >& value, Consumer& consumer )\n      {\n         consumer.binary( std::move( value ), pos );\n      }\n   };\n\n   template<>\n   struct jaxn_action< json::jaxn::internal::rules::binary >\n      : change_action_and_states< json::jaxn::internal::bunescape_action, std::vector< std::byte > >\n   {\n      template< typename Consumer >\n      static void success( const pegtl::position& pos, std::vector< std::byte >& value, Consumer& consumer )\n      {\n         consumer.binary( std::move( value ), pos );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/jaxn_to_entry.hpp",
    "content": "// Copyright (c) 2016-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config\n\n#ifndef TAO_CONFIG_INTERNAL_JAXN_TO_ENTRY_HPP\n#define TAO_CONFIG_INTERNAL_JAXN_TO_ENTRY_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <cstdint>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <utility>\n#include <vector>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"constants.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"object.hpp\"\n\nnamespace tao::config::internal\n{\n   struct jaxn_to_entry\n   {\n      jaxn_to_entry() noexcept = default;\n\n      std::vector< entry > stack_;\n      std::vector< std::string > keys_;\n      std::optional< entry > value;\n\n      void null( const pegtl::position& p )\n      {\n         value.emplace( internal::null( p ) );\n      }\n\n      void boolean( const bool v, const pegtl::position& p )\n      {\n         value.emplace( internal::boolean( v, p ) );\n      }\n\n      void number( const std::int64_t v, const pegtl::position& p )\n      {\n         value.emplace( internal::signed_t( v, p ) );\n      }\n\n      void number( const std::uint64_t v, const pegtl::position& p )\n      {\n         value.emplace( internal::unsigned_t( v, p ) );\n      }\n\n      void number( const double v, const pegtl::position& p )\n      {\n         value.emplace( internal::double_t( v, p ) );\n      }\n\n      void string( const std::string_view v, const pegtl::position& p )\n      {\n         value.emplace( internal::string_t( v, p ) );\n      }\n\n      void string( const char* v, const pegtl::position& p )\n      {\n         value.emplace( internal::string_t( v, p ) );\n      }\n\n      void string( std::string&& v, const pegtl::position& p )\n      {\n         value.emplace( internal::string_t( std::move( v ), p ) );\n      }\n\n      void binary( const tao::binary_view v, const pegtl::position& p )\n      {\n         binary( std::vector< std::byte >( v.data(), v.data() + v.size() ), p );\n      }\n\n      void binary( std::vector< std::byte >&& v, const pegtl::position& p )\n      {\n         value.emplace( internal::binary_t( std::move( v ), p ) );\n      }\n\n      void begin_array( const pegtl::position& p )\n      {\n         stack_.emplace_back( array_init, p );\n      }\n\n      void begin_array( const std::size_t /*unused*/, const pegtl::position& p )\n      {\n         begin_array( p );\n      }\n\n      void element( const pegtl::position& p )\n      {\n         concat& c = stack_.back().get_array().array.emplace_back( p );\n         c.remove = true;\n         c.concat.emplace_back( std::move( value ).value() );\n      }\n\n      void end_array( const pegtl::position& /*unused*/ )\n      {\n         value = std::move( stack_.back() );\n         stack_.pop_back();\n      }\n\n      void end_array( const std::size_t /*unused*/, const pegtl::position& p )\n      {\n         end_array( p );\n      }\n\n      void begin_object( const pegtl::position& p )\n      {\n         stack_.emplace_back( object_init, p );\n      }\n\n      void begin_object( const std::size_t /*unused*/, const pegtl::position& p )\n      {\n         begin_object( p );\n      }\n\n      void key( const std::string_view v, const pegtl::position& /*unused*/ )\n      {\n         keys_.emplace_back( v );\n      }\n\n      void key( const char* v, const pegtl::position& /*unused*/ )\n      {\n         keys_.emplace_back( v );\n      }\n\n      void key( std::string&& v, const pegtl::position& /*unused*/ )\n      {\n         keys_.emplace_back( std::move( v ) );\n      }\n\n      void member( const pegtl::position& p )\n      {\n         auto [ i, b ] = stack_.back().get_object().object.try_emplace( std::move( keys_.back() ), p );\n         (void)b;\n         keys_.pop_back();\n         i->second.remove = true;\n         i->second.concat.emplace_back( std::move( value ).value() );\n      }\n\n      void end_object( const pegtl::position& /*unused*/ )\n      {\n         value = std::move( stack_.back() );\n         stack_.pop_back();\n      }\n\n      void end_object( const std::size_t /*unused*/, const pegtl::position& p )\n      {\n         end_object( p );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/json.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_JSON_HPP\n#define TAO_CONFIG_INTERNAL_JSON_HPP\n\n#include <tao/json.hpp>\n\n#include <tao/json/contrib/position.hpp>\n#include <tao/json/contrib/traits.hpp>  // TODO: This might be a problem...\n\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal::rules\n{\n   namespace jaxn = tao::json::jaxn::internal::rules;\n\n   struct wss\n      : pegtl::star< jaxn::ws >\n   {};\n\n   struct wsp\n      : pegtl::plus< jaxn::ws >\n   {};\n\n}  // namespace tao::config::internal::rules\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key1.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY1_HPP\n#define TAO_CONFIG_INTERNAL_KEY1_HPP\n\n#include <initializer_list>\n#include <string>\n#include <vector>\n\n#include \"key1_action.hpp\"\n#include \"key1_grammar.hpp\"\n#include \"key1_part.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   struct key1\n      : std::vector< key1_part >\n   {\n      key1() = default;\n\n      key1( key1&& ) = default;\n      key1& operator=( key1&& ) = default;\n\n      ~key1() = default;\n\n      key1( const key1& ) = default;\n      key1& operator=( const key1& ) = default;\n\n      explicit key1( const std::string& s )\n      {\n         assign( s );\n      }\n\n      key1( const std::initializer_list< key1_part >& l )\n         : std::vector< key1_part >( l )\n      {}\n\n      key1( const std::vector< key1_part >::const_iterator& begin, const std::vector< key1_part >::const_iterator& end )\n         : std::vector< key1_part >( begin, end )\n      {}\n\n      key1& operator=( const std::string& s )\n      {\n         clear();\n         assign( s );\n         return *this;\n      }\n\n      key1& operator=( const std::initializer_list< key1_part >& l )\n      {\n         vector() = l;\n         return *this;\n      }\n\n      [[nodiscard]] std::vector< key1_part >& vector() noexcept\n      {\n         return static_cast< std::vector< key1_part >& >( *this );\n      }\n\n      [[nodiscard]] const std::vector< key1_part >& vector() const noexcept\n      {\n         return static_cast< const std::vector< key1_part >& >( *this );\n      }\n\n      void assign( const std::string& s )\n      {\n         using grammar = pegtl::must< rules::key1_rule, pegtl::eof >;\n         pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( s, __FUNCTION__ );\n         pegtl::parse< grammar, key1_action >( in, vector() );\n      }\n   };\n\n   inline key1 pop_front( const key1& p )\n   {\n      assert( !p.empty() );\n\n      return key1( p.begin() + 1, p.end() );\n   }\n\n   inline key1 pop_back( const key1& p )\n   {\n      assert( !p.empty() );\n\n      return key1( p.begin(), p.end() - 1 );\n   }\n\n   inline key1& operator+=( key1& l, const key1& r )\n   {\n      l.insert( l.end(), r.begin(), r.end() );\n      return l;\n   }\n\n   inline key1& operator+=( key1& l, const key1_part& p )\n   {\n      l.emplace_back( p );\n      return l;\n   }\n\n   [[nodiscard]] inline key1 operator+( const key1& l, const key1& r )\n   {\n      key1 t( l );\n      t += r;\n      return t;\n   }\n\n   [[nodiscard]] inline key1 operator+( const key1& l, const key1_part& r )\n   {\n      key1 t( l );\n      t += r;\n      return t;\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key1_action.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY1_ACTION_HPP\n#define TAO_CONFIG_INTERNAL_KEY1_ACTION_HPP\n\n#include <cstddef>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"json.hpp\"\n#include \"key1_grammar.hpp\"\n#include \"key1_part.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename Rule >\n   struct key1_action\n      : pegtl::nothing< Rule >\n   {};\n\n   template<>\n   struct key1_action< rules::ident >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< key1_part >& st )\n      {\n         st.emplace_back( in.string(), in.position() );\n      }\n   };\n\n   template<>\n   struct key1_action< rules::index >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< key1_part >& st )\n      {\n         st.emplace_back( std::size_t( std::stoul( in.string() ) ), in.position() );\n      }\n   };\n\n   template<>\n   struct key1_action< rules::asterisk >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< key1_part >& st )\n      {\n         st.emplace_back( part_asterisk, in.position() );\n      }\n   };\n\n   template<>\n   struct key1_action< rules::quoted_choice >\n      : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string >\n   {\n      template< typename Input >\n      static void success( const Input& in, std::string& unescaped, std::vector< key1_part >& st )\n      {\n         st.emplace_back( std::move( unescaped ), in.position() );  // TODO: Position from beginning of quoted string instead of end.\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key1_grammar.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY1_GRAMMAR_HPP\n#define TAO_CONFIG_INTERNAL_KEY1_GRAMMAR_HPP\n\n#include \"key_grammar.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal::rules\n{\n   // clang-format off\n   struct asterisk : pegtl::one< '*' > {};\n\n   struct key1_part : pegtl::sor< ident, quoted, index, asterisk > {};\n   struct key1_rule : pegtl::list_must< key1_part, dot > {};\n   // clang-format on\n\n}  // namespace tao::config::internal::rules\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key1_guard.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY1_GUARD_HPP\n#define TAO_CONFIG_INTERNAL_KEY1_GUARD_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <utility>\n\n#include \"forward.hpp\"\n#include \"key1.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   class [[nodiscard]] key1_guard\n   {\n   public:\n      key1_guard() = delete;\n\n      template< typename State >\n      key1_guard( State& st, key1&& suffix )\n         : m_prefix( st.prefix ),\n           m_suffix( st.suffix ),\n           m_size( m_prefix.size() )\n      {\n         m_prefix += m_suffix;\n         m_suffix = std::move( suffix );\n      }\n\n      template< typename State >\n      key1_guard( const pegtl_input_t& in, State& st, const function_map& /*unused*/ )\n         : m_prefix( st.prefix ),\n           m_suffix( st.suffix ),\n           m_size( m_prefix.size() )\n      {\n         m_prefix += m_suffix;\n         m_suffix.clear();\n         m_suffix.emplace_back( in.position(), ++st.generation );\n      }\n\n      key1_guard( key1_guard&& ) = delete;\n      key1_guard( const key1_guard& ) = delete;\n\n      ~key1_guard()\n      {\n         assert( m_prefix.size() >= m_size );\n\n         m_suffix.clear();\n         m_suffix.insert( m_suffix.end(), m_prefix.begin() + m_size, m_prefix.end() );\n         m_prefix.erase( m_prefix.begin() + m_size, m_prefix.end() );\n      }\n\n      void operator=( key1_guard&& ) = delete;\n      void operator=( const key1_guard& ) = delete;\n\n   private:\n      key1& m_prefix;\n      key1& m_suffix;\n\n      const std::size_t m_size;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key1_kind.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY1_KIND_HPP\n#define TAO_CONFIG_INTERNAL_KEY1_KIND_HPP\n\nnamespace tao::config::internal\n{\n   enum class key1_kind : char\n   {\n      name = 0,\n      index = 1,\n      asterisk = 2,\n      append = 3\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key1_part.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY1_PART_HPP\n#define TAO_CONFIG_INTERNAL_KEY1_PART_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <variant>\n\n#include \"constants.hpp\"\n#include \"key1_kind.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   struct key1_part\n   {\n      using data_t = std::variant< std::string, std::size_t, part_asterisk_t, std::shared_ptr< std::uint64_t > >;\n\n      key1_part( const part_asterisk_t t, const pegtl::position& p )\n         : position( p ),\n           data( t )\n      {}\n\n      // key1_part( const char, const pegtl::position& ) = delete;\n      // key1_part( const signed char, const pegtl::position& ) = delete;\n      // key1_part( const unsigned char, const pegtl::position& ) = delete;\n\n      key1_part( const std::size_t i, const pegtl::position& p )\n         : position( p ),\n           data( i )\n      {}\n\n      key1_part( const pegtl::position& p, const std::uint64_t g )\n         : position( p ),\n           data( std::make_shared< std::uint64_t >( g ) )\n      {}\n\n      key1_part( const std::string& n, const pegtl::position& p )\n         : position( p ),\n           data( n )\n      {}\n\n      [[nodiscard]] key1_kind kind() const noexcept\n      {\n         return key1_kind( data.index() );\n      }\n\n      [[nodiscard]] std::size_t get_index() const noexcept\n      {\n         const auto* s = std::get_if< std::size_t >( &data );\n         assert( s != nullptr );\n         return *s;\n      }\n\n      [[nodiscard]] const std::string& get_name() const noexcept\n      {\n         const auto* s = std::get_if< std::string >( &data );\n         assert( s != nullptr );\n         return *s;\n      }\n\n      void set_generation( const std::uint64_t g ) noexcept\n      {\n         assert( g > 0 );\n\n         if( const auto* s = std::get_if< std::shared_ptr< std::uint64_t > >( &data ) ) {\n            assert( s != nullptr );\n            assert( s->get() != nullptr );\n            assert( g > **s );\n            **s = g;\n         }\n      }\n\n      [[nodiscard]] std::uint64_t get_generation() const noexcept\n      {\n         const auto* s = std::get_if< std::shared_ptr< std::uint64_t > >( &data );\n         assert( s != nullptr );\n         assert( s->get() != nullptr );\n         assert( **s > 0 );\n         return **s;\n      }\n\n      pegtl::position position;\n      data_t data;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key_action.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY_ACTION_HPP\n#define TAO_CONFIG_INTERNAL_KEY_ACTION_HPP\n\n#include <cstddef>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"json.hpp\"\n#include \"key_grammar.hpp\"\n#include \"pegtl.hpp\"\n\n#include \"../key_part.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename Rule >\n   struct key_action\n      : pegtl::nothing< Rule >\n   {};\n\n   template<>\n   struct key_action< rules::ident >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< key_part >& st )\n      {\n         st.emplace_back( in.string() );\n      }\n   };\n\n   template<>\n   struct key_action< rules::index >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< key_part >& st )\n      {\n         st.emplace_back( std::size_t( std::stoul( in.string() ) ) );\n      }\n   };\n\n   template<>\n   struct key_action< rules::quoted_choice >\n      : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string >\n   {\n      template< typename Input >\n      static void success( const Input& /*unused*/, std::string& unescaped, std::vector< key_part >& st )\n      {\n         st.emplace_back( std::move( unescaped ) );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/key_grammar.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY_GRAMMAR_HPP\n#define TAO_CONFIG_INTERNAL_KEY_GRAMMAR_HPP\n\n#include \"json.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal::rules\n{\n   namespace jaxn = tao::json::jaxn::internal::rules;\n\n   // clang-format off\n   struct dot : pegtl::one< '.' > {};\n\n   struct index : pegtl::rep_min_max< 1, 15, pegtl::digit > {};\n\n   struct ident_first : pegtl::ranges< 'a', 'z', 'A', 'Z', '_' > {};\n   struct ident_other : pegtl::ranges< 'a', 'z', 'A', 'Z', '0', '9', '-', '-', '_' > {};\n   struct ident : pegtl::seq< ident_first, pegtl::star< ident_other > > {};\n\n   struct at_quote : pegtl::at< pegtl::one< '\\'', '\"' > > {};\n\n   struct quoted_choice : jaxn::string_fragment {};\n   struct quoted : pegtl::if_must< at_quote, quoted_choice > {};\n\n   struct key_other : pegtl::sor< ident, quoted, index > {};\n   struct key_first : pegtl::sor< ident, quoted > {};\n\n   struct key_rule : pegtl::seq< key_first, pegtl::star_must< dot, key_other > > {};\n   // clang-format on\n\n}  // namespace tao::config::internal::rules\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/limits.hpp",
    "content": "// Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_LIMITS_HPP\n#define TAO_CONFIG_INTERNAL_LIMITS_HPP\n\n#include <cstddef>\n\nnamespace tao::config::internal\n{\n   static constexpr std::size_t global_nesting_limit = 96;\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/object.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_OBJECT_HPP\n#define TAO_CONFIG_INTERNAL_OBJECT_HPP\n\n#include <cassert>\n#include <map>\n#include <string>\n\n#include \"forward.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename C >\n   struct basic_object\n   {\n      using data_t = std::map< std::string, C >;\n\n      basic_object() = delete;\n\n      explicit basic_object( const pegtl::position& p )\n         : position( p )\n      {}\n\n      basic_object( basic_object&& ) = default;\n      basic_object( const basic_object& ) = default;\n\n      ~basic_object() = default;\n\n      basic_object& operator=( basic_object&& ) = default;\n      basic_object& operator=( const basic_object& ) = default;\n\n      [[nodiscard]] std::pair< const std::string, C >* find( const std::string& k ) noexcept\n      {\n         const auto i = object.find( k );\n         return ( i == object.end() ) ? nullptr : ( &*i );\n      }\n\n      [[nodiscard]] const std::pair< const std::string, C >* find( const std::string& k ) const noexcept\n      {\n         const auto i = object.find( k );\n         return ( i == object.end() ) ? nullptr : ( &*i );\n      }\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         return position;\n      }\n\n      std::map< std::string, C > object;\n      pegtl::position position;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/parse_utility.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PARSE_UTILITY_HPP\n#define TAO_CONFIG_INTERNAL_PARSE_UTILITY_HPP\n\n#include <utility>\n\n#include \"forward.hpp\"\n#include \"key1.hpp\"\n#include \"key1_action.hpp\"\n#include \"key1_grammar.hpp\"\n#include \"pegtl.hpp\"\n#include \"reference2.hpp\"\n#include \"reference2_action.hpp\"\n#include \"reference2_grammar.hpp\"\n\nnamespace tao::config::internal\n{\n   [[nodiscard]] inline key1 parse_key1( pegtl_input_t& in )\n   {\n      key1 result;\n      pegtl::parse< pegtl::must< rules::key1_rule >, key1_action >( in, result.vector() );\n      return result;\n   }\n\n   [[nodiscard]] inline reference2 parse_reference2( pegtl_input_t& in )\n   {\n      reference2 result;\n      pegtl::parse< pegtl::must< rules::reference2_rest >, reference2_action >( in, result.vector() );  // NOTE: Assumes that the opening bracket was already parsed!\n      return result;\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/pegtl.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PEGTL_HPP\n#define TAO_CONFIG_INTERNAL_PEGTL_HPP\n\n#include <tao/pegtl.hpp>\n\n#include <tao/pegtl/contrib/function.hpp>\n#include <tao/pegtl/contrib/instantiate.hpp>\n#include <tao/pegtl/contrib/predicates.hpp>\n\n#include <tao/pegtl/change_action_and_state.hpp>\n\nnamespace tao::pegtl\n{\n   template< typename P >\n   using invert = internal::predicates< internal::predicate_not_test, typename P::peek_t, P >;\n\n}  // namespace tao::pegtl\n\nnamespace tao::config\n{\n   using pegtl_input_t = pegtl::memory_input< pegtl::tracking_mode::eager, pegtl::eol::lf_crlf >;\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase1_append.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE1_APPEND_HPP\n#define TAO_CONFIG_INTERNAL_PHASE1_APPEND_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <iterator>\n#include <optional>\n#include <set>\n#include <stdexcept>\n#include <string>\n#include <type_traits>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"constants.hpp\"\n#include \"entry.hpp\"\n#include \"json.hpp\"\n#include \"key1.hpp\"\n#include \"limits.hpp\"\n#include \"object.hpp\"\n#include \"phase1_mode.hpp\"\n#include \"reference2.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename T >\n   void phase1_append( concat& c, const key1& path, const T& thing, const phase1_mode mode );\n\n   template< typename T >\n   void phase1_append_asterisk( concat& c, const pegtl::position& p, const key1& path, const T& thing, const phase1_mode mode )\n   {\n      c.back_ensure_init( asterisk_init, p );\n      phase1_append( c.concat.back().get_asterisk(), path, thing, mode );\n   }\n\n   template< typename T >\n   void phase1_append_name( concat& c, const pegtl::position& p, const std::string& name, const key1& path, const T& thing, const phase1_mode mode )\n   {\n      c.back_ensure_init( object_init, p );\n      const auto pair = c.concat.back().get_object().object.try_emplace( name, p );\n      pair.first->second.implicit = ( mode == phase1_mode::implicit ) && ( pair.second || pair.first->second.implicit );\n      phase1_append( pair.first->second, path, thing, mode );\n   }\n\n   template< typename T >\n   void phase1_append_index( concat& c, const pegtl::position& p, const std::size_t index, const key1& path, const T& thing, const phase1_mode mode )\n   {\n      std::size_t n = index;\n\n      for( auto& e : c.concat ) {\n         switch( e.kind() ) {\n            case entry_kind::NULL_:\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               throw pegtl::parse_error( \"cannot index (across) value\", p );\n            case entry_kind::ARRAY:\n               if( e.get_array().array.size() > n ) {\n                  phase1_append( *std::next( e.get_array().array.begin(), n ), path, thing, mode );\n                  return;\n               }\n               n -= e.get_array().array.size();\n               continue;\n            case entry_kind::OBJECT:\n               throw pegtl::parse_error( \"cannot index (across) object\", p );\n            case entry_kind::ASTERISK:\n               throw pegtl::parse_error( \"cannot index (across) asterisk\", p );\n            case entry_kind::REFERENCE:\n               throw pegtl::parse_error( \"cannot index (across) reference\", p );\n         }\n      }\n      throw pegtl::parse_error( \"index out of range\", p );\n   }\n\n   template< typename T >\n   void phase1_append_append( concat& c, const pegtl::position& p, const std::uint64_t g, const key1& path, const T& thing, const phase1_mode mode )\n   {\n      c.back_ensure_init( array_init, p );\n      auto& a = c.concat.back().get_array();\n      if( g > c.generation ) {\n         c.generation = g;\n         concat& d = a.array.emplace_back( p );\n         d.remove = false;  // TODO: Make consistent with entry::expand()?\n         phase1_append( d, path, thing, mode );\n         return;\n      }\n      assert( !a.array.empty() );\n      phase1_append( a.array.back(), path, thing, mode );\n   }\n\n   template< typename T >\n   void phase1_append( concat& c, const key1& path, const T& thing, const phase1_mode mode )\n   {\n      if( path.empty() ) {\n         thing( c );\n         return;\n      }\n      const auto& part = path.at( 0 );\n\n      switch( part.kind() ) {\n         case key1_kind::asterisk:\n            phase1_append_asterisk( c, part.position, pop_front( path ), thing, mode );\n            return;\n         case key1_kind::name:\n            phase1_append_name( c, part.position, part.get_name(), pop_front( path ), thing, mode );\n            return;\n         case key1_kind::index:\n            phase1_append_index( c, part.position, part.get_index(), pop_front( path ), thing, mode );\n            return;\n         case key1_kind::append:\n            phase1_append_append( c, part.position, part.get_generation(), pop_front( path ), thing, mode );\n            return;\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n   template< typename T >\n   void phase1_append( object& o, const key1& path, const T& thing, const phase1_mode mode )\n   {\n      assert( !path.empty() );\n\n      if( path.size() > global_nesting_limit ) {\n         throw pegtl::parse_error( \"nesting depth exceeded\", path.at( global_nesting_limit ).position );\n      }\n      if( path.front().kind() != key1_kind::name ) {\n         throw pegtl::parse_error( \"expected name\", path.front().position );\n      }\n      const std::string& name = path.front().get_name();\n      const auto pair = o.object.try_emplace( name, path.front().position );\n      pair.first->second.implicit = ( mode == phase1_mode::implicit ) && ( pair.second || pair.first->second.implicit );\n      phase1_append( pair.first->second, pop_front( path ), thing, mode );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase1_mode.hpp",
    "content": "// Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE1_MODE_HPP\n#define TAO_CONFIG_INTERNAL_PHASE1_MODE_HPP\n\nnamespace tao::config::internal\n{\n   enum class phase1_mode : bool\n   {\n      implicit = true,\n      manifest = false  // Can't use explicit as enum label.\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase2_access.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE2_ACCESS_HPP\n#define TAO_CONFIG_INTERNAL_PHASE2_ACCESS_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <iterator>\n#include <stdexcept>\n#include <string>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"constants.hpp\"\n#include \"entry.hpp\"\n#include \"key1.hpp\"\n#include \"object.hpp\"\n#include \"statistics.hpp\"\n\nnamespace tao::config::internal\n{\n   struct phase2_access_return\n   {};\n\n   [[nodiscard]] inline const concat* phase2_access( const concat& c, const key1& suffix, const int down );\n\n   [[nodiscard]] inline const concat* phase2_access_name( const concat& c, const pegtl::position& p, const std::string& name, const key1& suffix, const int down )\n   {\n      if( c.concat.empty() ) {\n         if( down >= 0 ) {\n            return nullptr;\n         }\n         throw phase2_access_return();  // TODO: Or error or return?\n      }\n      if( c.concat.size() > 1 ) {\n         throw phase2_access_return();\n      }\n      const auto& e = c.concat.front();\n      switch( e.kind() ) {\n         case entry_kind::NULL_:\n         case entry_kind::BOOLEAN:\n         case entry_kind::STRING:\n         case entry_kind::BINARY:\n         case entry_kind::SIGNED:\n         case entry_kind::UNSIGNED:\n         case entry_kind::DOUBLE:\n            throw pegtl::parse_error( \"access name in value\", p );  // TODO: Add c.position to the exception, too?\n         case entry_kind::ARRAY:\n            if( down >= 0 ) {\n               return nullptr;\n            }\n            throw pegtl::parse_error( \"access name in array\", p );\n         case entry_kind::OBJECT:\n            if( const auto i = e.get_object().object.find( name ); i != e.get_object().object.end() ) {\n               return phase2_access( i->second, suffix, down - 1 );\n            }\n            if( down >= 0 ) {\n               return nullptr;\n            }\n            throw pegtl::parse_error( \"name not found\", p );\n         case entry_kind::ASTERISK:\n            if( down >= 0 ) {\n               return nullptr;\n            }\n            throw pegtl::parse_error( \"name not found\", p );\n         case entry_kind::REFERENCE:\n            throw phase2_access_return();\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n   [[nodiscard]] inline const concat* phase2_access_index( const concat& c, const pegtl::position& p, const std::size_t index, const key1& suffix, const int down )\n   {\n      if( c.concat.empty() ) {\n         if( down >= 0 ) {\n            return nullptr;\n         }\n         throw phase2_access_return();  // TODO: Or error or return?\n      }\n      if( c.concat.size() > 1 ) {\n         throw phase2_access_return();\n      }\n      const auto& e = c.concat.front();\n      switch( e.kind() ) {\n         case entry_kind::NULL_:\n         case entry_kind::BOOLEAN:\n         case entry_kind::STRING:\n         case entry_kind::BINARY:\n         case entry_kind::SIGNED:\n         case entry_kind::UNSIGNED:\n         case entry_kind::DOUBLE:\n            throw pegtl::parse_error( \"cannot index (across) value\", p );\n         case entry_kind::ARRAY:\n            if( e.get_array().array.size() > index ) {\n               return phase2_access( *std::next( e.get_array().array.begin(), index ), suffix, down - 1 );\n            }\n            if( down >= 0 ) {\n               return nullptr;\n            }\n            throw pegtl::parse_error( \"index out of range\", p );\n         case entry_kind::OBJECT:\n            throw pegtl::parse_error( \"cannot index (across) object\", p );\n         case entry_kind::ASTERISK:\n            if( down >= 0 ) {\n               return nullptr;\n            }\n            throw pegtl::parse_error( \"cannot index (across) asterisk\", p );\n         case entry_kind::REFERENCE:\n            throw pegtl::parse_error( \"cannot index (across) reference\", p );\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n   [[nodiscard]] inline const concat* phase2_access( const concat& c, const key1_part& p, const key1& suffix, const int down )\n   {\n      switch( p.kind() ) {\n         case key1_kind::asterisk:\n            throw pegtl::parse_error( \"unable to access asterisk\", p.position );\n         case key1_kind::name:\n            return phase2_access_name( c, p.position, p.get_name(), suffix, down );\n         case key1_kind::index:\n            return phase2_access_index( c, p.position, p.get_index(), suffix, down );\n         case key1_kind::append:\n            throw pegtl::parse_error( \"this should be impossible\", p.position );\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n   [[nodiscard]] inline const concat* phase2_access( const concat& c, const key1& suffix, const int down )\n   {\n      if( !suffix.empty() ) {\n         return phase2_access( c, suffix.at( 0 ), pop_front( suffix ), down );\n      }\n      if( statistics( c ).is_primitive() ) {\n         return &c;\n      }\n      throw phase2_access_return();\n   }\n\n   [[nodiscard]] inline const concat* phase2_access( const object& o, const key1& prefix, const key1& suffix )\n   {\n      assert( !suffix.empty() );\n\n      try {\n         for( std::size_t i = 0; i <= prefix.size(); ++i ) {\n            const int down = int( prefix.size() ) - int( i );\n            const key1 path = key1( prefix.begin(), prefix.end() - i ) + suffix;\n            const auto j = o.object.find( path.front().get_name() );\n            if( j != o.object.end() ) {\n               if( const concat* c = phase2_access( j->second, pop_front( path ), down - 1 ) ) {\n                  return c;\n               }\n            }\n         }\n         return nullptr;\n      }\n      catch( const phase2_access_return& /*unused*/ ) {\n         return nullptr;\n      }\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase2_additions.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE2_ADDITIONS_HPP\n#define TAO_CONFIG_INTERNAL_PHASE2_ADDITIONS_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <iterator>\n#include <stdexcept>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"json.hpp\"\n#include \"object.hpp\"\n#include \"string_utility.hpp\"\n\nnamespace tao::config::internal\n{\n   struct phase2_additions_impl\n   {\n      explicit phase2_additions_impl( object& root )\n         : m_root( root )\n      {}\n\n      [[nodiscard]] std::size_t process()\n      {\n         for( auto& p : m_root.object ) {\n            process_concat( p.second );\n         }\n         return m_changes;\n      }\n\n   private:\n      object& m_root;\n      std::size_t m_changes = 0;\n\n      void process_concat( concat& c )\n      {\n         for( entry& e : c.concat ) {\n            process_entry( e );\n         }\n         if( c.concat.size() < 2 ) {\n            return;\n         }\n         for( auto r = ++c.concat.begin(); r != c.concat.end(); ++r ) {\n            const auto l = std::prev( r );\n            switch( r->kind() ) {\n               case entry_kind::NULL_:\n               case entry_kind::BOOLEAN:\n                  throw_type_error( *l, *r );\n\n               case entry_kind::SIGNED:\n               case entry_kind::UNSIGNED:\n                  if( ignore_entry( *l ) || ignore_entry( *r ) ) {\n                     continue;\n                  }\n                  if( ( r->kind() == entry_kind::SIGNED ) ) {\n                     if( l->kind() == entry_kind::SIGNED ) {\n                        r->get_signed_atom().value += l->get_signed();\n                        break;\n                     }\n                     else if( l->kind() == entry_kind::UNSIGNED ) {\n                        r->get_signed_atom().value += std::int64_t( l->get_unsigned() );\n                        break;\n                     }\n                  }\n                  else {  // r->kind() == entry_kind::UNSIGNED\n                     if( l->kind() == entry_kind::UNSIGNED ) {\n                        r->get_unsigned_atom().value += l->get_unsigned();\n                        break;\n                     }\n                     else if( l->kind() == entry_kind::SIGNED ) {\n                        l->get_signed_atom().value += std::int64_t( r->get_unsigned() );\n                        ( *r ) = ( *l );\n                        break;\n                     }\n                  }\n                  throw_type_error( *l, *r );\n\n               case entry_kind::DOUBLE:\n                  if( !throw_type_error_if( *l, *r, entry_kind::DOUBLE ) ) {\n                     continue;\n                  }\n                  r->get_double_atom().value += l->get_double();\n                  break;\n\n               case entry_kind::STRING:\n                  if( !throw_type_error_if( *l, *r, entry_kind::STRING ) ) {\n                     continue;\n                  }\n                  r->get_string_atom().value = l->get_string() + r->get_string();\n                  break;\n\n               case entry_kind::BINARY:\n                  if( !throw_type_error_if( *l, *r, entry_kind::BINARY ) ) {\n                     continue;\n                  }\n                  r->get_binary_atom().value.insert( r->get_binary().begin(), l->get_binary().begin(), l->get_binary().end() );\n                  break;\n\n               case entry_kind::ARRAY:\n                  if( !throw_type_error_if( *l, *r, entry_kind::ARRAY ) ) {\n                     continue;\n                  }\n                  r->get_array().array.splice( r->get_array().array.begin(), l->get_array().array );  // throw_type_error_if returns false if l and/or r are functions.\n                  break;\n\n               case entry_kind::OBJECT:\n                  if( !throw_type_error_if( *l, *r, entry_kind::OBJECT ) ) {\n                     continue;\n                  }\n                  process_object( std::move( l->get_object() ), r->get_object() );\n                  break;\n\n               case entry_kind::ASTERISK:\n               case entry_kind::REFERENCE:\n                  continue;\n            }\n            [[maybe_unused]] const auto t = c.concat.erase( l );\n            assert( t == r );\n            ++m_changes;\n         }\n      }\n\n      void process_entry( entry& e )\n      {\n         switch( e.kind() ) {\n            case entry_kind::NULL_:\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               return;\n            case entry_kind::ARRAY:\n               for( concat& c : e.get_array().array ) {\n                  process_concat( c );\n               }\n               return;\n            case entry_kind::OBJECT:\n               for( auto& p : e.get_object().object ) {\n                  process_concat( p.second );\n               }\n               return;\n            case entry_kind::ASTERISK:\n               process_concat( e.get_asterisk() );\n               return;\n            case entry_kind::REFERENCE:\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n\n      [[nodiscard]] static bool ignore_entry( const entry& e ) noexcept\n      {\n         if( ( e.kind() == entry_kind::ASTERISK ) || ( e.kind() == entry_kind::REFERENCE ) ) {\n            return true;\n         }\n         if( ( e.kind() == entry_kind::ARRAY ) && ( !e.get_array().function.empty() ) ) {\n            return true;\n         }\n         return false;\n      }\n\n      [[nodiscard]] static bool throw_type_error_if( const entry& l, const entry& r, const entry_kind k )\n      {\n         if( ignore_entry( l ) ) {\n            return false;\n         }\n         if( ignore_entry( r ) ) {\n            return false;\n         }\n         if( l.kind() == k ) {\n            return true;\n         }\n         throw_type_error( l, r );\n      }\n\n      [[noreturn]] static void throw_type_error( const entry& l, const entry& r )\n      {\n         throw pegtl::parse_error( strcat( \"incompatible or invalid type(s) in addition \", l.kind(), \"@\", l.get_position(), \" and \", r.kind(), \"@\", r.get_position() ), pegtl::position( 0, 0, 0, \"TODO: location of '+'\" ) );\n      }\n\n      static void process_object( object&& l, object& r )\n      {\n         for( std::pair< const std::string, concat >& m : l.object ) {\n            const auto pair = r.object.try_emplace( m.first, m.second );\n            if( !pair.second ) {\n               if( pair.first->second.remove ) {\n                  continue;\n               }\n               if( m.second.remove ) {\n                  pair.first->second.remove = true;\n               }\n               if( m.second.temporary ) {\n                  pair.first->second.temporary = true;\n               }\n               pair.first->second.concat.splice( pair.first->second.concat.begin(), m.second.concat );\n            }\n         }\n      }\n   };\n\n   [[nodiscard]] inline std::size_t phase2_additions( object& root )\n   {\n      return phase2_additions_impl( root ).process();\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase2_asterisks.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE2_ASTERISKS_HPP\n#define TAO_CONFIG_INTERNAL_PHASE2_ASTERISKS_HPP\n\n#include <cstddef>\n#include <list>\n#include <set>\n#include <stdexcept>\n#include <string>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"json.hpp\"\n#include \"object.hpp\"\n\nnamespace tao::config::internal\n{\n   struct phase2_asterisks_impl\n   {\n      explicit phase2_asterisks_impl( object& root )\n         : m_root( root )\n      {}\n\n      [[nodiscard]] std::size_t process()\n      {\n         for( auto& p : m_root.object ) {\n            process_concat( p.second );\n         }\n         return m_changes;\n      }\n\n   private:\n      object& m_root;\n      std::size_t m_changes = 0;\n\n      void process_concat( concat& c )\n      {\n         auto i = c.concat.begin();\n\n         while( i != c.concat.end() ) {\n            process_entry( c, i );\n         }\n      }\n\n      void process_entry( concat& c, std::list< entry >::iterator& i )\n      {\n         switch( i->kind() ) {\n            case entry_kind::NULL_:\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               ++i;\n               return;\n            case entry_kind::ARRAY:\n               if( c.concat.size() == 1 ) {\n                  for( concat& d : i->get_array().array ) {\n                     process_concat( d );\n                  }\n               }\n               ++i;\n               return;\n            case entry_kind::OBJECT:\n               if( c.concat.size() == 1 ) {\n                  for( auto& p : i->get_object().object ) {\n                     process_concat( p.second );\n                  }\n               }\n               ++i;\n               return;\n            case entry_kind::ASTERISK:\n               process_asterisk( c, i );\n               return;\n            case entry_kind::REFERENCE:\n               ++i;\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n\n      void process_asterisk( concat& c, std::list< entry >::iterator& i )\n      {\n         const concat star = std::move( i->get_asterisk() );\n\n         std::set< std::string > names;\n\n         for( auto j = c.concat.begin(); j != i; ++j ) {\n            switch( j->kind() ) {\n               case entry_kind::NULL_:\n               case entry_kind::BOOLEAN:\n               case entry_kind::STRING:\n               case entry_kind::BINARY:\n               case entry_kind::SIGNED:\n               case entry_kind::UNSIGNED:\n               case entry_kind::DOUBLE:\n                  continue;\n               case entry_kind::ARRAY:\n                  if( !j->get_array().function.empty() ) {\n                     throw pegtl::parse_error( \"please do not use an asterisk inside of a function\", j->get_array().position );\n                  }\n                  process_array_and_asterisk( j->get_array(), star );\n                  continue;\n               case entry_kind::OBJECT:\n                  for( const auto& p : j->get_object().object ) {\n                     names.emplace( p.first );\n                  }\n                  continue;\n               case entry_kind::ASTERISK:\n               case entry_kind::REFERENCE:\n                  continue;\n            }\n         }\n         for( auto j = i; j != c.concat.end(); ++j ) {\n            switch( j->kind() ) {\n               case entry_kind::NULL_:\n               case entry_kind::BOOLEAN:\n               case entry_kind::STRING:\n               case entry_kind::BINARY:\n               case entry_kind::SIGNED:\n               case entry_kind::UNSIGNED:\n               case entry_kind::DOUBLE:\n                  continue;\n               case entry_kind::ARRAY:\n                  if( !j->get_array().function.empty() ) {\n                     throw pegtl::parse_error( \"please do not use an asterisk inside of a function\", j->get_array().position );\n                  }\n                  process_asterisk_and_array( star, j->get_array() );\n                  continue;\n               case entry_kind::OBJECT:\n                  for( const auto& p : j->get_object().object ) {\n                     names.emplace( p.first );\n                  }\n                  continue;\n               case entry_kind::ASTERISK:\n               case entry_kind::REFERENCE:\n                  continue;\n            }\n         }\n         ++m_changes;\n\n         if( names.empty() ) {\n            i = c.concat.erase( i );\n            return;\n         }\n         i->set_object( star.position );\n\n         for( const auto& name : names ) {\n            [[maybe_unused]] const auto [ j, b ] = i->get_object().object.try_emplace( name, star );\n            assert( b && ( j->second.temporary == star.temporary ) );\n         }\n         ++i;\n      }\n\n      void process_asterisk_and_array( const concat& s, array& a )\n      {\n         for( concat& c : a.array ) {\n            if( c.remove ) {\n               continue;\n            }\n            c.remove = s.remove;\n            c.temporary |= s.temporary;\n            c.concat.insert( c.concat.begin(), s.concat.begin(), s.concat.end() );\n         }\n      }\n\n      void process_array_and_asterisk( array& a, const concat& s )\n      {\n         for( concat& c : a.array ) {\n            if( s.remove ) {\n               c.remove = true;\n               c.concat.clear();\n            }\n            c.temporary |= s.temporary;\n            c.concat.insert( c.concat.end(), s.concat.begin(), s.concat.end() );\n         }\n      }\n   };\n\n   [[nodiscard]] inline std::size_t phase2_asterisks( object& root )\n   {\n      return phase2_asterisks_impl( root ).process();\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase2_everything.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE2_EVERYTHING_HPP\n#define TAO_CONFIG_INTERNAL_PHASE2_EVERYTHING_HPP\n\n#include \"forward.hpp\"\n#include \"phase2_additions.hpp\"\n#include \"phase2_asterisks.hpp\"\n#include \"phase2_functions.hpp\"\n#include \"phase2_references.hpp\"\n#include \"state.hpp\"\n\nnamespace tao::config::internal\n{\n   [[nodiscard]] inline bool phase2_iteration( state& st, const function_map& fm )\n   {\n      return ( phase2_functions( st, fm ) | phase2_additions( st.root ) | phase2_references( st.root ) | phase2_asterisks( st.root ) ) > 0;\n   }\n\n   inline void phase2_everything( state& st, const function_map& fm )\n   {\n      while( phase2_iteration( st, fm ) ) {\n         // This loop could do with some major optimisations; probably not worth the effort for config files.\n      }\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase2_functions.hpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE2_FUNCTIONS_HPP\n#define TAO_CONFIG_INTERNAL_PHASE2_FUNCTIONS_HPP\n\n#include <cstddef>\n#include <stdexcept>\n#include <string>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"config_action.hpp\"\n#include \"config_grammar.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"function_traits.hpp\"\n#include \"object.hpp\"\n#include \"pegtl.hpp\"\n#include \"state.hpp\"\n\nnamespace tao::config::internal\n{\n   struct phase2_functions_impl\n   {\n      phase2_functions_impl( state& st, const function_map& fm )\n         : m_state( st ),\n           m_functions( fm )\n      {}\n\n      [[nodiscard]] std::size_t process()\n      {\n         for( auto& p : m_state.root.object ) {\n            process_concat( p.second );\n         }\n         return m_changes;\n      }\n\n   private:\n      state& m_state;\n      std::size_t m_changes = 0;\n      const function_map& m_functions;\n\n      void process_concat( concat& c )\n      {\n         for( auto& e : c.concat ) {\n            process_entry( e );\n         }\n      }\n\n      void process_entry( entry& e )\n      {\n         switch( e.kind() ) {\n            case entry_kind::NULL_:\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               return;\n            case entry_kind::ARRAY:\n               for( auto& c : e.get_array().array ) {\n                  process_concat( c );\n               }\n               if( !e.get_array().function.empty() ) {\n                  process_function( e );\n               }\n               return;\n            case entry_kind::OBJECT:\n               for( auto& p : e.get_object().object ) {\n                  process_concat( p.second );\n               }\n               return;\n            case entry_kind::ASTERISK:\n            case entry_kind::REFERENCE:\n               return;\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n\n      void process_function( entry& e )\n      {\n         array& a = e.get_array();\n\n         if( a.function == \"parse\" ) {\n            process_parse_function( e, a );\n            ++m_changes;\n            return;\n         }\n         const auto i = m_functions.find( a.function );\n\n         if( i == m_functions.end() ) {\n            throw pegtl::parse_error( \"unknown function name \" + a.function, a.position );\n         }\n         if( i->second( e ) ) {\n            ++m_changes;\n         }\n      }\n\n      void process_parse_function( entry& e, array& a )\n      {\n         try {\n            state st;\n            std::size_t i = 0;\n            const std::string s = function_traits< std::string >::get( a, i );\n            const key1 k = { key1_part( std::string( \"\\0\", 1 ), a.position ) };\n            const key1_guard kg( st, key1( k ) );\n            pegtl::string_input< pegtl::tracking_mode::eager, pegtl_input_t::eol_t > in( s, __FUNCTION__ );\n            pegtl::parse_nested< rules::value, config_action >( a.position, static_cast< pegtl_input_t& >( in ), st, m_functions );\n            assert( st.root.object.size() == 1 );\n            assert( st.root.object.begin()->second.concat.size() == 1 );\n            e = st.root.object.begin()->second.concat.front();  // TODO: This is slightly hack-ish.\n         }\n         catch( const arguments_unready& ) {\n         }\n      }\n   };\n\n   [[nodiscard]] inline std::size_t phase2_functions( state& st, const function_map& fm )\n   {\n      return phase2_functions_impl( st, fm ).process();\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase2_references.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE2_REFERENCES_HPP\n#define TAO_CONFIG_INTERNAL_PHASE2_REFERENCES_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <optional>\n#include <set>\n#include <stdexcept>\n#include <vector>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"json.hpp\"\n#include \"object.hpp\"\n#include \"phase2_access.hpp\"\n#include \"string_utility.hpp\"\n\nnamespace tao::config::internal\n{\n   struct phase2_references_impl\n   {\n      explicit phase2_references_impl( object& root )\n         : m_root( root )\n      {}\n\n      [[nodiscard]] std::size_t process()\n      {\n         for( auto& p : m_root.object ) {\n            process_concat( key1{ key1_part( p.first, m_root.position ) }, p.second );\n         }\n         return m_changes;\n      }\n\n   private:\n      object& m_root;\n      std::size_t m_changes = 0;\n\n      void process_concat( const key1& prefix, concat& c )\n      {\n         for( auto& e : c.concat ) {\n            if( const concat* d = process_entry( prefix, e ); d != nullptr ) {\n               assert( d != &c );  // TODO: This needs to be ensured elsewhere/in another way.\n\n               if( !d->concat.empty() ) {\n                  assert( d->concat.size() == 1 );\n\n                  e = d->concat.front();\n                  ++m_changes;\n               }\n            }\n         }\n      }\n\n      [[nodiscard]] std::optional< key1_part > process_reference_part( const key1& prefix, const reference2_part& part )\n      {\n         switch( part.kind() ) {\n            case reference2_kind::name:\n               return key1_part( part.get_name(), part.position );\n            case reference2_kind::index:\n               return key1_part( part.get_index(), part.position );\n            case reference2_kind::vector:\n               return process_inner_reference( prefix, part.get_vector() );\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n\n      [[nodiscard]] const concat* process_reference_parts( const key1& prefix, const std::vector< reference2_part >& reference )\n      {\n         key1 suffix;\n\n         for( auto& p : reference ) {\n            if( const std::optional< key1_part > k = process_reference_part( prefix, p ) ) {\n               suffix += *k;\n               continue;\n            }\n            return nullptr;\n         }\n         assert( !prefix.empty() );\n\n         return phase2_access( m_root, pop_back( prefix ), suffix );  // Returns nullptr if not primitive.\n      }\n\n      [[nodiscard]] std::optional< key1_part > process_inner_reference( const key1& prefix, const std::vector< reference2_part >& reference )\n      {\n         if( const concat* c = process_reference_parts( prefix, reference ) ) {\n            if( c->concat.size() == 1 ) {\n               const entry& e = c->concat.back();\n               switch( e.kind() ) {\n                  case entry_kind::STRING:\n                     return key1_part( e.get_string(), e.get_string_atom().position );\n                  case entry_kind::UNSIGNED:\n                     return key1_part( e.get_unsigned(), e.get_unsigned_atom().position );\n                  case entry_kind::NULL_:\n                  case entry_kind::BOOLEAN:\n                  case entry_kind::BINARY:\n                  case entry_kind::SIGNED:\n                  case entry_kind::DOUBLE:\n                  case entry_kind::ARRAY:\n                  case entry_kind::OBJECT:\n                  case entry_kind::ASTERISK:\n                  case entry_kind::REFERENCE:\n                     throw pegtl::parse_error( strcat( \"invalid type '\", e.kind(), \"' for reference part\" ), e.get_position() );\n               }\n            }\n         }\n         return std::nullopt;\n      }\n\n      [[nodiscard]] const concat* process_entry( const key1& prefix, entry& e )\n      {\n         switch( e.kind() ) {\n            case entry_kind::NULL_:\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               return nullptr;\n            case entry_kind::ARRAY: {\n               std::size_t i = 0;\n               for( auto& c : e.get_array().array ) {\n                  process_concat( prefix + key1_part( i++, m_root.position ), c );\n               }\n               return nullptr;\n            }\n            case entry_kind::OBJECT:\n               for( auto& p : e.get_object().object ) {\n                  process_concat( prefix + key1_part( p.first, m_root.position ), p.second );\n               }\n               return nullptr;\n            case entry_kind::ASTERISK:\n               return nullptr;\n            case entry_kind::REFERENCE:\n               return process_reference_parts( prefix, e.get_reference() );\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n   };\n\n   [[nodiscard]] inline std::size_t phase2_references( object& root )\n   {\n      return phase2_references_impl( root ).process();\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase3_remove.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE3_REMOVE_HPP\n#define TAO_CONFIG_INTERNAL_PHASE3_REMOVE_HPP\n\n#include <cassert>\n#include <stdexcept>\n#include <string>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"object.hpp\"\n#include \"pegtl.hpp\"\n#include \"string_utility.hpp\"\n\nnamespace tao::config::internal\n{\n   inline void phase3_remove( array& a );\n   inline void phase3_remove( object& o );\n\n   inline void phase3_remove( concat& c )\n   {\n      for( auto& e : c.concat ) {\n         switch( e.kind() ) {\n            case entry_kind::NULL_:\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               continue;\n            case entry_kind::ARRAY:\n               if( !e.get_array().function.empty() ) {\n                  throw pegtl::parse_error( \"function '\" + e.get_array().function + \"' could not be called\", e.get_array().position );\n               }\n               phase3_remove( e.get_array() );\n               continue;\n            case entry_kind::OBJECT:\n               phase3_remove( e.get_object() );\n               continue;\n            case entry_kind::ASTERISK:\n               throw pegtl::parse_error( \"asterisk could not be expanded\", e.get_asterisk().position );  // Can happen when there are also unresolved references?\n            case entry_kind::REFERENCE:\n               throw pegtl::parse_error( \"reference '\" + e.get_reference().to_string() + \"' could not be resolved\", e.get_reference().at( 0 ).position );\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n   }\n\n   inline void phase3_remove( array& a )\n   {\n      auto i = a.array.begin();\n\n      while( i != a.array.end() ) {\n         phase3_remove( *i );\n         if( i->omit_from_final_result() ) {\n            i = a.array.erase( i );\n         }\n         else {\n            ++i;\n         }\n      }\n   }\n\n   inline void phase3_remove( object& o )\n   {\n      auto i = o.object.begin();\n\n      while( i != o.object.end() ) {\n         phase3_remove( i->second );\n         if( i->second.omit_from_final_result() ) {\n            i = o.object.erase( i );\n         }\n         else {\n            ++i;\n         }\n      }\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/phase5_repack.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_PHASE5_REPACK_HPP\n#define TAO_CONFIG_INTERNAL_PHASE5_REPACK_HPP\n\n#include <cassert>\n#include <cstddef>\n#include <stdexcept>\n#include <utility>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"forward.hpp\"\n#include \"object.hpp\"\n#include \"repack_traits.hpp\"\n\n#include \"../key.hpp\"\n\nnamespace tao::config::internal\n{\n   template< template< typename... > class Traits >\n   void set_key_and_position( [[maybe_unused]] json::basic_value< Traits >& r, [[maybe_unused]] const key& k, [[maybe_unused]] const pegtl::position& p )\n   {\n      if constexpr( has_set_key< json::basic_value< Traits > > ) {\n         r.set_key( k );\n      }\n      if constexpr( has_set_position< json::basic_value< Traits > > ) {\n         r.set_position( p );\n      }\n   }\n\n   template< template< typename... > class Traits >\n   void phase5_repack( const key& k, json::events::to_basic_value< Traits >& consumer, const concat& c );\n\n   template< template< typename... > class Traits >\n   void phase5_repack( const key& k, json::events::to_basic_value< Traits >& consumer, const array& a )\n   {\n      consumer.begin_array( a.array.size() );\n      set_key_and_position( consumer.stack_.back(), k, a.position );\n      std::size_t i = 0;\n      for( const auto& c : a.array ) {\n         phase5_repack( k + i++, consumer, c );\n         consumer.element();\n      }\n      consumer.end_array( a.array.size() );\n   }\n\n   template< template< typename... > class Traits >\n   void phase5_repack( const key& k, json::events::to_basic_value< Traits >& consumer, const object& o )\n   {\n      consumer.begin_object( o.object.size() );\n      set_key_and_position( consumer.stack_.back(), k, o.position );\n      for( const auto& p : o.object ) {\n         consumer.key( p.first );\n         phase5_repack( k + p.first, consumer, p.second );\n         consumer.member();\n      }\n      consumer.end_object( o.object.size() );\n   }\n\n   template< template< typename... > class Traits >\n   void phase5_repack( const key& k, json::events::to_basic_value< Traits >& consumer, const entry& e )\n   {\n      switch( e.kind() ) {\n         case entry_kind::NULL_:\n            consumer.null();\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::BOOLEAN:\n            consumer.boolean( e.get_boolean() );\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::SIGNED:\n            consumer.number( e.get_signed() );\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::UNSIGNED:\n            consumer.number( e.get_unsigned() );\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::DOUBLE:\n            consumer.number( e.get_double() );\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::STRING:\n            consumer.string( e.get_string() );\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::BINARY:\n            consumer.binary( e.get_binary() );\n            set_key_and_position( consumer.value, k, e.get_position() );\n            return;\n         case entry_kind::ARRAY:\n            if( !e.get_array().function.empty() ) {\n               throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE -- must have been either eliminated or flagged as error earlier.\n            }\n            phase5_repack( k, consumer, e.get_array() );\n            return;\n         case entry_kind::OBJECT:\n            phase5_repack( k, consumer, e.get_object() );\n            return;\n         case entry_kind::ASTERISK:\n         case entry_kind::REFERENCE:\n            throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE -- must have been either eliminated or flagged as error earlier.\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n   template< template< typename... > class Traits >\n   void phase5_repack( const key& k, json::events::to_basic_value< Traits >& consumer, const concat& c )\n   {\n      assert( c.concat.size() == 1 );  // This should be ensured by phase3_remove().\n\n      phase5_repack( k, consumer, c.concat.front() );\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > phase5_repack( const concat& c )\n   {\n      json::events::to_basic_value< Traits > consumer;\n      phase5_repack( key(), consumer, c );\n      return std::move( consumer.value );\n   }\n\n   template< template< typename... > class Traits >\n   [[nodiscard]] json::basic_value< Traits > phase5_repack( const object& o )\n   {\n      json::events::to_basic_value< Traits > consumer;\n      phase5_repack( key(), consumer, o );\n      set_key_and_position( consumer.value, key(), o.position );\n      return std::move( consumer.value );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/reference2.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_REFERENCE2_HPP\n#define TAO_CONFIG_INTERNAL_REFERENCE2_HPP\n\n#include <cassert>\n#include <initializer_list>\n#include <string>\n#include <vector>\n\n#include \"reference2_action.hpp\"\n#include \"reference2_grammar.hpp\"\n#include \"reference2_part.hpp\"\n\nnamespace tao::config::internal\n{\n   struct reference2\n      : std::vector< reference2_part >\n   {\n      reference2() = default;\n\n      reference2( reference2&& ) = default;\n      reference2( const reference2& ) = default;\n\n      ~reference2() = default;\n\n      reference2& operator=( reference2&& ) = default;\n      reference2& operator=( const reference2& ) = default;\n\n      explicit reference2( const std::string& s )\n      {\n         assign( s );\n      }\n\n      reference2( const std::initializer_list< reference2_part >& l )\n         : std::vector< reference2_part >( l )\n      {}\n\n      reference2( const std::vector< reference2_part >::const_iterator& begin, const std::vector< reference2_part >::const_iterator& end )\n         : std::vector< reference2_part >( begin, end )\n      {}\n\n      reference2& operator=( const std::string& s )\n      {\n         clear();\n         assign( s );\n         return *this;\n      }\n\n      reference2& operator=( const std::initializer_list< reference2_part >& l )\n      {\n         vector() = l;\n         return *this;\n      }\n\n      [[nodiscard]] std::vector< reference2_part >& vector() noexcept\n      {\n         return static_cast< std::vector< reference2_part >& >( *this );\n      }\n\n      [[nodiscard]] const std::vector< reference2_part >& vector() const noexcept\n      {\n         return static_cast< const std::vector< reference2_part >& >( *this );\n      }\n\n      [[nodiscard]] std::string to_string() const\n      {\n         return internal::to_string( vector() );\n      }\n\n      void assign( const std::string& s )\n      {\n         using grammar = pegtl::must< rules::reference2_rule, pegtl::eof >;\n         pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( s, __FUNCTION__ );\n         pegtl::parse< grammar, reference2_action >( in, vector() );\n      }\n\n      [[nodiscard]] const pegtl::position& get_position() const noexcept\n      {\n         assert( !vector().empty() );\n         return vector()[ 0 ].position;\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/reference2_action.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_REFERENCE2_ACTION_HPP\n#define TAO_CONFIG_INTERNAL_REFERENCE2_ACTION_HPP\n\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"json.hpp\"\n#include \"pegtl.hpp\"\n#include \"reference2_grammar.hpp\"\n#include \"reference2_part.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename Rule >\n   struct reference2_action\n      : pegtl::nothing< Rule >\n   {};\n\n   template<>\n   struct reference2_action< rules::ident >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< reference2_part >& st )\n      {\n         st.emplace_back( in.string(), in.position() );\n      }\n   };\n\n   template<>\n   struct reference2_action< rules::index >\n   {\n      template< typename Input >\n      static void apply( const Input& in, std::vector< reference2_part >& st )\n      {\n         st.emplace_back( std::stoul( in.string() ), in.position() );\n      }\n   };\n\n   template<>\n   struct reference2_action< rules::quoted_choice >\n      : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string >\n   {\n      template< typename Input >\n      static void success( const Input& in, std::string& unescaped, std::vector< reference2_part >& st )\n      {\n         st.emplace_back( std::move( unescaped ), in.position() );  // TODO: Position from beginning of quoted string instead of end.\n      }\n   };\n\n   template<>\n   struct reference2_action< rules::reference2_must >\n      : pegtl::nothing< rules::reference2_must >\n   {\n      template< typename Rule,\n                pegtl::apply_mode A,\n                pegtl::rewind_mode M,\n                template< typename... >\n                class Action,\n                template< typename... >\n                class Control,\n                typename ParseInput >\n      [[nodiscard]] static bool match( ParseInput& in, std::vector< reference2_part >& st )\n      {\n         st.emplace_back( part_vector, in.position() );\n         return pegtl::match< Rule, A, M, Action, Control >( in, st.back().get_vector() );\n      }\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/reference2_grammar.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_REFERENCE2_GRAMMAR_HPP\n#define TAO_CONFIG_INTERNAL_REFERENCE2_GRAMMAR_HPP\n\n#include \"key_grammar.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal::rules\n{\n   struct reference2_must;\n\n   // clang-format off\n   struct reference2_part : pegtl::sor< ident, quoted, index, reference2_must > {};\n   struct reference2_list : pegtl::list_must< reference2_part, dot > {};\n   struct reference2_rest : pegtl::seq< reference2_list, pegtl::one< ')' > > {};  // For config_grammar.hpp -- used without actions.\n   struct reference2_must : pegtl::if_must< pegtl::one< '(' >, reference2_list, pegtl::one< ')' > > {};\n   struct reference2_rule : pegtl::if_must< pegtl::one< '(' >, reference2_list, pegtl::one< ')' > > {};\n   // clang-format on\n\n}  // namespace tao::config::internal::rules\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/reference2_kind.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_REFERENCE2_KIND_HPP\n#define TAO_CONFIG_INTERNAL_REFERENCE2_KIND_HPP\n\nnamespace tao::config::internal\n{\n   enum class reference2_kind : char\n   {\n      name = 0,\n      index = 1,\n      vector = 2\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/reference2_part.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_REFERENCE2_PART_HPP\n#define TAO_CONFIG_INTERNAL_REFERENCE2_PART_HPP\n\n#include <cassert>\n#include <cstdlib>\n#include <ostream>\n#include <stdexcept>\n#include <string>\n#include <variant>\n#include <vector>\n\n#include \"constants.hpp\"\n#include \"pegtl.hpp\"\n#include \"reference2_kind.hpp\"\n\nnamespace tao::config::internal\n{\n   struct reference2_part;\n\n   [[nodiscard]] inline std::string to_string( const std::vector< reference2_part >& );\n\n   struct reference2_part\n   {\n      using data_t = std::variant< std::string, std::size_t, std::vector< reference2_part > >;\n\n      reference2_part( const part_vector_t /*unused*/, const pegtl::position& p )\n         : position( p ),\n           data( std::vector< reference2_part >() )\n      {}\n\n      reference2_part( const std::size_t i, const pegtl::position& p )\n         : position( p ),\n           data( i )\n      {}\n\n      reference2_part( const std::string& n, const pegtl::position& p )\n         : position( p ),\n           data( n )\n      {}\n\n      [[nodiscard]] reference2_kind kind() const noexcept\n      {\n         return reference2_kind( data.index() );\n      }\n\n      [[nodiscard]] std::size_t get_index() const noexcept\n      {\n         const auto* s = std::get_if< std::size_t >( &data );\n         assert( s != nullptr );\n         return *s;\n      }\n\n      [[nodiscard]] const std::string& get_name() const noexcept\n      {\n         const auto* s = std::get_if< std::string >( &data );\n         assert( s != nullptr );\n         return *s;\n      }\n\n      [[nodiscard]] std::vector< reference2_part >& get_vector() noexcept\n      {\n         auto* s = std::get_if< std::vector< reference2_part > >( &data );\n         assert( s != nullptr );\n         return *s;\n      }\n\n      [[nodiscard]] const std::vector< reference2_part >& get_vector() const noexcept\n      {\n         const auto* s = std::get_if< std::vector< reference2_part > >( &data );\n         assert( s != nullptr );\n         return *s;\n      }\n\n      [[nodiscard]] std::string to_string() const\n      {\n         switch( kind() ) {\n            case reference2_kind::name:\n               return get_name();  // TODO: Unescape if not identifier?\n            case reference2_kind::index:\n               return std::to_string( get_index() );\n            case reference2_kind::vector:\n               return internal::to_string( get_vector() );\n         }\n         throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n      }\n\n      pegtl::position position;\n      data_t data;\n   };\n\n   [[nodiscard]] inline std::string to_string( const std::vector< reference2_part >& v )\n   {\n      std::string result;\n      result += '(';\n      auto it = v.begin();\n      result += it->to_string();\n      while( ++it != v.end() ) {\n         result += '.';\n         result += it->to_string();\n      }\n      result += ')';\n      return result;\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/repack_traits.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_REPACK_TRAITS_HPP\n#define TAO_CONFIG_INTERNAL_REPACK_TRAITS_HPP\n\n#include <utility>\n\n#include \"../key.hpp\"\n\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename V, typename = void >\n   inline constexpr bool has_set_key = false;\n\n   template< typename V >\n   inline constexpr bool has_set_key< V, decltype( std::declval< V >().public_base().set_key( std::declval< const config::key& >() ), void() ) > = true;\n\n   template< typename V, typename = void >\n   inline constexpr bool has_set_position = false;\n\n   template< typename V >\n   inline constexpr bool has_set_position< V, decltype( std::declval< V >().public_base().set_position( std::declval< const pegtl::position& >() ), void() ) > = true;\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/state.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_STATE_HPP\n#define TAO_CONFIG_INTERNAL_STATE_HPP\n\n#include <cstdint>\n\n#include \"key1.hpp\"\n#include \"object.hpp\"\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   struct state\n   {\n      state()\n         : root( pegtl::position( 1, 1, 1, \"(root)\" ) )\n      {}\n\n      state( state&& ) = delete;\n      state( const state& ) = delete;\n\n      ~state() = default;\n\n      void operator=( state&& ) = delete;\n      void operator=( const state& ) = delete;\n\n      key1 prefix;\n      key1 suffix;\n      key1 member;\n\n      object root;\n\n      bool include_is_optional;\n      std::uint64_t generation = 1;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/statistics.hpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_STATISTICS_HPP\n#define TAO_CONFIG_INTERNAL_STATISTICS_HPP\n\n#include <cstddef>\n#include <cstdlib>\n\n#include \"array.hpp\"\n#include \"concat.hpp\"\n#include \"entry.hpp\"\n#include \"object.hpp\"\n\nnamespace tao::config::internal\n{\n   struct statistics\n   {\n      statistics() noexcept = default;\n\n      explicit statistics( const entry& e )\n      {\n         count( e );\n      }\n\n      explicit statistics( const concat& c )\n      {\n         count( c );\n      }\n\n      explicit statistics( const array& a )\n      {\n         count( a );\n      }\n\n      void count( const entry& e )\n      {\n         switch( e.kind() ) {\n            case entry_kind::NULL_:\n               ++m_nulls;\n               return;\n            case entry_kind::BOOLEAN:\n            case entry_kind::STRING:\n            case entry_kind::BINARY:\n            case entry_kind::SIGNED:\n            case entry_kind::UNSIGNED:\n            case entry_kind::DOUBLE:\n               ++m_atoms;\n               return;\n            case entry_kind::ARRAY:\n               count( e.get_array() );\n               return;\n            case entry_kind::OBJECT:\n               count( e.get_object() );\n               return;\n            case entry_kind::ASTERISK:\n               ++m_asterisks;\n               count( e.get_asterisk() );\n               return;\n            case entry_kind::REFERENCE:\n               ++m_references;\n               return;\n         }\n         std::abort();  // LCOV_EXCL_LINE\n      }\n\n      void count( const array& a )\n      {\n         if( a.function.empty() ) {\n            ++m_arrays;\n         }\n         else {\n            ++m_functions;\n         }\n         for( const auto& c : a.array ) {\n            count( c );\n         }\n      }\n\n      void count( const object& o )\n      {\n         for( const auto& p : o.object ) {\n            count( p.second );\n         }\n         ++m_objects;\n      }\n\n      void count( const concat& c )\n      {\n         if( c.concat.size() > 1 ) {\n            ++m_additions;\n         }\n         for( const auto& e : c.concat ) {\n            count( e );\n         }\n      }\n\n      [[nodiscard]] std::size_t nulls() const noexcept\n      {\n         return m_nulls;\n      }\n\n      [[nodiscard]] std::size_t references() const noexcept\n      {\n         return m_references;\n      }\n\n      [[nodiscard]] bool is_primitive() const noexcept\n      {\n         return ( m_functions == 0 ) && ( m_additions == 0 ) && ( m_asterisks == 0 ) && ( m_references == 0 );\n      }\n\n   private:\n      std::size_t m_nulls = 0;\n      std::size_t m_atoms = 0;\n      std::size_t m_arrays = 0;\n      std::size_t m_objects = 0;\n      std::size_t m_functions = 0;\n      std::size_t m_additions = 0;\n      std::size_t m_asterisks = 0;\n      std::size_t m_references = 0;\n   };\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/string_utility.hpp",
    "content": "// Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_STRING_UTILITY_HPP\n#define TAO_CONFIG_INTERNAL_STRING_UTILITY_HPP\n\n#include <sstream>\n#include <string>\n#include <utility>\n\n#include \"json.hpp\"\n\nnamespace tao::config::internal\n{\n   struct strcat_stream\n   {\n      std::ostringstream oss;\n   };\n\n   template< typename T >\n   strcat_stream& operator<<=( strcat_stream& ss, const T& t )\n   {\n      ss.oss << t;\n      return ss;\n   }\n\n   inline strcat_stream& operator<<=( strcat_stream& ss, const json::type t )\n   {\n      ss.oss << json::to_string( t );\n      return ss;\n   }\n\n   template< typename... Ts >\n   [[nodiscard]] std::string strcat( const Ts&... ts )\n   {\n      strcat_stream ss;\n      (void)( ss <<= ... <<= ts );\n      return std::move( ss.oss ).str();\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/system_utility.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_SYSTEM_UTILITY_HPP\n#define TAO_CONFIG_INTERNAL_SYSTEM_UTILITY_HPP\n\n#include <stdio.h>\n\n#include <cstdlib>\n#include <memory>\n#include <optional>\n#include <stdexcept>\n#include <string>\n#include <utility>\n\n#include \"pegtl.hpp\"\n\nnamespace tao::config::internal\n{\n   // TODO: Use std::filesystem::path for filenames?\n\n   [[nodiscard]] inline std::string read_file_throws( const std::string& filename )\n   {\n      return pegtl::internal::read_file_stdio( filename ).read_string();\n   }\n\n   [[nodiscard]] inline std::optional< std::string > read_file_nothrow( const std::string& filename )\n   {\n      try {\n         return read_file_throws( filename );\n      }\n      catch( const std::system_error& ) {\n         return std::nullopt;\n      }\n   }\n\n   [[nodiscard]] inline std::optional< std::string > getenv_nothrow( const std::string& name )\n   {\n#if defined( _MSC_VER )\n      char buffer[ 256 ];\n      std::size_t s = 0;\n      if( ::getenv_s( &s, buffer, name.c_str() ) == 0 ) {\n         if( s > 0 ) {\n            return std::string( buffer );\n         }\n      }\n      // TODO: Check s and try with a larger buffer\n#else\n      if( const char* r = std::getenv( name.c_str() ) ) {\n         return std::string( r );\n      }\n#endif\n      return std::nullopt;\n   }\n\n   [[nodiscard]] inline std::string getenv_throws( const pegtl::position& pos, const std::string& name )\n   {\n      if( auto result = getenv_nothrow( name ) ) {\n         return std::move( *result );\n      }\n      throw pegtl::parse_error( \"environment variable '\" + name + \"' not found\", pos );\n   }\n\n#if !defined( _MSC_VER )\n   [[nodiscard]] inline std::string shell_popen_throws( const pegtl::position& pos, const std::string& script )\n   {\n      errno = 0;\n\n      std::unique_ptr< FILE, void ( * )( FILE* ) > file( ::popen( script.c_str(), \"r\" ), []( FILE* f ) { ::pclose( f ); } );\n\n      if( !file ) {\n         throw pegtl::parse_error( \"TODO: Better error message for shell function popen error.\", pos );\n         //         throw pegtl::parse_error( format( __FILE__, __LINE__, \"popen failed\", { { \"command\", script }, { \"errno\", errno } } ), pos );\n      }\n      std::string result;\n      char buffer[ 1000 ];\n\n      while( const auto temp = ::fread( buffer, 1, sizeof( buffer ), file.get() ) ) {\n         result.append( buffer, temp );\n      }\n      errno = 0;\n\n      if( ::pclose( file.release() ) != 0 ) {\n         throw pegtl::parse_error( \"TODO: Better error message for shell function pclose error.\", pos );  // LCOV_EXCL_LINE\n      }\n      return result;\n   }\n#endif\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/internal/to_stream.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_TO_STREAM_HPP\n#define TAO_CONFIG_INTERNAL_TO_STREAM_HPP\n\n#include <cstddef>\n#include <ostream>\n\n#include \"debug_traits.hpp\"\n#include \"json.hpp\"\n\nnamespace tao::config::internal\n{\n   template< typename T >\n   void to_stream( std::ostream& os, const T& t )\n   {\n      json::jaxn::events::to_stream consumer( os );\n      json::events::produce< debug_traits >( consumer, t );\n   }\n\n   template< typename T >\n   void to_stream( std::ostream& os, const T& t, const std::size_t indent )\n   {\n      json::jaxn::events::to_pretty_stream consumer( os, indent );\n      json::events::produce< debug_traits >( consumer, t );\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "include/tao/config/key.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_INTERNAL_KEY_HPP\n#define TAO_CONFIG_INTERNAL_KEY_HPP\n\n#include <sstream>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"internal/key_action.hpp\"\n#include \"internal/key_grammar.hpp\"\n#include \"internal/pegtl.hpp\"\n\n#include \"key_part.hpp\"\n\nnamespace tao::config\n{\n   struct key\n      : std::vector< key_part >\n   {\n      key() = default;\n\n      key( key&& ) = default;\n      key& operator=( key&& ) = default;\n\n      ~key() = default;\n\n      key( const key& ) = default;\n      key& operator=( const key& ) = default;\n\n      explicit key( const std::string& s )\n      {\n         assign( s );\n      }\n\n      key( const std::initializer_list< key_part >& l )\n         : std::vector< key_part >( l )\n      {}\n\n      key( const std::vector< key_part >::const_iterator& begin, const std::vector< key_part >::const_iterator& end )\n         : std::vector< key_part >( begin, end )\n      {}\n\n      key& operator=( const std::string& s )\n      {\n         clear();\n         assign( s );\n         return *this;\n      }\n\n      key& operator=( const std::initializer_list< key_part >& l )\n      {\n         vector() = l;\n         return *this;\n      }\n\n      [[nodiscard]] std::vector< key_part >& vector() noexcept\n      {\n         return static_cast< std::vector< key_part >& >( *this );\n      }\n\n      [[nodiscard]] const std::vector< key_part >& vector() const noexcept\n      {\n         return static_cast< const std::vector< key_part >& >( *this );\n      }\n\n      void assign( const std::string& s )\n      {\n         using grammar = pegtl::must< internal::rules::key_rule, pegtl::eof >;\n         pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( s, __FUNCTION__ );\n         pegtl::parse< grammar, internal::key_action >( in, vector() );\n      }\n   };\n\n   inline key pop_front( const key& p )\n   {\n      assert( !p.empty() );\n      return key( p.begin() + 1, p.end() );\n   }\n\n   inline key pop_back( const key& p )\n   {\n      assert( !p.empty() );\n      return key( p.begin(), p.end() - 1 );\n   }\n\n   inline key& operator+=( key& l, const key& r )\n   {\n      l.insert( l.end(), r.begin(), r.end() );\n      return l;\n   }\n\n   inline key& operator+=( key& l, const key_part& p )\n   {\n      l.emplace_back( p );\n      return l;\n   }\n\n   inline key& operator+=( key& l, const std::size_t i )\n   {\n      l.emplace_back( i );\n      return l;\n   }\n\n   inline key& operator+=( key& l, std::string&& n )\n   {\n      l.emplace_back( std::move( n ) );\n      return l;\n   }\n\n   inline key& operator+=( key& l, const std::string& n )\n   {\n      l.emplace_back( n );\n      return l;\n   }\n\n   [[nodiscard]] inline key operator+( const key& l, const key& r )\n   {\n      key t( l );\n      t += r;\n      return t;\n   }\n\n   [[nodiscard]] inline key operator+( const key& l, const key_part& r )\n   {\n      key t( l );\n      t += r;\n      return t;\n   }\n\n   [[nodiscard]] inline key operator+( const key& l, const std::size_t i )\n   {\n      key t( l );\n      t += i;\n      return t;\n   }\n\n   [[nodiscard]] inline key operator+( const key& l, std::string&& n )\n   {\n      key t( l );\n      t += std::move( n );\n      return t;\n   }\n\n   [[nodiscard]] inline key operator+( const key& l, const std::string& n )\n   {\n      key t( l );\n      t += n;\n      return t;\n   }\n\n   inline void to_stream( std::ostream& o, const key& p )\n   {\n      if( !p.empty() ) {\n         to_stream( o, p[ 0 ] );\n\n         for( std::size_t i = 1; i < p.size(); ++i ) {\n            o << '.';\n            to_stream( o, p[ i ] );\n         }\n      }\n   }\n\n   [[nodiscard]] inline std::string to_string( const key& p )\n   {\n      std::ostringstream oss;\n      to_stream( oss, p );\n      return std::move( oss ).str();\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/key_kind.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_KEY_KIND_HPP\n#define TAO_CONFIG_KEY_KIND_HPP\n\nnamespace tao::config\n{\n   enum class key_kind : char\n   {\n      name = 0,\n      index = 1\n   };\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/key_part.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_KEY_PART_HPP\n#define TAO_CONFIG_KEY_PART_HPP\n\n#include <ostream>\n#include <stdexcept>\n#include <string>\n#include <utility>\n#include <variant>\n\n#include \"internal/constants.hpp\"\n#include \"internal/json.hpp\"\n#include \"internal/key_grammar.hpp\"\n#include \"internal/pegtl.hpp\"\n\n#include \"key_kind.hpp\"\n\nnamespace tao::config\n{\n   struct key_part\n   {\n      using data_t = std::variant< std::string, std::size_t >;\n\n      explicit key_part( const std::size_t i ) noexcept\n         : data( i )\n      {}\n\n      explicit key_part( std::string&& n ) noexcept\n         : data( std::move( n ) )\n      {}\n\n      explicit key_part( const std::string& n )\n         : data( n )\n      {}\n\n      [[nodiscard]] key_kind kind() const noexcept\n      {\n         return key_kind( data.index() );\n      }\n\n      [[nodiscard]] std::size_t get_index() const noexcept\n      {\n         return std::get< std::size_t >( data );\n      }\n\n      [[nodiscard]] const std::string& get_name() const noexcept\n      {\n         return std::get< std::string >( data );\n      }\n\n      data_t data;\n   };\n\n   [[nodiscard]] inline bool operator<( const key_part& l, const key_part& r ) noexcept\n   {\n      return l.data < r.data;\n   }\n\n   [[nodiscard]] inline bool operator==( const key_part& l, const key_part& r ) noexcept\n   {\n      return l.data == r.data;\n   }\n\n   [[nodiscard]] inline bool is_identifier( const std::string& n )\n   {\n      using grammar = pegtl::seq< internal::rules::ident, pegtl::eof >;\n      pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( n, __FUNCTION__ );\n      return pegtl::parse< grammar >( in );\n   }\n\n   [[nodiscard]] inline std::string name_to_string( const std::string& n )\n   {\n      return is_identifier( n ) ? n : ( '\"' + json::internal::escape( n ) + '\"' );\n   }\n\n   [[nodiscard]] inline std::string to_string( const key_part& t )\n   {\n      switch( t.kind() ) {\n         case key_kind::name:\n            return name_to_string( t.get_name() );\n         case key_kind::index:\n            return std::to_string( t.get_index() );\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n   inline void name_to_stream( std::ostream& o, const std::string& n )\n   {\n      if( is_identifier( n ) ) {\n         o << n;\n      }\n      else {\n         o << '\"' << json::internal::escape( n ) << '\"';\n      }\n   }\n\n   inline void to_stream( std::ostream& o, const key_part& t )\n   {\n      switch( t.kind() ) {\n         case key_kind::name:\n            name_to_stream( o, t.get_name() );\n            return;\n         case key_kind::index:\n            o << t.get_index();\n            return;\n      }\n      throw std::logic_error( \"code should be unreachable\" );  // LCOV_EXCL_LINE\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/parser.hpp",
    "content": "// Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_PARSER_HPP\n#define TAO_CONFIG_PARSER_HPP\n\n#include \"internal/config_parser.hpp\"\n#include \"internal/function_wrapper.hpp\"\n\nnamespace tao::config\n{\n   class parser\n   {\n   public:\n      parser() = default;\n\n      void parse( const std::filesystem::path& path )\n      {\n         m_parser.parse( path );\n      }\n\n      void parse( const std::string_view data, const std::string& source )\n      {\n         m_parser.parse( data, source );\n      }\n\n      template< typename F >\n      void set_inner_extension( const std::string& name, F& f )\n      {\n         m_parser.fm[ name ] = internal::wrap( f );\n      }\n\n      template< template< typename... > class Traits >\n      [[nodiscard]] json::basic_value< Traits > result()\n      {\n         return m_parser.finish< Traits >();\n      }\n\n   protected:\n      internal::config_parser m_parser;\n   };\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/to_stream.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_TO_STREAM_HPP\n#define TAO_CONFIG_TO_STREAM_HPP\n\n#include <ostream>\n\n#include <tao/json/jaxn/events/to_pretty_stream.hpp>\n#include <tao/json/jaxn/events/to_stream.hpp>\n\n#include \"internal/events_from_value.hpp\"\n\n#include \"value.hpp\"\n\nnamespace tao::config\n{\n   inline void to_stream( std::ostream& os, const value& v )\n   {\n      json::jaxn::events::to_stream consumer( os );\n      internal::events_from_value( consumer, v );\n   }\n\n   inline void to_stream( std::ostream& os, const value& v, const std::size_t indent )\n   {\n      json::jaxn::events::to_pretty_stream consumer( os, indent );\n      internal::events_from_value( consumer, v );\n   }\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/traits.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_TRAITS_HPP\n#define TAO_CONFIG_TRAITS_HPP\n\n#include <tao/json.hpp>\n\n#include \"annotation.hpp\"\n\nnamespace tao::config\n{\n   template< typename T >\n   struct traits\n      : json::traits< T >\n   {};\n\n   template<>\n   struct traits< void >\n      : json::traits< void >\n   {\n      static constexpr const bool enable_implicit_constructor = false;\n\n      template< typename Value >\n      using public_base = annotation;\n   };\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config/value.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_VALUE_HPP\n#define TAO_CONFIG_VALUE_HPP\n\n#include <tao/json.hpp>\n\n#include \"traits.hpp\"\n\nnamespace tao::config\n{\n   using value = json::basic_value< traits >;\n\n}  // namespace tao::config\n\n#endif\n"
  },
  {
    "path": "include/tao/config.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_HPP\n#define TAO_CONFIG_HPP\n\n#include \"config/key.hpp\"\n#include \"config/value.hpp\"\n\n#include \"config/from_file.hpp\"\n#include \"config/from_files.hpp\"\n#include \"config/from_input.hpp\"\n#include \"config/from_string.hpp\"\n#include \"config/to_stream.hpp\"\n\n#include \"config/access.hpp\"\n#include \"config/assign.hpp\"\n\n#include \"config/parser.hpp\"\n\n#endif\n"
  },
  {
    "path": "src/example/config/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.8...3.19)\n\nset(examplesources\n  dump_all_phases.cpp\n  dump_only_data.cpp\n  dump_phase_one.cpp\n  dump_phase_three.cpp\n  dump_phase_two.cpp\n  dump_with_meta.cpp\n)\n\n# file(GLOB ...) is used to validate the above list of example_sources\nfile(GLOB glob_example_sources RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.cpp)\n\nforeach(examplesourcefile ${examplesources})\n  if(${examplesourcefile} IN_LIST glob_example_sources)\n    list(REMOVE_ITEM glob_example_sources ${examplesourcefile})\n  else()\n    message(SEND_ERROR \"File ${examplesourcefile} is missing from src/example/config\")\n  endif()\n  get_filename_component(exename ${examplesourcefile} NAME_WE)\n  set(exename \"tao-config-example-${exename}\")\n  add_executable(${exename} ${examplesourcefile})\n  target_link_libraries(${exename} PRIVATE taocpp::config)\n  set_target_properties(${exename} PROPERTIES\n    CXX_STANDARD 11\n    CXX_STANDARD_REQUIRED ON\n    CXX_EXTENSIONS OFF\n  )\n  if(MSVC)\n    target_compile_options(${exename} PRIVATE /W4 /WX /utf-8 /bigobj)\n  else()\n    target_compile_options(${exename} PRIVATE -pedantic -Wall -Wextra -Werror)\n  endif()\nendforeach()\n\nif(glob_example_sources)\n  foreach(ignored_source_file ${glob_example_sources})\n    message(SEND_ERROR \"File ${ignored_source_file} in src/example/config is ignored\")\n  endforeach()\nendif()\n"
  },
  {
    "path": "src/example/config/dump_all_phases.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <iostream>\n#include <stdexcept>\n#include <string>\n\n#include <tao/config.hpp>\n\n#include <tao/config/internal/to_stream.hpp>\n\nint main( int argc, char** argv )\n{\n   tao::config::internal::config_parser cfg;\n\n   try {\n      for( int i = 1; i < argc; ++i ) {\n         const std::filesystem::path file( argv[ i ] );\n         std::cout << \"PARSE \" << file << std::endl;\n         cfg.parse( file );\n         tao::config::internal::to_stream( std::cout, cfg.st.root, 3 );\n         std::cout << std::endl;\n      }\n      std::cout << \"PHASE 2\" << std::endl;\n      tao::config::internal::phase2_everything( cfg.st, cfg.fm );\n      tao::config::internal::to_stream( std::cout, cfg.st.root, 3 );\n      std::cout << std::endl;\n      std::cout << \"PHASE 3\" << std::endl;\n      tao::config::internal::phase3_remove( cfg.st.root );\n      tao::config::internal::to_stream( std::cout, cfg.st.root, 3 );\n      std::cout << std::endl;\n      std::cout << \"RESULT\" << std::endl;\n      const tao::config::value j = tao::config::internal::phase5_repack< tao::config::traits >( cfg.st.root );\n      tao::config::to_stream( std::cout, j, 3 );\n      std::cout << std::endl;\n   }\n   catch( const std::exception& e ) {\n      std::cerr << \"ERROR \" << e.what() << std::endl;\n      return 1;\n   }\n   catch( const std::string& e ) {\n      std::cerr << \"STRING \" << e << std::endl;\n      return 1;\n   }\n   return 0;\n}\n"
  },
  {
    "path": "src/example/config/dump_only_data.cpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <filesystem>\n#include <iostream>\n#include <vector>\n\n#include <tao/config.hpp>\n\n#include <tao/json/jaxn/events/to_stream.hpp>\n\n#include \"try_catch.hpp\"\n\nint main( int argc, char** argv )\n{\n   tao::config::internal::try_catch( [ = ]() {\n      const tao::config::value v = tao::config::from_files( std::vector< std::filesystem::path >( argv + 1, argv + argc ) );\n      tao::json::jaxn::to_stream( std::cout, v, 3 );\n      std::cout << std::endl;\n   } );\n   return 0;\n}\n"
  },
  {
    "path": "src/example/config/dump_phase_one.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <iostream>\n#include <stdexcept>\n#include <string>\n\n#include <tao/config.hpp>\n\n#include <tao/config/internal/to_stream.hpp>\n\nint main( int argc, char** argv )\n{\n   tao::config::internal::config_parser cfg;\n\n   try {\n      for( int i = 1; i < argc; ++i ) {\n         const std::filesystem::path file( argv[ i ] );\n         std::cout << \"PARSE \" << file << std::endl;\n         cfg.parse( file );\n         tao::config::internal::to_stream( std::cout, cfg.st.root, 3 );\n         std::cout << std::endl;\n      }\n   }\n   catch( const std::exception& e ) {\n      std::cerr << \"ERROR \" << e.what() << std::endl;\n      return 1;\n   }\n   catch( const std::string& e ) {\n      std::cerr << \"STRING \" << e << std::endl;\n      return 1;\n   }\n   return 0;\n}\n"
  },
  {
    "path": "src/example/config/dump_phase_three.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <iostream>\n#include <stdexcept>\n#include <string>\n\n#include <tao/config.hpp>\n\n#include <tao/config/internal/to_stream.hpp>\n\nint main( int argc, char** argv )\n{\n   tao::config::internal::config_parser cfg;\n\n   try {\n      for( int i = 1; i < argc; ++i ) {\n         const std::filesystem::path file( argv[ i ] );\n         std::cout << \"PARSE \" << file << std::endl;\n         cfg.parse( file );\n      }\n      std::cout << \"PHASE 2\" << std::endl;\n      tao::config::internal::phase2_everything( cfg.st, cfg.fm );\n      std::cout << \"PHASE 3\" << std::endl;\n      tao::config::internal::phase3_remove( cfg.st.root );\n      tao::config::internal::to_stream( std::cout, cfg.st.root, 3 );\n      std::cout << std::endl;\n   }\n   catch( const std::exception& e ) {\n      std::cerr << \"ERROR \" << e.what() << std::endl;\n      return 1;\n   }\n   catch( const std::string& e ) {\n      std::cerr << \"STRING \" << e << std::endl;\n      return 1;\n   }\n   return 0;\n}\n"
  },
  {
    "path": "src/example/config/dump_phase_two.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <iostream>\n#include <stdexcept>\n#include <string>\n\n#include <tao/config.hpp>\n\n#include <tao/config/internal/to_stream.hpp>\n\nint main( int argc, char** argv )\n{\n   tao::config::internal::config_parser cfg;\n\n   try {\n      for( int i = 1; i < argc; ++i ) {\n         const std::filesystem::path file( argv[ i ] );\n         std::cout << \"PARSE \" << file << std::endl;\n         cfg.parse( file );\n      }\n      std::cout << \"PHASE 2\" << std::endl;\n      tao::config::internal::phase2_everything( cfg.st, cfg.fm );\n      tao::config::internal::to_stream( std::cout, cfg.st.root, 3 );\n      std::cout << std::endl;\n   }\n   catch( const std::exception& e ) {\n      std::cerr << \"ERROR \" << e.what() << std::endl;\n      return 1;\n   }\n   catch( const std::string& e ) {\n      std::cerr << \"STRING \" << e << std::endl;\n      return 1;\n   }\n   return 0;\n}\n"
  },
  {
    "path": "src/example/config/dump_with_meta.cpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <filesystem>\n#include <iostream>\n#include <vector>\n\n#include <tao/config.hpp>\n\n#include \"try_catch.hpp\"\n\nint main( int argc, char** argv )\n{\n   tao::config::internal::try_catch( [ = ]() {\n      const tao::config::value v = tao::config::from_files( std::vector< std::filesystem::path >( argv + 1, argv + argc ) );\n      tao::config::to_stream( std::cout, v, 3 );\n      std::cout << std::endl;\n   } );\n   return 0;\n}\n"
  },
  {
    "path": "src/example/config/try_catch.hpp",
    "content": "// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_EXAMPLE_CONFIG_TRY_CATCH_HPP\n#define TAO_EXAMPLE_CONFIG_TRY_CATCH_HPP\n\n#include <iostream>\n#include <stdexcept>\n#include <string>\n\n#include <tao/pegtl/contrib/nested_exceptions.hpp>\n\n#include <tao/config/internal/pegtl.hpp>\n\nnamespace tao::config::internal\n{\n   template< typename F >\n   void try_catch( const F& f )\n   {\n      try {\n         f();\n      }\n      catch( const pegtl::parse_error& ) {\n         std::cerr << \"*** config parse error ***\" << std::endl;\n         for( const auto& e : pegtl::nested::flatten() ) {\n            std::cerr << e.message() << \": \" << e.position_string() << std::endl;\n         }\n      }\n      catch( const std::exception& e ) {\n         std::cerr << \"*** config error ***\" << std::endl;\n         std::cerr << e.what() << std::endl;\n      }\n      catch( const std::string& s ) {\n         std::cerr << \"*** config error ***\" << std::endl;\n         std::cerr << s << std::endl;\n      }\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "src/test/config/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.8...3.19)\n\nset(testsources\n  access.cpp\n  assign.cpp\n  custom.cpp\n  debug_traits.cpp\n  enumerations.cpp\n  failure.cpp\n  independence.cpp\n  key.cpp\n  key_part.cpp\n  multi_line_string_position.cpp\n  parse_key1.cpp\n  parse_key.cpp\n  parse_reference2.cpp\n  success.cpp\n  to_stream.cpp\n  value.cpp\n)\n\n# file(GLOB ...) is used to validate the above list of test_sources\nfile(GLOB glob_test_sources RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.cpp)\n\nforeach(testsourcefile ${testsources})\n  if(${testsourcefile} IN_LIST glob_test_sources)\n    list(REMOVE_ITEM glob_test_sources ${testsourcefile})\n  else()\n    message(SEND_ERROR \"File ${testsourcefile} is missing from src/test/config\")\n  endif()\n  get_filename_component(exename ${testsourcefile} NAME_WE)\n  set(exename \"tao-config-test-${exename}\")\n  add_executable(${exename} ${testsourcefile})\n  target_link_libraries(${exename} PRIVATE taocpp::config)\n  set_target_properties(${exename} PROPERTIES\n    CXX_STANDARD 17\n    CXX_STANDARD_REQUIRED ON\n    CXX_EXTENSIONS OFF\n  )\n  if(MSVC)\n    target_compile_options(${exename} PRIVATE /W4 /WX /utf-8 /bigobj)\n  else()\n    target_compile_options(${exename} PRIVATE -pedantic -Wall -Wextra -Werror)\n  endif()\n  add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${exename})\nendforeach()\n\nif(glob_test_sources)\n  foreach(ignored_source_file ${glob_test_sources})\n    message(SEND_ERROR \"File ${ignored_source_file} in src/test/config is ignored\")\n  endforeach()\nendif()\n"
  },
  {
    "path": "src/test/config/access.cpp",
    "content": "// Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      const auto v = from_string( \"a = 1, b = 2, c = { d = { e = [ 6 7 ] } }\", __FUNCTION__ );\n\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"a\" ) ) == value( 1 ) );\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"b\" ) ) == value( 2 ) );\n\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"a\" ) ).key == key( \"a\" ) );\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"b\" ) ).key == key( \"b\" ) );\n\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"c.d.e.0\" ) ) == value( 6 ) );\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"c.d.e.1\" ) ) == value( 7 ) );\n\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"c.d.e.0\" ) ).key == key( \"c.d.e.0\" ) );\n      TAO_CONFIG_TEST_ASSERT( access( v, key( \"c.d.e.1\" ) ).key == key( \"c.d.e.1\" ) );\n\n      TAO_CONFIG_TEST_THROWS( (void)access( v, key( \"0\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)access( v, key( \"a.0\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)access( v, key( \"r\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)access( v, key( \"c.d.e.f\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)access( v, key( \"c.d.e.2\" ) ) );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/assign.cpp",
    "content": "// Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      auto v = from_string( \"a = 1, b = 2, c = { d = { e = [ 6 7 ] } }\", __FUNCTION__ );\n\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"a\" ) ) == value( 1 ) );\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"b\" ) ) == value( 2 ) );\n\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"a\" ) ).key == key( \"a\" ) );\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"b\" ) ).key == key( \"b\" ) );\n\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"c.d.e.0\" ) ) == value( 6 ) );\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"c.d.e.1\" ) ) == value( 7 ) );\n\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"c.d.e.0\" ) ).key == key( \"c.d.e.0\" ) );\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"c.d.e.1\" ) ).key == key( \"c.d.e.1\" ) );\n\n      TAO_CONFIG_TEST_THROWS( (void)assign( v, key( \"0\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)assign( v, key( \"c.d.e.f\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)assign( v, key( \"c.d.e.2\" ) ) );\n      TAO_CONFIG_TEST_THROWS( (void)assign( v, key( \"a.0\" ) ) );\n\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"r\" ) ) == value( json::empty_object ) );\n      TAO_CONFIG_TEST_ASSERT( assign( v, key( \"r.s.t\" ) ) == value( json::empty_object ) );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/custom.cpp",
    "content": "// Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n#include <tao/config/contrib/rot13.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      parser p;\n      p.set_inner_extension( \"rot13\", rot13 );\n      p.parse( \"a = (rot13 \\\"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@[]{}`\\\")\", __FUNCTION__ );\n      const auto j = p.result< json::traits >();\n\n      TAO_CONFIG_TEST_ASSERT( j.at( \"a\" ) == \"0123456789nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM@[]{}`\" );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/debug_traits.cpp",
    "content": "// Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <sstream>\n#include <string>\n#include <string_view>\n\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n#include <tao/config/internal/to_stream.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      internal::config_parser cp;\n      cp.parse( std::filesystem::path( \"tests/debug_traits.config\" ) );\n      json::events::to_value consumer;\n      json::events::produce< internal::debug_traits >( consumer, cp.st.root );\n      const json::value config = std::move( consumer.value );\n      const json::value output = json::jaxn::from_file( std::filesystem::path( \"tests/debug_traits.output\" ) );\n      TAO_CONFIG_TEST_ASSERT( output == config );\n      {\n         std::ostringstream os1;\n         internal::to_stream( os1, cp.st.root );\n         TAO_CONFIG_TEST_ASSERT( json::jaxn::from_string( os1.str() ) == output );\n      }\n      std::ostringstream os2;\n      internal::to_stream( os2, cp.st.root, 3 );\n      TAO_CONFIG_TEST_ASSERT( json::jaxn::from_string( os2.str() ) == output );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/enumerations.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <type_traits>\n\n#include \"test.hpp\"\n\n#include <tao/config/internal/array.hpp>\n#include <tao/config/internal/entry.hpp>\n#include <tao/config/internal/forward.hpp>\n#include <tao/config/internal/json.hpp>\n#include <tao/config/internal/key1.hpp>\n#include <tao/config/internal/object.hpp>\n#include <tao/config/internal/reference2.hpp>\n\n#include <tao/config/key.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( key_kind::name ), key_part::data_t >, std::string > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( key_kind::index ), key_part::data_t >, std::size_t > );\n\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::entry_kind::ARRAY ), internal::entry::data_t >, internal::array > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::entry_kind::OBJECT ), internal::entry::data_t >, internal::object > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::entry_kind::REFERENCE ), internal::entry::data_t >, internal::reference2 > );\n\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::key1_kind::name ), internal::key1_part::data_t >, std::string > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::key1_kind::index ), internal::key1_part::data_t >, std::size_t > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::key1_kind::asterisk ), internal::key1_part::data_t >, internal::part_asterisk_t > );\n\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::reference2_kind::name ), internal::reference2_part::data_t >, std::string > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::reference2_kind::index ), internal::reference2_part::data_t >, std::size_t > );\n      static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::reference2_kind::vector ), internal::reference2_part::data_t >, std::vector< internal::reference2_part > > );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/failure.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <algorithm>\n#include <filesystem>\n#include <iostream>\n\n#include <tao/config.hpp>\n\nconst char* ansi_reset = \"\\033[0m\";\nconst char* ansi_message = \"\\033[1;31m\";\nconst char* ansi_source = \"\\033[36m\";\nconst char* ansi_text = \"\\033[33m\";\n\nnamespace tao\n{\n   unsigned failed = 0;\n\n   template< template< typename... > class Traits >\n   void unit_test( const std::filesystem::path& path )\n   {\n      try {\n         // For a failure testcase to succeed the next line must throw an error.\n         const auto cc = config::basic_from_file< Traits >( path );\n         // LCOV_EXCL_START\n         const auto ccs = json::jaxn::to_string( cc );\n         ++failed;\n         std::cerr << std::endl\n                   << \"Testcase '\" << path << \"' failed error test!\" << std::endl;\n         std::cerr << \"<<< Config parsed as config <<<\" << std::endl;\n         std::cerr << ccs << std::endl;\n         std::cerr << \">>> Config parsed as config >>>\" << std::endl;\n         // LCOV_EXCL_STOP\n      }\n      catch( const pegtl::parse_error_base& e ) {\n         std::cout << ansi_text << \"pegtl::parse_error: \" << ansi_message << e.message() << \": \" << ansi_source << e.position_string() << ansi_reset << std::endl;\n      }\n   }\n\n}  // namespace tao\n\nint main()\n{\n   unsigned count = 0;\n\n   for( const auto& entry : std::filesystem::directory_iterator( \"tests\" ) ) {\n      if( const auto& path = entry.path(); path.extension() == \".failure\" ) {\n         tao::unit_test< tao::json::traits >( path );\n         tao::unit_test< tao::config::traits >( path );\n         ++count;\n      }\n   }\n   if( tao::failed == 0 ) {\n      std::cerr << \"All \" << count << \" failure testcases passed.\" << std::endl;\n   }\n   return std::min( int( tao::failed ), 127 );\n}\n"
  },
  {
    "path": "src/test/config/independence.cpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <algorithm>\n#include <filesystem>\n#include <iostream>\n#include <set>\n#include <stdexcept>\n#include <vector>\n\n#include \"setenv.hpp\"\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n\nnamespace tao::config\n{\n   std::size_t iteration = 0;\n\n   [[nodiscard]] std::size_t p2fun( internal::state& st, const internal::function_map& fm )\n   {\n      return internal::phase2_functions( st, fm );\n   }\n\n   [[nodiscard]] std::size_t p2add( internal::state& st, const internal::function_map& /*unused*/ )\n   {\n      return internal::phase2_additions( st.root );\n   }\n\n   [[nodiscard]] std::size_t p2ref( internal::state& st, const internal::function_map& /*unused*/ )\n   {\n      return internal::phase2_references( st.root );\n   }\n\n   [[nodiscard]] std::size_t p2ast( internal::state& st, const internal::function_map& /*unused*/ )\n   {\n      return internal::phase2_asterisks( st.root );\n   }\n\n   using func_t = std::size_t ( * )( internal::state&, const internal::function_map& );\n\n   std::set< func_t > p2funcs = { p2fun, p2add, p2ref, p2ast };\n\n   void unit_test( const std::filesystem::path& path )\n   {\n      try {\n         std::filesystem::path jaxn = path;\n         jaxn.replace_extension( \".jaxn\" );\n         const auto cj = from_file( jaxn );\n         const auto cjs = json::jaxn::to_string( cj );\n\n         std::vector< func_t > v( p2funcs.begin(), p2funcs.end() );\n\n         do {\n            internal::config_parser p;\n            p.parse( path );\n\n            while( v[ 0 ]( p.st, p.fm ) | v[ 1 ]( p.st, p.fm ) | v[ 2 ]( p.st, p.fm ) | v[ 3 ]( p.st, p.fm ) ) {\n            }\n\n            internal::phase3_remove( p.st.root );\n            const auto cc = internal::phase5_repack< traits >( p.st.root );\n            const auto ccs = json::jaxn::to_string( cc );\n\n            if( ccs != cjs ) {\n               // LCOV_EXCL_START\n               ++failed;\n               std::cerr << std::endl\n                         << \"Testcase '\" << path << \"' failed identity test in iteration \" << iteration << std::endl;\n               std::cerr << \"<<< Config parsed as config <<<\" << std::endl;\n               std::cerr << ccs << std::endl;\n               std::cerr << \">>> Config parsed as config >>>\" << std::endl;\n               std::cerr << \"<<< Reference data parsed as config <<<\" << std::endl;\n               std::cerr << cjs << std::endl;\n               std::cerr << \">>> Reference data parsed as config >>>\" << std::endl;\n               // LCOV_EXCL_STOP\n            }\n            ++iteration;\n         } while( std::next_permutation( v.begin(), v.end() ) );\n      }\n      // LCOV_EXCL_START\n      catch( const std::exception& e ) {\n         std::cerr << \"Testcase '\" << path << \"' failed with exception '\" << e.what() << \"' in iteration \" << iteration << std::endl;\n         ++failed;\n      }\n      // LCOV_EXCL_STOP\n   }\n\n}  // namespace tao::config\n\nint main()\n{\n   for( const auto& entry : std::filesystem::directory_iterator( \"tests\" ) ) {\n      if( const auto& path = entry.path(); path.extension() == \".success\" ) {\n#if defined( _MSC_VER )\n         if( entry.path().stem() == \"shell\" ) {\n            continue;\n         }\n#endif\n         tao::config::internal::setenv_throws( \"TAO_CONFIG\", \"env_value\" );\n         tao::config::unit_test( path );\n      }\n   }\n   if( tao::config::failed == 0 ) {\n      std::cerr << \"All \" << tao::config::iteration << \" order independence testcases passed.\" << std::endl;\n   }\n   return std::min( int( tao::config::failed ), 127 );\n}\n"
  },
  {
    "path": "src/test/config/key.cpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <sstream>\n#include <string>\n\n#include \"test.hpp\"\n\n#include <tao/config/key.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      const std::string s0 = \"foo.bar.42.\\\" \\\"\";\n      const std::vector< key_part > kpv = { key_part( \"foo\" ), key_part( \"bar\" ), key_part( 42 ), key_part( \" \" ) };\n      const key k1( kpv.begin(), kpv.end() );\n      const key k2( \"foo.bar.42.' '\" );\n      const key k3 = { key_part( \"foo\" ), key_part( \"bar\" ), key_part( 42 ), key_part( \" \" ) };\n      key k4 = k3;\n      TAO_CONFIG_TEST_ASSERT( k1.size() == 4 );\n      TAO_CONFIG_TEST_ASSERT( k1 == k2 );\n      TAO_CONFIG_TEST_ASSERT( k1 == k3 );\n      TAO_CONFIG_TEST_ASSERT( k1.vector() == k2.vector() );\n      TAO_CONFIG_TEST_ASSERT( k1.vector() == k4.vector() );\n      const auto k5 = pop_front( k1 );\n      const auto k6 = pop_back( k1 );\n      TAO_CONFIG_TEST_ASSERT( k5.size() == 3 );\n      TAO_CONFIG_TEST_ASSERT( k6.size() == 3 );\n      TAO_CONFIG_TEST_ASSERT( k5 == key( \"bar.42.' '\" ) );\n      TAO_CONFIG_TEST_ASSERT( k6 == key( \"foo.bar.42\" ) );\n      const std::string s1 = to_string( k1 );\n      TAO_CONFIG_TEST_ASSERT( s1 == s0 );\n      std::ostringstream oss;\n      to_stream( oss, k1 );\n      TAO_CONFIG_TEST_ASSERT( oss.str() == s0 );\n      k4 = pop_back( k1 );\n      TAO_CONFIG_TEST_ASSERT( k4 + \" \" == k1 );\n      TAO_CONFIG_TEST_ASSERT( k4 + key_part( \" \" ) == k1 );\n      TAO_CONFIG_TEST_ASSERT( k4 + key( \"\\\" \\\"\" ) == k1 );\n      TAO_CONFIG_TEST_ASSERT( k1 + 123 == key( s0 + \".123\" ) );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/key_part.cpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <sstream>\n#include <string>\n\n#include \"test.hpp\"\n\n#include <tao/config/key_part.hpp>\n\nnamespace tao::config\n{\n   void test_name1()\n   {\n      const std::string str = \"foo\";\n      const key_part p( str );\n      TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::name );\n      TAO_CONFIG_TEST_ASSERT( p.get_name() == str );\n      TAO_CONFIG_TEST_ASSERT( to_string( p ) == str );\n      std::ostringstream oss;\n      to_stream( oss, p );\n      TAO_CONFIG_TEST_ASSERT( oss.str() == str );\n   }\n\n   void test_name2()\n   {\n      const std::string str = \"+- \";\n      const key_part p( str );\n      TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::name );\n      TAO_CONFIG_TEST_ASSERT( p.get_name() == str );\n      TAO_CONFIG_TEST_ASSERT( to_string( p ) == '\"' + str + '\"' );\n      std::ostringstream oss;\n      to_stream( oss, p );\n      TAO_CONFIG_TEST_ASSERT( oss.str() == '\"' + str + '\"' );\n   }\n\n   void test_index()\n   {\n      const std::size_t ind = 42;\n      const key_part p( ind );\n      TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::index );\n      TAO_CONFIG_TEST_ASSERT( p.get_index() == ind );\n      TAO_CONFIG_TEST_ASSERT( to_string( p ) == \"42\" );\n      std::ostringstream oss;\n      to_stream( oss, p );\n      TAO_CONFIG_TEST_ASSERT( oss.str() == \"42\" );\n   }\n\n   void unit_test()\n   {\n      test_name1();\n      test_name2();\n      test_index();\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/main.hpp",
    "content": "// Copyright (c) 2014-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_SRC_TEST_CONFIG_MAIN_HPP\n#define TAO_CONFIG_SRC_TEST_CONFIG_MAIN_HPP\n\n#include <cstdlib>\n#include <iostream>\n\nint main( int /*unused*/, char** argv )\n{\n   tao::config::unit_test();\n\n   if( tao::config::failed != 0 ) {\n      std::cerr << \"config: unit test \" << argv[ 0 ] << \" failed \" << tao::config::failed << std::endl;  // LCOV_EXCL_LINE\n   }\n   return ( tao::config::failed == 0 ) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n\n#endif\n"
  },
  {
    "path": "src/test/config/multi_line_string_position.cpp",
    "content": "// Copyright (c) 2023-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <cassert>\n\n#include <tao/config.hpp>\n\nnamespace tao\n{\n   void test1()\n   {\n      const std::string input = \"foo = '''a\\nb\\nc\\n'''\";\n      const auto config = config::from_string( input, __FUNCTION__ );\n      const auto string = config.get_object().at( \"foo\" );\n      assert( string.position.line() == 1 );\n      assert( string.get_string() == \"a\\nb\\nc\\n\" );\n   }\n\n   void test2()\n   {\n      const std::string input = \"foo = '''\\na\\nb\\nc\\n'''\";\n      const auto config = config::from_string( input, __FUNCTION__ );\n      const auto string = config.get_object().at( \"foo\" );\n      assert( string.position.line() == 1 );  // Should this be 2?\n      assert( string.get_string() == \"a\\nb\\nc\\n\" );\n   }\n\n   void test3()\n   {\n      const std::string input = \"\\n\\n\\nfoo = '''a\\nb\\nc\\n'''\";\n      const auto config = config::from_string( input, __FUNCTION__ );\n      const auto string = config.get_object().at( \"foo\" );\n      assert( string.position.line() == 4 );\n      assert( string.get_string() == \"a\\nb\\nc\\n\" );\n   }\n\n   void test4()\n   {\n      const std::string input = \"\\n\\n\\nfoo = '''\\na\\nb\\nc\\n'''\";\n      const auto config = config::from_string( input, __FUNCTION__ );\n      const auto string = config.get_object().at( \"foo\" );\n      assert( string.position.line() == 4 );  // Should this be 5?\n      assert( string.get_string() == \"a\\nb\\nc\\n\" );\n   }\n\n}  // namespace tao\n\nint main()\n{\n   tao::test1();\n   tao::test2();\n   tao::test3();\n   tao::test4();\n   return 0;\n}\n"
  },
  {
    "path": "src/test/config/parse_key.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include \"test.hpp\"\n\n#include <tao/config/key.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      key k( \"foo.bar.42\" );\n      TAO_CONFIG_TEST_ASSERT( k.size() == 3 );\n      TAO_CONFIG_TEST_ASSERT( k[ 0 ].kind() == key_kind::name );\n      TAO_CONFIG_TEST_ASSERT( k[ 0 ].get_name() == \"foo\" );\n      TAO_CONFIG_TEST_ASSERT( k[ 1 ].kind() == key_kind::name );\n      TAO_CONFIG_TEST_ASSERT( k[ 1 ].get_name() == \"bar\" );\n      TAO_CONFIG_TEST_ASSERT( k[ 2 ].kind() == key_kind::index );\n      TAO_CONFIG_TEST_ASSERT( k[ 2 ].get_index() == 42 );\n\n      TAO_CONFIG_TEST_THROWS( key( \"foo.-\" ) );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/parse_key1.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include \"test.hpp\"\n\n#include <tao/config/internal/key1.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      internal::key1 k( \"foo.bar.42.*\" );\n      TAO_CONFIG_TEST_ASSERT( k.size() == 4 );\n      TAO_CONFIG_TEST_ASSERT( k[ 0 ].kind() == internal::key1_kind::name );\n      TAO_CONFIG_TEST_ASSERT( k[ 0 ].get_name() == \"foo\" );\n      TAO_CONFIG_TEST_ASSERT( k[ 1 ].kind() == internal::key1_kind::name );\n      TAO_CONFIG_TEST_ASSERT( k[ 1 ].get_name() == \"bar\" );\n      TAO_CONFIG_TEST_ASSERT( k[ 2 ].kind() == internal::key1_kind::index );\n      TAO_CONFIG_TEST_ASSERT( k[ 2 ].get_index() == 42 );\n      TAO_CONFIG_TEST_ASSERT( k[ 3 ].kind() == internal::key1_kind::asterisk );\n\n      TAO_CONFIG_TEST_THROWS( internal::key1( \"foo.-\" ) );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/parse_reference2.cpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include \"test.hpp\"\n\n#include <tao/config/internal/reference2.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      internal::reference2 k( \"(foo.(bar.1).42)\" );\n      TAO_CONFIG_TEST_ASSERT( k.size() == 3 );\n      TAO_CONFIG_TEST_ASSERT( k[ 0 ].kind() == internal::reference2_kind::name );\n      TAO_CONFIG_TEST_ASSERT( k[ 0 ].get_name() == \"foo\" );\n      TAO_CONFIG_TEST_ASSERT( k[ 1 ].kind() == internal::reference2_kind::vector );\n      const auto& v = k[ 1 ].get_vector();\n      TAO_CONFIG_TEST_ASSERT( v.size() == 2 );\n      TAO_CONFIG_TEST_ASSERT( v[ 0 ].kind() == internal::reference2_kind::name );\n      TAO_CONFIG_TEST_ASSERT( v[ 0 ].get_name() == \"bar\" );\n      TAO_CONFIG_TEST_ASSERT( v[ 1 ].kind() == internal::reference2_kind::index );\n      TAO_CONFIG_TEST_ASSERT( v[ 1 ].get_index() == 1 );\n      TAO_CONFIG_TEST_ASSERT( k[ 2 ].kind() == internal::reference2_kind::index );\n      TAO_CONFIG_TEST_ASSERT( k[ 2 ].get_index() == 42 );\n\n      TAO_CONFIG_TEST_THROWS( internal::reference2( \"foo.-\" ) );\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/setenv.hpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_SRC_TEST_CONFIG_SETENV_HPP\n#define TAO_CONFIG_SRC_TEST_CONFIG_SETENV_HPP\n\n#include <stdexcept>\n#include <stdlib.h>\n#include <string>\n\nnamespace tao::config::internal\n{\n   void setenv_throws( const std::string& name, const std::string& value )\n   {\n#if defined( _MSC_VER )\n      const auto e = ::_putenv_s( name.c_str(), value.c_str() );\n      if( e != 0 ) {\n#else\n      errno = 0;\n      if( ::setenv( name.c_str(), value.c_str(), 1 ) != 0 ) {\n         // LCOV_EXCL_START\n         const auto e = errno;\n#endif\n         (void)e;\n         throw std::runtime_error( \"setenv failed\" );\n         // LCOV_EXCL_STOP\n      }\n   }\n\n}  // namespace tao::config::internal\n\n#endif\n"
  },
  {
    "path": "src/test/config/success.cpp",
    "content": "// Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <algorithm>\n#include <filesystem>\n#include <iostream>\n#include <stdexcept>\n\n#include \"setenv.hpp\"\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n\nnamespace tao::config\n{\n   template< template< typename... > class Traits >\n   void unit_test( const std::filesystem::path& path )\n   {\n      try {\n         const auto cc = basic_from_file< Traits >( path );\n         const std::vector< std::filesystem::path > paths = { \"tests/empty.success\", path, \"tests/empty.success\" };\n         const auto cf = basic_from_files< Traits >( paths );\n\n         std::filesystem::path jaxn = path;\n         jaxn.replace_extension( \".jaxn\" );\n         const auto cj = basic_from_file< Traits >( jaxn );\n         const auto jj = json::jaxn::basic_from_file< Traits >( jaxn );\n\n         const auto ccs = json::jaxn::to_string( cc );\n         const auto cfs = json::jaxn::to_string( cf );\n         const auto cjs = json::jaxn::to_string( cj );\n         const auto jjs = json::jaxn::to_string( jj );\n\n         if( ccs != cfs ) {\n            // LCOV_EXCL_START\n            ++failed;\n            std::cerr << std::endl\n                      << \"Testcase '\" << path << \"' failed config test!\" << std::endl;\n            std::cerr << \"<<< Config parsed as config <<<\" << std::endl;\n            std::cerr << ccs << std::endl;\n            std::cerr << \">>> Config parsed as config >>>\" << std::endl;\n            std::cerr << \"<<< Config parsed as config with empty files <<<\" << std::endl;\n            std::cerr << jjs << std::endl;\n            std::cerr << \">>> Config parsed as config with empty files >>>\" << std::endl;\n            // LCOV_EXCL_STOP\n         }\n         if( ccs != jjs ) {\n            // LCOV_EXCL_START\n            ++failed;\n            std::cerr << std::endl\n                      << \"Testcase '\" << path << \"' failed config test!\" << std::endl;\n            std::cerr << \"<<< Config parsed as config <<<\" << std::endl;\n            std::cerr << ccs << std::endl;\n            std::cerr << \">>> Config parsed as config >>>\" << std::endl;\n            std::cerr << \"<<< Reference data parsed as jaxn <<<\" << std::endl;\n            std::cerr << jjs << std::endl;\n            std::cerr << \">>> Reference data parsed as jaxn >>>\" << std::endl;\n            // LCOV_EXCL_STOP\n         }\n         if( ccs != cjs ) {\n            // LCOV_EXCL_START\n            ++failed;\n            std::cerr << std::endl\n                      << \"Testcase '\" << path << \"' failed identity test!\" << std::endl;\n            std::cerr << \"<<< Config parsed as config <<<\" << std::endl;\n            std::cerr << ccs << std::endl;\n            std::cerr << \">>> Config parsed as config >>>\" << std::endl;\n            std::cerr << \"<<< Reference data parsed as config <<<\" << std::endl;\n            std::cerr << cjs << std::endl;\n            std::cerr << \">>> Reference data parsed as config >>>\" << std::endl;\n            // LCOV_EXCL_STOP\n         }\n         const auto fc = from_file( path );\n         const auto ff = from_files( paths );\n\n         const auto fcs = json::jaxn::to_string( fc );\n         const auto ffs = json::jaxn::to_string( ff );\n\n         if constexpr( std::is_same_v< decltype( cc ), decltype( fc ) > ) {\n            TAO_CONFIG_TEST_ASSERT( ccs == fcs );\n            TAO_CONFIG_TEST_ASSERT( cfs == ffs );\n         }\n         TAO_CONFIG_TEST_ASSERT( fcs == ffs );\n      }\n      // LCOV_EXCL_START\n      catch( const std::exception& e ) {\n         std::cerr << \"Testcase '\" << path << \"' failed with exception '\" << e.what() << \"'\" << std::endl;\n         ++failed;\n      }\n      // LCOV_EXCL_STOP\n   }\n\n}  // namespace tao::config\n\nint main()\n{\n   unsigned count = 0;\n\n   for( const auto& entry : std::filesystem::directory_iterator( \"tests\" ) ) {\n      if( const auto& path = entry.path(); path.extension() == \".success\" ) {\n#if defined( _MSC_VER )\n         if( entry.path().stem() == \"shell\" ) {\n            continue;\n         }\n#endif\n         tao::config::internal::setenv_throws( \"TAO_CONFIG\", \"env_value\" );\n         tao::config::unit_test< tao::json::traits >( path );\n         tao::config::unit_test< tao::config::traits >( path );\n         ++count;\n      }\n   }\n   if( tao::config::failed == 0 ) {\n      std::cerr << \"All \" << count << \" success testcases passed.\" << std::endl;\n   }\n   return std::min( int( tao::config::failed ), 127 );\n}\n"
  },
  {
    "path": "src/test/config/test.hpp",
    "content": "// Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#ifndef TAO_CONFIG_SRC_TEST_CONFIG_TEST_HPP\n#define TAO_CONFIG_SRC_TEST_CONFIG_TEST_HPP\n\n#include <cstddef>\n#include <iostream>\n\nnamespace tao::config\n{\n   std::size_t failed = 0;\n\n}  // namespace tao::config\n\n#define TAO_TEST_STRINGIZE_INTERNAL( ... ) #__VA_ARGS__\n#define TAO_TEST_STRINGIZE( ... ) TAO_TEST_STRINGIZE_INTERNAL( __VA_ARGS__ )\n\n#define TAO_TEST_LINE TAO_TEST_STRINGIZE( __LINE__ )\n\n#define TAO_CONFIG_TEST_UNWRAP( ... ) __VA_ARGS__\n\n#define TAO_CONFIG_TEST_FAILED( MeSSaGe )            \\\n   do {                                              \\\n      std::cerr << \"config: unit test failed for [ \" \\\n                << tao::demangle< Rule >()           \\\n                << \" ] \"                             \\\n                << TAO_CONFIG_TEST_UNWRAP( MeSSaGe ) \\\n                << \" in line [ \"                     \\\n                << line                              \\\n                << \" ] file [ \"                      \\\n                << file << \" ]\"                      \\\n                << std::endl;                        \\\n      ++failed;                                      \\\n   } while( false )\n\n#define TAO_CONFIG_TEST_ASSERT( ... )               \\\n   do {                                             \\\n      if( !( __VA_ARGS__ ) ) {                      \\\n         std::cerr << \"config: unit test assert [ \" \\\n                   << ( #__VA_ARGS__ )              \\\n                   << \" ] failed in line [ \"        \\\n                   << __LINE__                      \\\n                   << \" ] file [ \"                  \\\n                   << __FILE__ << \" ]\"              \\\n                   << std::endl;                    \\\n         ++failed;                                  \\\n      }                                             \\\n   } while( false )\n\n#define TAO_CONFIG_TEST_THROWS( ... )               \\\n   do {                                             \\\n      try {                                         \\\n         __VA_ARGS__;                               \\\n         std::cerr << \"config: unit test [ \"        \\\n                   << ( #__VA_ARGS__ )              \\\n                   << \" ] did not throw in line [ \" \\\n                   << __LINE__                      \\\n                   << \" ] file [ \"                  \\\n                   << __FILE__ << \" ]\"              \\\n                   << std::endl;                    \\\n         ++failed;                                  \\\n      }                                             \\\n      catch( ... ) {                                \\\n      }                                             \\\n   } while( false )\n\n#define TAO_CONFIG_TEST_UNREACHABLE                                                                                             \\\n   do {                                                                                                                         \\\n      std::cerr << \"Code should be unreachable in \" << __FUNCTION__ << \" (\" << __FILE__ << ':' << __LINE__ << ')' << std::endl; \\\n      std::abort();                                                                                                             \\\n   } while( false )\n\n#endif\n"
  },
  {
    "path": "src/test/config/to_stream.cpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <iostream>\n#include <sstream>\n#include <string>\n\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n\nnamespace tao::config\n{\n   void unit_test()\n   {\n      const std::string input = \"a = 1 b { c = 42 d = [ null, true ] }\";\n      const tao::config::value parsed = tao::config::from_string( input, \"main\" );\n      {\n         std::ostringstream oss;\n         tao::config::to_stream( oss, parsed );\n         const std::string string1 = oss.str();\n         const std::string reference1 = \"{meta:{key:[],position:\\\"(root):1:1\\\"},data:{a:{meta:{key:[{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"a\\\"}}],position:\\\"main:1:6\\\"},data:1},b:{meta:{key:[{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"b\\\"}}],position:\\\"main:1:9\\\"},data:{c:{meta:{key:[{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"b\\\"}},{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"c\\\"}}],position:\\\"main:1:17\\\"},data:42},d:{meta:{key:[{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"b\\\"}},{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"d\\\"}}],position:\\\"main:1:22\\\"},data:[{meta:{key:[{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"b\\\"}},{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"d\\\"}},{key_kind:\\\"index\\\",key_data:{index:1,value:0}}],position:\\\"main:1:24\\\"},data:null},{meta:{key:[{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"b\\\"}},{key_kind:\\\"name\\\",key_data:{index:0,value:\\\"d\\\"}},{key_kind:\\\"index\\\",key_data:{index:1,value:1}}],position:\\\"main:1:30\\\"},data:true}]}}}}}\";\n         if( string1 != reference1 ) {\n            // LCOV_EXCL_START\n            std::cerr << string1 << std::endl;\n            std::cerr << reference1 << std::endl;\n            std::cerr << \"Config to_stream test 1 failed!\" << std::endl;\n            ++failed;\n            // LCOV_EXCL_STOP\n         }\n      }\n      {\n         std::ostringstream oss;\n         tao::config::to_stream( oss, parsed, 3 );\n         const std::string string2 = oss.str();\n         const std::string reference2 = \"{\\n   meta: {\\n      key: [],\\n      position: \\\"(root):1:1\\\"\\n   },\\n   data: {\\n      a: {\\n         meta: {\\n            key: [\\n               {\\n                  key_kind: \\\"name\\\",\\n                  key_data: {\\n                     index: 0,\\n                     value: \\\"a\\\"\\n                  }\\n               }\\n            ],\\n            position: \\\"main:1:6\\\"\\n         },\\n         data: 1\\n      },\\n      b: {\\n         meta: {\\n            key: [\\n               {\\n                  key_kind: \\\"name\\\",\\n                  key_data: {\\n                     index: 0,\\n                     value: \\\"b\\\"\\n                  }\\n               }\\n            ],\\n            position: \\\"main:1:9\\\"\\n         },\\n         data: {\\n            c: {\\n               meta: {\\n                  key: [\\n                     {\\n                        key_kind: \\\"name\\\",\\n                        key_data: {\\n                           index: 0,\\n                           value: \\\"b\\\"\\n                        }\\n                     },\\n                     {\\n                        key_kind: \\\"name\\\",\\n                        key_data: {\\n                           index: 0,\\n                           value: \\\"c\\\"\\n                        }\\n                     }\\n                  ],\\n                  position: \\\"main:1:17\\\"\\n               },\\n               data: 42\\n            },\\n            d: {\\n               meta: {\\n                  key: [\\n                     {\\n                        key_kind: \\\"name\\\",\\n                        key_data: {\\n                           index: 0,\\n                           value: \\\"b\\\"\\n                        }\\n                     },\\n                     {\\n                        key_kind: \\\"name\\\",\\n                        key_data: {\\n                           index: 0,\\n                           value: \\\"d\\\"\\n                        }\\n                     }\\n                  ],\\n                  position: \\\"main:1:22\\\"\\n               },\\n               data: [\\n                  {\\n                     meta: {\\n                        key: [\\n                           {\\n                              key_kind: \\\"name\\\",\\n                              key_data: {\\n                                 index: 0,\\n                                 value: \\\"b\\\"\\n                              }\\n                           },\\n                           {\\n                              key_kind: \\\"name\\\",\\n                              key_data: {\\n                                 index: 0,\\n                                 value: \\\"d\\\"\\n                              }\\n                           },\\n                           {\\n                              key_kind: \\\"index\\\",\\n                              key_data: {\\n                                 index: 1,\\n                                 value: 0\\n                              }\\n                           }\\n                        ],\\n                        position: \\\"main:1:24\\\"\\n                     },\\n                     data: null\\n                  },\\n                  {\\n                     meta: {\\n                        key: [\\n                           {\\n                              key_kind: \\\"name\\\",\\n                              key_data: {\\n                                 index: 0,\\n                                 value: \\\"b\\\"\\n                              }\\n                           },\\n                           {\\n                              key_kind: \\\"name\\\",\\n                              key_data: {\\n                                 index: 0,\\n                                 value: \\\"d\\\"\\n                              }\\n                           },\\n                           {\\n                              key_kind: \\\"index\\\",\\n                              key_data: {\\n                                 index: 1,\\n                                 value: 1\\n                              }\\n                           }\\n                        ],\\n                        position: \\\"main:1:30\\\"\\n                     },\\n                     data: true\\n                  }\\n               ]\\n            }\\n         }\\n      }\\n   }\\n}\";\n         if( string2 != reference2 ) {\n            // LCOV_EXCL_START\n            std::cerr << string2.size() << \" \" << reference2.size() << std::endl;\n            std::cerr << string2 << std::endl;\n            std::cerr << reference2 << std::endl;\n            std::cerr << \"Config to_stream test 2 failed!\" << std::endl;\n            ++failed;\n            // LCOV_EXCL_STOP\n         }\n      }\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "src/test/config/value.cpp",
    "content": "// Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey\n// Please see LICENSE for license or visit https://github.com/taocpp/config/\n\n#include <sstream>\n#include <string>\n\n#include \"test.hpp\"\n\n#include <tao/config.hpp>\n\nnamespace tao::config\n{\n   const std::string s = \"invalid json type 'object' for conversion to std::string  [(root):1:1]\";  // TODO: Where does the second space come from?\n\n   void unit_test()\n   {\n      const auto v = from_string( \"foo = 42\", __FUNCTION__ );\n\n      try {\n         (void)v.as< std::string >();\n         ++failed;  // LCOV_EXCL_LINE\n      }\n      catch( const std::exception& e ) {\n         TAO_CONFIG_TEST_ASSERT( e.what() == s );\n      }\n   }\n\n}  // namespace tao::config\n\n#include \"main.hpp\"\n"
  },
  {
    "path": "tests/add_01.failure",
    "content": "a = null + null\n"
  },
  {
    "path": "tests/add_02.failure",
    "content": "a = null + true\n"
  },
  {
    "path": "tests/add_03.failure",
    "content": "a = true + null\n"
  },
  {
    "path": "tests/add_04.failure",
    "content": "a = true + false\n"
  },
  {
    "path": "tests/add_05.failure",
    "content": "a = null + 1\n"
  },
  {
    "path": "tests/add_06.failure",
    "content": "a = 1 + null\n"
  },
  {
    "path": "tests/add_07.failure",
    "content": "a = true + 1\n"
  },
  {
    "path": "tests/add_08.failure",
    "content": "a = 1 + true\n"
  },
  {
    "path": "tests/add_09.failure",
    "content": "a = null + \"\"\n"
  },
  {
    "path": "tests/add_10.failure",
    "content": "a = \"\" + null\n"
  },
  {
    "path": "tests/add_11.failure",
    "content": "a = true + \"\"\n"
  },
  {
    "path": "tests/add_12.failure",
    "content": "a = \"\" + true\n"
  },
  {
    "path": "tests/add_13.failure",
    "content": "a = 1 + \"\"\n"
  },
  {
    "path": "tests/add_14.failure",
    "content": "a = \"\" + 1\n"
  },
  {
    "path": "tests/add_15.failure",
    "content": "a = null + $\"\"\n"
  },
  {
    "path": "tests/add_16.failure",
    "content": "a = $\"\" + null\n"
  },
  {
    "path": "tests/add_17.failure",
    "content": "a = true + $\"\"\n"
  },
  {
    "path": "tests/add_18.failure",
    "content": "a = $\"\" + true\n"
  },
  {
    "path": "tests/add_19.failure",
    "content": "a = 1 + $\"\"\n"
  },
  {
    "path": "tests/add_20.failure",
    "content": "a = $\"\" + 1\n"
  },
  {
    "path": "tests/add_21.failure",
    "content": "a = \"\" + $\"\"\n"
  },
  {
    "path": "tests/add_22.failure",
    "content": "a = $\"\" + \"\"\n"
  },
  {
    "path": "tests/add_23.failure",
    "content": "a = null + {}\n"
  },
  {
    "path": "tests/add_24.failure",
    "content": "a = {} + null\n"
  },
  {
    "path": "tests/add_25.failure",
    "content": "a = true + {}\n"
  },
  {
    "path": "tests/add_26.failure",
    "content": "a = {} + true\n"
  },
  {
    "path": "tests/add_27.failure",
    "content": "a = 1 + {}\n"
  },
  {
    "path": "tests/add_28.failure",
    "content": "a = {} + 1\n"
  },
  {
    "path": "tests/add_29.failure",
    "content": "a = \"\" + {}\n"
  },
  {
    "path": "tests/add_30.failure",
    "content": "a = {} + \"\"\n"
  },
  {
    "path": "tests/add_31.failure",
    "content": "a = $\"\" + {}\n"
  },
  {
    "path": "tests/add_32.failure",
    "content": "a = {} + $\"\"\n"
  },
  {
    "path": "tests/add_33.failure",
    "content": "a = null + []\n"
  },
  {
    "path": "tests/add_34.failure",
    "content": "a = [] + null\n"
  },
  {
    "path": "tests/add_35.failure",
    "content": "a = true + []\n"
  },
  {
    "path": "tests/add_36.failure",
    "content": "a = [] + true\n"
  },
  {
    "path": "tests/add_37.failure",
    "content": "a = 1 + []\n"
  },
  {
    "path": "tests/add_38.failure",
    "content": "a = [] + 1\n"
  },
  {
    "path": "tests/add_39.failure",
    "content": "a = \"\" + []\n"
  },
  {
    "path": "tests/add_40.failure",
    "content": "a = [] + \"\"\n"
  },
  {
    "path": "tests/add_41.failure",
    "content": "a = $\"\" + []\n"
  },
  {
    "path": "tests/add_42.failure",
    "content": "a = [] + $\"\"\n"
  },
  {
    "path": "tests/add_43.failure",
    "content": "a = {} + []\n"
  },
  {
    "path": "tests/add_44.failure",
    "content": "a = [] + {}\n"
  },
  {
    "path": "tests/add_45.failure",
    "content": "a = []\nb = {}\nc = (a) + (b)\n"
  },
  {
    "path": "tests/add_46.failure",
    "content": "a = null\nb = 1\nc = (a) + (b)\n"
  },
  {
    "path": "tests/add_47.failure",
    "content": "a = null\nb = 1\nc = (a)\nd = (b)\ne = (c) + (d)\n"
  },
  {
    "path": "tests/add_48.failure",
    "content": "a {\n    b {\n        c {\n        }\n        c [\n        ]\n    }\n}\n"
  },
  {
    "path": "tests/add_number.jaxn",
    "content": "{\n   a: 18446744073709551615,\n   b: -1,\n   c: -7,\n   d: -1,\n   e: -1,\n   f: -19,\n   g: 1,\n   h: 1,\n   i: 0,\n   j: 0,\n   k: 42,\n   l: 8,\n   m: 1,\n   n: 1\n}\n"
  },
  {
    "path": "tests/add_number.success",
    "content": "a = 9223372036854775807 + 9223372036854775808\nb = -9223372036854775808 + 9223372036854775807\nc = -3 + -4\nd = -6 + 5\ne = 7 + -8\nf = -9 + -10\ng = 0 + 1\nh = 1 + 0\ni = 0 + 0\nj = 0 + 0 + 0\nk = 21 + 21\nl = +5 + +3\nm = -3 ++4\nn = 2+-1\n"
  },
  {
    "path": "tests/add_string.jaxn",
    "content": "{\n   a: \"a\",\n   b: \"ab\",\n   c: \"abc\"\n}\n"
  },
  {
    "path": "tests/add_string.success",
    "content": "a = \"a\"\n\nb = \"a\"\nb += \"b\"\n\nc = \"a\" + \"b\" + \"c\"\n"
  },
  {
    "path": "tests/array_index_01.jaxn",
    "content": "{\n   bar: 1,\n   baz: 5,\n   foo: [\n      1,\n      12,\n      3,\n      34,\n      5\n   ]\n}\n"
  },
  {
    "path": "tests/array_index_01.success",
    "content": "foo = [ 0 1 2 3 4 ]\nbar = (foo.0)\nbaz = (foo.4)\nfoo.1 += 10\nfoo.3 += 30\nfoo.* += 1\n"
  },
  {
    "path": "tests/array_index_02.jaxn",
    "content": "{\n   foo: []\n}\n"
  },
  {
    "path": "tests/array_index_02.success",
    "content": "foo = [ 1 2 3 ]\nfoo.* = delete\n"
  },
  {
    "path": "tests/binary.jaxn",
    "content": "{\n   a : $3031,\n   b : $3031,\n   c : $3031\n}\n"
  },
  {
    "path": "tests/binary.success",
    "content": "a = $3031\nb = $30 + $31\nc = $\"\\x30\\x31\"\n"
  },
  {
    "path": "tests/braces.jaxn",
    "content": "{}\n"
  },
  {
    "path": "tests/braces.success",
    "content": "{\n}\n"
  },
  {
    "path": "tests/combo_01.jaxn",
    "content": "{\n   foo: {\n      a: {\n         baz: 2\n      },\n      b: {\n         bar: 42,\n         baz: 1\n      }\n   }\n}\n"
  },
  {
    "path": "tests/combo_01.success",
    "content": "foo.*.bar = 42\nfoo.a.bar = delete\nfoo.b.baz = 1\nfoo.a.baz = 2\n"
  },
  {
    "path": "tests/combo_02.jaxn",
    "content": "{\n   foo: {\n      a: {\n         bar: 42,\n         baz: 2\n      },\n      b: {\n         bar: 42,\n         baz: 1\n      }\n   }\n}\n"
  },
  {
    "path": "tests/combo_02.success",
    "content": "foo.a.bar = delete\nfoo.*.bar = 42\nfoo.b.baz = 1\nfoo.a.baz = 2\n"
  },
  {
    "path": "tests/commas.jaxn",
    "content": "{\n   commas: {\n      arrays: [\n         [\n            1,\n            2,\n            3\n         ],\n         [\n            1,\n            2,\n            3\n         ],\n         [\n            1,\n            2,\n            3\n         ],\n         [\n            1,\n            2,\n            3\n         ],\n         [\n            1,\n            2,\n            3\n         ]\n      ],\n      objects: [\n         {\n            a: 1,\n            b: 2,\n            c: 3\n         },\n         {\n            a: 1,\n            b: 2,\n            c: 3\n         },\n         {\n            a: 1,\n            b: 2,\n            c: 3\n         },\n         {\n            a: 1,\n            b: 2,\n            c: 3\n         },\n         {\n            a: 1,\n            b: 2,\n            c: 3\n         }\n      ]\n   }\n}\n"
  },
  {
    "path": "tests/commas.success",
    "content": "commas : {\n    arrays : [\n        [ 1 2 3 ],\n        [ 1, 2, 3 ],\n        [ 1, 2, 3, ],\n        [ 1 2, 3 ]\n        [ 1 2 3, ]\n    ]\n    objects : [\n        { a : 1 b : 2 c : 3 },\n        { a : 1, b : 2, c : 3 },\n        { a : 1, b : 2, c : 3, },\n        { a : 1 b : 2, c : 3 }\n        { a : 1 b : 2 c : 3, }\n    ]\n}\n"
  },
  {
    "path": "tests/comments.jaxn",
    "content": "{\n   a: 1,\n   b: 2,\n   c: 3,\n   d: 4,\n   e: {\n      f: 6\n   },\n   g: [\n      7\n   ],\n   h: \"hH\"\n}\n"
  },
  {
    "path": "tests/comments.success",
    "content": "#!/bin/grmblfx\n\n# This is a comment.\n\n// This is another comment.\n\n/* And another one. */\n\n/* These comments /* don't nest */\n\na = 1\nb = 2 # foo\nc = 3 // foo\n\n/* foo */ d /* foo */ = /* foo */ 4 /* foo */\n\ne /* foo */ { /* foo */ f = 6 /* foo */ , /* foo */ } /* foo */\n\ng /* foo */ [ /* foo */ 7 /* foo */ , /* foo */ ] /* foo */\n\nh /* foo */ += /* foo */ \"h\" /* foo */ + /* foo */ \"H\" /* foo */\n"
  },
  {
    "path": "tests/complex_01.failure",
    "content": "a = (default (b) \"foo\")\nb = (default (a) \"bar\")\n"
  },
  {
    "path": "tests/complex_02.failure",
    "content": "x.* = 3\nx.a += 1\n\na = 2\ny.a = 1\ny.* += (a)\n"
  },
  {
    "path": "tests/complex_03.failure",
    "content": "a = (default (b) \"foo\") + \"a\"\nb = (default (a) \"bar\") + \"b\"\n"
  },
  {
    "path": "tests/debug_traits.config",
    "content": "a = 1 b { c = 42 d = [ null, true ] e = (a.42.(b)) f = 'yo' g = -3 h = 3.14 i = (env \"USER\") j = $beef } c.* = 42\n"
  },
  {
    "path": "tests/debug_traits.output",
    "content": "{\n   position: \"(root):1:1\",\n   object_data: {\n      a: {\n         remove: true,\n         implicit: false,\n         temporary: false,\n         position: \"tests/debug_traits.config:1:1\",\n         concat_list: [\n            {\n               type: \"unsigned\",\n               data: 1\n            }\n         ]\n      },\n      b: {\n         remove: false,\n         implicit: false,\n         temporary: false,\n         position: \"tests/debug_traits.config:1:7\",\n         concat_list: [\n            {\n               type: \"object\",\n               data: {\n                  position: \"tests/debug_traits.config:1:9\",\n                  object_data: {\n                     c: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:11\",\n                        concat_list: [\n                           {\n                              type: \"unsigned\",\n                              data: 42\n                           }\n                        ]\n                     },\n                     d: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:18\",\n                        concat_list: [\n                           {\n                              type: \"array\",\n                              data: {\n                                 position: \"tests/debug_traits.config:1:22\",\n                                 function: \"\",\n                                 array_data: [\n                                    {\n                                       remove: false,\n                                       implicit: false,\n                                       temporary: false,\n                                       position: \"tests/debug_traits.config:1:24\",\n                                       concat_list: [\n                                          {\n                                             type: \"null\"\n                                          }\n                                       ]\n                                    },\n                                    {\n                                       remove: false,\n                                       implicit: false,\n                                       temporary: false,\n                                       position: \"tests/debug_traits.config:1:24\",\n                                       concat_list: [\n                                          {\n                                             type: \"boolean\",\n                                             data: true\n                                          }\n                                       ]\n                                    }\n                                 ]\n                              }\n                           }\n                        ]\n                     },\n                     e: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:37\",\n                        concat_list: [\n                           {\n                              type: \"reference\",\n                              data: [\n                                 {\n                                    reference2_kind: \"name\",\n                                    reference2_data: {\n                                       index: 0,\n                                       value: \"a\"\n                                    },\n                                    position: \"tests/debug_traits.config:1:42\"\n                                 },\n                                 {\n                                    reference2_kind: \"index\",\n                                    reference2_data: {\n                                       index: 1,\n                                       value: 42\n                                    },\n                                    position: \"tests/debug_traits.config:1:44\"\n                                 },\n                                 {\n                                    reference2_kind: \"reference\",\n                                    reference2_data: {\n                                       index: 2,\n                                       value: [\n                                          {\n                                             reference2_kind: \"name\",\n                                             reference2_data: {\n                                                index: 0,\n                                                value: \"b\"\n                                             },\n                                             position: \"tests/debug_traits.config:1:48\"\n                                          }\n                                       ]\n                                    },\n                                    position: \"tests/debug_traits.config:1:47\"\n                                 }\n                              ]\n                           }\n                        ]\n                     },\n                     f: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:52\",\n                        concat_list: [\n                           {\n                              type: \"string\",\n                              data: \"yo\"\n                           }\n                        ]\n                     },\n                     g: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:61\",\n                        concat_list: [\n                           {\n                              type: \"signed\",\n                              data: -3\n                           }\n                        ]\n                     },\n                     h: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:68\",\n                        concat_list: [\n                           {\n                              type: \"double\",\n                              data: 3.14\n                           }\n                        ]\n                     },\n                     i: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:77\",\n                        concat_list: [\n                           {\n                              type: \"array\",\n                              data: {\n                                 position: \"tests/debug_traits.config:1:82\",\n                                 function: \"env\",\n                                 array_data: [\n                                    {\n                                       remove: false,\n                                       implicit: false,\n                                       temporary: false,\n                                       position: \"tests/debug_traits.config:1:86\",\n                                       concat_list: [\n                                          {\n                                             type: \"string\",\n                                             data: \"USER\"\n                                          }\n                                       ]\n                                    }\n                                 ]\n                              }\n                           }\n                        ]\n                     },\n                     j: {\n                        remove: true,\n                        implicit: false,\n                        temporary: false,\n                        position: \"tests/debug_traits.config:1:94\",\n                        concat_list: [\n                           {\n                              type: \"binary\",\n                              data: $BEEF\n                           }\n                        ]\n                     }\n                  }\n               }\n            }\n         ]\n      },\n      c: {\n         remove: false,\n         implicit: false,\n         temporary: false,\n         position: \"tests/debug_traits.config:1:106\",\n         concat_list: [\n            {\n               type: \"asterisk\",\n               data: {\n                  remove: true,\n                  implicit: false,\n                  temporary: false,\n                  position: \"tests/debug_traits.config:1:108\",\n                  concat_list: [\n                     {\n                        type: \"unsigned\",\n                        data: 42\n                     }\n                  ]\n               }\n            }\n         ]\n      }\n   }\n}\n"
  },
  {
    "path": "tests/delete.jaxn",
    "content": "{\n   c: [\n      {},\n      {}\n   ],\n   d: {\n      a: {},\n      b: {},\n      c: {}\n   },\n   f: {},\n   g: 2,\n   h: 2\n}\n"
  },
  {
    "path": "tests/delete.success",
    "content": "a = 1\na = delete\n\nb.c.d = delete\n\nc = [ {\n  d = delete\n} {\n  e = 42\n} ]\n\nc.1.e = delete\n\nd.a.d = 1\nd.b.d = 2\nd.c.d = 3\n\nd.*.d = delete\ne.*.e = delete\n\nf.a = 1\nf.b = 2\nf.c = 3\n\nf.* = delete\n\ng = 1\ng = delete\ng = 2\n\nh += 1\nh = delete\nh += 2\n"
  },
  {
    "path": "tests/doc_asterisk_01.jaxn",
    "content": "{\n   servers: {\n      primary: {\n         port: 7000\n      },\n      secondary: {\n         port: 7000\n      }\n   }\n}\n"
  },
  {
    "path": "tests/doc_asterisk_01.success",
    "content": "servers\n{\n    primary\n    {\n        port = 443\n    }\n    secondary\n    {\n        port = 8888\n    }\n}\nservers.*.port = 7000  // Testing\n"
  },
  {
    "path": "tests/doc_default.jaxn",
    "content": "{\n   bar: false,\n   foo: 1\n}\n"
  },
  {
    "path": "tests/doc_default.success",
    "content": "foo = (default 1 2)\nbar = (default null false true)\n"
  },
  {
    "path": "tests/doc_delete_01.jaxn",
    "content": "{\n   ip: \"127.0.0.2\",\n   port: 27960\n}\n"
  },
  {
    "path": "tests/doc_delete_01.success",
    "content": "#!/usr/local/bin/qs\n\nip = \"127.0.0.2\"\nport = 27960\nmaps = [ \"ztn\" \"dm13\" \"t9\" ]\nmaps = delete  // Changed our minds, no maps.\n"
  },
  {
    "path": "tests/doc_delete_02.jaxn",
    "content": "{\n   foo: 44\n}\n"
  },
  {
    "path": "tests/doc_delete_02.success",
    "content": "foo = 42\nfoo = delete\nfoo += 44\n"
  },
  {
    "path": "tests/doc_dotted_names.jaxn",
    "content": "{\n   foo: {\n      bar: {\n         baz: 3\n      }\n   }\n}\n"
  },
  {
    "path": "tests/doc_dotted_names.success",
    "content": "foo\n{\n    bar.baz += 1\n}\nfoo.bar\n{\n    baz += 1\n}\nfoo.bar.baz += 1\n"
  },
  {
    "path": "tests/doc_include.inc",
    "content": "bar = 42\nbaz = [ true, false ]\n"
  },
  {
    "path": "tests/doc_include.jaxn",
    "content": "{\n   bar: 42,\n   baz: [\n      true,\n      false\n   ],\n   foo: {\n      bar: 42,\n      baz: [\n         true,\n         false\n      ]\n   }\n}\n"
  },
  {
    "path": "tests/doc_include.success",
    "content": "// Include the file whose contents are shown below.\n(include \"tests/doc_include.inc\")\n\nfoo\n{\n    // Include the same file again, this time within an object.\n    (include \"tests/doc_include.inc\")\n}\n\n// Use include? with a non-existing file, not an error.\n(include? \"tests/non_existing_file_is_no_error_with_question_mark\")\n"
  },
  {
    "path": "tests/doc_object_merge_01.jaxn",
    "content": "{\n   foo: {\n      a: 10,\n      b: 22,\n      c: 3,\n      d: 40\n   }\n}\n"
  },
  {
    "path": "tests/doc_object_merge_01.success",
    "content": "foo\n{\n    a = 1\n    b = 2\n    c = 3\n}\nfoo\n{\n    a = 10\n    b += 20\n    d = 40\n}\n"
  },
  {
    "path": "tests/doc_references_01.jaxn",
    "content": "{\n   a: {\n      b: {\n         c: {\n            i: 4,\n            j: 3,\n            k: 2,\n            x: 4\n         },\n         x: 3\n      },\n      x: 2\n   },\n   r: 3,\n   x: 1\n}\n"
  },
  {
    "path": "tests/doc_references_01.success",
    "content": "r = (a.b.x)\n\na\n{\n    b\n    {\n        c\n        {\n            i = (x)\n            j = (b.x)\n            k = (a.x)\n\n            x = 4\n        }\n        x = 3\n    }\n    x = 2\n}\nx = 1\n"
  },
  {
    "path": "tests/doc_references_02.failure",
    "content": "a = (b)\nb = (a)\n"
  },
  {
    "path": "tests/doc_references_03.failure",
    "content": "a\n{\n    a\n    {\n        c = (a.b)\n    }\n    b = 1\n}\n"
  },
  {
    "path": "tests/doc_references_05.jaxn",
    "content": "{\n   bar: 3,\n   baz: 13,\n   foo: [\n      10,\n      11,\n      12,\n      13,\n      14\n   ]\n}\n"
  },
  {
    "path": "tests/doc_references_05.success",
    "content": "foo = [ 10 11 12 13 14 ]\nbar = 3\nbaz = (foo.(bar))\n"
  },
  {
    "path": "tests/doc_references_06.jaxn",
    "content": "{\n   ttt: {\n      bar: {\n         a: 1\n      }\n   }\n}\n"
  },
  {
    "path": "tests/doc_references_06.success",
    "content": "(temporary foo)\n(temporary foo.baz)\n\nfoo\n{\n    bar\n    {\n        a = 1\n    }\n    baz\n    {\n        b = 2\n    }\n}\n\nttt = (foo)\n"
  },
  {
    "path": "tests/doc_temporary.jaxn",
    "content": "{\n   bar: {\n      host: \"127.0.0.1\",\n      port: 6001,\n      version: 42\n   },\n   foo: {\n      host: \"127.0.0.2\",\n      port: 6000,\n      version: 42\n   }\n}\n"
  },
  {
    "path": "tests/doc_temporary.success",
    "content": "(temporary template)  // Can occur before...\n\ntemplate\n{\n    host = \"127.0.0.1\"\n    port = 6000\n    version = 42\n}\n\nfoo = (template) +\n{\n    host = \"127.0.0.2\"\n}\n\nbar = (template) +\n{\n    port = 6001\n}\n\n(temporary template)  // ...and/or after.\n"
  },
  {
    "path": "tests/empty.jaxn",
    "content": "{}"
  },
  {
    "path": "tests/empty.success",
    "content": ""
  },
  {
    "path": "tests/env.failure",
    "content": "a = (env \"RUBBERDUCKY\")\n"
  },
  {
    "path": "tests/extensions.jaxn",
    "content": "{\n   default: {\n      a: 1,\n      b: 2,\n      c: 1,\n      d: null\n   },\n   env: {\n      a: \"env_value\",\n      b: \"default_value\"\n   },\n   parse: {\n      a: 42,\n      b: null\n   },\n   split: {\n      a: [],\n      b: [\n         \"a\"\n      ],\n      c: [\n         \"a\"\n      ],\n      d: [\n         \"a\",\n         \"b\",\n         \"c\"\n      ],\n      e: [\n         \"a\",\n         \"b\",\n         \"c\"\n      ]\n   },\n   string: {\n      a: \"\",\n      b: \"foo\",\n      c: \"01\"\n   },\n   unready: {\n      a: \"env_value\",\n      b: \"env_value\",\n      c: \"env_value\"\n   }\n}\n"
  },
  {
    "path": "tests/extensions.success",
    "content": "default\n{\n    a = (default 1 2 3 4 5)\n    b = (default null null 2)\n    c = (default 1 null)\n    d = null  // (default null null)\n}\n\nenv\n{\n    a = (env \"TAO_CONFIG\")\n    b = (env? \"a b c d e f g h i j k l m n o p q r s t u v w x y z\" \"default_value\")\n}\n\nparse\n{\n    a = (parse \"42\")\n    b = (parse \"null\")\n}\n\nsplit\n{\n    a = (split \"\")\n    b = (split \"a\")\n    c = (split \" a \")\n    d = (split \"a b c\")\n    e = (split \" a b c \")\n}\n\nstring\n{\n    a = (string \"\")\n    b = (string \"foo\")\n    c = (string $3031)\n}\n\nunready\n{\n    a = (env \"TAO_CONFIG\")\n    b = (default (a) (c))\n    c = (env \"TAO_CONFIG\")\n}\n"
  },
  {
    "path": "tests/formats.cbor",
    "content": "ehallo"
  },
  {
    "path": "tests/formats.jaxn",
    "content": "{\n   jaxn: \"hallo\",\n   txt: \"hallo\",\n}\n"
  },
  {
    "path": "tests/formats.json",
    "content": "\"hallo\"\n"
  },
  {
    "path": "tests/formats.msgpack",
    "content": "hallo"
  },
  {
    "path": "tests/formats.success",
    "content": "// cbor = (cbor (read \"tests/formats.cbor\"))\njaxn = (jaxn (read \"tests/formats.json\"))\n// json = (json (read \"tests/formats.json\"))\n// msgpack = (msgpack (read \"tests/formats.msgpack\"))\ntxt = (string (read \"tests/formats.txt\"))\n// ubjson = (ubjson (read \"tests/formats.ubjson\"))\n"
  },
  {
    "path": "tests/formats.txt",
    "content": "hallo"
  },
  {
    "path": "tests/formats.ubjson",
    "content": "SU\u0005hallo"
  },
  {
    "path": "tests/include.jaxn",
    "content": "{\n   a: {\n      simple: 42\n   },\n   b: {\n      simple: 43\n   },\n   c: {},\n   simple: 42\n}\n"
  },
  {
    "path": "tests/include.success",
    "content": "(include \"tests/simple.success\")\n\na = {\n  (include \"tests/simple.success\")\n}\n\nb = {\n   ( include \"tests/simple.success\" )\n}\n\nb.simple += 1\n\nc = {\n   (include? \"a b c d e f g h i j k l m n o p q r s t u v w x y z\")\n}\n"
  },
  {
    "path": "tests/jaxn.jaxn",
    "content": "{\n   foo: [\n      null,\n      true,\n      false,\n      42,\n      $FF,\n      \"foo\",\n      {\n         a: null,\n         b: true,\n         c: false,\n         d: 42,\n         e: $FF,\n         f: \"foo\"\n      }\n   ]\n}\n"
  },
  {
    "path": "tests/jaxn.success",
    "content": "foo = (jaxn \"[ null, true, false, 42, $ff, 'foo', { a: null, b: true, c: false, d: 42, e: $ff, f: 'foo' } ]\")\n"
  },
  {
    "path": "tests/merge_number_01.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 2\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_01.success",
    "content": "foo\n{\n    v = 1\n}\n\nbar = (foo) +\n{\n    v = 2\n}\n"
  },
  {
    "path": "tests/merge_number_02.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 3\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_02.success",
    "content": "foo\n{\n    v = 1\n}\n\nbar = (foo) +\n{\n    v += 2\n}\n"
  },
  {
    "path": "tests/merge_number_03.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 2\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_03.success",
    "content": "foo\n{\n    v += 1\n}\n\nbar = (foo) +\n{\n    v = 2\n}\n"
  },
  {
    "path": "tests/merge_number_04.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 3\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_04.success",
    "content": "foo\n{\n    v += 1\n}\n\nbar = (foo) +\n{\n    v += 2\n}\n"
  },
  {
    "path": "tests/merge_number_05.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 1\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_05.success",
    "content": "foo\n{\n    v = 1\n}\n\nbar =\n{\n    v = 2\n} + (foo)\n"
  },
  {
    "path": "tests/merge_number_06.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 1\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_06.success",
    "content": "foo\n{\n    v = 1\n}\n\nbar =\n{\n    v += 2\n} + (foo)\n"
  },
  {
    "path": "tests/merge_number_07.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 3\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_07.success",
    "content": "foo\n{\n    v += 1\n}\n\nbar =\n{\n    v = 2\n} + (foo)\n"
  },
  {
    "path": "tests/merge_number_08.jaxn",
    "content": "{\n    foo: {\n        v: 1\n    },\n    bar: {\n        v: 3\n    }\n}\n"
  },
  {
    "path": "tests/merge_number_08.success",
    "content": "foo\n{\n    v += 1\n}\n\nbar =\n{\n    v += 2\n} + (foo)\n"
  },
  {
    "path": "tests/merge_string_01.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"2\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_01.success",
    "content": "foo\n{\n    v = \"1\"\n}\n\nbar = (foo) +\n{\n    v = \"2\"\n}\n"
  },
  {
    "path": "tests/merge_string_02.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"12\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_02.success",
    "content": "foo\n{\n    v = \"1\"\n}\n\nbar = (foo) +\n{\n    v += \"2\"\n}\n"
  },
  {
    "path": "tests/merge_string_03.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"2\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_03.success",
    "content": "foo\n{\n    v += \"1\"\n}\n\nbar = (foo) +\n{\n    v = \"2\"\n}\n"
  },
  {
    "path": "tests/merge_string_04.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"12\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_04.success",
    "content": "foo\n{\n    v += \"1\"\n}\n\nbar = (foo) +\n{\n    v += \"2\"\n}\n"
  },
  {
    "path": "tests/merge_string_05.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"1\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_05.success",
    "content": "foo\n{\n    v = \"1\"\n}\n\nbar =\n{\n    v = \"2\"\n} + (foo)\n"
  },
  {
    "path": "tests/merge_string_06.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"1\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_06.success",
    "content": "foo\n{\n    v = \"1\"\n}\n\nbar =\n{\n    v += \"2\"\n} + (foo)\n"
  },
  {
    "path": "tests/merge_string_07.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"21\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_07.success",
    "content": "foo\n{\n    v += \"1\"\n}\n\nbar =\n{\n    v = \"2\"\n} + (foo)\n"
  },
  {
    "path": "tests/merge_string_08.jaxn",
    "content": "{\n    foo: {\n        v: \"1\"\n    },\n    bar: {\n        v: \"21\"\n    }\n}\n"
  },
  {
    "path": "tests/merge_string_08.success",
    "content": "foo\n{\n    v += \"1\"\n}\n\nbar =\n{\n    v += \"2\"\n} + (foo)\n"
  },
  {
    "path": "tests/numbers.jaxn",
    "content": "{\n   dec0: -1000000000000000,\n   dec1: 0,\n   dec2: 0,\n   dec3: 0,\n   dec4: 42,\n   dec5: 1284712984,\n   dec6: 1284712984,\n   dec7: -1284712984,\n   dec8: 1000000000000000,\n   dec9: 1000000000000000,\n   float1: 0.1,\n   float2: 1.23e47,\n   float3: -0.42,\n   float4: -0.12,\n   float5: 0.0,\n   float6: NaN,\n   float7: -Infinity,\n   hex1: 291,\n   hex2: 291,\n   hex3: -291\n}\n"
  },
  {
    "path": "tests/numbers.success",
    "content": "# Just enough to convince us that we have properly integrated the JSON library...\n# ...which has a far more extensive test-suite for parsing integers and doubles.\n\ndec1 = 0\ndec2 = -0\ndec3 = +0\ndec4 = 42\ndec5 = 1284712984\ndec6 = +1284712984\ndec7 = -1284712984\ndec8 = 1000000000000000\ndec9 = +1000000000000000\ndec0 = -1000000000000000\n\nhex1 = 0x123\nhex2 = +0X123\nhex3 = -0x123\n\nfloat1 = .1\nfloat2 = 123e45\nfloat3 = -.42\nfloat4 = -1.2e-1\nfloat5 = 0.0\nfloat6 = NaN\nfloat7 = -Infinity\n"
  },
  {
    "path": "tests/quoted.jaxn",
    "content": "{\n   a: {\n      \" \": {\n         b: 1\n      }\n   },\n   c: {\n      \" \": {\n         d: 2\n      }\n   }\n}\n"
  },
  {
    "path": "tests/quoted.success",
    "content": "a.\" \".b = 1\nc.' '.d = 2\n"
  },
  {
    "path": "tests/reference_01.failure",
    "content": "a = (b)\nb = (a)\n"
  },
  {
    "path": "tests/reference_01.jaxn",
    "content": "{\n   a: 1,\n   b: {\n      c: 2\n   },\n   d: 1,\n   e: 2,\n   f: {\n      g: {\n         h: 4\n      }\n   },\n   i: \"g\",\n   j: 8,\n   k: 15\n}\n"
  },
  {
    "path": "tests/reference_01.success",
    "content": "k = (f.(i).h) + (b.c) + 9\n\na = 1\n\nb.c = 2\n\nd = (a)\ne = (b.c)\n\nf.g.h = 1 + (a) + 2\ni = \"g\"\nj = 3 + (f.(i).h) + 1\n"
  },
  {
    "path": "tests/reference_02.failure",
    "content": "a = 1 + (b)\nb = 1 + (a)\n"
  },
  {
    "path": "tests/reference_02.jaxn",
    "content": "{\n   bar: [\n      {\n         i: 42\n      }\n   ],\n   foo: {\n      i: 42\n   }\n}\n"
  },
  {
    "path": "tests/reference_02.success",
    "content": "foo\n{\n    i = 42\n}\nbar\n[\n    (foo)\n]\n"
  },
  {
    "path": "tests/reference_03.failure",
    "content": "a = (b)\nb = (c)\nc = (a)\n"
  },
  {
    "path": "tests/reference_03.jaxn",
    "content": "{\n   baz: [\n      [\n         [\n            {\n               i: 42\n            }\n         ]\n      ]\n   ],\n   foo: {\n      bar: {\n         i: 42\n      }\n   }\n}\n"
  },
  {
    "path": "tests/reference_03.success",
    "content": "foo\n{\n    bar\n    {\n        i = 42\n    }\n}\nbaz\n[ [ [\n    (foo.bar)\n] ] ]\n"
  },
  {
    "path": "tests/reference_04.failure",
    "content": "a = [ 0 1 2 ]\nb = (a.3)\n"
  },
  {
    "path": "tests/reference_05.failure",
    "content": "a = (c)\n"
  },
  {
    "path": "tests/reference_06.failure",
    "content": "a\n{\n    a\n    {\n        b = 1\n    }\n    b\n    {\n        c = (a.a)\n    }\n}\n"
  },
  {
    "path": "tests/reference_07.failure",
    "content": "a\n{\n    b\n    {\n        c = (a)\n    }\n}\n"
  },
  {
    "path": "tests/reference_08.failure",
    "content": "a = null\nb = ((a))\n"
  },
  {
    "path": "tests/reference_09.failure",
    "content": "a = []\nb = ((a))\n"
  },
  {
    "path": "tests/reference_10.failure",
    "content": "foo\n[\n]\nbaz\n[\n    (foo.bar)\n]\n"
  },
  {
    "path": "tests/reference_11.failure",
    "content": "a.b.c = (b.x)\na.b.x = (b.c)\n"
  },
  {
    "path": "tests/reference_12.failure",
    "content": "a = ((y))\ny = ((a))\n"
  },
  {
    "path": "tests/regression_01.jaxn",
    "content": "{\n   foo: {\n      interface: {\n         ip: \"127.0.0.1\"\n      }\n   }\n}\n"
  },
  {
    "path": "tests/regression_01.success",
    "content": "(temporary tmp)\n\ntmp =\n{\n    ip = \"127.0.0.1\"\n}\n\nfoo\n{\n    interface\n    {\n        ip = (tmp.ip)\n    }\n}\n\nfoo\n{\n    interface\n    {\n    }\n}\n"
  },
  {
    "path": "tests/regression_02.jaxn",
    "content": "{\n   foo: {\n      interface: {\n         ip: \"127.0.0.1\"\n      }\n   }\n}\n"
  },
  {
    "path": "tests/regression_02.success",
    "content": "(temporary tmp)\n\ntmp\n{\n    ip = \"127.0.0.1\"\n}\n\nfoo\n{\n    interface\n    {\n        ip = (tmp.ip)\n    }\n}\n\nfoo\n{\n}\n"
  },
  {
    "path": "tests/regression_03.jaxn",
    "content": "{\n   a: {\n      b: [\n         2\n      ]\n   },\n   c: {\n      d: [\n         2\n      ]\n   }\n}\n"
  },
  {
    "path": "tests/regression_03.success",
    "content": "a\n{\n    b = [ 1 ]\n}\n\na\n{\n    b = [ 2 ]\n}\n\nc.d = [ 1 ]\nc.d = [ 2 ]\n"
  },
  {
    "path": "tests/regression_04.jaxn",
    "content": "{\n   a: {\n      b: 42\n   },\n   c: {\n      b: 42,\n      d: 1,\n      x: {\n         a: 90\n      }\n   },\n   e: {\n      f: 43\n   },\n   g: {\n      f: 43,\n      h: 2,\n      x: {\n         a: 91\n      }\n   },\n   h: {\n      i: 44\n   },\n   j: {\n      i: 44,\n      k: 3,\n      x: {\n         a: 92\n      }\n   },\n   l: {\n      m: {\n         n: 45\n      }\n   },\n   o: {\n      m: {\n         n: 45\n      },\n      p: {\n         q: 4\n      },\n      x: {\n         a: 93\n      }\n   }\n}\n"
  },
  {
    "path": "tests/regression_04.success",
    "content": "a.b = 42\nc = (a)\nc.d += 1\nc.x.a = 90\n\ne.f = 43\ng = (e)\ng.h = 2\ng.x.a = 91\n\nh.i = 44\nj = (h)\nj += { k = 3 }\nj.x.a = 92\n\nl.m.n = 45\no = (l)\no.p.q = 4\no.x.a = 93\n"
  },
  {
    "path": "tests/regression_05.jaxn",
    "content": "{\n   a: {\n      b: 1,\n      c: {\n         b: 2,\n         d: {\n            x: 2,\n            y: 3\n         }\n      },\n      e: 3\n   }\n}\n"
  },
  {
    "path": "tests/regression_05.success",
    "content": "a {\n  b = 1\n  e = 3\n\n  c {\n    b = 2\n\n    d {\n      x = (b)\n      y = (e)\n    }\n  }\n}\n"
  },
  {
    "path": "tests/regression_06.jaxn",
    "content": "{\n   a: {\n      b: 42\n   },\n   c: {\n      b: 42\n   },\n   d: 42\n}\n"
  },
  {
    "path": "tests/regression_06.success",
    "content": "a.b = 42\nc = (a)\nd = (c.b)\n"
  },
  {
    "path": "tests/regression_07.jaxn",
    "content": "{\n   a: {\n      b: {\n         c: 8,\n         d: {\n            e: 13\n         }\n      }\n   }\n}\n"
  },
  {
    "path": "tests/regression_07.success",
    "content": "a = {\n    b = {\n        c = 1\n        d = {\n            e = 4\n        }\n    }\n}\n\na.b.c += 7\na.b.d.e += 9\n"
  },
  {
    "path": "tests/regression_08.jaxn",
    "content": "{\n   bar: {\n      baz: {\n         a: 11,\n         b: 3\n      }\n   },\n   foo: {\n      a: 1,\n      b: 2\n   }\n}\n"
  },
  {
    "path": "tests/regression_08.success",
    "content": "foo\n{\n   a = 1\n   b = 2\n}\n\nbar\n{\n   baz = (foo) +\n   {\n      a += 10\n      b = 3\n   }\n}\n"
  },
  {
    "path": "tests/regression_09.jaxn",
    "content": "{\n   bar: {\n      m: 3,\n      n: 1\n   },\n   baz: 3,\n   foo: {\n      n: 1\n   }\n}\n"
  },
  {
    "path": "tests/regression_09.success",
    "content": "foo.n = 1\nbar = (foo)\nbaz = 3\nbar.m = (baz)\n"
  },
  {
    "path": "tests/regression_10.jaxn",
    "content": "{\n   d: {\n      e: {\n         f: 42\n      }\n   }\n}\n"
  },
  {
    "path": "tests/regression_10.success",
    "content": "a.b.c = delete\na.b.c = delete\n\nd.e.f = 42\n\nd.e.g.h.i = delete\nd.e.g.h.i = delete\n"
  },
  {
    "path": "tests/regression_11.jaxn",
    "content": "{}\n"
  },
  {
    "path": "tests/regression_11.success",
    "content": "(temporary a.a)\n\n(permanent b.a)\n\n(temporary c.a)\n(temporary c.a)\n\n(permanent d.a)\n(permanent d.a)\n\n(permanent e.a)\n(temporary e.a)\n\n(temporary f.a)\n(permanent f.a)\n\n(temporary g.a)\n(permanent g.a)\n(temporary g.a)\n(permanent g.a)\n\nh = 1\ni = 2\n\n(permanent h)\nh = delete\n\n(temporary i)\ni = delete\n(permanent i)\n"
  },
  {
    "path": "tests/regression_12.jaxn",
    "content": "{\n   a: {\n      b: {\n         d: 1\n      }\n   },\n   b: {\n      c: {\n         e: 2\n      }\n   },\n   c: {\n      d: {\n         g: 3\n      }\n   }\n}\n"
  },
  {
    "path": "tests/regression_12.success",
    "content": "a.b.c.d.e = delete\na.b.d = 1\n\n(temporary b.c.d.e.f)\nb.c.e = 2\n\n(permanent c.d.e.f.g)\nc.d.g = 3\n"
  },
  {
    "path": "tests/regression_13.failure",
    "content": "foo = [ 0 ]\nfoo.0 = delete\nbar = (foo.0)\n"
  },
  {
    "path": "tests/scoping.jaxn",
    "content": "{\n   h: {\n      i: {\n         j: {\n            k: 43,\n            m: 43\n         },\n         l: 43\n      },\n      n: 43\n   }\n}\n"
  },
  {
    "path": "tests/scoping.success",
    "content": "h {\n    i {\n        j {\n            k = 43\n        }\n        l = (j.k)\n        j.m = (k)\n    }\n    n = (h.i.j.k)\n}\n"
  },
  {
    "path": "tests/serialise.jaxn",
    "content": "{\n   str: \"{b1:true,b2:\\\"Hello, Test!\\\",b3:[$00,$DEADBEEF],b4:42}\"\n}\n"
  },
  {
    "path": "tests/serialise.success",
    "content": "(temporary foo)\n\nfoo\n{\n    b1 = true\n    b2 = \"Hello, Test!\"\n    b3 = [ $00, $deadbeef ]\n    b4 = 42\n}\n\nstr = (print (foo))\n"
  },
  {
    "path": "tests/shell.jaxn",
    "content": "{\n   shell: {\n      a: \"hallo\\n\"\n   }\n}\n"
  },
  {
    "path": "tests/shell.success",
    "content": "shell\n{\n    a = (shell \"echo hallo\")\n}\n"
  },
  {
    "path": "tests/simple.jaxn",
    "content": "{\n   simple: 42\n}\n"
  },
  {
    "path": "tests/simple.success",
    "content": "simple = 42\n"
  },
  {
    "path": "tests/space.jaxn",
    "content": "{}"
  },
  {
    "path": "tests/space.success",
    "content": "\n\n"
  },
  {
    "path": "tests/star_01.jaxn",
    "content": "{\n   t1: {\n      a: {\n         b: {\n            c: {\n               x: 3,\n               y: 3,\n               z: 2\n            }\n         }\n      }\n   },\n   t2: {\n      a: {\n         b: {\n            c: {\n               x: 1,\n               y: 3,\n               z: 2\n            }\n         }\n      }\n   },\n   t3: {\n      a: {\n         b: {\n            c: {\n               x: \"21\",\n               y: \"12\",\n               z: \"2\"\n            }\n         }\n      }\n   },\n   t4: {\n      a: {\n         b: {\n            c: {\n               x: \"1\",\n               y: \"12\",\n               z: \"2\"\n            }\n         }\n      }\n   }\n}\n"
  },
  {
    "path": "tests/star_01.success",
    "content": "t1\n{\n    a.b.c.x = 2\n    a.b.c.* += 1\n    a.b.c.y += 2\n    a.b.c.z = 2\n}\n\nt2\n{\n    a.b.c.x = 2\n    a.b.c.* = 1\n    a.b.c.y += 2\n    a.b.c.z = 2\n}\n\nt3\n{\n    a.b.c.x = \"2\"\n    a.b.c.* += \"1\"\n    a.b.c.y += \"2\"\n    a.b.c.z = \"2\"\n}\n\nt4\n{\n    a.b.c.x = \"2\"\n    a.b.c.* = \"1\"\n    a.b.c.y += \"2\"\n    a.b.c.z = \"2\"\n}\n"
  },
  {
    "path": "tests/star_02.jaxn",
    "content": "{\n   foo: {\n      a: [\n         \"10\",\n         \"20\",\n         \"30\",\n         \"06\",\n         \"07\",\n         \"08\"\n      ]\n   }\n}\n"
  },
  {
    "path": "tests/star_02.success",
    "content": "foo.a += [ \"1\" \"2\" \"3\" ]\nfoo.a.* += \"0\"\nfoo.a += [ \"6\" \"7\" \"8\" ]\n"
  },
  {
    "path": "tests/star_03.jaxn",
    "content": "{\n   a: {\n      b: {\n         c: {\n            i: 3\n         }\n      }\n   },\n   f: {}\n}\n"
  },
  {
    "path": "tests/star_03.success",
    "content": "f = {}\n\na\n{\n   b\n   {\n      c\n      {\n          i += 1\n      }\n   }\n} + (f) + {\n   b\n   {\n       c\n       {\n           i += 1\n       }\n   } + (f) + {\n       c\n       {\n       }\n   }\n}\n\na.*.*.* += 1\n"
  },
  {
    "path": "tests/string_01.failure",
    "content": "foo = (split 42)\n"
  },
  {
    "path": "tests/string_02.failure",
    "content": "foo = (env $ff)\n"
  },
  {
    "path": "tests/temporary_01.jaxn",
    "content": "{\n   c: {\n      d: {}\n   },\n   f: {\n      g: {}\n   },\n   foo: {\n      bar: {\n         c: {\n            d: {}\n         },\n         f: {\n            g: {}\n         }\n      },\n      baz: [\n         {\n            c: {\n               d: {}\n            },\n            f: {\n               g: {}\n            }\n         }\n      ]\n   }\n}\n"
  },
  {
    "path": "tests/temporary_01.success",
    "content": "(temporary a)\na = 1\n\nb = 2\n(temporary b)\n\n(temporary c.d.e)\nc.d.e = 3\n\nf.g.h = 4\n(temporary f.g.h)\n\ni = 5\n(temporary i)\ni = 6\n\nj += 7\n(temporary j)\nj += 8\n\n(temporary k)\n(temporary l.m)\n\nfoo.bar\n{\n    (temporary a)\n    a = 1\n\n    b = 2\n    (temporary b)\n\n    (temporary c.d.e)\n    c.d.e = 3\n\n    f.g.h = 4\n    (temporary f.g.h)\n\n    i = 5\n    (temporary i)\n    i = 6\n\n    j += 7\n    (temporary j)\n    j += 8\n\n    (temporary k)\n    (temporary l.m)\n}\n\nfoo.baz\n[ {\n    (temporary a)\n    a = 1\n\n    b = 2\n    (temporary b)\n\n    (temporary c.d.e)\n    c.d.e = 3\n\n    f.g.h = 4\n    (temporary f.g.h)\n\n    i = 5\n    (temporary i)\n    i = 6\n\n    j += 7\n    (temporary j)\n    j += 8\n\n    (temporary k)\n    (temporary l.m)\n} ]\n"
  },
  {
    "path": "tests/temporary_02.jaxn",
    "content": "{\n   dst: {\n      bar: {\n         i: 42\n      }\n   }\n}\n"
  },
  {
    "path": "tests/temporary_02.success",
    "content": "(temporary foo)\n(temporary foo.baz)\n\nfoo\n{\n    bar\n    {\n        i = 42\n    }\n    baz\n    {\n        j = 43\n    }\n}\n\ndst = (foo)\n"
  },
  {
    "path": "tests/temporary_03.jaxn",
    "content": "{\n   d: 1,\n   e: 2,\n   f: 3,\n   g: 4,\n   h: 5\n}\n"
  },
  {
    "path": "tests/temporary_03.success",
    "content": "(temporary a)\n(permanent a)\n\n(permanent b)\n\n(permanent c)\n(temporary c)\n\n(temporary d)\n(permanent d)\nd = 1\n\n(temporary e)\ne = 2\n(permanent e)\n\nf = 3\n(temporary f)\n(permanent f)\n\n(permanent g)\ng = 4\n\nh = 5\n(permanent h)\n\n(permanent i)\n(temporary i)\ni = 6\n\n(permanent j)\nj = 7\n(temporary j)\n\nk = 8\n(permanent k)\n(temporary k)\n"
  },
  {
    "path": "tests/temporary_04.jaxn",
    "content": "{\n   bar: {\n      a: [],\n      b: []\n   },\n   foo: {\n      a: {},\n      b: {  // TODO: Fix code -- b should be an empty object.\n         c: 1,\n         d: 2,\n         e: [\n            3\n         ]\n      }\n   }\n}\n"
  },
  {
    "path": "tests/temporary_04.success",
    "content": "foo.a\n{\n    c = 1\n    d = 2\n    e = [ 3 ]\n}\n\n(temporary foo.*.*)\n\nfoo.b\n{\n    c = 1\n    d = 2\n    e = [ 3 ]\n}\n\nbar.a\n[\n    true\n    false\n    null\n]\n\n(temporary bar.*.*)\n\nbar.b\n[\n    true\n    false\n    null\n]\n"
  },
  {
    "path": "tests/temporary_05.jaxn",
    "content": "{\n   bar: {},\n   foo: {}\n}\n"
  },
  {
    "path": "tests/temporary_05.success",
    "content": "foo.a\n{\n    c = 1\n}\n\n(temporary foo.*)\n\nfoo.b\n{\n    c = 1\n}\n\nbar.a\n[\n    true\n]\n\n(temporary bar.*)\n\nbar.b\n[\n    true\n]\n"
  },
  {
    "path": "tests/unready.jaxn",
    "content": "{\n   a1: 1,\n   a2: 1,\n   a3: 3,\n   a4: 1,\n   b2: 3,\n   b4: 3,\n   c1: 1,\n   c2: 1,\n   c3: 3,\n   c4: 1,\n   d1: \"nu\",\n   d2: null,\n   d3: \"ll\",\n   e1: \"nu\",\n   e2: [\n      \"null\"\n   ],\n   e3: \"ll\",\n   f1: \"asdlfjaslj\",\n   f2: \"default\",\n   f3: \"x,cqokxi2$(&!\"\n}\n"
  },
  {
    "path": "tests/unready.success",
    "content": "a1 = 1\na2 = (default null (a1) (a3))\na3 = 3\na4 = (a2)\n\nb2 = (default null 1 + 2)\nb4 = (b2)\n\nc1 = (default null 1)\nc2 = (default null (c1) (c3))\nc3 = (default null 3)\nc4 = (c2)\n\nd1 = \"nu\"\nd2 = (parse (d1) + (d3))\nd3 = \"ll\"\n\ne1 = \"nu\"\ne2 = (split (e1) + (e3))\ne3 = \"ll\"\n\nf1 = \"asdlfjaslj\"\nf2 = (env? (f1) + (f3) \"default\")\nf3 = \"x,cqokxi2$(&!\"\n"
  }
]