Skip to content

Commit bac3ea7

Browse files
authored
Implement disallow for Draft 3 (#781)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent cb26a0b commit bac3ea7

2 files changed

Lines changed: 100 additions & 8 deletions

File tree

src/compiler/default_compiler_draft3.h

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,30 @@ auto properties_as_loop(const Context &context,
389389
}));
390390
}
391391

392+
auto draft3_set_type_bits(const std::string &name, ValueTypes &types) -> bool {
393+
using sourcemeta::core::JSON;
394+
if (name == "null") {
395+
types.set(std::to_underlying(JSON::Type::Null));
396+
} else if (name == "boolean") {
397+
types.set(std::to_underlying(JSON::Type::Boolean));
398+
} else if (name == "object") {
399+
types.set(std::to_underlying(JSON::Type::Object));
400+
} else if (name == "array") {
401+
types.set(std::to_underlying(JSON::Type::Array));
402+
} else if (name == "integer") {
403+
types.set(std::to_underlying(JSON::Type::Integer));
404+
} else if (name == "string") {
405+
types.set(std::to_underlying(JSON::Type::String));
406+
} else if (name == "number") {
407+
types.set(std::to_underlying(JSON::Type::Real));
408+
types.set(std::to_underlying(JSON::Type::Integer));
409+
types.set(std::to_underlying(JSON::Type::Decimal));
410+
} else {
411+
return false;
412+
}
413+
return true;
414+
}
415+
392416
auto is_integer_type_check(const Instruction &instruction) -> bool {
393417
return (instruction.type == InstructionIndex::AssertionType ||
394418
instruction.type == InstructionIndex::AssertionTypeStrict) &&
@@ -2151,13 +2175,83 @@ auto compiler_draft3_validation_type(const Context &context,
21512175
return {};
21522176
}
21532177

2154-
auto compiler_draft3_validation_disallow(const Context &,
2178+
auto compiler_draft3_validation_disallow(const Context &context,
21552179
const SchemaContext &schema_context,
2156-
const DynamicContext &,
2180+
const DynamicContext &dynamic_context,
21572181
const Instructions &) -> Instructions {
2158-
throw sourcemeta::blaze::CompilerError(
2159-
schema_context.base, to_pointer(schema_context.relative_pointer),
2160-
"Draft 3 disallow compilation is not yet implemented");
2182+
const auto &value{schema_context.schema.at(dynamic_context.keyword)};
2183+
2184+
const auto contains_any{
2185+
(value.is_string() && value.to_string() == "any") ||
2186+
(value.is_array() &&
2187+
std::ranges::any_of(value.as_array(), [](const auto &element) {
2188+
return element.is_string() && element.to_string() == "any";
2189+
}))};
2190+
if (contains_any) {
2191+
return {make(sourcemeta::blaze::InstructionIndex::AssertionFail, context,
2192+
schema_context, dynamic_context, ValueNone{})};
2193+
}
2194+
2195+
ValueTypes types{};
2196+
Instructions subschema_nots;
2197+
2198+
if (value.is_string()) {
2199+
draft3_set_type_bits(value.to_string(), types);
2200+
} else if (value.is_array()) {
2201+
for (std::uint64_t index = 0; index < value.size(); index++) {
2202+
const auto &element{value.at(index)};
2203+
if (element.is_string()) {
2204+
draft3_set_type_bits(element.to_string(), types);
2205+
} else if (element.is_object()) {
2206+
sourcemeta::core::WeakPointer index_suffix;
2207+
index_suffix.push_back(index);
2208+
const auto element_uri{
2209+
sourcemeta::core::to_uri(
2210+
schema_context.relative_pointer.concat(index_suffix),
2211+
schema_context.base)
2212+
.canonicalize()
2213+
.recompose()};
2214+
2215+
auto inner_instructions{
2216+
compile(context, schema_context, relative_dynamic_context(),
2217+
sourcemeta::core::empty_weak_pointer,
2218+
sourcemeta::core::empty_weak_pointer, element_uri)};
2219+
2220+
const auto element_relative_pointer{
2221+
schema_context.relative_pointer.concat(index_suffix)};
2222+
const SchemaContext element_schema_context{
2223+
.relative_pointer = element_relative_pointer,
2224+
.schema = schema_context.schema,
2225+
.vocabularies = schema_context.vocabularies,
2226+
.base = schema_context.base,
2227+
.is_property_name = schema_context.is_property_name};
2228+
2229+
const auto element_base_schema_location{
2230+
sourcemeta::blaze::make_weak_pointer(dynamic_context.keyword,
2231+
index)};
2232+
const DynamicContext element_dynamic_context{
2233+
.keyword = KEYWORD_EMPTY,
2234+
.base_schema_location = element_base_schema_location,
2235+
.base_instance_location = dynamic_context.base_instance_location};
2236+
2237+
subschema_nots.push_back(
2238+
make(sourcemeta::blaze::InstructionIndex::LogicalNot, context,
2239+
element_schema_context, element_dynamic_context, ValueNone{},
2240+
std::move(inner_instructions)));
2241+
}
2242+
}
2243+
}
2244+
2245+
Instructions result;
2246+
if (types.any()) {
2247+
result.push_back(
2248+
make(sourcemeta::blaze::InstructionIndex::AssertionNotTypeStrictAny,
2249+
context, schema_context, dynamic_context, types));
2250+
}
2251+
for (auto &&instruction : subschema_nots) {
2252+
result.push_back(std::move(instruction));
2253+
}
2254+
return result;
21612255
}
21622256

21632257
auto compiler_draft3_applicator_extends(const Context &context,

test/evaluator/officialsuite.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,7 @@ int main(int argc, char **argv) {
418418

419419
// Draft 3
420420
register_tests("draft3", "JSONSchemaOfficialSuite_Draft3",
421-
"http://json-schema.org/draft-03/schema#",
422-
// TODO: Enable all tests
423-
{"disallow"});
421+
"http://json-schema.org/draft-03/schema#", {});
424422
register_tests(std::filesystem::path{"draft3"} / "optional",
425423
"JSONSchemaOfficialSuite_Draft3_Optional",
426424
"http://json-schema.org/draft-03/schema#", {});

0 commit comments

Comments
 (0)