diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9ca0e79..2ac59735 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: CXX: ${{ matrix.platform.cxx }} steps: - name: Install ClangFormat - run: pip install clang-format==19.1.0 + run: pipx install clang-format==19.1.0 - uses: actions/checkout@v3 - name: Install dependencies (macOS) diff --git a/DEPENDENCIES b/DEPENDENCIES index 57ba58df..ad1384e9 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,6 +1,6 @@ vendorpull https://github.com/sourcemeta/vendorpull 70342aaf458e6cb80baeb5b718901075fc42ede6 -jsontoolkit https://github.com/sourcemeta/jsontoolkit 9abbaee71e9e00e95632858d29c7ebe5c2a723b0 -alterschema https://github.com/sourcemeta/alterschema 358df64771979da64e043a416cf340d83a5382ca +jsontoolkit https://github.com/sourcemeta/jsontoolkit 9685d29e2e633d71319c64b1ab2fbceab865dbf3 +alterschema https://github.com/sourcemeta/alterschema 36dc1933bbbdbf1f2574c309e41f510f58874838 googletest https://github.com/google/googletest 987e225614755fec7253aa95bf959c09e0d380d7 bootstrap https://github.com/twbs/bootstrap 1a6fdfae6be09b09eaced8f0e442ca6f7680a61e -noa https://github.com/sourcemeta/noa 517e88aef5981b88ac6bb8caff15d17dffcb4320 +noa https://github.com/sourcemeta/noa 837e1ff981f8df45d9e2977a50f5da61d8affed4 diff --git a/src/compiler/encoding.h b/src/compiler/encoding.h index be1f2b36..304d45c8 100644 --- a/src/compiler/encoding.h +++ b/src/compiler/encoding.h @@ -4,8 +4,6 @@ #include #include -#include // std::future - namespace sourcemeta::jsonbinpack { constexpr auto ENCODING_V1{"tag:sourcemeta.com,2024:jsonbinpack/encoding/v1"}; @@ -13,22 +11,19 @@ constexpr auto ENCODING_V1{"tag:sourcemeta.com,2024:jsonbinpack/encoding/v1"}; inline auto make_resolver(const sourcemeta::jsontoolkit::SchemaResolver &fallback) -> auto { return [&fallback](std::string_view identifier) - -> std::future> { - std::promise> promise; + -> std::optional { if (identifier == ENCODING_V1) { - promise.set_value(sourcemeta::jsontoolkit::parse(R"JSON({ + return sourcemeta::jsontoolkit::parse(R"JSON({ "$id": "tag:sourcemeta.com,2024:jsonbinpack/encoding/v1", "$schema": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true, "tag:sourcemeta.com,2024:jsonbinpack/encoding/v1": true } - })JSON")); + })JSON"); } else { - promise.set_value(fallback(identifier).get()); + return fallback(identifier); } - - return promise.get_future(); }; } diff --git a/test/compiler/canonicalizer_test.cc b/test/compiler/canonicalizer_test.cc index 26abaa0a..ed5e804b 100644 --- a/test/compiler/canonicalizer_test.cc +++ b/test/compiler/canonicalizer_test.cc @@ -4,24 +4,19 @@ #include #include -#include // std::promise, std::future #include // std::optional #include // std::string static auto test_resolver(std::string_view identifier) - -> std::future> { - std::promise> promise; + -> std::optional { if (identifier == "https://jsonbinpack.sourcemeta.com/draft/unknown") { - promise.set_value(sourcemeta::jsontoolkit::parse(R"JSON({ + return sourcemeta::jsontoolkit::parse(R"JSON({ "$schema": "https://jsonbinpack.sourcemeta.com/draft/unknown", "$id": "https://jsonbinpack.sourcemeta.com/draft/unknown" - })JSON")); + })JSON"); } else { - promise.set_value( - sourcemeta::jsontoolkit::official_resolver(identifier).get()); + return sourcemeta::jsontoolkit::official_resolver(identifier); } - - return promise.get_future(); } TEST(JSONBinPack_Canonicalizer, unsupported_draft) { diff --git a/vendor/alterschema/src/engine/rule.cc b/vendor/alterschema/src/engine/rule.cc index 669d3a53..3e45c659 100644 --- a/vendor/alterschema/src/engine/rule.cc +++ b/vendor/alterschema/src/engine/rule.cc @@ -48,9 +48,9 @@ auto sourcemeta::alterschema::Rule::apply( "Could not determine the schema dialect"); } - const auto vocabularies{vocabularies_to_set( - sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect) - .get())}; + const auto vocabularies{ + vocabularies_to_set(sourcemeta::jsontoolkit::vocabularies( + schema, resolver, default_dialect))}; if (!this->condition(schema, dialect.value(), vocabularies, pointer)) { return {}; } @@ -83,8 +83,8 @@ auto sourcemeta::alterschema::Rule::check( "Could not determine the schema dialect"); } - const auto vocabularies{vocabularies_to_set( - sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect) - .get())}; + const auto vocabularies{ + vocabularies_to_set(sourcemeta::jsontoolkit::vocabularies( + schema, resolver, default_dialect))}; return this->condition(schema, dialect.value(), vocabularies, pointer); } diff --git a/vendor/alterschema/vendor/noa/cmake/noa/compiler/options.cmake b/vendor/alterschema/vendor/noa/cmake/noa/compiler/options.cmake index b1fc6e53..dde90f21 100644 --- a/vendor/alterschema/vendor/noa/cmake/noa/compiler/options.cmake +++ b/vendor/alterschema/vendor/noa/cmake/noa/compiler/options.cmake @@ -42,6 +42,10 @@ function(noa_add_default_options visibility target) -Winvalid-offsetof -funroll-loops -fstrict-aliasing + -ftree-vectorize + + # To improve how much GCC/Clang will vectorize + -fno-math-errno # Assume that signed arithmetic overflow of addition, subtraction and # multiplication wraps around using twos-complement representation @@ -78,10 +82,28 @@ function(noa_add_default_options visibility target) -fslp-vectorize) elseif(NOA_COMPILER_GCC) target_compile_options("${target}" ${visibility} + -fno-trapping-math # Newer versions of GCC (i.e. 14) seem to print a lot of false-positives here -Wno-dangling-reference - + # GCC seems to print a lot of false-positives here + -Wno-free-nonheap-object # Disables runtime type information -fno-rtti) endif() endfunction() + +# For studying failed vectorization results +# - On Clang , seems to only take effect on release shared builds +# - On GCC, seems to only take effect on release shared builds +function(noa_add_vectorization_diagnostics target) + if(NOA_COMPILER_LLVM) + # See https://llvm.org/docs/Vectorizers.html#id6 + target_compile_options("${target}" PRIVATE + -Rpass-analysis=loop-vectorize + -Rpass-missed=loop-vectorize) + elseif(NOA_COMPILER_GCC) + target_compile_options("${target}" PRIVATE + -fopt-info-vec-missed + -fopt-info-loop-missed) + endif() +endfunction() diff --git a/vendor/alterschema/vendor/noa/cmake/noa/library.cmake b/vendor/alterschema/vendor/noa/cmake/noa/library.cmake index 05d57748..9868714d 100644 --- a/vendor/alterschema/vendor/noa/cmake/noa/library.cmake +++ b/vendor/alterschema/vendor/noa/cmake/noa/library.cmake @@ -1,6 +1,6 @@ function(noa_library) cmake_parse_arguments(NOA_LIBRARY "" - "NAMESPACE;PROJECT;NAME;FOLDER" "PRIVATE_HEADERS;SOURCES" ${ARGN}) + "NAMESPACE;PROJECT;NAME;FOLDER;VARIANT" "PRIVATE_HEADERS;SOURCES" ${ARGN}) if(NOT NOA_LIBRARY_PROJECT) message(FATAL_ERROR "You must pass the project name using the PROJECT option") @@ -18,7 +18,11 @@ function(noa_library) set(INCLUDE_PREFIX "include/${NOA_LIBRARY_PROJECT}") endif() - set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + if(NOT NOA_LIBRARY_VARIANT) + set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + else() + set(PUBLIC_HEADER "../${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + endif() if(NOA_LIBRARY_SOURCES) set(ABSOLUTE_PRIVATE_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${NOA_LIBRARY_NAME}_export.h") @@ -38,6 +42,11 @@ function(noa_library) set(ALIAS_NAME "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}") endif() + if(NOA_LIBRARY_VARIANT) + set(TARGET_NAME "${TARGET_NAME}_${NOA_LIBRARY_VARIANT}") + set(ALIAS_NAME "${ALIAS_NAME}::${NOA_LIBRARY_VARIANT}") + endif() + if(NOA_LIBRARY_SOURCES) add_library(${TARGET_NAME} ${PUBLIC_HEADER} ${ABSOLUTE_PRIVATE_HEADERS} ${NOA_LIBRARY_SOURCES}) @@ -50,23 +59,34 @@ function(noa_library) add_library(${ALIAS_NAME} ALIAS ${TARGET_NAME}) + if(NOT NOA_LIBRARY_VARIANT) + set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/include") + else() + set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/../include") + endif() if(NOA_LIBRARY_SOURCES) target_include_directories(${TARGET_NAME} PUBLIC - "$" + "$" "$") else() target_include_directories(${TARGET_NAME} INTERFACE - "$" + "$" "$") endif() if(NOA_LIBRARY_SOURCES) + if(NOA_LIBRARY_VARIANT) + set(export_name "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}::${NOA_LIBRARY_VARIANT}") + else() + set(export_name "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}") + endif() + set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME} PUBLIC_HEADER "${PUBLIC_HEADER}" PRIVATE_HEADER "${ABSOLUTE_PRIVATE_HEADERS}" - EXPORT_NAME "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}" + EXPORT_NAME "${export_name}" FOLDER "${NOA_LIBRARY_FOLDER}") else() set_target_properties(${TARGET_NAME} @@ -93,7 +113,7 @@ function(noa_library) endfunction() function(noa_library_install) - cmake_parse_arguments(NOA_LIBRARY "" "NAMESPACE;PROJECT;NAME" "" ${ARGN}) + cmake_parse_arguments(NOA_LIBRARY "" "NAMESPACE;PROJECT;NAME;VARIANT" "" ${ARGN}) if(NOT NOA_LIBRARY_PROJECT) message(FATAL_ERROR "You must pass the project name using the PROJECT option") @@ -114,6 +134,10 @@ function(noa_library_install) set(NAMESPACE_PREFIX "") endif() + if(NOA_LIBRARY_VARIANT) + set(TARGET_NAME "${TARGET_NAME}_${NOA_LIBRARY_VARIANT}") + endif() + include(GNUInstallDirs) install(TARGETS ${TARGET_NAME} EXPORT ${TARGET_NAME} diff --git a/vendor/jsontoolkit/CMakeLists.txt b/vendor/jsontoolkit/CMakeLists.txt index 37f1c948..00afac4f 100644 --- a/vendor/jsontoolkit/CMakeLists.txt +++ b/vendor/jsontoolkit/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(jsontoolkit VERSION 2.0.0 LANGUAGES CXX - DESCRIPTION "The high-performance JSON Schema evaluator and related JSON utilities for modern C++" +project(jsontoolkit VERSION 2.0.0 LANGUAGES C CXX + DESCRIPTION "The swiss-army knife for JSON programming in C++" HOMEPAGE_URL "https://jsontoolkit.sourcemeta.com") list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(vendor/noa/cmake/noa.cmake) @@ -9,7 +9,6 @@ include(vendor/noa/cmake/noa.cmake) option(JSONTOOLKIT_URI "Build the JSON Toolkit URI library" ON) option(JSONTOOLKIT_JSON "Build the JSON Toolkit JSON library" ON) option(JSONTOOLKIT_JSONSCHEMA "Build the JSON Toolkit JSON Schema library" ON) -option(JSONTOOLKIT_EVALUATOR "Build the JSON Toolkit JSON Schema evaluator library" ON) option(JSONTOOLKIT_JSONPOINTER "Build the JSON Toolkit JSON Pointer library" ON) option(JSONTOOLKIT_JSONL "Build the JSON Toolkit JSONL library" ON) option(JSONTOOLKIT_TESTS "Build the JSON Toolkit tests" OFF) @@ -50,13 +49,7 @@ if(JSONTOOLKIT_JSON AND JSONTOOLKIT_JSONPOINTER) endif() if(JSONTOOLKIT_URI AND JSONTOOLKIT_JSON AND - JSONTOOLKIT_JSONPOINTER AND JSONTOOLKIT_EVALUATOR) - add_subdirectory(src/evaluator) -endif() - -if(JSONTOOLKIT_URI AND JSONTOOLKIT_JSON AND - JSONTOOLKIT_JSONPOINTER AND JSONTOOLKIT_EVALUATOR AND - JSONTOOLKIT_JSONSCHEMA) + JSONTOOLKIT_JSONPOINTER AND JSONTOOLKIT_JSONSCHEMA) add_subdirectory(src/jsonschema) endif() @@ -77,6 +70,7 @@ endif() if(PROJECT_IS_TOP_LEVEL) noa_target_clang_format(SOURCES + bindings/*.cc src/*.h src/*.cc benchmark/*.h benchmark/*.cc test/*.h test/*.cc) @@ -102,13 +96,7 @@ if(JSONTOOLKIT_TESTS) endif() if(JSONTOOLKIT_URI AND JSONTOOLKIT_JSON AND - JSONTOOLKIT_JSONPOINTER AND JSONTOOLKIT_EVALUATOR) - add_subdirectory(test/evaluator) - endif() - - if(JSONTOOLKIT_URI AND JSONTOOLKIT_JSON AND - JSONTOOLKIT_JSONPOINTER AND JSONTOOLKIT_EVALUATOR AND - JSONTOOLKIT_JSONSCHEMA) + JSONTOOLKIT_JSONPOINTER AND JSONTOOLKIT_JSONSCHEMA) add_subdirectory(test/jsonschema) endif() diff --git a/vendor/jsontoolkit/cmake/FindGoogleBenchmark.cmake b/vendor/jsontoolkit/cmake/FindGoogleBenchmark.cmake index 1ae1b8af..da442f63 100644 --- a/vendor/jsontoolkit/cmake/FindGoogleBenchmark.cmake +++ b/vendor/jsontoolkit/cmake/FindGoogleBenchmark.cmake @@ -1,5 +1,5 @@ -if(NOT Benchnark_FOUND) +if(NOT Benchmark_FOUND) set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Enable testing of the benchmark library.") add_subdirectory("${PROJECT_SOURCE_DIR}/vendor/googlebenchmark") - set(Benchnark_FOUND ON) + set(Benchmark_FOUND ON) endif() diff --git a/vendor/jsontoolkit/cmake/FindUriParser.cmake b/vendor/jsontoolkit/cmake/FindUriParser.cmake index 29a44938..0a73a5c9 100644 --- a/vendor/jsontoolkit/cmake/FindUriParser.cmake +++ b/vendor/jsontoolkit/cmake/FindUriParser.cmake @@ -1,17 +1,73 @@ if(NOT UriParser_FOUND) - set(URIPARSER_BUILD_DOCS OFF CACHE BOOL "omit docs") - set(URIPARSER_BUILD_TESTS OFF CACHE BOOL "omit tests") - set(URIPARSER_BUILD_TOOLS OFF CACHE BOOL "omit tools") - set(URIPARSER_BUILD_TOOLS OFF CACHE BOOL "omit tools") - set(URIPARSER_ENABLE_INSTALL OFF CACHE BOOL "omit installation") + set(URIPARSER_DIR "${PROJECT_SOURCE_DIR}/vendor/uriparser") - add_subdirectory("${PROJECT_SOURCE_DIR}/vendor/uriparser") + set(URIPARSER_PUBLIC_HEADER "${URIPARSER_DIR}/include/uriparser/Uri.h") + set(URIPARSER_PRIVATE_HEADERS + "${URIPARSER_DIR}/include/uriparser/UriBase.h" + "${URIPARSER_DIR}/include/uriparser/UriDefsAnsi.h" + "${URIPARSER_DIR}/include/uriparser/UriDefsConfig.h" + "${URIPARSER_DIR}/include/uriparser/UriDefsUnicode.h" + "${URIPARSER_DIR}/include/uriparser/UriIp4.h") + + configure_file("${URIPARSER_DIR}/src/UriConfig.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/uriparser/UriConfig.h") + + set(URIPARSER_SOURCES + "${URIPARSER_PUBLIC_HEADER}" ${URIPARSER_PRIVATE_HEADERS} + "${CMAKE_CURRENT_BINARY_DIR}/uriparser/UriConfig.h" + "${URIPARSER_DIR}/src/UriCommon.c" + "${URIPARSER_DIR}/src/UriCommon.h" + "${URIPARSER_DIR}/src/UriCompare.c" + "${URIPARSER_DIR}/src/UriEscape.c" + "${URIPARSER_DIR}/src/UriFile.c" + "${URIPARSER_DIR}/src/UriIp4.c" + "${URIPARSER_DIR}/src/UriIp4Base.c" + "${URIPARSER_DIR}/src/UriIp4Base.h" + "${URIPARSER_DIR}/src/UriMemory.c" + "${URIPARSER_DIR}/src/UriMemory.h" + "${URIPARSER_DIR}/src/UriNormalize.c" + "${URIPARSER_DIR}/src/UriNormalizeBase.c" + "${URIPARSER_DIR}/src/UriNormalizeBase.h" + "${URIPARSER_DIR}/src/UriParse.c" + "${URIPARSER_DIR}/src/UriParseBase.c" + "${URIPARSER_DIR}/src/UriParseBase.h" + "${URIPARSER_DIR}/src/UriQuery.c" + "${URIPARSER_DIR}/src/UriRecompose.c" + "${URIPARSER_DIR}/src/UriResolve.c" + "${URIPARSER_DIR}/src/UriShorten.c") + + add_library(uriparser ${URIPARSER_SOURCES}) add_library(uriparser::uriparser ALIAS uriparser) + if(BUILD_SHARED_LIBS) + target_compile_definitions(uriparser PUBLIC URI_LIBRARY_BUILD) + target_compile_definitions(uriparser PUBLIC URI_VISIBILITY) + else() + target_compile_definitions(uriparser PUBLIC URI_STATIC_BUILD) + endif() + + target_include_directories(uriparser PRIVATE "${URIPARSER_DIR}/include") + target_include_directories(uriparser PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/uriparser") + + target_include_directories(uriparser PUBLIC + "$" + "$") + + set_target_properties(uriparser + PROPERTIES + OUTPUT_NAME uriparser + PUBLIC_HEADER "${URIPARSER_PUBLIC_HEADER}" + PRIVATE_HEADER "${URIPARSER_PRIVATE_HEADERS}" + EXPORT_NAME uriparser) + if(JSONTOOLKIT_INSTALL) include(GNUInstallDirs) install(TARGETS uriparser EXPORT uriparser + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/uriparser" + COMPONENT sourcemeta_jsontoolkit_dev + PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/uriparser" + COMPONENT sourcemeta_jsontoolkit_dev RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT sourcemeta_jsontoolkit LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" diff --git a/vendor/jsontoolkit/config.cmake.in b/vendor/jsontoolkit/config.cmake.in index 6d611955..4a7d224b 100644 --- a/vendor/jsontoolkit/config.cmake.in +++ b/vendor/jsontoolkit/config.cmake.in @@ -9,7 +9,6 @@ if(NOT JSONTOOLKIT_COMPONENTS) list(APPEND JSONTOOLKIT_COMPONENTS jsonl) list(APPEND JSONTOOLKIT_COMPONENTS jsonpointer) list(APPEND JSONTOOLKIT_COMPONENTS jsonschema) - list(APPEND JSONTOOLKIT_COMPONENTS evaluator) endif() foreach(component ${JSONTOOLKIT_COMPONENTS}) @@ -36,22 +35,7 @@ foreach(component ${JSONTOOLKIT_COMPONENTS}) include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_uri.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_json.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_jsonpointer.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_evaluator.cmake") - - # GCC does not allow the use of std::promise, std::future - # without compiling with pthreads support. - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_THREAD_PREFER_PTHREAD TRUE) - set(THREADS_PREFER_PTHREAD_FLAG TRUE) - include(CMakeFindDependencyMacro) - find_dependency(Threads) - endif() - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_jsonschema.cmake") - elseif(component STREQUAL "evaluator") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_uri.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_json.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_jsontoolkit_evaluator.cmake") else() message(FATAL_ERROR "Unknown JSON Toolkit component: ${component}") endif() diff --git a/vendor/jsontoolkit/src/evaluator/CMakeLists.txt b/vendor/jsontoolkit/src/evaluator/CMakeLists.txt deleted file mode 100644 index 1140bc9f..00000000 --- a/vendor/jsontoolkit/src/evaluator/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -noa_library(NAMESPACE sourcemeta PROJECT jsontoolkit NAME evaluator - FOLDER "JSON Toolkit/Evaluator" - PRIVATE_HEADERS error.h value.h template.h context.h - SOURCES evaluator.cc context.cc trace.h) - -if(JSONTOOLKIT_INSTALL) - noa_library_install(NAMESPACE sourcemeta PROJECT jsontoolkit NAME evaluator) -endif() - -if(PROJECT_IS_TOP_LEVEL) - noa_add_vectorization_diagnostics(sourcemeta_jsontoolkit_evaluator) -endif() - -target_link_libraries(sourcemeta_jsontoolkit_evaluator PUBLIC - sourcemeta::jsontoolkit::json) -target_link_libraries(sourcemeta_jsontoolkit_evaluator PUBLIC - sourcemeta::jsontoolkit::jsonpointer) -target_link_libraries(sourcemeta_jsontoolkit_evaluator PRIVATE - sourcemeta::jsontoolkit::uri) diff --git a/vendor/jsontoolkit/src/evaluator/context.cc b/vendor/jsontoolkit/src/evaluator/context.cc deleted file mode 100644 index 699f63b0..00000000 --- a/vendor/jsontoolkit/src/evaluator/context.cc +++ /dev/null @@ -1,288 +0,0 @@ -#include -#include - -#include // assert - -namespace sourcemeta::jsontoolkit { - -auto EvaluationContext::prepare(const JSON &instance) -> void { - // Do a full reset for the next run - assert(this->evaluate_path_.empty()); - assert(this->instance_location_.empty()); - assert(this->frame_sizes.empty()); - assert(this->resources_.empty()); - this->instances_.clear(); - this->instances_.emplace_back(instance); - this->annotation_blacklist.clear(); - this->annotations_.clear(); - this->labels.clear(); - this->property_as_instance = false; -} - -auto EvaluationContext::push_without_traverse( - const Pointer &relative_schema_location, - const Pointer &relative_instance_location, - const std::string &schema_resource, const bool dynamic) -> void { - // Guard against infinite recursion in a cheap manner, as - // infinite recursion will manifest itself through huge - // ever-growing evaluate paths - constexpr auto EVALUATE_PATH_LIMIT{300}; - if (this->evaluate_path_.size() > EVALUATE_PATH_LIMIT) [[unlikely]] { - throw sourcemeta::jsontoolkit::SchemaEvaluationError( - "The evaluation path depth limit was reached " - "likely due to infinite recursion"); - } - - this->frame_sizes.emplace_back(relative_schema_location.size(), - relative_instance_location.size()); - this->evaluate_path_.push_back(relative_schema_location); - this->instance_location_.push_back(relative_instance_location); - - if (dynamic) { - // Note that we are potentially repeatedly pushing back the - // same schema resource over and over again. However, the - // logic for making sure this list is "pure" takes a lot of - // computation power. Being silly seems faster. - this->resources_.push_back(schema_resource); - } -} - -auto EvaluationContext::push(const Pointer &relative_schema_location, - const Pointer &relative_instance_location, - const std::string &schema_resource, - const bool dynamic) -> void { - this->push_without_traverse(relative_schema_location, - relative_instance_location, schema_resource, - dynamic); - if (!relative_instance_location.empty()) { - assert(!this->instances_.empty()); - this->instances_.emplace_back( - get(this->instances_.back().get(), relative_instance_location)); - } -} - -auto EvaluationContext::push(const Pointer &relative_schema_location, - const Pointer &relative_instance_location, - const std::string &schema_resource, - const bool dynamic, - std::reference_wrapper &&new_instance) - -> void { - this->push_without_traverse(relative_schema_location, - relative_instance_location, schema_resource, - dynamic); - assert(!relative_instance_location.empty()); - this->instances_.emplace_back(new_instance); -} - -auto EvaluationContext::pop(const bool dynamic) -> void { - assert(!this->frame_sizes.empty()); - const auto &sizes{this->frame_sizes.back()}; - this->evaluate_path_.pop_back(sizes.first); - this->instance_location_.pop_back(sizes.second); - if (sizes.second > 0) { - this->instances_.pop_back(); - } - - this->frame_sizes.pop_back(); - - // TODO: Do schema resource management using hashes to avoid - // expensive string comparisons - if (dynamic) { - assert(!this->resources_.empty()); - this->resources_.pop_back(); - } -} - -auto EvaluationContext::annotate(const WeakPointer ¤t_instance_location, - const JSON &value) - -> std::pair, bool> { - const auto result{this->annotations_.insert({current_instance_location, {}}) - .first->second.insert({this->evaluate_path(), {}}) - .first->second.insert(value)}; - return {*(result.first), result.second}; -} - -auto EvaluationContext::defines_annotation( - const WeakPointer &expected_instance_location, - const WeakPointer &base_evaluate_path, - const std::vector &keywords, const JSON &value) const -> bool { - if (keywords.empty()) { - return false; - } - - const auto instance_location_result{ - this->annotations_.find(expected_instance_location)}; - if (instance_location_result == this->annotations_.end()) { - return false; - } - - for (const auto &[schema_location, schema_annotations] : - instance_location_result->second) { - assert(!schema_location.empty()); - const auto &keyword{schema_location.back()}; - - if (keyword.is_property() && - std::find(keywords.cbegin(), keywords.cend(), keyword.to_property()) != - keywords.cend() && - schema_annotations.contains(value) && - schema_location.initial().starts_with(base_evaluate_path)) { - bool blacklisted = false; - for (const auto &masked : this->annotation_blacklist) { - if (schema_location.starts_with(masked) && - !this->evaluate_path_.starts_with(masked)) { - blacklisted = true; - break; - } - } - - if (!blacklisted) { - return true; - } - } - } - - return false; -} - -auto EvaluationContext::largest_annotation_index( - const WeakPointer &expected_instance_location, - const std::vector &keywords, - const std::uint64_t default_value) const -> std::uint64_t { - // TODO: We should be taking masks into account - - std::uint64_t result{default_value}; - - const auto instance_location_result{ - this->annotations_.find(expected_instance_location)}; - if (instance_location_result == this->annotations_.end()) { - return result; - } - - for (const auto &[schema_location, schema_annotations] : - instance_location_result->second) { - assert(!schema_location.empty()); - const auto &keyword{schema_location.back()}; - if (!keyword.is_property()) { - continue; - } - - if (std::find(keywords.cbegin(), keywords.cend(), keyword.to_property()) == - keywords.cend()) { - continue; - } - - for (const auto &annotation : schema_annotations) { - if (annotation.is_integer() && annotation.is_positive()) { - result = std::max( - result, static_cast(annotation.to_integer()) + 1); - } - } - } - - return result; -} - -auto EvaluationContext::enter(const WeakPointer::Token::Property &property) - -> void { - this->instance_location_.push_back(property); - this->instances_.emplace_back(this->instances_.back().get().at(property)); -} - -auto EvaluationContext::enter(const WeakPointer::Token::Index &index) -> void { - this->instance_location_.push_back(index); - this->instances_.emplace_back(this->instances_.back().get().at(index)); -} - -auto EvaluationContext::leave() -> void { - this->instance_location_.pop_back(); - this->instances_.pop_back(); -} - -auto EvaluationContext::instances() const noexcept - -> const std::vector> & { - return this->instances_; -} - -auto EvaluationContext::resources() const noexcept - -> const std::vector & { - return this->resources_; -} - -auto EvaluationContext::evaluate_path() const noexcept -> const WeakPointer & { - return this->evaluate_path_; -} - -auto EvaluationContext::instance_location() const noexcept - -> const WeakPointer & { - return this->instance_location_; -} - -auto EvaluationContext::target_type(const TargetType type) noexcept -> void { - this->property_as_instance = (type == TargetType::Key); -} - -auto EvaluationContext::resolve_target() -> const JSON & { - if (this->property_as_instance) [[unlikely]] { - // In this case, we still need to return a string in order - // to cope with non-string keywords inside `propertyNames` - // that need to fail validation. But then, the actual string - // we return doesn't matter, so we can always return a dummy one. - static const JSON empty_string{""}; - return empty_string; - } - - return this->instances_.back().get(); -} - -auto EvaluationContext::resolve_string_target() - -> std::optional> { - if (this->property_as_instance) [[unlikely]] { - assert(!this->instance_location().empty()); - assert(this->instance_location().back().is_property()); - return this->instance_location().back().to_property(); - } else { - const auto &result{this->instances_.back().get()}; - if (!result.is_string()) { - return std::nullopt; - } - - return result.to_string(); - } -} - -auto EvaluationContext::mark(const std::size_t id, - const SchemaCompilerTemplate &children) -> void { - this->labels.try_emplace(id, children); -} - -// TODO: At least currently, we only need to mask if a schema -// makes use of `unevaluatedProperties` or `unevaluatedItems` -// Detect if a schema does need this so if not, we avoid -// an unnecessary copy -auto EvaluationContext::mask() -> void { - this->annotation_blacklist.push_back(this->evaluate_path_); -} - -auto EvaluationContext::jump(const std::size_t id) const noexcept - -> const SchemaCompilerTemplate & { - assert(this->labels.contains(id)); - return this->labels.at(id).get(); -} - -auto EvaluationContext::find_dynamic_anchor(const std::string &anchor) const - -> std::optional { - for (const auto &resource : this->resources()) { - std::ostringstream name; - name << resource; - name << '#'; - name << anchor; - const auto label{std::hash{}(name.str())}; - if (this->labels.contains(label)) { - return label; - } - } - - return std::nullopt; -} - -} // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/evaluator/evaluator.cc b/vendor/jsontoolkit/src/evaluator/evaluator.cc deleted file mode 100644 index e9d46829..00000000 --- a/vendor/jsontoolkit/src/evaluator/evaluator.cc +++ /dev/null @@ -1,1189 +0,0 @@ -#include -#include - -#include "trace.h" - -#include // std::min, std::any_of -#include // assert -#include // std::distance, std::advance -#include // std::numeric_limits -#include // std::optional - -namespace { - -auto evaluate_step( - const sourcemeta::jsontoolkit::SchemaCompilerTemplate::value_type &step, - const sourcemeta::jsontoolkit::SchemaCompilerEvaluationMode mode, - const std::optional< - sourcemeta::jsontoolkit::SchemaCompilerEvaluationCallback> &callback, - sourcemeta::jsontoolkit::EvaluationContext &context) -> bool { - SOURCEMETA_TRACE_REGISTER_ID(trace_dispatch_id); - SOURCEMETA_TRACE_REGISTER_ID(trace_id); - SOURCEMETA_TRACE_START(trace_dispatch_id, "Dispatch"); - using namespace sourcemeta::jsontoolkit; - -#define STRINGIFY(x) #x - -#define EVALUATE_BEGIN(step_category, step_type, precondition) \ - SOURCEMETA_TRACE_END(trace_dispatch_id, "Dispatch"); \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &step_category{std::get(step)}; \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic); \ - const auto &target{context.resolve_target()}; \ - if (!(precondition)) { \ - context.pop(step_category.dynamic); \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; \ - } \ - if (step_category.report && callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), context.instance_location(), \ - context.null); \ - } \ - bool result{false}; - -#define EVALUATE_BEGIN_IF_STRING(step_category, step_type) \ - SOURCEMETA_TRACE_END(trace_dispatch_id, "Dispatch"); \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &step_category{std::get(step)}; \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic); \ - const auto &maybe_target{context.resolve_string_target()}; \ - if (!maybe_target.has_value()) { \ - context.pop(step_category.dynamic); \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; \ - } \ - if (step_category.report && callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), context.instance_location(), \ - context.null); \ - } \ - const auto &target{maybe_target.value().get()}; \ - bool result{false}; - -#define EVALUATE_BEGIN_NO_TARGET(step_category, step_type, precondition) \ - SOURCEMETA_TRACE_END(trace_dispatch_id, "Dispatch"); \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &step_category{std::get(step)}; \ - if (!(precondition)) { \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; \ - } \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic); \ - if (step_category.report && callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), context.instance_location(), \ - context.null); \ - } \ - bool result{false}; - - // This is a slightly complicated dance to avoid traversing the relative - // instance location twice. We first need to traverse it to check if its - // valid in the document as part of the condition, but if it is, we can - // pass it to `.push()` so that it doesn't need to traverse it again. -#define EVALUATE_BEGIN_TRY_TARGET(step_category, step_type, precondition) \ - SOURCEMETA_TRACE_END(trace_dispatch_id, "Dispatch"); \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &target{context.resolve_target()}; \ - const auto &step_category{std::get(step)}; \ - if (!(precondition)) { \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; \ - } \ - auto target_check{ \ - try_get(target, step_category.relative_instance_location)}; \ - if (!target_check.has_value()) { \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; \ - } \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic, \ - std::move(target_check.value())); \ - if (step_category.report && callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), context.instance_location(), \ - context.null); \ - } \ - bool result{false}; - -#define EVALUATE_BEGIN_NO_PRECONDITION(step_category, step_type) \ - SOURCEMETA_TRACE_END(trace_dispatch_id, "Dispatch"); \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &step_category{std::get(step)}; \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic); \ - if (step_category.report && callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), context.instance_location(), \ - context.null); \ - } \ - bool result{false}; - -#define EVALUATE_END(step_category, step_type) \ - if (step_category.report && callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Post, result, step, \ - context.evaluate_path(), context.instance_location(), \ - context.null); \ - } \ - context.pop(step_category.dynamic); \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return result; - - // As a safety guard, only emit the annotation if it didn't exist already. - // Otherwise we risk confusing consumers - -#define EVALUATE_ANNOTATION(step_category, step_type, precondition, \ - destination, annotation_value) \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &step_category{std::get(step)}; \ - assert(step_category.relative_instance_location.empty()); \ - const auto &target{context.resolve_target()}; \ - if (!(precondition)) { \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; \ - } \ - const auto annotation_result{ \ - context.annotate(destination, annotation_value)}; \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic); \ - if (annotation_result.second && step_category.report && \ - callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), destination, context.null); \ - callback.value()(SchemaCompilerEvaluationType::Post, true, step, \ - context.evaluate_path(), destination, \ - annotation_result.first); \ - } \ - context.pop(step_category.dynamic); \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; - -#define EVALUATE_ANNOTATION_NO_PRECONDITION(step_category, step_type, \ - destination, annotation_value) \ - SOURCEMETA_TRACE_START(trace_id, STRINGIFY(step_type)); \ - const auto &step_category{std::get(step)}; \ - const auto annotation_result{ \ - context.annotate(destination, annotation_value)}; \ - context.push(step_category.relative_schema_location, \ - step_category.relative_instance_location, \ - step_category.schema_resource, step_category.dynamic); \ - if (annotation_result.second && step_category.report && \ - callback.has_value()) { \ - callback.value()(SchemaCompilerEvaluationType::Pre, true, step, \ - context.evaluate_path(), destination, context.null); \ - callback.value()(SchemaCompilerEvaluationType::Post, true, step, \ - context.evaluate_path(), destination, \ - annotation_result.first); \ - } \ - context.pop(step_category.dynamic); \ - SOURCEMETA_TRACE_END(trace_id, STRINGIFY(step_type)); \ - return true; - -#define IS_STEP(step_type) SchemaCompilerTemplateIndex::step_type - switch (static_cast(step.index())) { - case IS_STEP(SchemaCompilerAssertionFail): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, SchemaCompilerAssertionFail); - EVALUATE_END(assertion, SchemaCompilerAssertionFail); - } - - case IS_STEP(SchemaCompilerAssertionDefines): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionDefines, - target.is_object()); - result = target.defines(assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionDefines); - } - - case IS_STEP(SchemaCompilerAssertionDefinesAll): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionDefinesAll, - target.is_object()); - - // Otherwise we are we even emitting this instruction? - assert(assertion.value.size() > 1); - result = true; - for (const auto &property : assertion.value) { - if (!target.defines(property)) { - result = false; - break; - } - } - - EVALUATE_END(assertion, SchemaCompilerAssertionDefinesAll); - } - - case IS_STEP(SchemaCompilerAssertionPropertyDependencies): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionPropertyDependencies, - target.is_object()); - // Otherwise we are we even emitting this instruction? - assert(!assertion.value.empty()); - result = true; - for (const auto &[property, dependencies] : assertion.value) { - if (!target.defines(property)) { - continue; - } - - assert(!dependencies.empty()); - for (const auto &dependency : dependencies) { - if (!target.defines(dependency)) { - result = false; - // For efficiently breaking from the outer loop too - goto evaluate_assertion_property_dependencies_end; - } - } - } - - evaluate_assertion_property_dependencies_end: - EVALUATE_END(assertion, SchemaCompilerAssertionPropertyDependencies); - } - - case IS_STEP(SchemaCompilerAssertionType): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, SchemaCompilerAssertionType); - const auto &target{context.resolve_target()}; - // In non-strict mode, we consider a real number that represents an - // integer to be an integer - result = - target.type() == assertion.value || - (assertion.value == JSON::Type::Integer && target.is_integer_real()); - EVALUATE_END(assertion, SchemaCompilerAssertionType); - } - - case IS_STEP(SchemaCompilerAssertionTypeAny): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, SchemaCompilerAssertionTypeAny); - // Otherwise we are we even emitting this instruction? - assert(assertion.value.size() > 1); - const auto &target{context.resolve_target()}; - // In non-strict mode, we consider a real number that represents an - // integer to be an integer - for (const auto type : assertion.value) { - if (type == JSON::Type::Integer && target.is_integer_real()) { - result = true; - break; - } else if (type == target.type()) { - result = true; - break; - } - } - - EVALUATE_END(assertion, SchemaCompilerAssertionTypeAny); - } - - case IS_STEP(SchemaCompilerAssertionTypeStrict): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, - SchemaCompilerAssertionTypeStrict); - result = context.resolve_target().type() == assertion.value; - EVALUATE_END(assertion, SchemaCompilerAssertionTypeStrict); - } - - case IS_STEP(SchemaCompilerAssertionTypeStrictAny): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, - SchemaCompilerAssertionTypeStrictAny); - // Otherwise we are we even emitting this instruction? - assert(assertion.value.size() > 1); - result = (std::find(assertion.value.cbegin(), assertion.value.cend(), - context.resolve_target().type()) != - assertion.value.cend()); - EVALUATE_END(assertion, SchemaCompilerAssertionTypeStrictAny); - } - - case IS_STEP(SchemaCompilerAssertionTypeStringBounded): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, - SchemaCompilerAssertionTypeStringBounded); - const auto &target{context.resolve_target()}; - const auto minimum{std::get<0>(assertion.value)}; - const auto maximum{std::get<1>(assertion.value)}; - assert(!maximum.has_value() || maximum.value() >= minimum); - // Require early breaking - assert(!std::get<2>(assertion.value)); - result = target.type() == JSON::Type::String && - target.size() >= minimum && - (!maximum.has_value() || target.size() <= maximum.value()); - EVALUATE_END(assertion, SchemaCompilerAssertionTypeStringBounded); - } - - case IS_STEP(SchemaCompilerAssertionTypeArrayBounded): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, - SchemaCompilerAssertionTypeArrayBounded); - const auto &target{context.resolve_target()}; - const auto minimum{std::get<0>(assertion.value)}; - const auto maximum{std::get<1>(assertion.value)}; - assert(!maximum.has_value() || maximum.value() >= minimum); - // Require early breaking - assert(!std::get<2>(assertion.value)); - result = target.type() == JSON::Type::Array && target.size() >= minimum && - (!maximum.has_value() || target.size() <= maximum.value()); - EVALUATE_END(assertion, SchemaCompilerAssertionTypeArrayBounded); - } - - case IS_STEP(SchemaCompilerAssertionTypeObjectBounded): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, - SchemaCompilerAssertionTypeObjectBounded); - const auto &target{context.resolve_target()}; - const auto minimum{std::get<0>(assertion.value)}; - const auto maximum{std::get<1>(assertion.value)}; - assert(!maximum.has_value() || maximum.value() >= minimum); - // Require early breaking - assert(!std::get<2>(assertion.value)); - result = target.type() == JSON::Type::Object && - target.size() >= minimum && - (!maximum.has_value() || target.size() <= maximum.value()); - EVALUATE_END(assertion, SchemaCompilerAssertionTypeObjectBounded); - } - - case IS_STEP(SchemaCompilerAssertionRegex): { - EVALUATE_BEGIN_IF_STRING(assertion, SchemaCompilerAssertionRegex); - result = std::regex_search(target, assertion.value.first); - EVALUATE_END(assertion, SchemaCompilerAssertionRegex); - } - - case IS_STEP(SchemaCompilerAssertionStringSizeLess): { - EVALUATE_BEGIN_IF_STRING(assertion, - SchemaCompilerAssertionStringSizeLess); - result = (JSON::size(target) < assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionStringSizeLess); - } - - case IS_STEP(SchemaCompilerAssertionStringSizeGreater): { - EVALUATE_BEGIN_IF_STRING(assertion, - SchemaCompilerAssertionStringSizeGreater); - result = (JSON::size(target) > assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionStringSizeGreater); - } - - case IS_STEP(SchemaCompilerAssertionArraySizeLess): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionArraySizeLess, - target.is_array()); - result = (target.size() < assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionArraySizeLess); - } - - case IS_STEP(SchemaCompilerAssertionArraySizeGreater): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionArraySizeGreater, - target.is_array()); - result = (target.size() > assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionArraySizeGreater); - } - - case IS_STEP(SchemaCompilerAssertionObjectSizeLess): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionObjectSizeLess, - target.is_object()); - result = (target.size() < assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionObjectSizeLess); - } - - case IS_STEP(SchemaCompilerAssertionObjectSizeGreater): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionObjectSizeGreater, - target.is_object()); - result = (target.size() > assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionObjectSizeGreater); - } - - case IS_STEP(SchemaCompilerAssertionEqual): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, SchemaCompilerAssertionEqual); - result = (context.resolve_target() == assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionEqual); - } - - case IS_STEP(SchemaCompilerAssertionEqualsAny): { - EVALUATE_BEGIN_NO_PRECONDITION(assertion, - SchemaCompilerAssertionEqualsAny); - result = (std::find(assertion.value.cbegin(), assertion.value.cend(), - context.resolve_target()) != assertion.value.cend()); - EVALUATE_END(assertion, SchemaCompilerAssertionEqualsAny); - } - - case IS_STEP(SchemaCompilerAssertionGreaterEqual): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionGreaterEqual, - target.is_number()); - result = target >= assertion.value; - EVALUATE_END(assertion, SchemaCompilerAssertionGreaterEqual); - } - - case IS_STEP(SchemaCompilerAssertionLessEqual): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionLessEqual, - target.is_number()); - result = target <= assertion.value; - EVALUATE_END(assertion, SchemaCompilerAssertionLessEqual); - } - - case IS_STEP(SchemaCompilerAssertionGreater): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionGreater, - target.is_number()); - result = target > assertion.value; - EVALUATE_END(assertion, SchemaCompilerAssertionGreater); - } - - case IS_STEP(SchemaCompilerAssertionLess): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionLess, - target.is_number()); - result = target < assertion.value; - EVALUATE_END(assertion, SchemaCompilerAssertionLess); - } - - case IS_STEP(SchemaCompilerAssertionUnique): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionUnique, - target.is_array()); - result = target.unique(); - EVALUATE_END(assertion, SchemaCompilerAssertionUnique); - } - - case IS_STEP(SchemaCompilerAssertionDivisible): { - EVALUATE_BEGIN(assertion, SchemaCompilerAssertionDivisible, - target.is_number()); - assert(assertion.value.is_number()); - result = target.divisible_by(assertion.value); - EVALUATE_END(assertion, SchemaCompilerAssertionDivisible); - } - - case IS_STEP(SchemaCompilerAssertionStringType): { - EVALUATE_BEGIN_IF_STRING(assertion, SchemaCompilerAssertionStringType); - switch (assertion.value) { - case SchemaCompilerValueStringType::URI: - try { - // TODO: This implies a string copy - result = URI{target}.is_absolute(); - } catch (const URIParseError &) { - result = false; - } - - break; - default: - // We should never get here - assert(false); - } - - EVALUATE_END(assertion, SchemaCompilerAssertionStringType); - } - - case IS_STEP(SchemaCompilerAssertionPropertyType): { - EVALUATE_BEGIN_TRY_TARGET( - assertion, SchemaCompilerAssertionPropertyType, - // Note that here are are referring to the parent - // object that might hold the given property, - // before traversing into the actual property - target.is_object()); - // Now here we refer to the actual property - const auto &effective_target{context.resolve_target()}; - // In non-strict mode, we consider a real number that represents an - // integer to be an integer - result = effective_target.type() == assertion.value || - (assertion.value == JSON::Type::Integer && - effective_target.is_integer_real()); - EVALUATE_END(assertion, SchemaCompilerAssertionPropertyType); - } - - case IS_STEP(SchemaCompilerAssertionPropertyTypeStrict): { - EVALUATE_BEGIN_TRY_TARGET( - assertion, SchemaCompilerAssertionPropertyTypeStrict, - // Note that here are are referring to the parent - // object that might hold the given property, - // before traversing into the actual property - target.is_object()); - // Now here we refer to the actual property - result = context.resolve_target().type() == assertion.value; - EVALUATE_END(assertion, SchemaCompilerAssertionPropertyTypeStrict); - } - - case IS_STEP(SchemaCompilerLogicalOr): { - EVALUATE_BEGIN_NO_PRECONDITION(logical, SchemaCompilerLogicalOr); - result = logical.children.empty(); - for (const auto &child : logical.children) { - if (evaluate_step(child, mode, callback, context)) { - result = true; - // This boolean value controls whether we should still evaluate - // every disjunction even on fast mode - if (mode == SchemaCompilerEvaluationMode::Fast && !logical.value) { - break; - } - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalOr); - } - - case IS_STEP(SchemaCompilerLogicalAnd): { - EVALUATE_BEGIN_NO_PRECONDITION(logical, SchemaCompilerLogicalAnd); - result = true; - for (const auto &child : logical.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalAnd); - } - - case IS_STEP(SchemaCompilerLogicalWhenType): { - EVALUATE_BEGIN(logical, SchemaCompilerLogicalWhenType, - target.type() == logical.value); - result = true; - for (const auto &child : logical.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalWhenType); - } - - case IS_STEP(SchemaCompilerLogicalWhenDefines): { - EVALUATE_BEGIN(logical, SchemaCompilerLogicalWhenDefines, - target.is_object() && target.defines(logical.value)); - result = true; - for (const auto &child : logical.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalWhenDefines); - } - - case IS_STEP(SchemaCompilerLogicalWhenArraySizeGreater): { - EVALUATE_BEGIN(logical, SchemaCompilerLogicalWhenArraySizeGreater, - target.is_array() && target.size() > logical.value); - result = true; - for (const auto &child : logical.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalWhenArraySizeGreater); - } - - case IS_STEP(SchemaCompilerLogicalWhenArraySizeEqual): { - EVALUATE_BEGIN(logical, SchemaCompilerLogicalWhenArraySizeEqual, - target.is_array() && target.size() == logical.value); - result = true; - for (const auto &child : logical.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalWhenArraySizeEqual); - } - - case IS_STEP(SchemaCompilerLogicalXor): { - EVALUATE_BEGIN_NO_PRECONDITION(logical, SchemaCompilerLogicalXor); - result = true; - bool has_matched{false}; - for (const auto &child : logical.children) { - if (evaluate_step(child, mode, callback, context)) { - if (has_matched) { - result = false; - if (mode == SchemaCompilerEvaluationMode::Fast) { - break; - } - } else { - has_matched = true; - } - } - } - - result = result && has_matched; - EVALUATE_END(logical, SchemaCompilerLogicalXor); - } - - case IS_STEP(SchemaCompilerLogicalCondition): { - EVALUATE_BEGIN_NO_PRECONDITION(logical, SchemaCompilerLogicalCondition); - result = true; - const auto children_size{logical.children.size()}; - assert(children_size >= logical.value.first); - assert(children_size >= logical.value.second); - - auto condition_end{children_size}; - if (logical.value.first > 0) { - condition_end = logical.value.first; - } else if (logical.value.second > 0) { - condition_end = logical.value.second; - } - - for (std::size_t cursor = 0; cursor < condition_end; cursor++) { - if (!evaluate_step(logical.children[cursor], mode, callback, context)) { - result = false; - break; - } - } - - const auto consequence_start{result ? logical.value.first - : logical.value.second}; - const auto consequence_end{(result && logical.value.second > 0) - ? logical.value.second - : children_size}; - result = true; - if (consequence_start > 0) { - for (auto cursor = consequence_start; cursor < consequence_end; - cursor++) { - if (!evaluate_step(logical.children[cursor], mode, callback, - context)) { - result = false; - break; - } - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalCondition); - } - - case IS_STEP(SchemaCompilerLogicalNot): { - EVALUATE_BEGIN_NO_PRECONDITION(logical, SchemaCompilerLogicalNot); - // Ignore annotations produced inside "not" - context.mask(); - result = false; - for (const auto &child : logical.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = true; - if (mode == SchemaCompilerEvaluationMode::Fast) { - break; - } - } - } - - EVALUATE_END(logical, SchemaCompilerLogicalNot); - } - - case IS_STEP(SchemaCompilerControlLabel): { - EVALUATE_BEGIN_NO_PRECONDITION(control, SchemaCompilerControlLabel); - context.mark(control.value, control.children); - result = true; - for (const auto &child : control.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(control, SchemaCompilerControlLabel); - } - - case IS_STEP(SchemaCompilerControlMark): { - SOURCEMETA_TRACE_START(trace_id, "SchemaCompilerControlMark"); - const auto &control{std::get(step)}; - context.mark(control.value, control.children); - SOURCEMETA_TRACE_END(trace_id, "SchemaCompilerControlMark"); - return true; - } - - case IS_STEP(SchemaCompilerControlJump): { - EVALUATE_BEGIN_NO_PRECONDITION(control, SchemaCompilerControlJump); - result = true; - for (const auto &child : context.jump(control.value)) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - - EVALUATE_END(control, SchemaCompilerControlJump); - } - - case IS_STEP(SchemaCompilerControlDynamicAnchorJump): { - EVALUATE_BEGIN_NO_PRECONDITION(control, - SchemaCompilerControlDynamicAnchorJump); - const auto id{context.find_dynamic_anchor(control.value)}; - result = id.has_value(); - if (id.has_value()) { - for (const auto &child : context.jump(id.value())) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - break; - } - } - } - - EVALUATE_END(control, SchemaCompilerControlDynamicAnchorJump); - } - - case IS_STEP(SchemaCompilerAnnotationEmit): { - EVALUATE_ANNOTATION_NO_PRECONDITION( - annotation, SchemaCompilerAnnotationEmit, context.instance_location(), - annotation.value); - } - - case IS_STEP(SchemaCompilerAnnotationWhenArraySizeEqual): { - EVALUATE_ANNOTATION( - annotation, SchemaCompilerAnnotationWhenArraySizeEqual, - target.is_array() && target.size() == annotation.value.first, - context.instance_location(), annotation.value.second); - } - - case IS_STEP(SchemaCompilerAnnotationWhenArraySizeGreater): { - EVALUATE_ANNOTATION( - annotation, SchemaCompilerAnnotationWhenArraySizeGreater, - target.is_array() && target.size() > annotation.value.first, - context.instance_location(), annotation.value.second); - } - - case IS_STEP(SchemaCompilerAnnotationToParent): { - EVALUATE_ANNOTATION_NO_PRECONDITION( - annotation, SchemaCompilerAnnotationToParent, - // TODO: Can we avoid a copy of the instance location here? - context.instance_location().initial(), annotation.value); - } - - case IS_STEP(SchemaCompilerAnnotationBasenameToParent): { - EVALUATE_ANNOTATION_NO_PRECONDITION( - annotation, SchemaCompilerAnnotationBasenameToParent, - // TODO: Can we avoid a copy of the instance location here? - context.instance_location().initial(), - context.instance_location().back().to_json()); - } - - case IS_STEP(SchemaCompilerLoopPropertiesMatch): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopPropertiesMatch, - target.is_object()); - assert(!loop.value.empty()); - result = true; - for (const auto &entry : target.as_object()) { - const auto index{loop.value.find(entry.first)}; - if (index == loop.value.cend()) { - continue; - } - - const auto &substep{loop.children[index->second]}; - assert(std::holds_alternative(substep)); - for (const auto &child : - std::get(substep).children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - // For efficiently breaking from the outer loop too - goto evaluate_loop_properties_match_end; - } - } - } - - evaluate_loop_properties_match_end: - EVALUATE_END(loop, SchemaCompilerLoopPropertiesMatch); - } - - case IS_STEP(SchemaCompilerLoopProperties): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopProperties, target.is_object()); - result = true; - for (const auto &entry : target.as_object()) { - context.enter(entry.first); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - // For efficiently breaking from the outer loop too - goto evaluate_loop_properties_end; - } - } - - context.leave(); - } - - evaluate_loop_properties_end: - EVALUATE_END(loop, SchemaCompilerLoopProperties); - } - - case IS_STEP(SchemaCompilerLoopPropertiesRegex): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopPropertiesRegex, - target.is_object()); - result = true; - for (const auto &entry : target.as_object()) { - if (!std::regex_search(entry.first, loop.value.first)) { - continue; - } - - context.enter(entry.first); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - // For efficiently breaking from the outer loop too - goto evaluate_loop_properties_regex_end; - } - } - - context.leave(); - } - - evaluate_loop_properties_regex_end: - EVALUATE_END(loop, SchemaCompilerLoopPropertiesRegex); - } - - case IS_STEP(SchemaCompilerLoopPropertiesNoAnnotation): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopPropertiesNoAnnotation, - target.is_object()); - result = true; - assert(!loop.value.empty()); - - for (const auto &entry : target.as_object()) { - // TODO: It might be more efficient to get all the annotations we - // potentially care about as a set first, and the make the loop - // check for O(1) containment in that set? - if (context.defines_annotation( - context.instance_location(), - // TODO: Can we avoid doing this expensive operation on a loop? - context.evaluate_path().initial(), loop.value, - // TODO: This conversion implies a string copy - JSON{entry.first})) { - continue; - } - - context.enter(entry.first); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - // For efficiently breaking from the outer loop too - goto evaluate_loop_properties_no_annotation_end; - } - } - - context.leave(); - } - - evaluate_loop_properties_no_annotation_end: - EVALUATE_END(loop, SchemaCompilerLoopPropertiesNoAnnotation); - } - - case IS_STEP(SchemaCompilerLoopPropertiesExcept): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopPropertiesExcept, - target.is_object()); - result = true; - // Otherwise why emit this instruction? - assert(!loop.value.first.empty() || !loop.value.second.empty()); - - for (const auto &entry : target.as_object()) { - if (loop.value.first.contains(entry.first) || - std::any_of(loop.value.second.cbegin(), loop.value.second.cend(), - [&entry](const auto &pattern) { - return std::regex_search(entry.first, pattern.first); - })) { - continue; - } - - context.enter(entry.first); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - // For efficiently breaking from the outer loop too - goto evaluate_loop_properties_except_end; - } - } - - context.leave(); - } - - evaluate_loop_properties_except_end: - EVALUATE_END(loop, SchemaCompilerLoopPropertiesExcept); - } - - case IS_STEP(SchemaCompilerLoopPropertiesType): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopPropertiesType, - target.is_object()); - result = true; - for (const auto &entry : target.as_object()) { - context.enter(entry.first); - const auto &entry_target{context.resolve_target()}; - // In non-strict mode, we consider a real number that represents an - // integer to be an integer - if (entry_target.type() != loop.value && - (loop.value != JSON::Type::Integer || - entry_target.is_integer_real())) { - result = false; - context.leave(); - break; - } - - context.leave(); - } - - EVALUATE_END(loop, SchemaCompilerLoopPropertiesType); - } - - case IS_STEP(SchemaCompilerLoopPropertiesTypeStrict): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopPropertiesTypeStrict, - target.is_object()); - result = true; - for (const auto &entry : target.as_object()) { - context.enter(entry.first); - if (context.resolve_target().type() != loop.value) { - result = false; - context.leave(); - break; - } - - context.leave(); - } - - EVALUATE_END(loop, SchemaCompilerLoopPropertiesTypeStrict); - } - - case IS_STEP(SchemaCompilerLoopKeys): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopKeys, target.is_object()); - result = true; - context.target_type( - sourcemeta::jsontoolkit::EvaluationContext::TargetType::Key); - for (const auto &entry : target.as_object()) { - context.enter(entry.first); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - goto evaluate_loop_keys_end; - } - } - - context.leave(); - } - - evaluate_loop_keys_end: - context.target_type( - sourcemeta::jsontoolkit::EvaluationContext::TargetType::Value); - EVALUATE_END(loop, SchemaCompilerLoopKeys); - } - - case IS_STEP(SchemaCompilerLoopItems): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopItems, target.is_array()); - const auto &array{target.as_array()}; - result = true; - auto iterator{array.cbegin()}; - - // We need this check, as advancing an iterator past its bounds - // is considered undefined behavior - // See https://en.cppreference.com/w/cpp/iterator/advance - std::advance(iterator, - std::min(static_cast(loop.value), - static_cast(target.size()))); - - for (; iterator != array.cend(); ++iterator) { - const auto index{std::distance(array.cbegin(), iterator)}; - context.enter(static_cast(index)); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - goto evaluate_compiler_loop_items_end; - } - } - - context.leave(); - } - - evaluate_compiler_loop_items_end: - EVALUATE_END(loop, SchemaCompilerLoopItems); - } - - case IS_STEP(SchemaCompilerLoopItemsUnmarked): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopItemsUnmarked, - target.is_array() && - !context.defines_annotation( - context.instance_location(), - context.evaluate_path(), loop.value, JSON{true})); - // Otherwise you shouldn't be using this step? - assert(!loop.value.empty()); - const auto &array{target.as_array()}; - result = true; - - for (auto iterator = array.cbegin(); iterator != array.cend(); - ++iterator) { - const auto index{std::distance(array.cbegin(), iterator)}; - context.enter(static_cast(index)); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - goto evaluate_compiler_loop_items_unmarked_end; - } - } - - context.leave(); - } - - evaluate_compiler_loop_items_unmarked_end: - EVALUATE_END(loop, SchemaCompilerLoopItemsUnmarked); - } - - case IS_STEP(SchemaCompilerLoopItemsUnevaluated): { - // TODO: This precondition is very expensive due to pointer manipulation - EVALUATE_BEGIN(loop, SchemaCompilerLoopItemsUnevaluated, - target.is_array() && !context.defines_annotation( - context.instance_location(), - context.evaluate_path().initial(), - loop.value.mask, JSON{true})); - const auto &array{target.as_array()}; - result = true; - auto iterator{array.cbegin()}; - - // Determine the proper start based on integer annotations collected for - // the current instance location by the keyword requested by the user. - const std::uint64_t start{context.largest_annotation_index( - context.instance_location(), {loop.value.index}, 0)}; - - // We need this check, as advancing an iterator past its bounds - // is considered undefined behavior - // See https://en.cppreference.com/w/cpp/iterator/advance - std::advance(iterator, - std::min(static_cast(start), - static_cast(target.size()))); - - for (; iterator != array.cend(); ++iterator) { - const auto index{std::distance(array.cbegin(), iterator)}; - - if (context.defines_annotation( - context.instance_location(), - // TODO: Can we avoid doing this expensive operation on a loop? - context.evaluate_path().initial(), loop.value.filter, - JSON{static_cast(index)})) { - continue; - } - - context.enter(static_cast(index)); - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - result = false; - context.leave(); - goto evaluate_compiler_loop_items_unevaluated_end; - } - } - - context.leave(); - } - - evaluate_compiler_loop_items_unevaluated_end: - EVALUATE_END(loop, SchemaCompilerLoopItemsUnevaluated); - } - - case IS_STEP(SchemaCompilerLoopContains): { - EVALUATE_BEGIN(loop, SchemaCompilerLoopContains, target.is_array()); - const auto minimum{std::get<0>(loop.value)}; - const auto &maximum{std::get<1>(loop.value)}; - assert(!maximum.has_value() || maximum.value() >= minimum); - const auto is_exhaustive{std::get<2>(loop.value)}; - result = minimum == 0 && target.empty(); - const auto &array{target.as_array()}; - auto match_count{std::numeric_limits::min()}; - for (auto iterator = array.cbegin(); iterator != array.cend(); - ++iterator) { - const auto index{std::distance(array.cbegin(), iterator)}; - context.enter(static_cast(index)); - bool subresult{true}; - for (const auto &child : loop.children) { - if (!evaluate_step(child, mode, callback, context)) { - subresult = false; - break; - } - } - - context.leave(); - - if (subresult) { - match_count += 1; - - // Exceeding the upper bound is definitely a failure - if (maximum.has_value() && match_count > maximum.value()) { - result = false; - - // Note that here we don't want to consider whether to run - // exhaustively or not. At this point, its already a failure, - // and anything that comes after would not run at all anyway - break; - } - - if (match_count >= minimum) { - result = true; - - // Exceeding the lower bound when there is no upper bound - // is definitely a success - if (!maximum.has_value() && !is_exhaustive) { - break; - } - } - } - } - - EVALUATE_END(loop, SchemaCompilerLoopContains); - } - -#undef IS_STEP -#undef STRINGIFY -#undef EVALUATE_BEGIN -#undef EVALUATE_BEGIN_IF_STRING -#undef EVALUATE_BEGIN_NO_TARGET -#undef EVALUATE_BEGIN_TRY_TARGET -#undef EVALUATE_BEGIN_NO_PRECONDITION -#undef EVALUATE_END -#undef EVALUATE_ANNOTATION -#undef EVALUATE_ANNOTATION_NO_PRECONDITION - - default: - // We should never get here - assert(false); - return false; - } -} - -inline auto evaluate_internal( - sourcemeta::jsontoolkit::EvaluationContext &context, - const sourcemeta::jsontoolkit::SchemaCompilerTemplate &steps, - const sourcemeta::jsontoolkit::SchemaCompilerEvaluationMode mode, - const std::optional< - sourcemeta::jsontoolkit::SchemaCompilerEvaluationCallback> &callback) - -> bool { - bool overall{true}; - for (const auto &step : steps) { - if (!evaluate_step(step, mode, callback, context)) { - overall = false; - break; - } - } - - // The evaluation path and instance location must be empty by the time - // we are done, otherwise there was a frame push/pop mismatch - assert(context.evaluate_path().empty()); - assert(context.instance_location().empty()); - assert(context.resources().empty()); - // We should end up at the root of the instance - assert(context.instances().size() == 1); - return overall; -} - -} // namespace - -namespace sourcemeta::jsontoolkit { - -auto evaluate(const SchemaCompilerTemplate &steps, const JSON &instance, - const SchemaCompilerEvaluationMode mode, - const SchemaCompilerEvaluationCallback &callback) -> bool { - EvaluationContext context; - context.prepare(instance); - return evaluate_internal(context, steps, mode, callback); -} - -auto evaluate(const SchemaCompilerTemplate &steps, const JSON &instance) - -> bool { - EvaluationContext context; - context.prepare(instance); - return evaluate_internal(context, steps, - // Otherwise what's the point of an exhaustive - // evaluation if you don't get the results? - SchemaCompilerEvaluationMode::Fast, std::nullopt); -} - -auto evaluate(const SchemaCompilerTemplate &steps, EvaluationContext &context) - -> bool { - return evaluate_internal(context, steps, - // Otherwise what's the point of an exhaustive - // evaluation if you don't get the results? - SchemaCompilerEvaluationMode::Fast, std::nullopt); -} - -} // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator.h b/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator.h deleted file mode 100644 index b7d0f78a..00000000 --- a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator.h +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_EVALUATOR_H_ -#define SOURCEMETA_JSONTOOLKIT_EVALUATOR_H_ - -#include "evaluator_export.h" - -#include -#include -#include - -#include -#include - -#include // std::uint8_t -#include // std::function - -/// @defgroup evaluator Evaluator -/// @brief A high-performance JSON Schema evaluator -/// -/// This functionality is included as follows: -/// -/// ```cpp -/// #include -/// ``` - -namespace sourcemeta::jsontoolkit { - -/// @ingroup evaluator -/// Represents the mode of evalution -enum class SchemaCompilerEvaluationMode : std::uint8_t { - /// Attempt to get to a boolean result as fast as possible - Fast, - /// Perform a full schema evaluation - Exhaustive -}; - -/// @ingroup evaluator -/// Represents the state of a step evaluation -enum class SchemaCompilerEvaluationType : std::uint8_t { Pre, Post }; - -/// @ingroup evaluator -/// A callback of this type is invoked after evaluating any keyword. The -/// arguments go as follows: -/// -/// - The stage at which the step in question is -/// - Whether the evaluation was successful or not (always true before -/// evaluation) -/// - The step that was just evaluated -/// - The evaluation path -/// - The instance location -/// - The annotation result, if any (otherwise null) -/// -/// You can use this callback mechanism to implement arbitrary output formats. -using SchemaCompilerEvaluationCallback = - std::function; - -/// @ingroup evaluator -/// -/// This function evaluates a schema compiler template in validation mode, -/// returning a boolean without error information. For example: -/// -/// ```cpp -/// #include -/// #include -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// const sourcemeta::jsontoolkit::JSON instance{"foo bar"}; -/// const auto result{sourcemeta::jsontoolkit::evaluate( -/// schema_template, instance)}; -/// assert(result); -/// ``` -auto SOURCEMETA_JSONTOOLKIT_EVALUATOR_EXPORT -evaluate(const SchemaCompilerTemplate &steps, const JSON &instance) -> bool; - -/// @ingroup evaluator -/// -/// This function evaluates a schema compiler template, executing the given -/// callback at every step of the way. For example: -/// -/// ```cpp -/// #include -/// #include -/// #include -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// static auto callback( -/// bool result, -/// const sourcemeta::jsontoolkit::SchemaCompilerTemplate::value_type &step, -/// const sourcemeta::jsontoolkit::Pointer &evaluate_path, -/// const sourcemeta::jsontoolkit::Pointer &instance_location, -/// const sourcemeta::jsontoolkit::JSON &document, -/// const sourcemeta::jsontoolkit::JSON &annotation) -> void { -/// std::cout << "TYPE: " << (result ? "Success" : "Failure") << "\n"; -/// std::cout << "STEP:\n"; -/// sourcemeta::jsontoolkit::prettify(sourcemeta::jsontoolkit::to_json({step}), -/// std::cout); -/// std::cout << "\nEVALUATE PATH:"; -/// sourcemeta::jsontoolkit::stringify(evaluate_path, std::cout); -/// std::cout << "\nINSTANCE LOCATION:"; -/// sourcemeta::jsontoolkit::stringify(instance_location, std::cout); -/// std::cout << "\nANNOTATION:\n"; -/// sourcemeta::jsontoolkit::prettify(annotation, std::cout); -/// std::cout << "\n"; -/// } -/// -/// const sourcemeta::jsontoolkit::JSON instance{"foo bar"}; -/// const auto result{sourcemeta::jsontoolkit::evaluate( -/// schema_template, instance, -/// sourcemeta::jsontoolkit::SchemaCompilerEvaluationMode::Fast, -/// callback)}; -/// -/// assert(result); -/// ``` -auto SOURCEMETA_JSONTOOLKIT_EVALUATOR_EXPORT -evaluate(const SchemaCompilerTemplate &steps, const JSON &instance, - const SchemaCompilerEvaluationMode mode, - const SchemaCompilerEvaluationCallback &callback) -> bool; - -/// @ingroup evaluator -/// -/// This function evaluates a schema compiler template from an evaluation -/// context, returning a boolean without error information. The evaluation -/// context can be re-used among evaluations (as long as its always loaded with -/// the new instance first) for performance reasons. For example: -/// -/// ```cpp -/// #include -/// #include -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// const sourcemeta::jsontoolkit::JSON instance{"foo bar"}; -/// sourcemeta::jsontoolkit::EvaluationContext context; -/// context.prepare(instance); -/// -/// const auto result{sourcemeta::jsontoolkit::evaluate( -/// schema_template, context)}; -/// assert(result); -/// ``` -auto SOURCEMETA_JSONTOOLKIT_EVALUATOR_EXPORT evaluate( - const SchemaCompilerTemplate &steps, EvaluationContext &context) -> bool; - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_context.h b/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_context.h deleted file mode 100644 index 9a10278e..00000000 --- a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_context.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_EVALUATOR_CONTEXT_H -#define SOURCEMETA_JSONTOOLKIT_EVALUATOR_CONTEXT_H - -#include "evaluator_export.h" - -#include - -#include -#include - -#include // assert -#include // std::uint8_t -#include // std::reference_wrapper -#include // std::map -#include // std::optional -#include // std::set -#include // std::vector - -namespace sourcemeta::jsontoolkit { - -/// @ingroup evaluator -/// Represents a stateful schema evaluation context -class SOURCEMETA_JSONTOOLKIT_EVALUATOR_EXPORT EvaluationContext { -public: - /// Prepare the schema evaluation context with a given instance. - /// Performing evaluation on a context without preparing it with - /// an instance is undefined behavior. - auto prepare(const JSON &instance) -> void; - - // All of these methods are considered internal and no - // client must depend on them -#ifndef DOXYGEN - - /////////////////////////////////////////////// - // Evaluation stack - /////////////////////////////////////////////// - - auto evaluate_path() const noexcept -> const WeakPointer &; - auto instance_location() const noexcept -> const WeakPointer &; - auto push(const Pointer &relative_schema_location, - const Pointer &relative_instance_location, - const std::string &schema_resource, const bool dynamic) -> void; - // A performance shortcut for pushing without re-traversing the target - // if we already know that the destination target will be - auto push(const Pointer &relative_schema_location, - const Pointer &relative_instance_location, - const std::string &schema_resource, const bool dynamic, - std::reference_wrapper &&new_instance) -> void; - auto pop(const bool dynamic) -> void; - auto enter(const WeakPointer::Token::Property &property) -> void; - auto enter(const WeakPointer::Token::Index &index) -> void; - auto leave() -> void; - -private: - auto push_without_traverse(const Pointer &relative_schema_location, - const Pointer &relative_instance_location, - const std::string &schema_resource, - const bool dynamic) -> void; - -public: - /////////////////////////////////////////////// - // Target resolution - /////////////////////////////////////////////// - - auto instances() const noexcept - -> const std::vector> &; - enum class TargetType : std::uint8_t { Key, Value }; - auto target_type(const TargetType type) noexcept -> void; - auto resolve_target() -> const JSON &; - auto resolve_string_target() - -> std::optional>; - - /////////////////////////////////////////////// - // References and anchors - /////////////////////////////////////////////// - - auto resources() const noexcept -> const std::vector &; - auto mark(const std::size_t id, const SchemaCompilerTemplate &children) - -> void; - // TODO: At least currently, we only need to mask if a schema - // makes use of `unevaluatedProperties` or `unevaluatedItems` - // Detect if a schema does need this so if not, we avoid - // an unnecessary copy - auto mask() -> void; - auto jump(const std::size_t id) const noexcept - -> const SchemaCompilerTemplate &; - auto find_dynamic_anchor(const std::string &anchor) const - -> std::optional; - - /////////////////////////////////////////////// - // Annotations - /////////////////////////////////////////////// - - auto annotate(const WeakPointer ¤t_instance_location, const JSON &value) - -> std::pair, bool>; - auto defines_annotation(const WeakPointer &expected_instance_location, - const WeakPointer &base_evaluate_path, - const std::vector &keywords, - const JSON &value) const -> bool; - auto largest_annotation_index(const WeakPointer &expected_instance_location, - const std::vector &keywords, - const std::uint64_t default_value) const - -> std::uint64_t; - -public: - // TODO: Remove this - const JSON null{nullptr}; - -private: -// Exporting symbols that depends on the standard C++ library is considered -// safe. -// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN -#if defined(_MSC_VER) -#pragma warning(disable : 4251 4275) -#endif - std::vector> instances_; - WeakPointer evaluate_path_; - WeakPointer instance_location_; - std::vector> frame_sizes; - // TODO: Keep hashes of schema resources URI instead for performance reasons - std::vector resources_; - std::vector annotation_blacklist; - // We don't use a pair for holding the two pointers for runtime - // efficiency when resolving keywords like `unevaluatedProperties` - std::map>> annotations_; - std::map> - labels; - bool property_as_instance{false}; -#if defined(_MSC_VER) -#pragma warning(default : 4251 4275) -#endif -#endif -}; - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_error.h b/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_error.h deleted file mode 100644 index 46df2644..00000000 --- a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_error.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_EVALUATOR_ERROR_H -#define SOURCEMETA_JSONTOOLKIT_EVALUATOR_ERROR_H - -#include "evaluator_export.h" - -#include // std::exception -#include // std::string -#include // std::move - -namespace sourcemeta::jsontoolkit { - -// Exporting symbols that depends on the standard C++ library is considered -// safe. -// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN -#if defined(_MSC_VER) -#pragma warning(disable : 4251 4275) -#endif - -/// @ingroup jsonschema -/// An error that represents a schema evaluation error event -class SOURCEMETA_JSONTOOLKIT_EVALUATOR_EXPORT SchemaEvaluationError - : public std::exception { -public: - SchemaEvaluationError(std::string message) : message_{std::move(message)} {} - [[nodiscard]] auto what() const noexcept -> const char * override { - return this->message_.c_str(); - } - -private: - std::string message_; -}; - -#if defined(_MSC_VER) -#pragma warning(default : 4251 4275) -#endif - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_template.h b/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_template.h deleted file mode 100644 index 9a71442a..00000000 --- a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_template.h +++ /dev/null @@ -1,516 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_EVALUATOR_TEMPLATE_H -#define SOURCEMETA_JSONTOOLKIT_EVALUATOR_TEMPLATE_H - -#include - -#include - -#include // std::uint8_t -#include // std::string -#include // std::vector - -namespace sourcemeta::jsontoolkit { - -// Forward declarations for the sole purpose of being bale to define circular -// structures -#ifndef DOXYGEN -struct SchemaCompilerAssertionFail; -struct SchemaCompilerAssertionDefines; -struct SchemaCompilerAssertionDefinesAll; -struct SchemaCompilerAssertionPropertyDependencies; -struct SchemaCompilerAssertionType; -struct SchemaCompilerAssertionTypeAny; -struct SchemaCompilerAssertionTypeStrict; -struct SchemaCompilerAssertionTypeStrictAny; -struct SchemaCompilerAssertionTypeStringBounded; -struct SchemaCompilerAssertionTypeArrayBounded; -struct SchemaCompilerAssertionTypeObjectBounded; -struct SchemaCompilerAssertionRegex; -struct SchemaCompilerAssertionStringSizeLess; -struct SchemaCompilerAssertionStringSizeGreater; -struct SchemaCompilerAssertionArraySizeLess; -struct SchemaCompilerAssertionArraySizeGreater; -struct SchemaCompilerAssertionObjectSizeLess; -struct SchemaCompilerAssertionObjectSizeGreater; -struct SchemaCompilerAssertionEqual; -struct SchemaCompilerAssertionEqualsAny; -struct SchemaCompilerAssertionGreaterEqual; -struct SchemaCompilerAssertionLessEqual; -struct SchemaCompilerAssertionGreater; -struct SchemaCompilerAssertionLess; -struct SchemaCompilerAssertionUnique; -struct SchemaCompilerAssertionDivisible; -struct SchemaCompilerAssertionStringType; -struct SchemaCompilerAssertionPropertyType; -struct SchemaCompilerAssertionPropertyTypeStrict; -struct SchemaCompilerAnnotationEmit; -struct SchemaCompilerAnnotationWhenArraySizeEqual; -struct SchemaCompilerAnnotationWhenArraySizeGreater; -struct SchemaCompilerAnnotationToParent; -struct SchemaCompilerAnnotationBasenameToParent; -struct SchemaCompilerLogicalOr; -struct SchemaCompilerLogicalAnd; -struct SchemaCompilerLogicalXor; -struct SchemaCompilerLogicalCondition; -struct SchemaCompilerLogicalNot; -struct SchemaCompilerLogicalWhenType; -struct SchemaCompilerLogicalWhenDefines; -struct SchemaCompilerLogicalWhenArraySizeGreater; -struct SchemaCompilerLogicalWhenArraySizeEqual; -struct SchemaCompilerLoopPropertiesMatch; -struct SchemaCompilerLoopProperties; -struct SchemaCompilerLoopPropertiesRegex; -struct SchemaCompilerLoopPropertiesNoAnnotation; -struct SchemaCompilerLoopPropertiesExcept; -struct SchemaCompilerLoopPropertiesType; -struct SchemaCompilerLoopPropertiesTypeStrict; -struct SchemaCompilerLoopKeys; -struct SchemaCompilerLoopItems; -struct SchemaCompilerLoopItemsUnmarked; -struct SchemaCompilerLoopItemsUnevaluated; -struct SchemaCompilerLoopContains; -struct SchemaCompilerControlLabel; -struct SchemaCompilerControlMark; -struct SchemaCompilerControlJump; -struct SchemaCompilerControlDynamicAnchorJump; -#endif - -/// @ingroup evaluator -/// Represents a schema compilation step that can be evaluated -using SchemaCompilerTemplate = std::vector>; - -#if !defined(DOXYGEN) -// For fast internal instruction dispatching. It must stay -// in sync with the variant ordering above -enum class SchemaCompilerTemplateIndex : std::uint8_t { - SchemaCompilerAssertionFail = 0, - SchemaCompilerAssertionDefines, - SchemaCompilerAssertionDefinesAll, - SchemaCompilerAssertionPropertyDependencies, - SchemaCompilerAssertionType, - SchemaCompilerAssertionTypeAny, - SchemaCompilerAssertionTypeStrict, - SchemaCompilerAssertionTypeStrictAny, - SchemaCompilerAssertionTypeStringBounded, - SchemaCompilerAssertionTypeArrayBounded, - SchemaCompilerAssertionTypeObjectBounded, - SchemaCompilerAssertionRegex, - SchemaCompilerAssertionStringSizeLess, - SchemaCompilerAssertionStringSizeGreater, - SchemaCompilerAssertionArraySizeLess, - SchemaCompilerAssertionArraySizeGreater, - SchemaCompilerAssertionObjectSizeLess, - SchemaCompilerAssertionObjectSizeGreater, - SchemaCompilerAssertionEqual, - SchemaCompilerAssertionEqualsAny, - SchemaCompilerAssertionGreaterEqual, - SchemaCompilerAssertionLessEqual, - SchemaCompilerAssertionGreater, - SchemaCompilerAssertionLess, - SchemaCompilerAssertionUnique, - SchemaCompilerAssertionDivisible, - SchemaCompilerAssertionStringType, - SchemaCompilerAssertionPropertyType, - SchemaCompilerAssertionPropertyTypeStrict, - SchemaCompilerAnnotationEmit, - SchemaCompilerAnnotationWhenArraySizeEqual, - SchemaCompilerAnnotationWhenArraySizeGreater, - SchemaCompilerAnnotationToParent, - SchemaCompilerAnnotationBasenameToParent, - SchemaCompilerLogicalOr, - SchemaCompilerLogicalAnd, - SchemaCompilerLogicalXor, - SchemaCompilerLogicalCondition, - SchemaCompilerLogicalNot, - SchemaCompilerLogicalWhenType, - SchemaCompilerLogicalWhenDefines, - SchemaCompilerLogicalWhenArraySizeGreater, - SchemaCompilerLogicalWhenArraySizeEqual, - SchemaCompilerLoopPropertiesMatch, - SchemaCompilerLoopProperties, - SchemaCompilerLoopPropertiesRegex, - SchemaCompilerLoopPropertiesNoAnnotation, - SchemaCompilerLoopPropertiesExcept, - SchemaCompilerLoopPropertiesType, - SchemaCompilerLoopPropertiesTypeStrict, - SchemaCompilerLoopKeys, - SchemaCompilerLoopItems, - SchemaCompilerLoopItemsUnmarked, - SchemaCompilerLoopItemsUnevaluated, - SchemaCompilerLoopContains, - SchemaCompilerControlLabel, - SchemaCompilerControlMark, - SchemaCompilerControlJump, - SchemaCompilerControlDynamicAnchorJump -}; -#endif - -#define DEFINE_STEP_WITH_VALUE(category, name, type) \ - struct SchemaCompiler##category##name { \ - const Pointer relative_schema_location; \ - const Pointer relative_instance_location; \ - const std::string keyword_location; \ - const std::string schema_resource; \ - const bool dynamic; \ - const bool report; \ - const type value; \ - }; - -#define DEFINE_STEP_APPLICATOR(category, name, type) \ - struct SchemaCompiler##category##name { \ - const Pointer relative_schema_location; \ - const Pointer relative_instance_location; \ - const std::string keyword_location; \ - const std::string schema_resource; \ - const bool dynamic; \ - const bool report; \ - const type value; \ - const SchemaCompilerTemplate children; \ - }; - -/// @defgroup evaluator_instructions Instruction Set -/// @ingroup evaluator -/// @brief The set of instructions supported by the evaluator. -/// @details -/// -/// Every instruction operates at a specific instance location and with the -/// given value, whose type depends on the instruction. - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that always fails -DEFINE_STEP_WITH_VALUE(Assertion, Fail, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if an object defines -/// a given property -DEFINE_STEP_WITH_VALUE(Assertion, Defines, SchemaCompilerValueString) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if an object defines -/// a set of properties -DEFINE_STEP_WITH_VALUE(Assertion, DefinesAll, SchemaCompilerValueStrings) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if an object defines -/// a set of properties if it defines other set of properties -DEFINE_STEP_WITH_VALUE(Assertion, PropertyDependencies, - SchemaCompilerValueStringMap) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// the given type -DEFINE_STEP_WITH_VALUE(Assertion, Type, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// any of the given types -DEFINE_STEP_WITH_VALUE(Assertion, TypeAny, SchemaCompilerValueTypes) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// the given type (strict version) -DEFINE_STEP_WITH_VALUE(Assertion, TypeStrict, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// any of the given types (strict version) -DEFINE_STEP_WITH_VALUE(Assertion, TypeStrictAny, SchemaCompilerValueTypes) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// type string and adheres to the given bounds -DEFINE_STEP_WITH_VALUE(Assertion, TypeStringBounded, SchemaCompilerValueRange) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// type array and adheres to the given bounds -DEFINE_STEP_WITH_VALUE(Assertion, TypeArrayBounded, SchemaCompilerValueRange) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks if a document is of -/// type object and adheres to the given bounds -DEFINE_STEP_WITH_VALUE(Assertion, TypeObjectBounded, SchemaCompilerValueRange) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a string against an -/// ECMA regular expression -DEFINE_STEP_WITH_VALUE(Assertion, Regex, SchemaCompilerValueRegex) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given string has -/// less than a certain number of characters -DEFINE_STEP_WITH_VALUE(Assertion, StringSizeLess, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given string has -/// greater than a certain number of characters -DEFINE_STEP_WITH_VALUE(Assertion, StringSizeGreater, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given array has -/// less than a certain number of items -DEFINE_STEP_WITH_VALUE(Assertion, ArraySizeLess, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given array has -/// greater than a certain number of items -DEFINE_STEP_WITH_VALUE(Assertion, ArraySizeGreater, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given object has -/// less than a certain number of properties -DEFINE_STEP_WITH_VALUE(Assertion, ObjectSizeLess, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given object has -/// greater than a certain number of properties -DEFINE_STEP_WITH_VALUE(Assertion, ObjectSizeGreater, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks the instance equals -/// a given JSON document -DEFINE_STEP_WITH_VALUE(Assertion, Equal, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks that a JSON document -/// is equal to at least one of the given elements -DEFINE_STEP_WITH_VALUE(Assertion, EqualsAny, SchemaCompilerValueArray) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a JSON document is -/// greater than or equal to another JSON document -DEFINE_STEP_WITH_VALUE(Assertion, GreaterEqual, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a JSON document is -/// less than or equal to another JSON document -DEFINE_STEP_WITH_VALUE(Assertion, LessEqual, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a JSON document is -/// greater than another JSON document -DEFINE_STEP_WITH_VALUE(Assertion, Greater, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a JSON document is -/// less than another JSON document -DEFINE_STEP_WITH_VALUE(Assertion, Less, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a given JSON array -/// does not contain duplicate items -DEFINE_STEP_WITH_VALUE(Assertion, Unique, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks a number is -/// divisible by another number -DEFINE_STEP_WITH_VALUE(Assertion, Divisible, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks that a string is of -/// a certain type -DEFINE_STEP_WITH_VALUE(Assertion, StringType, SchemaCompilerValueStringType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks that an instance -/// property is of a given type if present -DEFINE_STEP_WITH_VALUE(Assertion, PropertyType, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler assertion step that checks that an instance -/// property is of a given type if present (strict mode) -DEFINE_STEP_WITH_VALUE(Assertion, PropertyTypeStrict, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that emits an annotation -DEFINE_STEP_WITH_VALUE(Annotation, Emit, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that emits an annotation when the size of -/// the array instance is equal to the given size -DEFINE_STEP_WITH_VALUE(Annotation, WhenArraySizeEqual, - SchemaCompilerValueIndexedJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that emits an annotation when the size of -/// the array instance is greater than the given size -DEFINE_STEP_WITH_VALUE(Annotation, WhenArraySizeGreater, - SchemaCompilerValueIndexedJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that emits an annotation to the parent -DEFINE_STEP_WITH_VALUE(Annotation, ToParent, SchemaCompilerValueJSON) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that emits the current basename as an -/// annotation to the parent -DEFINE_STEP_WITH_VALUE(Annotation, BasenameToParent, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a disjunction -DEFINE_STEP_APPLICATOR(Logical, Or, SchemaCompilerValueBoolean) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a conjunction -DEFINE_STEP_APPLICATOR(Logical, And, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents an exclusive -/// disjunction -DEFINE_STEP_APPLICATOR(Logical, Xor, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents an imperative conditional compiler logical step -DEFINE_STEP_APPLICATOR(Logical, Condition, SchemaCompilerValueIndexPair) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a negation -DEFINE_STEP_APPLICATOR(Logical, Not, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a conjunction when -/// the instance is of a given type -DEFINE_STEP_APPLICATOR(Logical, WhenType, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a conjunction when -/// the instance is an object and defines a given property -DEFINE_STEP_APPLICATOR(Logical, WhenDefines, SchemaCompilerValueString) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a conjunction when -/// the array instance size is greater than the given number -DEFINE_STEP_APPLICATOR(Logical, WhenArraySizeGreater, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler logical step that represents a conjunction when -/// the array instance size is equal to the given number -DEFINE_STEP_APPLICATOR(Logical, WhenArraySizeEqual, - SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that matches steps to object properties -DEFINE_STEP_APPLICATOR(Loop, PropertiesMatch, SchemaCompilerValueNamedIndexes) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over object properties -DEFINE_STEP_APPLICATOR(Loop, Properties, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over object properties that -/// match a given ECMA regular expression -DEFINE_STEP_APPLICATOR(Loop, PropertiesRegex, SchemaCompilerValueRegex) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over object properties that -/// were not collected as annotations -DEFINE_STEP_APPLICATOR(Loop, PropertiesNoAnnotation, SchemaCompilerValueStrings) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over object properties that -/// do not match the given property filters -DEFINE_STEP_APPLICATOR(Loop, PropertiesExcept, - SchemaCompilerValuePropertyFilter) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that checks every object property is of a -/// given type -DEFINE_STEP_WITH_VALUE(Loop, PropertiesType, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that checks every object property is of a -/// given type (strict mode) -DEFINE_STEP_WITH_VALUE(Loop, PropertiesTypeStrict, SchemaCompilerValueType) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over object property keys -DEFINE_STEP_APPLICATOR(Loop, Keys, SchemaCompilerValueNone) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over array items starting from -/// a given index -DEFINE_STEP_APPLICATOR(Loop, Items, SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over array items when the array -/// is considered unmarked -DEFINE_STEP_APPLICATOR(Loop, ItemsUnmarked, SchemaCompilerValueStrings) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that loops over unevaluated array items -DEFINE_STEP_APPLICATOR(Loop, ItemsUnevaluated, - SchemaCompilerValueItemsAnnotationKeywords) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that checks array items match a given -/// criteria -DEFINE_STEP_APPLICATOR(Loop, Contains, SchemaCompilerValueRange) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that consists of a mark to jump to while -/// executing children instructions -DEFINE_STEP_APPLICATOR(Control, Label, SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that consists of a mark to jump to, but -/// without executing children instructions -DEFINE_STEP_APPLICATOR(Control, Mark, SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that consists of jumping into a -/// pre-registered label -DEFINE_STEP_WITH_VALUE(Control, Jump, SchemaCompilerValueUnsignedInteger) - -/// @ingroup evaluator_instructions -/// @brief Represents a compiler step that consists of jump to a dynamic anchor -DEFINE_STEP_WITH_VALUE(Control, DynamicAnchorJump, SchemaCompilerValueString) - -#undef DEFINE_STEP_WITH_VALUE -#undef DEFINE_STEP_APPLICATOR - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_value.h b/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_value.h deleted file mode 100644 index 2a2ba107..00000000 --- a/vendor/jsontoolkit/src/evaluator/include/sourcemeta/jsontoolkit/evaluator_value.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_EVALUATOR_VALUE_H -#define SOURCEMETA_JSONTOOLKIT_EVALUATOR_VALUE_H - -#include -#include - -#include // std::uint8_t -#include // std::optional, std::nullopt -#include // std::regex -#include // std::set -#include // std::string -#include // std::tuple -#include // std::unordered_map -#include // std::pair -#include // std::vector - -namespace sourcemeta::jsontoolkit { - -/// @ingroup evaluator -/// @brief Represents a compiler step empty value -struct SchemaCompilerValueNone {}; - -/// @ingroup evaluator -/// Represents a compiler step JSON value -using SchemaCompilerValueJSON = JSON; - -// Note that for these steps, we prefer vectors over sets as the former performs -// better for small collections, where we can even guarantee uniqueness when -// generating the instructions - -/// @ingroup evaluator -/// Represents a set of JSON values -using SchemaCompilerValueArray = std::vector; - -/// @ingroup evaluator -/// Represents a compiler step string values -using SchemaCompilerValueStrings = std::vector; - -/// @ingroup evaluator -/// Represents a compiler step JSON types value -using SchemaCompilerValueTypes = std::vector; - -/// @ingroup evaluator -/// Represents a compiler step string value -using SchemaCompilerValueString = JSON::String; - -/// @ingroup evaluator -/// Represents a compiler step JSON type value -using SchemaCompilerValueType = JSON::Type; - -/// @ingroup evaluator -/// Represents a compiler step ECMA regular expression value. We store both the -/// original string and the regular expression as standard regular expressions -/// do not keep a copy of their original value (which we need for serialization -/// purposes) -using SchemaCompilerValueRegex = std::pair; - -/// @ingroup evaluator -/// Represents a compiler step JSON unsigned integer value -using SchemaCompilerValueUnsignedInteger = std::size_t; - -/// @ingroup evaluator -/// Represents a compiler step range value. The boolean option -/// modifies whether the range is considered exhaustively or -/// if the evaluator is allowed to break early -using SchemaCompilerValueRange = - std::tuple, bool>; - -/// @ingroup evaluator -/// Represents a compiler step boolean value -using SchemaCompilerValueBoolean = bool; - -/// @ingroup evaluator -/// Represents a compiler step string to index map -using SchemaCompilerValueNamedIndexes = - std::unordered_map; - -/// @ingroup evaluator -/// Represents a compiler step string logical type -enum class SchemaCompilerValueStringType : std::uint8_t { URI }; - -/// @ingroup evaluator -/// Represents an array loop compiler step annotation keywords -struct SchemaCompilerValueItemsAnnotationKeywords { - const SchemaCompilerValueString index; - const SchemaCompilerValueStrings filter; - const SchemaCompilerValueStrings mask; -}; - -/// @ingroup evaluator -/// Represents an compiler step that maps strings to strings -using SchemaCompilerValueStringMap = - std::unordered_map; - -/// @ingroup evaluator -/// Represents a compiler step JSON value accompanied with an index -using SchemaCompilerValueIndexedJSON = - std::pair; - -// Note that while we generally avoid sets, in this case, we want -// hash-based lookups on string collections that might get large. -/// @ingroup evaluator -/// Represents a compiler step value that consist of object property filters -using SchemaCompilerValuePropertyFilter = - std::pair, - std::vector>; - -/// @ingroup evaluator -/// Represents a compiler step value that consists of two indexes -using SchemaCompilerValueIndexPair = std::pair; - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/evaluator/trace.h b/vendor/jsontoolkit/src/evaluator/trace.h deleted file mode 100644 index 770967f2..00000000 --- a/vendor/jsontoolkit/src/evaluator/trace.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_EVALUATOR_TRACE_H_ -#define SOURCEMETA_JSONTOOLKIT_EVALUATOR_TRACE_H_ - -// We only perform tracing on debugging builds, at least for now -#if !defined(NDEBUG) && defined(__APPLE__) && defined(__clang__) - -#include -#include - -// See -// https://www.jviotti.com/2022/02/21/emitting-signposts-to-instruments-on-macos-using-cpp.html - -static os_log_t log_handle = os_log_create("com.sourcemeta.jsontoolkit", - OS_LOG_CATEGORY_POINTS_OF_INTEREST); - -#define SOURCEMETA_TRACE_REGISTER_ID(name) \ - const os_signpost_id_t name = os_signpost_id_generate(log_handle); \ - assert((name) != OS_SIGNPOST_ID_INVALID); -#define SOURCEMETA_TRACE_START(id, title) \ - os_signpost_interval_begin(log_handle, id, title); -#define SOURCEMETA_TRACE_END(id, title) \ - os_signpost_interval_end(log_handle, id, title); - -#else -#define SOURCEMETA_TRACE_REGISTER_ID(name) -#define SOURCEMETA_TRACE_START(id, title) -#define SOURCEMETA_TRACE_END(id, title) -#endif - -#endif diff --git a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json.h b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json.h index 19fd1b97..88224e69 100644 --- a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json.h +++ b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSON_H_ #define SOURCEMETA_JSONTOOLKIT_JSON_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSON_EXPORT #include "json_export.h" +#endif #include #include diff --git a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_error.h b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_error.h index 08b90cab..4e9b341a 100644 --- a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_error.h +++ b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_error.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSON_ERROR_H_ #define SOURCEMETA_JSONTOOLKIT_JSON_ERROR_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSON_EXPORT #include "json_export.h" +#endif #include // std::uint64_t #include // std::exception diff --git a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_value.h b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_value.h index e2142b02..005561f7 100644 --- a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_value.h +++ b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_value.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSON_VALUE_H_ #define SOURCEMETA_JSONTOOLKIT_JSON_VALUE_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSON_EXPORT #include "json_export.h" +#endif #include #include diff --git a/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl.h b/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl.h index 0f76cad1..813210f8 100644 --- a/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl.h +++ b/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONL_H_ #define SOURCEMETA_JSONTOOLKIT_JSONL_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONL_EXPORT #include "jsonl_export.h" +#endif #include #include diff --git a/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl_iterator.h b/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl_iterator.h index 654098ad..6e2d31b7 100644 --- a/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl_iterator.h +++ b/vendor/jsontoolkit/src/jsonl/include/sourcemeta/jsontoolkit/jsonl_iterator.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONL_ITERATOR_H_ #define SOURCEMETA_JSONTOOLKIT_JSONL_ITERATOR_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONL_EXPORT #include "jsonl_export.h" +#endif #include diff --git a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h index cedda358..2cd68d9a 100644 --- a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h +++ b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONPOINTER_H_ #define SOURCEMETA_JSONTOOLKIT_JSONPOINTER_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT #include "jsonpointer_export.h" +#endif #include #include diff --git a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_error.h b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_error.h index 6710219d..71b08a12 100644 --- a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_error.h +++ b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_error.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONPOINTER_ERROR_H_ #define SOURCEMETA_JSONTOOLKIT_JSONPOINTER_ERROR_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT #include "jsonpointer_export.h" +#endif #include diff --git a/vendor/jsontoolkit/src/jsonschema/CMakeLists.txt b/vendor/jsontoolkit/src/jsonschema/CMakeLists.txt index d7ae24d4..901fece7 100644 --- a/vendor/jsontoolkit/src/jsonschema/CMakeLists.txt +++ b/vendor/jsontoolkit/src/jsonschema/CMakeLists.txt @@ -5,19 +5,10 @@ include(./official_resolver.cmake) noa_library(NAMESPACE sourcemeta PROJECT jsontoolkit NAME jsonschema FOLDER "JSON Toolkit/JSON Schema" PRIVATE_HEADERS anchor.h bundle.h resolver.h - walker.h reference.h error.h compile.h + walker.h reference.h error.h SOURCES jsonschema.cc default_walker.cc reference.cc anchor.cc resolver.cc - walker.cc bundle.cc compile.cc - compile_json.cc compile_describe.cc - compile_helpers.h default_compiler.cc - - default_compiler_2020_12.h - default_compiler_2019_09.h - default_compiler_draft7.h - default_compiler_draft6.h - default_compiler_draft4.h - + walker.cc bundle.cc "${CMAKE_CURRENT_BINARY_DIR}/official_resolver.cc") if(JSONTOOLKIT_INSTALL) @@ -30,14 +21,3 @@ target_link_libraries(sourcemeta_jsontoolkit_jsonschema PUBLIC sourcemeta::jsontoolkit::jsonpointer) target_link_libraries(sourcemeta_jsontoolkit_jsonschema PRIVATE sourcemeta::jsontoolkit::uri) -target_link_libraries(sourcemeta_jsontoolkit_jsonschema PUBLIC - sourcemeta::jsontoolkit::evaluator) - -# GCC does not allow the use of std::promise, std::future -# without compiling with pthreads support. -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_THREAD_PREFER_PTHREAD TRUE) - set(THREADS_PREFER_PTHREAD_FLAG TRUE) - find_package(Threads REQUIRED) - target_link_libraries(sourcemeta_jsontoolkit_jsonschema PUBLIC Threads::Threads) -endif() diff --git a/vendor/jsontoolkit/src/jsonschema/anchor.cc b/vendor/jsontoolkit/src/jsonschema/anchor.cc index f6d69e57..69e30060 100644 --- a/vendor/jsontoolkit/src/jsonschema/anchor.cc +++ b/vendor/jsontoolkit/src/jsonschema/anchor.cc @@ -8,13 +8,10 @@ namespace sourcemeta::jsontoolkit { auto anchors(const JSON &schema, const SchemaResolver &resolver, const std::optional &default_dialect) - -> std::future> { + -> std::map { const std::map vocabularies{ - sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect) - .get()}; - std::promise> promise; - promise.set_value(anchors(schema, vocabularies)); - return promise.get_future(); + sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect)}; + return anchors(schema, vocabularies); } auto anchors(const JSON &schema, diff --git a/vendor/jsontoolkit/src/jsonschema/bundle.cc b/vendor/jsontoolkit/src/jsonschema/bundle.cc index cd4ae5b0..b8032113 100644 --- a/vendor/jsontoolkit/src/jsonschema/bundle.cc +++ b/vendor/jsontoolkit/src/jsonschema/bundle.cc @@ -46,9 +46,7 @@ auto is_official_metaschema_reference( const std::string &destination) -> bool { return !pointer.empty() && pointer.back().is_property() && pointer.back().to_property() == "$schema" && - sourcemeta::jsontoolkit::official_resolver(destination) - .get() - .has_value(); + sourcemeta::jsontoolkit::official_resolver(destination).has_value(); } auto bundle_schema(sourcemeta::jsontoolkit::JSON &root, @@ -60,8 +58,7 @@ auto bundle_schema(sourcemeta::jsontoolkit::JSON &root, const std::optional &default_dialect) -> void { sourcemeta::jsontoolkit::ReferenceMap references; sourcemeta::jsontoolkit::frame(subschema, frame, references, walker, resolver, - default_dialect) - .wait(); + default_dialect); for (const auto &[key, reference] : references) { if (frame.contains({sourcemeta::jsontoolkit::ReferenceType::Static, @@ -86,7 +83,7 @@ auto bundle_schema(sourcemeta::jsontoolkit::JSON &root, assert(reference.base.has_value()); const auto identifier{reference.base.value()}; - const auto remote{resolver(identifier).get()}; + const auto remote{resolver(identifier)}; if (!remote.has_value()) { if (frame.contains( {sourcemeta::jsontoolkit::ReferenceType::Static, identifier}) || @@ -138,8 +135,7 @@ auto remove_identifiers(sourcemeta::jsontoolkit::JSON &schema, sourcemeta::jsontoolkit::ReferenceFrame frame; sourcemeta::jsontoolkit::ReferenceMap references; sourcemeta::jsontoolkit::frame(schema, frame, references, walker, resolver, - default_dialect) - .wait(); + default_dialect); // (2) Remove all identifiers and anchors for (const auto &entry : sourcemeta::jsontoolkit::SchemaIterator{ @@ -199,8 +195,7 @@ auto bundle(sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, const BundleOptions options, const std::optional &default_dialect) -> void { const auto vocabularies{ - sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect) - .get()}; + sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect)}; sourcemeta::jsontoolkit::ReferenceFrame frame; bundle_schema(schema, definitions_keyword(vocabularies), schema, frame, walker, resolver, default_dialect); diff --git a/vendor/jsontoolkit/src/jsonschema/compile.cc b/vendor/jsontoolkit/src/jsonschema/compile.cc deleted file mode 100644 index d2b06f98..00000000 --- a/vendor/jsontoolkit/src/jsonschema/compile.cc +++ /dev/null @@ -1,283 +0,0 @@ -#include -#include - -#include // std::move, std::any_of -#include // assert -#include // std::back_inserter -#include // std::move - -#include "compile_helpers.h" - -namespace { - -auto compile_subschema( - const sourcemeta::jsontoolkit::SchemaCompilerContext &context, - const sourcemeta::jsontoolkit::SchemaCompilerSchemaContext &schema_context, - const sourcemeta::jsontoolkit::SchemaCompilerDynamicContext - &dynamic_context, - const std::optional &default_dialect) - -> sourcemeta::jsontoolkit::SchemaCompilerTemplate { - using namespace sourcemeta::jsontoolkit; - assert(is_schema(schema_context.schema)); - - // Handle boolean schemas earlier on, as nobody should be able to - // override what these mean. - if (schema_context.schema.is_boolean()) { - if (schema_context.schema.to_boolean()) { - return {}; - } else { - return {make(true, context, schema_context, - dynamic_context, - SchemaCompilerValueNone{})}; - } - } - - SchemaCompilerTemplate steps; - for (const auto &entry : - SchemaKeywordIterator{schema_context.schema, context.walker, - context.resolver, default_dialect}) { - assert(entry.pointer.back().is_property()); - const auto &keyword{entry.pointer.back().to_property()}; - for (auto &&step : context.compiler( - context, - {schema_context.relative_pointer.concat({keyword}), - schema_context.schema, entry.vocabularies, schema_context.base, - // TODO: This represents a copy - schema_context.labels, schema_context.references}, - {keyword, dynamic_context.base_schema_location, - dynamic_context.base_instance_location})) { - // Just a sanity check to ensure every keyword location is indeed valid - assert(context.frame.contains( - {ReferenceType::Static, - std::visit([](const auto &value) { return value.keyword_location; }, - step)})); - steps.push_back(std::move(step)); - } - } - - return steps; -} - -} // namespace - -namespace sourcemeta::jsontoolkit { - -auto compile(const JSON &schema, const SchemaWalker &walker, - const SchemaResolver &resolver, const SchemaCompiler &compiler, - const std::optional &default_dialect) - -> SchemaCompilerTemplate { - assert(is_schema(schema)); - - // Make sure the input schema is bundled, otherwise we won't be able to - // resolve remote references here - const JSON result{bundle(schema, walker, resolver, BundleOptions::Default, - default_dialect)}; - - // Perform framing to resolve references later on - ReferenceFrame frame; - ReferenceMap references; - sourcemeta::jsontoolkit::frame(result, frame, references, walker, resolver, - default_dialect) - .wait(); - - const std::string base{ - URI{sourcemeta::jsontoolkit::identify( - schema, resolver, - sourcemeta::jsontoolkit::IdentificationStrategy::Strict, - default_dialect) - .get() - .value_or("")} - .canonicalize() - .recompose()}; - - assert(frame.contains({ReferenceType::Static, base})); - const auto root_frame_entry{frame.at({ReferenceType::Static, base})}; - - // Check whether dynamic referencing takes places in this schema. If not, - // we can avoid the overhead of keeping track of dynamics scopes, etc - bool uses_dynamic_scopes{false}; - for (const auto &reference : references) { - if (reference.first.first == ReferenceType::Dynamic) { - uses_dynamic_scopes = true; - break; - } - } - - const sourcemeta::jsontoolkit::SchemaCompilerContext context{ - result, frame, references, walker, - resolver, compiler, uses_dynamic_scopes}; - sourcemeta::jsontoolkit::SchemaCompilerSchemaContext schema_context{ - empty_pointer, - result, - vocabularies(schema, resolver, root_frame_entry.dialect).get(), - root_frame_entry.base, - {}, - {}}; - const sourcemeta::jsontoolkit::SchemaCompilerDynamicContext dynamic_context{ - relative_dynamic_context}; - sourcemeta::jsontoolkit::SchemaCompilerTemplate compiler_template; - - if (uses_dynamic_scopes && - (schema_context.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/core") || - schema_context.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/core"))) { - for (const auto &entry : frame) { - // We are only trying to find dynamic anchors - if (entry.second.type != ReferenceEntryType::Anchor || - entry.first.first != ReferenceType::Dynamic) { - continue; - } - - const URI anchor_uri{entry.first.second}; - std::ostringstream name; - name << anchor_uri.recompose_without_fragment().value_or(""); - name << '#'; - name << anchor_uri.fragment().value_or(""); - const auto label{std::hash{}(name.str())}; - schema_context.labels.insert(label); - - // Configure a schema context that corresponds to the - // schema resource that we are precompiling - auto subschema{get(result, entry.second.pointer)}; - auto nested_vocabularies{ - vocabularies(subschema, resolver, entry.second.dialect).get()}; - const sourcemeta::jsontoolkit::SchemaCompilerSchemaContext - nested_schema_context{entry.second.relative_pointer, - std::move(subschema), - std::move(nested_vocabularies), - entry.second.base, - {}, - {}}; - - compiler_template.push_back(make( - true, context, nested_schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{label}, - compile(context, nested_schema_context, relative_dynamic_context, - empty_pointer, empty_pointer, entry.first.second))); - } - } - - auto children{compile_subschema(context, schema_context, dynamic_context, - root_frame_entry.dialect)}; - if (compiler_template.empty()) { - return children; - } else { - compiler_template.reserve(compiler_template.size() + children.size()); - std::move(children.begin(), children.end(), - std::back_inserter(compiler_template)); - return compiler_template; - } -} - -auto compile(const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, - const Pointer &schema_suffix, const Pointer &instance_suffix, - const std::optional &uri) -> SchemaCompilerTemplate { - // Determine URI of the destination after recursion - const std::string destination{ - uri.has_value() - ? URI{uri.value()}.canonicalize().recompose() - : to_uri(schema_context.relative_pointer.concat(schema_suffix), - schema_context.base) - .canonicalize() - .recompose()}; - - // Otherwise the recursion attempt is non-sense - if (!context.frame.contains({ReferenceType::Static, destination})) { - throw SchemaReferenceError( - destination, schema_context.relative_pointer, - "The target of the reference does not exist in the schema"); - } - - const auto &entry{context.frame.at({ReferenceType::Static, destination})}; - const auto &new_schema{get(context.root, entry.pointer)}; - - if (!is_schema(new_schema)) { - throw SchemaReferenceError( - destination, schema_context.relative_pointer, - "The target of the reference is not a valid schema"); - } - - const Pointer destination_pointer{ - dynamic_context.keyword.empty() - ? dynamic_context.base_schema_location.concat(schema_suffix) - : dynamic_context.base_schema_location - .concat({dynamic_context.keyword}) - .concat(schema_suffix)}; - - return compile_subschema( - context, - {entry.relative_pointer, new_schema, - vocabularies(new_schema, context.resolver, entry.dialect).get(), - entry.base, - // TODO: This represents a copy - schema_context.labels, schema_context.references}, - {dynamic_context.keyword, destination_pointer, - dynamic_context.base_instance_location.concat(instance_suffix)}, - entry.dialect); -} - -SchemaCompilerErrorTraceOutput::SchemaCompilerErrorTraceOutput( - const JSON &instance, const WeakPointer &base) - : instance_{instance}, base_{base} {} - -auto SchemaCompilerErrorTraceOutput::begin() const -> const_iterator { - return this->output.begin(); -} - -auto SchemaCompilerErrorTraceOutput::end() const -> const_iterator { - return this->output.end(); -} - -auto SchemaCompilerErrorTraceOutput::cbegin() const -> const_iterator { - return this->output.cbegin(); -} - -auto SchemaCompilerErrorTraceOutput::cend() const -> const_iterator { - return this->output.cend(); -} - -auto SchemaCompilerErrorTraceOutput::operator()( - const SchemaCompilerEvaluationType type, const bool result, - const SchemaCompilerTemplate::value_type &step, - const WeakPointer &evaluate_path, const WeakPointer &instance_location, - const JSON &annotation) -> void { - assert(!evaluate_path.empty()); - assert(evaluate_path.back().is_property()); - - if (type == sourcemeta::jsontoolkit::SchemaCompilerEvaluationType::Pre) { - assert(result); - const auto &keyword{evaluate_path.back().to_property()}; - // To ease the output - if (keyword == "oneOf" || keyword == "not") { - this->mask.insert(evaluate_path); - } - } else if (type == - sourcemeta::jsontoolkit::SchemaCompilerEvaluationType::Post && - this->mask.contains(evaluate_path)) { - this->mask.erase(evaluate_path); - } - - // Ignore successful or masked steps - if (result || std::any_of(this->mask.cbegin(), this->mask.cend(), - [&evaluate_path](const auto &entry) { - return evaluate_path.starts_with(entry); - })) { - return; - } - - auto effective_evaluate_path{evaluate_path.resolve_from(this->base_)}; - if (effective_evaluate_path.empty()) { - return; - } - - this->output.push_back( - {sourcemeta::jsontoolkit::describe(result, step, evaluate_path, - instance_location, this->instance_, - annotation), - instance_location, std::move(effective_evaluate_path)}); -} - -} // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/jsonschema/compile_describe.cc b/vendor/jsontoolkit/src/jsonschema/compile_describe.cc deleted file mode 100644 index a65f49d1..00000000 --- a/vendor/jsontoolkit/src/jsonschema/compile_describe.cc +++ /dev/null @@ -1,1746 +0,0 @@ -#include - -#include // std::any_of -#include // assert -#include // std::ostringstream -#include // std::visit - -namespace { -using namespace sourcemeta::jsontoolkit; - -template auto step_value(const T &step) -> decltype(auto) { - if constexpr (requires { step.value; }) { - return step.value; - } else { - return step.id; - } -} - -auto to_string(const JSON::Type type) -> std::string { - // Otherwise the type "real" might not make a lot - // of sense to JSON Schema users - if (type == JSON::Type::Real) { - return "number"; - } else { - std::ostringstream result; - result << type; - return result.str(); - } -} - -auto escape_string(const std::string &input) -> std::string { - std::ostringstream result; - result << '"'; - - for (const auto character : input) { - if (character == '"') { - result << "\\\""; - } else { - result << character; - } - } - - result << '"'; - return result.str(); -} - -auto describe_type_check(const bool valid, const JSON::Type current, - const JSON::Type expected, std::ostringstream &message) - -> void { - message << "The value was expected to be of type "; - message << to_string(expected); - if (!valid) { - message << " but it was of type "; - message << to_string(current); - } -} - -auto describe_types_check(const bool valid, const JSON::Type current, - const std::vector &expected, - std::ostringstream &message) -> void { - assert(expected.size() > 1); - auto copy = expected; - - const auto match_real{ - std::find(copy.cbegin(), copy.cend(), JSON::Type::Real)}; - const auto match_integer{ - std::find(copy.cbegin(), copy.cend(), JSON::Type::Integer)}; - if (match_real != copy.cend() && match_integer != copy.cend()) { - copy.erase(match_integer); - } - - if (copy.size() == 1) { - describe_type_check(valid, current, *(copy.cbegin()), message); - return; - } - - message << "The value was expected to be of type "; - for (auto iterator = copy.cbegin(); iterator != copy.cend(); ++iterator) { - if (std::next(iterator) == copy.cend()) { - message << "or " << to_string(*iterator); - } else { - message << to_string(*iterator) << ", "; - } - } - - if (valid) { - message << " and it was of type "; - } else { - message << " but it was of type "; - } - - if (valid && current == JSON::Type::Integer && - std::find(copy.cbegin(), copy.cend(), JSON::Type::Real) != copy.cend()) { - message << "number"; - } else { - message << to_string(current); - } -} - -auto describe_reference(const JSON &target) -> std::string { - std::ostringstream message; - message << "The " << to_string(target.type()) - << " value was expected to validate against the statically " - "referenced schema"; - return message.str(); -} - -auto is_within_keyword(const WeakPointer &evaluate_path, - const std::string &keyword) -> bool { - return std::any_of(evaluate_path.cbegin(), evaluate_path.cend(), - [&keyword](const auto &token) { - return token.is_property() && - token.to_property() == keyword; - }); -} - -auto unknown() -> std::string { - // In theory we should never get here - assert(false); - return ""; -} - -struct DescribeVisitor { - const bool valid; - const WeakPointer &evaluate_path; - const std::string &keyword; - const WeakPointer &instance_location; - const JSON ⌖ - const JSON &annotation; - - auto operator()(const SchemaCompilerAssertionFail &) const -> std::string { - if (this->keyword == "contains") { - return "The constraints declared for this keyword were not satisfiable"; - } - - if (this->keyword == "additionalProperties" || - this->keyword == "unevaluatedProperties") { - std::ostringstream message; - assert(!this->instance_location.empty()); - assert(this->instance_location.back().is_property()); - message << "The object value was not expected to define the property " - << escape_string(this->instance_location.back().to_property()); - return message.str(); - } - - assert(this->keyword.empty()); - return "No instance is expected to succeed against the false schema"; - } - - auto operator()(const SchemaCompilerLogicalOr &step) const -> std::string { - assert(!step.children.empty()); - std::ostringstream message; - message << "The " << to_string(this->target.type()) - << " value was expected to validate against "; - if (step.children.size() > 1) { - message << "at least one of the " << step.children.size() - << " given subschemas"; - } else { - message << "the given subschema"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLogicalAnd &step) const -> std::string { - if (this->keyword == "allOf") { - assert(!step.children.empty()); - std::ostringstream message; - message << "The " << to_string(this->target.type()) - << " value was expected to validate against the "; - if (step.children.size() > 1) { - message << step.children.size() << " given subschemas"; - } else { - message << "given subschema"; - } - - return message.str(); - } - - if (this->keyword == "properties") { - assert(!step.children.empty()); - assert(this->target.is_object()); - std::ostringstream message; - message << "The object value was expected to validate against the "; - if (step.children.size() == 1) { - message << "single defined property subschema"; - } else { - // We cannot provide the specific number of properties, - // as the number of children might be flatten out - // for performance reasons - message << "defined properties subschemas"; - } - - return message.str(); - } - - if (this->keyword == "$ref") { - return describe_reference(this->target); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerLogicalXor &step) const -> std::string { - assert(!step.children.empty()); - std::ostringstream message; - message << "The " << to_string(this->target.type()) - << " value was expected to validate against "; - if (step.children.size() > 1) { - message << "one and only one of the " << step.children.size() - << " given subschemas"; - } else { - message << "the given subschema"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLogicalCondition &) const -> std::string { - return unknown(); - } - - auto operator()(const SchemaCompilerLogicalNot &) const -> std::string { - std::ostringstream message; - message - << "The " << to_string(this->target.type()) - << " value was expected to not validate against the given subschema"; - if (!this->valid) { - message << ", but it did"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerControlLabel &) const -> std::string { - return describe_reference(this->target); - } - - auto operator()(const SchemaCompilerControlMark &) const -> std::string { - return describe_reference(this->target); - } - - auto operator()(const SchemaCompilerControlJump &) const -> std::string { - return describe_reference(this->target); - } - - auto operator()(const SchemaCompilerControlDynamicAnchorJump &step) const - -> std::string { - if (this->keyword == "$dynamicRef") { - const auto &value{step_value(step)}; - std::ostringstream message; - message << "The " << to_string(target.type()) - << " value was expected to validate against the first subschema " - "in scope that declared the dynamic anchor " - << escape_string(value); - return message.str(); - } - - assert(this->keyword == "$recursiveRef"); - std::ostringstream message; - message << "The " << to_string(target.type()) - << " value was expected to validate against the first subschema " - "in scope that declared a recursive anchor"; - return message.str(); - } - - auto operator()(const SchemaCompilerAnnotationEmit &) const -> std::string { - if (this->keyword == "properties") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The object property " - << escape_string(this->annotation.to_string()) - << " successfully validated against its property " - "subschema"; - return message.str(); - } - - if ((this->keyword == "items" || this->keyword == "additionalItems") && - this->annotation.is_boolean() && this->annotation.to_boolean()) { - assert(this->target.is_array()); - std::ostringstream message; - message << "At least one item of the array value successfully validated " - "against the given subschema"; - return message.str(); - } - - if ((this->keyword == "prefixItems" || this->keyword == "items") && - this->annotation.is_integer()) { - assert(this->target.is_array()); - assert(this->annotation.is_positive()); - std::ostringstream message; - if (this->annotation.to_integer() == 0) { - message << "The first item of the array value successfully validated " - "against the first " - "positional subschema"; - } else { - message << "The first " << this->annotation.to_integer() + 1 - << " items of the array value successfully validated against " - "the given " - "positional subschemas"; - } - - return message.str(); - } - - if (this->keyword == "title" || this->keyword == "description") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The " << this->keyword << " of the"; - if (this->instance_location.empty()) { - message << " instance"; - } else { - message << " instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - message << " was " << escape_string(this->annotation.to_string()); - return message.str(); - } - - if (this->keyword == "default") { - std::ostringstream message; - message << "The default value of the"; - if (this->instance_location.empty()) { - message << " instance"; - } else { - message << " instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - message << " was "; - stringify(this->annotation, message); - return message.str(); - } - - if (this->keyword == "deprecated" && this->annotation.is_boolean()) { - std::ostringstream message; - if (this->instance_location.empty()) { - message << "The instance"; - } else { - message << "The instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - if (this->annotation.to_boolean()) { - message << " was considered deprecated"; - } else { - message << " was not considered deprecated"; - } - - return message.str(); - } - - if (this->keyword == "readOnly" && this->annotation.is_boolean()) { - std::ostringstream message; - if (this->instance_location.empty()) { - message << "The instance"; - } else { - message << "The instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - if (this->annotation.to_boolean()) { - message << " was considered read-only"; - } else { - message << " was not considered read-only"; - } - - return message.str(); - } - - if (this->keyword == "writeOnly" && this->annotation.is_boolean()) { - std::ostringstream message; - if (this->instance_location.empty()) { - message << "The instance"; - } else { - message << "The instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - if (this->annotation.to_boolean()) { - message << " was considered write-only"; - } else { - message << " was not considered write-only"; - } - - return message.str(); - } - - if (this->keyword == "examples") { - assert(this->annotation.is_array()); - std::ostringstream message; - if (this->instance_location.empty()) { - message << "Examples of the instance"; - } else { - message << "Examples of the instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - message << " were "; - for (auto iterator = this->annotation.as_array().cbegin(); - iterator != this->annotation.as_array().cend(); ++iterator) { - if (std::next(iterator) == this->annotation.as_array().cend()) { - message << "and "; - stringify(*iterator, message); - } else { - stringify(*iterator, message); - message << ", "; - } - } - - return message.str(); - } - - if (this->keyword == "contentEncoding") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The content encoding of the"; - if (this->instance_location.empty()) { - message << " instance"; - } else { - message << " instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - message << " was " << escape_string(this->annotation.to_string()); - return message.str(); - } - - if (this->keyword == "contentMediaType") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The content media type of the"; - if (this->instance_location.empty()) { - message << " instance"; - } else { - message << " instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - message << " was " << escape_string(this->annotation.to_string()); - return message.str(); - } - - if (this->keyword == "contentSchema") { - std::ostringstream message; - message << "When decoded, the"; - if (this->instance_location.empty()) { - message << " instance"; - } else { - message << " instance location \""; - stringify(this->instance_location, message); - message << "\""; - } - - message << " was expected to validate against the schema "; - stringify(this->annotation, message); - return message.str(); - } - - std::ostringstream message; - message << "The unrecognized keyword " << escape_string(this->keyword) - << " was collected as the annotation "; - stringify(this->annotation, message); - return message.str(); - } - - auto operator()(const SchemaCompilerAnnotationWhenArraySizeEqual &) const - -> std::string { - if (this->keyword == "items" && this->annotation.is_boolean() && - this->annotation.to_boolean()) { - assert(this->target.is_array()); - std::ostringstream message; - message << "At least one item of the array value successfully validated " - "against the given subschema"; - return message.str(); - } - - if (this->keyword == "prefixItems" && this->annotation.is_boolean() && - this->annotation.to_boolean()) { - assert(this->target.is_array()); - std::ostringstream message; - message << "Every item of the array value validated against the given " - "positional subschemas"; - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAnnotationWhenArraySizeGreater &) const - -> std::string { - if ((this->keyword == "prefixItems" || this->keyword == "items") && - this->annotation.is_integer()) { - assert(this->target.is_array()); - assert(this->annotation.is_positive()); - std::ostringstream message; - if (this->annotation.to_integer() == 0) { - message << "The first item of the array value successfully validated " - "against the first " - "positional subschema"; - } else { - message << "The first " << this->annotation.to_integer() + 1 - << " items of the array value successfully validated against " - "the given " - "positional subschemas"; - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAnnotationToParent &) const - -> std::string { - if (this->keyword == "unevaluatedItems" && this->annotation.is_boolean() && - this->annotation.to_boolean()) { - assert(this->target.is_array()); - std::ostringstream message; - message << "At least one item of the array value successfully validated " - "against the subschema for unevaluated items"; - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAnnotationBasenameToParent &) const - -> std::string { - if (this->keyword == "patternProperties") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The object property " - << escape_string(this->annotation.to_string()) - << " successfully validated against its pattern property " - "subschema"; - return message.str(); - } - - if (this->keyword == "additionalProperties") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The object property " - << escape_string(this->annotation.to_string()) - << " successfully validated against the additional properties " - "subschema"; - return message.str(); - } - - if (this->keyword == "unevaluatedProperties") { - assert(this->annotation.is_string()); - std::ostringstream message; - message << "The object property " - << escape_string(this->annotation.to_string()) - << " successfully validated against the subschema for " - "unevaluated properties"; - return message.str(); - } - - if (this->keyword == "contains" && this->annotation.is_integer()) { - assert(this->target.is_array()); - assert(this->annotation.is_positive()); - std::ostringstream message; - message << "The item at index " << this->annotation.to_integer() - << " of the array value successfully validated against the " - "containment check subschema"; - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerLoopProperties &step) const - -> std::string { - assert(this->keyword == "additionalProperties"); - std::ostringstream message; - if (step.children.size() == 1 && - std::holds_alternative( - step.children.front())) { - message << "The object value was not expected to define additional " - "properties"; - } else { - message << "The object properties not covered by other adjacent object " - "keywords were expected to validate against this subschema"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLoopPropertiesNoAnnotation &step) const - -> std::string { - if (this->keyword == "unevaluatedProperties") { - std::ostringstream message; - if (!step.children.empty() && - std::holds_alternative( - step.children.front())) { - message << "The object value was not expected to define unevaluated " - "properties"; - } else { - message << "The object properties not covered by other object " - "keywords were expected to validate against this subschema"; - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerLoopPropertiesExcept &step) const - -> std::string { - assert(this->keyword == "additionalProperties"); - std::ostringstream message; - if (step.children.size() == 1 && - std::holds_alternative( - step.children.front())) { - message << "The object value was not expected to define additional " - "properties"; - } else { - message << "The object properties not covered by other adjacent object " - "keywords were expected to validate against this subschema"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLoopPropertiesType &step) const - -> std::string { - std::ostringstream message; - message << "The object properties were expected to be of type " - << to_string(step.value); - return message.str(); - } - - auto operator()(const SchemaCompilerLoopPropertiesTypeStrict &step) const - -> std::string { - std::ostringstream message; - message << "The object properties were expected to be of type " - << to_string(step.value); - return message.str(); - } - - auto operator()(const SchemaCompilerLoopKeys &) const -> std::string { - assert(this->keyword == "propertyNames"); - assert(this->target.is_object()); - std::ostringstream message; - - if (this->target.size() == 0) { - assert(this->valid); - message << "The object is empty and no properties were expected to " - "validate against the given subschema"; - } else if (this->target.size() == 1) { - message << "The object property "; - message << escape_string(this->target.as_object().cbegin()->first); - message << " was expected to validate against the given subschema"; - } else { - message << "The object properties "; - for (auto iterator = this->target.as_object().cbegin(); - iterator != this->target.as_object().cend(); ++iterator) { - if (std::next(iterator) == this->target.as_object().cend()) { - message << "and " << escape_string(iterator->first); - } else { - message << escape_string(iterator->first) << ", "; - } - } - - message << " were expected to validate against the given subschema"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLoopItems &step) const -> std::string { - assert(this->target.is_array()); - const auto &value{step_value(step)}; - std::ostringstream message; - message << "Every item in the array value"; - if (value == 1) { - message << " except for the first one"; - } else if (value > 0) { - message << " except for the first " << value; - } - - message << " was expected to validate against the given subschema"; - return message.str(); - } - - auto operator()(const SchemaCompilerLoopItemsUnmarked &) const - -> std::string { - return unknown(); - } - - auto operator()(const SchemaCompilerLoopItemsUnevaluated &step) const - -> std::string { - assert(this->keyword == "unevaluatedItems"); - const auto &value{step_value(step)}; - std::ostringstream message; - message << "The array items not evaluated by the keyword " - << escape_string(value.index) - << ", if any, were expected to validate against this subschema"; - return message.str(); - } - - auto operator()(const SchemaCompilerLoopContains &step) const -> std::string { - assert(this->target.is_array()); - std::ostringstream message; - const auto &value{step_value(step)}; - const auto minimum{std::get<0>(value)}; - const auto maximum{std::get<1>(value)}; - bool plural{true}; - - message << "The array value was expected to contain "; - if (maximum.has_value()) { - if (minimum == maximum.value() && minimum == 0) { - message << "any number of"; - } else if (minimum == maximum.value()) { - message << "exactly " << minimum; - if (minimum == 1) { - plural = false; - } - } else if (minimum == 0) { - message << "up to " << maximum.value(); - if (maximum.value() == 1) { - plural = false; - } - } else { - message << minimum << " to " << maximum.value(); - if (maximum.value() == 1) { - plural = false; - } - } - } else { - message << "at least " << minimum; - if (minimum == 1) { - plural = false; - } - } - - if (plural) { - message << " items that validate against the given subschema"; - } else { - message << " item that validates against the given subschema"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionDefines &step) const - -> std::string { - std::ostringstream message; - message << "The object value was expected to define the property " - << escape_string(step_value(step)); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionDefinesAll &step) const - -> std::string { - const auto &value{step_value(step)}; - assert(value.size() > 1); - std::ostringstream message; - message << "The object value was expected to define properties "; - for (auto iterator = value.cbegin(); iterator != value.cend(); ++iterator) { - if (std::next(iterator) == value.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - - if (this->valid) { - return message.str(); - } - - assert(this->target.is_object()); - std::set missing; - for (const auto &property : value) { - if (!this->target.defines(property)) { - missing.insert(property); - } - } - - assert(!missing.empty()); - if (missing.size() == 1) { - message << " but did not define the property " - << escape_string(*(missing.cbegin())); - } else { - message << " but did not define properties "; - for (auto iterator = missing.cbegin(); iterator != missing.cend(); - ++iterator) { - if (std::next(iterator) == missing.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionType &step) const - -> std::string { - std::ostringstream message; - describe_type_check(this->valid, this->target.type(), step_value(step), - message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionTypeStrict &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - if (!this->valid && value == JSON::Type::Real && - this->target.type() == JSON::Type::Integer) { - message - << "The value was expected to be a real number but it was an integer"; - } else if (!this->valid && value == JSON::Type::Integer && - this->target.type() == JSON::Type::Real) { - message - << "The value was expected to be an integer but it was a real number"; - } else { - describe_type_check(this->valid, this->target.type(), value, message); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionTypeAny &step) const - -> std::string { - std::ostringstream message; - describe_types_check(this->valid, this->target.type(), step_value(step), - message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionTypeStrictAny &step) const - -> std::string { - std::ostringstream message; - describe_types_check(this->valid, this->target.type(), step_value(step), - message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionTypeStringBounded &step) const - -> std::string { - std::ostringstream message; - - const auto minimum{std::get<0>(step.value)}; - const auto maximum{std::get<1>(step.value)}; - if (minimum == 0 && maximum.has_value()) { - message << "The value was expected to consist of a string of at most " - << maximum.value() - << (maximum.value() == 1 ? " character" : " characters"); - } else if (maximum.has_value()) { - message << "The value was expected to consist of a string of " << minimum - << " to " << maximum.value() - << (maximum.value() == 1 ? " character" : " characters"); - } else { - message << "The value was expected to consist of a string of at least " - << minimum << (minimum == 1 ? " character" : " characters"); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionTypeArrayBounded &step) const - -> std::string { - std::ostringstream message; - - const auto minimum{std::get<0>(step.value)}; - const auto maximum{std::get<1>(step.value)}; - if (minimum == 0 && maximum.has_value()) { - message << "The value was expected to consist of an array of at most " - << maximum.value() << (maximum.value() == 1 ? " item" : " items"); - } else if (maximum.has_value()) { - message << "The value was expected to consist of an array of " << minimum - << " to " << maximum.value() - << (maximum.value() == 1 ? " item" : " items"); - } else { - message << "The value was expected to consist of an array of at least " - << minimum << (minimum == 1 ? " item" : " items"); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionTypeObjectBounded &step) const - -> std::string { - std::ostringstream message; - - const auto minimum{std::get<0>(step.value)}; - const auto maximum{std::get<1>(step.value)}; - if (minimum == 0 && maximum.has_value()) { - message << "The value was expected to consist of an object of at most " - << maximum.value() - << (maximum.value() == 1 ? " property" : " properties"); - } else if (maximum.has_value()) { - message << "The value was expected to consist of an object of " << minimum - << " to " << maximum.value() - << (maximum.value() == 1 ? " property" : " properties"); - } else { - message << "The value was expected to consist of an object of at least " - << minimum << (minimum == 1 ? " property" : " properties"); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionRegex &step) const - -> std::string { - assert(this->target.is_string()); - std::ostringstream message; - message << "The string value " << escape_string(this->target.to_string()) - << " was expected to match the regular expression " - << escape_string(step_value(step).second); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionStringSizeLess &step) const - -> std::string { - if (this->keyword == "maxLength") { - std::ostringstream message; - const auto maximum{step_value(step) - 1}; - - if (is_within_keyword(this->evaluate_path, "propertyNames")) { - assert(this->instance_location.back().is_property()); - message << "The object property name " - << escape_string(this->instance_location.back().to_property()); - } else { - message << "The string value "; - stringify(this->target, message); - } - - message << " was expected to consist of at most " << maximum - << (maximum == 1 ? " character" : " characters"); - - if (this->valid) { - message << " and"; - } else { - message << " but"; - } - - message << " it consisted of "; - - if (is_within_keyword(this->evaluate_path, "propertyNames")) { - message << this->instance_location.back().to_property().size(); - message << (this->instance_location.back().to_property().size() == 1 - ? " character" - : " characters"); - } else { - message << this->target.size(); - message << (this->target.size() == 1 ? " character" : " characters"); - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionStringSizeGreater &step) const - -> std::string { - if (this->keyword == "minLength") { - std::ostringstream message; - const auto minimum{step_value(step) + 1}; - - if (is_within_keyword(this->evaluate_path, "propertyNames")) { - assert(this->instance_location.back().is_property()); - message << "The object property name " - << escape_string(this->instance_location.back().to_property()); - } else { - message << "The string value "; - stringify(this->target, message); - } - - message << " was expected to consist of at least " << minimum - << (minimum == 1 ? " character" : " characters"); - - if (this->valid) { - message << " and"; - } else { - message << " but"; - } - - message << " it consisted of "; - - if (is_within_keyword(this->evaluate_path, "propertyNames")) { - message << this->instance_location.back().to_property().size(); - message << (this->instance_location.back().to_property().size() == 1 - ? " character" - : " characters"); - } else { - message << this->target.size(); - message << (this->target.size() == 1 ? " character" : " characters"); - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionArraySizeLess &step) const - -> std::string { - if (this->keyword == "maxItems") { - assert(this->target.is_array()); - std::ostringstream message; - const auto maximum{step_value(step) - 1}; - message << "The array value was expected to contain at most " << maximum; - assert(maximum > 0); - if (maximum == 1) { - message << " item"; - } else { - message << " items"; - } - - if (this->valid) { - message << " and"; - } else { - message << " but"; - } - - message << " it contained " << this->target.size(); - if (this->target.size() == 1) { - message << " item"; - } else { - message << " items"; - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionArraySizeGreater &step) const - -> std::string { - if (this->keyword == "minItems") { - assert(this->target.is_array()); - std::ostringstream message; - const auto minimum{step_value(step) + 1}; - message << "The array value was expected to contain at least " << minimum; - assert(minimum > 0); - if (minimum == 1) { - message << " item"; - } else { - message << " items"; - } - - if (this->valid) { - message << " and"; - } else { - message << " but"; - } - - message << " it contained " << this->target.size(); - if (this->target.size() == 1) { - message << " item"; - } else { - message << " items"; - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionObjectSizeLess &step) const - -> std::string { - if (this->keyword == "maxProperties") { - assert(this->target.is_object()); - std::ostringstream message; - const auto maximum{step_value(step) - 1}; - message << "The object value was expected to contain at most " << maximum; - assert(maximum > 0); - if (maximum == 1) { - message << " property"; - } else { - message << " properties"; - } - - if (this->valid) { - message << " and"; - } else { - message << " but"; - } - - message << " it contained " << this->target.size(); - if (this->target.size() == 1) { - message << " property: "; - message << escape_string(this->target.as_object().cbegin()->first); - } else { - message << " properties: "; - - std::vector properties; - for (const auto &entry : this->target.as_object()) { - properties.push_back(entry.first); - } - std::sort(properties.begin(), properties.end()); - - for (auto iterator = properties.cbegin(); iterator != properties.cend(); - ++iterator) { - if (std::next(iterator) == properties.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionObjectSizeGreater &step) const - -> std::string { - if (this->keyword == "minProperties") { - assert(this->target.is_object()); - std::ostringstream message; - const auto minimum{step_value(step) + 1}; - message << "The object value was expected to contain at least " - << minimum; - assert(minimum > 0); - if (minimum == 1) { - message << " property"; - } else { - message << " properties"; - } - - if (this->valid) { - message << " and"; - } else { - message << " but"; - } - - message << " it contained " << this->target.size(); - if (this->target.size() == 1) { - message << " property: "; - message << escape_string(this->target.as_object().cbegin()->first); - } else { - message << " properties: "; - std::vector properties; - for (const auto &entry : this->target.as_object()) { - properties.push_back(entry.first); - } - std::sort(properties.begin(), properties.end()); - - for (auto iterator = properties.cbegin(); iterator != properties.cend(); - ++iterator) { - if (std::next(iterator) == properties.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionEqual &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - message << " was expected to equal the " << to_string(value.type()) - << " constant "; - stringify(value, message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionGreaterEqual &step) const { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - message << " was expected to be greater than or equal to the " - << to_string(value.type()) << " "; - stringify(value, message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionLessEqual &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - message << " was expected to be less than or equal to the " - << to_string(value.type()) << " "; - stringify(value, message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionGreater &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - message << " was expected to be greater than the " - << to_string(value.type()) << " "; - stringify(value, message); - if (!this->valid && value == this->target) { - message << ", but they were equal"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionLess &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - message << " was expected to be less than the " << to_string(value.type()) - << " "; - stringify(value, message); - if (!this->valid && value == this->target) { - message << ", but they were equal"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionUnique &) const -> std::string { - assert(this->target.is_array()); - auto array{this->target.as_array()}; - std::ostringstream message; - if (this->valid) { - message << "The array value was expected to not contain duplicate items"; - } else { - std::set duplicates; - for (auto iterator = array.cbegin(); iterator != array.cend(); - ++iterator) { - for (auto subiterator = std::next(iterator); - subiterator != array.cend(); ++subiterator) { - if (*iterator == *subiterator) { - duplicates.insert(*iterator); - } - } - } - - assert(!duplicates.empty()); - message << "The array value contained the following duplicate"; - if (duplicates.size() == 1) { - message << " item: "; - stringify(*(duplicates.cbegin()), message); - } else { - message << " items: "; - for (auto subiterator = duplicates.cbegin(); - subiterator != duplicates.cend(); ++subiterator) { - if (std::next(subiterator) == duplicates.cend()) { - message << "and "; - stringify(*subiterator, message); - } else { - stringify(*subiterator, message); - message << ", "; - } - } - } - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionDivisible &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - message << " was expected to be divisible by the " - << to_string(value.type()) << " "; - stringify(value, message); - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionEqualsAny &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - message << "The " << to_string(this->target.type()) << " value "; - stringify(this->target, message); - assert(!value.empty()); - - if (value.size() == 1) { - message << " was expected to equal the " - << to_string(value.cbegin()->type()) << " constant "; - stringify(*(value.cbegin()), message); - } else { - if (this->valid) { - message << " was expected to equal one of the " << value.size() - << " declared values"; - } else { - message << " was expected to equal one of the following values: "; - for (auto iterator = value.cbegin(); iterator != value.cend(); - ++iterator) { - if (std::next(iterator) == value.cend()) { - message << "and "; - stringify(*iterator, message); - } else { - stringify(*iterator, message); - message << ", "; - } - } - } - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionStringType &step) const - -> std::string { - assert(this->target.is_string()); - std::ostringstream message; - message << "The string value " << escape_string(this->target.to_string()) - << " was expected to represent a valid"; - switch (step_value(step)) { - case SchemaCompilerValueStringType::URI: - message << " URI"; - break; - default: - return unknown(); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionPropertyType &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - if (!this->valid && value == JSON::Type::Real && - this->target.type() == JSON::Type::Integer) { - message - << "The value was expected to be a real number but it was an integer"; - } else if (!this->valid && value == JSON::Type::Integer && - this->target.type() == JSON::Type::Real) { - message - << "The value was expected to be an integer but it was a real number"; - } else { - describe_type_check(this->valid, this->target.type(), value, message); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerAssertionPropertyTypeStrict &step) const - -> std::string { - std::ostringstream message; - const auto &value{step_value(step)}; - if (!this->valid && value == JSON::Type::Real && - this->target.type() == JSON::Type::Integer) { - message - << "The value was expected to be a real number but it was an integer"; - } else if (!this->valid && value == JSON::Type::Integer && - this->target.type() == JSON::Type::Real) { - message - << "The value was expected to be an integer but it was a real number"; - } else { - describe_type_check(this->valid, this->target.type(), value, message); - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLoopPropertiesMatch &step) const - -> std::string { - assert(!step.children.empty()); - assert(this->target.is_object()); - std::ostringstream message; - message << "The object value was expected to validate against the "; - if (step.children.size() == 1) { - message << "single defined property subschema"; - } else { - message << step.children.size() << " defined properties subschemas"; - } - - return message.str(); - } - - auto operator()(const SchemaCompilerLogicalWhenType &step) const - -> std::string { - if (this->keyword == "patternProperties") { - assert(!step.children.empty()); - assert(this->target.is_object()); - std::ostringstream message; - message << "The object value was expected to validate against the "; - if (step.children.size() == 1) { - message << "single defined pattern property subschema"; - } else { - message << step.children.size() - << " defined pattern properties subschemas"; - } - - return message.str(); - } - - if (this->keyword == "items" || this->keyword == "prefixItems") { - assert(!step.children.empty()); - assert(this->target.is_array()); - std::ostringstream message; - message << "The first "; - if (step.children.size() == 1) { - message << "item of the array value was"; - } else { - message << step.children.size() << " items of the array value were"; - } - - message << " expected to validate against the corresponding subschemas"; - return message.str(); - } - - if (this->keyword == "dependencies") { - assert(this->target.is_object()); - assert(!step.children.empty()); - - std::set present; - std::set present_with_schemas; - std::set present_with_properties; - std::set all_dependencies; - std::set required_properties; - - for (const auto &child : step.children) { - // Schema - if (std::holds_alternative(child)) { - const auto &substep{ - std::get(child)}; - const auto &property{step_value(substep)}; - all_dependencies.insert(property); - if (!this->target.defines(property)) { - continue; - } - - present.insert(property); - present_with_schemas.insert(property); - - // Properties - } else { - assert(std::holds_alternative< - SchemaCompilerAssertionPropertyDependencies>(child)); - const auto &substep{ - std::get(child)}; - - for (const auto &[property, dependencies] : substep.value) { - all_dependencies.insert(property); - if (this->target.defines(property)) { - present.insert(property); - present_with_properties.insert(property); - for (const auto &dependency : dependencies) { - if (this->valid || !this->target.defines(dependency)) { - required_properties.insert(dependency); - } - } - } - } - } - } - - std::ostringstream message; - - if (present_with_schemas.empty() && present_with_properties.empty()) { - message << "The object value did not define the"; - assert(!all_dependencies.empty()); - if (all_dependencies.size() == 1) { - message << " property " - << escape_string(*(all_dependencies.cbegin())); - } else { - message << " properties "; - for (auto iterator = all_dependencies.cbegin(); - iterator != all_dependencies.cend(); ++iterator) { - if (std::next(iterator) == all_dependencies.cend()) { - message << "or " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - return message.str(); - } - - if (present.size() == 1) { - message << "Because the object value defined the"; - message << " property " << escape_string(*(present.cbegin())); - } else { - message << "Because the object value defined the"; - message << " properties "; - for (auto iterator = present.cbegin(); iterator != present.cend(); - ++iterator) { - if (std::next(iterator) == present.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - if (!required_properties.empty()) { - message << ", it was also expected to define the"; - if (required_properties.size() == 1) { - message << " property " - << escape_string(*(required_properties.cbegin())); - } else { - message << " properties "; - for (auto iterator = required_properties.cbegin(); - iterator != required_properties.cend(); ++iterator) { - if (std::next(iterator) == required_properties.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - } - - if (!present_with_schemas.empty()) { - message << ", "; - if (!required_properties.empty()) { - message << "and "; - } - - message << "it was also expected to successfully validate against the " - "corresponding "; - if (present_with_schemas.size() == 1) { - message << escape_string(*(present_with_schemas.cbegin())); - message << " subschema"; - } else { - for (auto iterator = present_with_schemas.cbegin(); - iterator != present_with_schemas.cend(); ++iterator) { - if (std::next(iterator) == present_with_schemas.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - - message << " subschemas"; - } - } - - return message.str(); - } - - if (this->keyword == "dependentSchemas") { - assert(this->target.is_object()); - assert(!step.children.empty()); - std::set present; - std::set all_dependencies; - for (const auto &child : step.children) { - assert(std::holds_alternative(child)); - const auto &substep{std::get(child)}; - const auto &property{step_value(substep)}; - all_dependencies.insert(property); - if (!this->target.defines(property)) { - continue; - } - - present.insert(property); - } - - std::ostringstream message; - - if (present.empty()) { - message << "The object value did not define the"; - assert(!all_dependencies.empty()); - if (all_dependencies.size() == 1) { - message << " property " - << escape_string(*(all_dependencies.cbegin())); - } else { - message << " properties "; - for (auto iterator = all_dependencies.cbegin(); - iterator != all_dependencies.cend(); ++iterator) { - if (std::next(iterator) == all_dependencies.cend()) { - message << "or " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - } else if (present.size() == 1) { - message << "Because the object value defined the"; - message << " property " << escape_string(*(present.cbegin())); - message - << ", it was also expected to validate against the corresponding " - "subschema"; - } else { - message << "Because the object value defined the"; - message << " properties "; - for (auto iterator = present.cbegin(); iterator != present.cend(); - ++iterator) { - if (std::next(iterator) == present.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - - message - << ", it was also expected to validate against the corresponding " - "subschemas"; - } - - return message.str(); - } - - return unknown(); - } - - auto operator()(const SchemaCompilerAssertionPropertyDependencies &step) const - -> std::string { - if (this->keyword == "dependentRequired") { - assert(this->target.is_object()); - std::set present; - std::set all_dependencies; - std::set required; - - for (const auto &[property, dependencies] : step.value) { - all_dependencies.insert(property); - if (this->target.defines(property)) { - present.insert(property); - for (const auto &dependency : dependencies) { - if (this->valid || !this->target.defines(dependency)) { - required.insert(dependency); - } - } - } - } - - std::ostringstream message; - - if (present.empty()) { - message << "The object value did not define the"; - assert(!all_dependencies.empty()); - if (all_dependencies.size() == 1) { - message << " property " - << escape_string(*(all_dependencies.cbegin())); - } else { - message << " properties "; - for (auto iterator = all_dependencies.cbegin(); - iterator != all_dependencies.cend(); ++iterator) { - if (std::next(iterator) == all_dependencies.cend()) { - message << "or " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - return message.str(); - } else if (present.size() == 1) { - message << "Because the object value defined the"; - message << " property " << escape_string(*(present.cbegin())); - } else { - message << "Because the object value defined the"; - message << " properties "; - for (auto iterator = present.cbegin(); iterator != present.cend(); - ++iterator) { - if (std::next(iterator) == present.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - assert(!required.empty()); - message << ", it was also expected to define the"; - if (required.size() == 1) { - message << " property " << escape_string(*(required.cbegin())); - } else { - message << " properties "; - for (auto iterator = required.cbegin(); iterator != required.cend(); - ++iterator) { - if (std::next(iterator) == required.cend()) { - message << "and " << escape_string(*iterator); - } else { - message << escape_string(*iterator) << ", "; - } - } - } - - return message.str(); - } - - return unknown(); - } - - // These steps are never described, at least not right now - - auto operator()(const SchemaCompilerLogicalWhenArraySizeGreater &) const - -> std::string { - return unknown(); - } - auto operator()(const SchemaCompilerLogicalWhenArraySizeEqual &) const - -> std::string { - return unknown(); - } - auto operator()(const SchemaCompilerLogicalWhenDefines &) const - -> std::string { - return unknown(); - } - auto operator()(const SchemaCompilerLoopPropertiesRegex &) const - -> std::string { - return unknown(); - } -}; - -} // namespace - -namespace sourcemeta::jsontoolkit { - -// TODO: What will unlock even better error messages is being able to -// get the subschema being evaluated along with the keyword -auto describe(const bool valid, const SchemaCompilerTemplate::value_type &step, - const WeakPointer &evaluate_path, - const WeakPointer &instance_location, const JSON &instance, - const JSON &annotation) -> std::string { - assert(evaluate_path.empty() || evaluate_path.back().is_property()); - return std::visit( - DescribeVisitor{ - valid, evaluate_path, - evaluate_path.empty() ? "" : evaluate_path.back().to_property(), - instance_location, get(instance, instance_location), annotation}, - step); -} - -} // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/jsonschema/compile_helpers.h b/vendor/jsontoolkit/src/jsonschema/compile_helpers.h deleted file mode 100644 index e0d66256..00000000 --- a/vendor/jsontoolkit/src/jsonschema/compile_helpers.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_COMPILE_HELPERS_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_COMPILE_HELPERS_H_ - -#include - -#include // assert -#include // std::declval, std::move - -namespace sourcemeta::jsontoolkit { - -static const SchemaCompilerDynamicContext relative_dynamic_context{ - "", empty_pointer, empty_pointer}; - -// Instantiate a value-oriented step -template -auto make(const bool report, const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, - // Take the value type from the "type" property of the step struct - const decltype(std::declval().value) &value) -> Step { - return { - dynamic_context.keyword.empty() - ? dynamic_context.base_schema_location - : dynamic_context.base_schema_location.concat( - {dynamic_context.keyword}), - dynamic_context.base_instance_location, - to_uri(schema_context.relative_pointer, schema_context.base).recompose(), - schema_context.base.recompose(), - context.uses_dynamic_scopes, - report, - value}; -} - -// Instantiate an applicator step -template -auto make(const bool report, const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, - // Take the value type from the "value" property of the step struct - decltype(std::declval().value) &&value, - SchemaCompilerTemplate &&children) -> Step { - return { - dynamic_context.keyword.empty() - ? dynamic_context.base_schema_location - : dynamic_context.base_schema_location.concat( - {dynamic_context.keyword}), - dynamic_context.base_instance_location, - to_uri(schema_context.relative_pointer, schema_context.base).recompose(), - schema_context.base.recompose(), - context.uses_dynamic_scopes, - report, - std::move(value), - std::move(children)}; -} - -template -auto unroll(const SchemaCompilerDynamicContext &dynamic_context, - const Step &step, - const Pointer &base_instance_location = empty_pointer) -> Type { - assert(std::holds_alternative(step)); - return {dynamic_context.keyword.empty() - ? std::get(step).relative_schema_location - : dynamic_context.base_schema_location - .concat({dynamic_context.keyword}) - .concat(std::get(step).relative_schema_location), - base_instance_location.concat( - std::get(step).relative_instance_location), - std::get(step).keyword_location, - std::get(step).schema_resource, - std::get(step).dynamic, - std::get(step).report, - std::get(step).value}; -} - -inline auto unsigned_integer_property(const JSON &document, - const JSON::String &property) - -> std::optional { - if (document.defines(property) && document.at(property).is_integer()) { - const auto value{document.at(property).to_integer()}; - assert(value >= 0); - return static_cast(value); - } - - return std::nullopt; -} - -inline auto unsigned_integer_property(const JSON &document, - const JSON::String &property, - const std::size_t otherwise) - -> std::size_t { - return unsigned_integer_property(document, property).value_or(otherwise); -} - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/compile_json.cc b/vendor/jsontoolkit/src/jsonschema/compile_json.cc deleted file mode 100644 index 89ad1bec..00000000 --- a/vendor/jsontoolkit/src/jsonschema/compile_json.cc +++ /dev/null @@ -1,335 +0,0 @@ -#include - -#include // assert -#include // std::less -#include // std::map -#include // std::ostringstream -#include // std::string_view -#include // std::is_same_v -#include // std::move - -namespace { - -template -auto value_to_json(const T &value) -> sourcemeta::jsontoolkit::JSON { - using namespace sourcemeta::jsontoolkit; - JSON result{JSON::make_object()}; - result.assign("category", JSON{"value"}); - if constexpr (std::is_same_v) { - result.assign("type", JSON{"json"}); - result.assign("value", JSON{value}); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"boolean"}); - result.assign("value", JSON{value}); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"regex"}); - result.assign("value", JSON{value.second}); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"type"}); - std::ostringstream type_string; - type_string << value; - result.assign("value", JSON{type_string.str()}); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"types"}); - JSON types{JSON::make_array()}; - for (const auto type : value) { - std::ostringstream type_string; - type_string << type; - types.push_back(JSON{type_string.str()}); - } - - result.assign("value", std::move(types)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"string"}); - result.assign("value", JSON{value}); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"strings"}); - JSON items{JSON::make_array()}; - for (const auto &item : value) { - items.push_back(JSON{item}); - } - - result.assign("value", std::move(items)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"array"}); - JSON items{JSON::make_array()}; - for (const auto &item : value) { - items.push_back(item); - } - - result.assign("value", std::move(items)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"unsigned-integer"}); - result.assign("value", JSON{value}); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"range"}); - JSON values{JSON::make_array()}; - const auto &range{value}; - values.push_back(JSON{std::get<0>(range)}); - values.push_back(std::get<1>(range).has_value() - ? JSON{std::get<1>(range).value()} - : JSON{nullptr}); - values.push_back(JSON{std::get<2>(range)}); - result.assign("value", std::move(values)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"named-indexes"}); - JSON values{JSON::make_object()}; - for (const auto &[name, index] : value) { - values.assign(name, JSON{index}); - } - - result.assign("value", std::move(values)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"string-map"}); - JSON map{JSON::make_object()}; - for (const auto &[string, strings] : value) { - JSON dependencies{JSON::make_array()}; - for (const auto &substring : strings) { - dependencies.push_back(JSON{substring}); - } - - map.assign(string, std::move(dependencies)); - } - - result.assign("value", std::move(map)); - return result; - } else if constexpr (std::is_same_v< - SchemaCompilerValueItemsAnnotationKeywords, T>) { - result.assign("type", JSON{"items-annotation-keywords"}); - JSON data{JSON::make_object()}; - data.assign("index", JSON{value.index}); - - JSON mask{JSON::make_array()}; - for (const auto &keyword : value.mask) { - mask.push_back(JSON{keyword}); - } - data.assign("mask", std::move(mask)); - - JSON filter{JSON::make_array()}; - for (const auto &keyword : value.filter) { - filter.push_back(JSON{keyword}); - } - data.assign("filter", std::move(filter)); - - result.assign("value", std::move(data)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"indexed-json"}); - JSON data{JSON::make_object()}; - data.assign("index", JSON{value.first}); - data.assign("value", value.second); - result.assign("value", std::move(data)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"property-filter"}); - JSON data{JSON::make_object()}; - data.assign("names", JSON::make_array()); - data.assign("patterns", JSON::make_array()); - - for (const auto &name : value.first) { - data.at("names").push_back(JSON{name}); - } - - for (const auto &pattern : value.second) { - data.at("patterns").push_back(JSON{pattern.second}); - } - - result.assign("value", std::move(data)); - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"string-type"}); - switch (value) { - case SchemaCompilerValueStringType::URI: - result.assign("value", JSON{"uri"}); - break; - default: - // We should never get here - assert(false); - } - - return result; - } else if constexpr (std::is_same_v) { - result.assign("type", JSON{"index-pair"}); - JSON data{JSON::make_array()}; - data.push_back(JSON{value.first}); - data.push_back(JSON{value.second}); - result.assign("value", std::move(data)); - return result; - } else { - static_assert(std::is_same_v); - return JSON{nullptr}; - } -} - -template -auto step_to_json( - const sourcemeta::jsontoolkit::SchemaCompilerTemplate::value_type &step) - -> sourcemeta::jsontoolkit::JSON { - static V visitor; - return std::visit(visitor, step); -} - -template -auto encode_step(const std::string_view category, const std::string_view type, - const T &step) -> sourcemeta::jsontoolkit::JSON { - using namespace sourcemeta::jsontoolkit; - JSON result{JSON::make_object()}; - result.assign("category", JSON{category}); - result.assign("type", JSON{type}); - result.assign("relativeSchemaLocation", - JSON{to_string(step.relative_schema_location)}); - result.assign("relativeInstanceLocation", - JSON{to_string(step.relative_instance_location)}); - result.assign("absoluteKeywordLocation", JSON{step.keyword_location}); - result.assign("schemaResource", JSON{step.schema_resource}); - result.assign("dynamic", JSON{step.dynamic}); - result.assign("report", JSON{step.report}); - result.assign("value", value_to_json(step.value)); - - if constexpr (requires { step.children; }) { - result.assign("children", JSON::make_array()); - for (const auto &child : step.children) { - result.at("children").push_back(step_to_json(child)); - } - } - - return result; -} - -struct StepVisitor { -#define HANDLE_STEP(category, type, name) \ - auto operator()(const sourcemeta::jsontoolkit::name &step) \ - const->sourcemeta::jsontoolkit::JSON { \ - return encode_step(category, type, step); \ - } - - HANDLE_STEP("assertion", "fail", SchemaCompilerAssertionFail) - HANDLE_STEP("assertion", "defines", SchemaCompilerAssertionDefines) - HANDLE_STEP("assertion", "defines-all", SchemaCompilerAssertionDefinesAll) - HANDLE_STEP("assertion", "property-dependencies", - SchemaCompilerAssertionPropertyDependencies) - HANDLE_STEP("assertion", "type", SchemaCompilerAssertionType) - HANDLE_STEP("assertion", "type-any", SchemaCompilerAssertionTypeAny) - HANDLE_STEP("assertion", "type-strict", SchemaCompilerAssertionTypeStrict) - HANDLE_STEP("assertion", "type-strict-any", - SchemaCompilerAssertionTypeStrictAny) - HANDLE_STEP("assertion", "type-string-bounded", - SchemaCompilerAssertionTypeStringBounded) - HANDLE_STEP("assertion", "type-array-bounded", - SchemaCompilerAssertionTypeArrayBounded) - HANDLE_STEP("assertion", "type-object-bounded", - SchemaCompilerAssertionTypeObjectBounded) - HANDLE_STEP("assertion", "regex", SchemaCompilerAssertionRegex) - HANDLE_STEP("assertion", "string-size-less", - SchemaCompilerAssertionStringSizeLess) - HANDLE_STEP("assertion", "string-size-greater", - SchemaCompilerAssertionStringSizeGreater) - HANDLE_STEP("assertion", "array-size-less", - SchemaCompilerAssertionArraySizeLess) - HANDLE_STEP("assertion", "array-size-greater", - SchemaCompilerAssertionArraySizeGreater) - HANDLE_STEP("assertion", "object-size-less", - SchemaCompilerAssertionObjectSizeLess) - HANDLE_STEP("assertion", "object-size-greater", - SchemaCompilerAssertionObjectSizeGreater) - HANDLE_STEP("assertion", "equal", SchemaCompilerAssertionEqual) - HANDLE_STEP("assertion", "greater-equal", SchemaCompilerAssertionGreaterEqual) - HANDLE_STEP("assertion", "less-equal", SchemaCompilerAssertionLessEqual) - HANDLE_STEP("assertion", "greater", SchemaCompilerAssertionGreater) - HANDLE_STEP("assertion", "less", SchemaCompilerAssertionLess) - HANDLE_STEP("assertion", "unique", SchemaCompilerAssertionUnique) - HANDLE_STEP("assertion", "divisible", SchemaCompilerAssertionDivisible) - HANDLE_STEP("assertion", "string-type", SchemaCompilerAssertionStringType) - HANDLE_STEP("assertion", "property-type", SchemaCompilerAssertionPropertyType) - HANDLE_STEP("assertion", "property-type-strict", - SchemaCompilerAssertionPropertyTypeStrict) - HANDLE_STEP("assertion", "equals-any", SchemaCompilerAssertionEqualsAny) - HANDLE_STEP("annotation", "emit", SchemaCompilerAnnotationEmit) - HANDLE_STEP("annotation", "when-array-size-equal", - SchemaCompilerAnnotationWhenArraySizeEqual) - HANDLE_STEP("annotation", "when-array-size-greater", - SchemaCompilerAnnotationWhenArraySizeGreater) - HANDLE_STEP("annotation", "to-parent", SchemaCompilerAnnotationToParent) - HANDLE_STEP("annotation", "basename-to-parent", - SchemaCompilerAnnotationBasenameToParent) - HANDLE_STEP("logical", "or", SchemaCompilerLogicalOr) - HANDLE_STEP("logical", "and", SchemaCompilerLogicalAnd) - HANDLE_STEP("logical", "xor", SchemaCompilerLogicalXor) - HANDLE_STEP("logical", "condition", SchemaCompilerLogicalCondition) - HANDLE_STEP("logical", "not", SchemaCompilerLogicalNot) - HANDLE_STEP("logical", "when-type", SchemaCompilerLogicalWhenType) - HANDLE_STEP("logical", "when-defines", SchemaCompilerLogicalWhenDefines) - HANDLE_STEP("logical", "when-array-size-greater", - SchemaCompilerLogicalWhenArraySizeGreater) - HANDLE_STEP("logical", "when-array-size-equal", - SchemaCompilerLogicalWhenArraySizeEqual) - HANDLE_STEP("loop", "properties-match", SchemaCompilerLoopPropertiesMatch) - HANDLE_STEP("loop", "properties", SchemaCompilerLoopProperties) - HANDLE_STEP("loop", "properties-regex", SchemaCompilerLoopPropertiesRegex) - HANDLE_STEP("loop", "properties-no-annotation", - SchemaCompilerLoopPropertiesNoAnnotation) - HANDLE_STEP("loop", "properties-except", SchemaCompilerLoopPropertiesExcept) - HANDLE_STEP("loop", "properties-type", SchemaCompilerLoopPropertiesType) - HANDLE_STEP("loop", "properties-type-strict", - SchemaCompilerLoopPropertiesTypeStrict) - HANDLE_STEP("loop", "keys", SchemaCompilerLoopKeys) - HANDLE_STEP("loop", "items", SchemaCompilerLoopItems) - HANDLE_STEP("loop", "items-unmarked", SchemaCompilerLoopItemsUnmarked) - HANDLE_STEP("loop", "items-unevaluated", SchemaCompilerLoopItemsUnevaluated) - HANDLE_STEP("loop", "contains", SchemaCompilerLoopContains) - HANDLE_STEP("control", "label", SchemaCompilerControlLabel) - HANDLE_STEP("control", "mark", SchemaCompilerControlMark) - HANDLE_STEP("control", "jump", SchemaCompilerControlJump) - HANDLE_STEP("control", "dynamic-anchor-jump", - SchemaCompilerControlDynamicAnchorJump) - -#undef HANDLE_STEP -}; - -} // namespace - -namespace sourcemeta::jsontoolkit { - -auto to_json(const SchemaCompilerTemplate &steps) -> JSON { - JSON result{JSON::make_array()}; - for (const auto &step : steps) { - result.push_back(step_to_json(step)); - } - - return result; -} - -auto compiler_template_format_compare(const JSON::String &left, - const JSON::String &right) -> bool { - using Rank = - std::map, - JSON::Allocator>>; - static Rank rank{{"category", 0}, - {"type", 1}, - {"value", 2}, - {"schemaResource", 3}, - {"absoluteKeywordLocation", 4}, - {"relativeSchemaLocation", 5}, - {"relativeInstanceLocation", 6}, - {"report", 7}, - {"dynamic", 8}, - {"children", 9}}; - - constexpr std::uint64_t DEFAULT_RANK{999}; - const auto left_rank{rank.contains(left) ? rank.at(left) : DEFAULT_RANK}; - const auto right_rank{rank.contains(right) ? rank.at(right) : DEFAULT_RANK}; - return left_rank < right_rank; -} - -} // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler.cc b/vendor/jsontoolkit/src/jsonschema/default_compiler.cc deleted file mode 100644 index 443804bb..00000000 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler.cc +++ /dev/null @@ -1,520 +0,0 @@ -#include -#include - -#include "default_compiler_2019_09.h" -#include "default_compiler_2020_12.h" -#include "default_compiler_draft4.h" -#include "default_compiler_draft6.h" -#include "default_compiler_draft7.h" - -#include // assert -#include // std::set -#include // std::string - -// TODO: Support every keyword -auto sourcemeta::jsontoolkit::default_schema_compiler( - const sourcemeta::jsontoolkit::SchemaCompilerContext &context, - const sourcemeta::jsontoolkit::SchemaCompilerSchemaContext &schema_context, - const sourcemeta::jsontoolkit::SchemaCompilerDynamicContext - &dynamic_context) -> sourcemeta::jsontoolkit::SchemaCompilerTemplate { - assert(!dynamic_context.keyword.empty()); - - static std::set SUPPORTED_VOCABULARIES{ - "https://json-schema.org/draft/2020-12/vocab/core", - "https://json-schema.org/draft/2020-12/vocab/applicator", - "https://json-schema.org/draft/2020-12/vocab/validation", - "https://json-schema.org/draft/2020-12/vocab/meta-data", - "https://json-schema.org/draft/2020-12/vocab/unevaluated", - "https://json-schema.org/draft/2020-12/vocab/format-annotation", - "https://json-schema.org/draft/2020-12/vocab/content", - "https://json-schema.org/draft/2019-09/vocab/core", - "https://json-schema.org/draft/2019-09/vocab/applicator", - "https://json-schema.org/draft/2019-09/vocab/validation", - "https://json-schema.org/draft/2019-09/vocab/meta-data", - "https://json-schema.org/draft/2019-09/vocab/format", - "https://json-schema.org/draft/2019-09/vocab/content", - "http://json-schema.org/draft-07/schema#", - "http://json-schema.org/draft-06/schema#", - "http://json-schema.org/draft-04/schema#"}; - for (const auto &vocabulary : schema_context.vocabularies) { - if (!SUPPORTED_VOCABULARIES.contains(vocabulary.first) && - vocabulary.second) { - throw SchemaVocabularyError(vocabulary.first, - "Cannot compile unsupported vocabulary"); - } - } - - using namespace sourcemeta::jsontoolkit; - -#define COMPILE(vocabulary, _keyword, handler) \ - if (schema_context.vocabularies.contains(vocabulary) && \ - dynamic_context.keyword == (_keyword)) { \ - return internal::handler(context, schema_context, dynamic_context); \ - } - -#define STOP_IF_SIBLING_KEYWORD(vocabulary, _keyword) \ - if (schema_context.vocabularies.contains(vocabulary) && \ - schema_context.schema.is_object() && \ - schema_context.schema.defines(_keyword)) { \ - return {}; \ - } - - // ******************************************** - // 2020-12 - // ******************************************** - - COMPILE("https://json-schema.org/draft/2020-12/vocab/core", "$dynamicRef", - compiler_2020_12_core_dynamicref); - - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "prefixItems", compiler_2020_12_applicator_prefixitems); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "items", - compiler_2020_12_applicator_items); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "contains", - compiler_2020_12_applicator_contains); - - // Same as 2019-09 - - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "dependentRequired", compiler_2019_09_validation_dependentrequired); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "dependentSchemas", compiler_2019_09_applicator_dependentschemas); - - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "properties", compiler_2019_09_applicator_properties); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "patternProperties", compiler_2019_09_applicator_patternproperties); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "additionalProperties", - compiler_2019_09_applicator_additionalproperties); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "anyOf", - compiler_2019_09_applicator_anyof); - COMPILE("https://json-schema.org/draft/2020-12/vocab/unevaluated", - "unevaluatedProperties", - compiler_2019_09_applicator_unevaluatedproperties); - COMPILE("https://json-schema.org/draft/2020-12/vocab/unevaluated", - "unevaluatedItems", compiler_2019_09_applicator_unevaluateditems); - - // Same as Draft 7 - - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "if", - compiler_draft7_applicator_if); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "then", - compiler_draft7_applicator_then); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "else", - compiler_draft7_applicator_else); - - // Same as Draft 6 - - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "propertyNames", compiler_draft6_validation_propertynames); - - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "type", - compiler_draft6_validation_type); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "const", - compiler_draft6_validation_const); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "exclusiveMaximum", compiler_draft6_validation_exclusivemaximum); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "exclusiveMinimum", compiler_draft6_validation_exclusiveminimum); - - // Same as Draft 4 - - // As per compatibility optional test - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", - "dependencies", compiler_draft4_applicator_dependencies); - - COMPILE("https://json-schema.org/draft/2020-12/vocab/core", "$ref", - compiler_draft4_core_ref); - - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "allOf", - compiler_draft4_applicator_allof); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "oneOf", - compiler_draft4_applicator_oneof); - COMPILE("https://json-schema.org/draft/2020-12/vocab/applicator", "not", - compiler_draft4_applicator_not); - - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "enum", - compiler_draft4_validation_enum); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "uniqueItems", compiler_draft4_validation_uniqueitems); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "maxItems", - compiler_draft4_validation_maxitems); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "minItems", - compiler_draft4_validation_minitems); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "required", - compiler_draft4_validation_required); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "maxProperties", compiler_draft4_validation_maxproperties); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "minProperties", compiler_draft4_validation_minproperties); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "maximum", - compiler_draft4_validation_maximum); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "minimum", - compiler_draft4_validation_minimum); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", - "multipleOf", compiler_draft4_validation_multipleof); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "maxLength", - compiler_draft4_validation_maxlength); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "minLength", - compiler_draft4_validation_minlength); - COMPILE("https://json-schema.org/draft/2020-12/vocab/validation", "pattern", - compiler_draft4_validation_pattern); - - // ******************************************** - // 2019-09 - // ******************************************** - - COMPILE("https://json-schema.org/draft/2019-09/vocab/core", "$recursiveRef", - compiler_2019_09_core_recursiveref); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "dependentRequired", compiler_2019_09_validation_dependentrequired); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "dependentSchemas", compiler_2019_09_applicator_dependentschemas); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "contains", - compiler_2019_09_applicator_contains); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "unevaluatedItems", compiler_2019_09_applicator_unevaluateditems); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "unevaluatedProperties", - compiler_2019_09_applicator_unevaluatedproperties); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "items", - compiler_2019_09_applicator_items); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "additionalItems", compiler_2019_09_applicator_additionalitems); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "anyOf", - compiler_2019_09_applicator_anyof); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "properties", compiler_2019_09_applicator_properties); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "patternProperties", compiler_2019_09_applicator_patternproperties); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "additionalProperties", - compiler_2019_09_applicator_additionalproperties); - - // Same as Draft 7 - - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "if", - compiler_draft7_applicator_if); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "then", - compiler_draft7_applicator_then); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "else", - compiler_draft7_applicator_else); - - // Same as Draft 6 - - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "propertyNames", compiler_draft6_validation_propertynames); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "type", - compiler_draft6_validation_type); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "const", - compiler_draft6_validation_const); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "exclusiveMaximum", compiler_draft6_validation_exclusivemaximum); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "exclusiveMinimum", compiler_draft6_validation_exclusiveminimum); - - // Same as Draft 4 - - // As per compatibility optional test - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", - "dependencies", compiler_draft4_applicator_dependencies); - - COMPILE("https://json-schema.org/draft/2019-09/vocab/core", "$ref", - compiler_draft4_core_ref); - - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "allOf", - compiler_draft4_applicator_allof); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "oneOf", - compiler_draft4_applicator_oneof); - COMPILE("https://json-schema.org/draft/2019-09/vocab/applicator", "not", - compiler_draft4_applicator_not); - - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "enum", - compiler_draft4_validation_enum); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "uniqueItems", compiler_draft4_validation_uniqueitems); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "maxItems", - compiler_draft4_validation_maxitems); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "minItems", - compiler_draft4_validation_minitems); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "required", - compiler_draft4_validation_required); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "maxProperties", compiler_draft4_validation_maxproperties); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "minProperties", compiler_draft4_validation_minproperties); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "maximum", - compiler_draft4_validation_maximum); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "minimum", - compiler_draft4_validation_minimum); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", - "multipleOf", compiler_draft4_validation_multipleof); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "maxLength", - compiler_draft4_validation_maxlength); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "minLength", - compiler_draft4_validation_minlength); - COMPILE("https://json-schema.org/draft/2019-09/vocab/validation", "pattern", - compiler_draft4_validation_pattern); - - // ******************************************** - // DRAFT 7 - // ******************************************** - - COMPILE("http://json-schema.org/draft-07/schema#", "$ref", - compiler_draft4_core_ref); - STOP_IF_SIBLING_KEYWORD("http://json-schema.org/draft-07/schema#", "$ref"); - - // Any - COMPILE("http://json-schema.org/draft-07/schema#", "if", - compiler_draft7_applicator_if); - COMPILE("http://json-schema.org/draft-07/schema#", "then", - compiler_draft7_applicator_then); - COMPILE("http://json-schema.org/draft-07/schema#", "else", - compiler_draft7_applicator_else); - - // Same as Draft 6 - - COMPILE("http://json-schema.org/draft-07/schema#", "type", - compiler_draft6_validation_type); - COMPILE("http://json-schema.org/draft-07/schema#", "const", - compiler_draft6_validation_const); - COMPILE("http://json-schema.org/draft-07/schema#", "contains", - compiler_draft6_applicator_contains); - COMPILE("http://json-schema.org/draft-07/schema#", "propertyNames", - compiler_draft6_validation_propertynames); - COMPILE("http://json-schema.org/draft-07/schema#", "exclusiveMaximum", - compiler_draft6_validation_exclusivemaximum); - COMPILE("http://json-schema.org/draft-07/schema#", "exclusiveMinimum", - compiler_draft6_validation_exclusiveminimum); - - // Same as Draft 4 - - COMPILE("http://json-schema.org/draft-07/schema#", "allOf", - compiler_draft4_applicator_allof); - COMPILE("http://json-schema.org/draft-07/schema#", "anyOf", - compiler_draft4_applicator_anyof); - COMPILE("http://json-schema.org/draft-07/schema#", "oneOf", - compiler_draft4_applicator_oneof); - COMPILE("http://json-schema.org/draft-07/schema#", "not", - compiler_draft4_applicator_not); - COMPILE("http://json-schema.org/draft-07/schema#", "enum", - compiler_draft4_validation_enum); - - COMPILE("http://json-schema.org/draft-07/schema#", "items", - compiler_draft4_applicator_items); - COMPILE("http://json-schema.org/draft-07/schema#", "additionalItems", - compiler_draft4_applicator_additionalitems); - COMPILE("http://json-schema.org/draft-07/schema#", "uniqueItems", - compiler_draft4_validation_uniqueitems); - COMPILE("http://json-schema.org/draft-07/schema#", "maxItems", - compiler_draft4_validation_maxitems); - COMPILE("http://json-schema.org/draft-07/schema#", "minItems", - compiler_draft4_validation_minitems); - - COMPILE("http://json-schema.org/draft-07/schema#", "required", - compiler_draft4_validation_required); - COMPILE("http://json-schema.org/draft-07/schema#", "maxProperties", - compiler_draft4_validation_maxproperties); - COMPILE("http://json-schema.org/draft-07/schema#", "minProperties", - compiler_draft4_validation_minproperties); - COMPILE("http://json-schema.org/draft-07/schema#", "properties", - compiler_draft4_applicator_properties); - COMPILE("http://json-schema.org/draft-07/schema#", "patternProperties", - compiler_draft4_applicator_patternproperties); - COMPILE("http://json-schema.org/draft-07/schema#", "additionalProperties", - compiler_draft4_applicator_additionalproperties); - COMPILE("http://json-schema.org/draft-07/schema#", "dependencies", - compiler_draft4_applicator_dependencies); - - COMPILE("http://json-schema.org/draft-07/schema#", "maximum", - compiler_draft4_validation_maximum); - COMPILE("http://json-schema.org/draft-07/schema#", "minimum", - compiler_draft4_validation_minimum); - COMPILE("http://json-schema.org/draft-07/schema#", "multipleOf", - compiler_draft4_validation_multipleof); - - COMPILE("http://json-schema.org/draft-07/schema#", "maxLength", - compiler_draft4_validation_maxlength); - COMPILE("http://json-schema.org/draft-07/schema#", "minLength", - compiler_draft4_validation_minlength); - COMPILE("http://json-schema.org/draft-07/schema#", "pattern", - compiler_draft4_validation_pattern); - - // ******************************************** - // DRAFT 6 - // ******************************************** - - COMPILE("http://json-schema.org/draft-06/schema#", "$ref", - compiler_draft4_core_ref); - STOP_IF_SIBLING_KEYWORD("http://json-schema.org/draft-06/schema#", "$ref"); - - // Any - COMPILE("http://json-schema.org/draft-06/schema#", "type", - compiler_draft6_validation_type); - COMPILE("http://json-schema.org/draft-06/schema#", "const", - compiler_draft6_validation_const); - - // Array - COMPILE("http://json-schema.org/draft-06/schema#", "contains", - compiler_draft6_applicator_contains); - - // Object - COMPILE("http://json-schema.org/draft-06/schema#", "propertyNames", - compiler_draft6_validation_propertynames); - - // Number - COMPILE("http://json-schema.org/draft-06/schema#", "exclusiveMaximum", - compiler_draft6_validation_exclusivemaximum); - COMPILE("http://json-schema.org/draft-06/schema#", "exclusiveMinimum", - compiler_draft6_validation_exclusiveminimum); - - // Same as Draft 4 - - COMPILE("http://json-schema.org/draft-06/schema#", "allOf", - compiler_draft4_applicator_allof); - COMPILE("http://json-schema.org/draft-06/schema#", "anyOf", - compiler_draft4_applicator_anyof); - COMPILE("http://json-schema.org/draft-06/schema#", "oneOf", - compiler_draft4_applicator_oneof); - COMPILE("http://json-schema.org/draft-06/schema#", "not", - compiler_draft4_applicator_not); - COMPILE("http://json-schema.org/draft-06/schema#", "enum", - compiler_draft4_validation_enum); - - COMPILE("http://json-schema.org/draft-06/schema#", "items", - compiler_draft4_applicator_items); - COMPILE("http://json-schema.org/draft-06/schema#", "additionalItems", - compiler_draft4_applicator_additionalitems); - COMPILE("http://json-schema.org/draft-06/schema#", "uniqueItems", - compiler_draft4_validation_uniqueitems); - COMPILE("http://json-schema.org/draft-06/schema#", "maxItems", - compiler_draft4_validation_maxitems); - COMPILE("http://json-schema.org/draft-06/schema#", "minItems", - compiler_draft4_validation_minitems); - - COMPILE("http://json-schema.org/draft-06/schema#", "required", - compiler_draft4_validation_required); - COMPILE("http://json-schema.org/draft-06/schema#", "maxProperties", - compiler_draft4_validation_maxproperties); - COMPILE("http://json-schema.org/draft-06/schema#", "minProperties", - compiler_draft4_validation_minproperties); - COMPILE("http://json-schema.org/draft-06/schema#", "properties", - compiler_draft4_applicator_properties); - COMPILE("http://json-schema.org/draft-06/schema#", "patternProperties", - compiler_draft4_applicator_patternproperties); - COMPILE("http://json-schema.org/draft-06/schema#", "additionalProperties", - compiler_draft4_applicator_additionalproperties); - COMPILE("http://json-schema.org/draft-06/schema#", "dependencies", - compiler_draft4_applicator_dependencies); - - COMPILE("http://json-schema.org/draft-06/schema#", "maximum", - compiler_draft4_validation_maximum); - COMPILE("http://json-schema.org/draft-06/schema#", "minimum", - compiler_draft4_validation_minimum); - COMPILE("http://json-schema.org/draft-06/schema#", "multipleOf", - compiler_draft4_validation_multipleof); - - COMPILE("http://json-schema.org/draft-06/schema#", "maxLength", - compiler_draft4_validation_maxlength); - COMPILE("http://json-schema.org/draft-06/schema#", "minLength", - compiler_draft4_validation_minlength); - COMPILE("http://json-schema.org/draft-06/schema#", "pattern", - compiler_draft4_validation_pattern); - - // ******************************************** - // DRAFT 4 - // ******************************************** - - COMPILE("http://json-schema.org/draft-04/schema#", "$ref", - compiler_draft4_core_ref); - STOP_IF_SIBLING_KEYWORD("http://json-schema.org/draft-04/schema#", "$ref"); - - // Applicators - COMPILE("http://json-schema.org/draft-04/schema#", "allOf", - compiler_draft4_applicator_allof); - COMPILE("http://json-schema.org/draft-04/schema#", "anyOf", - compiler_draft4_applicator_anyof); - COMPILE("http://json-schema.org/draft-04/schema#", "oneOf", - compiler_draft4_applicator_oneof); - COMPILE("http://json-schema.org/draft-04/schema#", "not", - compiler_draft4_applicator_not); - COMPILE("http://json-schema.org/draft-04/schema#", "properties", - compiler_draft4_applicator_properties); - COMPILE("http://json-schema.org/draft-04/schema#", "patternProperties", - compiler_draft4_applicator_patternproperties); - COMPILE("http://json-schema.org/draft-04/schema#", "additionalProperties", - compiler_draft4_applicator_additionalproperties); - COMPILE("http://json-schema.org/draft-04/schema#", "items", - compiler_draft4_applicator_items); - COMPILE("http://json-schema.org/draft-04/schema#", "additionalItems", - compiler_draft4_applicator_additionalitems); - COMPILE("http://json-schema.org/draft-04/schema#", "dependencies", - compiler_draft4_applicator_dependencies); - - // Any - COMPILE("http://json-schema.org/draft-04/schema#", "type", - compiler_draft4_validation_type); - COMPILE("http://json-schema.org/draft-04/schema#", "enum", - compiler_draft4_validation_enum); - - // Object - COMPILE("http://json-schema.org/draft-04/schema#", "required", - compiler_draft4_validation_required); - COMPILE("http://json-schema.org/draft-04/schema#", "maxProperties", - compiler_draft4_validation_maxproperties); - COMPILE("http://json-schema.org/draft-04/schema#", "minProperties", - compiler_draft4_validation_minproperties); - - // Array - COMPILE("http://json-schema.org/draft-04/schema#", "uniqueItems", - compiler_draft4_validation_uniqueitems); - COMPILE("http://json-schema.org/draft-04/schema#", "maxItems", - compiler_draft4_validation_maxitems); - COMPILE("http://json-schema.org/draft-04/schema#", "minItems", - compiler_draft4_validation_minitems); - - // String - COMPILE("http://json-schema.org/draft-04/schema#", "pattern", - compiler_draft4_validation_pattern); - COMPILE("http://json-schema.org/draft-04/schema#", "maxLength", - compiler_draft4_validation_maxlength); - COMPILE("http://json-schema.org/draft-04/schema#", "minLength", - compiler_draft4_validation_minlength); - COMPILE("http://json-schema.org/draft-04/schema#", "format", - compiler_draft4_validation_format); - - // Number - COMPILE("http://json-schema.org/draft-04/schema#", "maximum", - compiler_draft4_validation_maximum); - COMPILE("http://json-schema.org/draft-04/schema#", "minimum", - compiler_draft4_validation_minimum); - COMPILE("http://json-schema.org/draft-04/schema#", "multipleOf", - compiler_draft4_validation_multipleof); - -#undef COMPILE -#undef STOP_IF_SIBLING_KEYWORD - - if ((schema_context.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/core") || - schema_context.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/core")) && - !dynamic_context.keyword.starts_with('$') && - dynamic_context.keyword != "definitions") { - - // We handle these keywords as part of "contains" - if ((schema_context.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/validation") || - schema_context.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/validation")) && - (dynamic_context.keyword == "minContains" || - dynamic_context.keyword == "maxContains")) { - return {}; - } - - return internal::compiler_2019_09_core_annotation(context, schema_context, - dynamic_context); - } - - return {}; -} diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler_2019_09.h b/vendor/jsontoolkit/src/jsonschema/default_compiler_2019_09.h deleted file mode 100644 index 36c4957b..00000000 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler_2019_09.h +++ /dev/null @@ -1,345 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_2019_09_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_2019_09_H_ - -#include -#include - -#include "compile_helpers.h" -#include "default_compiler_draft4.h" - -namespace internal { -using namespace sourcemeta::jsontoolkit; - -auto compiler_2019_09_applicator_dependentschemas( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_object()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - SchemaCompilerTemplate children; - - // To guarantee order - std::vector dependents; - for (const auto &entry : - schema_context.schema.at(dynamic_context.keyword).as_object()) { - dependents.push_back(entry.first); - } - std::sort(dependents.begin(), dependents.end()); - - for (const auto &dependent : dependents) { - const auto &dependency{ - schema_context.schema.at(dynamic_context.keyword).at(dependent)}; - if (!is_schema(dependency)) { - continue; - } - - if (!dependency.is_boolean() || !dependency.to_boolean()) { - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueString{dependent}, - compile(context, schema_context, relative_dynamic_context, - {dependent}, empty_pointer))); - } - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object, - std::move(children))}; -} - -auto compiler_2019_09_validation_dependentrequired( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (!schema_context.schema.at(dynamic_context.keyword).is_object()) { - return {}; - } - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - SchemaCompilerValueStringMap dependencies; - for (const auto &entry : - schema_context.schema.at(dynamic_context.keyword).as_object()) { - if (!entry.second.is_array()) { - continue; - } - - std::vector properties; - for (const auto &property : entry.second.as_array()) { - assert(property.is_string()); - properties.push_back(property.to_string()); - } - - if (!properties.empty()) { - dependencies.emplace(entry.first, std::move(properties)); - } - } - - if (dependencies.empty()) { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, std::move(dependencies))}; -} - -auto compiler_2019_09_core_annotation( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; -} - -auto compiler_2019_09_applicator_contains_conditional_annotate( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - std::size_t minimum{1}; - if (schema_context.schema.defines("minContains")) { - if (schema_context.schema.at("minContains").is_integer() && - schema_context.schema.at("minContains").is_positive()) { - minimum = static_cast( - schema_context.schema.at("minContains").to_integer()); - } else if (schema_context.schema.at("minContains").is_real() && - schema_context.schema.at("minContains").is_positive()) { - minimum = static_cast( - schema_context.schema.at("minContains").as_integer()); - } - } - - std::optional maximum; - if (schema_context.schema.defines("maxContains")) { - if (schema_context.schema.at("maxContains").is_integer() && - schema_context.schema.at("maxContains").is_positive()) { - maximum = schema_context.schema.at("maxContains").to_integer(); - } else if (schema_context.schema.at("maxContains").is_real() && - schema_context.schema.at("maxContains").is_positive()) { - maximum = schema_context.schema.at("maxContains").as_integer(); - } - } - - if (maximum.has_value() && minimum > maximum.value()) { - return {make(true, context, schema_context, - dynamic_context, - SchemaCompilerValueNone{})}; - } - - if (minimum == 0 && !maximum.has_value()) { - return {}; - } - - SchemaCompilerTemplate children{compile(context, schema_context, - relative_dynamic_context, - empty_pointer, empty_pointer)}; - - if (annotate) { - children.push_back(make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{})); - - // TODO: If after emitting the above annotation, the number of annotations - // for the current schema location + instance location is equal to the - // array size (which means we annotated all of the items), then emit - // an annotation "true" - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueRange{ - minimum, maximum, - // TODO: We only need to be exhaustive here if `unevaluatedItems` is - // in use on the schema. Can we pre-determine that and speed things up - // if not? - annotate}, - std::move(children))}; -} - -auto compiler_2019_09_applicator_contains( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_2019_09_applicator_contains_conditional_annotate( - context, schema_context, dynamic_context, false); -} - -auto compiler_2019_09_applicator_additionalproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_additionalproperties_conditional_annotation( - context, schema_context, dynamic_context, true); -} - -auto compiler_2019_09_applicator_items( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_items_conditional_annotation( - context, schema_context, dynamic_context, true); -} - -auto compiler_2019_09_applicator_additionalitems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_additionalitems_conditional_annotation( - context, schema_context, dynamic_context, true); -} - -auto compiler_2019_09_applicator_unevaluateditems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - SchemaCompilerTemplate children{compile(context, schema_context, - relative_dynamic_context, - empty_pointer, empty_pointer)}; - children.push_back(make( - true, context, schema_context, relative_dynamic_context, JSON{true})); - - if (schema_context.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/applicator")) { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueItemsAnnotationKeywords{ - "items", {}, {"items", "additionalItems", "unevaluatedItems"}}, - std::move(children))}; - } else if (schema_context.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/applicator")) { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueItemsAnnotationKeywords{ - "prefixItems", - {"contains"}, - {"prefixItems", "items", "contains", "unevaluatedItems"}}, - std::move(children))}; - } else { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueStrings{"unevaluatedItems"}, std::move(children))}; - } -} - -auto compiler_2019_09_applicator_unevaluatedproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - SchemaCompilerValueStrings dependencies{"unevaluatedProperties"}; - - if (schema_context.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/applicator")) { - dependencies.push_back("properties"); - dependencies.push_back("patternProperties"); - dependencies.push_back("additionalProperties"); - } - - if (schema_context.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/applicator")) { - dependencies.push_back("properties"); - dependencies.push_back("patternProperties"); - dependencies.push_back("additionalProperties"); - } - - SchemaCompilerTemplate children{compile(context, schema_context, - relative_dynamic_context, - empty_pointer, empty_pointer)}; - children.push_back(make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{})); - - return {make( - true, context, schema_context, dynamic_context, std::move(dependencies), - std::move(children))}; -} - -auto compiler_2019_09_core_recursiveref( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - const auto current{ - to_uri(schema_context.relative_pointer, schema_context.base).recompose()}; - assert(context.frame.contains({ReferenceType::Static, current})); - const auto &entry{context.frame.at({ReferenceType::Static, current})}; - // In this case, just behave as a normal static reference - if (!context.references.contains({ReferenceType::Dynamic, entry.pointer})) { - return compiler_draft4_core_ref(context, schema_context, dynamic_context); - } - - return {make( - true, context, schema_context, dynamic_context, "")}; -} - -auto compiler_2019_09_applicator_anyof( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_anyof_conditional_exhaustive( - context, schema_context, dynamic_context, - // TODO: This set to true means that every disjunction of `anyOf` - // is always evaluated. In fact, we only need to enable this if - // the schema makes any use of `unevaluatedItems` or - // `unevaluatedProperties` - true); -} - -auto compiler_2019_09_applicator_properties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_properties_conditional_annotation( - context, schema_context, dynamic_context, true); -} - -auto compiler_2019_09_applicator_patternproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_patternproperties_conditional_annotation( - context, schema_context, dynamic_context, true); -} - -} // namespace internal -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler_2020_12.h b/vendor/jsontoolkit/src/jsonschema/default_compiler_2020_12.h deleted file mode 100644 index 8d184028..00000000 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler_2020_12.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_2020_12_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_2020_12_H_ - -#include -#include -#include - -#include "compile_helpers.h" -#include "default_compiler_draft4.h" - -namespace internal { -using namespace sourcemeta::jsontoolkit; - -auto compiler_2020_12_applicator_prefixitems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_items_array(context, schema_context, - dynamic_context, true); -} - -auto compiler_2020_12_applicator_items( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - const auto cursor{(schema_context.schema.defines("prefixItems") && - schema_context.schema.at("prefixItems").is_array()) - ? schema_context.schema.at("prefixItems").size() - : 0}; - - return compiler_draft4_applicator_additionalitems_from_cursor( - context, schema_context, dynamic_context, cursor, true); -} - -auto compiler_2020_12_applicator_contains( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_2019_09_applicator_contains_conditional_annotate( - context, schema_context, dynamic_context, true); -} - -auto compiler_2020_12_core_dynamicref( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - const auto current{ - to_uri(schema_context.relative_pointer, schema_context.base).recompose()}; - assert(context.frame.contains({ReferenceType::Static, current})); - const auto &entry{context.frame.at({ReferenceType::Static, current})}; - // In this case, just behave as a normal static reference - if (!context.references.contains({ReferenceType::Dynamic, entry.pointer})) { - return compiler_draft4_core_ref(context, schema_context, dynamic_context); - } - - assert(schema_context.schema.at(dynamic_context.keyword).is_string()); - URI reference{schema_context.schema.at(dynamic_context.keyword).to_string()}; - reference.resolve_from_if_absolute(schema_context.base); - reference.canonicalize(); - // We handle the non-anchor variant by not treating it as a dynamic reference - assert(reference.fragment().has_value()); - - // Note we don't need to even care about the static part of the dynamic - // reference (if any), as even if we jump first there, we will still - // look for the oldest dynamic anchor in the schema resource chain. - return {make( - true, context, schema_context, dynamic_context, - std::string{reference.fragment().value()})}; -} - -} // namespace internal -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft4.h b/vendor/jsontoolkit/src/jsonschema/default_compiler_draft4.h deleted file mode 100644 index df2c31da..00000000 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft4.h +++ /dev/null @@ -1,1364 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_DRAFT4_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_DRAFT4_H_ - -#include -#include - -#include // std::sort, std::any_of -#include // assert -#include // std::regex, std::regex_error -#include // std::set -#include // std::ostringstream -#include // std::move - -#include "compile_helpers.h" - -static auto parse_regex(const std::string &pattern, - const sourcemeta::jsontoolkit::URI &base, - const sourcemeta::jsontoolkit::Pointer &schema_location) - -> std::regex { - try { - return std::regex{pattern, std::regex::ECMAScript | std::regex::nosubs}; - } catch (const std::regex_error &) { - std::ostringstream message; - message << "Invalid regular expression: " << pattern; - throw sourcemeta::jsontoolkit::SchemaCompilationError(base, schema_location, - message.str()); - } -} - -namespace internal { -using namespace sourcemeta::jsontoolkit; - -auto compiler_draft4_core_ref( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - // Determine the label - const auto type{ReferenceType::Static}; - const auto current{ - to_uri(schema_context.relative_pointer, schema_context.base).recompose()}; - assert(context.frame.contains({type, current})); - const auto &entry{context.frame.at({type, current})}; - if (!context.references.contains({type, entry.pointer})) { - assert(schema_context.schema.at(dynamic_context.keyword).is_string()); - throw SchemaReferenceError( - schema_context.schema.at(dynamic_context.keyword).to_string(), - entry.pointer, "The schema location is inside of an unknown keyword"); - } - - const auto &reference{context.references.at({type, entry.pointer})}; - const auto label{std::hash{}(reference.destination)}; - - // The label is already registered, so just jump to it - if (schema_context.labels.contains(label)) { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{label})}; - } - - auto new_schema_context{schema_context}; - new_schema_context.references.insert(reference.destination); - - std::size_t direct_children_references{0}; - if (context.frame.contains({type, reference.destination})) { - for (const auto &reference_entry : context.references) { - if (reference_entry.first.second.starts_with( - context.frame.at({type, reference.destination}).pointer)) { - direct_children_references += 1; - } - } - } - - // If the reference is not a recursive one, we can avoid the extra - // overhead of marking the location for future jumps, and pretty much - // just expand the reference destination in place. - const bool is_recursive{ - // This means the reference is directly recursive, by jumping to - // a parent of the reference itself. - (context.frame.contains({type, reference.destination}) && - entry.pointer.starts_with( - context.frame.at({type, reference.destination}).pointer)) || - schema_context.references.contains(reference.destination)}; - - if (!is_recursive && direct_children_references <= 5) { - // TODO: Enable this optimization for 2019-09 on-wards - if (schema_context.vocabularies.contains( - "http://json-schema.org/draft-04/schema#") || - schema_context.vocabularies.contains( - "http://json-schema.org/draft-06/schema#") || - schema_context.vocabularies.contains( - "http://json-schema.org/draft-07/schema#")) { - return compile(context, new_schema_context, dynamic_context, - empty_pointer, empty_pointer, reference.destination); - } else { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueNone{}, - compile(context, new_schema_context, relative_dynamic_context, - empty_pointer, empty_pointer, reference.destination))}; - } - } - - // The idea to handle recursion is to expand the reference once, and when - // doing so, create a "checkpoint" that we can jump back to in a subsequent - // recursive reference. While unrolling the reference once may initially - // feel weird, we do it so we can handle references purely in this keyword - // handler, without having to add logic to every single keyword to check - // whether something points to them and add the "checkpoint" themselves. - new_schema_context.labels.insert(label); - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{label}, - compile(context, new_schema_context, relative_dynamic_context, - empty_pointer, empty_pointer, reference.destination))}; -} - -auto compiler_draft4_validation_type( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.at(dynamic_context.keyword).is_string()) { - const auto &type{ - schema_context.schema.at(dynamic_context.keyword).to_string()}; - if (type == "null") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Null)}; - } else if (type == "boolean") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Boolean)}; - } else if (type == "object") { - const auto minimum{ - unsigned_integer_property(schema_context.schema, "minProperties", 0)}; - const auto maximum{ - unsigned_integer_property(schema_context.schema, "maxProperties")}; - if (minimum > 0 || maximum.has_value()) { - return {make( - true, context, schema_context, dynamic_context, - {minimum, maximum, false})}; - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object)}; - } else if (type == "array") { - const auto minimum{ - unsigned_integer_property(schema_context.schema, "minItems", 0)}; - const auto maximum{ - unsigned_integer_property(schema_context.schema, "maxItems")}; - if (minimum > 0 || maximum.has_value()) { - return {make( - true, context, schema_context, dynamic_context, - {minimum, maximum, false})}; - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Array)}; - } else if (type == "number") { - return {make( - true, context, schema_context, dynamic_context, - std::vector{JSON::Type::Real, JSON::Type::Integer})}; - } else if (type == "integer") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Integer)}; - } else if (type == "string") { - const auto minimum{ - unsigned_integer_property(schema_context.schema, "minLength", 0)}; - const auto maximum{ - unsigned_integer_property(schema_context.schema, "maxLength")}; - if (minimum > 0 || maximum.has_value()) { - return {make( - true, context, schema_context, dynamic_context, - {minimum, maximum, false})}; - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::String)}; - } else { - return {}; - } - } else if (schema_context.schema.at(dynamic_context.keyword).is_array() && - schema_context.schema.at(dynamic_context.keyword).size() == 1 && - schema_context.schema.at(dynamic_context.keyword) - .front() - .is_string()) { - const auto &type{ - schema_context.schema.at(dynamic_context.keyword).front().to_string()}; - if (type == "null") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Null)}; - } else if (type == "boolean") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Boolean)}; - } else if (type == "object") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object)}; - } else if (type == "array") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Array)}; - } else if (type == "number") { - return {make( - true, context, schema_context, dynamic_context, - std::vector{JSON::Type::Real, JSON::Type::Integer})}; - } else if (type == "integer") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Integer)}; - } else if (type == "string") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::String)}; - } else { - return {}; - } - } else if (schema_context.schema.at(dynamic_context.keyword).is_array()) { - std::vector types; - for (const auto &type : - schema_context.schema.at(dynamic_context.keyword).as_array()) { - assert(type.is_string()); - const auto &type_string{type.to_string()}; - if (type_string == "null") { - types.push_back(JSON::Type::Null); - } else if (type_string == "boolean") { - types.push_back(JSON::Type::Boolean); - } else if (type_string == "object") { - types.push_back(JSON::Type::Object); - } else if (type_string == "array") { - types.push_back(JSON::Type::Array); - } else if (type_string == "number") { - types.push_back(JSON::Type::Integer); - types.push_back(JSON::Type::Real); - } else if (type_string == "integer") { - types.push_back(JSON::Type::Integer); - } else if (type_string == "string") { - types.push_back(JSON::Type::String); - } - } - - assert(types.size() >= - schema_context.schema.at(dynamic_context.keyword).size()); - return {make( - true, context, schema_context, dynamic_context, std::move(types))}; - } - - return {}; -} - -auto compiler_draft4_validation_required( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_array()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - if (schema_context.schema.at(dynamic_context.keyword).empty()) { - return {}; - } else if (schema_context.schema.at(dynamic_context.keyword).size() > 1) { - std::vector properties; - for (const auto &property : - schema_context.schema.at(dynamic_context.keyword).as_array()) { - assert(property.is_string()); - properties.push_back(property.to_string()); - } - - if (properties.size() == 1) { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueString{*(properties.cbegin())})}; - } else { - return {make( - true, context, schema_context, dynamic_context, - std::move(properties))}; - } - } else { - assert( - schema_context.schema.at(dynamic_context.keyword).front().is_string()); - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueString{ - schema_context.schema.at(dynamic_context.keyword) - .front() - .to_string()})}; - } -} - -auto compiler_draft4_applicator_allof( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_array()); - assert(!schema_context.schema.at(dynamic_context.keyword).empty()); - - SchemaCompilerTemplate children; - for (std::uint64_t index = 0; - index < schema_context.schema.at(dynamic_context.keyword).size(); - index++) { - for (auto &&step : - compile(context, schema_context, relative_dynamic_context, - {static_cast(index)})) { - children.push_back(std::move(step)); - } - } - - return {make( - true, context, schema_context, dynamic_context, SchemaCompilerValueNone{}, - std::move(children))}; -} - -auto compiler_draft4_applicator_anyof_conditional_exhaustive( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool exhaustive) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_array()); - assert(!schema_context.schema.at(dynamic_context.keyword).empty()); - - SchemaCompilerTemplate disjunctors; - for (std::uint64_t index = 0; - index < schema_context.schema.at(dynamic_context.keyword).size(); - index++) { - disjunctors.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{}, - compile(context, schema_context, relative_dynamic_context, - {static_cast(index)}))); - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueBoolean{exhaustive}, std::move(disjunctors))}; -} - -auto compiler_draft4_applicator_anyof( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_anyof_conditional_exhaustive( - context, schema_context, dynamic_context, false); -} - -auto compiler_draft4_applicator_oneof( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_array()); - assert(!schema_context.schema.at(dynamic_context.keyword).empty()); - - SchemaCompilerTemplate disjunctors; - for (std::uint64_t index = 0; - index < schema_context.schema.at(dynamic_context.keyword).size(); - index++) { - disjunctors.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{}, - compile(context, schema_context, relative_dynamic_context, - {static_cast(index)}))); - } - - return {make( - true, context, schema_context, dynamic_context, SchemaCompilerValueNone{}, - std::move(disjunctors))}; -} - -auto compiler_draft4_applicator_properties_conditional_annotation( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_object()); - if (schema_context.schema.at(dynamic_context.keyword).empty()) { - return {}; - } - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - const auto size{schema_context.schema.at(dynamic_context.keyword).size()}; - const auto imports_validation_vocabulary = - schema_context.vocabularies.contains( - "http://json-schema.org/draft-04/schema#") || - schema_context.vocabularies.contains( - "http://json-schema.org/draft-06/schema#") || - schema_context.vocabularies.contains( - "http://json-schema.org/draft-07/schema#") || - schema_context.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/validation") || - schema_context.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/validation"); - std::set required; - if (imports_validation_vocabulary && - schema_context.schema.defines("required") && - schema_context.schema.at("required").is_array()) { - for (const auto &property : - schema_context.schema.at("required").as_array()) { - if (property.is_string() && - // Only count the required property if its indeed in "properties" - schema_context.schema.at(dynamic_context.keyword) - .defines(property.to_string())) { - required.insert(property.to_string()); - } - } - } - - std::size_t is_required = 0; - std::vector> properties; - for (const auto &entry : - schema_context.schema.at(dynamic_context.keyword).as_object()) { - properties.push_back( - {entry.first, compile(context, schema_context, relative_dynamic_context, - {entry.first}, {entry.first})}); - if (required.contains(entry.first)) { - is_required += 1; - } - } - - // In many cases, `properties` have some subschemas that are small - // and some subschemas that are large. To attempt to improve performance, - // we prefer to evaluate smaller subschemas first, in the hope of failing - // earlier without spending a lot of time on other subschemas - std::sort(properties.begin(), properties.end(), - [](const auto &left, const auto &right) { - return (left.second.size() == right.second.size()) - ? (left.first < right.first) - : (left.second.size() < right.second.size()); - }); - - assert(schema_context.relative_pointer.back().is_property()); - assert(schema_context.relative_pointer.back().to_property() == - dynamic_context.keyword); - const auto relative_pointer_size{schema_context.relative_pointer.size()}; - const auto is_directly_inside_oneof{ - relative_pointer_size > 2 && - schema_context.relative_pointer.at(relative_pointer_size - 2) - .is_index() && - schema_context.relative_pointer.at(relative_pointer_size - 3) - .is_property() && - schema_context.relative_pointer.at(relative_pointer_size - 3) - .to_property() == "oneOf"}; - - // There are two ways to compile `properties` depending on whether - // most of the properties are marked as required using `required` - // or whether most of the properties are optional. Each shines - // in the corresponding case. - const auto prefer_loop_over_instance{ - // This strategy only makes sense if most of the properties are "optional" - is_required <= (size / 2) && - // If `properties` only defines a relatively small amount of properties, - // then its probably still faster to unroll - schema_context.schema.at(dynamic_context.keyword).size() > 5 && - // Always unroll inside `oneOf`, to have a better chance at - // short-circuiting quickly - !is_directly_inside_oneof}; - - if (prefer_loop_over_instance) { - SchemaCompilerValueNamedIndexes indexes; - SchemaCompilerTemplate children; - std::size_t cursor = 0; - - for (auto &&[name, substeps] : properties) { - indexes.emplace(name, cursor); - if (annotate) { - substeps.push_back(make( - true, context, schema_context, relative_dynamic_context, - JSON{name})); - } - - // Note that the evaluator completely ignores this wrapper anyway - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{}, std::move(substeps))); - cursor += 1; - } - - return {make( - true, context, schema_context, dynamic_context, std::move(indexes), - std::move(children))}; - } - - SchemaCompilerTemplate children; - - for (auto &&[name, substeps] : properties) { - if (annotate) { - substeps.push_back(make( - true, context, schema_context, relative_dynamic_context, JSON{name})); - } - - const auto assume_object{imports_validation_vocabulary && - schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == - "object"}; - - // We can avoid this "defines" condition if the property is a required one - if (imports_validation_vocabulary && assume_object && - schema_context.schema.defines("required") && - schema_context.schema.at("required").is_array() && - schema_context.schema.at("required").contains(JSON{name})) { - // We can avoid the container too and just inline these steps - for (auto &&substep : substeps) { - children.push_back(std::move(substep)); - } - - // Optimize `properties` where its subschemas just include a type check, - // as that's a very common pattern - - } else if (substeps.size() == 1 && - std::holds_alternative( - substeps.front())) { - const auto &type_step{ - std::get(substeps.front())}; - children.push_back(SchemaCompilerAssertionPropertyTypeStrict{ - type_step.relative_schema_location, - dynamic_context.base_instance_location.concat( - type_step.relative_instance_location), - type_step.keyword_location, type_step.schema_resource, - type_step.dynamic, type_step.report, type_step.value}); - } else if (substeps.size() == 1 && - std::holds_alternative( - substeps.front())) { - const auto &type_step{ - std::get(substeps.front())}; - children.push_back(SchemaCompilerAssertionPropertyType{ - type_step.relative_schema_location, - dynamic_context.base_instance_location.concat( - type_step.relative_instance_location), - type_step.keyword_location, type_step.schema_resource, - type_step.dynamic, type_step.report, type_step.value}); - } else if (substeps.size() == 1 && - std::holds_alternative< - SchemaCompilerAssertionPropertyTypeStrict>( - substeps.front())) { - children.push_back(unroll( - relative_dynamic_context, substeps.front(), - dynamic_context.base_instance_location)); - } else if (substeps.size() == 1 && - std::holds_alternative( - substeps.front())) { - children.push_back(unroll( - relative_dynamic_context, substeps.front(), - dynamic_context.base_instance_location)); - - } else { - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueString{name}, std::move(substeps))); - } - } - - // Optimize away the wrapper when emitting a single instruction - if (children.size() == 1 && - std::holds_alternative( - children.front())) { - return {unroll( - dynamic_context, children.front())}; - } - - return {make( - true, context, schema_context, dynamic_context, SchemaCompilerValueNone{}, - std::move(children))}; -} - -auto compiler_draft4_applicator_properties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_properties_conditional_annotation( - context, schema_context, dynamic_context, false); -} - -auto compiler_draft4_applicator_patternproperties_conditional_annotation( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_object()); - if (schema_context.schema.at(dynamic_context.keyword).empty()) { - return {}; - } - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - SchemaCompilerTemplate children; - - // To guarantee ordering - std::vector patterns; - for (auto &entry : - schema_context.schema.at(dynamic_context.keyword).as_object()) { - patterns.push_back(entry.first); - } - - std::sort(patterns.begin(), patterns.end()); - - // For each regular expression and corresponding subschema in the object - for (const auto &pattern : patterns) { - auto substeps{compile(context, schema_context, relative_dynamic_context, - {pattern}, {})}; - - if (annotate) { - // The evaluator will make sure the same annotation is not reported twice. - // For example, if the same property matches more than one subschema in - // `patternProperties` - substeps.push_back(make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{})); - } - - // If the `patternProperties` subschema for the given pattern does - // nothing, then we can avoid generating an entire loop for it - if (!substeps.empty()) { - // Loop over the instance properties - children.push_back(make( - // Treat this as an internal step - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueRegex{parse_regex(pattern, schema_context.base, - schema_context.relative_pointer), - pattern}, - std::move(substeps))); - } - } - - if (children.empty()) { - return {}; - } - - // If the instance is an object... - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object, - std::move(children))}; -} - -auto compiler_draft4_applicator_patternproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_patternproperties_conditional_annotation( - context, schema_context, dynamic_context, false); -} - -auto compiler_draft4_applicator_additionalproperties_conditional_annotation( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - SchemaCompilerTemplate children{compile(context, schema_context, - relative_dynamic_context, - empty_pointer, empty_pointer)}; - - if (annotate) { - children.push_back(make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueNone{})); - } - - SchemaCompilerValuePropertyFilter filter; - - if (schema_context.schema.defines("properties") && - schema_context.schema.at("properties").is_object()) { - for (const auto &entry : - schema_context.schema.at("properties").as_object()) { - filter.first.insert(entry.first); - } - } - - if (schema_context.schema.defines("patternProperties") && - schema_context.schema.at("patternProperties").is_object()) { - for (const auto &entry : - schema_context.schema.at("patternProperties").as_object()) { - filter.second.push_back( - {parse_regex(entry.first, schema_context.base, - schema_context.relative_pointer.initial().concat( - {"patternProperties"})), - entry.first}); - } - } - - if (!filter.first.empty() || !filter.second.empty()) { - return {make( - true, context, schema_context, dynamic_context, std::move(filter), - std::move(children))}; - } else { - if (children.size() == 1) { - // Optimize `additionalProperties` set to just `type`, which is a - // pretty common pattern - if (std::holds_alternative( - children.front())) { - const auto &type_step{ - std::get(children.front())}; - return {make( - true, context, schema_context, dynamic_context, type_step.value)}; - } else if (std::holds_alternative( - children.front())) { - const auto &type_step{ - std::get(children.front())}; - return {make( - true, context, schema_context, dynamic_context, type_step.value)}; - } - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueNone{}, std::move(children))}; - } -} - -auto compiler_draft4_applicator_additionalproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_additionalproperties_conditional_annotation( - context, schema_context, dynamic_context, false); -} - -auto compiler_draft4_validation_pattern( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_string()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "string") { - return {}; - } - - const auto ®ex_string{ - schema_context.schema.at(dynamic_context.keyword).to_string()}; - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueRegex{parse_regex(regex_string, schema_context.base, - schema_context.relative_pointer), - regex_string})}; -} - -auto compiler_draft4_validation_format( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (!schema_context.schema.at(dynamic_context.keyword).is_string()) { - return {}; - } - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "string") { - return {}; - } - - // Regular expressions - - static const std::string FORMAT_REGEX_IPV4{ - "^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-" - "9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-" - "9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"}; - - const auto &format{ - schema_context.schema.at(dynamic_context.keyword).to_string()}; - - if (format == "uri") { - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueStringType::URI)}; - } - -#define COMPILE_FORMAT_REGEX(name, regular_expression) \ - if (format == (name)) { \ - return {make( \ - true, context, schema_context, dynamic_context, \ - SchemaCompilerValueRegex{parse_regex(regular_expression, \ - schema_context.base, \ - schema_context.relative_pointer), \ - (regular_expression)})}; \ - } - - COMPILE_FORMAT_REGEX("ipv4", FORMAT_REGEX_IPV4) - -#undef COMPILE_FORMAT_REGEX - - return {}; -} - -auto compiler_draft4_applicator_not( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return {make( - true, context, schema_context, dynamic_context, SchemaCompilerValueNone{}, - compile(context, schema_context, relative_dynamic_context, empty_pointer, - empty_pointer))}; -} - -auto compiler_draft4_applicator_items_array( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_array()); - const auto items_size{ - schema_context.schema.at(dynamic_context.keyword).size()}; - if (items_size == 0) { - return {}; - } - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - // The idea here is to precompile all possibilities depending on the size - // of the instance array up to the size of the `items` keyword array. - // For example, if `items` is set to `[ {}, {}, {} ]`, we create 3 - // conjunctions: - // - [ {}, {}, {} ] if the instance array size is >= 3 - // - [ {}, {} ] if the instance array size is == 2 - // - [ {} ] if the instance array size is == 1 - - // Precompile subschemas - std::vector subschemas; - subschemas.reserve(items_size); - const auto &array{ - schema_context.schema.at(dynamic_context.keyword).as_array()}; - for (auto iterator{array.cbegin()}; iterator != array.cend(); ++iterator) { - subschemas.push_back(compile(context, schema_context, - relative_dynamic_context, {subschemas.size()}, - {subschemas.size()})); - } - - SchemaCompilerTemplate children; - for (std::size_t cursor = items_size; cursor > 0; cursor--) { - SchemaCompilerTemplate subchildren; - for (std::size_t index = 0; index < cursor; index++) { - for (const auto &substep : subschemas.at(index)) { - subchildren.push_back(substep); - } - } - - // The first entry - if (cursor == items_size) { - if (annotate) { - subchildren.push_back(make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueIndexedJSON{cursor, JSON{true}})); - subchildren.push_back( - make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueIndexedJSON{cursor, JSON{cursor - 1}})); - } - - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueUnsignedInteger{cursor - 1}, - std::move(subchildren))); - } else { - if (annotate) { - subchildren.push_back(make( - true, context, schema_context, relative_dynamic_context, - JSON{cursor - 1})); - } - - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueUnsignedInteger{cursor}, std::move(subchildren))); - } - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Array, - std::move(children))}; -} - -auto compiler_draft4_applicator_items_conditional_annotation( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - if (is_schema(schema_context.schema.at(dynamic_context.keyword))) { - if (annotate) { - SchemaCompilerTemplate children; - children.push_back(make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueUnsignedInteger{0}, - compile(context, schema_context, relative_dynamic_context, - empty_pointer, empty_pointer))); - children.push_back(make( - true, context, schema_context, relative_dynamic_context, JSON{true})); - - return {make( - false, context, schema_context, dynamic_context, JSON::Type::Array, - std::move(children))}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{0}, - compile(context, schema_context, relative_dynamic_context, - empty_pointer, empty_pointer))}; - } - - return compiler_draft4_applicator_items_array(context, schema_context, - dynamic_context, annotate); -} - -auto compiler_draft4_applicator_items( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_items_conditional_annotation( - context, schema_context, dynamic_context, false); -} - -auto compiler_draft4_applicator_additionalitems_from_cursor( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, - const std::size_t cursor, const bool annotate) -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - SchemaCompilerTemplate children{make( - true, context, schema_context, relative_dynamic_context, - SchemaCompilerValueUnsignedInteger{cursor}, - compile(context, schema_context, relative_dynamic_context, empty_pointer, - empty_pointer))}; - - if (annotate) { - children.push_back(make( - true, context, schema_context, relative_dynamic_context, JSON{true})); - } - - return {make( - false, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{cursor}, std::move(children))}; -} - -auto compiler_draft4_applicator_additionalitems_conditional_annotation( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, const bool annotate) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - assert(schema_context.schema.is_object()); - - // Nothing to do here - if (!schema_context.schema.defines("items") || - schema_context.schema.at("items").is_object()) { - return {}; - } - - const auto cursor{(schema_context.schema.defines("items") && - schema_context.schema.at("items").is_array()) - ? schema_context.schema.at("items").size() - : 0}; - - return compiler_draft4_applicator_additionalitems_from_cursor( - context, schema_context, dynamic_context, cursor, annotate); -} - -auto compiler_draft4_applicator_additionalitems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return compiler_draft4_applicator_additionalitems_conditional_annotation( - context, schema_context, dynamic_context, false); -} - -auto compiler_draft4_applicator_dependencies( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - assert(schema_context.schema.at(dynamic_context.keyword).is_object()); - SchemaCompilerTemplate children; - SchemaCompilerValueStringMap dependencies; - - for (const auto &entry : - schema_context.schema.at(dynamic_context.keyword).as_object()) { - if (is_schema(entry.second)) { - if (!entry.second.is_boolean() || !entry.second.to_boolean()) { - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - SchemaCompilerValueString{entry.first}, - compile(context, schema_context, relative_dynamic_context, - {entry.first}, empty_pointer))); - } - } else if (entry.second.is_array()) { - std::vector properties; - for (const auto &property : entry.second.as_array()) { - assert(property.is_string()); - properties.push_back(property.to_string()); - } - - if (!properties.empty()) { - dependencies.emplace(entry.first, std::move(properties)); - } - } - } - - if (!dependencies.empty()) { - children.push_back(make( - false, context, schema_context, relative_dynamic_context, - std::move(dependencies))); - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object, - std::move(children))}; -} - -auto compiler_draft4_validation_enum( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_array()); - - if (schema_context.schema.at(dynamic_context.keyword).size() == 1) { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword).front()})}; - } - - std::vector options; - for (const auto &option : - schema_context.schema.at(dynamic_context.keyword).as_array()) { - options.push_back(option); - } - - return {make( - true, context, schema_context, dynamic_context, std::move(options))}; -} - -auto compiler_draft4_validation_uniqueitems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (!schema_context.schema.at(dynamic_context.keyword).is_boolean() || - !schema_context.schema.at(dynamic_context.keyword).to_boolean()) { - return {}; - } - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - return {make(true, context, schema_context, - dynamic_context, - SchemaCompilerValueNone{})}; -} - -auto compiler_draft4_validation_maxlength( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_integer() || - schema_context.schema.at(dynamic_context.keyword).is_integer_real()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "string") { - return {}; - } - - // We'll handle it at the type level as an optimization - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == "string") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{ - static_cast( - schema_context.schema.at(dynamic_context.keyword).as_integer()) + - 1})}; -} - -auto compiler_draft4_validation_minlength( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_integer() || - schema_context.schema.at(dynamic_context.keyword).is_integer_real()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "string") { - return {}; - } - - // We'll handle it at the type level as an optimization - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == "string") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{ - static_cast( - schema_context.schema.at(dynamic_context.keyword).as_integer()) - - 1})}; -} - -auto compiler_draft4_validation_maxitems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_integer() || - schema_context.schema.at(dynamic_context.keyword).is_integer_real()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - // We'll handle it at the type level as an optimization - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == "array") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{ - static_cast( - schema_context.schema.at(dynamic_context.keyword).as_integer()) + - 1})}; -} - -auto compiler_draft4_validation_minitems( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_integer() || - schema_context.schema.at(dynamic_context.keyword).is_integer_real()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - // We'll handle it at the type level as an optimization - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == "array") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{ - static_cast( - schema_context.schema.at(dynamic_context.keyword).as_integer()) - - 1})}; -} - -auto compiler_draft4_validation_maxproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_integer() || - schema_context.schema.at(dynamic_context.keyword).is_integer_real()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - // We'll handle it at the type level as an optimization - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == "object") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{ - static_cast( - schema_context.schema.at(dynamic_context.keyword).as_integer()) + - 1})}; -} - -auto compiler_draft4_validation_minproperties( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_integer() || - schema_context.schema.at(dynamic_context.keyword).is_integer_real()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "object") { - return {}; - } - - // We'll handle it at the type level as an optimization - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() == "object") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueUnsignedInteger{ - static_cast( - schema_context.schema.at(dynamic_context.keyword).as_integer()) - - 1})}; -} - -auto compiler_draft4_validation_maximum( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_number()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "integer" && - schema_context.schema.at("type").to_string() != "number") { - return {}; - } - - // TODO: As an optimization, if `minimum` is set to the same number, do - // a single equality assertion - - assert(schema_context.schema.is_object()); - if (schema_context.schema.defines("exclusiveMaximum") && - schema_context.schema.at("exclusiveMaximum").is_boolean() && - schema_context.schema.at("exclusiveMaximum").to_boolean()) { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; - } else { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; - } -} - -auto compiler_draft4_validation_minimum( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_number()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "integer" && - schema_context.schema.at("type").to_string() != "number") { - return {}; - } - - // TODO: As an optimization, if `maximum` is set to the same number, do - // a single equality assertion - - assert(schema_context.schema.is_object()); - if (schema_context.schema.defines("exclusiveMinimum") && - schema_context.schema.at("exclusiveMinimum").is_boolean() && - schema_context.schema.at("exclusiveMinimum").to_boolean()) { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; - } else { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; - } -} - -auto compiler_draft4_validation_multipleof( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_number()); - assert(schema_context.schema.at(dynamic_context.keyword).is_positive()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "integer" && - schema_context.schema.at("type").to_string() != "number") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; -} - -} // namespace internal -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h b/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h deleted file mode 100644 index 977202cd..00000000 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h +++ /dev/null @@ -1,224 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_DRAFT6_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_DRAFT6_H_ - -#include -#include - -#include "compile_helpers.h" - -namespace internal { -using namespace sourcemeta::jsontoolkit; - -auto compiler_draft6_validation_type( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.at(dynamic_context.keyword).is_string()) { - const auto &type{ - schema_context.schema.at(dynamic_context.keyword).to_string()}; - if (type == "null") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Null)}; - } else if (type == "boolean") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Boolean)}; - } else if (type == "object") { - const auto minimum{ - unsigned_integer_property(schema_context.schema, "minProperties", 0)}; - const auto maximum{ - unsigned_integer_property(schema_context.schema, "maxProperties")}; - if (minimum > 0 || maximum.has_value()) { - return {make( - true, context, schema_context, dynamic_context, - {minimum, maximum, false})}; - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object)}; - } else if (type == "array") { - const auto minimum{ - unsigned_integer_property(schema_context.schema, "minItems", 0)}; - const auto maximum{ - unsigned_integer_property(schema_context.schema, "maxItems")}; - if (minimum > 0 || maximum.has_value()) { - return {make( - true, context, schema_context, dynamic_context, - {minimum, maximum, false})}; - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Array)}; - } else if (type == "number") { - return {make( - true, context, schema_context, dynamic_context, - std::vector{JSON::Type::Real, JSON::Type::Integer})}; - } else if (type == "integer") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Integer)}; - } else if (type == "string") { - const auto minimum{ - unsigned_integer_property(schema_context.schema, "minLength", 0)}; - const auto maximum{ - unsigned_integer_property(schema_context.schema, "maxLength")}; - if (minimum > 0 || maximum.has_value()) { - return {make( - true, context, schema_context, dynamic_context, - {minimum, maximum, false})}; - } - - return {make( - true, context, schema_context, dynamic_context, JSON::Type::String)}; - } else { - return {}; - } - } else if (schema_context.schema.at(dynamic_context.keyword).is_array() && - schema_context.schema.at(dynamic_context.keyword).size() == 1 && - schema_context.schema.at(dynamic_context.keyword) - .front() - .is_string()) { - const auto &type{ - schema_context.schema.at(dynamic_context.keyword).front().to_string()}; - if (type == "null") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Null)}; - } else if (type == "boolean") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Boolean)}; - } else if (type == "object") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Object)}; - } else if (type == "array") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Array)}; - } else if (type == "number") { - return {make( - true, context, schema_context, dynamic_context, - std::vector{JSON::Type::Real, JSON::Type::Integer})}; - } else if (type == "integer") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::Integer)}; - } else if (type == "string") { - return {make( - true, context, schema_context, dynamic_context, JSON::Type::String)}; - } else { - return {}; - } - } else if (schema_context.schema.at(dynamic_context.keyword).is_array()) { - std::vector types; - for (const auto &type : - schema_context.schema.at(dynamic_context.keyword).as_array()) { - assert(type.is_string()); - const auto &type_string{type.to_string()}; - if (type_string == "null") { - types.push_back(JSON::Type::Null); - } else if (type_string == "boolean") { - types.push_back(JSON::Type::Boolean); - } else if (type_string == "object") { - types.push_back(JSON::Type::Object); - } else if (type_string == "array") { - types.push_back(JSON::Type::Array); - } else if (type_string == "number") { - types.push_back(JSON::Type::Integer); - types.push_back(JSON::Type::Real); - } else if (type_string == "integer") { - types.push_back(JSON::Type::Integer); - } else if (type_string == "string") { - types.push_back(JSON::Type::String); - } - } - - assert(types.size() >= - schema_context.schema.at(dynamic_context.keyword).size()); - return {make( - true, context, schema_context, dynamic_context, std::move(types))}; - } - - return {}; -} - -auto compiler_draft6_validation_const( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; -} - -auto compiler_draft6_validation_exclusivemaximum( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_number()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "integer" && - schema_context.schema.at("type").to_string() != "number") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; -} - -auto compiler_draft6_validation_exclusiveminimum( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - assert(schema_context.schema.at(dynamic_context.keyword).is_number()); - - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "integer" && - schema_context.schema.at("type").to_string() != "number") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - JSON{schema_context.schema.at(dynamic_context.keyword)})}; -} - -auto compiler_draft6_applicator_contains( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "array") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, - SchemaCompilerValueRange{1, std::nullopt, false}, - compile(context, schema_context, relative_dynamic_context, empty_pointer, - empty_pointer))}; -} - -auto compiler_draft6_validation_propertynames( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - if (schema_context.schema.defines("type") && - schema_context.schema.at("type").is_string() && - schema_context.schema.at("type").to_string() != "string") { - return {}; - } - - return {make( - true, context, schema_context, dynamic_context, SchemaCompilerValueNone{}, - compile(context, schema_context, relative_dynamic_context, empty_pointer, - empty_pointer))}; -} - -} // namespace internal -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft7.h b/vendor/jsontoolkit/src/jsonschema/default_compiler_draft7.h deleted file mode 100644 index 1bfd6a66..00000000 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft7.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_DRAFT7_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_DEFAULT_COMPILER_DRAFT7_H_ - -#include -#include - -#include "compile_helpers.h" - -namespace internal { -using namespace sourcemeta::jsontoolkit; - -// TODO: Don't generate `if` if neither `then` nor `else` is defined -auto compiler_draft7_applicator_if( - const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context) - -> SchemaCompilerTemplate { - // `if` - SchemaCompilerTemplate children{compile( - context, schema_context, dynamic_context, empty_pointer, empty_pointer)}; - - // `then` - std::size_t then_cursor{0}; - if (schema_context.schema.defines("then")) { - then_cursor = children.size(); - const auto destination{ - to_uri(schema_context.relative_pointer.initial().concat({"then"}), - schema_context.base) - .recompose()}; - assert(context.frame.contains({ReferenceType::Static, destination})); - for (auto &&step : - compile(context, schema_context, relative_dynamic_context, {"then"}, - empty_pointer, destination)) { - children.push_back(std::move(step)); - } - - // In this case, `if` did nothing, so we can short-circuit - if (then_cursor == 0) { - return children; - } - } - - // `else` - std::size_t else_cursor{0}; - if (schema_context.schema.defines("else")) { - else_cursor = children.size(); - const auto destination{ - to_uri(schema_context.relative_pointer.initial().concat({"else"}), - schema_context.base) - .recompose()}; - assert(context.frame.contains({ReferenceType::Static, destination})); - for (auto &&step : - compile(context, schema_context, relative_dynamic_context, {"else"}, - empty_pointer, destination)) { - children.push_back(std::move(step)); - } - } - - return {make( - false, context, - {schema_context.relative_pointer.initial(), schema_context.schema, - schema_context.vocabularies, schema_context.base, schema_context.labels, - schema_context.references}, - relative_dynamic_context, {then_cursor, else_cursor}, - std::move(children))}; -} - -// We handle `then` as part of `if` -auto compiler_draft7_applicator_then(const SchemaCompilerContext &, - const SchemaCompilerSchemaContext &, - const SchemaCompilerDynamicContext &) - -> SchemaCompilerTemplate { - return {}; -} - -// We handle `else` as part of `if` -auto compiler_draft7_applicator_else(const SchemaCompilerContext &, - const SchemaCompilerSchemaContext &, - const SchemaCompilerDynamicContext &) - -> SchemaCompilerTemplate { - return {}; -} - -} // namespace internal -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h index 4218c8fe..54e0d9fe 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h @@ -1,18 +1,18 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_H_ #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include #include -#include #include #include #include #include -#include // std::future #include // std::map #include // std::optional #include // std::string @@ -71,7 +71,7 @@ enum class IdentificationStrategy : std::uint8_t { /// })JSON"); /// /// std::optional id{sourcemeta::jsontoolkit::identify( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// assert(id.has_value()); /// assert(id.value() == "https://sourcemeta.com/example-schema"); /// ``` @@ -85,7 +85,7 @@ auto identify( const IdentificationStrategy strategy = IdentificationStrategy::Strict, const std::optional &default_dialect = std::nullopt, const std::optional &default_id = std::nullopt) - -> std::future>; + -> std::optional; /// @ingroup jsonschema /// @@ -118,7 +118,7 @@ auto identify(const JSON &schema, const std::string &base_dialect, /// "https://json-schema.org/draft/2020-12/schema"); /// /// std::optional id{sourcemeta::jsontoolkit::identify( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// assert(!id.has_value()); /// ``` SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT @@ -145,7 +145,7 @@ auto anonymize(JSON &schema, const std::string &base_dialect) -> void; /// sourcemeta::jsontoolkit::official_resolver); /// /// std::optional id{sourcemeta::jsontoolkit::identify( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// assert(id.has_value()); /// assert(id.value() == "https://example.com/my-new-id"); /// ``` @@ -239,7 +239,7 @@ auto metaschema( /// /// const std::optional base_dialect{ /// sourcemeta::jsontoolkit::base_dialect( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// /// assert(base_dialect.has_value()); /// assert(base_dialect.value() == @@ -248,7 +248,7 @@ auto metaschema( SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto base_dialect(const JSON &schema, const SchemaResolver &resolver, const std::optional &default_dialect = - std::nullopt) -> std::future>; + std::nullopt) -> std::optional; /// @ingroup jsonschema /// @@ -272,7 +272,7 @@ auto base_dialect(const JSON &schema, const SchemaResolver &resolver, /// /// const std::map vocabularies{ /// sourcemeta::jsontoolkit::vocabularies( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// /// assert(vocabularies.at("https://json-schema.org/draft/2020-12/vocab/core")); /// assert(vocabularies.at("https://json-schema.org/draft/2020-12/vocab/applicator")); @@ -285,7 +285,7 @@ auto base_dialect(const JSON &schema, const SchemaResolver &resolver, SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto vocabularies(const JSON &schema, const SchemaResolver &resolver, const std::optional &default_dialect = - std::nullopt) -> std::future>; + std::nullopt) -> std::map; /// @ingroup jsonschema /// @@ -294,7 +294,7 @@ auto vocabularies(const JSON &schema, const SchemaResolver &resolver, SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto vocabularies(const SchemaResolver &resolver, const std::string &base_dialect, const std::string &dialect) - -> std::future>; + -> std::map; /// @ingroup jsonschema /// diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_anchor.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_anchor.h index 5a0dcea9..a55d0c7c 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_anchor.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_anchor.h @@ -1,13 +1,14 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_ANCHOR_H_ #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_ANCHOR_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include #include // std::uint8_t -#include // std::promise, std::future #include // std::map #include // std::optional #include // std::string @@ -38,7 +39,7 @@ enum class AnchorType : std::uint8_t { Static, Dynamic, All }; /// })JSON"); /// /// const auto anchors{sourcemeta::jsontoolkit::anchors( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// assert(anchors.size() == 1); /// assert(anchors.contains("foo")); /// // This is a static anchor @@ -47,7 +48,7 @@ enum class AnchorType : std::uint8_t { Static, Dynamic, All }; SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto anchors(const JSON &schema, const SchemaResolver &resolver, const std::optional &default_dialect = std::nullopt) - -> std::future>; + -> std::map; /// @ingroup jsonschema /// diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h index 97822e53..bacca953 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h @@ -1,14 +1,15 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_BUNDLE_H_ #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_BUNDLE_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include #include #include // std::uint8_t -#include // std::future #include // std::optional, std::nullopt #include // std::string @@ -43,20 +44,16 @@ enum class BundleOptions : std::uint8_t { /// /// // A custom resolver that knows about an additional schema /// static auto test_resolver(std::string_view identifier) -/// -> std::future> { -/// std::promise> promise; +/// -> std::optional { /// if (identifier == "https://www.example.com/test") { -/// promise.set_value(sourcemeta::jsontoolkit::parse(R"JSON({ +/// return sourcemeta::jsontoolkit::parse(R"JSON({ /// "$id": "https://www.example.com/test", /// "$schema": "https://json-schema.org/draft/2020-12/schema", /// "type": "string" -/// })JSON")); +/// })JSON"); /// } else { -/// promise.set_value( -/// sourcemeta::jsontoolkit::official_resolver(identifier).get()); +/// return sourcemeta::jsontoolkit::official_resolver(identifier); /// } -/// -/// return promise.get_future(); /// } /// /// sourcemeta::jsontoolkit::JSON document = @@ -104,20 +101,16 @@ auto bundle(sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, /// /// // A custom resolver that knows about an additional schema /// static auto test_resolver(std::string_view identifier) -/// -> std::future> { -/// std::promise> promise; +/// -> std::optional { /// if (identifier == "https://www.example.com/test") { -/// promise.set_value(sourcemeta::jsontoolkit::parse(R"JSON({ +/// return sourcemeta::jsontoolkit::parse(R"JSON({ /// "$id": "https://www.example.com/test", /// "$schema": "https://json-schema.org/draft/2020-12/schema", /// "type": "string" -/// })JSON")); +/// })JSON"); /// } else { -/// promise.set_value( -/// sourcemeta::jsontoolkit::official_resolver(identifier).get()); +/// return sourcemeta::jsontoolkit::official_resolver(identifier); /// } -/// -/// return promise.get_future(); /// } /// /// const sourcemeta::jsontoolkit::JSON document = diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h deleted file mode 100644 index 3f7b3690..00000000 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h +++ /dev/null @@ -1,302 +0,0 @@ -#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_COMPILE_H_ -#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_COMPILE_H_ - -#include "jsonschema_export.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include // std::function -#include // std::map -#include // std::optional, std::nullopt -#include // std::set -#include // std::string -#include // std::vector - -/// @ingroup jsonschema -/// @defgroup jsonschema_compiler Compiler -/// @brief Compile a JSON Schema into a set of low-level instructions for fast -/// evaluation - -namespace sourcemeta::jsontoolkit { - -/// @ingroup jsonschema_compiler -/// The schema compiler context is the current subschema information you have at -/// your disposal to implement a keyword -struct SchemaCompilerSchemaContext { - /// The schema location relative to the base URI - const Pointer &relative_pointer; - /// The current subschema - const JSON &schema; - /// The schema vocabularies in use - const std::map &vocabularies; - /// The schema base URI - const URI &base; - /// The set of labels registered so far - std::set labels; - /// The set of references destinations traversed so far - std::set references; -}; - -/// @ingroup jsonschema_compiler -/// The dynamic compiler context is the read-write information you have at your -/// disposal to implement a keyword -struct SchemaCompilerDynamicContext { - /// The schema keyword - const std::string &keyword; - /// The schema base keyword path - const Pointer &base_schema_location; - /// The base instance location that the keyword must be evaluated to - const Pointer &base_instance_location; -}; - -#if !defined(DOXYGEN) -struct SchemaCompilerContext; -#endif - -/// @ingroup jsonschema_compiler -/// A compiler is represented as a function that maps a keyword compiler -/// contexts into a compiler template. You can provide your own to implement -/// your own keywords -using SchemaCompiler = std::function; - -/// @ingroup jsonschema_compiler -/// The static compiler context is the information you have at your -/// disposal to implement a keyword that will never change throughout -/// the compilation process -struct SchemaCompilerContext { - /// The root schema resource - const JSON &root; - /// The reference frame of the entire schema - const ReferenceFrame &frame; - /// The references of the entire schema - const ReferenceMap &references; - /// The schema walker in use - const SchemaWalker &walker; - /// The schema resolver in use - const SchemaResolver &resolver; - /// The schema compiler in use - const SchemaCompiler &compiler; - /// Whether the schema makes use of dynamic scoping - const bool uses_dynamic_scopes; -}; - -/// @ingroup jsonschema_compiler -/// -/// A simple evaluation callback that reports a stack trace in the case of -/// validation error that you can report as you with. For example: -/// -/// ```cpp -/// #include -/// #include -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// const sourcemeta::jsontoolkit::JSON instance{5}; -/// -/// sourcemeta::jsontoolkit::SchemaCompilerErrorTraceOutput output; -/// const auto result{sourcemeta::jsontoolkit::evaluate( -/// schema_template, instance, -/// sourcemeta::jsontoolkit::SchemaCompilerEvaluationMode::Fast, -/// std::ref(output))}; -/// -/// if (!result) { -/// for (const auto &trace : output) { -/// std::cerr << trace.message << "\n"; -/// sourcemeta::jsontoolkit::stringify(trace.instance_location, std::cerr); -/// std::cerr << "\n"; -/// sourcemeta::jsontoolkit::stringify(trace.evaluate_path, std::cerr); -/// std::cerr << "\n"; -/// } -/// } -/// ``` -class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT SchemaCompilerErrorTraceOutput { -public: - SchemaCompilerErrorTraceOutput(const JSON &instance, - const WeakPointer &base = empty_weak_pointer); - - // Prevent accidental copies - SchemaCompilerErrorTraceOutput(const SchemaCompilerErrorTraceOutput &) = - delete; - auto operator=(const SchemaCompilerErrorTraceOutput &) - -> SchemaCompilerErrorTraceOutput & = delete; - - struct Entry { - const std::string message; - const WeakPointer instance_location; - const WeakPointer evaluate_path; - }; - - auto operator()(const SchemaCompilerEvaluationType type, const bool result, - const SchemaCompilerTemplate::value_type &step, - const WeakPointer &evaluate_path, - const WeakPointer &instance_location, const JSON &annotation) - -> void; - - using container_type = typename std::vector; - using const_iterator = typename container_type::const_iterator; - auto begin() const -> const_iterator; - auto end() const -> const_iterator; - auto cbegin() const -> const_iterator; - auto cend() const -> const_iterator; - -private: -// Exporting symbols that depends on the standard C++ library is considered -// safe. -// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN -#if defined(_MSC_VER) -#pragma warning(disable : 4251) -#endif - const JSON &instance_; - const WeakPointer base_; - container_type output; - std::set mask; -#if defined(_MSC_VER) -#pragma warning(default : 4251) -#endif -}; - -/// @ingroup jsonschema_compiler -/// -/// This function translates a step execution into a human-readable string. -/// Useful as the building block for producing user-friendly evaluation results. -auto SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT -describe(const bool valid, const SchemaCompilerTemplate::value_type &step, - const WeakPointer &evaluate_path, const WeakPointer &instance_location, - const JSON &instance, const JSON &annotation) -> std::string; - -/// @ingroup jsonschema_compiler -/// A default compiler that aims to implement every keyword for official JSON -/// Schema dialects. -auto SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT default_schema_compiler( - const SchemaCompilerContext &, const SchemaCompilerSchemaContext &, - const SchemaCompilerDynamicContext &) -> SchemaCompilerTemplate; - -/// @ingroup jsonschema_compiler -/// -/// This function compiles an input JSON Schema into a template that can be -/// later evaluated. For example: -/// -/// ```cpp -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// // Evaluate or encode -/// ``` -auto SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT -compile(const JSON &schema, const SchemaWalker &walker, - const SchemaResolver &resolver, const SchemaCompiler &compiler, - const std::optional &default_dialect = std::nullopt) - -> SchemaCompilerTemplate; - -/// @ingroup jsonschema_compiler -/// -/// This function compiles a single subschema into a compiler template as -/// determined by the given pointer. If a URI is given, the compiler will -/// attempt to jump to that corresponding frame entry. Otherwise, it will -/// navigate within the current keyword. This function is not meant to be used -/// directly, but instead as a building block for supporting applicators on -/// compiler functions. -auto SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT -compile(const SchemaCompilerContext &context, - const SchemaCompilerSchemaContext &schema_context, - const SchemaCompilerDynamicContext &dynamic_context, - const Pointer &schema_suffix, - const Pointer &instance_suffix = empty_pointer, - const std::optional &uri = std::nullopt) - -> SchemaCompilerTemplate; - -/// @ingroup jsonschema_compiler -/// -/// This function converts a compiler template into JSON. Convenient for storing -/// it or sending it over the wire. For example: -/// -/// ```cpp -/// #include -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// const sourcemeta::jsontoolkit::JSON result{ -/// sourcemeta::jsontoolkit::to_json(schema_template)}; -/// -/// sourcemeta::jsontoolkit::prettify(result, std::cout); -/// std::cout << "\n"; -/// ``` -auto SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT -to_json(const SchemaCompilerTemplate &steps) -> JSON; - -/// @ingroup jsonschema_compiler -/// -/// An opinionated key comparison for printing JSON Schema compiler templates -/// with sourcemeta::jsontoolkit::prettify or -/// sourcemeta::jsontoolkit::stringify. For example: -/// -/// ```cpp -/// #include -/// #include -/// #include -/// -/// const sourcemeta::jsontoolkit::JSON schema = -/// sourcemeta::jsontoolkit::parse(R"JSON({ -/// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "type": "string" -/// })JSON"); -/// -/// const auto schema_template{sourcemeta::jsontoolkit::compile( -/// schema, sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver, -/// sourcemeta::jsontoolkit::default_schema_compiler)}; -/// -/// const sourcemeta::jsontoolkit::JSON result{ -/// sourcemeta::jsontoolkit::to_json(schema_template)}; -/// -/// sourcemeta::jsontoolkit::prettify(result, std::cout, -/// compiler_template_format_compare); std::cout << "\n"; -/// ``` -auto SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT compiler_template_format_compare( - const JSON::String &left, const JSON::String &right) -> bool; - -} // namespace sourcemeta::jsontoolkit - -#endif diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_error.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_error.h index 0a368029..887563f5 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_error.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_error.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_ERROR_H #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_ERROR_H +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include @@ -100,33 +102,6 @@ class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT SchemaReferenceError std::string message_; }; -/// @ingroup jsonschema -/// An error that represents a schema compilation failure event -class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT SchemaCompilationError - : public std::exception { -public: - SchemaCompilationError(const URI &base, const Pointer &schema_location, - std::string message) - : base_{base}, schema_location_{schema_location}, - message_{std::move(message)} {} - [[nodiscard]] auto what() const noexcept -> const char * override { - return this->message_.c_str(); - } - - [[nodiscard]] auto base() const noexcept -> const URI & { - return this->base_; - } - - [[nodiscard]] auto location() const noexcept -> const Pointer & { - return this->schema_location_; - } - -private: - URI base_; - Pointer schema_location_; - std::string message_; -}; - #if defined(_MSC_VER) #pragma warning(default : 4251 4275) #endif diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_reference.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_reference.h index 9a42e68f..3f4ff6af 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_reference.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_reference.h @@ -1,14 +1,15 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_REFERENCE_H_ #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_REFERENCE_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include #include #include // std::uint8_t -#include // std::future #include // std::map #include // std::optional #include // std::string @@ -102,11 +103,9 @@ using ReferenceMap = /// /// sourcemeta::jsontoolkit::ReferenceFrame frame; /// sourcemeta::jsontoolkit::ReferenceMap references; -/// sourcemeta::jsontoolkit::frame(document, frame, -/// references, +/// sourcemeta::jsontoolkit::frame(document, frame, references, /// sourcemeta::jsontoolkit::default_schema_walker, -/// sourcemeta::jsontoolkit::official_resolver) -/// .wait(); +/// sourcemeta::jsontoolkit::official_resolver); /// /// // IDs /// assert(frame.contains({sourcemeta::jsontoolkit::ReferenceType::Static, @@ -159,8 +158,7 @@ SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto frame(const JSON &schema, ReferenceFrame &frame, ReferenceMap &references, const SchemaWalker &walker, const SchemaResolver &resolver, const std::optional &default_dialect = std::nullopt, - const std::optional &default_id = std::nullopt) - -> std::future; + const std::optional &default_id = std::nullopt) -> void; } // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h index 8715fbd7..d1cb51d8 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h @@ -1,12 +1,13 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_RESOLVER_H_ #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_RESOLVER_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include // std::function -#include // std::future #include // std::map #include // std::optional #include // std::string_view @@ -28,14 +29,13 @@ namespace sourcemeta::jsontoolkit { /// requests, or anything your application might require. Unless your resolver /// is trivial, it is recommended to create a callable object that implements /// the function interface. -using SchemaResolver = - std::function>(std::string_view)>; +using SchemaResolver = std::function(std::string_view)>; /// @ingroup jsonschema /// A default resolver that relies on built-in official schemas. SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto official_resolver(std::string_view identifier) - -> std::future>; + -> std::optional; /// @ingroup jsonschema /// This is a convenient helper for constructing schema resolvers at runtime. @@ -60,7 +60,7 @@ auto official_resolver(std::string_view identifier) /// // (2) Register a schema /// resolver.add(schema); /// -/// assert(resolver("https://www.example.com").get().has_value()); +/// assert(resolver("https://www.example.com").has_value()); /// ``` class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT MapSchemaResolver { public: @@ -78,8 +78,7 @@ class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT MapSchemaResolver { const std::optional &default_id = std::nullopt) -> void; /// Attempt to resolve a schema - auto operator()(std::string_view identifier) const - -> std::future>; + auto operator()(std::string_view identifier) const -> std::optional; private: // Exporting symbols that depends on the standard C++ library is considered diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_walker.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_walker.h index de8e77b8..625a7f82 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_walker.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_walker.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_WALKER_H_ #define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_WALKER_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT #include "jsonschema_export.h" +#endif #include #include @@ -262,7 +264,7 @@ class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT SchemaIteratorFlat { /// /// const auto vocabularies{ /// sourcemeta::jsontoolkit::vocabularies( -/// document, sourcemeta::jsontoolkit::official_resolver).get()}; +/// document, sourcemeta::jsontoolkit::official_resolver)}; /// /// assert(sourcemeta::jsontoolkit::keyword_priority( /// "prefixItems", vocabularies, diff --git a/vendor/jsontoolkit/src/jsonschema/jsonschema.cc b/vendor/jsontoolkit/src/jsonschema/jsonschema.cc index 0d1c3d9b..ab18f167 100644 --- a/vendor/jsontoolkit/src/jsonschema/jsonschema.cc +++ b/vendor/jsontoolkit/src/jsonschema/jsonschema.cc @@ -4,7 +4,6 @@ #include // assert #include // std::uint64_t #include // std::less -#include // std::future #include // std::numeric_limits #include // std::ostringstream #include // std::remove_reference_t @@ -62,57 +61,43 @@ auto sourcemeta::jsontoolkit::identify( const IdentificationStrategy strategy, const std::optional &default_dialect, const std::optional &default_id) - -> std::future> { + -> std::optional { std::optional maybe_base_dialect; // TODO: Can we avoid a C++ exception as the potential normal way of // operation? try { - maybe_base_dialect = - sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect) - .get(); + maybe_base_dialect = sourcemeta::jsontoolkit::base_dialect(schema, resolver, + default_dialect); } catch (const SchemaResolutionError &) { // Attempt to play a heuristic guessing game before giving up if (strategy == IdentificationStrategy::Loose && schema.is_object()) { const auto keyword{id_keyword_guess(schema)}; - std::promise> promise; - if (keyword.has_value()) { - promise.set_value(schema.at(keyword.value()).to_string()); + return schema.at(keyword.value()).to_string(); } else { - promise.set_value(std::nullopt); + return std::nullopt; } - - return promise.get_future(); } throw; } if (!maybe_base_dialect.has_value()) { - // Attempt to play a heuristic guessing game before giving up if (strategy == IdentificationStrategy::Loose && schema.is_object()) { const auto keyword{id_keyword_guess(schema)}; - std::promise> promise; - if (keyword.has_value()) { - promise.set_value(schema.at(keyword.value()).to_string()); + return schema.at(keyword.value()).to_string(); } else { - promise.set_value(std::nullopt); + return std::nullopt; } - - return promise.get_future(); } - std::promise> promise; - promise.set_value(default_id); - return promise.get_future(); + return default_id; } - std::promise> promise; - promise.set_value(identify(schema, maybe_base_dialect.value(), default_id)); - return promise.get_future(); + return identify(schema, maybe_base_dialect.value(), default_id); } auto sourcemeta::jsontoolkit::identify( @@ -168,8 +153,7 @@ auto sourcemeta::jsontoolkit::reidentify( const SchemaResolver &resolver, const std::optional &default_dialect) -> void { const auto base_dialect{ - sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect) - .get()}; + sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect)}; if (!base_dialect.has_value()) { throw sourcemeta::jsontoolkit::SchemaError("Cannot determine base dialect"); } @@ -212,7 +196,7 @@ auto sourcemeta::jsontoolkit::metaschema( "Could not determine dialect of the schema"); } - const auto maybe_metaschema{resolver(maybe_dialect.value()).get()}; + const auto maybe_metaschema{resolver(maybe_dialect.value())}; if (!maybe_metaschema.has_value()) { throw sourcemeta::jsontoolkit::SchemaResolutionError( maybe_dialect.value(), @@ -226,7 +210,7 @@ auto sourcemeta::jsontoolkit::base_dialect( const sourcemeta::jsontoolkit::JSON &schema, const sourcemeta::jsontoolkit::SchemaResolver &resolver, const std::optional &default_dialect) - -> std::future> { + -> std::optional { assert(sourcemeta::jsontoolkit::is_schema(schema)); const std::optional dialect{ sourcemeta::jsontoolkit::dialect(schema, default_dialect)}; @@ -234,9 +218,7 @@ auto sourcemeta::jsontoolkit::base_dialect( // There is no metaschema information whatsoever // Nothing we can do at this point if (!dialect.has_value()) { - std::promise> promise; - promise.set_value(std::nullopt); - return promise.get_future(); + return std::nullopt; } const std::string &effective_dialect{dialect.value()}; @@ -246,9 +228,7 @@ auto sourcemeta::jsontoolkit::base_dialect( effective_dialect == "https://json-schema.org/draft/2019-09/schema" || effective_dialect == "http://json-schema.org/draft-07/schema#" || effective_dialect == "http://json-schema.org/draft-06/schema#") { - std::promise> promise; - promise.set_value(effective_dialect); - return promise.get_future(); + return effective_dialect; } // For compatibility with older JSON Schema drafts that didn't support $id nor @@ -266,9 +246,7 @@ auto sourcemeta::jsontoolkit::base_dialect( effective_dialect == "http://json-schema.org/draft-03/schema#" || effective_dialect == "http://json-schema.org/draft-04/hyper-schema#" || effective_dialect == "http://json-schema.org/draft-04/schema#") { - std::promise> promise; - promise.set_value(effective_dialect); - return promise.get_future(); + return effective_dialect; } // If we reach the bottom of the metaschema hierarchy, where the schema @@ -276,15 +254,13 @@ auto sourcemeta::jsontoolkit::base_dialect( if (schema.is_object() && schema.defines("$id")) { assert(schema.at("$id").is_string()); if (schema.at("$id").to_string() == effective_dialect) { - std::promise> promise; - promise.set_value(schema.at("$id").to_string()); - return promise.get_future(); + return schema.at("$id").to_string(); } } // Otherwise, traverse the metaschema hierarchy up const std::optional metaschema{ - resolver(effective_dialect).get()}; + resolver(effective_dialect)}; if (!metaschema.has_value()) { throw sourcemeta::jsontoolkit::SchemaResolutionError( effective_dialect, "Could not resolve the requested schema"); @@ -314,10 +290,9 @@ auto sourcemeta::jsontoolkit::vocabularies( const sourcemeta::jsontoolkit::JSON &schema, const sourcemeta::jsontoolkit::SchemaResolver &resolver, const std::optional &default_dialect) - -> std::future> { + -> std::map { const std::optional maybe_base_dialect{ - sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect) - .get()}; + sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect)}; if (!maybe_base_dialect.has_value()) { throw sourcemeta::jsontoolkit::SchemaError( "Could not determine base dialect for schema"); @@ -340,33 +315,25 @@ auto sourcemeta::jsontoolkit::vocabularies( auto sourcemeta::jsontoolkit::vocabularies(const SchemaResolver &resolver, const std::string &base_dialect, const std::string &dialect) - -> std::future> { + -> std::map { // As a performance optimization shortcut if (base_dialect == dialect) { if (dialect == "https://json-schema.org/draft/2020-12/schema") { - std::promise> promise; - promise.set_value( - {{"https://json-schema.org/draft/2020-12/vocab/core", true}, - {"https://json-schema.org/draft/2020-12/vocab/applicator", true}, - {"https://json-schema.org/draft/2020-12/vocab/unevaluated", true}, - {"https://json-schema.org/draft/2020-12/vocab/validation", true}, - {"https://json-schema.org/draft/2020-12/vocab/meta-data", true}, - {"https://json-schema.org/draft/2020-12/vocab/format-annotation", - true}, - {"https://json-schema.org/draft/2020-12/vocab/content", true}}); - - return promise.get_future(); + return {{"https://json-schema.org/draft/2020-12/vocab/core", true}, + {"https://json-schema.org/draft/2020-12/vocab/applicator", true}, + {"https://json-schema.org/draft/2020-12/vocab/unevaluated", true}, + {"https://json-schema.org/draft/2020-12/vocab/validation", true}, + {"https://json-schema.org/draft/2020-12/vocab/meta-data", true}, + {"https://json-schema.org/draft/2020-12/vocab/format-annotation", + true}, + {"https://json-schema.org/draft/2020-12/vocab/content", true}}; } else if (dialect == "https://json-schema.org/draft/2019-09/schema") { - std::promise> promise; - promise.set_value( - {{"https://json-schema.org/draft/2019-09/vocab/core", true}, - {"https://json-schema.org/draft/2019-09/vocab/applicator", true}, - {"https://json-schema.org/draft/2019-09/vocab/validation", true}, - {"https://json-schema.org/draft/2019-09/vocab/meta-data", true}, - {"https://json-schema.org/draft/2019-09/vocab/format", false}, - {"https://json-schema.org/draft/2019-09/vocab/content", true}}); - - return promise.get_future(); + return {{"https://json-schema.org/draft/2019-09/vocab/core", true}, + {"https://json-schema.org/draft/2019-09/vocab/applicator", true}, + {"https://json-schema.org/draft/2019-09/vocab/validation", true}, + {"https://json-schema.org/draft/2019-09/vocab/meta-data", true}, + {"https://json-schema.org/draft/2019-09/vocab/format", false}, + {"https://json-schema.org/draft/2019-09/vocab/content", true}}; } } @@ -387,9 +354,7 @@ auto sourcemeta::jsontoolkit::vocabularies(const SchemaResolver &resolver, base_dialect == "http://json-schema.org/draft-02/hyper-schema#" || base_dialect == "http://json-schema.org/draft-01/hyper-schema#" || base_dialect == "http://json-schema.org/draft-00/hyper-schema#") { - std::promise> promise; - promise.set_value({{base_dialect, true}}); - return promise.get_future(); + return {{base_dialect, true}}; } /* @@ -397,7 +362,7 @@ auto sourcemeta::jsontoolkit::vocabularies(const SchemaResolver &resolver, */ const std::optional maybe_schema_dialect{ - resolver(dialect).get()}; + resolver(dialect)}; if (!maybe_schema_dialect.has_value()) { throw sourcemeta::jsontoolkit::SchemaResolutionError( dialect, "Could not resolve the requested schema"); @@ -438,9 +403,7 @@ auto sourcemeta::jsontoolkit::vocabularies(const SchemaResolver &resolver, "The core vocabulary must always be required"); } - std::promise> promise; - promise.set_value(std::move(result)); - return promise.get_future(); + return result; } auto sourcemeta::jsontoolkit::schema_format_compare( diff --git a/vendor/jsontoolkit/src/jsonschema/official_resolver.in.cc b/vendor/jsontoolkit/src/jsonschema/official_resolver.in.cc index e138dcf9..6a14d0cd 100644 --- a/vendor/jsontoolkit/src/jsonschema/official_resolver.in.cc +++ b/vendor/jsontoolkit/src/jsonschema/official_resolver.in.cc @@ -1,229 +1,218 @@ #include auto sourcemeta::jsontoolkit::official_resolver(std::string_view identifier) - -> std::future> { - std::promise> promise; - + -> std::optional { // JSON Schema 2020-12 if (identifier == "https://json-schema.org/draft/2020-12/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_2020_12@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_2020_12@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/applicator") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_APPLICATOR@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_APPLICATOR@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/content") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_CONTENT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_CONTENT@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/core") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_CORE@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_CORE@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/format-annotation") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_FORMAT_ANNOTATION@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_FORMAT_ANNOTATION@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/format-assertion") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_FORMAT_ASSERTION@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_FORMAT_ASSERTION@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_HYPER_SCHEMA@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_HYPER_SCHEMA@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/meta-data") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_META_DATA@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_META_DATA@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/unevaluated") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_UNEVALUATED@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_UNEVALUATED@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/meta/validation") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_VALIDATION@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_VALIDATION@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_2020_12@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_LINKS_2020_12@)EOF"); } else if (identifier == "https://json-schema.org/draft/2020-12/output/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_OUTPUT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2020_12_OUTPUT@)EOF"); // JSON Schema 2019-09 } else if (identifier == "https://json-schema.org/draft/2019-09/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_2019_09@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_2019_09@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/applicator") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_APPLICATOR@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_APPLICATOR@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/content") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_CONTENT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_CONTENT@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/core") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_CORE@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_CORE@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/format") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_FORMAT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_FORMAT@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_HYPER_SCHEMA@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_HYPER_SCHEMA@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/meta-data") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_META_DATA@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_META_DATA@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/meta/validation") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_VALIDATION@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_VALIDATION@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_2019_09@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_LINKS_2019_09@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/output/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_OUTPUT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_2019_09_OUTPUT@)EOF"); } else if (identifier == "https://json-schema.org/draft/2019-09/output/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_2019_09_OUTPUT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_2019_09_OUTPUT@)EOF"); // JSON Schema Draft7 } else if (identifier == "http://json-schema.org/draft-07/schema#" || identifier == "http://json-schema.org/draft-07/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT7@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT7@)EOF"); } else if (identifier == "http://json-schema.org/draft-07/hyper-schema#" || identifier == "http://json-schema.org/draft-07/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT7@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT7@)EOF"); } else if (identifier == "http://json-schema.org/draft-07/links#" || identifier == "http://json-schema.org/draft-07/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT7@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT7@)EOF"); } else if (identifier == "http://json-schema.org/draft-07/hyper-schema-output") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT7_OUTPUT@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT7_OUTPUT@)EOF"); // JSON Schema Draft6 } else if (identifier == "http://json-schema.org/draft-06/schema#" || identifier == "http://json-schema.org/draft-06/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT6@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT6@)EOF"); } else if (identifier == "http://json-schema.org/draft-06/hyper-schema#" || identifier == "http://json-schema.org/draft-06/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT6@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT6@)EOF"); } else if (identifier == "http://json-schema.org/draft-06/links#" || identifier == "http://json-schema.org/draft-06/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT6@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT6@)EOF"); // JSON Schema Draft4 } else if (identifier == "http://json-schema.org/draft-04/schema#" || identifier == "http://json-schema.org/draft-04/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT4@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT4@)EOF"); } else if (identifier == "http://json-schema.org/draft-04/hyper-schema#" || identifier == "http://json-schema.org/draft-04/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT4@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT4@)EOF"); } else if (identifier == "http://json-schema.org/draft-04/links#" || identifier == "http://json-schema.org/draft-04/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT4@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT4@)EOF"); // JSON Schema Draft3 } else if (identifier == "http://json-schema.org/draft-03/schema#" || identifier == "http://json-schema.org/draft-03/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT3@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT3@)EOF"); } else if (identifier == "http://json-schema.org/draft-03/hyper-schema#" || identifier == "http://json-schema.org/draft-03/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT3@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT3@)EOF"); } else if (identifier == "http://json-schema.org/draft-03/links#" || identifier == "http://json-schema.org/draft-03/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT3@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT3@)EOF"); } else if (identifier == "http://json-schema.org/draft-03/json-ref#" || identifier == "http://json-schema.org/draft-03/json-ref") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSON_REF_DRAFT3@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSON_REF_DRAFT3@)EOF"); // JSON Schema Draft2 } else if (identifier == "http://json-schema.org/draft-02/schema#" || identifier == "http://json-schema.org/draft-02/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT2@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT2@)EOF"); } else if (identifier == "http://json-schema.org/draft-02/hyper-schema#" || identifier == "http://json-schema.org/draft-02/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT2@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT2@)EOF"); } else if (identifier == "http://json-schema.org/draft-02/links#" || identifier == "http://json-schema.org/draft-02/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT2@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT2@)EOF"); } else if (identifier == "http://json-schema.org/draft-02/json-ref#" || identifier == "http://json-schema.org/draft-02/json-ref") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSON_REF_DRAFT2@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSON_REF_DRAFT2@)EOF"); // JSON Schema Draft1 } else if (identifier == "http://json-schema.org/draft-01/schema#" || identifier == "http://json-schema.org/draft-01/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT1@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT1@)EOF"); } else if (identifier == "http://json-schema.org/draft-01/hyper-schema#" || identifier == "http://json-schema.org/draft-01/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT1@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT1@)EOF"); } else if (identifier == "http://json-schema.org/draft-01/links#" || identifier == "http://json-schema.org/draft-01/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT1@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT1@)EOF"); } else if (identifier == "http://json-schema.org/draft-01/json-ref#" || identifier == "http://json-schema.org/draft-01/json-ref") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSON_REF_DRAFT1@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSON_REF_DRAFT1@)EOF"); // JSON Schema Draft0 } else if (identifier == "http://json-schema.org/draft-00/schema#" || identifier == "http://json-schema.org/draft-00/schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT0@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSONSCHEMA_DRAFT0@)EOF"); } else if (identifier == "http://json-schema.org/draft-00/hyper-schema#" || identifier == "http://json-schema.org/draft-00/hyper-schema") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT0@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_HYPERSCHEMA_DRAFT0@)EOF"); } else if (identifier == "http://json-schema.org/draft-00/links#" || identifier == "http://json-schema.org/draft-00/links") { - promise.set_value( - sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT0@)EOF")); + return sourcemeta::jsontoolkit::parse(R"EOF(@METASCHEMA_LINKS_DRAFT0@)EOF"); } else if (identifier == "http://json-schema.org/draft-00/json-ref#" || identifier == "http://json-schema.org/draft-00/json-ref") { - promise.set_value(sourcemeta::jsontoolkit::parse( - R"EOF(@METASCHEMA_JSON_REF_DRAFT0@)EOF")); + return sourcemeta::jsontoolkit::parse( + R"EOF(@METASCHEMA_JSON_REF_DRAFT0@)EOF"); // Otherwise } else { - promise.set_value(std::nullopt); + return std::nullopt; } - - return promise.get_future(); } diff --git a/vendor/jsontoolkit/src/jsonschema/reference.cc b/vendor/jsontoolkit/src/jsonschema/reference.cc index 303ded4f..b455e5e7 100644 --- a/vendor/jsontoolkit/src/jsonschema/reference.cc +++ b/vendor/jsontoolkit/src/jsonschema/reference.cc @@ -130,7 +130,7 @@ auto sourcemeta::jsontoolkit::frame( const sourcemeta::jsontoolkit::SchemaWalker &walker, const sourcemeta::jsontoolkit::SchemaResolver &resolver, const std::optional &default_dialect, - const std::optional &default_id) -> std::future { + const std::optional &default_id) -> void { std::vector subschema_entries; std::map> base_uris; @@ -138,8 +138,7 @@ auto sourcemeta::jsontoolkit::frame( base_dialects; const std::optional root_base_dialect{ - sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect) - .get()}; + sourcemeta::jsontoolkit::base_dialect(schema, resolver, default_dialect)}; assert(root_base_dialect.has_value()); const std::optional root_id{sourcemeta::jsontoolkit::identify( @@ -463,6 +462,4 @@ auto sourcemeta::jsontoolkit::frame( } } } - - return std::promise{}.get_future(); } diff --git a/vendor/jsontoolkit/src/jsonschema/resolver.cc b/vendor/jsontoolkit/src/jsonschema/resolver.cc index 4622ba2f..f8f4bcb3 100644 --- a/vendor/jsontoolkit/src/jsonschema/resolver.cc +++ b/vendor/jsontoolkit/src/jsonschema/resolver.cc @@ -22,8 +22,7 @@ auto MapSchemaResolver::add(const JSON &schema, ReferenceFrame entries; ReferenceMap references; frame(schema, entries, references, default_schema_walker, *this, - default_dialect, default_id) - .wait(); + default_dialect, default_id); for (const auto &[key, entry] : entries) { if (entry.type != ReferenceEntryType::Resource) { @@ -33,11 +32,10 @@ auto MapSchemaResolver::add(const JSON &schema, auto subschema{get(schema, entry.pointer)}; // TODO: Set the base dialect in the frame entries const auto subschema_base_dialect{ - base_dialect(subschema, *this, entry.dialect).get()}; + base_dialect(subschema, *this, entry.dialect)}; assert(subschema_base_dialect.has_value()); const auto subschema_vocabularies{ - vocabularies(*this, subschema_base_dialect.value(), entry.dialect) - .get()}; + vocabularies(*this, subschema_base_dialect.value(), entry.dialect)}; // Given we might be resolving embedded resources, we fully // resolve their dialect and identifiers, otherwise the @@ -69,21 +67,17 @@ auto MapSchemaResolver::add(const JSON &schema, } auto MapSchemaResolver::operator()(std::string_view identifier) const - -> std::future> { + -> std::optional { const std::string string_identifier{identifier}; if (this->schemas.contains(string_identifier)) { - std::promise> promise; - promise.set_value(this->schemas.at(string_identifier)); - return promise.get_future(); + return this->schemas.at(string_identifier); } if (this->default_resolver) { return this->default_resolver(identifier); } - std::promise> promise; - promise.set_value(std::nullopt); - return promise.get_future(); + return std::nullopt; } } // namespace sourcemeta::jsontoolkit diff --git a/vendor/jsontoolkit/src/jsonschema/walker.cc b/vendor/jsontoolkit/src/jsonschema/walker.cc index 23856cfd..c3ff20cd 100644 --- a/vendor/jsontoolkit/src/jsonschema/walker.cc +++ b/vendor/jsontoolkit/src/jsonschema/walker.cc @@ -2,10 +2,9 @@ #include #include -#include // std::max +#include // std::max, std::sort #include // assert #include // std::accumulate -#include // std::ranges::sort auto sourcemeta::jsontoolkit::keyword_priority( std::string_view keyword, const std::map &vocabularies, @@ -44,13 +43,11 @@ auto walk(sourcemeta::jsontoolkit::Pointer &pointer, const std::string &new_dialect{current_dialect.value()}; const std::optional base_dialect{ - sourcemeta::jsontoolkit::base_dialect(subschema, resolver, new_dialect) - .get()}; + sourcemeta::jsontoolkit::base_dialect(subschema, resolver, new_dialect)}; assert(base_dialect.has_value()); const std::map vocabularies{ sourcemeta::jsontoolkit::vocabularies(resolver, base_dialect.value(), - new_dialect) - .get()}; + new_dialect)}; if (type == SchemaWalkerType_t::Deep || level > 0) { subschemas.push_back( @@ -193,13 +190,12 @@ sourcemeta::jsontoolkit::SchemaKeywordIterator::SchemaKeywordIterator( const std::optional dialect{ sourcemeta::jsontoolkit::dialect(schema, default_dialect)}; const std::optional base_dialect{ - sourcemeta::jsontoolkit::base_dialect(schema, resolver, dialect).get()}; + sourcemeta::jsontoolkit::base_dialect(schema, resolver, dialect)}; std::map vocabularies; if (base_dialect.has_value() && dialect.has_value()) { vocabularies.merge(sourcemeta::jsontoolkit::vocabularies( - resolver, base_dialect.value(), dialect.value()) - .get()); + resolver, base_dialect.value(), dialect.value())); } for (const auto &[key, value] : schema.as_object()) { @@ -208,8 +204,8 @@ sourcemeta::jsontoolkit::SchemaKeywordIterator::SchemaKeywordIterator( } // Sort keywords based on priority for correct evaluation - std::ranges::sort( - this->entries, + std::sort( + this->entries.begin(), this->entries.end(), [&vocabularies, &walker](const auto &left, const auto &right) -> bool { // These cannot be empty or indexes, as we created // the entries array from a JSON object diff --git a/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri.h b/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri.h index 8c5ef1d4..b9ee2d4c 100644 --- a/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri.h +++ b/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_URI_H_ #define SOURCEMETA_JSONTOOLKIT_URI_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_URI_EXPORT #include "uri_export.h" +#endif #include diff --git a/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri_error.h b/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri_error.h index 110bf799..8062f450 100644 --- a/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri_error.h +++ b/vendor/jsontoolkit/src/uri/include/sourcemeta/jsontoolkit/uri_error.h @@ -1,7 +1,9 @@ #ifndef SOURCEMETA_JSONTOOLKIT_URI_ERROR_H_ #define SOURCEMETA_JSONTOOLKIT_URI_ERROR_H_ +#ifndef SOURCEMETA_JSONTOOLKIT_URI_EXPORT #include "uri_export.h" +#endif #include // std::uint64_t #include // std::exception diff --git a/vendor/jsontoolkit/vendor/jsonschema-test-suite.mask b/vendor/jsontoolkit/vendor/jsonschema-test-suite.mask deleted file mode 100644 index 5d301d48..00000000 --- a/vendor/jsontoolkit/vendor/jsonschema-test-suite.mask +++ /dev/null @@ -1,18 +0,0 @@ -bin -output-tests -.editorconfig -CONTRIBUTING.md -output-test-schema.json -package.json -README.md -test-schema.json -tox.ini -tests/latest -tests/draft-next -tests/draft3 -remotes/draft-next -remotes/locationIndependentIdentifier.json -remotes/name-defs.json -remotes/ref-and-defs.json -remotes/tree.json -remotes/extendible-dynamic-ref.json diff --git a/vendor/jsontoolkit/vendor/noa/cmake/noa/compiler/options.cmake b/vendor/jsontoolkit/vendor/noa/cmake/noa/compiler/options.cmake index a368c0f6..dde90f21 100644 --- a/vendor/jsontoolkit/vendor/noa/cmake/noa/compiler/options.cmake +++ b/vendor/jsontoolkit/vendor/noa/cmake/noa/compiler/options.cmake @@ -85,6 +85,8 @@ function(noa_add_default_options visibility target) -fno-trapping-math # Newer versions of GCC (i.e. 14) seem to print a lot of false-positives here -Wno-dangling-reference + # GCC seems to print a lot of false-positives here + -Wno-free-nonheap-object # Disables runtime type information -fno-rtti) endif() diff --git a/vendor/jsontoolkit/vendor/noa/cmake/noa/library.cmake b/vendor/jsontoolkit/vendor/noa/cmake/noa/library.cmake index 05d57748..9868714d 100644 --- a/vendor/jsontoolkit/vendor/noa/cmake/noa/library.cmake +++ b/vendor/jsontoolkit/vendor/noa/cmake/noa/library.cmake @@ -1,6 +1,6 @@ function(noa_library) cmake_parse_arguments(NOA_LIBRARY "" - "NAMESPACE;PROJECT;NAME;FOLDER" "PRIVATE_HEADERS;SOURCES" ${ARGN}) + "NAMESPACE;PROJECT;NAME;FOLDER;VARIANT" "PRIVATE_HEADERS;SOURCES" ${ARGN}) if(NOT NOA_LIBRARY_PROJECT) message(FATAL_ERROR "You must pass the project name using the PROJECT option") @@ -18,7 +18,11 @@ function(noa_library) set(INCLUDE_PREFIX "include/${NOA_LIBRARY_PROJECT}") endif() - set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + if(NOT NOA_LIBRARY_VARIANT) + set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + else() + set(PUBLIC_HEADER "../${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + endif() if(NOA_LIBRARY_SOURCES) set(ABSOLUTE_PRIVATE_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${NOA_LIBRARY_NAME}_export.h") @@ -38,6 +42,11 @@ function(noa_library) set(ALIAS_NAME "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}") endif() + if(NOA_LIBRARY_VARIANT) + set(TARGET_NAME "${TARGET_NAME}_${NOA_LIBRARY_VARIANT}") + set(ALIAS_NAME "${ALIAS_NAME}::${NOA_LIBRARY_VARIANT}") + endif() + if(NOA_LIBRARY_SOURCES) add_library(${TARGET_NAME} ${PUBLIC_HEADER} ${ABSOLUTE_PRIVATE_HEADERS} ${NOA_LIBRARY_SOURCES}) @@ -50,23 +59,34 @@ function(noa_library) add_library(${ALIAS_NAME} ALIAS ${TARGET_NAME}) + if(NOT NOA_LIBRARY_VARIANT) + set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/include") + else() + set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/../include") + endif() if(NOA_LIBRARY_SOURCES) target_include_directories(${TARGET_NAME} PUBLIC - "$" + "$" "$") else() target_include_directories(${TARGET_NAME} INTERFACE - "$" + "$" "$") endif() if(NOA_LIBRARY_SOURCES) + if(NOA_LIBRARY_VARIANT) + set(export_name "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}::${NOA_LIBRARY_VARIANT}") + else() + set(export_name "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}") + endif() + set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME} PUBLIC_HEADER "${PUBLIC_HEADER}" PRIVATE_HEADER "${ABSOLUTE_PRIVATE_HEADERS}" - EXPORT_NAME "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}" + EXPORT_NAME "${export_name}" FOLDER "${NOA_LIBRARY_FOLDER}") else() set_target_properties(${TARGET_NAME} @@ -93,7 +113,7 @@ function(noa_library) endfunction() function(noa_library_install) - cmake_parse_arguments(NOA_LIBRARY "" "NAMESPACE;PROJECT;NAME" "" ${ARGN}) + cmake_parse_arguments(NOA_LIBRARY "" "NAMESPACE;PROJECT;NAME;VARIANT" "" ${ARGN}) if(NOT NOA_LIBRARY_PROJECT) message(FATAL_ERROR "You must pass the project name using the PROJECT option") @@ -114,6 +134,10 @@ function(noa_library_install) set(NAMESPACE_PREFIX "") endif() + if(NOA_LIBRARY_VARIANT) + set(TARGET_NAME "${TARGET_NAME}_${NOA_LIBRARY_VARIANT}") + endif() + include(GNUInstallDirs) install(TARGETS ${TARGET_NAME} EXPORT ${TARGET_NAME} diff --git a/vendor/jsontoolkit/vendor/uriparser/CMakeLists.txt b/vendor/jsontoolkit/vendor/uriparser/CMakeLists.txt deleted file mode 100644 index 77f8adaa..00000000 --- a/vendor/jsontoolkit/vendor/uriparser/CMakeLists.txt +++ /dev/null @@ -1,505 +0,0 @@ -# uriparser - RFC 3986 URI parsing library -# -# Copyright (C) 2018, Sebastian Pipping -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials -# provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of -# its contributors may be used to endorse or promote products -# derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. -# -cmake_minimum_required(VERSION 3.5.0) - -project(uriparser - VERSION - 0.9.8 - LANGUAGES - C -) - -# See https://verbump.de/ for what these numbers do -set(URIPARSER_SO_CURRENT 1) -set(URIPARSER_SO_REVISION 31) -set(URIPARSER_SO_AGE 0) - -include(CheckCCompilerFlag) -include(CheckFunctionExists) -include(CheckLibraryExists) -include(CheckSymbolExists) -include(CMakePackageConfigHelpers) -include(GNUInstallDirs) - -# -# Configuration -# -if(DEFINED BUILD_SHARED_LIBS) - set(_URIPARSER_SHARED_LIBS_DEFAULT ${BUILD_SHARED_LIBS}) -else() - set(_URIPARSER_SHARED_LIBS_DEFAULT ON) -endif() -option(URIPARSER_SHARED_LIBS "Build shared libraries (rather than static ones)" ${_URIPARSER_SHARED_LIBS_DEFAULT}) -option(URIPARSER_BUILD_DOCS "Build API documentation (requires Doxygen, Graphviz, and (optional) Qt's qhelpgenerator)" ON) -option(URIPARSER_BUILD_TESTS "Build test suite (requires GTest >=1.8.0)" ON) -option(URIPARSER_BUILD_TOOLS "Build tools (e.g. CLI \"uriparse\")" ON) -option(URIPARSER_BUILD_CHAR "Build code supporting data type 'char'" ON) -option(URIPARSER_BUILD_WCHAR_T "Build code supporting data type 'wchar_t'" ON) -option(URIPARSER_ENABLE_INSTALL "Enable installation of uriparser" ON) -option(URIPARSER_WARNINGS_AS_ERRORS "Treat all compiler warnings as errors" OFF) -set(URIPARSER_MSVC_RUNTIME "" CACHE STRING "Use of specific runtime library (/MT /MTd /MD /MDd) with MSVC") - -if(NOT URIPARSER_BUILD_CHAR AND NOT URIPARSER_BUILD_WCHAR_T) - message(SEND_ERROR "One or more of URIPARSER_BUILD_CHAR and URIPARSER_BUILD_WCHAR_T needs to be enabled.") -endif() -if(URIPARSER_BUILD_TESTS AND NOT (URIPARSER_BUILD_CHAR AND URIPARSER_BUILD_WCHAR_T)) - message(SEND_ERROR "URIPARSER_BUILD_TESTS=ON requires both URIPARSER_BUILD_CHAR=ON and URIPARSER_BUILD_WCHAR_T=ON.") -endif() -if(URIPARSER_BUILD_TOOLS AND NOT URIPARSER_BUILD_CHAR) - message(SEND_ERROR "URIPARSER_BUILD_TOOLS=ON requires URIPARSER_BUILD_CHAR=ON.") -endif() - -if(URIPARSER_BUILD_TESTS) - # We have to call enable_language() before modifying any CMAKE_CXX_* variables - enable_language(CXX) -endif() - -if(URIPARSER_SHARED_LIBS) - set(_URIPARSER_STATIC_OR_SHARED SHARED) -else() - set(_URIPARSER_STATIC_OR_SHARED STATIC) -endif() - -macro(uriparser_apply_msvc_runtime_to ref) - string(REGEX REPLACE "/M[DT]d?" ${URIPARSER_MSVC_RUNTIME} ${ref} "${${ref}}") -endmacro() - -if(MSVC AND URIPARSER_MSVC_RUNTIME) - uriparser_apply_msvc_runtime_to(CMAKE_C_FLAGS) - uriparser_apply_msvc_runtime_to(CMAKE_C_FLAGS_DEBUG) - uriparser_apply_msvc_runtime_to(CMAKE_C_FLAGS_RELEASE) -endif() - -macro(uriparser_install) - if(URIPARSER_ENABLE_INSTALL) - install(${ARGN}) - endif() -endmacro() - -# -# Compiler checks -# -set(URIPARSER_EXTRA_COMPILE_FLAGS) - -check_c_compiler_flag("-fvisibility=hidden" URIPARSER_COMPILER_SUPPORTS_VISIBILITY) -if(URIPARSER_COMPILER_SUPPORTS_VISIBILITY) - set(URIPARSER_EXTRA_COMPILE_FLAGS "${URIPARSER_EXTRA_COMPILE_FLAGS} -fvisibility=hidden") -endif() - -# -# UriConfig.h -# -check_symbol_exists(wprintf wchar.h HAVE_WPRINTF) -check_function_exists(reallocarray HAVE_REALLOCARRAY) # no luck with CheckSymbolExists -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/UriConfig.h.in UriConfig.h) - -# -# C library -# -set(API_HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/include/uriparser/UriBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/uriparser/UriDefsAnsi.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/uriparser/UriDefsConfig.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/uriparser/UriDefsUnicode.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/uriparser/Uri.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/uriparser/UriIp4.h -) -set(LIBRARY_CODE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriCommon.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriCommon.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriCompare.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriEscape.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriFile.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriIp4Base.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriIp4Base.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriIp4.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriMemory.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriMemory.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalizeBase.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalizeBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalize.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriParseBase.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriParseBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriParse.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriQuery.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriRecompose.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriResolve.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/UriShorten.c -) - -add_library(uriparser - ${_URIPARSER_STATIC_OR_SHARED} - ${API_HEADER_FILES} - ${LIBRARY_CODE_FILES} -) - -if(NOT MSVC) - math(EXPR URIPARSER_SO_CURRENT_MINUS_AGE "${URIPARSER_SO_CURRENT} - ${URIPARSER_SO_AGE}") - set_property(TARGET uriparser PROPERTY VERSION ${URIPARSER_SO_CURRENT_MINUS_AGE}.${URIPARSER_SO_AGE}.${URIPARSER_SO_REVISION}) - set_property(TARGET uriparser PROPERTY SOVERSION ${URIPARSER_SO_CURRENT_MINUS_AGE}) - if(WIN32) - set_target_properties(uriparser PROPERTIES - OUTPUT_NAME uriparser - RUNTIME_OUTPUT_NAME uriparser-${URIPARSER_SO_CURRENT_MINUS_AGE} - ARCHIVE_OUTPUT_NAME uriparser) - endif() -endif() - -set_property( - TARGET - uriparser - PROPERTY - PUBLIC_HEADER "${API_HEADER_FILES}" -) - -target_compile_definitions(uriparser PRIVATE URI_LIBRARY_BUILD) -if (NOT URIPARSER_SHARED_LIBS) - target_compile_definitions(uriparser PUBLIC URI_STATIC_BUILD) -endif() -if(NOT URIPARSER_BUILD_CHAR) - target_compile_definitions(uriparser PUBLIC URI_NO_ANSI) -endif() -if(NOT URIPARSER_BUILD_WCHAR_T) - target_compile_definitions(uriparser PUBLIC URI_NO_UNICODE) -endif() -if(URIPARSER_COMPILER_SUPPORTS_VISIBILITY) - target_compile_definitions(uriparser PRIVATE URI_VISIBILITY) -endif() - -target_include_directories(uriparser - PUBLIC - $ - $ - PRIVATE - ${CMAKE_CURRENT_BINARY_DIR} # for UriConfig.h -) - -uriparser_install( - TARGETS - uriparser - EXPORT - uriparser - ARCHIVE - DESTINATION - ${CMAKE_INSTALL_LIBDIR} - LIBRARY - DESTINATION - ${CMAKE_INSTALL_LIBDIR} - RUNTIME - DESTINATION - ${CMAKE_INSTALL_BINDIR} - PUBLIC_HEADER - DESTINATION - ${CMAKE_INSTALL_INCLUDEDIR}/uriparser -) - -# -# C command line tool -# -if(URIPARSER_BUILD_TOOLS) - add_executable(uriparse - ${CMAKE_CURRENT_SOURCE_DIR}/tool/uriparse.c - ) - - target_link_libraries(uriparse PUBLIC uriparser) - - if(HAIKU) - # Function inet_ntop needs -lsocket or -lnetwork (see pull request #45) - check_library_exists(socket inet_ntop "" HAVE_LIBSOCKET__INET_NTOP) - check_library_exists(network inet_ntop "" HAVE_LIBNETWORK__INET_NTOP) - if(HAVE_LIBSOCKET__INET_NTOP) - target_link_libraries(uriparse PUBLIC socket) - endif() - if(HAVE_LIBNETWORK__INET_NTOP) - target_link_libraries(uriparse PUBLIC network) - endif() - endif() - - if(WIN32) - target_link_libraries(uriparse PUBLIC ws2_32) - endif() - - uriparser_install( - TARGETS - uriparse - DESTINATION - ${CMAKE_INSTALL_BINDIR} - ) -endif() - -# -# C++ test runner -# -if(URIPARSER_BUILD_TESTS) - if(MSVC AND URIPARSER_MSVC_RUNTIME) - uriparser_apply_msvc_runtime_to(CMAKE_CXX_FLAGS) - uriparser_apply_msvc_runtime_to(CMAKE_CXX_FLAGS_DEBUG) - uriparser_apply_msvc_runtime_to(CMAKE_CXX_FLAGS_RELEASE) - endif() - - enable_testing() - - find_package(GTest 1.8.0 REQUIRED) - - add_executable(testrunner - ${CMAKE_CURRENT_SOURCE_DIR}/test/FourSuite.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test/MemoryManagerSuite.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test/test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test/VersionSuite.cpp - - # These library code files have non-public symbols that the test suite - # needs to link to, so they appear here as well: - ${API_HEADER_FILES} - ${LIBRARY_CODE_FILES} - ) - - target_compile_definitions(testrunner PRIVATE URI_STATIC_BUILD) - - if(MSVC) - target_compile_definitions(testrunner PRIVATE -D_CRT_NONSTDC_NO_WARNINGS) - target_compile_definitions(testrunner PRIVATE -D_CRT_SECURE_NO_WARNINGS) - endif() - - target_include_directories(testrunner SYSTEM PRIVATE - ${GTEST_INCLUDE_DIRS} - ) - - target_include_directories(testrunner PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_BINARY_DIR} # for UriConfig.h - ) - - target_link_libraries(testrunner PUBLIC - ${GTEST_BOTH_LIBRARIES} - ) - - # NOTE: uriparser does not use pthreads itself but gtest does - find_package(Threads REQUIRED) - target_link_libraries(testrunner PRIVATE Threads::Threads) - - if(MSVC) - # Specify unwind semantics so that MSVC knowns how to handle exceptions - target_compile_options(testrunner PRIVATE /EHsc) - endif() - - if(MINGW) - set(_URIPARSER_TEST_COMMAND wine testrunner) - else() - set(_URIPARSER_TEST_COMMAND testrunner) - endif() - - add_test( - NAME - test - COMMAND - ${_URIPARSER_TEST_COMMAND} - ) - - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) -endif() - -# -# Compiler flags -# -if(URIPARSER_WARNINGS_AS_ERRORS) - if(MSVC) - add_definitions(/WX) - else() - set(URIPARSER_EXTRA_COMPILE_FLAGS "${URIPARSER_EXTRA_COMPILE_FLAGS} -Werror") - endif() -endif() - -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${URIPARSER_EXTRA_COMPILE_FLAGS}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${URIPARSER_EXTRA_COMPILE_FLAGS}") - -# -# Doxygen API documentation -# -if(URIPARSER_BUILD_DOCS) - find_package(Doxygen REQUIRED dot doxygen) - - set(QHG_LOCATION "" CACHE FILEPATH "Path to qhelpgenerator program (default: auto-detect)") - if(NOT QHG_LOCATION) - find_package(Qt5Help QUIET) - if(TARGET Qt5::qhelpgenerator) - get_target_property(QHG_LOCATION Qt5::qhelpgenerator LOCATION) - mark_as_advanced(Qt5Core_DIR) - mark_as_advanced(Qt5Gui_DIR) - mark_as_advanced(Qt5Help_DIR) - mark_as_advanced(Qt5Sql_DIR) - mark_as_advanced(Qt5Widgets_DIR) - endif() - endif() - - include(FindHTMLHelp) - - # Generate Doxyfile - if(HTML_HELP_COMPILER) - set(GENERATE_HTMLHELP YES) - else() - set(GENERATE_HTMLHELP NO) - endif() - if(QHG_LOCATION) - set(GENERATE_QHP YES) - else() - set(GENERATE_QHP NO) - endif() - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in doc/Doxyfile @ONLY) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/release.sh.in doc/release.sh @ONLY) - - add_custom_target(doc - ALL - COMMAND - ${DOXYGEN_EXECUTABLE} - Doxyfile - WORKING_DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/doc - COMMENT - "Generating API documentation with Doxygen" - VERBATIM - ) - - uriparser_install( - DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/doc/html - DESTINATION - ${CMAKE_INSTALL_DOCDIR} - ) - if(QHG_LOCATION) - uriparser_install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/doc/uriparser-${PROJECT_VERSION}.qch - DESTINATION - ${CMAKE_INSTALL_DOCDIR} - ) - endif() -endif() - -# -# CMake files for find_package(uriparser [..] CONFIG [..]) -# -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/uriparser-config.cmake.in - cmake/uriparser-config.cmake - INSTALL_DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/uriparser-${PROJECT_VERSION}/ -) -write_basic_package_version_file( - cmake/uriparser-config-version.cmake - COMPATIBILITY SameMajorVersion # i.e. semver -) -export( - TARGETS - uriparser - FILE - cmake/uriparser-targets.cmake # not going to be installed -) -uriparser_install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/cmake/uriparser-config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/cmake/uriparser-config-version.cmake - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/uriparser-${PROJECT_VERSION}/ -) -uriparser_install( - EXPORT - uriparser - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/uriparser-${PROJECT_VERSION}/ - NAMESPACE - uriparser:: -) - -# -# pkg-config file -# -if(NOT MSVC) - if(CMAKE_INSTALL_LIBDIR MATCHES "^/") - set(_URIPARSER_PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}") - else() - set(_URIPARSER_PKGCONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") - endif() - - if(CMAKE_INSTALL_INCLUDEDIR MATCHES "^/") - set(_URIPARSER_PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") - else() - set(_URIPARSER_PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") - endif() - - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/liburiparser.pc.in liburiparser.pc @ONLY) - uriparser_install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/liburiparser.pc - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/pkgconfig/ - ) -endif() - -# -# Summary -# -message(STATUS "===========================================================================") -message(STATUS "") -message(STATUS "Configuration") -message(STATUS " Build type ............. ${CMAKE_BUILD_TYPE}") -message(STATUS " Shared libraries ....... ${URIPARSER_SHARED_LIBS}") -message(STATUS " Compiler flags") -message(STATUS " C .................... ${CMAKE_C_FLAGS}") -message(STATUS " C++ .................. ${CMAKE_CXX_FLAGS}") -message(STATUS " Linker flags") -message(STATUS " Executable ........... ${CMAKE_EXE_LINKER_FLAGS}") -message(STATUS " Module ............... ${CMAKE_MODULE_LINKER_FLAGS}") -message(STATUS " Shared ............... ${CMAKE_SHARED_LINKER_FLAGS}") -message(STATUS " Paths") -message(STATUS " Prefix ............... ${CMAKE_INSTALL_PREFIX}") -message(STATUS " qhelpgenerator ....... ${QHG_LOCATION}") -message(STATUS "") -message(STATUS " Features") -message(STATUS " Code for char * ...... ${URIPARSER_BUILD_CHAR}") -message(STATUS " Code for wchar_t * ... ${URIPARSER_BUILD_WCHAR_T}") -message(STATUS " Tools ................ ${URIPARSER_BUILD_TOOLS}") -message(STATUS " Test suite ........... ${URIPARSER_BUILD_TESTS}") -message(STATUS " Documentation ........ ${URIPARSER_BUILD_DOCS}") -message(STATUS "") -if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") - message(STATUS "Continue with") - message(STATUS " make") - message(STATUS " make test") - message(STATUS " sudo make install") - message(STATUS "") -endif() -message(STATUS "===========================================================================") diff --git a/vendor/jsontoolkit/vendor/uriparser/cmake/.gitignore b/vendor/jsontoolkit/vendor/uriparser/cmake/.gitignore deleted file mode 100644 index 3142a219..00000000 --- a/vendor/jsontoolkit/vendor/uriparser/cmake/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/uriparser-config.cmake -/uriparser-config-version.cmake -/uriparser-targets.cmake diff --git a/vendor/jsontoolkit/vendor/uriparser/cmake/uriparser-config.cmake.in b/vendor/jsontoolkit/vendor/uriparser/cmake/uriparser-config.cmake.in deleted file mode 100644 index 64938cff..00000000 --- a/vendor/jsontoolkit/vendor/uriparser/cmake/uriparser-config.cmake.in +++ /dev/null @@ -1,57 +0,0 @@ -# uriparser - RFC 3986 URI parsing library -# -# Copyright (C) 2018, Sebastian Pipping -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials -# provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of -# its contributors may be used to endorse or promote products -# derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. -# -if(NOT _uriparser_config_included) - # Protect against multiple inclusion - set(_uriparser_config_included TRUE) - - -include("${CMAKE_CURRENT_LIST_DIR}/uriparser.cmake") - -@PACKAGE_INIT@ - -# -# Supported components -# -macro(_register_component _NAME _AVAILABE) - set(uriparser_${_NAME}_FOUND ${_AVAILABE}) -endmacro() -_register_component(char @URIPARSER_BUILD_CHAR@) -_register_component(wchar_t @URIPARSER_BUILD_WCHAR_T@) -check_required_components(uriparser) - - -endif(NOT _uriparser_config_included) diff --git a/vendor/jsontoolkit/vendor/uriparser/liburiparser.pc.in b/vendor/jsontoolkit/vendor/uriparser/liburiparser.pc.in deleted file mode 100644 index cb780001..00000000 --- a/vendor/jsontoolkit/vendor/uriparser/liburiparser.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=@_URIPARSER_PKGCONFIG_LIBDIR@ -includedir=@_URIPARSER_PKGCONFIG_INCLUDEDIR@ - -Name: liburiparser -Description: URI parsing and handling library - -Version: @PROJECT_VERSION@ -URL: https://uriparser.github.io/ -Libs: -L${libdir} -luriparser -Cflags: -I${includedir} diff --git a/vendor/noa/cmake/noa/compiler/options.cmake b/vendor/noa/cmake/noa/compiler/options.cmake index b1fc6e53..dde90f21 100644 --- a/vendor/noa/cmake/noa/compiler/options.cmake +++ b/vendor/noa/cmake/noa/compiler/options.cmake @@ -42,6 +42,10 @@ function(noa_add_default_options visibility target) -Winvalid-offsetof -funroll-loops -fstrict-aliasing + -ftree-vectorize + + # To improve how much GCC/Clang will vectorize + -fno-math-errno # Assume that signed arithmetic overflow of addition, subtraction and # multiplication wraps around using twos-complement representation @@ -78,10 +82,28 @@ function(noa_add_default_options visibility target) -fslp-vectorize) elseif(NOA_COMPILER_GCC) target_compile_options("${target}" ${visibility} + -fno-trapping-math # Newer versions of GCC (i.e. 14) seem to print a lot of false-positives here -Wno-dangling-reference - + # GCC seems to print a lot of false-positives here + -Wno-free-nonheap-object # Disables runtime type information -fno-rtti) endif() endfunction() + +# For studying failed vectorization results +# - On Clang , seems to only take effect on release shared builds +# - On GCC, seems to only take effect on release shared builds +function(noa_add_vectorization_diagnostics target) + if(NOA_COMPILER_LLVM) + # See https://llvm.org/docs/Vectorizers.html#id6 + target_compile_options("${target}" PRIVATE + -Rpass-analysis=loop-vectorize + -Rpass-missed=loop-vectorize) + elseif(NOA_COMPILER_GCC) + target_compile_options("${target}" PRIVATE + -fopt-info-vec-missed + -fopt-info-loop-missed) + endif() +endfunction() diff --git a/vendor/noa/cmake/noa/library.cmake b/vendor/noa/cmake/noa/library.cmake index 05d57748..9868714d 100644 --- a/vendor/noa/cmake/noa/library.cmake +++ b/vendor/noa/cmake/noa/library.cmake @@ -1,6 +1,6 @@ function(noa_library) cmake_parse_arguments(NOA_LIBRARY "" - "NAMESPACE;PROJECT;NAME;FOLDER" "PRIVATE_HEADERS;SOURCES" ${ARGN}) + "NAMESPACE;PROJECT;NAME;FOLDER;VARIANT" "PRIVATE_HEADERS;SOURCES" ${ARGN}) if(NOT NOA_LIBRARY_PROJECT) message(FATAL_ERROR "You must pass the project name using the PROJECT option") @@ -18,7 +18,11 @@ function(noa_library) set(INCLUDE_PREFIX "include/${NOA_LIBRARY_PROJECT}") endif() - set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + if(NOT NOA_LIBRARY_VARIANT) + set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + else() + set(PUBLIC_HEADER "../${INCLUDE_PREFIX}/${NOA_LIBRARY_NAME}.h") + endif() if(NOA_LIBRARY_SOURCES) set(ABSOLUTE_PRIVATE_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${NOA_LIBRARY_NAME}_export.h") @@ -38,6 +42,11 @@ function(noa_library) set(ALIAS_NAME "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}") endif() + if(NOA_LIBRARY_VARIANT) + set(TARGET_NAME "${TARGET_NAME}_${NOA_LIBRARY_VARIANT}") + set(ALIAS_NAME "${ALIAS_NAME}::${NOA_LIBRARY_VARIANT}") + endif() + if(NOA_LIBRARY_SOURCES) add_library(${TARGET_NAME} ${PUBLIC_HEADER} ${ABSOLUTE_PRIVATE_HEADERS} ${NOA_LIBRARY_SOURCES}) @@ -50,23 +59,34 @@ function(noa_library) add_library(${ALIAS_NAME} ALIAS ${TARGET_NAME}) + if(NOT NOA_LIBRARY_VARIANT) + set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/include") + else() + set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/../include") + endif() if(NOA_LIBRARY_SOURCES) target_include_directories(${TARGET_NAME} PUBLIC - "$" + "$" "$") else() target_include_directories(${TARGET_NAME} INTERFACE - "$" + "$" "$") endif() if(NOA_LIBRARY_SOURCES) + if(NOA_LIBRARY_VARIANT) + set(export_name "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}::${NOA_LIBRARY_VARIANT}") + else() + set(export_name "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}") + endif() + set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${TARGET_NAME} PUBLIC_HEADER "${PUBLIC_HEADER}" PRIVATE_HEADER "${ABSOLUTE_PRIVATE_HEADERS}" - EXPORT_NAME "${NOA_LIBRARY_PROJECT}::${NOA_LIBRARY_NAME}" + EXPORT_NAME "${export_name}" FOLDER "${NOA_LIBRARY_FOLDER}") else() set_target_properties(${TARGET_NAME} @@ -93,7 +113,7 @@ function(noa_library) endfunction() function(noa_library_install) - cmake_parse_arguments(NOA_LIBRARY "" "NAMESPACE;PROJECT;NAME" "" ${ARGN}) + cmake_parse_arguments(NOA_LIBRARY "" "NAMESPACE;PROJECT;NAME;VARIANT" "" ${ARGN}) if(NOT NOA_LIBRARY_PROJECT) message(FATAL_ERROR "You must pass the project name using the PROJECT option") @@ -114,6 +134,10 @@ function(noa_library_install) set(NAMESPACE_PREFIX "") endif() + if(NOA_LIBRARY_VARIANT) + set(TARGET_NAME "${TARGET_NAME}_${NOA_LIBRARY_VARIANT}") + endif() + include(GNUInstallDirs) install(TARGETS ${TARGET_NAME} EXPORT ${TARGET_NAME}