Skip to content

Commit

Permalink
Represent schema compiler targets with a pair of type/pointer (#570)
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
  • Loading branch information
jviotti authored Apr 23, 2024
1 parent 1d29c6c commit f3f3828
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 105 deletions.
57 changes: 30 additions & 27 deletions src/jsonschema/compile_evaluate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,35 @@ class EvaluationContext {
std::map<Pointer, std::map<Pointer, std::set<JSON>>> annotations;
};

struct TargetInstanceVisitor {
TargetInstanceVisitor(const sourcemeta::jsontoolkit::JSON &instance)
: instance_{instance} {}

auto operator()(const sourcemeta::jsontoolkit::SchemaCompilerTargetInstance
&pointer) const -> const sourcemeta::jsontoolkit::JSON & {
return sourcemeta::jsontoolkit::get(this->instance_, pointer);
auto target_instance(
const sourcemeta::jsontoolkit::SchemaCompilerTarget &target,
const sourcemeta::jsontoolkit::JSON &instance)
-> const sourcemeta::jsontoolkit::JSON & {
using namespace sourcemeta::jsontoolkit;
switch (target.first) {
case SchemaCompilerTargetType::Instance:
return get(instance, target.second);
default:
// We should never get here
assert(false);
static JSON placeholder{nullptr};
return placeholder;
}
}

private:
const sourcemeta::jsontoolkit::JSON &instance_;
};

struct TargetLocationVisitor {
auto operator()(
const sourcemeta::jsontoolkit::SchemaCompilerTargetInstance &pointer)
const -> const sourcemeta::jsontoolkit::Pointer & {
return pointer;
auto target_location(const sourcemeta::jsontoolkit::SchemaCompilerTarget
&target) -> const sourcemeta::jsontoolkit::Pointer & {
using namespace sourcemeta::jsontoolkit;
switch (target.first) {
case SchemaCompilerTargetType::Instance:
return target.second;
default:
// We should never get here
assert(false);
static Pointer placeholder;
return placeholder;
}
};
}

auto callback_noop(
bool, const sourcemeta::jsontoolkit::SchemaCompilerTemplate::value_type
Expand Down Expand Up @@ -85,17 +94,15 @@ auto evaluate_step(
assert(std::holds_alternative<SchemaCompilerValueString>(assertion.value));
const auto &value{std::get<SchemaCompilerValueString>(assertion.value)};
EVALUATE_CONDITION_GUARD(assertion.condition, instance);
const auto &target{
std::visit(TargetInstanceVisitor{instance}, assertion.target)};
const auto &target{target_instance(assertion.target, instance)};
assert(target.is_object());
result = target.defines(value);
} else if (std::holds_alternative<SchemaCompilerAssertionType>(step)) {
const auto &assertion{std::get<SchemaCompilerAssertionType>(step)};
assert(std::holds_alternative<SchemaCompilerValueType>(assertion.value));
const auto value{std::get<SchemaCompilerValueType>(assertion.value)};
EVALUATE_CONDITION_GUARD(assertion.condition, instance);
const auto &target{
std::visit(TargetInstanceVisitor{instance}, assertion.target)};
const auto &target{target_instance(assertion.target, instance)};
result = target.type() == value;
} else if (std::holds_alternative<SchemaCompilerLogicalOr>(step)) {
const auto &logical{std::get<SchemaCompilerLogicalOr>(step)};
Expand Down Expand Up @@ -144,17 +151,13 @@ auto evaluate_step(

const auto &annotation{std::get<SchemaCompilerAnnotationPublic>(step)};
EVALUATE_CONDITION_GUARD(annotation.condition, instance);
static TargetLocationVisitor target_location_visitor;
const auto &instance_location{
std::visit(target_location_visitor, annotation.target)};
const auto &instance_location{target_location(annotation.target)};
context.annotate(instance_location, annotation.evaluation_path,
annotation.value);
} else if (std::holds_alternative<SchemaCompilerAnnotationPrivate>(step)) {
const auto &annotation{std::get<SchemaCompilerAnnotationPrivate>(step)};
EVALUATE_CONDITION_GUARD(annotation.condition, instance);
static TargetLocationVisitor target_location_visitor;
const auto &instance_location{
std::visit(target_location_visitor, annotation.target)};
const auto &instance_location{target_location(annotation.target)};
context.annotate(instance_location, annotation.evaluation_path,
annotation.value);

Expand Down
31 changes: 17 additions & 14 deletions src/jsonschema/compile_json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@

namespace {

struct TargetVisitor {
auto operator()(const sourcemeta::jsontoolkit::SchemaCompilerTargetInstance
&pointer) const -> sourcemeta::jsontoolkit::JSON {
using namespace sourcemeta::jsontoolkit;
JSON result{JSON::make_object()};
result.assign("category", JSON{"target"});
result.assign("type", JSON{"instance"});
result.assign("location", JSON{to_string(pointer)});
return result;
auto target_to_json(const sourcemeta::jsontoolkit::SchemaCompilerTarget &target)
-> sourcemeta::jsontoolkit::JSON {
using namespace sourcemeta::jsontoolkit;
JSON result{JSON::make_object()};
switch (target.first) {
case SchemaCompilerTargetType::Instance:
result.assign("category", JSON{"target"});
result.assign("type", JSON{"instance"});
result.assign("location", JSON{to_string(target.second)});
return result;
default:
// We should never get here
assert(false);
return result;
}
};
}

auto step_to_json(
const sourcemeta::jsontoolkit::SchemaCompilerTemplate::value_type &step)
Expand All @@ -31,11 +36,10 @@ auto assertion_to_json(
const sourcemeta::jsontoolkit::SchemaCompilerTemplate &condition)
-> sourcemeta::jsontoolkit::JSON {
using namespace sourcemeta::jsontoolkit;
static const TargetVisitor visitor;
JSON result{JSON::make_object()};
result.assign("category", JSON{"assertion"});
result.assign("type", JSON{type});
result.assign("target", std::visit(visitor, target));
result.assign("target", target_to_json(target));
result.assign("keywordLocation", JSON{to_string(evaluation_path)});
result.assign("absoluteKeywordLocation", JSON{keyword_location});
result.assign("value", std::move(value));
Expand Down Expand Up @@ -99,11 +103,10 @@ auto annotation_to_json(
const sourcemeta::jsontoolkit::SchemaCompilerTemplate &condition)
-> sourcemeta::jsontoolkit::JSON {
using namespace sourcemeta::jsontoolkit;
static const TargetVisitor visitor;
JSON result{JSON::make_object()};
result.assign("category", JSON{"annotation"});
result.assign("type", JSON{type});
result.assign("target", std::visit(visitor, target));
result.assign("target", target_to_json(target));
result.assign("keywordLocation", JSON{to_string(evaluation_path)});
result.assign("absoluteKeywordLocation", JSON{keyword_location});
result.assign("value", value);
Expand Down
2 changes: 1 addition & 1 deletion src/jsonschema/default_compiler_draft4.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ auto compiler_draft4_validation_properties(const SchemaCompilerContext &context)
// Annotations as such don't exist in Draft 4,
// so emit a private annotation instead
substeps.push_back(SchemaCompilerAnnotationPrivate{
context.instance_location,
{SchemaCompilerTargetType::Instance, context.instance_location},
context.evaluation_path,
to_uri(context.relative_pointer, context.base).recompose(),
JSON{key},
Expand Down
17 changes: 11 additions & 6 deletions src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include <map> // std::map
#include <optional> // std::optional, std::nullopt
#include <string> // std::string
#include <utility> // std::move
#include <utility> // std::move, std::pair
#include <variant> // std::variant
#include <vector> // std::vector

Expand All @@ -38,12 +38,15 @@ using SchemaCompilerValueString = JSON::String;
using SchemaCompilerValueType = JSON::Type;

/// @ingroup jsonschema
/// Represents a compiler step target that corresponds to an instance location
using SchemaCompilerTargetInstance = Pointer;
/// Represents a type of compiler step target
enum class SchemaCompilerTargetType {
/// An static instance literal
Instance
};

/// @ingroup jsonschema
/// Represents a generic compiler step target
using SchemaCompilerTarget = std::variant<SchemaCompilerTargetInstance>;
using SchemaCompilerTarget = std::pair<SchemaCompilerTargetType, Pointer>;

/// @ingroup jsonschema
/// Represents a compiler assertion step that always fails
Expand Down Expand Up @@ -189,9 +192,11 @@ struct SchemaCompilerContext {
template <typename Step, typename ValueType>
auto make(const SchemaCompilerContext &context, ValueType &&type,
SchemaCompilerTemplate &&condition) -> Step {
return {context.instance_location, context.evaluation_path,
return {{SchemaCompilerTargetType::Instance, context.instance_location},
context.evaluation_path,
to_uri(context.relative_pointer, context.base).recompose(),
std::move(type), std::move(condition)};
std::move(type),
std::move(condition)};
}

/// @ingroup jsonschema
Expand Down
Loading

0 comments on commit f3f3828

Please sign in to comment.