Skip to content

Commit

Permalink
Add a templated instance schema compiler target type (#571)
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 f3f3828 commit 8c62eab
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
39 changes: 19 additions & 20 deletions src/jsonschema/compile_evaluate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace {
class EvaluationContext {
public:
using Pointer = sourcemeta::jsontoolkit::Pointer;
std::map<Pointer, Pointer> templates;

using JSON = sourcemeta::jsontoolkit::JSON;

auto annotate(const Pointer &instance_location,
Expand All @@ -34,34 +36,31 @@ class EvaluationContext {
std::map<Pointer, std::map<Pointer, std::set<JSON>>> annotations;
};

auto target_instance(
auto target_location(
const sourcemeta::jsontoolkit::SchemaCompilerTarget &target,
const sourcemeta::jsontoolkit::JSON &instance)
-> const sourcemeta::jsontoolkit::JSON & {
EvaluationContext &context) -> const sourcemeta::jsontoolkit::Pointer & {
using namespace sourcemeta::jsontoolkit;
switch (target.first) {
case SchemaCompilerTargetType::Instance:
return get(instance, target.second);
return target.second;
case SchemaCompilerTargetType::TemplateInstance:
assert(context.templates.contains(target.second));
return context.templates[target.second];
default:
// We should never get here
assert(false);
static JSON placeholder{nullptr};
static Pointer placeholder;
return placeholder;
}
}

auto target_location(const sourcemeta::jsontoolkit::SchemaCompilerTarget
&target) -> const sourcemeta::jsontoolkit::Pointer & {
auto target_instance(
const sourcemeta::jsontoolkit::SchemaCompilerTarget &target,
const sourcemeta::jsontoolkit::JSON &instance,
EvaluationContext &context) -> const sourcemeta::jsontoolkit::JSON & {
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;
}
// Follow the actual target location on the instance
return get(instance, target_location(target, context));
}

auto callback_noop(
Expand Down Expand Up @@ -94,15 +93,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{target_instance(assertion.target, instance)};
const auto &target{target_instance(assertion.target, instance, context)};
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{target_instance(assertion.target, instance)};
const auto &target{target_instance(assertion.target, instance, context)};
result = target.type() == value;
} else if (std::holds_alternative<SchemaCompilerLogicalOr>(step)) {
const auto &logical{std::get<SchemaCompilerLogicalOr>(step)};
Expand Down Expand Up @@ -151,13 +150,13 @@ auto evaluate_step(

const auto &annotation{std::get<SchemaCompilerAnnotationPublic>(step)};
EVALUATE_CONDITION_GUARD(annotation.condition, instance);
const auto &instance_location{target_location(annotation.target)};
const auto &instance_location{target_location(annotation.target, context)};
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);
const auto &instance_location{target_location(annotation.target)};
const auto &instance_location{target_location(annotation.target, context)};
context.annotate(instance_location, annotation.evaluation_path,
annotation.value);

Expand Down
5 changes: 5 additions & 0 deletions src/jsonschema/compile_json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ auto target_to_json(const sourcemeta::jsontoolkit::SchemaCompilerTarget &target)
result.assign("type", JSON{"instance"});
result.assign("location", JSON{to_string(target.second)});
return result;
case SchemaCompilerTargetType::TemplateInstance:
result.assign("category", JSON{"target"});
result.assign("type", JSON{"template-instance"});
result.assign("location", JSON{to_string(target.second)});
return result;
default:
// We should never get here
assert(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ using SchemaCompilerValueType = JSON::Type;
/// Represents a type of compiler step target
enum class SchemaCompilerTargetType {
/// An static instance literal
Instance
Instance,

/// A pointer to an instance
TemplateInstance
};

/// @ingroup jsonschema
Expand Down
33 changes: 33 additions & 0 deletions test/jsonschema/jsonschema_compile_json_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -719,3 +719,36 @@ TEST(JSONSchema_compile_json, private_annotation_with_condition) {

EXPECT_EQ(result, expected);
}

TEST(JSONSchema_compile_json, target_instance_template) {
using namespace sourcemeta::jsontoolkit;
const SchemaCompilerTemplate steps{SchemaCompilerAssertionDefines{
{SchemaCompilerTargetType::TemplateInstance, {"xxx"}},
Pointer{},
"#",
SchemaCompilerValueString{"foo"},
{}}};

const JSON result{to_json(steps)};
const JSON expected{parse(R"EOF([
{
"category": "assertion",
"type": "defines",
"keywordLocation": "",
"absoluteKeywordLocation": "#",
"target": {
"category": "target",
"location": "/xxx",
"type": "template-instance"
},
"value": {
"category": "value",
"type": "string",
"value": "foo"
},
"condition": []
}
])EOF")};

EXPECT_EQ(result, expected);
}

0 comments on commit 8c62eab

Please sign in to comment.