├── .clang-format ├── .cmake └── taocpp-config-config.cmake.in ├── .codecov.yml ├── .github └── workflows │ ├── clang-analyze.yml │ ├── clang-format.yml │ ├── clang-tidy.yml │ ├── code-coverage.yml │ ├── codeql-analysis.yml │ ├── linux.yml │ ├── macos.yml │ ├── sanitizer.yml │ └── windows.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── doc ├── All-Config-Functions.md ├── Changelog.md ├── Parsing-Config-Files.md ├── README.md └── Writing-Config-Files.md ├── include └── tao │ ├── config.hpp │ └── config │ ├── access.hpp │ ├── annotation.hpp │ ├── assign.hpp │ ├── contrib │ └── rot13.hpp │ ├── from_file.hpp │ ├── from_files.hpp │ ├── from_input.hpp │ ├── from_string.hpp │ ├── internal │ ├── array.hpp │ ├── atom.hpp │ ├── change_action_and_states.hpp │ ├── concat.hpp │ ├── config_action.hpp │ ├── config_grammar.hpp │ ├── config_parser.hpp │ ├── constants.hpp │ ├── debug_traits.hpp │ ├── entry.hpp │ ├── entry_kind.hpp │ ├── events_from_value.hpp │ ├── forward.hpp │ ├── function_implementations.hpp │ ├── function_traits.hpp │ ├── function_wrapper.hpp │ ├── jaxn_action.hpp │ ├── jaxn_to_entry.hpp │ ├── json.hpp │ ├── key1.hpp │ ├── key1_action.hpp │ ├── key1_grammar.hpp │ ├── key1_guard.hpp │ ├── key1_kind.hpp │ ├── key1_part.hpp │ ├── key_action.hpp │ ├── key_grammar.hpp │ ├── limits.hpp │ ├── object.hpp │ ├── parse_utility.hpp │ ├── pegtl.hpp │ ├── phase1_append.hpp │ ├── phase1_mode.hpp │ ├── phase2_access.hpp │ ├── phase2_additions.hpp │ ├── phase2_asterisks.hpp │ ├── phase2_everything.hpp │ ├── phase2_functions.hpp │ ├── phase2_references.hpp │ ├── phase3_remove.hpp │ ├── phase5_repack.hpp │ ├── reference2.hpp │ ├── reference2_action.hpp │ ├── reference2_grammar.hpp │ ├── reference2_kind.hpp │ ├── reference2_part.hpp │ ├── repack_traits.hpp │ ├── state.hpp │ ├── statistics.hpp │ ├── string_utility.hpp │ ├── system_utility.hpp │ └── to_stream.hpp │ ├── key.hpp │ ├── key_kind.hpp │ ├── key_part.hpp │ ├── parser.hpp │ ├── to_stream.hpp │ ├── traits.hpp │ └── value.hpp ├── src ├── example │ └── config │ │ ├── CMakeLists.txt │ │ ├── dump_all_phases.cpp │ │ ├── dump_only_data.cpp │ │ ├── dump_phase_one.cpp │ │ ├── dump_phase_three.cpp │ │ ├── dump_phase_two.cpp │ │ ├── dump_with_meta.cpp │ │ └── try_catch.hpp └── test │ └── config │ ├── CMakeLists.txt │ ├── access.cpp │ ├── assign.cpp │ ├── custom.cpp │ ├── debug_traits.cpp │ ├── enumerations.cpp │ ├── failure.cpp │ ├── independence.cpp │ ├── key.cpp │ ├── key_part.cpp │ ├── main.hpp │ ├── multi_line_string_position.cpp │ ├── parse_key.cpp │ ├── parse_key1.cpp │ ├── parse_reference2.cpp │ ├── setenv.hpp │ ├── success.cpp │ ├── test.hpp │ ├── to_stream.cpp │ └── value.cpp └── tests ├── add_01.failure ├── add_02.failure ├── add_03.failure ├── add_04.failure ├── add_05.failure ├── add_06.failure ├── add_07.failure ├── add_08.failure ├── add_09.failure ├── add_10.failure ├── add_11.failure ├── add_12.failure ├── add_13.failure ├── add_14.failure ├── add_15.failure ├── add_16.failure ├── add_17.failure ├── add_18.failure ├── add_19.failure ├── add_20.failure ├── add_21.failure ├── add_22.failure ├── add_23.failure ├── add_24.failure ├── add_25.failure ├── add_26.failure ├── add_27.failure ├── add_28.failure ├── add_29.failure ├── add_30.failure ├── add_31.failure ├── add_32.failure ├── add_33.failure ├── add_34.failure ├── add_35.failure ├── add_36.failure ├── add_37.failure ├── add_38.failure ├── add_39.failure ├── add_40.failure ├── add_41.failure ├── add_42.failure ├── add_43.failure ├── add_44.failure ├── add_45.failure ├── add_46.failure ├── add_47.failure ├── add_48.failure ├── add_number.jaxn ├── add_number.success ├── add_string.jaxn ├── add_string.success ├── array_index_01.jaxn ├── array_index_01.success ├── array_index_02.jaxn ├── array_index_02.success ├── binary.jaxn ├── binary.success ├── braces.jaxn ├── braces.success ├── combo_01.jaxn ├── combo_01.success ├── combo_02.jaxn ├── combo_02.success ├── commas.jaxn ├── commas.success ├── comments.jaxn ├── comments.success ├── complex_01.failure ├── complex_02.failure ├── complex_03.failure ├── debug_traits.config ├── debug_traits.output ├── delete.jaxn ├── delete.success ├── doc_asterisk_01.jaxn ├── doc_asterisk_01.success ├── doc_default.jaxn ├── doc_default.success ├── doc_delete_01.jaxn ├── doc_delete_01.success ├── doc_delete_02.jaxn ├── doc_delete_02.success ├── doc_dotted_names.jaxn ├── doc_dotted_names.success ├── doc_include.inc ├── doc_include.jaxn ├── doc_include.success ├── doc_object_merge_01.jaxn ├── doc_object_merge_01.success ├── doc_references_01.jaxn ├── doc_references_01.success ├── doc_references_02.failure ├── doc_references_03.failure ├── doc_references_05.jaxn ├── doc_references_05.success ├── doc_references_06.jaxn ├── doc_references_06.success ├── doc_temporary.jaxn ├── doc_temporary.success ├── empty.jaxn ├── empty.success ├── env.failure ├── extensions.jaxn ├── extensions.success ├── formats.cbor ├── formats.jaxn ├── formats.json ├── formats.msgpack ├── formats.success ├── formats.txt ├── formats.ubjson ├── include.jaxn ├── include.success ├── jaxn.jaxn ├── jaxn.success ├── merge_number_01.jaxn ├── merge_number_01.success ├── merge_number_02.jaxn ├── merge_number_02.success ├── merge_number_03.jaxn ├── merge_number_03.success ├── merge_number_04.jaxn ├── merge_number_04.success ├── merge_number_05.jaxn ├── merge_number_05.success ├── merge_number_06.jaxn ├── merge_number_06.success ├── merge_number_07.jaxn ├── merge_number_07.success ├── merge_number_08.jaxn ├── merge_number_08.success ├── merge_string_01.jaxn ├── merge_string_01.success ├── merge_string_02.jaxn ├── merge_string_02.success ├── merge_string_03.jaxn ├── merge_string_03.success ├── merge_string_04.jaxn ├── merge_string_04.success ├── merge_string_05.jaxn ├── merge_string_05.success ├── merge_string_06.jaxn ├── merge_string_06.success ├── merge_string_07.jaxn ├── merge_string_07.success ├── merge_string_08.jaxn ├── merge_string_08.success ├── numbers.jaxn ├── numbers.success ├── quoted.jaxn ├── quoted.success ├── reference_01.failure ├── reference_01.jaxn ├── reference_01.success ├── reference_02.failure ├── reference_02.jaxn ├── reference_02.success ├── reference_03.failure ├── reference_03.jaxn ├── reference_03.success ├── reference_04.failure ├── reference_05.failure ├── reference_06.failure ├── reference_07.failure ├── reference_08.failure ├── reference_09.failure ├── reference_10.failure ├── reference_11.failure ├── reference_12.failure ├── regression_01.jaxn ├── regression_01.success ├── regression_02.jaxn ├── regression_02.success ├── regression_03.jaxn ├── regression_03.success ├── regression_04.jaxn ├── regression_04.success ├── regression_05.jaxn ├── regression_05.success ├── regression_06.jaxn ├── regression_06.success ├── regression_07.jaxn ├── regression_07.success ├── regression_08.jaxn ├── regression_08.success ├── regression_09.jaxn ├── regression_09.success ├── regression_10.jaxn ├── regression_10.success ├── regression_11.jaxn ├── regression_11.success ├── regression_12.jaxn ├── regression_12.success ├── regression_13.failure ├── scoping.jaxn ├── scoping.success ├── serialise.jaxn ├── serialise.success ├── shell.jaxn ├── shell.success ├── simple.jaxn ├── simple.success ├── space.jaxn ├── space.success ├── star_01.jaxn ├── star_01.success ├── star_02.jaxn ├── star_02.success ├── star_03.jaxn ├── star_03.success ├── string_01.failure ├── string_02.failure ├── temporary_01.jaxn ├── temporary_01.success ├── temporary_02.jaxn ├── temporary_02.success ├── temporary_03.jaxn ├── temporary_03.success ├── temporary_04.jaxn ├── temporary_04.success ├── temporary_05.jaxn ├── temporary_05.success ├── unready.jaxn └── unready.success /.clang-format: -------------------------------------------------------------------------------- 1 | # the official .clang-format style for https://github.com/taocpp 2 | # 3 | # clang-format -i -style=file $(find . -name '[^.]*.[hc]pp') 4 | 5 | Language: Cpp 6 | Standard: Latest 7 | 8 | AccessModifierOffset: -3 9 | AlignAfterOpenBracket: Align 10 | AlignConsecutiveAssignments: false 11 | AlignConsecutiveDeclarations: false 12 | AlignEscapedNewlinesLeft: false 13 | AlignOperands: true 14 | AlignTrailingComments: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortBlocksOnASingleLine: false 17 | AllowShortCaseLabelsOnASingleLine: false 18 | AllowShortFunctionsOnASingleLine: Empty 19 | AllowShortIfStatementsOnASingleLine: false 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterReturnType: None 22 | AlwaysBreakBeforeMultilineStrings: false 23 | AlwaysBreakTemplateDeclarations: Yes 24 | BinPackArguments: false 25 | BinPackParameters: false 26 | BraceWrapping: 27 | AfterClass: true 28 | AfterControlStatement: false 29 | AfterEnum : true 30 | AfterFunction : true 31 | AfterNamespace : true 32 | AfterStruct : true 33 | AfterUnion : true 34 | AfterExternBlock: true 35 | BeforeCatch : true 36 | BeforeElse : true 37 | IndentBraces : false 38 | SplitEmptyFunction: false 39 | SplitEmptyRecord: false 40 | SplitEmptyNamespace: false 41 | BreakBeforeBinaryOperators: All 42 | BreakBeforeBraces: Custom 43 | BreakBeforeTernaryOperators: false 44 | BreakConstructorInitializers: BeforeColon 45 | BreakInheritanceList: BeforeColon 46 | BreakStringLiterals: false 47 | ColumnLimit: 0 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 50 | ConstructorInitializerIndentWidth: 3 51 | ContinuationIndentWidth: 3 52 | Cpp11BracedListStyle: false 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: true 57 | IncludeBlocks: Preserve 58 | IndentCaseLabels: true 59 | IndentPPDirectives: None 60 | IndentWidth: 3 61 | IndentWrappedFunctionNames: false 62 | KeepEmptyLinesAtTheStartOfBlocks: false 63 | MaxEmptyLinesToKeep: 1 64 | NamespaceIndentation: All 65 | PointerAlignment: Left 66 | ReflowComments: false 67 | SortIncludes: true 68 | SortUsingDeclarations: false 69 | SpaceAfterCStyleCast: false 70 | SpaceAfterTemplateKeyword: false 71 | SpaceBeforeAssignmentOperators: true 72 | SpaceBeforeCpp11BracedList: false 73 | SpaceBeforeCtorInitializerColon: true 74 | SpaceBeforeInheritanceColon: true 75 | SpaceBeforeParens: Never 76 | SpaceBeforeRangeBasedForLoopColon: true 77 | SpaceInEmptyParentheses: false 78 | SpacesBeforeTrailingComments: 2 79 | SpacesInAngles: true 80 | SpacesInCStyleCastParentheses: false 81 | SpacesInParentheses: true 82 | SpacesInSquareBrackets: true 83 | TabWidth: 8 84 | UseTab: Never 85 | -------------------------------------------------------------------------------- /.cmake/taocpp-config-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | find_dependency(taocpp-json @TAOCPP_CONFIG_JSON_MIN_VERSION@ CONFIG) 5 | 6 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") 7 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - src/example/**/* 3 | -------------------------------------------------------------------------------- /.github/workflows/clang-analyze.yml: -------------------------------------------------------------------------------- 1 | name: clang-analyze 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | clang-analyze: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | submodules: recursive 21 | 22 | - run: sudo apt-get install -yq clang-tools 23 | 24 | - run: scan-build cmake -E make_directory build 25 | 26 | - working-directory: build/ 27 | run: scan-build cmake $GITHUB_WORKSPACE 28 | 29 | - working-directory: build/ 30 | run: scan-build cmake --build . 31 | -------------------------------------------------------------------------------- /.github/workflows/clang-format.yml: -------------------------------------------------------------------------------- 1 | name: clang-format 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | clang-format: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | submodules: recursive 21 | 22 | - uses: DoozyX/clang-format-lint-action@v0.13 23 | with: 24 | source: './include ./src' 25 | extensions: 'hpp,cpp' 26 | clangFormatVersion: 13 27 | -------------------------------------------------------------------------------- /.github/workflows/clang-tidy.yml: -------------------------------------------------------------------------------- 1 | name: clang-tidy 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | clang-tidy: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | submodules: recursive 21 | 22 | - run: sudo apt-get install -yq clang-tidy 23 | 24 | - run: find include/ -src/ name '*.hpp' | xargs -I '{}' clang-tidy --quiet '{}' -- --std=c++17 -Iinclude -Iexternal/json/include -Iexternal/PEGTL/include 25 | -------------------------------------------------------------------------------- /.github/workflows/code-coverage.yml: -------------------------------------------------------------------------------- 1 | name: Code Coverage 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | code-coverage: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | with: 20 | submodules: recursive 21 | 22 | - run: cmake -E make_directory build 23 | 24 | - working-directory: build/ 25 | run: cmake $GITHUB_WORKSPACE -DCMAKE_CXX_FLAGS="-coverage" 26 | 27 | - working-directory: build/ 28 | run: cmake --build . 29 | 30 | - working-directory: build/ 31 | run: ctest --output-on-failure 32 | 33 | - working-directory: build/ 34 | run: bash <(curl -s https://codecov.io/bash) 35 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | paths-ignore: 18 | - 'README.md' 19 | - 'doc/**' 20 | pull_request: 21 | # The branches below must be a subset of the branches above 22 | branches: [ main ] 23 | paths-ignore: 24 | - 'README.md' 25 | - 'doc/**' 26 | schedule: 27 | - cron: '31 6 * * 0' 28 | 29 | jobs: 30 | analyze: 31 | name: Analyze 32 | runs-on: ubuntu-latest 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | language: [ 'cpp' ] 38 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 39 | # Learn more: 40 | # 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 41 | 42 | steps: 43 | - name: Checkout repository 44 | uses: actions/checkout@v3 45 | with: 46 | submodules: recursive 47 | 48 | # Initializes the CodeQL tools for scanning. 49 | - name: Initialize CodeQL 50 | uses: github/codeql-action/init@v2 51 | with: 52 | languages: ${{ matrix.language }} 53 | # If you wish to specify custom queries, you can do so here or in a config file. 54 | # By default, queries listed here will override any specified in a config file. 55 | # Prefix the list here with "+" to use these queries and those in the config file. 56 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 57 | 58 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 59 | # If this step fails, then you should remove it and run the build manually (see below) 60 | - name: Autobuild 61 | uses: github/codeql-action/autobuild@v2 62 | 63 | # ℹ️ Command-line programs to run using the OS shell. 64 | # 📚 https://git.io/JvXDl 65 | 66 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 67 | # and modify them (or add more) to build your code if your project 68 | # uses a compiled language 69 | 70 | #- run: | 71 | # make bootstrap 72 | # make release 73 | 74 | - name: Perform CodeQL Analysis 75 | uses: github/codeql-action/analyze@v2 76 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | linux: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | compiler: 19 | - g++-9 20 | - g++-10 21 | - g++-11 22 | - g++-12 23 | - clang++-13 24 | - clang++-14 25 | build_type: [Debug, Release] 26 | 27 | runs-on: ubuntu-latest 28 | 29 | env: 30 | CXX: ${{ matrix.compiler }} 31 | 32 | steps: 33 | - uses: actions/checkout@v3 34 | with: 35 | submodules: recursive 36 | 37 | - run: cmake -E make_directory build 38 | 39 | - working-directory: build/ 40 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 41 | 42 | - working-directory: build/ 43 | run: cmake --build . 44 | 45 | - working-directory: build/ 46 | run: ctest --output-on-failure 47 | 48 | linux-old: 49 | strategy: 50 | fail-fast: false 51 | matrix: 52 | compiler: 53 | - clang++-11 54 | - clang++-12 55 | build_type: [Debug, Release] 56 | 57 | runs-on: ubuntu-latest 58 | 59 | env: 60 | CXX: ${{ matrix.compiler }} 61 | 62 | steps: 63 | - uses: actions/checkout@v3 64 | with: 65 | submodules: recursive 66 | 67 | - run: sudo apt-get update 68 | 69 | - run: sudo apt-get install -y ${{ matrix.compiler }} 70 | 71 | - run: cmake -E make_directory build 72 | 73 | - working-directory: build/ 74 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 75 | 76 | - working-directory: build/ 77 | run: cmake --build . 78 | 79 | - working-directory: build/ 80 | run: ctest --output-on-failure 81 | 82 | linux-clang-extra: 83 | strategy: 84 | fail-fast: false 85 | matrix: 86 | build_type: [Debug, Release] 87 | 88 | runs-on: ubuntu-latest 89 | 90 | env: 91 | CXX: clang++ 92 | 93 | steps: 94 | - uses: actions/checkout@v3 95 | with: 96 | submodules: recursive 97 | 98 | - run: cmake -E make_directory build 99 | 100 | - working-directory: build/ 101 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_CXX_FLAGS="-fms-extensions" 102 | 103 | - working-directory: build/ 104 | run: cmake --build . 105 | 106 | - working-directory: build/ 107 | run: ctest --output-on-failure 108 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | xcode: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | xcode: ['13', '14'] 19 | build_type: [Debug, Release] 20 | 21 | runs-on: macos-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | with: 26 | submodules: recursive 27 | 28 | - uses: maxim-lobanov/setup-xcode@v1 29 | with: 30 | xcode-version: ${{ matrix.xcode }} 31 | 32 | - run: cmake -E make_directory build 33 | 34 | - working-directory: build/ 35 | run: cmake $GITHUB_WORKSPACE 36 | 37 | - working-directory: build/ 38 | run: cmake --build . --config ${{ matrix.build_type }} 39 | 40 | - working-directory: build/ 41 | run: ctest --config ${{ matrix.build_type }} --output-on-failure 42 | -------------------------------------------------------------------------------- /.github/workflows/sanitizer.yml: -------------------------------------------------------------------------------- 1 | name: Sanitizer 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | sanitizer: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | cxx: [g++, clang++] 19 | sanitizer: [address, undefined] 20 | 21 | runs-on: ubuntu-latest 22 | 23 | env: 24 | CXX: ${{ matrix.cxx }} 25 | 26 | steps: 27 | - uses: actions/checkout@v3 28 | with: 29 | submodules: recursive 30 | 31 | - run: cmake -E make_directory build 32 | 33 | - working-directory: build/ 34 | run: cmake $GITHUB_WORKSPACE -DCMAKE_CXX_FLAGS="-fsanitize=${{ matrix.sanitizer }}" 35 | 36 | - working-directory: build/ 37 | run: cmake --build . 38 | 39 | - working-directory: build/ 40 | run: ctest --output-on-failure 41 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - 'README.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | vs2022: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | build_type: [Debug, Release] 19 | 20 | runs-on: windows-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | with: 25 | submodules: recursive 26 | 27 | - run: cmake -E make_directory build 28 | 29 | - shell: bash 30 | working-directory: build/ 31 | run: cmake $GITHUB_WORKSPACE -G "Visual Studio 17 2022" 32 | 33 | - working-directory: build/ 34 | run: cmake --build . --config ${{ matrix.build_type }} 35 | 36 | - working-directory: build/ 37 | run: ctest -C ${{ matrix.build_type }} --output-on-failure 38 | 39 | vs2022-clang: 40 | strategy: 41 | fail-fast: false 42 | matrix: 43 | build_type: [Debug, Release] 44 | 45 | runs-on: windows-latest 46 | 47 | steps: 48 | - uses: actions/checkout@v3 49 | with: 50 | submodules: recursive 51 | 52 | - run: cmake -E make_directory build 53 | 54 | - shell: bash 55 | working-directory: build/ 56 | run: cmake $GITHUB_WORKSPACE -G "Visual Studio 17 2022" -T ClangCL 57 | 58 | - working-directory: build/ 59 | run: cmake --build . --config ${{ matrix.build_type }} 60 | 61 | - working-directory: build/ 62 | run: ctest -C ${{ matrix.build_type }} --output-on-failure 63 | 64 | vs2019: 65 | strategy: 66 | fail-fast: false 67 | matrix: 68 | build_type: [Debug, Release] 69 | 70 | runs-on: windows-2019 71 | 72 | steps: 73 | - uses: actions/checkout@v3 74 | with: 75 | submodules: recursive 76 | 77 | - run: cmake -E make_directory build 78 | 79 | - shell: bash 80 | working-directory: build/ 81 | run: cmake $GITHUB_WORKSPACE -G "Visual Studio 16 2019" 82 | 83 | - working-directory: build/ 84 | run: cmake --build . --config ${{ matrix.build_type }} 85 | 86 | - working-directory: build/ 87 | run: ctest -C ${{ matrix.build_type }} --output-on-failure 88 | 89 | vs2019-clang: 90 | strategy: 91 | fail-fast: false 92 | matrix: 93 | build_type: [Debug, Release] 94 | 95 | runs-on: windows-2019 96 | 97 | steps: 98 | - uses: actions/checkout@v3 99 | with: 100 | submodules: recursive 101 | 102 | - run: cmake -E make_directory build 103 | 104 | - shell: bash 105 | working-directory: build/ 106 | run: cmake $GITHUB_WORKSPACE -G "Visual Studio 16 2019" -T ClangCL 107 | 108 | - working-directory: build/ 109 | run: cmake --build . --config ${{ matrix.build_type }} 110 | 111 | - working-directory: build/ 112 | run: ctest -C ${{ matrix.build_type }} --output-on-failure 113 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | build 3 | private 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/json"] 2 | path = external/json 3 | url = https://github.com/taocpp/json 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8...3.19) 2 | 3 | project(taocpp-config VERSION 1.0.0 LANGUAGES CXX) 4 | 5 | set(TAOCPP_CONFIG_IS_MAIN_PROJECT OFF) 6 | if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 7 | set(TAOCPP_CONFIG_IS_MAIN_PROJECT ON) 8 | endif() 9 | 10 | # installation directories 11 | include(GNUInstallDirs) 12 | 13 | set(TAOCPP_CONFIG_INSTALL_DOC_DIR "${CMAKE_INSTALL_DOCDIR}/tao/config" CACHE STRING "The installation doc directory") 14 | set(TAOCPP_CONFIG_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake" CACHE STRING "The installation cmake directory") 15 | 16 | # define a header-only library 17 | add_library(taocpp-config INTERFACE) 18 | add_library(taocpp::config ALIAS taocpp-config) 19 | target_include_directories(taocpp-config INTERFACE 20 | $ 21 | $ 22 | ) 23 | 24 | # require C++17 25 | target_compile_features(taocpp-config INTERFACE cxx_std_17) 26 | 27 | # find a suitable taoJSON 28 | set(TAOCPP_CONFIG_JSON_MIN_VERSION 1.0.0) 29 | find_package(taocpp-json ${TAOCPP_CONFIG_JSON_MIN_VERSION} QUIET CONFIG) 30 | if(NOT taocpp-json_FOUND) 31 | # if a compatible version of taoJSON is not already installed, build and install it from the submodule directory 32 | message(STATUS "Adding taoJSON as submodule from external/json") 33 | set(TAOCPP_JSON_INSTALL ON) 34 | set(TAOCPP_JSON_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING "Override taoJSON include install directory") 35 | set(TAOCPP_JSON_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_DATAROOTDIR}/json/cmake CACHE STRING "Override taoJSON cmake install directory") 36 | add_subdirectory(external/json) 37 | endif() 38 | 39 | # add taoJSON as a dependency 40 | target_link_libraries(taocpp-config INTERFACE taocpp-json) 41 | 42 | # testing 43 | option(TAOCPP_CONFIG_BUILD_TESTS "Build test programs" ${TAOCPP_CONFIG_IS_MAIN_PROJECT}) 44 | if(TAOCPP_CONFIG_BUILD_TESTS) 45 | enable_testing() 46 | add_subdirectory(src/test/config) 47 | endif() 48 | 49 | # examples 50 | option(TAOCPP_CONFIG_BUILD_EXAMPLES "Build example programs" ${TAOCPP_CONFIG_IS_MAIN_PROJECT}) 51 | if(TAOCPP_CONFIG_BUILD_EXAMPLES) 52 | add_subdirectory(src/example/config) 53 | endif() 54 | 55 | option(TAOCPP_CONFIG_INSTALL "Generate the install target" ${TAOCPP_CONFIG_IS_MAIN_PROJECT}) 56 | if(TAOCPP_CONFIG_INSTALL) 57 | include(CMakePackageConfigHelpers) 58 | 59 | # Make package findable 60 | configure_package_config_file(.cmake/taocpp-config-config.cmake.in ${PROJECT_NAME}-config.cmake 61 | INSTALL_DESTINATION ${TAOCPP_CONFIG_INSTALL_CMAKE_DIR} 62 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 63 | NO_SET_AND_CHECK_MACRO 64 | ) 65 | 66 | # Ignore pointer width differences since this is a header-only library 67 | unset(CMAKE_SIZEOF_VOID_P) 68 | 69 | # Enable version checks in find_package 70 | write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake COMPATIBILITY SameMajorVersion) 71 | 72 | # keep taocpp::config target compatibility 73 | set_target_properties(taocpp-config PROPERTIES EXPORT_NAME config) 74 | 75 | # install and export target 76 | install(TARGETS taocpp-config taocpp-json EXPORT ${PROJECT_NAME}-targets) 77 | install(FILES 78 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake 79 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake 80 | DESTINATION ${TAOCPP_CONFIG_INSTALL_CMAKE_DIR} 81 | ) 82 | install(EXPORT ${PROJECT_NAME}-targets 83 | NAMESPACE taocpp:: 84 | DESTINATION ${TAOCPP_CONFIG_INSTALL_CMAKE_DIR} 85 | ) 86 | 87 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 88 | install(FILES LICENSE DESTINATION ${TAOCPP_CONFIG_INSTALL_DOC_DIR}) 89 | endif() 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-2023 Dr. Colin Hirsch and Daniel Frey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # The Art of C++ 2 | # Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 3 | # Please see LICENSE for license or visit https://github.com/taocpp/config 4 | 5 | .SUFFIXES: 6 | .SECONDARY: 7 | 8 | CXXSTD = -std=c++17 9 | CPPFLAGS ?= -pedantic -Iinclude -Iexternal/json/include -Iexternal/json/external/PEGTL/include 10 | CXXFLAGS ?= -Wall -Wextra -Werror -O3 11 | 12 | HEADERS := $(shell find include -name "*.hpp") 13 | SOURCES := $(shell find src -name '*.cpp') 14 | DEPENDS := $(SOURCES:src/%.cpp=build/dep/%.d) 15 | BINARIES := $(SOURCES:src/%.cpp=build/bin/%) 16 | 17 | UNIT_TESTS := $(filter build/bin/test/%,$(BINARIES)) 18 | 19 | .PHONY: all 20 | all: compile check 21 | 22 | .PHONY: compile 23 | compile: $(BINARIES) 24 | 25 | .PHONY: check 26 | check: $(UNIT_TESTS) 27 | echo $(UNIT_TESTS) 28 | @set -e; for T in $(UNIT_TESTS); do echo $$T; TAO_CONFIG_VAR=hello $$T; done 29 | 30 | .PHONE: clean 31 | clean: 32 | @rm -rf build/* 33 | @find . -name '*~' -delete 34 | 35 | build/dep/%.d: src/%.cpp Makefile 36 | @mkdir -p $(@D) 37 | $(CXX) $(CXXSTD) $(CPPFLAGS) -MM -MQ $@ $< -o $@ 38 | 39 | build/bin/%: src/%.cpp build/dep/%.d 40 | @mkdir -p $(@D) 41 | $(CXX) $(CXXSTD) $(CPPFLAGS) $(CXXFLAGS) $< -o $@ 42 | 43 | ifeq ($(findstring $(MAKECMDGOALS),clean),) 44 | -include $(DEPENDS) 45 | endif 46 | -------------------------------------------------------------------------------- /doc/Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0 4 | 5 | **Not yet released** 6 | 7 | ## Milestones 8 | 9 | Pre-1.0.0 milestones in rough reverse chronological order. 10 | 11 | * Restrict some phase 1 features[^1]. 12 | * Make functions[^2] a phase 2 features. 13 | * Remove schema support (temporarily?). 14 | * Reduce member extensions to the essentials. 15 | * Remove the minus token from config keys. 16 | * Change the semantics of star and move evaluation to phase two. 17 | * Refactor everything in order to simplify the implementation. 18 | * Syntactically turn `delete` into a literal pseudo-value. 19 | * More intuitive semantics requires less knowledge of implementation details. 20 | * Change the semantics to perform nested additions by default. 21 | * Get the interactions between references and additions correct for both arrays and objects. 22 | 23 | ## History 24 | 25 | Development of taoCONFIG started in September 2018 to provide a more expressive config file syntax for [JSON] (or [JAXN]) config files. 26 | 27 | 28 | 29 | Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 30 | 31 | [^1]: Previously "member extensions". 32 | [^2]: Previously "value extensions". 33 | [JAXN]: https://github.com/stand-art/jaxn 34 | [JSON]: https://tools.ietf.org/html/rfc8259 35 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # taoCONFIG Documentation 2 | 3 | * [Project](https://github.com/taocpp/config) 4 | * [Writing Config Files](Writing-Config-Files.md) 5 | * [All Config Functions](All-Config-Functions.md) 6 | * [Parsing Config Files](Parsing-Config-Files.md) 7 | * [Changelog](Changelog.md) 8 | 9 | 10 | 11 | Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 12 | -------------------------------------------------------------------------------- /include/tao/config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_HPP 5 | #define TAO_CONFIG_HPP 6 | 7 | #include "config/key.hpp" 8 | #include "config/value.hpp" 9 | 10 | #include "config/from_file.hpp" 11 | #include "config/from_files.hpp" 12 | #include "config/from_input.hpp" 13 | #include "config/from_string.hpp" 14 | #include "config/to_stream.hpp" 15 | 16 | #include "config/access.hpp" 17 | #include "config/assign.hpp" 18 | 19 | #include "config/parser.hpp" 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/tao/config/access.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_ACCESS_HPP 5 | #define TAO_CONFIG_ACCESS_HPP 6 | 7 | #include 8 | #include 9 | 10 | #include "key.hpp" 11 | #include "value.hpp" 12 | 13 | #include "internal/json.hpp" 14 | #include "internal/string_utility.hpp" 15 | 16 | namespace tao::config 17 | { 18 | template< template< typename... > class Traits > 19 | [[nodiscard]] const json::basic_value< Traits >& access( const json::basic_value< Traits >& v, const key& k ); 20 | 21 | template< template< typename... > class Traits > 22 | [[nodiscard]] const json::basic_value< Traits >& access_name( const json::basic_value< Traits >& v, const std::string& k, const key& p ) 23 | { 24 | if( !v.is_object() ) { 25 | throw std::runtime_error( internal::strcat( "attempt to index non-object with \"", k, "\"" ) ); 26 | } 27 | const auto j = v.get_object().find( k ); 28 | 29 | if( j == v.get_object().end() ) { 30 | throw std::runtime_error( internal::strcat( "object index \"", k, "\" not found" ) ); 31 | } 32 | return access( j->second, p ); 33 | } 34 | 35 | template< template< typename... > class Traits > 36 | [[nodiscard]] const json::basic_value< Traits >& access_index( const json::basic_value< Traits >& v, const std::size_t n, const key& p ) 37 | { 38 | if( !v.is_array() ) { 39 | throw std::runtime_error( internal::strcat( "attempt to index non-array with ", n ) ); 40 | } 41 | if( v.get_array().size() <= n ) { 42 | throw std::runtime_error( internal::strcat( "array index ", n, " out of bounds ", v.get_array().size() ) ); 43 | } 44 | return access( v.get_array()[ n ], p ); 45 | } 46 | 47 | template< template< typename... > class Traits > 48 | [[nodiscard]] const json::basic_value< Traits >& access( const json::basic_value< Traits >& v, const key& k ) 49 | { 50 | if( k.empty() ) { 51 | return v; 52 | } 53 | switch( k[ 0 ].kind() ) { 54 | case key_kind::name: 55 | return access_name( v, k[ 0 ].get_name(), pop_front( k ) ); 56 | case key_kind::index: 57 | return access_index( v, k[ 0 ].get_index(), pop_front( k ) ); 58 | } 59 | throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE 60 | } 61 | 62 | } // namespace tao::config 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /include/tao/config/annotation.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_ANNOTATION_HPP 5 | #define TAO_CONFIG_ANNOTATION_HPP 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "key.hpp" 15 | 16 | namespace tao::config 17 | { 18 | struct annotation 19 | { 20 | config::key key; 21 | json::position position; // TODO: json::position, pegtl::position or TBD config::position? 22 | 23 | annotation() = default; 24 | 25 | annotation( annotation&& ) = default; 26 | annotation& operator=( annotation&& ) = default; 27 | 28 | annotation( const annotation& ) = default; 29 | annotation& operator=( const annotation& ) = default; 30 | 31 | void set_key( config::key k ) noexcept 32 | { 33 | key = std::move( k ); 34 | } 35 | 36 | void set_position( json::position p ) noexcept 37 | { 38 | position = std::move( p ); 39 | } 40 | 41 | void set_position( const pegtl::position& pos ) 42 | { 43 | position.set_position( pos ); 44 | } 45 | 46 | void append_message_extension( std::ostream& o ) const 47 | { 48 | to_stream( o, key ); 49 | o << ' '; 50 | position.append_message_extension( o ); 51 | } 52 | }; 53 | 54 | } // namespace tao::config 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/tao/config/assign.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_ASSIGN_HPP 5 | #define TAO_CONFIG_ASSIGN_HPP 6 | 7 | #include 8 | #include 9 | 10 | #include "key.hpp" 11 | #include "value.hpp" 12 | 13 | #include "internal/json.hpp" 14 | #include "internal/string_utility.hpp" 15 | 16 | namespace tao::config 17 | { 18 | template< template< typename... > class Traits > 19 | [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const key& k ); 20 | 21 | template< template< typename... > class Traits > 22 | [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const std::string& k, const key& p ) 23 | { 24 | if( !v.is_object() ) { 25 | throw std::runtime_error( internal::strcat( "attempt to index non-object with \"", k, "\"" ) ); 26 | } 27 | const auto t = v.get_object().try_emplace( k, json::empty_object ); // TODO: Detect empty_array vs. empty_object? 28 | return assign( t.first->second, p ); 29 | } 30 | 31 | template< template< typename... > class Traits > 32 | [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const std::size_t n, const key& p ) 33 | { 34 | if( !v.is_array() ) { 35 | throw std::runtime_error( internal::strcat( "attempt to index non-array with ", n ) ); 36 | } 37 | if( v.get_array().size() <= n ) { 38 | throw std::runtime_error( internal::strcat( "array index ", n, " out of bounds ", v.get_array().size() ) ); 39 | } 40 | return assign( v.get_array()[ n ], p ); 41 | } 42 | 43 | template< template< typename... > class Traits > 44 | [[nodiscard]] json::basic_value< Traits >& assign( json::basic_value< Traits >& v, const key& k ) 45 | { 46 | if( k.empty() ) { 47 | return v; 48 | } 49 | switch( k[ 0 ].kind() ) { 50 | case key_kind::name: 51 | return assign( v, k[ 0 ].get_name(), pop_front( k ) ); 52 | case key_kind::index: 53 | return assign( v, k[ 0 ].get_index(), pop_front( k ) ); 54 | } 55 | throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE 56 | } 57 | 58 | } // namespace tao::config 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /include/tao/config/contrib/rot13.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_CONTRIB_ROT13_HPP 5 | #define TAO_CONFIG_CONTRIB_ROT13_HPP 6 | 7 | #include 8 | 9 | #include "../internal/atom.hpp" 10 | #include "../internal/pegtl.hpp" 11 | 12 | namespace tao::config 13 | { 14 | [[nodiscard]] inline internal::string_t rot13( const pegtl::position& pos, const std::string& in ) 15 | { 16 | internal::string_t out( in, pos ); 17 | 18 | for( char& c : out.value ) { 19 | if( ( ( 'a' <= c ) && ( c <= 'm' ) ) || ( ( 'A' <= c ) && ( c <= 'M' ) ) ) { 20 | c += 13; 21 | } 22 | else if( ( ( 'n' <= c ) && ( c <= 'z' ) ) || ( ( 'N' <= c ) && ( c <= 'Z' ) ) ) { 23 | c -= 13; 24 | } 25 | } 26 | return out; 27 | } 28 | 29 | } // namespace tao::config 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/tao/config/from_file.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_FROM_FILE_HPP 5 | #define TAO_CONFIG_FROM_FILE_HPP 6 | 7 | #include 8 | #include 9 | 10 | #include "internal/config_parser.hpp" 11 | #include "value.hpp" 12 | 13 | namespace tao::config 14 | { 15 | template< template< typename... > class Traits > 16 | [[nodiscard]] json::basic_value< Traits > basic_from_file( const std::filesystem::path& path ) 17 | { 18 | internal::config_parser c; 19 | c.parse( path ); 20 | return c.finish< Traits >(); 21 | } 22 | 23 | [[nodiscard]] inline value from_file( const std::filesystem::path& path ) 24 | { 25 | return basic_from_file< traits >( path ); 26 | } 27 | 28 | } // namespace tao::config 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/tao/config/from_files.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_FROM_FILES_HPP 5 | #define TAO_CONFIG_FROM_FILES_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "internal/config_parser.hpp" 12 | #include "value.hpp" 13 | 14 | namespace tao::config 15 | { 16 | template< template< typename... > class Traits > 17 | [[nodiscard]] json::basic_value< Traits > basic_from_files( const std::vector< std::filesystem::path >& paths ) 18 | { 19 | internal::config_parser c; 20 | for( const auto& path : paths ) { 21 | c.parse( path ); 22 | } 23 | return c.finish< Traits >(); 24 | } 25 | 26 | [[nodiscard]] inline value from_files( const std::vector< std::filesystem::path >& paths ) 27 | { 28 | return basic_from_files< traits >( paths ); 29 | } 30 | 31 | } // namespace tao::config 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/tao/config/from_input.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_FROM_INPUT_HPP 5 | #define TAO_CONFIG_FROM_INPUT_HPP 6 | 7 | #include 8 | 9 | #include "internal/config_parser.hpp" 10 | #include "internal/pegtl.hpp" 11 | #include "value.hpp" 12 | 13 | namespace tao::config 14 | { 15 | template< template< typename... > class Traits > 16 | [[nodiscard]] json::basic_value< Traits > basic_from_input( pegtl_input_t&& in ) 17 | { 18 | internal::config_parser c; 19 | c.parse( std::move( in ) ); 20 | return c.finish< Traits >(); 21 | } 22 | 23 | [[nodiscard]] inline value from_input( pegtl_input_t&& in ) 24 | { 25 | return basic_from_input< traits >( std::move( in ) ); 26 | } 27 | 28 | } // namespace tao::config 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/tao/config/from_string.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_FROM_STRING_HPP 5 | #define TAO_CONFIG_FROM_STRING_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "internal/config_parser.hpp" 12 | #include "value.hpp" 13 | 14 | namespace tao::config 15 | { 16 | template< template< typename... > class Traits > 17 | [[nodiscard]] json::basic_value< Traits > basic_from_string( const char* data, const std::size_t size, const std::string& source ) 18 | { 19 | internal::config_parser c; 20 | c.parse( data, size, source ); 21 | return c.finish< Traits >(); 22 | } 23 | 24 | template< template< typename... > class Traits > 25 | [[nodiscard]] json::basic_value< Traits > basic_from_string( const std::string_view data, const std::string& source ) 26 | { 27 | return basic_from_string< Traits >( data.data(), data.size(), source ); 28 | } 29 | 30 | [[nodiscard]] inline value from_string( const char* data, const std::size_t size, const std::string& source ) 31 | { 32 | return basic_from_string< traits >( data, size, source ); 33 | } 34 | 35 | [[nodiscard]] inline value from_string( const std::string_view data, const std::string& source ) 36 | { 37 | return from_string( data.data(), data.size(), source ); 38 | } 39 | 40 | } // namespace tao::config 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/tao/config/internal/array.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_ARRAY_HPP 5 | #define TAO_CONFIG_INTERNAL_ARRAY_HPP 6 | 7 | #include 8 | #include 9 | 10 | #include "forward.hpp" 11 | #include "pegtl.hpp" 12 | 13 | namespace tao::config::internal 14 | { 15 | template< typename C > 16 | struct basic_array 17 | { 18 | using data_t = std::list< C >; 19 | 20 | basic_array() = delete; 21 | 22 | explicit basic_array( const pegtl::position& p ) 23 | : position( p ) 24 | {} 25 | 26 | explicit basic_array( const std::string& f, const pegtl::position& p ) 27 | : function( f ), 28 | position( p ) 29 | {} 30 | 31 | basic_array( basic_array&& ) = default; 32 | basic_array( const basic_array& ) = default; 33 | 34 | ~basic_array() = default; 35 | 36 | basic_array& operator=( basic_array&& ) = default; 37 | basic_array& operator=( const basic_array& ) = default; 38 | 39 | [[nodiscard]] const pegtl::position& get_position() const noexcept 40 | { 41 | return position; 42 | } 43 | 44 | std::string function; 45 | std::list< C > array; 46 | pegtl::position position; 47 | }; 48 | 49 | } // namespace tao::config::internal 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/tao/config/internal/atom.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_ATOM_HPP 5 | #define TAO_CONFIG_INTERNAL_ATOM_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "pegtl.hpp" 13 | 14 | namespace tao::config::internal 15 | { 16 | struct null 17 | { 18 | explicit null( const pegtl::position& pos ) 19 | : position( pos ) 20 | {} 21 | 22 | [[nodiscard]] const pegtl::position& get_position() const noexcept 23 | { 24 | return position; 25 | } 26 | 27 | pegtl::position position; 28 | }; 29 | 30 | template< typename T > 31 | struct atom 32 | { 33 | template< typename V > 34 | atom( V&& v, const pegtl::position& pos ) 35 | : value( std::forward< V >( v ) ), 36 | position( pos ) 37 | {} 38 | 39 | [[nodiscard]] const pegtl::position& get_position() const noexcept 40 | { 41 | return position; 42 | } 43 | 44 | T value; 45 | pegtl::position position; 46 | }; 47 | 48 | using boolean = atom< bool >; 49 | using string_t = atom< std::string >; 50 | using binary_t = atom< std::vector< std::byte > >; 51 | 52 | using signed_t = atom< std::int64_t >; 53 | using unsigned_t = atom< std::uint64_t >; 54 | using double_t = atom< double >; 55 | 56 | } // namespace tao::config::internal 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/tao/config/internal/change_action_and_states.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 4 | 5 | #ifndef TAO_CONFIG_INTERNAL_CHANGE_ACTION_AND_STATES_HPP 6 | #define TAO_CONFIG_INTERNAL_CHANGE_ACTION_AND_STATES_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "pegtl.hpp" 14 | 15 | namespace tao::config::internal 16 | { 17 | template< template< typename... > class NewAction, typename... NewStates > 18 | struct change_action_and_states 19 | : pegtl::maybe_nothing 20 | { 21 | template< typename Rule, 22 | pegtl::apply_mode A, 23 | pegtl::rewind_mode M, 24 | template< typename... > 25 | class Action, 26 | template< typename... > 27 | class Control, 28 | std::size_t... Ns, 29 | typename ParseInput, 30 | typename... States > 31 | [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st ) 32 | { 33 | auto t = std::tie( st... ); 34 | const auto pos = in.position(); 35 | if( Control< Rule >::template match< A, M, NewAction, Control >( in, std::get< Ns >( t )... ) ) { 36 | if constexpr( A == pegtl::apply_mode::action ) { 37 | Action< Rule >::success( pos, st... ); 38 | } 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | template< typename Rule, 45 | pegtl::apply_mode A, 46 | pegtl::rewind_mode M, 47 | template< typename... > 48 | class Action, 49 | template< typename... > 50 | class Control, 51 | typename ParseInput, 52 | typename... States > 53 | [[nodiscard]] static bool match( ParseInput& in, States&&... st ) 54 | { 55 | static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" ); 56 | return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... ); 57 | } 58 | }; 59 | 60 | } // namespace tao::config::internal 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/tao/config/internal/concat.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_CONCAT_HPP 5 | #define TAO_CONFIG_INTERNAL_CONCAT_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "constants.hpp" 16 | #include "entry_kind.hpp" 17 | #include "forward.hpp" 18 | #include "json.hpp" 19 | #include "key1.hpp" 20 | #include "pegtl.hpp" 21 | 22 | namespace tao::config::internal 23 | { 24 | template< typename E > 25 | struct basic_concat 26 | { 27 | using data_t = std::list< E >; 28 | using iterator_t = typename std::list< E >::iterator; 29 | 30 | basic_concat() = delete; 31 | 32 | explicit basic_concat( const pegtl::position& p ) 33 | : position( p ) 34 | {} 35 | 36 | basic_concat( basic_concat&& ) = default; 37 | basic_concat( const basic_concat& ) = default; 38 | 39 | ~basic_concat() = default; 40 | 41 | basic_concat& operator=( basic_concat&& ) = default; 42 | basic_concat& operator=( const basic_concat& ) = default; 43 | 44 | [[nodiscard]] bool omit_from_final_result() const noexcept 45 | { 46 | return implicit || temporary || concat.empty(); 47 | } 48 | 49 | template< typename T > 50 | void back_ensure_init( const T k, const pegtl::position& p ) 51 | { 52 | if( concat.empty() ) { 53 | concat.emplace_back( k, p ); 54 | } 55 | else if( concat.back().kind() != T::kind ) { 56 | concat.emplace_back( k, p ); 57 | } 58 | } 59 | 60 | void back_emplace_func( const std::string& name, const pegtl::position& p ) 61 | { 62 | back_ensure_init( array_init, p ); 63 | concat.back().get_array().function = name; 64 | } 65 | 66 | [[nodiscard]] const pegtl::position& get_position() const noexcept 67 | { 68 | return position; 69 | } 70 | 71 | bool remove = false; // Whether generated by += (false) or by = (true), because in the latter case everything that comes before must be removed. 72 | 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. 73 | 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. 74 | 75 | std::uint64_t generation = 0; 76 | 77 | std::list< E > concat; 78 | pegtl::position position; 79 | }; 80 | 81 | } // namespace tao::config::internal 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /include/tao/config/internal/config_parser.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_CONFIG_PARSER_HPP 5 | #define TAO_CONFIG_INTERNAL_CONFIG_PARSER_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config_action.hpp" 14 | #include "config_grammar.hpp" 15 | #include "forward.hpp" 16 | #include "function_implementations.hpp" 17 | #include "function_wrapper.hpp" 18 | #include "json.hpp" 19 | #include "pegtl.hpp" 20 | #include "phase2_everything.hpp" 21 | #include "phase3_remove.hpp" 22 | #include "phase5_repack.hpp" 23 | #include "state.hpp" 24 | 25 | namespace tao::config::internal 26 | { 27 | struct config_parser 28 | { 29 | config_parser() 30 | : fm( { { "binary", wrap( binary_function ) }, 31 | { "default", wrap( default_function ) }, 32 | { "env", wrap( env_function ) }, 33 | { "env?", wrap( env_if_function ) }, 34 | { "jaxn", wrap( jaxn_function ) }, 35 | { "print", wrap( print_function ) }, 36 | { "read", wrap( read_function ) }, 37 | { "shell", wrap( shell_function ) }, 38 | { "split", wrap( split_function ) }, 39 | { "string", wrap( string_function ) } } ) 40 | {} 41 | 42 | config_parser( config_parser&& ) = delete; 43 | config_parser( const config_parser& ) = delete; 44 | 45 | void operator=( config_parser&& ) = delete; 46 | void operator=( const config_parser& ) = delete; 47 | 48 | state st; 49 | function_map fm; 50 | 51 | void parse( pegtl_input_t&& in ) 52 | { 53 | pegtl::parse< rules::config_file, config_action >( in, st, fm ); 54 | } 55 | 56 | void parse( const std::filesystem::path& path ) 57 | { 58 | parse( pegtl::file_input( path ) ); 59 | } 60 | 61 | void parse( const char* data, const std::size_t size, const std::string& source ) 62 | { 63 | parse( pegtl_input_t( data, size, source ) ); 64 | } 65 | 66 | void parse( const std::string_view data, const std::string& source ) 67 | { 68 | parse( data.data(), data.size(), source ); 69 | } 70 | 71 | template< template< typename... > class Traits > 72 | [[nodiscard]] json::basic_value< Traits > finish() 73 | { 74 | phase2_everything( st, fm ); 75 | phase3_remove( st.root ); 76 | return phase5_repack< Traits >( st.root ); 77 | } 78 | }; 79 | 80 | } // namespace tao::config::internal 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/tao/config/internal/constants.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_CONSTANTS_HPP 5 | #define TAO_CONFIG_INTERNAL_CONSTANTS_HPP 6 | 7 | #include "entry_kind.hpp" 8 | 9 | namespace tao::config::internal 10 | { 11 | struct part_asterisk_t 12 | { 13 | explicit constexpr part_asterisk_t( int /*unused*/ ) {} 14 | }; 15 | 16 | struct part_vector_t 17 | { 18 | explicit constexpr part_vector_t( int /*unused*/ ) {} 19 | }; 20 | 21 | constexpr part_asterisk_t part_asterisk{ 0 }; 22 | constexpr part_vector_t part_vector{ 0 }; 23 | 24 | [[nodiscard]] constexpr bool operator<( const part_asterisk_t, const part_asterisk_t ) noexcept 25 | { 26 | return false; 27 | } 28 | 29 | struct array_init_t 30 | { 31 | explicit constexpr array_init_t( int /*unused*/ ) {} 32 | 33 | static constexpr entry_kind kind = entry_kind::ARRAY; 34 | }; 35 | 36 | struct object_init_t 37 | { 38 | explicit constexpr object_init_t( int /*unused*/ ) {} 39 | 40 | static constexpr entry_kind kind = entry_kind::OBJECT; 41 | }; 42 | 43 | struct asterisk_init_t 44 | { 45 | explicit constexpr asterisk_init_t( int /*unused*/ ) {} 46 | 47 | static constexpr entry_kind kind = entry_kind::ASTERISK; 48 | }; 49 | 50 | constexpr array_init_t array_init{ 0 }; 51 | constexpr object_init_t object_init{ 0 }; 52 | constexpr asterisk_init_t asterisk_init{ 0 }; 53 | 54 | } // namespace tao::config::internal 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/tao/config/internal/entry_kind.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_ENTRY_KIND_HPP 5 | #define TAO_CONFIG_INTERNAL_ENTRY_KIND_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace tao::config::internal 13 | { 14 | enum class entry_kind : char 15 | { 16 | NULL_ = 0, 17 | BOOLEAN = 1, 18 | STRING = 2, 19 | BINARY = 3, 20 | SIGNED = 4, 21 | UNSIGNED = 5, 22 | DOUBLE = 6, 23 | ARRAY = 7, 24 | OBJECT = 8, 25 | ASTERISK = 9, 26 | REFERENCE = 10 27 | }; 28 | 29 | [[nodiscard]] constexpr std::string_view to_string( const entry_kind k ) noexcept 30 | { 31 | switch( k ) { 32 | case entry_kind::NULL_: 33 | return "null"; 34 | case entry_kind::BOOLEAN: 35 | return "boolean"; 36 | case entry_kind::STRING: 37 | return "string"; 38 | case entry_kind::BINARY: 39 | return "binary"; 40 | case entry_kind::SIGNED: 41 | return "signed"; 42 | case entry_kind::UNSIGNED: 43 | return "unsigned"; 44 | case entry_kind::DOUBLE: 45 | return "double"; 46 | case entry_kind::ARRAY: 47 | return "array"; 48 | case entry_kind::OBJECT: 49 | return "object"; 50 | case entry_kind::ASTERISK: 51 | return "asterisk"; 52 | case entry_kind::REFERENCE: 53 | return "reference"; 54 | } 55 | std::abort(); 56 | } 57 | 58 | inline std::ostream& operator<<( std::ostream& o, const entry_kind k ) 59 | { 60 | return o << to_string( k ); 61 | } 62 | 63 | } // namespace tao::config::internal 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/tao/config/internal/events_from_value.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_EVENTS_FROM_VALUE_HPP 5 | #define TAO_CONFIG_INTERNAL_EVENTS_FROM_VALUE_HPP 6 | 7 | #include "debug_traits.hpp" 8 | #include "json.hpp" 9 | 10 | namespace tao::config::internal 11 | { 12 | template< typename Consumer, template< typename... > class Traits > 13 | void events_from_value( Consumer& c, const json::basic_value< Traits >& v ) 14 | { 15 | c.begin_object( 2 ); 16 | c.key( "meta" ); 17 | json::events::produce< debug_traits >( c, v.public_base() ); 18 | c.member(); 19 | c.key( "data" ); 20 | json::events::from_value< events_from_value< Consumer, Traits > >( c, v ); 21 | c.member(); 22 | c.end_object( 2 ); 23 | } 24 | 25 | } // namespace tao::config::internal 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/tao/config/internal/forward.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_FORWARD_HPP 5 | #define TAO_CONFIG_INTERNAL_FORWARD_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace tao::config::internal 12 | { 13 | struct entry; 14 | struct state; 15 | 16 | template< typename E > 17 | struct basic_concat; 18 | 19 | using concat = basic_concat< entry >; 20 | 21 | template< typename C > 22 | struct basic_array; 23 | template< typename C > 24 | struct basic_object; 25 | 26 | using array = basic_array< concat >; 27 | using object = basic_object< concat >; 28 | 29 | template< typename, typename > 30 | struct function_traits; 31 | 32 | using function = std::function< bool( entry& ) >; 33 | using function_map = std::map< std::string, function >; 34 | 35 | } // namespace tao::config::internal 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/tao/config/internal/function_traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_FUNCTION_TRAITS_HPP 5 | #define TAO_CONFIG_INTERNAL_FUNCTION_TRAITS_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "array.hpp" 15 | #include "entry.hpp" 16 | #include "forward.hpp" 17 | #include "json.hpp" 18 | #include "key1.hpp" 19 | #include "parse_utility.hpp" 20 | #include "pegtl.hpp" 21 | 22 | namespace tao::config::internal 23 | { 24 | struct arguments_unready 25 | {}; 26 | 27 | template< typename, typename = void > 28 | struct function_traits; 29 | 30 | template<> 31 | struct function_traits< entry > 32 | { 33 | static void put( entry& e, entry&& f ) 34 | { 35 | e = std::move( f ); 36 | } 37 | 38 | static void put( entry& e, const entry& f ) 39 | { 40 | e = f; 41 | } 42 | }; 43 | 44 | template< typename T > 45 | struct function_traits< atom< T > > 46 | { 47 | static void put( entry& e, atom< T >&& v ) 48 | { 49 | e.set_value( std::move( v ) ); 50 | } 51 | 52 | static void put( entry& e, const atom< T >& v ) 53 | { 54 | e.set_value( v ); 55 | } 56 | }; 57 | 58 | [[nodiscard]] inline const entry& function_traits_entry( array& f, const std::size_t i ) 59 | { 60 | assert( f.array.size() > i ); 61 | 62 | auto p = f.array.begin(); 63 | std::advance( p, i ); 64 | 65 | assert( !p->concat.empty() ); 66 | 67 | if( p->concat.size() != 1 ) { 68 | throw arguments_unready(); 69 | } 70 | return p->concat.front(); 71 | } 72 | 73 | template<> 74 | struct function_traits< std::string > 75 | { 76 | [[nodiscard]] static std::string get( array& f, const std::size_t i ) 77 | { 78 | const entry& e = function_traits_entry( f, i ); 79 | 80 | if( e.is_string() ) { 81 | return e.get_string(); 82 | } 83 | if( e.is_binary() ) { 84 | const std::vector< std::byte >& b = e.get_binary(); 85 | const std::string s( reinterpret_cast< const char* >( b.data() ), b.size() ); 86 | if( !json::internal::validate_utf8_nothrow( s ) ) { 87 | throw pegtl::parse_error( "invalid utf-8 in binary data used as string", e.get_position() ); 88 | } 89 | return s; 90 | } 91 | throw pegtl::parse_error( "invalid type for string argument", e.get_position() ); 92 | } 93 | }; 94 | 95 | } // namespace tao::config::internal 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /include/tao/config/internal/function_wrapper.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_FUNCTION_WRAPPER_HPP 5 | #define TAO_CONFIG_INTERNAL_FUNCTION_WRAPPER_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "forward.hpp" 12 | #include "function_traits.hpp" 13 | #include "json.hpp" 14 | #include "pegtl.hpp" 15 | 16 | namespace tao::config::internal 17 | { 18 | [[nodiscard]] inline function wrap( bool ( *x )( entry& e ) ) 19 | { 20 | return function( [ x ]( entry& e ) { 21 | try { 22 | return x( e ); 23 | } 24 | catch( const arguments_unready& ) { 25 | return false; 26 | } 27 | } ); 28 | } 29 | 30 | template< typename R, typename A > 31 | [[nodiscard]] function wrap( R ( *x )( const pegtl::position&, A ) ) 32 | { 33 | static_assert( !std::is_pointer_v< R > ); 34 | static_assert( !std::is_reference_v< R > ); 35 | static_assert( !std::is_same_v< R, void > ); 36 | 37 | return function( [ x ]( entry& e ) { 38 | try { 39 | array& f = e.get_array(); 40 | function_traits< std::decay_t< R > >::put( e, x( f.position, function_traits< std::decay_t< A > >::get( f, 0 ) ) ); 41 | } 42 | catch( const arguments_unready& ) { 43 | return false; 44 | } 45 | return true; 46 | } ); 47 | } 48 | 49 | template< typename R, typename A, typename B > 50 | [[nodiscard]] function wrap( R ( *x )( const pegtl::position&, A, B ) ) 51 | { 52 | static_assert( !std::is_pointer_v< R > ); 53 | static_assert( !std::is_reference_v< R > ); 54 | static_assert( !std::is_same_v< R, void > ); 55 | 56 | return function( [ x ]( entry& e ) { 57 | try { 58 | array& f = e.get_array(); 59 | 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 ) ) ); 60 | } 61 | catch( const arguments_unready& ) { 62 | return false; 63 | } 64 | return true; 65 | } ); 66 | } 67 | 68 | } // namespace tao::config::internal 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /include/tao/config/internal/json.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_JSON_HPP 5 | #define TAO_CONFIG_INTERNAL_JSON_HPP 6 | 7 | #include 8 | 9 | #include 10 | #include // TODO: This might be a problem... 11 | 12 | #include "pegtl.hpp" 13 | 14 | namespace tao::config::internal::rules 15 | { 16 | namespace jaxn = tao::json::jaxn::internal::rules; 17 | 18 | struct wss 19 | : pegtl::star< jaxn::ws > 20 | {}; 21 | 22 | struct wsp 23 | : pegtl::plus< jaxn::ws > 24 | {}; 25 | 26 | } // namespace tao::config::internal::rules 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/tao/config/internal/key1.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY1_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY1_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "key1_action.hpp" 12 | #include "key1_grammar.hpp" 13 | #include "key1_part.hpp" 14 | #include "pegtl.hpp" 15 | 16 | namespace tao::config::internal 17 | { 18 | struct key1 19 | : std::vector< key1_part > 20 | { 21 | key1() = default; 22 | 23 | key1( key1&& ) = default; 24 | key1& operator=( key1&& ) = default; 25 | 26 | ~key1() = default; 27 | 28 | key1( const key1& ) = default; 29 | key1& operator=( const key1& ) = default; 30 | 31 | explicit key1( const std::string& s ) 32 | { 33 | assign( s ); 34 | } 35 | 36 | key1( const std::initializer_list< key1_part >& l ) 37 | : std::vector< key1_part >( l ) 38 | {} 39 | 40 | key1( const std::vector< key1_part >::const_iterator& begin, const std::vector< key1_part >::const_iterator& end ) 41 | : std::vector< key1_part >( begin, end ) 42 | {} 43 | 44 | key1& operator=( const std::string& s ) 45 | { 46 | clear(); 47 | assign( s ); 48 | return *this; 49 | } 50 | 51 | key1& operator=( const std::initializer_list< key1_part >& l ) 52 | { 53 | vector() = l; 54 | return *this; 55 | } 56 | 57 | [[nodiscard]] std::vector< key1_part >& vector() noexcept 58 | { 59 | return static_cast< std::vector< key1_part >& >( *this ); 60 | } 61 | 62 | [[nodiscard]] const std::vector< key1_part >& vector() const noexcept 63 | { 64 | return static_cast< const std::vector< key1_part >& >( *this ); 65 | } 66 | 67 | void assign( const std::string& s ) 68 | { 69 | using grammar = pegtl::must< rules::key1_rule, pegtl::eof >; 70 | pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( s, __FUNCTION__ ); 71 | pegtl::parse< grammar, key1_action >( in, vector() ); 72 | } 73 | }; 74 | 75 | inline key1 pop_front( const key1& p ) 76 | { 77 | assert( !p.empty() ); 78 | 79 | return key1( p.begin() + 1, p.end() ); 80 | } 81 | 82 | inline key1 pop_back( const key1& p ) 83 | { 84 | assert( !p.empty() ); 85 | 86 | return key1( p.begin(), p.end() - 1 ); 87 | } 88 | 89 | inline key1& operator+=( key1& l, const key1& r ) 90 | { 91 | l.insert( l.end(), r.begin(), r.end() ); 92 | return l; 93 | } 94 | 95 | inline key1& operator+=( key1& l, const key1_part& p ) 96 | { 97 | l.emplace_back( p ); 98 | return l; 99 | } 100 | 101 | [[nodiscard]] inline key1 operator+( const key1& l, const key1& r ) 102 | { 103 | key1 t( l ); 104 | t += r; 105 | return t; 106 | } 107 | 108 | [[nodiscard]] inline key1 operator+( const key1& l, const key1_part& r ) 109 | { 110 | key1 t( l ); 111 | t += r; 112 | return t; 113 | } 114 | 115 | } // namespace tao::config::internal 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /include/tao/config/internal/key1_action.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY1_ACTION_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY1_ACTION_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "json.hpp" 13 | #include "key1_grammar.hpp" 14 | #include "key1_part.hpp" 15 | #include "pegtl.hpp" 16 | 17 | namespace tao::config::internal 18 | { 19 | template< typename Rule > 20 | struct key1_action 21 | : pegtl::nothing< Rule > 22 | {}; 23 | 24 | template<> 25 | struct key1_action< rules::ident > 26 | { 27 | template< typename Input > 28 | static void apply( const Input& in, std::vector< key1_part >& st ) 29 | { 30 | st.emplace_back( in.string(), in.position() ); 31 | } 32 | }; 33 | 34 | template<> 35 | struct key1_action< rules::index > 36 | { 37 | template< typename Input > 38 | static void apply( const Input& in, std::vector< key1_part >& st ) 39 | { 40 | st.emplace_back( std::size_t( std::stoul( in.string() ) ), in.position() ); 41 | } 42 | }; 43 | 44 | template<> 45 | struct key1_action< rules::asterisk > 46 | { 47 | template< typename Input > 48 | static void apply( const Input& in, std::vector< key1_part >& st ) 49 | { 50 | st.emplace_back( part_asterisk, in.position() ); 51 | } 52 | }; 53 | 54 | template<> 55 | struct key1_action< rules::quoted_choice > 56 | : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string > 57 | { 58 | template< typename Input > 59 | static void success( const Input& in, std::string& unescaped, std::vector< key1_part >& st ) 60 | { 61 | st.emplace_back( std::move( unescaped ), in.position() ); // TODO: Position from beginning of quoted string instead of end. 62 | } 63 | }; 64 | 65 | } // namespace tao::config::internal 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /include/tao/config/internal/key1_grammar.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY1_GRAMMAR_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY1_GRAMMAR_HPP 6 | 7 | #include "key_grammar.hpp" 8 | #include "pegtl.hpp" 9 | 10 | namespace tao::config::internal::rules 11 | { 12 | // clang-format off 13 | struct asterisk : pegtl::one< '*' > {}; 14 | 15 | struct key1_part : pegtl::sor< ident, quoted, index, asterisk > {}; 16 | struct key1_rule : pegtl::list_must< key1_part, dot > {}; 17 | // clang-format on 18 | 19 | } // namespace tao::config::internal::rules 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/tao/config/internal/key1_guard.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY1_GUARD_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY1_GUARD_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "forward.hpp" 12 | #include "key1.hpp" 13 | #include "pegtl.hpp" 14 | 15 | namespace tao::config::internal 16 | { 17 | class [[nodiscard]] key1_guard 18 | { 19 | public: 20 | key1_guard() = delete; 21 | 22 | template< typename State > 23 | key1_guard( State& st, key1&& suffix ) 24 | : m_prefix( st.prefix ), 25 | m_suffix( st.suffix ), 26 | m_size( m_prefix.size() ) 27 | { 28 | m_prefix += m_suffix; 29 | m_suffix = std::move( suffix ); 30 | } 31 | 32 | template< typename State > 33 | key1_guard( const pegtl_input_t& in, State& st, const function_map& /*unused*/ ) 34 | : m_prefix( st.prefix ), 35 | m_suffix( st.suffix ), 36 | m_size( m_prefix.size() ) 37 | { 38 | m_prefix += m_suffix; 39 | m_suffix.clear(); 40 | m_suffix.emplace_back( in.position(), ++st.generation ); 41 | } 42 | 43 | key1_guard( key1_guard&& ) = delete; 44 | key1_guard( const key1_guard& ) = delete; 45 | 46 | ~key1_guard() 47 | { 48 | assert( m_prefix.size() >= m_size ); 49 | 50 | m_suffix.clear(); 51 | m_suffix.insert( m_suffix.end(), m_prefix.begin() + m_size, m_prefix.end() ); 52 | m_prefix.erase( m_prefix.begin() + m_size, m_prefix.end() ); 53 | } 54 | 55 | void operator=( key1_guard&& ) = delete; 56 | void operator=( const key1_guard& ) = delete; 57 | 58 | private: 59 | key1& m_prefix; 60 | key1& m_suffix; 61 | 62 | const std::size_t m_size; 63 | }; 64 | 65 | } // namespace tao::config::internal 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /include/tao/config/internal/key1_kind.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY1_KIND_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY1_KIND_HPP 6 | 7 | namespace tao::config::internal 8 | { 9 | enum class key1_kind : char 10 | { 11 | name = 0, 12 | index = 1, 13 | asterisk = 2, 14 | append = 3 15 | }; 16 | 17 | } // namespace tao::config::internal 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /include/tao/config/internal/key1_part.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY1_PART_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY1_PART_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "constants.hpp" 15 | #include "key1_kind.hpp" 16 | #include "pegtl.hpp" 17 | 18 | namespace tao::config::internal 19 | { 20 | struct key1_part 21 | { 22 | using data_t = std::variant< std::string, std::size_t, part_asterisk_t, std::shared_ptr< std::uint64_t > >; 23 | 24 | key1_part( const part_asterisk_t t, const pegtl::position& p ) 25 | : position( p ), 26 | data( t ) 27 | {} 28 | 29 | // key1_part( const char, const pegtl::position& ) = delete; 30 | // key1_part( const signed char, const pegtl::position& ) = delete; 31 | // key1_part( const unsigned char, const pegtl::position& ) = delete; 32 | 33 | key1_part( const std::size_t i, const pegtl::position& p ) 34 | : position( p ), 35 | data( i ) 36 | {} 37 | 38 | key1_part( const pegtl::position& p, const std::uint64_t g ) 39 | : position( p ), 40 | data( std::make_shared< std::uint64_t >( g ) ) 41 | {} 42 | 43 | key1_part( const std::string& n, const pegtl::position& p ) 44 | : position( p ), 45 | data( n ) 46 | {} 47 | 48 | [[nodiscard]] key1_kind kind() const noexcept 49 | { 50 | return key1_kind( data.index() ); 51 | } 52 | 53 | [[nodiscard]] std::size_t get_index() const noexcept 54 | { 55 | const auto* s = std::get_if< std::size_t >( &data ); 56 | assert( s != nullptr ); 57 | return *s; 58 | } 59 | 60 | [[nodiscard]] const std::string& get_name() const noexcept 61 | { 62 | const auto* s = std::get_if< std::string >( &data ); 63 | assert( s != nullptr ); 64 | return *s; 65 | } 66 | 67 | void set_generation( const std::uint64_t g ) noexcept 68 | { 69 | assert( g > 0 ); 70 | 71 | if( const auto* s = std::get_if< std::shared_ptr< std::uint64_t > >( &data ) ) { 72 | assert( s != nullptr ); 73 | assert( s->get() != nullptr ); 74 | assert( g > **s ); 75 | **s = g; 76 | } 77 | } 78 | 79 | [[nodiscard]] std::uint64_t get_generation() const noexcept 80 | { 81 | const auto* s = std::get_if< std::shared_ptr< std::uint64_t > >( &data ); 82 | assert( s != nullptr ); 83 | assert( s->get() != nullptr ); 84 | assert( **s > 0 ); 85 | return **s; 86 | } 87 | 88 | pegtl::position position; 89 | data_t data; 90 | }; 91 | 92 | } // namespace tao::config::internal 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /include/tao/config/internal/key_action.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY_ACTION_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY_ACTION_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "json.hpp" 13 | #include "key_grammar.hpp" 14 | #include "pegtl.hpp" 15 | 16 | #include "../key_part.hpp" 17 | 18 | namespace tao::config::internal 19 | { 20 | template< typename Rule > 21 | struct key_action 22 | : pegtl::nothing< Rule > 23 | {}; 24 | 25 | template<> 26 | struct key_action< rules::ident > 27 | { 28 | template< typename Input > 29 | static void apply( const Input& in, std::vector< key_part >& st ) 30 | { 31 | st.emplace_back( in.string() ); 32 | } 33 | }; 34 | 35 | template<> 36 | struct key_action< rules::index > 37 | { 38 | template< typename Input > 39 | static void apply( const Input& in, std::vector< key_part >& st ) 40 | { 41 | st.emplace_back( std::size_t( std::stoul( in.string() ) ) ); 42 | } 43 | }; 44 | 45 | template<> 46 | struct key_action< rules::quoted_choice > 47 | : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string > 48 | { 49 | template< typename Input > 50 | static void success( const Input& /*unused*/, std::string& unescaped, std::vector< key_part >& st ) 51 | { 52 | st.emplace_back( std::move( unescaped ) ); 53 | } 54 | }; 55 | 56 | } // namespace tao::config::internal 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/tao/config/internal/key_grammar.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_KEY_GRAMMAR_HPP 5 | #define TAO_CONFIG_INTERNAL_KEY_GRAMMAR_HPP 6 | 7 | #include "json.hpp" 8 | #include "pegtl.hpp" 9 | 10 | namespace tao::config::internal::rules 11 | { 12 | namespace jaxn = tao::json::jaxn::internal::rules; 13 | 14 | // clang-format off 15 | struct dot : pegtl::one< '.' > {}; 16 | 17 | struct index : pegtl::rep_min_max< 1, 15, pegtl::digit > {}; 18 | 19 | struct ident_first : pegtl::ranges< 'a', 'z', 'A', 'Z', '_' > {}; 20 | struct ident_other : pegtl::ranges< 'a', 'z', 'A', 'Z', '0', '9', '-', '-', '_' > {}; 21 | struct ident : pegtl::seq< ident_first, pegtl::star< ident_other > > {}; 22 | 23 | struct at_quote : pegtl::at< pegtl::one< '\'', '"' > > {}; 24 | 25 | struct quoted_choice : jaxn::string_fragment {}; 26 | struct quoted : pegtl::if_must< at_quote, quoted_choice > {}; 27 | 28 | struct key_other : pegtl::sor< ident, quoted, index > {}; 29 | struct key_first : pegtl::sor< ident, quoted > {}; 30 | 31 | struct key_rule : pegtl::seq< key_first, pegtl::star_must< dot, key_other > > {}; 32 | // clang-format on 33 | 34 | } // namespace tao::config::internal::rules 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/tao/config/internal/limits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_LIMITS_HPP 5 | #define TAO_CONFIG_INTERNAL_LIMITS_HPP 6 | 7 | #include 8 | 9 | namespace tao::config::internal 10 | { 11 | static constexpr std::size_t global_nesting_limit = 96; 12 | 13 | } // namespace tao::config::internal 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/tao/config/internal/object.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_OBJECT_HPP 5 | #define TAO_CONFIG_INTERNAL_OBJECT_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "forward.hpp" 12 | #include "pegtl.hpp" 13 | 14 | namespace tao::config::internal 15 | { 16 | template< typename C > 17 | struct basic_object 18 | { 19 | using data_t = std::map< std::string, C >; 20 | 21 | basic_object() = delete; 22 | 23 | explicit basic_object( const pegtl::position& p ) 24 | : position( p ) 25 | {} 26 | 27 | basic_object( basic_object&& ) = default; 28 | basic_object( const basic_object& ) = default; 29 | 30 | ~basic_object() = default; 31 | 32 | basic_object& operator=( basic_object&& ) = default; 33 | basic_object& operator=( const basic_object& ) = default; 34 | 35 | [[nodiscard]] std::pair< const std::string, C >* find( const std::string& k ) noexcept 36 | { 37 | const auto i = object.find( k ); 38 | return ( i == object.end() ) ? nullptr : ( &*i ); 39 | } 40 | 41 | [[nodiscard]] const std::pair< const std::string, C >* find( const std::string& k ) const noexcept 42 | { 43 | const auto i = object.find( k ); 44 | return ( i == object.end() ) ? nullptr : ( &*i ); 45 | } 46 | 47 | [[nodiscard]] const pegtl::position& get_position() const noexcept 48 | { 49 | return position; 50 | } 51 | 52 | std::map< std::string, C > object; 53 | pegtl::position position; 54 | }; 55 | 56 | } // namespace tao::config::internal 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/tao/config/internal/parse_utility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_PARSE_UTILITY_HPP 5 | #define TAO_CONFIG_INTERNAL_PARSE_UTILITY_HPP 6 | 7 | #include 8 | 9 | #include "forward.hpp" 10 | #include "key1.hpp" 11 | #include "key1_action.hpp" 12 | #include "key1_grammar.hpp" 13 | #include "pegtl.hpp" 14 | #include "reference2.hpp" 15 | #include "reference2_action.hpp" 16 | #include "reference2_grammar.hpp" 17 | 18 | namespace tao::config::internal 19 | { 20 | [[nodiscard]] inline key1 parse_key1( pegtl_input_t& in ) 21 | { 22 | key1 result; 23 | pegtl::parse< pegtl::must< rules::key1_rule >, key1_action >( in, result.vector() ); 24 | return result; 25 | } 26 | 27 | [[nodiscard]] inline reference2 parse_reference2( pegtl_input_t& in ) 28 | { 29 | reference2 result; 30 | pegtl::parse< pegtl::must< rules::reference2_rest >, reference2_action >( in, result.vector() ); // NOTE: Assumes that the opening bracket was already parsed! 31 | return result; 32 | } 33 | 34 | } // namespace tao::config::internal 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/tao/config/internal/pegtl.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_PEGTL_HPP 5 | #define TAO_CONFIG_INTERNAL_PEGTL_HPP 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace tao::pegtl 16 | { 17 | template< typename P > 18 | using invert = internal::predicates< internal::predicate_not_test, typename P::peek_t, P >; 19 | 20 | } // namespace tao::pegtl 21 | 22 | namespace tao::config 23 | { 24 | using pegtl_input_t = pegtl::memory_input< pegtl::tracking_mode::eager, pegtl::eol::lf_crlf >; 25 | 26 | } // namespace tao::config 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/tao/config/internal/phase1_mode.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_PHASE1_MODE_HPP 5 | #define TAO_CONFIG_INTERNAL_PHASE1_MODE_HPP 6 | 7 | namespace tao::config::internal 8 | { 9 | enum class phase1_mode : bool 10 | { 11 | implicit = true, 12 | manifest = false // Can't use explicit as enum label. 13 | }; 14 | 15 | } // namespace tao::config::internal 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/tao/config/internal/phase2_everything.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_PHASE2_EVERYTHING_HPP 5 | #define TAO_CONFIG_INTERNAL_PHASE2_EVERYTHING_HPP 6 | 7 | #include "forward.hpp" 8 | #include "phase2_additions.hpp" 9 | #include "phase2_asterisks.hpp" 10 | #include "phase2_functions.hpp" 11 | #include "phase2_references.hpp" 12 | #include "state.hpp" 13 | 14 | namespace tao::config::internal 15 | { 16 | [[nodiscard]] inline bool phase2_iteration( state& st, const function_map& fm ) 17 | { 18 | return ( phase2_functions( st, fm ) | phase2_additions( st.root ) | phase2_references( st.root ) | phase2_asterisks( st.root ) ) > 0; 19 | } 20 | 21 | inline void phase2_everything( state& st, const function_map& fm ) 22 | { 23 | while( phase2_iteration( st, fm ) ) { 24 | // This loop could do with some major optimisations; probably not worth the effort for config files. 25 | } 26 | } 27 | 28 | } // namespace tao::config::internal 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/tao/config/internal/phase3_remove.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_PHASE3_REMOVE_HPP 5 | #define TAO_CONFIG_INTERNAL_PHASE3_REMOVE_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "array.hpp" 12 | #include "concat.hpp" 13 | #include "entry.hpp" 14 | #include "forward.hpp" 15 | #include "object.hpp" 16 | #include "pegtl.hpp" 17 | #include "string_utility.hpp" 18 | 19 | namespace tao::config::internal 20 | { 21 | inline void phase3_remove( array& a ); 22 | inline void phase3_remove( object& o ); 23 | 24 | inline void phase3_remove( concat& c ) 25 | { 26 | for( auto& e : c.concat ) { 27 | switch( e.kind() ) { 28 | case entry_kind::NULL_: 29 | case entry_kind::BOOLEAN: 30 | case entry_kind::STRING: 31 | case entry_kind::BINARY: 32 | case entry_kind::SIGNED: 33 | case entry_kind::UNSIGNED: 34 | case entry_kind::DOUBLE: 35 | continue; 36 | case entry_kind::ARRAY: 37 | if( !e.get_array().function.empty() ) { 38 | throw pegtl::parse_error( "function '" + e.get_array().function + "' could not be called", e.get_array().position ); 39 | } 40 | phase3_remove( e.get_array() ); 41 | continue; 42 | case entry_kind::OBJECT: 43 | phase3_remove( e.get_object() ); 44 | continue; 45 | case entry_kind::ASTERISK: 46 | throw pegtl::parse_error( "asterisk could not be expanded", e.get_asterisk().position ); // Can happen when there are also unresolved references? 47 | case entry_kind::REFERENCE: 48 | throw pegtl::parse_error( "reference '" + e.get_reference().to_string() + "' could not be resolved", e.get_reference().at( 0 ).position ); 49 | } 50 | throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE 51 | } 52 | } 53 | 54 | inline void phase3_remove( array& a ) 55 | { 56 | auto i = a.array.begin(); 57 | 58 | while( i != a.array.end() ) { 59 | phase3_remove( *i ); 60 | if( i->omit_from_final_result() ) { 61 | i = a.array.erase( i ); 62 | } 63 | else { 64 | ++i; 65 | } 66 | } 67 | } 68 | 69 | inline void phase3_remove( object& o ) 70 | { 71 | auto i = o.object.begin(); 72 | 73 | while( i != o.object.end() ) { 74 | phase3_remove( i->second ); 75 | if( i->second.omit_from_final_result() ) { 76 | i = o.object.erase( i ); 77 | } 78 | else { 79 | ++i; 80 | } 81 | } 82 | } 83 | 84 | } // namespace tao::config::internal 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /include/tao/config/internal/reference2.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_REFERENCE2_HPP 5 | #define TAO_CONFIG_INTERNAL_REFERENCE2_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "reference2_action.hpp" 13 | #include "reference2_grammar.hpp" 14 | #include "reference2_part.hpp" 15 | 16 | namespace tao::config::internal 17 | { 18 | struct reference2 19 | : std::vector< reference2_part > 20 | { 21 | reference2() = default; 22 | 23 | reference2( reference2&& ) = default; 24 | reference2( const reference2& ) = default; 25 | 26 | ~reference2() = default; 27 | 28 | reference2& operator=( reference2&& ) = default; 29 | reference2& operator=( const reference2& ) = default; 30 | 31 | explicit reference2( const std::string& s ) 32 | { 33 | assign( s ); 34 | } 35 | 36 | reference2( const std::initializer_list< reference2_part >& l ) 37 | : std::vector< reference2_part >( l ) 38 | {} 39 | 40 | reference2( const std::vector< reference2_part >::const_iterator& begin, const std::vector< reference2_part >::const_iterator& end ) 41 | : std::vector< reference2_part >( begin, end ) 42 | {} 43 | 44 | reference2& operator=( const std::string& s ) 45 | { 46 | clear(); 47 | assign( s ); 48 | return *this; 49 | } 50 | 51 | reference2& operator=( const std::initializer_list< reference2_part >& l ) 52 | { 53 | vector() = l; 54 | return *this; 55 | } 56 | 57 | [[nodiscard]] std::vector< reference2_part >& vector() noexcept 58 | { 59 | return static_cast< std::vector< reference2_part >& >( *this ); 60 | } 61 | 62 | [[nodiscard]] const std::vector< reference2_part >& vector() const noexcept 63 | { 64 | return static_cast< const std::vector< reference2_part >& >( *this ); 65 | } 66 | 67 | [[nodiscard]] std::string to_string() const 68 | { 69 | return internal::to_string( vector() ); 70 | } 71 | 72 | void assign( const std::string& s ) 73 | { 74 | using grammar = pegtl::must< rules::reference2_rule, pegtl::eof >; 75 | pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( s, __FUNCTION__ ); 76 | pegtl::parse< grammar, reference2_action >( in, vector() ); 77 | } 78 | 79 | [[nodiscard]] const pegtl::position& get_position() const noexcept 80 | { 81 | assert( !vector().empty() ); 82 | return vector()[ 0 ].position; 83 | } 84 | }; 85 | 86 | } // namespace tao::config::internal 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/tao/config/internal/reference2_action.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_REFERENCE2_ACTION_HPP 5 | #define TAO_CONFIG_INTERNAL_REFERENCE2_ACTION_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "json.hpp" 12 | #include "pegtl.hpp" 13 | #include "reference2_grammar.hpp" 14 | #include "reference2_part.hpp" 15 | 16 | namespace tao::config::internal 17 | { 18 | template< typename Rule > 19 | struct reference2_action 20 | : pegtl::nothing< Rule > 21 | {}; 22 | 23 | template<> 24 | struct reference2_action< rules::ident > 25 | { 26 | template< typename Input > 27 | static void apply( const Input& in, std::vector< reference2_part >& st ) 28 | { 29 | st.emplace_back( in.string(), in.position() ); 30 | } 31 | }; 32 | 33 | template<> 34 | struct reference2_action< rules::index > 35 | { 36 | template< typename Input > 37 | static void apply( const Input& in, std::vector< reference2_part >& st ) 38 | { 39 | st.emplace_back( std::stoul( in.string() ), in.position() ); 40 | } 41 | }; 42 | 43 | template<> 44 | struct reference2_action< rules::quoted_choice > 45 | : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string > 46 | { 47 | template< typename Input > 48 | static void success( const Input& in, std::string& unescaped, std::vector< reference2_part >& st ) 49 | { 50 | st.emplace_back( std::move( unescaped ), in.position() ); // TODO: Position from beginning of quoted string instead of end. 51 | } 52 | }; 53 | 54 | template<> 55 | struct reference2_action< rules::reference2_must > 56 | : pegtl::nothing< rules::reference2_must > 57 | { 58 | template< typename Rule, 59 | pegtl::apply_mode A, 60 | pegtl::rewind_mode M, 61 | template< typename... > 62 | class Action, 63 | template< typename... > 64 | class Control, 65 | typename ParseInput > 66 | [[nodiscard]] static bool match( ParseInput& in, std::vector< reference2_part >& st ) 67 | { 68 | st.emplace_back( part_vector, in.position() ); 69 | return pegtl::match< Rule, A, M, Action, Control >( in, st.back().get_vector() ); 70 | } 71 | }; 72 | 73 | } // namespace tao::config::internal 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /include/tao/config/internal/reference2_grammar.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_REFERENCE2_GRAMMAR_HPP 5 | #define TAO_CONFIG_INTERNAL_REFERENCE2_GRAMMAR_HPP 6 | 7 | #include "key_grammar.hpp" 8 | #include "pegtl.hpp" 9 | 10 | namespace tao::config::internal::rules 11 | { 12 | struct reference2_must; 13 | 14 | // clang-format off 15 | struct reference2_part : pegtl::sor< ident, quoted, index, reference2_must > {}; 16 | struct reference2_list : pegtl::list_must< reference2_part, dot > {}; 17 | struct reference2_rest : pegtl::seq< reference2_list, pegtl::one< ')' > > {}; // For config_grammar.hpp -- used without actions. 18 | struct reference2_must : pegtl::if_must< pegtl::one< '(' >, reference2_list, pegtl::one< ')' > > {}; 19 | struct reference2_rule : pegtl::if_must< pegtl::one< '(' >, reference2_list, pegtl::one< ')' > > {}; 20 | // clang-format on 21 | 22 | } // namespace tao::config::internal::rules 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/tao/config/internal/reference2_kind.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_REFERENCE2_KIND_HPP 5 | #define TAO_CONFIG_INTERNAL_REFERENCE2_KIND_HPP 6 | 7 | namespace tao::config::internal 8 | { 9 | enum class reference2_kind : char 10 | { 11 | name = 0, 12 | index = 1, 13 | vector = 2 14 | }; 15 | 16 | } // namespace tao::config::internal 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/tao/config/internal/reference2_part.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_REFERENCE2_PART_HPP 5 | #define TAO_CONFIG_INTERNAL_REFERENCE2_PART_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "constants.hpp" 16 | #include "pegtl.hpp" 17 | #include "reference2_kind.hpp" 18 | 19 | namespace tao::config::internal 20 | { 21 | struct reference2_part; 22 | 23 | [[nodiscard]] inline std::string to_string( const std::vector< reference2_part >& ); 24 | 25 | struct reference2_part 26 | { 27 | using data_t = std::variant< std::string, std::size_t, std::vector< reference2_part > >; 28 | 29 | reference2_part( const part_vector_t /*unused*/, const pegtl::position& p ) 30 | : position( p ), 31 | data( std::vector< reference2_part >() ) 32 | {} 33 | 34 | reference2_part( const std::size_t i, const pegtl::position& p ) 35 | : position( p ), 36 | data( i ) 37 | {} 38 | 39 | reference2_part( const std::string& n, const pegtl::position& p ) 40 | : position( p ), 41 | data( n ) 42 | {} 43 | 44 | [[nodiscard]] reference2_kind kind() const noexcept 45 | { 46 | return reference2_kind( data.index() ); 47 | } 48 | 49 | [[nodiscard]] std::size_t get_index() const noexcept 50 | { 51 | const auto* s = std::get_if< std::size_t >( &data ); 52 | assert( s != nullptr ); 53 | return *s; 54 | } 55 | 56 | [[nodiscard]] const std::string& get_name() const noexcept 57 | { 58 | const auto* s = std::get_if< std::string >( &data ); 59 | assert( s != nullptr ); 60 | return *s; 61 | } 62 | 63 | [[nodiscard]] std::vector< reference2_part >& get_vector() noexcept 64 | { 65 | auto* s = std::get_if< std::vector< reference2_part > >( &data ); 66 | assert( s != nullptr ); 67 | return *s; 68 | } 69 | 70 | [[nodiscard]] const std::vector< reference2_part >& get_vector() const noexcept 71 | { 72 | const auto* s = std::get_if< std::vector< reference2_part > >( &data ); 73 | assert( s != nullptr ); 74 | return *s; 75 | } 76 | 77 | [[nodiscard]] std::string to_string() const 78 | { 79 | switch( kind() ) { 80 | case reference2_kind::name: 81 | return get_name(); // TODO: Unescape if not identifier? 82 | case reference2_kind::index: 83 | return std::to_string( get_index() ); 84 | case reference2_kind::vector: 85 | return internal::to_string( get_vector() ); 86 | } 87 | throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE 88 | } 89 | 90 | pegtl::position position; 91 | data_t data; 92 | }; 93 | 94 | [[nodiscard]] inline std::string to_string( const std::vector< reference2_part >& v ) 95 | { 96 | std::string result; 97 | result += '('; 98 | auto it = v.begin(); 99 | result += it->to_string(); 100 | while( ++it != v.end() ) { 101 | result += '.'; 102 | result += it->to_string(); 103 | } 104 | result += ')'; 105 | return result; 106 | } 107 | 108 | } // namespace tao::config::internal 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /include/tao/config/internal/repack_traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_REPACK_TRAITS_HPP 5 | #define TAO_CONFIG_INTERNAL_REPACK_TRAITS_HPP 6 | 7 | #include 8 | 9 | #include "../key.hpp" 10 | 11 | #include "pegtl.hpp" 12 | 13 | namespace tao::config::internal 14 | { 15 | template< typename V, typename = void > 16 | inline constexpr bool has_set_key = false; 17 | 18 | template< typename V > 19 | inline constexpr bool has_set_key< V, decltype( std::declval< V >().public_base().set_key( std::declval< const config::key& >() ), void() ) > = true; 20 | 21 | template< typename V, typename = void > 22 | inline constexpr bool has_set_position = false; 23 | 24 | template< typename V > 25 | inline constexpr bool has_set_position< V, decltype( std::declval< V >().public_base().set_position( std::declval< const pegtl::position& >() ), void() ) > = true; 26 | 27 | } // namespace tao::config::internal 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/tao/config/internal/state.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_STATE_HPP 5 | #define TAO_CONFIG_INTERNAL_STATE_HPP 6 | 7 | #include 8 | 9 | #include "key1.hpp" 10 | #include "object.hpp" 11 | #include "pegtl.hpp" 12 | 13 | namespace tao::config::internal 14 | { 15 | struct state 16 | { 17 | state() 18 | : root( pegtl::position( 1, 1, 1, "(root)" ) ) 19 | {} 20 | 21 | state( state&& ) = delete; 22 | state( const state& ) = delete; 23 | 24 | ~state() = default; 25 | 26 | void operator=( state&& ) = delete; 27 | void operator=( const state& ) = delete; 28 | 29 | key1 prefix; 30 | key1 suffix; 31 | key1 member; 32 | 33 | object root; 34 | 35 | bool include_is_optional; 36 | std::uint64_t generation = 1; 37 | }; 38 | 39 | } // namespace tao::config::internal 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/tao/config/internal/statistics.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_STATISTICS_HPP 5 | #define TAO_CONFIG_INTERNAL_STATISTICS_HPP 6 | 7 | #include 8 | #include 9 | 10 | #include "array.hpp" 11 | #include "concat.hpp" 12 | #include "entry.hpp" 13 | #include "object.hpp" 14 | 15 | namespace tao::config::internal 16 | { 17 | struct statistics 18 | { 19 | statistics() noexcept = default; 20 | 21 | explicit statistics( const entry& e ) 22 | { 23 | count( e ); 24 | } 25 | 26 | explicit statistics( const concat& c ) 27 | { 28 | count( c ); 29 | } 30 | 31 | explicit statistics( const array& a ) 32 | { 33 | count( a ); 34 | } 35 | 36 | void count( const entry& e ) 37 | { 38 | switch( e.kind() ) { 39 | case entry_kind::NULL_: 40 | ++m_nulls; 41 | return; 42 | case entry_kind::BOOLEAN: 43 | case entry_kind::STRING: 44 | case entry_kind::BINARY: 45 | case entry_kind::SIGNED: 46 | case entry_kind::UNSIGNED: 47 | case entry_kind::DOUBLE: 48 | ++m_atoms; 49 | return; 50 | case entry_kind::ARRAY: 51 | count( e.get_array() ); 52 | return; 53 | case entry_kind::OBJECT: 54 | count( e.get_object() ); 55 | return; 56 | case entry_kind::ASTERISK: 57 | ++m_asterisks; 58 | count( e.get_asterisk() ); 59 | return; 60 | case entry_kind::REFERENCE: 61 | ++m_references; 62 | return; 63 | } 64 | std::abort(); // LCOV_EXCL_LINE 65 | } 66 | 67 | void count( const array& a ) 68 | { 69 | if( a.function.empty() ) { 70 | ++m_arrays; 71 | } 72 | else { 73 | ++m_functions; 74 | } 75 | for( const auto& c : a.array ) { 76 | count( c ); 77 | } 78 | } 79 | 80 | void count( const object& o ) 81 | { 82 | for( const auto& p : o.object ) { 83 | count( p.second ); 84 | } 85 | ++m_objects; 86 | } 87 | 88 | void count( const concat& c ) 89 | { 90 | if( c.concat.size() > 1 ) { 91 | ++m_additions; 92 | } 93 | for( const auto& e : c.concat ) { 94 | count( e ); 95 | } 96 | } 97 | 98 | [[nodiscard]] std::size_t nulls() const noexcept 99 | { 100 | return m_nulls; 101 | } 102 | 103 | [[nodiscard]] std::size_t references() const noexcept 104 | { 105 | return m_references; 106 | } 107 | 108 | [[nodiscard]] bool is_primitive() const noexcept 109 | { 110 | return ( m_functions == 0 ) && ( m_additions == 0 ) && ( m_asterisks == 0 ) && ( m_references == 0 ); 111 | } 112 | 113 | private: 114 | std::size_t m_nulls = 0; 115 | std::size_t m_atoms = 0; 116 | std::size_t m_arrays = 0; 117 | std::size_t m_objects = 0; 118 | std::size_t m_functions = 0; 119 | std::size_t m_additions = 0; 120 | std::size_t m_asterisks = 0; 121 | std::size_t m_references = 0; 122 | }; 123 | 124 | } // namespace tao::config::internal 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /include/tao/config/internal/string_utility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_STRING_UTILITY_HPP 5 | #define TAO_CONFIG_INTERNAL_STRING_UTILITY_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "json.hpp" 12 | 13 | namespace tao::config::internal 14 | { 15 | struct strcat_stream 16 | { 17 | std::ostringstream oss; 18 | }; 19 | 20 | template< typename T > 21 | strcat_stream& operator<<=( strcat_stream& ss, const T& t ) 22 | { 23 | ss.oss << t; 24 | return ss; 25 | } 26 | 27 | inline strcat_stream& operator<<=( strcat_stream& ss, const json::type t ) 28 | { 29 | ss.oss << json::to_string( t ); 30 | return ss; 31 | } 32 | 33 | template< typename... Ts > 34 | [[nodiscard]] std::string strcat( const Ts&... ts ) 35 | { 36 | strcat_stream ss; 37 | (void)( ss <<= ... <<= ts ); 38 | return std::move( ss.oss ).str(); 39 | } 40 | 41 | } // namespace tao::config::internal 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/tao/config/internal/system_utility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_SYSTEM_UTILITY_HPP 5 | #define TAO_CONFIG_INTERNAL_SYSTEM_UTILITY_HPP 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "pegtl.hpp" 17 | 18 | namespace tao::config::internal 19 | { 20 | // TODO: Use std::filesystem::path for filenames? 21 | 22 | [[nodiscard]] inline std::string read_file_throws( const std::string& filename ) 23 | { 24 | return pegtl::internal::read_file_stdio( filename ).read_string(); 25 | } 26 | 27 | [[nodiscard]] inline std::optional< std::string > read_file_nothrow( const std::string& filename ) 28 | { 29 | try { 30 | return read_file_throws( filename ); 31 | } 32 | catch( const std::system_error& ) { 33 | return std::nullopt; 34 | } 35 | } 36 | 37 | [[nodiscard]] inline std::optional< std::string > getenv_nothrow( const std::string& name ) 38 | { 39 | #if defined( _MSC_VER ) 40 | char buffer[ 256 ]; 41 | std::size_t s = 0; 42 | if( ::getenv_s( &s, buffer, name.c_str() ) == 0 ) { 43 | if( s > 0 ) { 44 | return std::string( buffer ); 45 | } 46 | } 47 | // TODO: Check s and try with a larger buffer 48 | #else 49 | if( const char* r = std::getenv( name.c_str() ) ) { 50 | return std::string( r ); 51 | } 52 | #endif 53 | return std::nullopt; 54 | } 55 | 56 | [[nodiscard]] inline std::string getenv_throws( const pegtl::position& pos, const std::string& name ) 57 | { 58 | if( auto result = getenv_nothrow( name ) ) { 59 | return std::move( *result ); 60 | } 61 | throw pegtl::parse_error( "environment variable '" + name + "' not found", pos ); 62 | } 63 | 64 | #if !defined( _MSC_VER ) 65 | [[nodiscard]] inline std::string shell_popen_throws( const pegtl::position& pos, const std::string& script ) 66 | { 67 | errno = 0; 68 | 69 | std::unique_ptr< FILE, void ( * )( FILE* ) > file( ::popen( script.c_str(), "r" ), []( FILE* f ) { ::pclose( f ); } ); 70 | 71 | if( !file ) { 72 | throw pegtl::parse_error( "TODO: Better error message for shell function popen error.", pos ); 73 | // throw pegtl::parse_error( format( __FILE__, __LINE__, "popen failed", { { "command", script }, { "errno", errno } } ), pos ); 74 | } 75 | std::string result; 76 | char buffer[ 1000 ]; 77 | 78 | while( const auto temp = ::fread( buffer, 1, sizeof( buffer ), file.get() ) ) { 79 | result.append( buffer, temp ); 80 | } 81 | errno = 0; 82 | 83 | if( ::pclose( file.release() ) != 0 ) { 84 | throw pegtl::parse_error( "TODO: Better error message for shell function pclose error.", pos ); // LCOV_EXCL_LINE 85 | } 86 | return result; 87 | } 88 | #endif 89 | 90 | } // namespace tao::config::internal 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /include/tao/config/internal/to_stream.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_INTERNAL_TO_STREAM_HPP 5 | #define TAO_CONFIG_INTERNAL_TO_STREAM_HPP 6 | 7 | #include 8 | #include 9 | 10 | #include "debug_traits.hpp" 11 | #include "json.hpp" 12 | 13 | namespace tao::config::internal 14 | { 15 | template< typename T > 16 | void to_stream( std::ostream& os, const T& t ) 17 | { 18 | json::jaxn::events::to_stream consumer( os ); 19 | json::events::produce< debug_traits >( consumer, t ); 20 | } 21 | 22 | template< typename T > 23 | void to_stream( std::ostream& os, const T& t, const std::size_t indent ) 24 | { 25 | json::jaxn::events::to_pretty_stream consumer( os, indent ); 26 | json::events::produce< debug_traits >( consumer, t ); 27 | } 28 | 29 | } // namespace tao::config::internal 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/tao/config/key_kind.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_KEY_KIND_HPP 5 | #define TAO_CONFIG_KEY_KIND_HPP 6 | 7 | namespace tao::config 8 | { 9 | enum class key_kind : char 10 | { 11 | name = 0, 12 | index = 1 13 | }; 14 | 15 | } // namespace tao::config 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/tao/config/key_part.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_KEY_PART_HPP 5 | #define TAO_CONFIG_KEY_PART_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "internal/constants.hpp" 14 | #include "internal/json.hpp" 15 | #include "internal/key_grammar.hpp" 16 | #include "internal/pegtl.hpp" 17 | 18 | #include "key_kind.hpp" 19 | 20 | namespace tao::config 21 | { 22 | struct key_part 23 | { 24 | using data_t = std::variant< std::string, std::size_t >; 25 | 26 | explicit key_part( const std::size_t i ) noexcept 27 | : data( i ) 28 | {} 29 | 30 | explicit key_part( std::string&& n ) noexcept 31 | : data( std::move( n ) ) 32 | {} 33 | 34 | explicit key_part( const std::string& n ) 35 | : data( n ) 36 | {} 37 | 38 | [[nodiscard]] key_kind kind() const noexcept 39 | { 40 | return key_kind( data.index() ); 41 | } 42 | 43 | [[nodiscard]] std::size_t get_index() const noexcept 44 | { 45 | return std::get< std::size_t >( data ); 46 | } 47 | 48 | [[nodiscard]] const std::string& get_name() const noexcept 49 | { 50 | return std::get< std::string >( data ); 51 | } 52 | 53 | data_t data; 54 | }; 55 | 56 | [[nodiscard]] inline bool operator<( const key_part& l, const key_part& r ) noexcept 57 | { 58 | return l.data < r.data; 59 | } 60 | 61 | [[nodiscard]] inline bool operator==( const key_part& l, const key_part& r ) noexcept 62 | { 63 | return l.data == r.data; 64 | } 65 | 66 | [[nodiscard]] inline bool is_identifier( const std::string& n ) 67 | { 68 | using grammar = pegtl::seq< internal::rules::ident, pegtl::eof >; 69 | pegtl::memory_input< pegtl::tracking_mode::lazy, pegtl::eol::lf_crlf, const char* > in( n, __FUNCTION__ ); 70 | return pegtl::parse< grammar >( in ); 71 | } 72 | 73 | [[nodiscard]] inline std::string name_to_string( const std::string& n ) 74 | { 75 | return is_identifier( n ) ? n : ( '"' + json::internal::escape( n ) + '"' ); 76 | } 77 | 78 | [[nodiscard]] inline std::string to_string( const key_part& t ) 79 | { 80 | switch( t.kind() ) { 81 | case key_kind::name: 82 | return name_to_string( t.get_name() ); 83 | case key_kind::index: 84 | return std::to_string( t.get_index() ); 85 | } 86 | throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE 87 | } 88 | 89 | inline void name_to_stream( std::ostream& o, const std::string& n ) 90 | { 91 | if( is_identifier( n ) ) { 92 | o << n; 93 | } 94 | else { 95 | o << '"' << json::internal::escape( n ) << '"'; 96 | } 97 | } 98 | 99 | inline void to_stream( std::ostream& o, const key_part& t ) 100 | { 101 | switch( t.kind() ) { 102 | case key_kind::name: 103 | name_to_stream( o, t.get_name() ); 104 | return; 105 | case key_kind::index: 106 | o << t.get_index(); 107 | return; 108 | } 109 | throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE 110 | } 111 | 112 | } // namespace tao::config 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /include/tao/config/parser.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_PARSER_HPP 5 | #define TAO_CONFIG_PARSER_HPP 6 | 7 | #include "internal/config_parser.hpp" 8 | #include "internal/function_wrapper.hpp" 9 | 10 | namespace tao::config 11 | { 12 | class parser 13 | { 14 | public: 15 | parser() = default; 16 | 17 | void parse( const std::filesystem::path& path ) 18 | { 19 | m_parser.parse( path ); 20 | } 21 | 22 | void parse( const std::string_view data, const std::string& source ) 23 | { 24 | m_parser.parse( data, source ); 25 | } 26 | 27 | template< typename F > 28 | void set_inner_extension( const std::string& name, F& f ) 29 | { 30 | m_parser.fm[ name ] = internal::wrap( f ); 31 | } 32 | 33 | template< template< typename... > class Traits > 34 | [[nodiscard]] json::basic_value< Traits > result() 35 | { 36 | return m_parser.finish< Traits >(); 37 | } 38 | 39 | protected: 40 | internal::config_parser m_parser; 41 | }; 42 | 43 | } // namespace tao::config 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/tao/config/to_stream.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_TO_STREAM_HPP 5 | #define TAO_CONFIG_TO_STREAM_HPP 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "internal/events_from_value.hpp" 13 | 14 | #include "value.hpp" 15 | 16 | namespace tao::config 17 | { 18 | inline void to_stream( std::ostream& os, const value& v ) 19 | { 20 | json::jaxn::events::to_stream consumer( os ); 21 | internal::events_from_value( consumer, v ); 22 | } 23 | 24 | inline void to_stream( std::ostream& os, const value& v, const std::size_t indent ) 25 | { 26 | json::jaxn::events::to_pretty_stream consumer( os, indent ); 27 | internal::events_from_value( consumer, v ); 28 | } 29 | 30 | } // namespace tao::config 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/tao/config/traits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_TRAITS_HPP 5 | #define TAO_CONFIG_TRAITS_HPP 6 | 7 | #include 8 | 9 | #include "annotation.hpp" 10 | 11 | namespace tao::config 12 | { 13 | template< typename T > 14 | struct traits 15 | : json::traits< T > 16 | {}; 17 | 18 | template<> 19 | struct traits< void > 20 | : json::traits< void > 21 | { 22 | static constexpr const bool enable_implicit_constructor = false; 23 | 24 | template< typename Value > 25 | using public_base = annotation; 26 | }; 27 | 28 | } // namespace tao::config 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/tao/config/value.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_VALUE_HPP 5 | #define TAO_CONFIG_VALUE_HPP 6 | 7 | #include 8 | 9 | #include "traits.hpp" 10 | 11 | namespace tao::config 12 | { 13 | using value = json::basic_value< traits >; 14 | 15 | } // namespace tao::config 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/example/config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8...3.19) 2 | 3 | set(examplesources 4 | dump_all_phases.cpp 5 | dump_only_data.cpp 6 | dump_phase_one.cpp 7 | dump_phase_three.cpp 8 | dump_phase_two.cpp 9 | dump_with_meta.cpp 10 | ) 11 | 12 | # file(GLOB ...) is used to validate the above list of example_sources 13 | file(GLOB glob_example_sources RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.cpp) 14 | 15 | foreach(examplesourcefile ${examplesources}) 16 | if(${examplesourcefile} IN_LIST glob_example_sources) 17 | list(REMOVE_ITEM glob_example_sources ${examplesourcefile}) 18 | else() 19 | message(SEND_ERROR "File ${examplesourcefile} is missing from src/example/config") 20 | endif() 21 | get_filename_component(exename ${examplesourcefile} NAME_WE) 22 | set(exename "tao-config-example-${exename}") 23 | add_executable(${exename} ${examplesourcefile}) 24 | target_link_libraries(${exename} PRIVATE taocpp::config) 25 | set_target_properties(${exename} PROPERTIES 26 | CXX_STANDARD 11 27 | CXX_STANDARD_REQUIRED ON 28 | CXX_EXTENSIONS OFF 29 | ) 30 | if(MSVC) 31 | target_compile_options(${exename} PRIVATE /W4 /WX /utf-8 /bigobj) 32 | else() 33 | target_compile_options(${exename} PRIVATE -pedantic -Wall -Wextra -Werror) 34 | endif() 35 | endforeach() 36 | 37 | if(glob_example_sources) 38 | foreach(ignored_source_file ${glob_example_sources}) 39 | message(SEND_ERROR "File ${ignored_source_file} in src/example/config is ignored") 40 | endforeach() 41 | endif() 42 | -------------------------------------------------------------------------------- /src/example/config/dump_all_phases.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | int main( int argc, char** argv ) 13 | { 14 | tao::config::internal::config_parser cfg; 15 | 16 | try { 17 | for( int i = 1; i < argc; ++i ) { 18 | const std::filesystem::path file( argv[ i ] ); 19 | std::cout << "PARSE " << file << std::endl; 20 | cfg.parse( file ); 21 | tao::config::internal::to_stream( std::cout, cfg.st.root, 3 ); 22 | std::cout << std::endl; 23 | } 24 | std::cout << "PHASE 2" << std::endl; 25 | tao::config::internal::phase2_everything( cfg.st, cfg.fm ); 26 | tao::config::internal::to_stream( std::cout, cfg.st.root, 3 ); 27 | std::cout << std::endl; 28 | std::cout << "PHASE 3" << std::endl; 29 | tao::config::internal::phase3_remove( cfg.st.root ); 30 | tao::config::internal::to_stream( std::cout, cfg.st.root, 3 ); 31 | std::cout << std::endl; 32 | std::cout << "RESULT" << std::endl; 33 | const tao::config::value j = tao::config::internal::phase5_repack< tao::config::traits >( cfg.st.root ); 34 | tao::config::to_stream( std::cout, j, 3 ); 35 | std::cout << std::endl; 36 | } 37 | catch( const std::exception& e ) { 38 | std::cerr << "ERROR " << e.what() << std::endl; 39 | return 1; 40 | } 41 | catch( const std::string& e ) { 42 | std::cerr << "STRING " << e << std::endl; 43 | return 1; 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/example/config/dump_only_data.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "try_catch.hpp" 13 | 14 | int main( int argc, char** argv ) 15 | { 16 | tao::config::internal::try_catch( [ = ]() { 17 | const tao::config::value v = tao::config::from_files( std::vector< std::filesystem::path >( argv + 1, argv + argc ) ); 18 | tao::json::jaxn::to_stream( std::cout, v, 3 ); 19 | std::cout << std::endl; 20 | } ); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/example/config/dump_phase_one.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | int main( int argc, char** argv ) 13 | { 14 | tao::config::internal::config_parser cfg; 15 | 16 | try { 17 | for( int i = 1; i < argc; ++i ) { 18 | const std::filesystem::path file( argv[ i ] ); 19 | std::cout << "PARSE " << file << std::endl; 20 | cfg.parse( file ); 21 | tao::config::internal::to_stream( std::cout, cfg.st.root, 3 ); 22 | std::cout << std::endl; 23 | } 24 | } 25 | catch( const std::exception& e ) { 26 | std::cerr << "ERROR " << e.what() << std::endl; 27 | return 1; 28 | } 29 | catch( const std::string& e ) { 30 | std::cerr << "STRING " << e << std::endl; 31 | return 1; 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /src/example/config/dump_phase_three.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | int main( int argc, char** argv ) 13 | { 14 | tao::config::internal::config_parser cfg; 15 | 16 | try { 17 | for( int i = 1; i < argc; ++i ) { 18 | const std::filesystem::path file( argv[ i ] ); 19 | std::cout << "PARSE " << file << std::endl; 20 | cfg.parse( file ); 21 | } 22 | std::cout << "PHASE 2" << std::endl; 23 | tao::config::internal::phase2_everything( cfg.st, cfg.fm ); 24 | std::cout << "PHASE 3" << std::endl; 25 | tao::config::internal::phase3_remove( cfg.st.root ); 26 | tao::config::internal::to_stream( std::cout, cfg.st.root, 3 ); 27 | std::cout << std::endl; 28 | } 29 | catch( const std::exception& e ) { 30 | std::cerr << "ERROR " << e.what() << std::endl; 31 | return 1; 32 | } 33 | catch( const std::string& e ) { 34 | std::cerr << "STRING " << e << std::endl; 35 | return 1; 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/example/config/dump_phase_two.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | int main( int argc, char** argv ) 13 | { 14 | tao::config::internal::config_parser cfg; 15 | 16 | try { 17 | for( int i = 1; i < argc; ++i ) { 18 | const std::filesystem::path file( argv[ i ] ); 19 | std::cout << "PARSE " << file << std::endl; 20 | cfg.parse( file ); 21 | } 22 | std::cout << "PHASE 2" << std::endl; 23 | tao::config::internal::phase2_everything( cfg.st, cfg.fm ); 24 | tao::config::internal::to_stream( std::cout, cfg.st.root, 3 ); 25 | std::cout << std::endl; 26 | } 27 | catch( const std::exception& e ) { 28 | std::cerr << "ERROR " << e.what() << std::endl; 29 | return 1; 30 | } 31 | catch( const std::string& e ) { 32 | std::cerr << "STRING " << e << std::endl; 33 | return 1; 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/example/config/dump_with_meta.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "try_catch.hpp" 11 | 12 | int main( int argc, char** argv ) 13 | { 14 | tao::config::internal::try_catch( [ = ]() { 15 | const tao::config::value v = tao::config::from_files( std::vector< std::filesystem::path >( argv + 1, argv + argc ) ); 16 | tao::config::to_stream( std::cout, v, 3 ); 17 | std::cout << std::endl; 18 | } ); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /src/example/config/try_catch.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_EXAMPLE_CONFIG_TRY_CATCH_HPP 5 | #define TAO_EXAMPLE_CONFIG_TRY_CATCH_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | namespace tao::config::internal 16 | { 17 | template< typename F > 18 | void try_catch( const F& f ) 19 | { 20 | try { 21 | f(); 22 | } 23 | catch( const pegtl::parse_error& ) { 24 | std::cerr << "*** config parse error ***" << std::endl; 25 | for( const auto& e : pegtl::nested::flatten() ) { 26 | std::cerr << e.message() << ": " << e.position_string() << std::endl; 27 | } 28 | } 29 | catch( const std::exception& e ) { 30 | std::cerr << "*** config error ***" << std::endl; 31 | std::cerr << e.what() << std::endl; 32 | } 33 | catch( const std::string& s ) { 34 | std::cerr << "*** config error ***" << std::endl; 35 | std::cerr << s << std::endl; 36 | } 37 | } 38 | 39 | } // namespace tao::config::internal 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/test/config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8...3.19) 2 | 3 | set(testsources 4 | access.cpp 5 | assign.cpp 6 | custom.cpp 7 | debug_traits.cpp 8 | enumerations.cpp 9 | failure.cpp 10 | independence.cpp 11 | key.cpp 12 | key_part.cpp 13 | multi_line_string_position.cpp 14 | parse_key1.cpp 15 | parse_key.cpp 16 | parse_reference2.cpp 17 | success.cpp 18 | to_stream.cpp 19 | value.cpp 20 | ) 21 | 22 | # file(GLOB ...) is used to validate the above list of test_sources 23 | file(GLOB glob_test_sources RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.cpp) 24 | 25 | foreach(testsourcefile ${testsources}) 26 | if(${testsourcefile} IN_LIST glob_test_sources) 27 | list(REMOVE_ITEM glob_test_sources ${testsourcefile}) 28 | else() 29 | message(SEND_ERROR "File ${testsourcefile} is missing from src/test/config") 30 | endif() 31 | get_filename_component(exename ${testsourcefile} NAME_WE) 32 | set(exename "tao-config-test-${exename}") 33 | add_executable(${exename} ${testsourcefile}) 34 | target_link_libraries(${exename} PRIVATE taocpp::config) 35 | set_target_properties(${exename} PROPERTIES 36 | CXX_STANDARD 17 37 | CXX_STANDARD_REQUIRED ON 38 | CXX_EXTENSIONS OFF 39 | ) 40 | if(MSVC) 41 | target_compile_options(${exename} PRIVATE /W4 /WX /utf-8 /bigobj) 42 | else() 43 | target_compile_options(${exename} PRIVATE -pedantic -Wall -Wextra -Werror) 44 | endif() 45 | add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${exename}) 46 | endforeach() 47 | 48 | if(glob_test_sources) 49 | foreach(ignored_source_file ${glob_test_sources}) 50 | message(SEND_ERROR "File ${ignored_source_file} in src/test/config is ignored") 51 | endforeach() 52 | endif() 53 | -------------------------------------------------------------------------------- /src/test/config/access.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | 8 | namespace tao::config 9 | { 10 | void unit_test() 11 | { 12 | const auto v = from_string( "a = 1, b = 2, c = { d = { e = [ 6 7 ] } }", __FUNCTION__ ); 13 | 14 | TAO_CONFIG_TEST_ASSERT( access( v, key( "a" ) ) == value( 1 ) ); 15 | TAO_CONFIG_TEST_ASSERT( access( v, key( "b" ) ) == value( 2 ) ); 16 | 17 | TAO_CONFIG_TEST_ASSERT( access( v, key( "a" ) ).key == key( "a" ) ); 18 | TAO_CONFIG_TEST_ASSERT( access( v, key( "b" ) ).key == key( "b" ) ); 19 | 20 | TAO_CONFIG_TEST_ASSERT( access( v, key( "c.d.e.0" ) ) == value( 6 ) ); 21 | TAO_CONFIG_TEST_ASSERT( access( v, key( "c.d.e.1" ) ) == value( 7 ) ); 22 | 23 | TAO_CONFIG_TEST_ASSERT( access( v, key( "c.d.e.0" ) ).key == key( "c.d.e.0" ) ); 24 | TAO_CONFIG_TEST_ASSERT( access( v, key( "c.d.e.1" ) ).key == key( "c.d.e.1" ) ); 25 | 26 | TAO_CONFIG_TEST_THROWS( (void)access( v, key( "0" ) ) ); 27 | TAO_CONFIG_TEST_THROWS( (void)access( v, key( "a.0" ) ) ); 28 | TAO_CONFIG_TEST_THROWS( (void)access( v, key( "r" ) ) ); 29 | TAO_CONFIG_TEST_THROWS( (void)access( v, key( "c.d.e.f" ) ) ); 30 | TAO_CONFIG_TEST_THROWS( (void)access( v, key( "c.d.e.2" ) ) ); 31 | } 32 | 33 | } // namespace tao::config 34 | 35 | #include "main.hpp" 36 | -------------------------------------------------------------------------------- /src/test/config/assign.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | 8 | namespace tao::config 9 | { 10 | void unit_test() 11 | { 12 | auto v = from_string( "a = 1, b = 2, c = { d = { e = [ 6 7 ] } }", __FUNCTION__ ); 13 | 14 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "a" ) ) == value( 1 ) ); 15 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "b" ) ) == value( 2 ) ); 16 | 17 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "a" ) ).key == key( "a" ) ); 18 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "b" ) ).key == key( "b" ) ); 19 | 20 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "c.d.e.0" ) ) == value( 6 ) ); 21 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "c.d.e.1" ) ) == value( 7 ) ); 22 | 23 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "c.d.e.0" ) ).key == key( "c.d.e.0" ) ); 24 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "c.d.e.1" ) ).key == key( "c.d.e.1" ) ); 25 | 26 | TAO_CONFIG_TEST_THROWS( (void)assign( v, key( "0" ) ) ); 27 | TAO_CONFIG_TEST_THROWS( (void)assign( v, key( "c.d.e.f" ) ) ); 28 | TAO_CONFIG_TEST_THROWS( (void)assign( v, key( "c.d.e.2" ) ) ); 29 | TAO_CONFIG_TEST_THROWS( (void)assign( v, key( "a.0" ) ) ); 30 | 31 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "r" ) ) == value( json::empty_object ) ); 32 | TAO_CONFIG_TEST_ASSERT( assign( v, key( "r.s.t" ) ) == value( json::empty_object ) ); 33 | } 34 | 35 | } // namespace tao::config 36 | 37 | #include "main.hpp" 38 | -------------------------------------------------------------------------------- /src/test/config/custom.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | #include 8 | 9 | namespace tao::config 10 | { 11 | void unit_test() 12 | { 13 | parser p; 14 | p.set_inner_extension( "rot13", rot13 ); 15 | p.parse( "a = (rot13 \"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@[]{}`\")", __FUNCTION__ ); 16 | const auto j = p.result< json::traits >(); 17 | 18 | TAO_CONFIG_TEST_ASSERT( j.at( "a" ) == "0123456789nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM@[]{}`" ); 19 | } 20 | 21 | } // namespace tao::config 22 | 23 | #include "main.hpp" 24 | -------------------------------------------------------------------------------- /src/test/config/debug_traits.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "test.hpp" 9 | 10 | #include 11 | #include 12 | 13 | namespace tao::config 14 | { 15 | void unit_test() 16 | { 17 | internal::config_parser cp; 18 | cp.parse( std::filesystem::path( "tests/debug_traits.config" ) ); 19 | json::events::to_value consumer; 20 | json::events::produce< internal::debug_traits >( consumer, cp.st.root ); 21 | const json::value config = std::move( consumer.value ); 22 | const json::value output = json::jaxn::from_file( std::filesystem::path( "tests/debug_traits.output" ) ); 23 | TAO_CONFIG_TEST_ASSERT( output == config ); 24 | { 25 | std::ostringstream os1; 26 | internal::to_stream( os1, cp.st.root ); 27 | TAO_CONFIG_TEST_ASSERT( json::jaxn::from_string( os1.str() ) == output ); 28 | } 29 | std::ostringstream os2; 30 | internal::to_stream( os2, cp.st.root, 3 ); 31 | TAO_CONFIG_TEST_ASSERT( json::jaxn::from_string( os2.str() ) == output ); 32 | } 33 | 34 | } // namespace tao::config 35 | 36 | #include "main.hpp" 37 | -------------------------------------------------------------------------------- /src/test/config/enumerations.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | 6 | #include "test.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | namespace tao::config 19 | { 20 | void unit_test() 21 | { 22 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( key_kind::name ), key_part::data_t >, std::string > ); 23 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( key_kind::index ), key_part::data_t >, std::size_t > ); 24 | 25 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::entry_kind::ARRAY ), internal::entry::data_t >, internal::array > ); 26 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::entry_kind::OBJECT ), internal::entry::data_t >, internal::object > ); 27 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::entry_kind::REFERENCE ), internal::entry::data_t >, internal::reference2 > ); 28 | 29 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::key1_kind::name ), internal::key1_part::data_t >, std::string > ); 30 | 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 > ); 31 | 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 > ); 32 | 33 | static_assert( std::is_same_v< std::variant_alternative_t< std::size_t( internal::reference2_kind::name ), internal::reference2_part::data_t >, std::string > ); 34 | 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 > ); 35 | 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 > > ); 36 | } 37 | 38 | } // namespace tao::config 39 | 40 | #include "main.hpp" 41 | -------------------------------------------------------------------------------- /src/test/config/failure.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | const char* ansi_reset = "\033[0m"; 11 | const char* ansi_message = "\033[1;31m"; 12 | const char* ansi_source = "\033[36m"; 13 | const char* ansi_text = "\033[33m"; 14 | 15 | namespace tao 16 | { 17 | unsigned failed = 0; 18 | 19 | template< template< typename... > class Traits > 20 | void unit_test( const std::filesystem::path& path ) 21 | { 22 | try { 23 | // For a failure testcase to succeed the next line must throw an error. 24 | const auto cc = config::basic_from_file< Traits >( path ); 25 | // LCOV_EXCL_START 26 | const auto ccs = json::jaxn::to_string( cc ); 27 | ++failed; 28 | std::cerr << std::endl 29 | << "Testcase '" << path << "' failed error test!" << std::endl; 30 | std::cerr << "<<< Config parsed as config <<<" << std::endl; 31 | std::cerr << ccs << std::endl; 32 | std::cerr << ">>> Config parsed as config >>>" << std::endl; 33 | // LCOV_EXCL_STOP 34 | } 35 | catch( const pegtl::parse_error_base& e ) { 36 | std::cout << ansi_text << "pegtl::parse_error: " << ansi_message << e.message() << ": " << ansi_source << e.position_string() << ansi_reset << std::endl; 37 | } 38 | } 39 | 40 | } // namespace tao 41 | 42 | int main() 43 | { 44 | unsigned count = 0; 45 | 46 | for( const auto& entry : std::filesystem::directory_iterator( "tests" ) ) { 47 | if( const auto& path = entry.path(); path.extension() == ".failure" ) { 48 | tao::unit_test< tao::json::traits >( path ); 49 | tao::unit_test< tao::config::traits >( path ); 50 | ++count; 51 | } 52 | } 53 | if( tao::failed == 0 ) { 54 | std::cerr << "All " << count << " failure testcases passed." << std::endl; 55 | } 56 | return std::min( int( tao::failed ), 127 ); 57 | } 58 | -------------------------------------------------------------------------------- /src/test/config/independence.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "setenv.hpp" 12 | #include "test.hpp" 13 | 14 | #include 15 | 16 | namespace tao::config 17 | { 18 | std::size_t iteration = 0; 19 | 20 | [[nodiscard]] std::size_t p2fun( internal::state& st, const internal::function_map& fm ) 21 | { 22 | return internal::phase2_functions( st, fm ); 23 | } 24 | 25 | [[nodiscard]] std::size_t p2add( internal::state& st, const internal::function_map& /*unused*/ ) 26 | { 27 | return internal::phase2_additions( st.root ); 28 | } 29 | 30 | [[nodiscard]] std::size_t p2ref( internal::state& st, const internal::function_map& /*unused*/ ) 31 | { 32 | return internal::phase2_references( st.root ); 33 | } 34 | 35 | [[nodiscard]] std::size_t p2ast( internal::state& st, const internal::function_map& /*unused*/ ) 36 | { 37 | return internal::phase2_asterisks( st.root ); 38 | } 39 | 40 | using func_t = std::size_t ( * )( internal::state&, const internal::function_map& ); 41 | 42 | std::set< func_t > p2funcs = { p2fun, p2add, p2ref, p2ast }; 43 | 44 | void unit_test( const std::filesystem::path& path ) 45 | { 46 | try { 47 | std::filesystem::path jaxn = path; 48 | jaxn.replace_extension( ".jaxn" ); 49 | const auto cj = from_file( jaxn ); 50 | const auto cjs = json::jaxn::to_string( cj ); 51 | 52 | std::vector< func_t > v( p2funcs.begin(), p2funcs.end() ); 53 | 54 | do { 55 | internal::config_parser p; 56 | p.parse( path ); 57 | 58 | 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 ) ) { 59 | } 60 | 61 | internal::phase3_remove( p.st.root ); 62 | const auto cc = internal::phase5_repack< traits >( p.st.root ); 63 | const auto ccs = json::jaxn::to_string( cc ); 64 | 65 | if( ccs != cjs ) { 66 | // LCOV_EXCL_START 67 | ++failed; 68 | std::cerr << std::endl 69 | << "Testcase '" << path << "' failed identity test in iteration " << iteration << std::endl; 70 | std::cerr << "<<< Config parsed as config <<<" << std::endl; 71 | std::cerr << ccs << std::endl; 72 | std::cerr << ">>> Config parsed as config >>>" << std::endl; 73 | std::cerr << "<<< Reference data parsed as config <<<" << std::endl; 74 | std::cerr << cjs << std::endl; 75 | std::cerr << ">>> Reference data parsed as config >>>" << std::endl; 76 | // LCOV_EXCL_STOP 77 | } 78 | ++iteration; 79 | } while( std::next_permutation( v.begin(), v.end() ) ); 80 | } 81 | // LCOV_EXCL_START 82 | catch( const std::exception& e ) { 83 | std::cerr << "Testcase '" << path << "' failed with exception '" << e.what() << "' in iteration " << iteration << std::endl; 84 | ++failed; 85 | } 86 | // LCOV_EXCL_STOP 87 | } 88 | 89 | } // namespace tao::config 90 | 91 | int main() 92 | { 93 | for( const auto& entry : std::filesystem::directory_iterator( "tests" ) ) { 94 | if( const auto& path = entry.path(); path.extension() == ".success" ) { 95 | #if defined( _MSC_VER ) 96 | if( entry.path().stem() == "shell" ) { 97 | continue; 98 | } 99 | #endif 100 | tao::config::internal::setenv_throws( "TAO_CONFIG", "env_value" ); 101 | tao::config::unit_test( path ); 102 | } 103 | } 104 | if( tao::config::failed == 0 ) { 105 | std::cerr << "All " << tao::config::iteration << " order independence testcases passed." << std::endl; 106 | } 107 | return std::min( int( tao::config::failed ), 127 ); 108 | } 109 | -------------------------------------------------------------------------------- /src/test/config/key.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | 7 | #include "test.hpp" 8 | 9 | #include 10 | 11 | namespace tao::config 12 | { 13 | void unit_test() 14 | { 15 | const std::string s0 = "foo.bar.42.\" \""; 16 | const std::vector< key_part > kpv = { key_part( "foo" ), key_part( "bar" ), key_part( 42 ), key_part( " " ) }; 17 | const key k1( kpv.begin(), kpv.end() ); 18 | const key k2( "foo.bar.42.' '" ); 19 | const key k3 = { key_part( "foo" ), key_part( "bar" ), key_part( 42 ), key_part( " " ) }; 20 | key k4 = k3; 21 | TAO_CONFIG_TEST_ASSERT( k1.size() == 4 ); 22 | TAO_CONFIG_TEST_ASSERT( k1 == k2 ); 23 | TAO_CONFIG_TEST_ASSERT( k1 == k3 ); 24 | TAO_CONFIG_TEST_ASSERT( k1.vector() == k2.vector() ); 25 | TAO_CONFIG_TEST_ASSERT( k1.vector() == k4.vector() ); 26 | const auto k5 = pop_front( k1 ); 27 | const auto k6 = pop_back( k1 ); 28 | TAO_CONFIG_TEST_ASSERT( k5.size() == 3 ); 29 | TAO_CONFIG_TEST_ASSERT( k6.size() == 3 ); 30 | TAO_CONFIG_TEST_ASSERT( k5 == key( "bar.42.' '" ) ); 31 | TAO_CONFIG_TEST_ASSERT( k6 == key( "foo.bar.42" ) ); 32 | const std::string s1 = to_string( k1 ); 33 | TAO_CONFIG_TEST_ASSERT( s1 == s0 ); 34 | std::ostringstream oss; 35 | to_stream( oss, k1 ); 36 | TAO_CONFIG_TEST_ASSERT( oss.str() == s0 ); 37 | k4 = pop_back( k1 ); 38 | TAO_CONFIG_TEST_ASSERT( k4 + " " == k1 ); 39 | TAO_CONFIG_TEST_ASSERT( k4 + key_part( " " ) == k1 ); 40 | TAO_CONFIG_TEST_ASSERT( k4 + key( "\" \"" ) == k1 ); 41 | TAO_CONFIG_TEST_ASSERT( k1 + 123 == key( s0 + ".123" ) ); 42 | } 43 | 44 | } // namespace tao::config 45 | 46 | #include "main.hpp" 47 | -------------------------------------------------------------------------------- /src/test/config/key_part.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | 7 | #include "test.hpp" 8 | 9 | #include 10 | 11 | namespace tao::config 12 | { 13 | void test_name1() 14 | { 15 | const std::string str = "foo"; 16 | const key_part p( str ); 17 | TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::name ); 18 | TAO_CONFIG_TEST_ASSERT( p.get_name() == str ); 19 | TAO_CONFIG_TEST_ASSERT( to_string( p ) == str ); 20 | std::ostringstream oss; 21 | to_stream( oss, p ); 22 | TAO_CONFIG_TEST_ASSERT( oss.str() == str ); 23 | } 24 | 25 | void test_name2() 26 | { 27 | const std::string str = "+- "; 28 | const key_part p( str ); 29 | TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::name ); 30 | TAO_CONFIG_TEST_ASSERT( p.get_name() == str ); 31 | TAO_CONFIG_TEST_ASSERT( to_string( p ) == '"' + str + '"' ); 32 | std::ostringstream oss; 33 | to_stream( oss, p ); 34 | TAO_CONFIG_TEST_ASSERT( oss.str() == '"' + str + '"' ); 35 | } 36 | 37 | void test_index() 38 | { 39 | const std::size_t ind = 42; 40 | const key_part p( ind ); 41 | TAO_CONFIG_TEST_ASSERT( p.kind() == key_kind::index ); 42 | TAO_CONFIG_TEST_ASSERT( p.get_index() == ind ); 43 | TAO_CONFIG_TEST_ASSERT( to_string( p ) == "42" ); 44 | std::ostringstream oss; 45 | to_stream( oss, p ); 46 | TAO_CONFIG_TEST_ASSERT( oss.str() == "42" ); 47 | } 48 | 49 | void unit_test() 50 | { 51 | test_name1(); 52 | test_name2(); 53 | test_index(); 54 | } 55 | 56 | } // namespace tao::config 57 | 58 | #include "main.hpp" 59 | -------------------------------------------------------------------------------- /src/test/config/main.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_SRC_TEST_CONFIG_MAIN_HPP 5 | #define TAO_CONFIG_SRC_TEST_CONFIG_MAIN_HPP 6 | 7 | #include 8 | #include 9 | 10 | int main( int /*unused*/, char** argv ) 11 | { 12 | tao::config::unit_test(); 13 | 14 | if( tao::config::failed != 0 ) { 15 | std::cerr << "config: unit test " << argv[ 0 ] << " failed " << tao::config::failed << std::endl; // LCOV_EXCL_LINE 16 | } 17 | return ( tao::config::failed == 0 ) ? EXIT_SUCCESS : EXIT_FAILURE; 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/test/config/multi_line_string_position.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace tao 9 | { 10 | void test1() 11 | { 12 | const std::string input = "foo = '''a\nb\nc\n'''"; 13 | const auto config = config::from_string( input, __FUNCTION__ ); 14 | const auto string = config.get_object().at( "foo" ); 15 | assert( string.position.line() == 1 ); 16 | assert( string.get_string() == "a\nb\nc\n" ); 17 | } 18 | 19 | void test2() 20 | { 21 | const std::string input = "foo = '''\na\nb\nc\n'''"; 22 | const auto config = config::from_string( input, __FUNCTION__ ); 23 | const auto string = config.get_object().at( "foo" ); 24 | assert( string.position.line() == 1 ); // Should this be 2? 25 | assert( string.get_string() == "a\nb\nc\n" ); 26 | } 27 | 28 | void test3() 29 | { 30 | const std::string input = "\n\n\nfoo = '''a\nb\nc\n'''"; 31 | const auto config = config::from_string( input, __FUNCTION__ ); 32 | const auto string = config.get_object().at( "foo" ); 33 | assert( string.position.line() == 4 ); 34 | assert( string.get_string() == "a\nb\nc\n" ); 35 | } 36 | 37 | void test4() 38 | { 39 | const std::string input = "\n\n\nfoo = '''\na\nb\nc\n'''"; 40 | const auto config = config::from_string( input, __FUNCTION__ ); 41 | const auto string = config.get_object().at( "foo" ); 42 | assert( string.position.line() == 4 ); // Should this be 5? 43 | assert( string.get_string() == "a\nb\nc\n" ); 44 | } 45 | 46 | } // namespace tao 47 | 48 | int main() 49 | { 50 | tao::test1(); 51 | tao::test2(); 52 | tao::test3(); 53 | tao::test4(); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/test/config/parse_key.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | 8 | namespace tao::config 9 | { 10 | void unit_test() 11 | { 12 | key k( "foo.bar.42" ); 13 | TAO_CONFIG_TEST_ASSERT( k.size() == 3 ); 14 | TAO_CONFIG_TEST_ASSERT( k[ 0 ].kind() == key_kind::name ); 15 | TAO_CONFIG_TEST_ASSERT( k[ 0 ].get_name() == "foo" ); 16 | TAO_CONFIG_TEST_ASSERT( k[ 1 ].kind() == key_kind::name ); 17 | TAO_CONFIG_TEST_ASSERT( k[ 1 ].get_name() == "bar" ); 18 | TAO_CONFIG_TEST_ASSERT( k[ 2 ].kind() == key_kind::index ); 19 | TAO_CONFIG_TEST_ASSERT( k[ 2 ].get_index() == 42 ); 20 | 21 | TAO_CONFIG_TEST_THROWS( key( "foo.-" ) ); 22 | } 23 | 24 | } // namespace tao::config 25 | 26 | #include "main.hpp" 27 | -------------------------------------------------------------------------------- /src/test/config/parse_key1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | 8 | namespace tao::config 9 | { 10 | void unit_test() 11 | { 12 | internal::key1 k( "foo.bar.42.*" ); 13 | TAO_CONFIG_TEST_ASSERT( k.size() == 4 ); 14 | TAO_CONFIG_TEST_ASSERT( k[ 0 ].kind() == internal::key1_kind::name ); 15 | TAO_CONFIG_TEST_ASSERT( k[ 0 ].get_name() == "foo" ); 16 | TAO_CONFIG_TEST_ASSERT( k[ 1 ].kind() == internal::key1_kind::name ); 17 | TAO_CONFIG_TEST_ASSERT( k[ 1 ].get_name() == "bar" ); 18 | TAO_CONFIG_TEST_ASSERT( k[ 2 ].kind() == internal::key1_kind::index ); 19 | TAO_CONFIG_TEST_ASSERT( k[ 2 ].get_index() == 42 ); 20 | TAO_CONFIG_TEST_ASSERT( k[ 3 ].kind() == internal::key1_kind::asterisk ); 21 | 22 | TAO_CONFIG_TEST_THROWS( internal::key1( "foo.-" ) ); 23 | } 24 | 25 | } // namespace tao::config 26 | 27 | #include "main.hpp" 28 | -------------------------------------------------------------------------------- /src/test/config/parse_reference2.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include "test.hpp" 5 | 6 | #include 7 | 8 | namespace tao::config 9 | { 10 | void unit_test() 11 | { 12 | internal::reference2 k( "(foo.(bar.1).42)" ); 13 | TAO_CONFIG_TEST_ASSERT( k.size() == 3 ); 14 | TAO_CONFIG_TEST_ASSERT( k[ 0 ].kind() == internal::reference2_kind::name ); 15 | TAO_CONFIG_TEST_ASSERT( k[ 0 ].get_name() == "foo" ); 16 | TAO_CONFIG_TEST_ASSERT( k[ 1 ].kind() == internal::reference2_kind::vector ); 17 | const auto& v = k[ 1 ].get_vector(); 18 | TAO_CONFIG_TEST_ASSERT( v.size() == 2 ); 19 | TAO_CONFIG_TEST_ASSERT( v[ 0 ].kind() == internal::reference2_kind::name ); 20 | TAO_CONFIG_TEST_ASSERT( v[ 0 ].get_name() == "bar" ); 21 | TAO_CONFIG_TEST_ASSERT( v[ 1 ].kind() == internal::reference2_kind::index ); 22 | TAO_CONFIG_TEST_ASSERT( v[ 1 ].get_index() == 1 ); 23 | TAO_CONFIG_TEST_ASSERT( k[ 2 ].kind() == internal::reference2_kind::index ); 24 | TAO_CONFIG_TEST_ASSERT( k[ 2 ].get_index() == 42 ); 25 | 26 | TAO_CONFIG_TEST_THROWS( internal::reference2( "foo.-" ) ); 27 | } 28 | 29 | } // namespace tao::config 30 | 31 | #include "main.hpp" 32 | -------------------------------------------------------------------------------- /src/test/config/setenv.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_SRC_TEST_CONFIG_SETENV_HPP 5 | #define TAO_CONFIG_SRC_TEST_CONFIG_SETENV_HPP 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace tao::config::internal 12 | { 13 | void setenv_throws( const std::string& name, const std::string& value ) 14 | { 15 | #if defined( _MSC_VER ) 16 | const auto e = ::_putenv_s( name.c_str(), value.c_str() ); 17 | if( e != 0 ) { 18 | #else 19 | errno = 0; 20 | if( ::setenv( name.c_str(), value.c_str(), 1 ) != 0 ) { 21 | // LCOV_EXCL_START 22 | const auto e = errno; 23 | #endif 24 | (void)e; 25 | throw std::runtime_error( "setenv failed" ); 26 | // LCOV_EXCL_STOP 27 | } 28 | } 29 | 30 | } // namespace tao::config::internal 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/test/config/test.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #ifndef TAO_CONFIG_SRC_TEST_CONFIG_TEST_HPP 5 | #define TAO_CONFIG_SRC_TEST_CONFIG_TEST_HPP 6 | 7 | #include 8 | #include 9 | 10 | namespace tao::config 11 | { 12 | std::size_t failed = 0; 13 | 14 | } // namespace tao::config 15 | 16 | #define TAO_TEST_STRINGIZE_INTERNAL( ... ) #__VA_ARGS__ 17 | #define TAO_TEST_STRINGIZE( ... ) TAO_TEST_STRINGIZE_INTERNAL( __VA_ARGS__ ) 18 | 19 | #define TAO_TEST_LINE TAO_TEST_STRINGIZE( __LINE__ ) 20 | 21 | #define TAO_CONFIG_TEST_UNWRAP( ... ) __VA_ARGS__ 22 | 23 | #define TAO_CONFIG_TEST_FAILED( MeSSaGe ) \ 24 | do { \ 25 | std::cerr << "config: unit test failed for [ " \ 26 | << tao::demangle< Rule >() \ 27 | << " ] " \ 28 | << TAO_CONFIG_TEST_UNWRAP( MeSSaGe ) \ 29 | << " in line [ " \ 30 | << line \ 31 | << " ] file [ " \ 32 | << file << " ]" \ 33 | << std::endl; \ 34 | ++failed; \ 35 | } while( false ) 36 | 37 | #define TAO_CONFIG_TEST_ASSERT( ... ) \ 38 | do { \ 39 | if( !( __VA_ARGS__ ) ) { \ 40 | std::cerr << "config: unit test assert [ " \ 41 | << ( #__VA_ARGS__ ) \ 42 | << " ] failed in line [ " \ 43 | << __LINE__ \ 44 | << " ] file [ " \ 45 | << __FILE__ << " ]" \ 46 | << std::endl; \ 47 | ++failed; \ 48 | } \ 49 | } while( false ) 50 | 51 | #define TAO_CONFIG_TEST_THROWS( ... ) \ 52 | do { \ 53 | try { \ 54 | __VA_ARGS__; \ 55 | std::cerr << "config: unit test [ " \ 56 | << ( #__VA_ARGS__ ) \ 57 | << " ] did not throw in line [ " \ 58 | << __LINE__ \ 59 | << " ] file [ " \ 60 | << __FILE__ << " ]" \ 61 | << std::endl; \ 62 | ++failed; \ 63 | } \ 64 | catch( ... ) { \ 65 | } \ 66 | } while( false ) 67 | 68 | #define TAO_CONFIG_TEST_UNREACHABLE \ 69 | do { \ 70 | std::cerr << "Code should be unreachable in " << __FUNCTION__ << " (" << __FILE__ << ':' << __LINE__ << ')' << std::endl; \ 71 | std::abort(); \ 72 | } while( false ) 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/test/config/value.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 Dr. Colin Hirsch and Daniel Frey 2 | // Please see LICENSE for license or visit https://github.com/taocpp/config/ 3 | 4 | #include 5 | #include 6 | 7 | #include "test.hpp" 8 | 9 | #include 10 | 11 | namespace tao::config 12 | { 13 | const std::string s = "invalid json type 'object' for conversion to std::string [(root):1:1]"; // TODO: Where does the second space come from? 14 | 15 | void unit_test() 16 | { 17 | const auto v = from_string( "foo = 42", __FUNCTION__ ); 18 | 19 | try { 20 | (void)v.as< std::string >(); 21 | ++failed; // LCOV_EXCL_LINE 22 | } 23 | catch( const std::exception& e ) { 24 | TAO_CONFIG_TEST_ASSERT( e.what() == s ); 25 | } 26 | } 27 | 28 | } // namespace tao::config 29 | 30 | #include "main.hpp" 31 | -------------------------------------------------------------------------------- /tests/add_01.failure: -------------------------------------------------------------------------------- 1 | a = null + null 2 | -------------------------------------------------------------------------------- /tests/add_02.failure: -------------------------------------------------------------------------------- 1 | a = null + true 2 | -------------------------------------------------------------------------------- /tests/add_03.failure: -------------------------------------------------------------------------------- 1 | a = true + null 2 | -------------------------------------------------------------------------------- /tests/add_04.failure: -------------------------------------------------------------------------------- 1 | a = true + false 2 | -------------------------------------------------------------------------------- /tests/add_05.failure: -------------------------------------------------------------------------------- 1 | a = null + 1 2 | -------------------------------------------------------------------------------- /tests/add_06.failure: -------------------------------------------------------------------------------- 1 | a = 1 + null 2 | -------------------------------------------------------------------------------- /tests/add_07.failure: -------------------------------------------------------------------------------- 1 | a = true + 1 2 | -------------------------------------------------------------------------------- /tests/add_08.failure: -------------------------------------------------------------------------------- 1 | a = 1 + true 2 | -------------------------------------------------------------------------------- /tests/add_09.failure: -------------------------------------------------------------------------------- 1 | a = null + "" 2 | -------------------------------------------------------------------------------- /tests/add_10.failure: -------------------------------------------------------------------------------- 1 | a = "" + null 2 | -------------------------------------------------------------------------------- /tests/add_11.failure: -------------------------------------------------------------------------------- 1 | a = true + "" 2 | -------------------------------------------------------------------------------- /tests/add_12.failure: -------------------------------------------------------------------------------- 1 | a = "" + true 2 | -------------------------------------------------------------------------------- /tests/add_13.failure: -------------------------------------------------------------------------------- 1 | a = 1 + "" 2 | -------------------------------------------------------------------------------- /tests/add_14.failure: -------------------------------------------------------------------------------- 1 | a = "" + 1 2 | -------------------------------------------------------------------------------- /tests/add_15.failure: -------------------------------------------------------------------------------- 1 | a = null + $"" 2 | -------------------------------------------------------------------------------- /tests/add_16.failure: -------------------------------------------------------------------------------- 1 | a = $"" + null 2 | -------------------------------------------------------------------------------- /tests/add_17.failure: -------------------------------------------------------------------------------- 1 | a = true + $"" 2 | -------------------------------------------------------------------------------- /tests/add_18.failure: -------------------------------------------------------------------------------- 1 | a = $"" + true 2 | -------------------------------------------------------------------------------- /tests/add_19.failure: -------------------------------------------------------------------------------- 1 | a = 1 + $"" 2 | -------------------------------------------------------------------------------- /tests/add_20.failure: -------------------------------------------------------------------------------- 1 | a = $"" + 1 2 | -------------------------------------------------------------------------------- /tests/add_21.failure: -------------------------------------------------------------------------------- 1 | a = "" + $"" 2 | -------------------------------------------------------------------------------- /tests/add_22.failure: -------------------------------------------------------------------------------- 1 | a = $"" + "" 2 | -------------------------------------------------------------------------------- /tests/add_23.failure: -------------------------------------------------------------------------------- 1 | a = null + {} 2 | -------------------------------------------------------------------------------- /tests/add_24.failure: -------------------------------------------------------------------------------- 1 | a = {} + null 2 | -------------------------------------------------------------------------------- /tests/add_25.failure: -------------------------------------------------------------------------------- 1 | a = true + {} 2 | -------------------------------------------------------------------------------- /tests/add_26.failure: -------------------------------------------------------------------------------- 1 | a = {} + true 2 | -------------------------------------------------------------------------------- /tests/add_27.failure: -------------------------------------------------------------------------------- 1 | a = 1 + {} 2 | -------------------------------------------------------------------------------- /tests/add_28.failure: -------------------------------------------------------------------------------- 1 | a = {} + 1 2 | -------------------------------------------------------------------------------- /tests/add_29.failure: -------------------------------------------------------------------------------- 1 | a = "" + {} 2 | -------------------------------------------------------------------------------- /tests/add_30.failure: -------------------------------------------------------------------------------- 1 | a = {} + "" 2 | -------------------------------------------------------------------------------- /tests/add_31.failure: -------------------------------------------------------------------------------- 1 | a = $"" + {} 2 | -------------------------------------------------------------------------------- /tests/add_32.failure: -------------------------------------------------------------------------------- 1 | a = {} + $"" 2 | -------------------------------------------------------------------------------- /tests/add_33.failure: -------------------------------------------------------------------------------- 1 | a = null + [] 2 | -------------------------------------------------------------------------------- /tests/add_34.failure: -------------------------------------------------------------------------------- 1 | a = [] + null 2 | -------------------------------------------------------------------------------- /tests/add_35.failure: -------------------------------------------------------------------------------- 1 | a = true + [] 2 | -------------------------------------------------------------------------------- /tests/add_36.failure: -------------------------------------------------------------------------------- 1 | a = [] + true 2 | -------------------------------------------------------------------------------- /tests/add_37.failure: -------------------------------------------------------------------------------- 1 | a = 1 + [] 2 | -------------------------------------------------------------------------------- /tests/add_38.failure: -------------------------------------------------------------------------------- 1 | a = [] + 1 2 | -------------------------------------------------------------------------------- /tests/add_39.failure: -------------------------------------------------------------------------------- 1 | a = "" + [] 2 | -------------------------------------------------------------------------------- /tests/add_40.failure: -------------------------------------------------------------------------------- 1 | a = [] + "" 2 | -------------------------------------------------------------------------------- /tests/add_41.failure: -------------------------------------------------------------------------------- 1 | a = $"" + [] 2 | -------------------------------------------------------------------------------- /tests/add_42.failure: -------------------------------------------------------------------------------- 1 | a = [] + $"" 2 | -------------------------------------------------------------------------------- /tests/add_43.failure: -------------------------------------------------------------------------------- 1 | a = {} + [] 2 | -------------------------------------------------------------------------------- /tests/add_44.failure: -------------------------------------------------------------------------------- 1 | a = [] + {} 2 | -------------------------------------------------------------------------------- /tests/add_45.failure: -------------------------------------------------------------------------------- 1 | a = [] 2 | b = {} 3 | c = (a) + (b) 4 | -------------------------------------------------------------------------------- /tests/add_46.failure: -------------------------------------------------------------------------------- 1 | a = null 2 | b = 1 3 | c = (a) + (b) 4 | -------------------------------------------------------------------------------- /tests/add_47.failure: -------------------------------------------------------------------------------- 1 | a = null 2 | b = 1 3 | c = (a) 4 | d = (b) 5 | e = (c) + (d) 6 | -------------------------------------------------------------------------------- /tests/add_48.failure: -------------------------------------------------------------------------------- 1 | a { 2 | b { 3 | c { 4 | } 5 | c [ 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/add_number.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: 18446744073709551615, 3 | b: -1, 4 | c: -7, 5 | d: -1, 6 | e: -1, 7 | f: -19, 8 | g: 1, 9 | h: 1, 10 | i: 0, 11 | j: 0, 12 | k: 42, 13 | l: 8, 14 | m: 1, 15 | n: 1 16 | } 17 | -------------------------------------------------------------------------------- /tests/add_number.success: -------------------------------------------------------------------------------- 1 | a = 9223372036854775807 + 9223372036854775808 2 | b = -9223372036854775808 + 9223372036854775807 3 | c = -3 + -4 4 | d = -6 + 5 5 | e = 7 + -8 6 | f = -9 + -10 7 | g = 0 + 1 8 | h = 1 + 0 9 | i = 0 + 0 10 | j = 0 + 0 + 0 11 | k = 21 + 21 12 | l = +5 + +3 13 | m = -3 ++4 14 | n = 2+-1 15 | -------------------------------------------------------------------------------- /tests/add_string.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: "a", 3 | b: "ab", 4 | c: "abc" 5 | } 6 | -------------------------------------------------------------------------------- /tests/add_string.success: -------------------------------------------------------------------------------- 1 | a = "a" 2 | 3 | b = "a" 4 | b += "b" 5 | 6 | c = "a" + "b" + "c" 7 | -------------------------------------------------------------------------------- /tests/array_index_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: 1, 3 | baz: 5, 4 | foo: [ 5 | 1, 6 | 12, 7 | 3, 8 | 34, 9 | 5 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tests/array_index_01.success: -------------------------------------------------------------------------------- 1 | foo = [ 0 1 2 3 4 ] 2 | bar = (foo.0) 3 | baz = (foo.4) 4 | foo.1 += 10 5 | foo.3 += 30 6 | foo.* += 1 7 | -------------------------------------------------------------------------------- /tests/array_index_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: [] 3 | } 4 | -------------------------------------------------------------------------------- /tests/array_index_02.success: -------------------------------------------------------------------------------- 1 | foo = [ 1 2 3 ] 2 | foo.* = delete 3 | -------------------------------------------------------------------------------- /tests/binary.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a : $3031, 3 | b : $3031, 4 | c : $3031 5 | } 6 | -------------------------------------------------------------------------------- /tests/binary.success: -------------------------------------------------------------------------------- 1 | a = $3031 2 | b = $30 + $31 3 | c = $"\x30\x31" 4 | -------------------------------------------------------------------------------- /tests/braces.jaxn: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /tests/braces.success: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /tests/combo_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | a: { 4 | baz: 2 5 | }, 6 | b: { 7 | bar: 42, 8 | baz: 1 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/combo_01.success: -------------------------------------------------------------------------------- 1 | foo.*.bar = 42 2 | foo.a.bar = delete 3 | foo.b.baz = 1 4 | foo.a.baz = 2 5 | -------------------------------------------------------------------------------- /tests/combo_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | a: { 4 | bar: 42, 5 | baz: 2 6 | }, 7 | b: { 8 | bar: 42, 9 | baz: 1 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/combo_02.success: -------------------------------------------------------------------------------- 1 | foo.a.bar = delete 2 | foo.*.bar = 42 3 | foo.b.baz = 1 4 | foo.a.baz = 2 5 | -------------------------------------------------------------------------------- /tests/commas.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | commas: { 3 | arrays: [ 4 | [ 5 | 1, 6 | 2, 7 | 3 8 | ], 9 | [ 10 | 1, 11 | 2, 12 | 3 13 | ], 14 | [ 15 | 1, 16 | 2, 17 | 3 18 | ], 19 | [ 20 | 1, 21 | 2, 22 | 3 23 | ], 24 | [ 25 | 1, 26 | 2, 27 | 3 28 | ] 29 | ], 30 | objects: [ 31 | { 32 | a: 1, 33 | b: 2, 34 | c: 3 35 | }, 36 | { 37 | a: 1, 38 | b: 2, 39 | c: 3 40 | }, 41 | { 42 | a: 1, 43 | b: 2, 44 | c: 3 45 | }, 46 | { 47 | a: 1, 48 | b: 2, 49 | c: 3 50 | }, 51 | { 52 | a: 1, 53 | b: 2, 54 | c: 3 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/commas.success: -------------------------------------------------------------------------------- 1 | commas : { 2 | arrays : [ 3 | [ 1 2 3 ], 4 | [ 1, 2, 3 ], 5 | [ 1, 2, 3, ], 6 | [ 1 2, 3 ] 7 | [ 1 2 3, ] 8 | ] 9 | objects : [ 10 | { a : 1 b : 2 c : 3 }, 11 | { a : 1, b : 2, c : 3 }, 12 | { a : 1, b : 2, c : 3, }, 13 | { a : 1 b : 2, c : 3 } 14 | { a : 1 b : 2 c : 3, } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /tests/comments.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: 1, 3 | b: 2, 4 | c: 3, 5 | d: 4, 6 | e: { 7 | f: 6 8 | }, 9 | g: [ 10 | 7 11 | ], 12 | h: "hH" 13 | } 14 | -------------------------------------------------------------------------------- /tests/comments.success: -------------------------------------------------------------------------------- 1 | #!/bin/grmblfx 2 | 3 | # This is a comment. 4 | 5 | // This is another comment. 6 | 7 | /* And another one. */ 8 | 9 | /* These comments /* don't nest */ 10 | 11 | a = 1 12 | b = 2 # foo 13 | c = 3 // foo 14 | 15 | /* foo */ d /* foo */ = /* foo */ 4 /* foo */ 16 | 17 | e /* foo */ { /* foo */ f = 6 /* foo */ , /* foo */ } /* foo */ 18 | 19 | g /* foo */ [ /* foo */ 7 /* foo */ , /* foo */ ] /* foo */ 20 | 21 | h /* foo */ += /* foo */ "h" /* foo */ + /* foo */ "H" /* foo */ 22 | -------------------------------------------------------------------------------- /tests/complex_01.failure: -------------------------------------------------------------------------------- 1 | a = (default (b) "foo") 2 | b = (default (a) "bar") 3 | -------------------------------------------------------------------------------- /tests/complex_02.failure: -------------------------------------------------------------------------------- 1 | x.* = 3 2 | x.a += 1 3 | 4 | a = 2 5 | y.a = 1 6 | y.* += (a) 7 | -------------------------------------------------------------------------------- /tests/complex_03.failure: -------------------------------------------------------------------------------- 1 | a = (default (b) "foo") + "a" 2 | b = (default (a) "bar") + "b" 3 | -------------------------------------------------------------------------------- /tests/debug_traits.config: -------------------------------------------------------------------------------- 1 | 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 2 | -------------------------------------------------------------------------------- /tests/delete.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | c: [ 3 | {}, 4 | {} 5 | ], 6 | d: { 7 | a: {}, 8 | b: {}, 9 | c: {} 10 | }, 11 | f: {}, 12 | g: 2, 13 | h: 2 14 | } 15 | -------------------------------------------------------------------------------- /tests/delete.success: -------------------------------------------------------------------------------- 1 | a = 1 2 | a = delete 3 | 4 | b.c.d = delete 5 | 6 | c = [ { 7 | d = delete 8 | } { 9 | e = 42 10 | } ] 11 | 12 | c.1.e = delete 13 | 14 | d.a.d = 1 15 | d.b.d = 2 16 | d.c.d = 3 17 | 18 | d.*.d = delete 19 | e.*.e = delete 20 | 21 | f.a = 1 22 | f.b = 2 23 | f.c = 3 24 | 25 | f.* = delete 26 | 27 | g = 1 28 | g = delete 29 | g = 2 30 | 31 | h += 1 32 | h = delete 33 | h += 2 34 | -------------------------------------------------------------------------------- /tests/doc_asterisk_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | servers: { 3 | primary: { 4 | port: 7000 5 | }, 6 | secondary: { 7 | port: 7000 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/doc_asterisk_01.success: -------------------------------------------------------------------------------- 1 | servers 2 | { 3 | primary 4 | { 5 | port = 443 6 | } 7 | secondary 8 | { 9 | port = 8888 10 | } 11 | } 12 | servers.*.port = 7000 // Testing 13 | -------------------------------------------------------------------------------- /tests/doc_default.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: false, 3 | foo: 1 4 | } 5 | -------------------------------------------------------------------------------- /tests/doc_default.success: -------------------------------------------------------------------------------- 1 | foo = (default 1 2) 2 | bar = (default null false true) 3 | -------------------------------------------------------------------------------- /tests/doc_delete_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | ip: "127.0.0.2", 3 | port: 27960 4 | } 5 | -------------------------------------------------------------------------------- /tests/doc_delete_01.success: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/qs 2 | 3 | ip = "127.0.0.2" 4 | port = 27960 5 | maps = [ "ztn" "dm13" "t9" ] 6 | maps = delete // Changed our minds, no maps. 7 | -------------------------------------------------------------------------------- /tests/doc_delete_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: 44 3 | } 4 | -------------------------------------------------------------------------------- /tests/doc_delete_02.success: -------------------------------------------------------------------------------- 1 | foo = 42 2 | foo = delete 3 | foo += 44 4 | -------------------------------------------------------------------------------- /tests/doc_dotted_names.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | bar: { 4 | baz: 3 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/doc_dotted_names.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | bar.baz += 1 4 | } 5 | foo.bar 6 | { 7 | baz += 1 8 | } 9 | foo.bar.baz += 1 10 | -------------------------------------------------------------------------------- /tests/doc_include.inc: -------------------------------------------------------------------------------- 1 | bar = 42 2 | baz = [ true, false ] 3 | -------------------------------------------------------------------------------- /tests/doc_include.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: 42, 3 | baz: [ 4 | true, 5 | false 6 | ], 7 | foo: { 8 | bar: 42, 9 | baz: [ 10 | true, 11 | false 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/doc_include.success: -------------------------------------------------------------------------------- 1 | // Include the file whose contents are shown below. 2 | (include "tests/doc_include.inc") 3 | 4 | foo 5 | { 6 | // Include the same file again, this time within an object. 7 | (include "tests/doc_include.inc") 8 | } 9 | 10 | // Use include? with a non-existing file, not an error. 11 | (include? "tests/non_existing_file_is_no_error_with_question_mark") 12 | -------------------------------------------------------------------------------- /tests/doc_object_merge_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | a: 10, 4 | b: 22, 5 | c: 3, 6 | d: 40 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/doc_object_merge_01.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | a = 1 4 | b = 2 5 | c = 3 6 | } 7 | foo 8 | { 9 | a = 10 10 | b += 20 11 | d = 40 12 | } 13 | -------------------------------------------------------------------------------- /tests/doc_references_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: { 4 | c: { 5 | i: 4, 6 | j: 3, 7 | k: 2, 8 | x: 4 9 | }, 10 | x: 3 11 | }, 12 | x: 2 13 | }, 14 | r: 3, 15 | x: 1 16 | } 17 | -------------------------------------------------------------------------------- /tests/doc_references_01.success: -------------------------------------------------------------------------------- 1 | r = (a.b.x) 2 | 3 | a 4 | { 5 | b 6 | { 7 | c 8 | { 9 | i = (x) 10 | j = (b.x) 11 | k = (a.x) 12 | 13 | x = 4 14 | } 15 | x = 3 16 | } 17 | x = 2 18 | } 19 | x = 1 20 | -------------------------------------------------------------------------------- /tests/doc_references_02.failure: -------------------------------------------------------------------------------- 1 | a = (b) 2 | b = (a) 3 | -------------------------------------------------------------------------------- /tests/doc_references_03.failure: -------------------------------------------------------------------------------- 1 | a 2 | { 3 | a 4 | { 5 | c = (a.b) 6 | } 7 | b = 1 8 | } 9 | -------------------------------------------------------------------------------- /tests/doc_references_05.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: 3, 3 | baz: 13, 4 | foo: [ 5 | 10, 6 | 11, 7 | 12, 8 | 13, 9 | 14 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tests/doc_references_05.success: -------------------------------------------------------------------------------- 1 | foo = [ 10 11 12 13 14 ] 2 | bar = 3 3 | baz = (foo.(bar)) 4 | -------------------------------------------------------------------------------- /tests/doc_references_06.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | ttt: { 3 | bar: { 4 | a: 1 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/doc_references_06.success: -------------------------------------------------------------------------------- 1 | (temporary foo) 2 | (temporary foo.baz) 3 | 4 | foo 5 | { 6 | bar 7 | { 8 | a = 1 9 | } 10 | baz 11 | { 12 | b = 2 13 | } 14 | } 15 | 16 | ttt = (foo) 17 | -------------------------------------------------------------------------------- /tests/doc_temporary.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: { 3 | host: "127.0.0.1", 4 | port: 6001, 5 | version: 42 6 | }, 7 | foo: { 8 | host: "127.0.0.2", 9 | port: 6000, 10 | version: 42 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/doc_temporary.success: -------------------------------------------------------------------------------- 1 | (temporary template) // Can occur before... 2 | 3 | template 4 | { 5 | host = "127.0.0.1" 6 | port = 6000 7 | version = 42 8 | } 9 | 10 | foo = (template) + 11 | { 12 | host = "127.0.0.2" 13 | } 14 | 15 | bar = (template) + 16 | { 17 | port = 6001 18 | } 19 | 20 | (temporary template) // ...and/or after. 21 | -------------------------------------------------------------------------------- /tests/empty.jaxn: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/empty.success: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taocpp/config/93a455e103cdd8030e770dfff4e2d64d9057ed46/tests/empty.success -------------------------------------------------------------------------------- /tests/env.failure: -------------------------------------------------------------------------------- 1 | a = (env "RUBBERDUCKY") 2 | -------------------------------------------------------------------------------- /tests/extensions.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | default: { 3 | a: 1, 4 | b: 2, 5 | c: 1, 6 | d: null 7 | }, 8 | env: { 9 | a: "env_value", 10 | b: "default_value" 11 | }, 12 | parse: { 13 | a: 42, 14 | b: null 15 | }, 16 | split: { 17 | a: [], 18 | b: [ 19 | "a" 20 | ], 21 | c: [ 22 | "a" 23 | ], 24 | d: [ 25 | "a", 26 | "b", 27 | "c" 28 | ], 29 | e: [ 30 | "a", 31 | "b", 32 | "c" 33 | ] 34 | }, 35 | string: { 36 | a: "", 37 | b: "foo", 38 | c: "01" 39 | }, 40 | unready: { 41 | a: "env_value", 42 | b: "env_value", 43 | c: "env_value" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/extensions.success: -------------------------------------------------------------------------------- 1 | default 2 | { 3 | a = (default 1 2 3 4 5) 4 | b = (default null null 2) 5 | c = (default 1 null) 6 | d = null // (default null null) 7 | } 8 | 9 | env 10 | { 11 | a = (env "TAO_CONFIG") 12 | 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") 13 | } 14 | 15 | parse 16 | { 17 | a = (parse "42") 18 | b = (parse "null") 19 | } 20 | 21 | split 22 | { 23 | a = (split "") 24 | b = (split "a") 25 | c = (split " a ") 26 | d = (split "a b c") 27 | e = (split " a b c ") 28 | } 29 | 30 | string 31 | { 32 | a = (string "") 33 | b = (string "foo") 34 | c = (string $3031) 35 | } 36 | 37 | unready 38 | { 39 | a = (env "TAO_CONFIG") 40 | b = (default (a) (c)) 41 | c = (env "TAO_CONFIG") 42 | } 43 | -------------------------------------------------------------------------------- /tests/formats.cbor: -------------------------------------------------------------------------------- 1 | ehallo -------------------------------------------------------------------------------- /tests/formats.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | jaxn: "hallo", 3 | txt: "hallo", 4 | } 5 | -------------------------------------------------------------------------------- /tests/formats.json: -------------------------------------------------------------------------------- 1 | "hallo" 2 | -------------------------------------------------------------------------------- /tests/formats.msgpack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taocpp/config/93a455e103cdd8030e770dfff4e2d64d9057ed46/tests/formats.msgpack -------------------------------------------------------------------------------- /tests/formats.success: -------------------------------------------------------------------------------- 1 | // cbor = (cbor (read "tests/formats.cbor")) 2 | jaxn = (jaxn (read "tests/formats.json")) 3 | // json = (json (read "tests/formats.json")) 4 | // msgpack = (msgpack (read "tests/formats.msgpack")) 5 | txt = (string (read "tests/formats.txt")) 6 | // ubjson = (ubjson (read "tests/formats.ubjson")) 7 | -------------------------------------------------------------------------------- /tests/formats.txt: -------------------------------------------------------------------------------- 1 | hallo -------------------------------------------------------------------------------- /tests/formats.ubjson: -------------------------------------------------------------------------------- 1 | SUhallo -------------------------------------------------------------------------------- /tests/include.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | simple: 42 4 | }, 5 | b: { 6 | simple: 43 7 | }, 8 | c: {}, 9 | simple: 42 10 | } 11 | -------------------------------------------------------------------------------- /tests/include.success: -------------------------------------------------------------------------------- 1 | (include "tests/simple.success") 2 | 3 | a = { 4 | (include "tests/simple.success") 5 | } 6 | 7 | b = { 8 | ( include "tests/simple.success" ) 9 | } 10 | 11 | b.simple += 1 12 | 13 | c = { 14 | (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") 15 | } 16 | -------------------------------------------------------------------------------- /tests/jaxn.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: [ 3 | null, 4 | true, 5 | false, 6 | 42, 7 | $FF, 8 | "foo", 9 | { 10 | a: null, 11 | b: true, 12 | c: false, 13 | d: 42, 14 | e: $FF, 15 | f: "foo" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tests/jaxn.success: -------------------------------------------------------------------------------- 1 | foo = (jaxn "[ null, true, false, 42, $ff, 'foo', { a: null, b: true, c: false, d: 42, e: $ff, f: 'foo' } ]") 2 | -------------------------------------------------------------------------------- /tests/merge_number_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_01.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = 1 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v = 2 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_number_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 3 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_02.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = 1 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v += 2 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_number_03.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_03.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += 1 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v = 2 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_number_04.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 3 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_04.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += 1 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v += 2 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_number_05.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 1 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_05.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = 1 4 | } 5 | 6 | bar = 7 | { 8 | v = 2 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_number_06.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 1 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_06.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = 1 4 | } 5 | 6 | bar = 7 | { 8 | v += 2 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_number_07.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 3 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_07.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += 1 4 | } 5 | 6 | bar = 7 | { 8 | v = 2 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_number_08.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: 1 4 | }, 5 | bar: { 6 | v: 3 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_number_08.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += 1 4 | } 5 | 6 | bar = 7 | { 8 | v += 2 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_string_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_01.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = "1" 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v = "2" 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_string_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "12" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_02.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = "1" 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v += "2" 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_string_03.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "2" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_03.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += "1" 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v = "2" 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_string_04.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "12" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_04.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += "1" 4 | } 5 | 6 | bar = (foo) + 7 | { 8 | v += "2" 9 | } 10 | -------------------------------------------------------------------------------- /tests/merge_string_05.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_05.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = "1" 4 | } 5 | 6 | bar = 7 | { 8 | v = "2" 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_string_06.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_06.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v = "1" 4 | } 5 | 6 | bar = 7 | { 8 | v += "2" 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_string_07.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "21" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_07.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += "1" 4 | } 5 | 6 | bar = 7 | { 8 | v = "2" 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/merge_string_08.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | v: "1" 4 | }, 5 | bar: { 6 | v: "21" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/merge_string_08.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | v += "1" 4 | } 5 | 6 | bar = 7 | { 8 | v += "2" 9 | } + (foo) 10 | -------------------------------------------------------------------------------- /tests/numbers.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | dec0: -1000000000000000, 3 | dec1: 0, 4 | dec2: 0, 5 | dec3: 0, 6 | dec4: 42, 7 | dec5: 1284712984, 8 | dec6: 1284712984, 9 | dec7: -1284712984, 10 | dec8: 1000000000000000, 11 | dec9: 1000000000000000, 12 | float1: 0.1, 13 | float2: 1.23e47, 14 | float3: -0.42, 15 | float4: -0.12, 16 | float5: 0.0, 17 | float6: NaN, 18 | float7: -Infinity, 19 | hex1: 291, 20 | hex2: 291, 21 | hex3: -291 22 | } 23 | -------------------------------------------------------------------------------- /tests/numbers.success: -------------------------------------------------------------------------------- 1 | # Just enough to convince us that we have properly integrated the JSON library... 2 | # ...which has a far more extensive test-suite for parsing integers and doubles. 3 | 4 | dec1 = 0 5 | dec2 = -0 6 | dec3 = +0 7 | dec4 = 42 8 | dec5 = 1284712984 9 | dec6 = +1284712984 10 | dec7 = -1284712984 11 | dec8 = 1000000000000000 12 | dec9 = +1000000000000000 13 | dec0 = -1000000000000000 14 | 15 | hex1 = 0x123 16 | hex2 = +0X123 17 | hex3 = -0x123 18 | 19 | float1 = .1 20 | float2 = 123e45 21 | float3 = -.42 22 | float4 = -1.2e-1 23 | float5 = 0.0 24 | float6 = NaN 25 | float7 = -Infinity 26 | -------------------------------------------------------------------------------- /tests/quoted.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | " ": { 4 | b: 1 5 | } 6 | }, 7 | c: { 8 | " ": { 9 | d: 2 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/quoted.success: -------------------------------------------------------------------------------- 1 | a." ".b = 1 2 | c.' '.d = 2 3 | -------------------------------------------------------------------------------- /tests/reference_01.failure: -------------------------------------------------------------------------------- 1 | a = (b) 2 | b = (a) 3 | -------------------------------------------------------------------------------- /tests/reference_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: 1, 3 | b: { 4 | c: 2 5 | }, 6 | d: 1, 7 | e: 2, 8 | f: { 9 | g: { 10 | h: 4 11 | } 12 | }, 13 | i: "g", 14 | j: 8, 15 | k: 15 16 | } 17 | -------------------------------------------------------------------------------- /tests/reference_01.success: -------------------------------------------------------------------------------- 1 | k = (f.(i).h) + (b.c) + 9 2 | 3 | a = 1 4 | 5 | b.c = 2 6 | 7 | d = (a) 8 | e = (b.c) 9 | 10 | f.g.h = 1 + (a) + 2 11 | i = "g" 12 | j = 3 + (f.(i).h) + 1 13 | -------------------------------------------------------------------------------- /tests/reference_02.failure: -------------------------------------------------------------------------------- 1 | a = 1 + (b) 2 | b = 1 + (a) 3 | -------------------------------------------------------------------------------- /tests/reference_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: [ 3 | { 4 | i: 42 5 | } 6 | ], 7 | foo: { 8 | i: 42 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/reference_02.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | i = 42 4 | } 5 | bar 6 | [ 7 | (foo) 8 | ] 9 | -------------------------------------------------------------------------------- /tests/reference_03.failure: -------------------------------------------------------------------------------- 1 | a = (b) 2 | b = (c) 3 | c = (a) 4 | -------------------------------------------------------------------------------- /tests/reference_03.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | baz: [ 3 | [ 4 | [ 5 | { 6 | i: 42 7 | } 8 | ] 9 | ] 10 | ], 11 | foo: { 12 | bar: { 13 | i: 42 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/reference_03.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | bar 4 | { 5 | i = 42 6 | } 7 | } 8 | baz 9 | [ [ [ 10 | (foo.bar) 11 | ] ] ] 12 | -------------------------------------------------------------------------------- /tests/reference_04.failure: -------------------------------------------------------------------------------- 1 | a = [ 0 1 2 ] 2 | b = (a.3) 3 | -------------------------------------------------------------------------------- /tests/reference_05.failure: -------------------------------------------------------------------------------- 1 | a = (c) 2 | -------------------------------------------------------------------------------- /tests/reference_06.failure: -------------------------------------------------------------------------------- 1 | a 2 | { 3 | a 4 | { 5 | b = 1 6 | } 7 | b 8 | { 9 | c = (a.a) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/reference_07.failure: -------------------------------------------------------------------------------- 1 | a 2 | { 3 | b 4 | { 5 | c = (a) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/reference_08.failure: -------------------------------------------------------------------------------- 1 | a = null 2 | b = ((a)) 3 | -------------------------------------------------------------------------------- /tests/reference_09.failure: -------------------------------------------------------------------------------- 1 | a = [] 2 | b = ((a)) 3 | -------------------------------------------------------------------------------- /tests/reference_10.failure: -------------------------------------------------------------------------------- 1 | foo 2 | [ 3 | ] 4 | baz 5 | [ 6 | (foo.bar) 7 | ] 8 | -------------------------------------------------------------------------------- /tests/reference_11.failure: -------------------------------------------------------------------------------- 1 | a.b.c = (b.x) 2 | a.b.x = (b.c) 3 | -------------------------------------------------------------------------------- /tests/reference_12.failure: -------------------------------------------------------------------------------- 1 | a = ((y)) 2 | y = ((a)) 3 | -------------------------------------------------------------------------------- /tests/regression_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | interface: { 4 | ip: "127.0.0.1" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/regression_01.success: -------------------------------------------------------------------------------- 1 | (temporary tmp) 2 | 3 | tmp = 4 | { 5 | ip = "127.0.0.1" 6 | } 7 | 8 | foo 9 | { 10 | interface 11 | { 12 | ip = (tmp.ip) 13 | } 14 | } 15 | 16 | foo 17 | { 18 | interface 19 | { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/regression_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | interface: { 4 | ip: "127.0.0.1" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/regression_02.success: -------------------------------------------------------------------------------- 1 | (temporary tmp) 2 | 3 | tmp 4 | { 5 | ip = "127.0.0.1" 6 | } 7 | 8 | foo 9 | { 10 | interface 11 | { 12 | ip = (tmp.ip) 13 | } 14 | } 15 | 16 | foo 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /tests/regression_03.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: [ 4 | 2 5 | ] 6 | }, 7 | c: { 8 | d: [ 9 | 2 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/regression_03.success: -------------------------------------------------------------------------------- 1 | a 2 | { 3 | b = [ 1 ] 4 | } 5 | 6 | a 7 | { 8 | b = [ 2 ] 9 | } 10 | 11 | c.d = [ 1 ] 12 | c.d = [ 2 ] 13 | -------------------------------------------------------------------------------- /tests/regression_04.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: 42 4 | }, 5 | c: { 6 | b: 42, 7 | d: 1, 8 | x: { 9 | a: 90 10 | } 11 | }, 12 | e: { 13 | f: 43 14 | }, 15 | g: { 16 | f: 43, 17 | h: 2, 18 | x: { 19 | a: 91 20 | } 21 | }, 22 | h: { 23 | i: 44 24 | }, 25 | j: { 26 | i: 44, 27 | k: 3, 28 | x: { 29 | a: 92 30 | } 31 | }, 32 | l: { 33 | m: { 34 | n: 45 35 | } 36 | }, 37 | o: { 38 | m: { 39 | n: 45 40 | }, 41 | p: { 42 | q: 4 43 | }, 44 | x: { 45 | a: 93 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/regression_04.success: -------------------------------------------------------------------------------- 1 | a.b = 42 2 | c = (a) 3 | c.d += 1 4 | c.x.a = 90 5 | 6 | e.f = 43 7 | g = (e) 8 | g.h = 2 9 | g.x.a = 91 10 | 11 | h.i = 44 12 | j = (h) 13 | j += { k = 3 } 14 | j.x.a = 92 15 | 16 | l.m.n = 45 17 | o = (l) 18 | o.p.q = 4 19 | o.x.a = 93 20 | -------------------------------------------------------------------------------- /tests/regression_05.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: 1, 4 | c: { 5 | b: 2, 6 | d: { 7 | x: 2, 8 | y: 3 9 | } 10 | }, 11 | e: 3 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/regression_05.success: -------------------------------------------------------------------------------- 1 | a { 2 | b = 1 3 | e = 3 4 | 5 | c { 6 | b = 2 7 | 8 | d { 9 | x = (b) 10 | y = (e) 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/regression_06.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: 42 4 | }, 5 | c: { 6 | b: 42 7 | }, 8 | d: 42 9 | } 10 | -------------------------------------------------------------------------------- /tests/regression_06.success: -------------------------------------------------------------------------------- 1 | a.b = 42 2 | c = (a) 3 | d = (c.b) 4 | -------------------------------------------------------------------------------- /tests/regression_07.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: { 4 | c: 8, 5 | d: { 6 | e: 13 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/regression_07.success: -------------------------------------------------------------------------------- 1 | a = { 2 | b = { 3 | c = 1 4 | d = { 5 | e = 4 6 | } 7 | } 8 | } 9 | 10 | a.b.c += 7 11 | a.b.d.e += 9 12 | -------------------------------------------------------------------------------- /tests/regression_08.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: { 3 | baz: { 4 | a: 11, 5 | b: 3 6 | } 7 | }, 8 | foo: { 9 | a: 1, 10 | b: 2 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/regression_08.success: -------------------------------------------------------------------------------- 1 | foo 2 | { 3 | a = 1 4 | b = 2 5 | } 6 | 7 | bar 8 | { 9 | baz = (foo) + 10 | { 11 | a += 10 12 | b = 3 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/regression_09.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: { 3 | m: 3, 4 | n: 1 5 | }, 6 | baz: 3, 7 | foo: { 8 | n: 1 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/regression_09.success: -------------------------------------------------------------------------------- 1 | foo.n = 1 2 | bar = (foo) 3 | baz = 3 4 | bar.m = (baz) 5 | -------------------------------------------------------------------------------- /tests/regression_10.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | d: { 3 | e: { 4 | f: 42 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/regression_10.success: -------------------------------------------------------------------------------- 1 | a.b.c = delete 2 | a.b.c = delete 3 | 4 | d.e.f = 42 5 | 6 | d.e.g.h.i = delete 7 | d.e.g.h.i = delete 8 | -------------------------------------------------------------------------------- /tests/regression_11.jaxn: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /tests/regression_11.success: -------------------------------------------------------------------------------- 1 | (temporary a.a) 2 | 3 | (permanent b.a) 4 | 5 | (temporary c.a) 6 | (temporary c.a) 7 | 8 | (permanent d.a) 9 | (permanent d.a) 10 | 11 | (permanent e.a) 12 | (temporary e.a) 13 | 14 | (temporary f.a) 15 | (permanent f.a) 16 | 17 | (temporary g.a) 18 | (permanent g.a) 19 | (temporary g.a) 20 | (permanent g.a) 21 | 22 | h = 1 23 | i = 2 24 | 25 | (permanent h) 26 | h = delete 27 | 28 | (temporary i) 29 | i = delete 30 | (permanent i) 31 | -------------------------------------------------------------------------------- /tests/regression_12.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: { 4 | d: 1 5 | } 6 | }, 7 | b: { 8 | c: { 9 | e: 2 10 | } 11 | }, 12 | c: { 13 | d: { 14 | g: 3 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/regression_12.success: -------------------------------------------------------------------------------- 1 | a.b.c.d.e = delete 2 | a.b.d = 1 3 | 4 | (temporary b.c.d.e.f) 5 | b.c.e = 2 6 | 7 | (permanent c.d.e.f.g) 8 | c.d.g = 3 9 | -------------------------------------------------------------------------------- /tests/regression_13.failure: -------------------------------------------------------------------------------- 1 | foo = [ 0 ] 2 | foo.0 = delete 3 | bar = (foo.0) 4 | -------------------------------------------------------------------------------- /tests/scoping.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | h: { 3 | i: { 4 | j: { 5 | k: 43, 6 | m: 43 7 | }, 8 | l: 43 9 | }, 10 | n: 43 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/scoping.success: -------------------------------------------------------------------------------- 1 | h { 2 | i { 3 | j { 4 | k = 43 5 | } 6 | l = (j.k) 7 | j.m = (k) 8 | } 9 | n = (h.i.j.k) 10 | } 11 | -------------------------------------------------------------------------------- /tests/serialise.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | str: "{b1:true,b2:\"Hello, Test!\",b3:[$00,$DEADBEEF],b4:42}" 3 | } 4 | -------------------------------------------------------------------------------- /tests/serialise.success: -------------------------------------------------------------------------------- 1 | (temporary foo) 2 | 3 | foo 4 | { 5 | b1 = true 6 | b2 = "Hello, Test!" 7 | b3 = [ $00, $deadbeef ] 8 | b4 = 42 9 | } 10 | 11 | str = (print (foo)) 12 | -------------------------------------------------------------------------------- /tests/shell.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | shell: { 3 | a: "hallo\n" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/shell.success: -------------------------------------------------------------------------------- 1 | shell 2 | { 3 | a = (shell "echo hallo") 4 | } 5 | -------------------------------------------------------------------------------- /tests/simple.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | simple: 42 3 | } 4 | -------------------------------------------------------------------------------- /tests/simple.success: -------------------------------------------------------------------------------- 1 | simple = 42 2 | -------------------------------------------------------------------------------- /tests/space.jaxn: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /tests/space.success: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /tests/star_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | t1: { 3 | a: { 4 | b: { 5 | c: { 6 | x: 3, 7 | y: 3, 8 | z: 2 9 | } 10 | } 11 | } 12 | }, 13 | t2: { 14 | a: { 15 | b: { 16 | c: { 17 | x: 1, 18 | y: 3, 19 | z: 2 20 | } 21 | } 22 | } 23 | }, 24 | t3: { 25 | a: { 26 | b: { 27 | c: { 28 | x: "21", 29 | y: "12", 30 | z: "2" 31 | } 32 | } 33 | } 34 | }, 35 | t4: { 36 | a: { 37 | b: { 38 | c: { 39 | x: "1", 40 | y: "12", 41 | z: "2" 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/star_01.success: -------------------------------------------------------------------------------- 1 | t1 2 | { 3 | a.b.c.x = 2 4 | a.b.c.* += 1 5 | a.b.c.y += 2 6 | a.b.c.z = 2 7 | } 8 | 9 | t2 10 | { 11 | a.b.c.x = 2 12 | a.b.c.* = 1 13 | a.b.c.y += 2 14 | a.b.c.z = 2 15 | } 16 | 17 | t3 18 | { 19 | a.b.c.x = "2" 20 | a.b.c.* += "1" 21 | a.b.c.y += "2" 22 | a.b.c.z = "2" 23 | } 24 | 25 | t4 26 | { 27 | a.b.c.x = "2" 28 | a.b.c.* = "1" 29 | a.b.c.y += "2" 30 | a.b.c.z = "2" 31 | } 32 | -------------------------------------------------------------------------------- /tests/star_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | foo: { 3 | a: [ 4 | "10", 5 | "20", 6 | "30", 7 | "06", 8 | "07", 9 | "08" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/star_02.success: -------------------------------------------------------------------------------- 1 | foo.a += [ "1" "2" "3" ] 2 | foo.a.* += "0" 3 | foo.a += [ "6" "7" "8" ] 4 | -------------------------------------------------------------------------------- /tests/star_03.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a: { 3 | b: { 4 | c: { 5 | i: 3 6 | } 7 | } 8 | }, 9 | f: {} 10 | } 11 | -------------------------------------------------------------------------------- /tests/star_03.success: -------------------------------------------------------------------------------- 1 | f = {} 2 | 3 | a 4 | { 5 | b 6 | { 7 | c 8 | { 9 | i += 1 10 | } 11 | } 12 | } + (f) + { 13 | b 14 | { 15 | c 16 | { 17 | i += 1 18 | } 19 | } + (f) + { 20 | c 21 | { 22 | } 23 | } 24 | } 25 | 26 | a.*.*.* += 1 27 | -------------------------------------------------------------------------------- /tests/string_01.failure: -------------------------------------------------------------------------------- 1 | foo = (split 42) 2 | -------------------------------------------------------------------------------- /tests/string_02.failure: -------------------------------------------------------------------------------- 1 | foo = (env $ff) 2 | -------------------------------------------------------------------------------- /tests/temporary_01.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | c: { 3 | d: {} 4 | }, 5 | f: { 6 | g: {} 7 | }, 8 | foo: { 9 | bar: { 10 | c: { 11 | d: {} 12 | }, 13 | f: { 14 | g: {} 15 | } 16 | }, 17 | baz: [ 18 | { 19 | c: { 20 | d: {} 21 | }, 22 | f: { 23 | g: {} 24 | } 25 | } 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/temporary_01.success: -------------------------------------------------------------------------------- 1 | (temporary a) 2 | a = 1 3 | 4 | b = 2 5 | (temporary b) 6 | 7 | (temporary c.d.e) 8 | c.d.e = 3 9 | 10 | f.g.h = 4 11 | (temporary f.g.h) 12 | 13 | i = 5 14 | (temporary i) 15 | i = 6 16 | 17 | j += 7 18 | (temporary j) 19 | j += 8 20 | 21 | (temporary k) 22 | (temporary l.m) 23 | 24 | foo.bar 25 | { 26 | (temporary a) 27 | a = 1 28 | 29 | b = 2 30 | (temporary b) 31 | 32 | (temporary c.d.e) 33 | c.d.e = 3 34 | 35 | f.g.h = 4 36 | (temporary f.g.h) 37 | 38 | i = 5 39 | (temporary i) 40 | i = 6 41 | 42 | j += 7 43 | (temporary j) 44 | j += 8 45 | 46 | (temporary k) 47 | (temporary l.m) 48 | } 49 | 50 | foo.baz 51 | [ { 52 | (temporary a) 53 | a = 1 54 | 55 | b = 2 56 | (temporary b) 57 | 58 | (temporary c.d.e) 59 | c.d.e = 3 60 | 61 | f.g.h = 4 62 | (temporary f.g.h) 63 | 64 | i = 5 65 | (temporary i) 66 | i = 6 67 | 68 | j += 7 69 | (temporary j) 70 | j += 8 71 | 72 | (temporary k) 73 | (temporary l.m) 74 | } ] 75 | -------------------------------------------------------------------------------- /tests/temporary_02.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | dst: { 3 | bar: { 4 | i: 42 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/temporary_02.success: -------------------------------------------------------------------------------- 1 | (temporary foo) 2 | (temporary foo.baz) 3 | 4 | foo 5 | { 6 | bar 7 | { 8 | i = 42 9 | } 10 | baz 11 | { 12 | j = 43 13 | } 14 | } 15 | 16 | dst = (foo) 17 | -------------------------------------------------------------------------------- /tests/temporary_03.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | d: 1, 3 | e: 2, 4 | f: 3, 5 | g: 4, 6 | h: 5 7 | } 8 | -------------------------------------------------------------------------------- /tests/temporary_03.success: -------------------------------------------------------------------------------- 1 | (temporary a) 2 | (permanent a) 3 | 4 | (permanent b) 5 | 6 | (permanent c) 7 | (temporary c) 8 | 9 | (temporary d) 10 | (permanent d) 11 | d = 1 12 | 13 | (temporary e) 14 | e = 2 15 | (permanent e) 16 | 17 | f = 3 18 | (temporary f) 19 | (permanent f) 20 | 21 | (permanent g) 22 | g = 4 23 | 24 | h = 5 25 | (permanent h) 26 | 27 | (permanent i) 28 | (temporary i) 29 | i = 6 30 | 31 | (permanent j) 32 | j = 7 33 | (temporary j) 34 | 35 | k = 8 36 | (permanent k) 37 | (temporary k) 38 | -------------------------------------------------------------------------------- /tests/temporary_04.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: { 3 | a: [], 4 | b: [] 5 | }, 6 | foo: { 7 | a: {}, 8 | b: { // TODO: Fix code -- b should be an empty object. 9 | c: 1, 10 | d: 2, 11 | e: [ 12 | 3 13 | ] 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/temporary_04.success: -------------------------------------------------------------------------------- 1 | foo.a 2 | { 3 | c = 1 4 | d = 2 5 | e = [ 3 ] 6 | } 7 | 8 | (temporary foo.*.*) 9 | 10 | foo.b 11 | { 12 | c = 1 13 | d = 2 14 | e = [ 3 ] 15 | } 16 | 17 | bar.a 18 | [ 19 | true 20 | false 21 | null 22 | ] 23 | 24 | (temporary bar.*.*) 25 | 26 | bar.b 27 | [ 28 | true 29 | false 30 | null 31 | ] 32 | -------------------------------------------------------------------------------- /tests/temporary_05.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | bar: {}, 3 | foo: {} 4 | } 5 | -------------------------------------------------------------------------------- /tests/temporary_05.success: -------------------------------------------------------------------------------- 1 | foo.a 2 | { 3 | c = 1 4 | } 5 | 6 | (temporary foo.*) 7 | 8 | foo.b 9 | { 10 | c = 1 11 | } 12 | 13 | bar.a 14 | [ 15 | true 16 | ] 17 | 18 | (temporary bar.*) 19 | 20 | bar.b 21 | [ 22 | true 23 | ] 24 | -------------------------------------------------------------------------------- /tests/unready.jaxn: -------------------------------------------------------------------------------- 1 | { 2 | a1: 1, 3 | a2: 1, 4 | a3: 3, 5 | a4: 1, 6 | b2: 3, 7 | b4: 3, 8 | c1: 1, 9 | c2: 1, 10 | c3: 3, 11 | c4: 1, 12 | d1: "nu", 13 | d2: null, 14 | d3: "ll", 15 | e1: "nu", 16 | e2: [ 17 | "null" 18 | ], 19 | e3: "ll", 20 | f1: "asdlfjaslj", 21 | f2: "default", 22 | f3: "x,cqokxi2$(&!" 23 | } 24 | -------------------------------------------------------------------------------- /tests/unready.success: -------------------------------------------------------------------------------- 1 | a1 = 1 2 | a2 = (default null (a1) (a3)) 3 | a3 = 3 4 | a4 = (a2) 5 | 6 | b2 = (default null 1 + 2) 7 | b4 = (b2) 8 | 9 | c1 = (default null 1) 10 | c2 = (default null (c1) (c3)) 11 | c3 = (default null 3) 12 | c4 = (c2) 13 | 14 | d1 = "nu" 15 | d2 = (parse (d1) + (d3)) 16 | d3 = "ll" 17 | 18 | e1 = "nu" 19 | e2 = (split (e1) + (e3)) 20 | e3 = "ll" 21 | 22 | f1 = "asdlfjaslj" 23 | f2 = (env? (f1) + (f3) "default") 24 | f3 = "x,cqokxi2$(&!" 25 | --------------------------------------------------------------------------------