Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract SchemaWalkerStrategy as KeywordType #1414

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/jsonschema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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 frame.h error.h unevaluated.h
walker.h reference.h frame.h error.h unevaluated.h keywords.h
SOURCES jsonschema.cc default_walker.cc frame.cc
anchor.cc resolver.cc walker.cc bundle.cc unevaluated.cc
"${CMAKE_CURRENT_BINARY_DIR}/official_resolver.cc")
Expand Down
25 changes: 10 additions & 15 deletions src/jsonschema/default_walker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ auto sourcemeta::jsontoolkit::default_schema_walker(
-> sourcemeta::jsontoolkit::SchemaWalkerResult {
#define WALK(vocabulary, _keyword, strategy, ...) \
if (vocabularies.contains(vocabulary) && keyword == _keyword) \
return {sourcemeta::jsontoolkit::SchemaWalkerStrategy::strategy, \
return {sourcemeta::jsontoolkit::KeywordType::strategy, \
vocabulary, \
{__VA_ARGS__}};

Expand Down Expand Up @@ -261,9 +261,8 @@ auto sourcemeta::jsontoolkit::default_schema_walker(
// $ref also takes precedence over any unknown keyword
if (vocabularies.contains(HTTP_BASE "draft-07/schema#") &&
keyword != "$ref") {
return {sourcemeta::jsontoolkit::SchemaWalkerStrategy::Unknown,
std::nullopt,
{"$ref"}};
return {
sourcemeta::jsontoolkit::KeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft6
Expand Down Expand Up @@ -327,9 +326,8 @@ auto sourcemeta::jsontoolkit::default_schema_walker(
// $ref also takes precedence over any unknown keyword
if (vocabularies.contains(HTTP_BASE "draft-06/schema#") &&
keyword != "$ref") {
return {sourcemeta::jsontoolkit::SchemaWalkerStrategy::Unknown,
std::nullopt,
{"$ref"}};
return {
sourcemeta::jsontoolkit::KeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft4
Expand Down Expand Up @@ -381,9 +379,8 @@ auto sourcemeta::jsontoolkit::default_schema_walker(
// $ref also takes precedence over any unknown keyword
if (vocabularies.contains(HTTP_BASE "draft-04/schema#") &&
keyword != "$ref") {
return {sourcemeta::jsontoolkit::SchemaWalkerStrategy::Unknown,
std::nullopt,
{"$ref"}};
return {
sourcemeta::jsontoolkit::KeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft3
Expand Down Expand Up @@ -427,9 +424,8 @@ auto sourcemeta::jsontoolkit::default_schema_walker(
// $ref also takes precedence over any unknown keyword
if (vocabularies.contains(HTTP_BASE "draft-03/schema#") &&
keyword != "$ref") {
return {sourcemeta::jsontoolkit::SchemaWalkerStrategy::Unknown,
std::nullopt,
{"$ref"}};
return {
sourcemeta::jsontoolkit::KeywordType::Unknown, std::nullopt, {"$ref"}};
}

// Draft2
Expand Down Expand Up @@ -552,6 +548,5 @@ auto sourcemeta::jsontoolkit::default_schema_walker(
#undef HTTP_BASE
#undef WALK
#undef WALK_MAYBE_DEPENDENT
return {
sourcemeta::jsontoolkit::SchemaWalkerStrategy::Unknown, std::nullopt, {}};
return {sourcemeta::jsontoolkit::KeywordType::Unknown, std::nullopt, {}};
}
1 change: 1 addition & 0 deletions src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <sourcemeta/jsontoolkit/jsonschema_bundle.h>
#include <sourcemeta/jsontoolkit/jsonschema_error.h>
#include <sourcemeta/jsontoolkit/jsonschema_frame.h>
#include <sourcemeta/jsontoolkit/jsonschema_keywords.h>
#include <sourcemeta/jsontoolkit/jsonschema_reference.h>
#include <sourcemeta/jsontoolkit/jsonschema_resolver.h>
#include <sourcemeta/jsontoolkit/jsonschema_unevaluated.h>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#ifndef SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_KEYWORDS_H_
#define SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_KEYWORDS_H_

#include <cstdint> // std::uint8_t

namespace sourcemeta::jsontoolkit {

#if defined(__GNUC__)
#pragma GCC diagnostic push
// For some strange reason, GCC on Debian 11 believes that a member of
// an enum class (which is namespaced by definition), can shadow an
// alias defined even on a different namespace.
#pragma GCC diagnostic ignored "-Wshadow"
#endif
/// @ingroup jsonschema
/// Determines the type of a JSON Schema keyword
enum class KeywordType : std::uint8_t {
/// The JSON Schema keyword is unknown
Unknown,
/// The JSON Schema keyword is a non-applicator assertion
Assertion,
/// The JSON Schema keyword is a non-applicator annotation
Annotation,
/// The JSON Schema keyword is a reference
Reference,
/// The JSON Schema keyword is known but doesn't match any other type
Other,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument
ApplicatorValue,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument but its evaluation follows
/// special rules
ApplicatorValueOther,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument without affecting the
/// instance location
ApplicatorValueInPlace,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument
ApplicatorElements,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location
ApplicatorElementsInPlace,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location and that can be
/// statically inlined
ApplicatorElementsInline,
/// The JSON Schema keyword is an applicator that potentially
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions
ApplicatorMembers,
/// The JSON Schema keyword is an applicator that potentially
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions without affecting the instance location
ApplicatorMembersInPlace,
/// The JSON Schema keyword is an applicator that may take a JSON Schema
/// definition or an array of potentially JSON Schema definitions
/// as an argument
ApplicatorValueOrElements,
/// The JSON Schema keyword is an applicator that may take a JSON Schema
/// definition or an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location
ApplicatorValueOrElementsInPlace,
/// The JSON Schema keyword is an applicator that may take an array of
/// potentially JSON Schema definitions or an object whose values are
/// potentially JSON Schema definitions as an argument
ApplicatorElementsOrMembers,
/// The JSON Schema keyword is a reserved location that potentially
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions
LocationMembers,
};
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif

} // namespace sourcemeta::jsontoolkit

#endif
81 changes: 4 additions & 77 deletions src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_walker.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

#include <sourcemeta/jsontoolkit/json.h>
#include <sourcemeta/jsontoolkit/jsonpointer.h>
#include <sourcemeta/jsontoolkit/jsonschema_keywords.h>
#include <sourcemeta/jsontoolkit/jsonschema_resolver.h>

#include <cstdint> // std::uint8_t
#include <cstdint> // std::uint64_t
#include <functional> // std::function
#include <map> // std::map
#include <optional> // std::optional
Expand All @@ -20,85 +21,11 @@

namespace sourcemeta::jsontoolkit {

#if defined(__GNUC__)
#pragma GCC diagnostic push
// For some strange reason, GCC on Debian 11 believes that a member of
// an enum class (which is namespaced by definition), can shadow an
// alias defined even on a different namespace.
#pragma GCC diagnostic ignored "-Wshadow"
#endif
// TODO: Extract this into a more generic keyword identification enumeration
/// @ingroup jsonschema
/// Determines the possible states of a schema walk strategy
enum class SchemaWalkerStrategy : std::uint8_t {
/// The JSON Schema keyword is unknown
Unknown,
/// The JSON Schema keyword is a non-applicator assertion
Assertion,
/// The JSON Schema keyword is a non-applicator annotation
Annotation,
/// The JSON Schema keyword is a reference
Reference,
/// The JSON Schema keyword is known but doesn't match any other type
Other,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument
ApplicatorValue,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument but its evaluation follows
/// special rules
ApplicatorValueOther,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument without affecting the
/// instance location
ApplicatorValueInPlace,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument
ApplicatorElements,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location
ApplicatorElementsInPlace,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location and that can be
/// statically inlined
ApplicatorElementsInline,
/// The JSON Schema keyword is an applicator that potentially
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions
ApplicatorMembers,
/// The JSON Schema keyword is an applicator that potentially
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions without affecting the instance location
ApplicatorMembersInPlace,
/// The JSON Schema keyword is an applicator that may take a JSON Schema
/// definition or an array of potentially JSON Schema definitions
/// as an argument
ApplicatorValueOrElements,
/// The JSON Schema keyword is an applicator that may take a JSON Schema
/// definition or an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location
ApplicatorValueOrElementsInPlace,
/// The JSON Schema keyword is an applicator that may take an array of
/// potentially JSON Schema definitions or an object whose values are
/// potentially JSON Schema definitions as an argument
ApplicatorElementsOrMembers,
/// The JSON Schema keyword is a reserved location that potentially
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions
LocationMembers,
};
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif

/// @ingroup jsonschema
/// A structure that encapsulates the result of walker over a specific keyword
struct SchemaWalkerResult {
/// The walker strategy to continue traversing across the schema
const SchemaWalkerStrategy strategy;
const KeywordType type;
/// The vocabulary associated with the keyword, if any
const std::optional<std::string> vocabulary;
/// The keywords a given keyword depends on (if any) during the evaluation
Expand Down Expand Up @@ -127,7 +54,7 @@ SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT
inline auto schema_walker_none(std::string_view,
const std::map<std::string, bool> &)
-> sourcemeta::jsontoolkit::SchemaWalkerResult {
return {SchemaWalkerStrategy::Unknown, std::nullopt, {}};
return {KeywordType::Unknown, std::nullopt, {}};
}

/// @ingroup jsonschema
Expand Down
16 changes: 7 additions & 9 deletions src/jsonschema/unevaluated.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,9 @@ auto find_adjacent_dependencies(
continue;
}

const auto strategy{
walker(property.first, subschema_vocabularies).strategy};
switch (strategy) {
switch (walker(property.first, subschema_vocabularies).type) {
// References
case SchemaWalkerStrategy::Reference:
case KeywordType::Reference:
if (references.contains({ReferenceType::Static,
entry.pointer.concat({property.first})})) {
const auto &reference{references.at(
Expand All @@ -82,7 +80,7 @@ auto find_adjacent_dependencies(
break;

// Static
case SchemaWalkerStrategy::ApplicatorElementsInline:
case KeywordType::ApplicatorElementsInline:
for (std::size_t index = 0; index < property.second.size(); index++) {
find_adjacent_dependencies(
current, schema, frame, references, walker, resolver, keywords,
Expand All @@ -93,7 +91,7 @@ auto find_adjacent_dependencies(
break;

// Dynamic
case SchemaWalkerStrategy::ApplicatorElementsInPlace:
case KeywordType::ApplicatorElementsInPlace:
if (property.second.is_array()) {
for (std::size_t index = 0; index < property.second.size(); index++) {
find_adjacent_dependencies(
Expand All @@ -104,7 +102,7 @@ auto find_adjacent_dependencies(
}

break;
case SchemaWalkerStrategy::ApplicatorValueInPlace:
case KeywordType::ApplicatorValueInPlace:
if (is_schema(property.second)) {
find_adjacent_dependencies(
current, schema, frame, references, walker, resolver, keywords,
Expand All @@ -113,7 +111,7 @@ auto find_adjacent_dependencies(
}

break;
case SchemaWalkerStrategy::ApplicatorValueOrElementsInPlace:
case KeywordType::ApplicatorValueOrElementsInPlace:
if (property.second.is_array()) {
for (std::size_t index = 0; index < property.second.size(); index++) {
find_adjacent_dependencies(
Expand All @@ -129,7 +127,7 @@ auto find_adjacent_dependencies(
}

break;
case SchemaWalkerStrategy::ApplicatorMembersInPlace:
case KeywordType::ApplicatorMembersInPlace:
if (property.second.is_object()) {
for (const auto &pair : property.second.as_object()) {
find_adjacent_dependencies(
Expand Down
Loading
Loading