diff --git a/DEPENDENCIES b/DEPENDENCIES index 2be41931..be9bbe08 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,4 +1,4 @@ vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02 -core https://github.com/sourcemeta/core 7745054cc2334341799207eabd6cc13986023db8 -blaze https://github.com/sourcemeta/blaze 93f98104ac0d2a62b3e0023077818cc7511fb6da +core https://github.com/sourcemeta/core ebd90cf348ed4700180f902a8af11068d7aece96 +blaze https://github.com/sourcemeta/blaze 36e8c64529424ff590ddd9e17e23f0c9422c5f30 bootstrap https://github.com/twbs/bootstrap 1a6fdfae6be09b09eaced8f0e442ca6f7680a61e diff --git a/src/compiler/compiler.cc b/src/compiler/compiler.cc index a589c0ec..1938cd47 100644 --- a/src/compiler/compiler.cc +++ b/src/compiler/compiler.cc @@ -12,9 +12,11 @@ #include // std::true_type static auto transformer_callback_noop( - const sourcemeta::core::Pointer &, const std::string_view, - const std::string_view, - const sourcemeta::blaze::SchemaTransformRule::Result &, + [[maybe_unused]] const sourcemeta::core::Pointer &pointer, + [[maybe_unused]] const std::string_view name, + [[maybe_unused]] const std::string_view message, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result, [[maybe_unused]] const bool applied) -> void { assert(applied); } diff --git a/src/compiler/encoding.h b/src/compiler/encoding.h index 557bcd85..c0a0b7fc 100644 --- a/src/compiler/encoding.h +++ b/src/compiler/encoding.h @@ -13,7 +13,7 @@ inline auto make_resolver(const sourcemeta::blaze::SchemaResolver &fallback) return [&fallback](std::string_view identifier) -> sourcemeta::blaze::SchemaResolverResult { if (identifier == ENCODING_V1) { - static const auto schema{sourcemeta::core::parse_json(R"JSON({ + static const auto SCHEMA{sourcemeta::core::parse_json(R"JSON({ "$id": "tag:sourcemeta.com,2024:jsonbinpack/encoding/v1", "$schema": "https://json-schema.org/draft/2020-12/schema", "$vocabulary": { @@ -21,10 +21,10 @@ inline auto make_resolver(const sourcemeta::blaze::SchemaResolver &fallback) "tag:sourcemeta.com,2024:jsonbinpack/encoding/v1": true } })JSON")}; - return schema; - } else { - return fallback(identifier); + return SCHEMA; } + + return fallback(identifier); }; } diff --git a/src/compiler/mapper/enum_8_bit.h b/src/compiler/mapper/enum_8_bit.h index 125d656a..1126c44c 100644 --- a/src/compiler/mapper/enum_8_bit.h +++ b/src/compiler/mapper/enum_8_bit.h @@ -7,12 +7,13 @@ class Enum8Bit final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -23,9 +24,10 @@ class Enum8Bit final : public sourcemeta::blaze::SchemaTransformRule { sourcemeta::core::is_byte(schema.at("enum").size() - 1); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto options = sourcemeta::core::JSON::make_object(); options.assign("choices", schema.at("enum")); make_encoding(schema, "BYTE_CHOICE_INDEX", options); diff --git a/src/compiler/mapper/enum_8_bit_top_level.h b/src/compiler/mapper/enum_8_bit_top_level.h index 01daa08e..756e3e4a 100644 --- a/src/compiler/mapper/enum_8_bit_top_level.h +++ b/src/compiler/mapper/enum_8_bit_top_level.h @@ -7,12 +7,13 @@ class Enum8BitTopLevel final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -23,9 +24,10 @@ class Enum8BitTopLevel final : public sourcemeta::blaze::SchemaTransformRule { sourcemeta::core::is_byte(schema.at("enum").size() - 1); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto options = sourcemeta::core::JSON::make_object(); options.assign("choices", schema.at("enum")); make_encoding(schema, "TOP_LEVEL_BYTE_CHOICE_INDEX", options); diff --git a/src/compiler/mapper/enum_arbitrary.h b/src/compiler/mapper/enum_arbitrary.h index 0ba1d22c..7fcca2bf 100644 --- a/src/compiler/mapper/enum_arbitrary.h +++ b/src/compiler/mapper/enum_arbitrary.h @@ -8,12 +8,13 @@ class EnumArbitrary final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -24,9 +25,10 @@ class EnumArbitrary final : public sourcemeta::blaze::SchemaTransformRule { !sourcemeta::core::is_byte(schema.at("enum").size() - 1); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto options = sourcemeta::core::JSON::make_object(); options.assign("choices", schema.at("enum")); make_encoding(schema, "LARGE_CHOICE_INDEX", options); diff --git a/src/compiler/mapper/enum_singleton.h b/src/compiler/mapper/enum_singleton.h index 49aa1ae4..7fd342fe 100644 --- a/src/compiler/mapper/enum_singleton.h +++ b/src/compiler/mapper/enum_singleton.h @@ -7,12 +7,13 @@ class EnumSingleton final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -21,9 +22,10 @@ class EnumSingleton final : public sourcemeta::blaze::SchemaTransformRule { schema.at("enum").is_array() && schema.at("enum").size() == 1; } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto options = sourcemeta::core::JSON::make_object(); options.assign("value", schema.at("enum").at(0)); make_encoding(schema, "CONST_NONE", options); diff --git a/src/compiler/mapper/integer_bounded_8_bit.h b/src/compiler/mapper/integer_bounded_8_bit.h index 1683d3d7..242f9de9 100644 --- a/src/compiler/mapper/integer_bounded_8_bit.h +++ b/src/compiler/mapper/integer_bounded_8_bit.h @@ -7,12 +7,13 @@ class IntegerBounded8Bit final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -25,9 +26,10 @@ class IntegerBounded8Bit final : public sourcemeta::blaze::SchemaTransformRule { !schema.defines("multipleOf"); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto minimum = schema.at("minimum"); auto maximum = schema.at("maximum"); auto options = sourcemeta::core::JSON::make_object(); diff --git a/src/compiler/mapper/integer_bounded_greater_than_8_bit.h b/src/compiler/mapper/integer_bounded_greater_than_8_bit.h index c5af171b..035e0ea6 100644 --- a/src/compiler/mapper/integer_bounded_greater_than_8_bit.h +++ b/src/compiler/mapper/integer_bounded_greater_than_8_bit.h @@ -9,12 +9,13 @@ class IntegerBoundedGreaterThan8Bit final [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -27,9 +28,10 @@ class IntegerBoundedGreaterThan8Bit final !schema.defines("multipleOf"); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto minimum = schema.at("minimum"); auto options = sourcemeta::core::JSON::make_object(); options.assign("minimum", std::move(minimum)); diff --git a/src/compiler/mapper/integer_bounded_multiplier_8_bit.h b/src/compiler/mapper/integer_bounded_multiplier_8_bit.h index 917800b1..593b72d2 100644 --- a/src/compiler/mapper/integer_bounded_multiplier_8_bit.h +++ b/src/compiler/mapper/integer_bounded_multiplier_8_bit.h @@ -9,12 +9,13 @@ class IntegerBoundedMultiplier8Bit final [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { if (location.dialect != "https://json-schema.org/draft/2020-12/schema" || !vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -33,9 +34,10 @@ class IntegerBoundedMultiplier8Bit final schema.at("multipleOf").to_integer())); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto minimum = schema.at("minimum"); auto maximum = schema.at("maximum"); auto multiplier = schema.at("multipleOf"); diff --git a/src/compiler/mapper/integer_bounded_multiplier_greater_than_8_bit.h b/src/compiler/mapper/integer_bounded_multiplier_greater_than_8_bit.h index 9bab917e..63805890 100644 --- a/src/compiler/mapper/integer_bounded_multiplier_greater_than_8_bit.h +++ b/src/compiler/mapper/integer_bounded_multiplier_greater_than_8_bit.h @@ -9,12 +9,13 @@ class IntegerBoundedMultiplierGreaterThan8Bit final [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { if (location.dialect != "https://json-schema.org/draft/2020-12/schema" || !vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -33,9 +34,10 @@ class IntegerBoundedMultiplierGreaterThan8Bit final schema.at("multipleOf").to_integer())); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto minimum = schema.at("minimum"); auto multiplier = schema.at("multipleOf"); auto options = sourcemeta::core::JSON::make_object(); diff --git a/src/compiler/mapper/integer_lower_bound.h b/src/compiler/mapper/integer_lower_bound.h index c0a00f28..c2a24dd4 100644 --- a/src/compiler/mapper/integer_lower_bound.h +++ b/src/compiler/mapper/integer_lower_bound.h @@ -7,12 +7,13 @@ class IntegerLowerBound final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -23,9 +24,10 @@ class IntegerLowerBound final : public sourcemeta::blaze::SchemaTransformRule { !schema.defines("multipleOf"); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto minimum = schema.at("minimum"); auto options = sourcemeta::core::JSON::make_object(); options.assign("minimum", std::move(minimum)); diff --git a/src/compiler/mapper/integer_lower_bound_multiplier.h b/src/compiler/mapper/integer_lower_bound_multiplier.h index a6d7c606..2388c4de 100644 --- a/src/compiler/mapper/integer_lower_bound_multiplier.h +++ b/src/compiler/mapper/integer_lower_bound_multiplier.h @@ -9,12 +9,13 @@ class IntegerLowerBoundMultiplier final [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -25,9 +26,10 @@ class IntegerLowerBoundMultiplier final schema.defines("multipleOf") && schema.at("multipleOf").is_integer(); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto minimum = schema.at("minimum"); auto multiplier = schema.at("multipleOf"); auto options = sourcemeta::core::JSON::make_object(); diff --git a/src/compiler/mapper/integer_unbound.h b/src/compiler/mapper/integer_unbound.h index 3d9c85fb..f1886b44 100644 --- a/src/compiler/mapper/integer_unbound.h +++ b/src/compiler/mapper/integer_unbound.h @@ -7,12 +7,13 @@ class IntegerUnbound final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -23,9 +24,10 @@ class IntegerUnbound final : public sourcemeta::blaze::SchemaTransformRule { !schema.defines("multipleOf"); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto options = sourcemeta::core::JSON::make_object(); options.assign("multiplier", sourcemeta::core::JSON{1}); make_encoding(schema, "ARBITRARY_MULTIPLE_ZIGZAG_VARINT", options); diff --git a/src/compiler/mapper/integer_unbound_multiplier.h b/src/compiler/mapper/integer_unbound_multiplier.h index 0d6f881a..b7c638e9 100644 --- a/src/compiler/mapper/integer_unbound_multiplier.h +++ b/src/compiler/mapper/integer_unbound_multiplier.h @@ -9,12 +9,13 @@ class IntegerUnboundMultiplier final [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -25,9 +26,10 @@ class IntegerUnboundMultiplier final schema.defines("multipleOf") && schema.at("multipleOf").is_integer(); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto multiplier = schema.at("multipleOf"); auto options = sourcemeta::core::JSON::make_object(); options.assign("multiplier", std::move(multiplier)); diff --git a/src/compiler/mapper/integer_upper_bound.h b/src/compiler/mapper/integer_upper_bound.h index 7a0cd159..ddb89a9b 100644 --- a/src/compiler/mapper/integer_upper_bound.h +++ b/src/compiler/mapper/integer_upper_bound.h @@ -7,12 +7,13 @@ class IntegerUpperBound final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -23,9 +24,10 @@ class IntegerUpperBound final : public sourcemeta::blaze::SchemaTransformRule { !schema.defines("multipleOf"); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto maximum = schema.at("maximum"); auto options = sourcemeta::core::JSON::make_object(); options.assign("maximum", std::move(maximum)); diff --git a/src/compiler/mapper/integer_upper_bound_multiplier.h b/src/compiler/mapper/integer_upper_bound_multiplier.h index 3c8cec87..3401d045 100644 --- a/src/compiler/mapper/integer_upper_bound_multiplier.h +++ b/src/compiler/mapper/integer_upper_bound_multiplier.h @@ -9,12 +9,13 @@ class IntegerUpperBoundMultiplier final [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -25,9 +26,10 @@ class IntegerUpperBoundMultiplier final schema.defines("multipleOf") && schema.at("multipleOf").is_integer(); } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { auto maximum = schema.at("maximum"); auto multiplier = schema.at("multipleOf"); auto options = sourcemeta::core::JSON::make_object(); diff --git a/src/compiler/mapper/number_arbitrary.h b/src/compiler/mapper/number_arbitrary.h index 1de719b4..e48c096a 100644 --- a/src/compiler/mapper/number_arbitrary.h +++ b/src/compiler/mapper/number_arbitrary.h @@ -7,12 +7,13 @@ class NumberArbitrary final : public sourcemeta::blaze::SchemaTransformRule { [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &, + [[maybe_unused]] const sourcemeta::core::JSON &root, const sourcemeta::blaze::SchemaVocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &, + [[maybe_unused]] const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const + [[maybe_unused]] const sourcemeta::blaze::SchemaWalker &walker, + [[maybe_unused]] const sourcemeta::blaze::SchemaResolver &resolver, + [[maybe_unused]] const bool is_metaschema) const -> sourcemeta::blaze::SchemaTransformRule::Result override { return location.dialect == "https://json-schema.org/draft/2020-12/schema" && vocabularies.contains(sourcemeta::blaze::SchemaVocabularies::Known:: @@ -21,9 +22,10 @@ class NumberArbitrary final : public sourcemeta::blaze::SchemaTransformRule { schema.at("type").to_string() == "number"; } - auto transform(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaTransformRule::Result &) const - -> void override { + auto transform( + sourcemeta::core::JSON &schema, + [[maybe_unused]] const sourcemeta::blaze::SchemaTransformRule::Result + &result) const -> void override { make_encoding(schema, "DOUBLE_VARINT_TUPLE", sourcemeta::core::JSON::make_object()); } diff --git a/src/runtime/cache.cc b/src/runtime/cache.cc index ce367951..def0ee80 100644 --- a/src/runtime/cache.cc +++ b/src/runtime/cache.cc @@ -21,42 +21,42 @@ auto Cache::record(const sourcemeta::core::JSON::String &value, } // Remove the oldest entries to make space if needed - while (!this->data.empty() && - this->byte_size + value_size >= MAXIMUM_BYTE_SIZE) { + while (!this->data_.empty() && + this->byte_size_ + value_size >= MAXIMUM_BYTE_SIZE) { this->remove_oldest(); } - auto result{this->data.insert({std::make_pair(value, type), offset})}; + auto result{this->data_.insert({std::make_pair(value, type), offset})}; if (result.second) { - this->byte_size += value_size; - this->order.emplace(offset, result.first->first); + this->byte_size_ += value_size; + this->order_.emplace(offset, result.first->first); } else if (offset > result.first->second) { - this->order.erase(result.first->second); + this->order_.erase(result.first->second); // If the string already exists, we want to // bump the offset for locality purposes. result.first->second = offset; - this->order.emplace(offset, result.first->first); + this->order_.emplace(offset, result.first->first); } // Otherwise we are doing something wrong - assert(this->order.size() == this->data.size()); + assert(this->order_.size() == this->data_.size()); } auto Cache::remove_oldest() -> void { - assert(!this->data.empty()); + assert(!this->data_.empty()); // std::map are by definition ordered by key, // so the begin iterator points to the entry // with the lowest offset, a.k.a. the oldest. - const auto iterator{this->order.cbegin()}; - this->byte_size -= iterator->second.get().first.size(); - this->data.erase(iterator->second.get()); - this->order.erase(iterator); + const auto iterator{this->order_.cbegin()}; + this->byte_size_ -= iterator->second.get().first.size(); + this->data_.erase(iterator->second.get()); + this->order_.erase(iterator); } auto Cache::find(const sourcemeta::core::JSON::String &value, const Type type) const -> std::optional { - const auto result{this->data.find(std::make_pair(value, type))}; - if (result == this->data.cend()) { + const auto result{this->data_.find(std::make_pair(value, type))}; + if (result == this->data_.cend()) { return std::nullopt; } diff --git a/src/runtime/decoder_any.cc b/src/runtime/decoder_any.cc index 4cd6f569..806d67b9 100644 --- a/src/runtime/decoder_any.cc +++ b/src/runtime/decoder_any.cc @@ -34,11 +34,11 @@ auto Decoder::TOP_LEVEL_BYTE_CHOICE_INDEX( assert(sourcemeta::core::is_byte(options.choices.size())); if (!this->has_more_data()) { return options.choices.front(); - } else { - const std::uint16_t index{static_cast(this->get_byte() + 1)}; - assert(options.choices.size() > index); - return options.choices[index]; } + + const std::uint16_t index{static_cast(this->get_byte() + 1)}; + assert(options.choices.size() > index); + return options.choices[index]; } auto Decoder::CONST_NONE(const struct CONST_NONE &options) @@ -47,12 +47,13 @@ auto Decoder::CONST_NONE(const struct CONST_NONE &options) } auto Decoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( - const struct ANY_PACKED_TYPE_TAG_BYTE_PREFIX &) -> sourcemeta::core::JSON { + [[maybe_unused]] const struct ANY_PACKED_TYPE_TAG_BYTE_PREFIX &options) + -> sourcemeta::core::JSON { using namespace internal::ANY_PACKED_TYPE_TAG_BYTE_PREFIX; const std::uint8_t byte{this->get_byte()}; const std::uint8_t type{ - static_cast(byte & (0xff >> subtype_size))}; - const std::uint8_t subtype{static_cast(byte >> type_size)}; + static_cast(byte & (0xff >> SUBTYPE_SIZE))}; + const std::uint8_t subtype{static_cast(byte >> TYPE_SIZE)}; if (type == TYPE_OTHER) { switch (subtype) { @@ -99,9 +100,9 @@ auto Decoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( case TYPE_SHARED_STRING: { const auto length = subtype == 0 ? this->get_varint() - 1 + - static_cast( - sourcemeta::core::uint_max<5>) * - 2 + (static_cast( + sourcemeta::core::uint_max<5>) * + 2) : subtype - 1; const std::uint64_t position{this->position()}; const std::uint64_t current{this->rewind(this->get_varint(), position)}; diff --git a/src/runtime/decoder_integer.cc b/src/runtime/decoder_integer.cc index d4c15bf7..427f1b46 100644 --- a/src/runtime/decoder_integer.cc +++ b/src/runtime/decoder_integer.cc @@ -21,14 +21,14 @@ auto Decoder::BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( // corresponds to a valid 64-bit signed integer. return sourcemeta::core::JSON{static_cast( (byte * options.multiplier) + closest_minimum_multiple)}; - } else { - const std::uint64_t closest_minimum_multiple{ - sourcemeta::core::abs(closest_minimum) * options.multiplier}; - // We trust the encoder that the data we are seeing - // corresponds to a valid 64-bit signed integer. - return sourcemeta::core::JSON{static_cast( - (byte * options.multiplier) - closest_minimum_multiple)}; } + + const std::uint64_t closest_minimum_multiple{ + sourcemeta::core::abs(closest_minimum) * options.multiplier}; + // We trust the encoder that the data we are seeing + // corresponds to a valid 64-bit signed integer. + return sourcemeta::core::JSON{static_cast( + (byte * options.multiplier) - closest_minimum_multiple)}; } auto Decoder::FLOOR_MULTIPLE_ENUM_VARINT( @@ -44,14 +44,14 @@ auto Decoder::FLOOR_MULTIPLE_ENUM_VARINT( // corresponds to a valid 64-bit signed integer. return sourcemeta::core::JSON{static_cast( (this->get_varint() * options.multiplier) + closest_minimum_multiple)}; - } else { - const std::uint64_t closest_minimum_multiple{ - sourcemeta::core::abs(closest_minimum) * options.multiplier}; - // We trust the encoder that the data we are seeing - // corresponds to a valid 64-bit signed integer. - return sourcemeta::core::JSON{static_cast( - (this->get_varint() * options.multiplier) - closest_minimum_multiple)}; } + + const std::uint64_t closest_minimum_multiple{ + sourcemeta::core::abs(closest_minimum) * options.multiplier}; + // We trust the encoder that the data we are seeing + // corresponds to a valid 64-bit signed integer. + return sourcemeta::core::JSON{static_cast( + (this->get_varint() * options.multiplier) - closest_minimum_multiple)}; } auto Decoder::ROOF_MULTIPLE_MIRROR_ENUM_VARINT( @@ -68,15 +68,15 @@ auto Decoder::ROOF_MULTIPLE_MIRROR_ENUM_VARINT( return sourcemeta::core::JSON{static_cast( -(static_cast(this->get_varint() * options.multiplier)) + static_cast(closest_maximum_multiple))}; - } else { - const std::uint64_t closest_maximum_multiple{ - sourcemeta::core::abs(closest_maximum) * options.multiplier}; - // We trust the encoder that the data we are seeing - // corresponds to a valid 64-bit signed integer. - return sourcemeta::core::JSON{static_cast( - -(static_cast(this->get_varint() * options.multiplier)) - - static_cast(closest_maximum_multiple))}; } + + const std::uint64_t closest_maximum_multiple{ + sourcemeta::core::abs(closest_maximum) * options.multiplier}; + // We trust the encoder that the data we are seeing + // corresponds to a valid 64-bit signed integer. + return sourcemeta::core::JSON{static_cast( + -(static_cast(this->get_varint() * options.multiplier)) - + static_cast(closest_maximum_multiple))}; } auto Decoder::ARBITRARY_MULTIPLE_ZIGZAG_VARINT( diff --git a/src/runtime/decoder_number.cc b/src/runtime/decoder_number.cc index 9d0a6869..2e55b87b 100644 --- a/src/runtime/decoder_number.cc +++ b/src/runtime/decoder_number.cc @@ -8,7 +8,8 @@ namespace sourcemeta::jsonbinpack { -auto Decoder::DOUBLE_VARINT_TUPLE(const struct DOUBLE_VARINT_TUPLE &) +auto Decoder::DOUBLE_VARINT_TUPLE( + [[maybe_unused]] const struct DOUBLE_VARINT_TUPLE &options) -> sourcemeta::core::JSON { #ifdef __clang__ #pragma clang fp reciprocal(off) diff --git a/src/runtime/decoder_string.cc b/src/runtime/decoder_string.cc index 76661deb..bcde8823 100644 --- a/src/runtime/decoder_string.cc +++ b/src/runtime/decoder_string.cc @@ -27,9 +27,9 @@ auto Decoder::FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED( const sourcemeta::core::JSON value{this->get_string_utf8(length)}; this->seek(current); return value; - } else { - return UTF8_STRING_NO_LENGTH({length}); } + + return UTF8_STRING_NO_LENGTH({length}); } auto Decoder::ROOF_VARINT_PREFIX_UTF8_STRING_SHARED( @@ -47,9 +47,9 @@ auto Decoder::ROOF_VARINT_PREFIX_UTF8_STRING_SHARED( const sourcemeta::core::JSON value{UTF8_STRING_NO_LENGTH({length})}; this->seek(current); return value; - } else { - return UTF8_STRING_NO_LENGTH({length}); } + + return UTF8_STRING_NO_LENGTH({length}); } auto Decoder::BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( @@ -69,13 +69,14 @@ auto Decoder::BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( const sourcemeta::core::JSON value{UTF8_STRING_NO_LENGTH({length})}; this->seek(current); return value; - } else { - return UTF8_STRING_NO_LENGTH({length}); } + + return UTF8_STRING_NO_LENGTH({length}); } auto Decoder::RFC3339_DATE_INTEGER_TRIPLET( - const struct RFC3339_DATE_INTEGER_TRIPLET &) -> sourcemeta::core::JSON { + [[maybe_unused]] const struct RFC3339_DATE_INTEGER_TRIPLET &options) + -> sourcemeta::core::JSON { const std::uint16_t year{this->get_word()}; const std::uint8_t month{this->get_byte()}; const std::uint8_t day{this->get_byte()}; @@ -110,9 +111,9 @@ auto Decoder::PREFIX_VARINT_LENGTH_STRING_SHARED( PREFIX_VARINT_LENGTH_STRING_SHARED(options)}; this->seek(current); return value; - } else { - return sourcemeta::core::JSON{this->get_string_utf8(prefix - 1)}; } + + return sourcemeta::core::JSON{this->get_string_utf8(prefix - 1)}; } } // namespace sourcemeta::jsonbinpack diff --git a/src/runtime/encoder_any.cc b/src/runtime/encoder_any.cc index 358696b4..6f97c019 100644 --- a/src/runtime/encoder_any.cc +++ b/src/runtime/encoder_any.cc @@ -30,7 +30,7 @@ auto Encoder::BYTE_CHOICE_INDEX(const sourcemeta::core::JSON &document, auto Encoder::LARGE_CHOICE_INDEX(const sourcemeta::core::JSON &document, const struct LARGE_CHOICE_INDEX &options) -> void { - assert(options.choices.size() > 0); + assert(!options.choices.empty()); const auto iterator{std::ranges::find_if( options.choices, [&document](const auto &choice) -> bool { return choice == document; })}; @@ -44,7 +44,7 @@ auto Encoder::LARGE_CHOICE_INDEX(const sourcemeta::core::JSON &document, auto Encoder::TOP_LEVEL_BYTE_CHOICE_INDEX( const sourcemeta::core::JSON &document, const struct TOP_LEVEL_BYTE_CHOICE_INDEX &options) -> void { - assert(options.choices.size() > 0); + assert(!options.choices.empty()); assert(sourcemeta::core::is_byte(options.choices.size())); const auto iterator{std::ranges::find_if( options.choices, @@ -60,38 +60,35 @@ auto Encoder::TOP_LEVEL_BYTE_CHOICE_INDEX( } auto Encoder::CONST_NONE( -#ifndef NDEBUG - const sourcemeta::core::JSON &document, const struct CONST_NONE &options) -#else - const sourcemeta::core::JSON &, const struct CONST_NONE &) -#endif - -> void { + [[maybe_unused]] const sourcemeta::core::JSON &document, + [[maybe_unused]] const struct CONST_NONE &options) -> void { assert(document == options.value); } auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( const sourcemeta::core::JSON &document, - const struct ANY_PACKED_TYPE_TAG_BYTE_PREFIX &) -> void { + [[maybe_unused]] const struct ANY_PACKED_TYPE_TAG_BYTE_PREFIX &options) + -> void { using namespace internal::ANY_PACKED_TYPE_TAG_BYTE_PREFIX; if (document.is_null()) { - this->put_byte(TYPE_OTHER | (SUBTYPE_NULL << type_size)); + this->put_byte(TYPE_OTHER | (SUBTYPE_NULL << TYPE_SIZE)); } else if (document.is_boolean()) { const std::uint8_t subtype{document.to_boolean() ? SUBTYPE_TRUE : SUBTYPE_FALSE}; this->put_byte(TYPE_OTHER | - static_cast(subtype << type_size)); + static_cast(subtype << TYPE_SIZE)); } else if (document.is_real() && document.is_integral()) { const auto value{document.as_integer()}; if (value >= 0 && sourcemeta::core::is_byte(value)) { this->put_byte(TYPE_OTHER | SUBTYPE_POSITIVE_REAL_INTEGER_BYTE - << type_size); + << TYPE_SIZE); this->put_byte(static_cast(value)); } else { - this->put_byte(TYPE_OTHER | SUBTYPE_NUMBER << type_size); + this->put_byte(TYPE_OTHER | SUBTYPE_NUMBER << TYPE_SIZE); this->DOUBLE_VARINT_TUPLE(document, {}); } } else if (document.is_real()) { - this->put_byte(TYPE_OTHER | SUBTYPE_NUMBER << type_size); + this->put_byte(TYPE_OTHER | SUBTYPE_NUMBER << TYPE_SIZE); this->DOUBLE_VARINT_TUPLE(document, {}); } else if (document.is_integer()) { const std::int64_t value{document.to_integer()}; @@ -105,7 +102,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( const std::uint8_t absolute_byte{static_cast(absolute)}; if (absolute < sourcemeta::core::uint_max<5>) { this->put_byte( - type | static_cast((absolute_byte + 1) << type_size)); + type | static_cast((absolute_byte + 1) << TYPE_SIZE)); } else { this->put_byte(type); this->put_byte(absolute_byte); @@ -114,7 +111,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( const std::uint8_t subtype{is_positive ? SUBTYPE_POSITIVE_INTEGER : SUBTYPE_NEGATIVE_INTEGER}; this->put_byte(TYPE_OTHER | - static_cast(subtype << type_size)); + static_cast(subtype << TYPE_SIZE)); this->put_varint(absolute); } } else if (document.is_string()) { @@ -125,7 +122,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( const std::uint8_t type{shared.has_value() ? TYPE_SHARED_STRING : TYPE_STRING}; this->put_byte( - static_cast(type | ((size + 1) << type_size))); + static_cast(type | ((size + 1) << TYPE_SIZE))); if (shared.has_value()) { this->put_varint(this->position() - shared.value()); } else { @@ -139,7 +136,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( !shared.has_value()) { this->put_byte(static_cast( TYPE_LONG_STRING | - ((size - sourcemeta::core::uint_max<5>) << type_size))); + ((size - sourcemeta::core::uint_max<5>) << TYPE_SIZE))); this->put_string_utf8(value, size); } else if (size >= 2 << (SUBTYPE_LONG_STRING_BASE_EXPONENT_7 - 1) && !shared.has_value()) { @@ -147,7 +144,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( size, 2, SUBTYPE_LONG_STRING_BASE_EXPONENT_7, SUBTYPE_LONG_STRING_BASE_EXPONENT_10)}; this->put_byte( - static_cast(TYPE_OTHER | (exponent << type_size))); + static_cast(TYPE_OTHER | (exponent << TYPE_SIZE))); this->put_varint(size - static_cast(2 << (exponent - 1))); this->put_string_utf8(value, size); } else { @@ -159,9 +156,10 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( } // If we got this far, the string is at least a certain length - return FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED( + FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED( document, {static_cast(sourcemeta::core::uint_max<5> * 2)}); + return; } } else if (document.is_array()) { const auto size{document.size()}; @@ -170,7 +168,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( this->put_varint(size - sourcemeta::core::uint_max<5>); } else { this->put_byte( - static_cast(TYPE_ARRAY | ((size + 1) << type_size))); + static_cast(TYPE_ARRAY | ((size + 1) << TYPE_SIZE))); } Encoding encoding{ @@ -186,7 +184,7 @@ auto Encoder::ANY_PACKED_TYPE_TAG_BYTE_PREFIX( this->put_varint(size - sourcemeta::core::uint_max<5>); } else { this->put_byte( - static_cast(TYPE_OBJECT | ((size + 1) << type_size))); + static_cast(TYPE_OBJECT | ((size + 1) << TYPE_SIZE))); } Encoding key_encoding{ diff --git a/src/runtime/encoder_integer.cc b/src/runtime/encoder_integer.cc index c229f255..2a2ba79a 100644 --- a/src/runtime/encoder_integer.cc +++ b/src/runtime/encoder_integer.cc @@ -35,11 +35,11 @@ auto Encoder::FLOOR_MULTIPLE_ENUM_VARINT( assert(options.multiplier > 0); assert(sourcemeta::core::abs(value) % options.multiplier == 0); if (options.multiplier == 1) { - return this->put_varint( - static_cast(value - options.minimum)); + this->put_varint(static_cast(value - options.minimum)); + return; } - return this->put_varint( + this->put_varint( (static_cast(value) / options.multiplier) - static_cast(sourcemeta::core::divide_ceil( options.minimum, static_cast(options.multiplier)))); @@ -54,14 +54,13 @@ auto Encoder::ROOF_MULTIPLE_MIRROR_ENUM_VARINT( assert(options.multiplier > 0); assert(sourcemeta::core::abs(value) % options.multiplier == 0); if (options.multiplier == 1) { - return this->put_varint( - static_cast(options.maximum - value)); + this->put_varint(static_cast(options.maximum - value)); + return; } - return this->put_varint( - static_cast( - sourcemeta::core::divide_floor(options.maximum, options.multiplier)) - - (static_cast(value) / options.multiplier)); + this->put_varint(static_cast(sourcemeta::core::divide_floor( + options.maximum, options.multiplier)) - + (static_cast(value) / options.multiplier)); } auto Encoder::ARBITRARY_MULTIPLE_ZIGZAG_VARINT( diff --git a/src/runtime/encoder_number.cc b/src/runtime/encoder_number.cc index 2812f6d4..a1b499e7 100644 --- a/src/runtime/encoder_number.cc +++ b/src/runtime/encoder_number.cc @@ -7,8 +7,9 @@ namespace sourcemeta::jsonbinpack { -auto Encoder::DOUBLE_VARINT_TUPLE(const sourcemeta::core::JSON &document, - const struct DOUBLE_VARINT_TUPLE &) -> void { +auto Encoder::DOUBLE_VARINT_TUPLE( + const sourcemeta::core::JSON &document, + [[maybe_unused]] const struct DOUBLE_VARINT_TUPLE &options) -> void { assert(document.is_real()); const auto value{document.to_real()}; std::uint64_t point_position; diff --git a/src/runtime/encoder_string.cc b/src/runtime/encoder_string.cc index f7451669..dda419f9 100644 --- a/src/runtime/encoder_string.cc +++ b/src/runtime/encoder_string.cc @@ -98,7 +98,8 @@ auto Encoder::BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( auto Encoder::RFC3339_DATE_INTEGER_TRIPLET( const sourcemeta::core::JSON &document, - const struct RFC3339_DATE_INTEGER_TRIPLET &) -> void { + [[maybe_unused]] const struct RFC3339_DATE_INTEGER_TRIPLET &options) + -> void { assert(document.is_string()); const auto &value{document.to_string()}; assert(value.size() == 10); @@ -122,7 +123,8 @@ auto Encoder::RFC3339_DATE_INTEGER_TRIPLET( auto Encoder::PREFIX_VARINT_LENGTH_STRING_SHARED( const sourcemeta::core::JSON &document, - const struct PREFIX_VARINT_LENGTH_STRING_SHARED &) -> void { + [[maybe_unused]] const struct PREFIX_VARINT_LENGTH_STRING_SHARED &options) + -> void { assert(document.is_string()); const sourcemeta::core::JSON::String &value{document.to_string()}; diff --git a/src/runtime/include/sourcemeta/jsonbinpack/runtime_decoder.h b/src/runtime/include/sourcemeta/jsonbinpack/runtime_decoder.h index aabfec00..e30e3c7d 100644 --- a/src/runtime/include/sourcemeta/jsonbinpack/runtime_decoder.h +++ b/src/runtime/include/sourcemeta/jsonbinpack/runtime_decoder.h @@ -20,6 +20,9 @@ class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT Decoder : private InputStream { // The methods that implement individual encodings as considered private #ifndef DOXYGEN +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) #define DECLARE_ENCODING(name) \ auto name(const name &) -> sourcemeta::core::JSON; @@ -62,6 +65,7 @@ class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT Decoder : private InputStream { DECLARE_ENCODING(VARINT_TYPED_ARBITRARY_OBJECT) #undef DECLARE_ENCODING +// NOLINTEND(readability-identifier-naming) #endif }; diff --git a/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder.h b/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder.h index ebdb9d01..ccb2965c 100644 --- a/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder.h +++ b/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder.h @@ -22,6 +22,9 @@ class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT Encoder : private OutputStream { // The methods that implement individual encodings as considered private #ifndef DOXYGEN +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) #define DECLARE_ENCODING(name) \ auto name(const sourcemeta::core::JSON &document, const name &) -> void; @@ -64,6 +67,7 @@ class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT Encoder : private OutputStream { DECLARE_ENCODING(VARINT_TYPED_ARBITRARY_OBJECT) #undef DECLARE_ENCODING +// NOLINTEND(readability-identifier-naming) #endif private: diff --git a/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder_cache.h b/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder_cache.h index 79dc14d8..9d3e40c1 100644 --- a/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder_cache.h +++ b/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoder_cache.h @@ -36,10 +36,10 @@ class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT Cache { #if defined(_MSC_VER) #pragma warning(disable : 4251 4275) #endif - std::uint64_t byte_size{0}; + std::uint64_t byte_size_{0}; using Entry = std::pair; - std::map data; - std::map> order; + std::map data_; + std::map> order_; #if defined(_MSC_VER) #pragma warning(default : 4251 4275) #endif diff --git a/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoding.h b/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoding.h index f239e824..9c543e3a 100644 --- a/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoding.h +++ b/src/runtime/include/sourcemeta/jsonbinpack/runtime_encoding.h @@ -14,6 +14,10 @@ namespace sourcemeta::jsonbinpack { // Forward declarations for the sole purpose of being bale to define circular // structures #ifndef DOXYGEN +// The encoding names are the ones the JSON BinPack specification +// defines, so they keep their casing rather than following the C++ +// naming convention +// NOLINTBEGIN(readability-identifier-naming) struct BOUNDED_MULTIPLE_8BITS_ENUM_FIXED; struct FLOOR_MULTIPLE_ENUM_VARINT; struct ROOF_MULTIPLE_MIRROR_ENUM_VARINT; @@ -36,6 +40,7 @@ struct FLOOR_TYPED_ARRAY; struct ROOF_TYPED_ARRAY; struct FIXED_TYPED_ARBITRARY_OBJECT; struct VARINT_TYPED_ARBITRARY_OBJECT; +// NOLINTEND(readability-identifier-naming) #endif /// @ingroup runtime @@ -52,6 +57,11 @@ using Encoding = std::variant< BOUNDED_8BITS_TYPED_ARRAY, FLOOR_TYPED_ARRAY, ROOF_TYPED_ARRAY, FIXED_TYPED_ARBITRARY_OBJECT, VARINT_TYPED_ARBITRARY_OBJECT>; +// The encoding names are the ones the JSON BinPack specification +// defines, so they keep their casing rather than following the C++ +// naming convention +// NOLINTBEGIN(readability-identifier-naming) + /// @ingroup runtime /// @defgroup encoding_integer Integer Encodings /// @{ @@ -403,7 +413,7 @@ struct CONST_NONE { struct ANY_PACKED_TYPE_TAG_BYTE_PREFIX {}; #ifndef DOXYGEN namespace internal::ANY_PACKED_TYPE_TAG_BYTE_PREFIX { -constexpr auto type_size = 3; +constexpr auto TYPE_SIZE = 3; constexpr std::uint8_t TYPE_SHARED_STRING = 0b00000000; constexpr std::uint8_t TYPE_STRING = 0b00000001; constexpr std::uint8_t TYPE_LONG_STRING = 0b00000010; @@ -412,18 +422,18 @@ constexpr std::uint8_t TYPE_ARRAY = 0b00000100; constexpr std::uint8_t TYPE_POSITIVE_INTEGER_BYTE = 0b00000101; constexpr std::uint8_t TYPE_NEGATIVE_INTEGER_BYTE = 0b00000110; constexpr std::uint8_t TYPE_OTHER = 0b00000111; -static_assert(TYPE_SHARED_STRING <= sourcemeta::core::uint_max); -static_assert(TYPE_STRING <= sourcemeta::core::uint_max); -static_assert(TYPE_LONG_STRING <= sourcemeta::core::uint_max); -static_assert(TYPE_OBJECT <= sourcemeta::core::uint_max); -static_assert(TYPE_ARRAY <= sourcemeta::core::uint_max); +static_assert(TYPE_SHARED_STRING <= sourcemeta::core::uint_max); +static_assert(TYPE_STRING <= sourcemeta::core::uint_max); +static_assert(TYPE_LONG_STRING <= sourcemeta::core::uint_max); +static_assert(TYPE_OBJECT <= sourcemeta::core::uint_max); +static_assert(TYPE_ARRAY <= sourcemeta::core::uint_max); static_assert(TYPE_POSITIVE_INTEGER_BYTE <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); static_assert(TYPE_NEGATIVE_INTEGER_BYTE <= - sourcemeta::core::uint_max); -static_assert(TYPE_OTHER <= sourcemeta::core::uint_max); + sourcemeta::core::uint_max); +static_assert(TYPE_OTHER <= sourcemeta::core::uint_max); -constexpr auto subtype_size = 5; +constexpr auto SUBTYPE_SIZE = 5; constexpr std::uint8_t SUBTYPE_FALSE = 0b00000000; constexpr std::uint8_t SUBTYPE_TRUE = 0b00000001; constexpr std::uint8_t SUBTYPE_NULL = 0b00000010; @@ -436,24 +446,24 @@ constexpr std::uint8_t SUBTYPE_LONG_STRING_BASE_EXPONENT_8 = 0b00001000; constexpr std::uint8_t SUBTYPE_LONG_STRING_BASE_EXPONENT_9 = 0b00001001; constexpr std::uint8_t SUBTYPE_LONG_STRING_BASE_EXPONENT_10 = 0b00001010; -static_assert(SUBTYPE_FALSE <= sourcemeta::core::uint_max); -static_assert(SUBTYPE_TRUE <= sourcemeta::core::uint_max); -static_assert(SUBTYPE_NULL <= sourcemeta::core::uint_max); +static_assert(SUBTYPE_FALSE <= sourcemeta::core::uint_max); +static_assert(SUBTYPE_TRUE <= sourcemeta::core::uint_max); +static_assert(SUBTYPE_NULL <= sourcemeta::core::uint_max); static_assert(SUBTYPE_POSITIVE_INTEGER <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); static_assert(SUBTYPE_NEGATIVE_INTEGER <= - sourcemeta::core::uint_max); -static_assert(SUBTYPE_NUMBER <= sourcemeta::core::uint_max); + sourcemeta::core::uint_max); +static_assert(SUBTYPE_NUMBER <= sourcemeta::core::uint_max); static_assert(SUBTYPE_POSITIVE_REAL_INTEGER_BYTE <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); static_assert(SUBTYPE_LONG_STRING_BASE_EXPONENT_7 <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); static_assert(SUBTYPE_LONG_STRING_BASE_EXPONENT_8 <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); static_assert(SUBTYPE_LONG_STRING_BASE_EXPONENT_9 <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); static_assert(SUBTYPE_LONG_STRING_BASE_EXPONENT_10 <= - sourcemeta::core::uint_max); + sourcemeta::core::uint_max); // Note that the binary values actually match the declared exponents static_assert(SUBTYPE_LONG_STRING_BASE_EXPONENT_7 == 7); @@ -1049,6 +1059,8 @@ struct VARINT_TYPED_ARBITRARY_OBJECT { /// @} +// NOLINTEND(readability-identifier-naming) + } // namespace sourcemeta::jsonbinpack #endif diff --git a/src/runtime/loader_v1_any.h b/src/runtime/loader_v1_any.h index 0cfaecb5..a0b855ae 100644 --- a/src/runtime/loader_v1_any.h +++ b/src/runtime/loader_v1_any.h @@ -11,6 +11,10 @@ namespace sourcemeta::jsonbinpack::v1 { +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) + auto BYTE_CHOICE_INDEX(const sourcemeta::core::JSON &options) -> Encoding { assert(options.defines("choices")); const auto &choices{options.at("choices")}; @@ -47,11 +51,12 @@ auto CONST_NONE(const sourcemeta::core::JSON &options) -> Encoding { return sourcemeta::jsonbinpack::CONST_NONE{.value = options.at("value")}; } -auto ANY_PACKED_TYPE_TAG_BYTE_PREFIX(const sourcemeta::core::JSON &) - -> Encoding { +auto ANY_PACKED_TYPE_TAG_BYTE_PREFIX( + [[maybe_unused]] const sourcemeta::core::JSON &options) -> Encoding { return sourcemeta::jsonbinpack::ANY_PACKED_TYPE_TAG_BYTE_PREFIX{}; } +// NOLINTEND(readability-identifier-naming) } // namespace sourcemeta::jsonbinpack::v1 #endif diff --git a/src/runtime/loader_v1_array.h b/src/runtime/loader_v1_array.h index 21bcc309..39e55d3a 100644 --- a/src/runtime/loader_v1_array.h +++ b/src/runtime/loader_v1_array.h @@ -14,6 +14,10 @@ namespace sourcemeta::jsonbinpack::v1 { +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) + auto FIXED_TYPED_ARRAY(const sourcemeta::core::JSON &options) -> Encoding { assert(options.defines("size")); assert(options.defines("encoding")); @@ -112,6 +116,7 @@ auto ROOF_TYPED_ARRAY(const sourcemeta::core::JSON &options) -> Encoding { .prefix_encodings = std::move(encodings)}; } +// NOLINTEND(readability-identifier-naming) } // namespace sourcemeta::jsonbinpack::v1 #endif diff --git a/src/runtime/loader_v1_integer.h b/src/runtime/loader_v1_integer.h index 74e45d5a..6c6e707c 100644 --- a/src/runtime/loader_v1_integer.h +++ b/src/runtime/loader_v1_integer.h @@ -10,6 +10,10 @@ namespace sourcemeta::jsonbinpack::v1 { +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) + auto BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(const sourcemeta::core::JSON &options) -> Encoding { assert(options.defines("minimum")); @@ -66,6 +70,7 @@ auto ARBITRARY_MULTIPLE_ZIGZAG_VARINT(const sourcemeta::core::JSON &options) .multiplier = static_cast(multiplier.to_integer())}; } +// NOLINTEND(readability-identifier-naming) } // namespace sourcemeta::jsonbinpack::v1 #endif diff --git a/src/runtime/loader_v1_number.h b/src/runtime/loader_v1_number.h index 5de9180b..8b8ebcc1 100644 --- a/src/runtime/loader_v1_number.h +++ b/src/runtime/loader_v1_number.h @@ -7,10 +7,16 @@ namespace sourcemeta::jsonbinpack::v1 { -auto DOUBLE_VARINT_TUPLE(const sourcemeta::core::JSON &) -> Encoding { +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) + +auto DOUBLE_VARINT_TUPLE([[maybe_unused]] const sourcemeta::core::JSON &options) + -> Encoding { return sourcemeta::jsonbinpack::DOUBLE_VARINT_TUPLE{}; } +// NOLINTEND(readability-identifier-naming) } // namespace sourcemeta::jsonbinpack::v1 #endif diff --git a/src/runtime/loader_v1_string.h b/src/runtime/loader_v1_string.h index 3b6340bd..1413c1d5 100644 --- a/src/runtime/loader_v1_string.h +++ b/src/runtime/loader_v1_string.h @@ -10,6 +10,10 @@ namespace sourcemeta::jsonbinpack::v1 { +// The encoding names are the ones the JSON BinPack specification defines, so +// they keep their casing rather than following the C++ naming convention +// NOLINTBEGIN(readability-identifier-naming) + auto UTF8_STRING_NO_LENGTH(const sourcemeta::core::JSON &options) -> Encoding { assert(options.defines("size")); const auto &size{options.at("size")}; @@ -54,15 +58,17 @@ auto BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( .maximum = static_cast(maximum.to_integer())}; } -auto RFC3339_DATE_INTEGER_TRIPLET(const sourcemeta::core::JSON &) -> Encoding { +auto RFC3339_DATE_INTEGER_TRIPLET( + [[maybe_unused]] const sourcemeta::core::JSON &options) -> Encoding { return sourcemeta::jsonbinpack::RFC3339_DATE_INTEGER_TRIPLET{}; } -auto PREFIX_VARINT_LENGTH_STRING_SHARED(const sourcemeta::core::JSON &) - -> Encoding { +auto PREFIX_VARINT_LENGTH_STRING_SHARED( + [[maybe_unused]] const sourcemeta::core::JSON &options) -> Encoding { return sourcemeta::jsonbinpack::PREFIX_VARINT_LENGTH_STRING_SHARED{}; } +// NOLINTEND(readability-identifier-naming) } // namespace sourcemeta::jsonbinpack::v1 #endif diff --git a/test/compiler/canonicalizer_test.cc b/test/compiler/canonicalizer_test.cc index 2e03d839..5ca3d2d1 100644 --- a/test/compiler/canonicalizer_test.cc +++ b/test/compiler/canonicalizer_test.cc @@ -8,14 +8,14 @@ static auto test_resolver(std::string_view identifier) -> sourcemeta::blaze::SchemaResolverResult { if (identifier == "https://jsonbinpack.sourcemeta.com/draft/unknown") { - static const auto schema{sourcemeta::core::parse_json(R"JSON({ + static const auto SCHEMA{sourcemeta::core::parse_json(R"JSON({ "$schema": "https://jsonbinpack.sourcemeta.com/draft/unknown", "$id": "https://jsonbinpack.sourcemeta.com/draft/unknown" })JSON")}; - return schema; - } else { - return sourcemeta::blaze::schema_resolver(identifier); + return SCHEMA; } + + return sourcemeta::blaze::schema_resolver(identifier); } TEST(unsupported_draft) { diff --git a/test/runtime/decode_any_test.cc b/test/runtime/decode_any_test.cc index af1f932e..b35e67c2 100644 --- a/test/runtime/decode_any_test.cc +++ b/test/runtime/decode_any_test.cc @@ -136,8 +136,9 @@ TEST(LARGE_CHOICE_INDEX_enum_250) { sourcemeta::jsonbinpack::Decoder decoder{stream}; std::vector choices; - for (std::int64_t x = 0; x < 255; x++) { - choices.emplace_back(x); + choices.reserve(255); + for (std::int64_t value = 0; value < 255; value++) { + choices.emplace_back(value); } const auto result = decoder.LARGE_CHOICE_INDEX({std::move(choices)}); diff --git a/test/runtime/decode_array_test.cc b/test/runtime/decode_array_test.cc index 1456d0a1..48670395 100644 --- a/test/runtime/decode_array_test.cc +++ b/test/runtime/decode_array_test.cc @@ -10,9 +10,10 @@ TEST(FIXED_TYPED_ARRAY_0_1_2__no_prefix_encodings) { sourcemeta::core::InputByteStream stream{0x00, 0x01, 0x02}; Decoder decoder{stream}; const auto result = decoder.FIXED_TYPED_ARRAY( - {3, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}), - {}}); + {.size = 3, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}), + .prefix_encodings = {}}); const auto expected = sourcemeta::core::parse_json("[ 0, 1, 2 ]"); EXPECT_EQ(result, expected); } @@ -26,13 +27,16 @@ TEST(FIXED_TYPED_ARRAY_0_1_true__semityped) { choices.emplace_back(false); choices.emplace_back(true); - Encoding first{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}}; - Encoding second{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}}; + Encoding first{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}}; + Encoding second{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}}; const auto result = decoder.FIXED_TYPED_ARRAY( - {3, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {std::move(first), std::move(second)}}); + {.size = 3, + .encoding = + std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {std::move(first), std::move(second)}}); const auto expected = sourcemeta::core::parse_json("[ 0, 1, true ]"); EXPECT_EQ(result, expected); @@ -43,9 +47,10 @@ TEST(FIXED_TYPED_ARRAY_empty__no_prefix_encodings) { sourcemeta::core::InputByteStream stream{}; Decoder decoder{stream}; const auto result = decoder.FIXED_TYPED_ARRAY( - {0, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}), - {}}); + {.size = 0, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}), + .prefix_encodings = {}}); const auto expected = sourcemeta::core::parse_json("[]"); EXPECT_EQ(result, expected); } @@ -60,10 +65,11 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_true_false_true__no_prefix_encodings) { choices.emplace_back(true); const auto result = decoder.BOUNDED_8BITS_TYPED_ARRAY( - {0, - 3, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + {.minimum = 0, + .maximum = 3, + .encoding = + std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); const auto expected = sourcemeta::core::parse_json("[ true, false, true ]"); EXPECT_EQ(result, expected); @@ -79,10 +85,11 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_true_false_true__same_max_min) { choices.emplace_back(true); const auto result = decoder.BOUNDED_8BITS_TYPED_ARRAY( - {3, - 3, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + {.minimum = 3, + .maximum = 3, + .encoding = + std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); const auto expected = sourcemeta::core::parse_json("[ true, false, true ]"); EXPECT_EQ(result, expected); @@ -98,10 +105,12 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_true_false_5__1_3) { choices.emplace_back(true); const auto result = decoder.BOUNDED_8BITS_TYPED_ARRAY( - {1, - 3, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 255, 1}), - {BYTE_CHOICE_INDEX{choices}, BYTE_CHOICE_INDEX{choices}}}); + {.minimum = 1, + .maximum = 3, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 255, .multiplier = 1}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + BYTE_CHOICE_INDEX{choices}}}); const auto expected = sourcemeta::core::parse_json("[ true, false, 5 ]"); EXPECT_EQ(result, expected); @@ -118,11 +127,12 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_complex) { choices.emplace_back(true); const auto result = decoder.BOUNDED_8BITS_TYPED_ARRAY( - {0, - 10, - std::make_shared(FLOOR_MULTIPLE_ENUM_VARINT{-2, 4}), - {BYTE_CHOICE_INDEX{choices}, - FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); + {.minimum = 0, + .maximum = 10, + .encoding = std::make_shared( + FLOOR_MULTIPLE_ENUM_VARINT{.minimum = -2, .multiplier = 4}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); const auto expected = sourcemeta::core::parse_json("[ true, \"foo\", 1000 ]"); EXPECT_EQ(result, expected); @@ -137,10 +147,11 @@ TEST(FLOOR_TYPED_ARRAY_true_false_true__no_prefix_encodings) { choices.emplace_back(false); choices.emplace_back(true); - const auto result = decoder.FLOOR_TYPED_ARRAY( - {0, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + const auto result = + decoder.FLOOR_TYPED_ARRAY({.minimum = 0, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); const auto expected = sourcemeta::core::parse_json("[ true, false, true ]"); EXPECT_EQ(result, expected); @@ -156,9 +167,11 @@ TEST(FLOOR_TYPED_ARRAY_true_false_5__1_3) { choices.emplace_back(true); const auto result = decoder.FLOOR_TYPED_ARRAY( - {1, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 255, 1}), - {BYTE_CHOICE_INDEX{choices}, BYTE_CHOICE_INDEX{choices}}}); + {.minimum = 1, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 255, .multiplier = 1}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + BYTE_CHOICE_INDEX{choices}}}); const auto expected = sourcemeta::core::parse_json("[ true, false, 5 ]"); EXPECT_EQ(result, expected); @@ -175,10 +188,11 @@ TEST(FLOOR_TYPED_ARRAY_complex) { choices.emplace_back(true); const auto result = decoder.FLOOR_TYPED_ARRAY( - {0, - std::make_shared(FLOOR_MULTIPLE_ENUM_VARINT{-2, 4}), - {BYTE_CHOICE_INDEX{choices}, - FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); + {.minimum = 0, + .encoding = std::make_shared( + FLOOR_MULTIPLE_ENUM_VARINT{.minimum = -2, .multiplier = 4}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); const auto expected = sourcemeta::core::parse_json("[ true, \"foo\", 1000 ]"); EXPECT_EQ(result, expected); @@ -193,10 +207,11 @@ TEST(ROOF_TYPED_ARRAY_true_false_true__no_prefix_encodings) { choices.emplace_back(false); choices.emplace_back(true); - const auto result = decoder.ROOF_TYPED_ARRAY( - {6, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + const auto result = + decoder.ROOF_TYPED_ARRAY({.maximum = 6, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); const auto expected = sourcemeta::core::parse_json("[ true, false, true ]"); EXPECT_EQ(result, expected); @@ -212,9 +227,11 @@ TEST(ROOF_TYPED_ARRAY_true_false_5__1_3) { choices.emplace_back(true); const auto result = decoder.ROOF_TYPED_ARRAY( - {5, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 255, 1}), - {BYTE_CHOICE_INDEX{choices}, BYTE_CHOICE_INDEX{choices}}}); + {.maximum = 5, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 255, .multiplier = 1}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + BYTE_CHOICE_INDEX{choices}}}); const auto expected = sourcemeta::core::parse_json("[ true, false, 5 ]"); EXPECT_EQ(result, expected); @@ -231,9 +248,11 @@ TEST(ROOF_TYPED_ARRAY_complex) { choices.emplace_back(true); const auto result = decoder.ROOF_TYPED_ARRAY( - {6, - std::make_shared(FLOOR_MULTIPLE_ENUM_VARINT{-2, 4}), - {BYTE_CHOICE_INDEX{choices}, ROOF_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); + {.maximum = 6, + .encoding = std::make_shared( + FLOOR_MULTIPLE_ENUM_VARINT{.minimum = -2, .multiplier = 4}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + ROOF_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); const auto expected = sourcemeta::core::parse_json("[ true, \"foo\", 1000 ]"); EXPECT_EQ(result, expected); diff --git a/test/runtime/decode_integer_test.cc b/test/runtime/decode_integer_test.cc index 4dea3a6a..6b8a95a5 100644 --- a/test/runtime/decode_integer_test.cc +++ b/test/runtime/decode_integer_test.cc @@ -8,7 +8,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__minus_5_minus_5_minus_1_1) { sourcemeta::core::InputByteStream stream{0x00}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED({-5, -1, 1}); + const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + {.minimum = -5, .maximum = -1, .multiplier = 1}); const sourcemeta::core::JSON expected{-5}; EXPECT_EQ(result, expected); } @@ -16,7 +17,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__minus_5_minus_5_minus_1_1) { TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__2_minus_5_5_1) { sourcemeta::core::InputByteStream stream{0x07}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED({-5, 5, 1}); + const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + {.minimum = -5, .maximum = 5, .multiplier = 1}); const sourcemeta::core::JSON expected{2}; EXPECT_EQ(result, expected); } @@ -24,7 +26,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__2_minus_5_5_1) { TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__5_2_8_1) { sourcemeta::core::InputByteStream stream{0x03}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED({2, 8, 1}); + const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + {.minimum = 2, .maximum = 8, .multiplier = 1}); const sourcemeta::core::JSON expected{5}; EXPECT_EQ(result, expected); } @@ -32,7 +35,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__5_2_8_1) { TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__5_1_19_5) { sourcemeta::core::InputByteStream stream{0x00}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED({1, 19, 5}); + const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + {.minimum = 1, .maximum = 19, .multiplier = 5}); const sourcemeta::core::JSON expected{5}; EXPECT_EQ(result, expected); } @@ -40,7 +44,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__5_1_19_5) { TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__255_0_255_1) { sourcemeta::core::InputByteStream stream{0xff}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED({0, 255, 1}); + const auto result = decoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + {.minimum = 0, .maximum = 255, .multiplier = 1}); const sourcemeta::core::JSON expected{255}; EXPECT_EQ(result, expected); } @@ -48,7 +53,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__255_0_255_1) { TEST(FLOOR_MULTIPLE_ENUM_VARINT__minus_3_minus_10_1) { sourcemeta::core::InputByteStream stream{0x07}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.FLOOR_MULTIPLE_ENUM_VARINT({-10, 1}); + const auto result = + decoder.FLOOR_MULTIPLE_ENUM_VARINT({.minimum = -10, .multiplier = 1}); const sourcemeta::core::JSON expected{-3}; EXPECT_EQ(result, expected); } @@ -56,7 +62,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__minus_3_minus_10_1) { TEST(FLOOR_MULTIPLE_ENUM_VARINT__5_2_1) { sourcemeta::core::InputByteStream stream{0x03}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.FLOOR_MULTIPLE_ENUM_VARINT({2, 1}); + const auto result = + decoder.FLOOR_MULTIPLE_ENUM_VARINT({.minimum = 2, .multiplier = 1}); const sourcemeta::core::JSON expected{5}; EXPECT_EQ(result, expected); } @@ -64,7 +71,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__5_2_1) { TEST(FLOOR_MULTIPLE_ENUM_VARINT__10_5_5) { sourcemeta::core::InputByteStream stream{0x01}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.FLOOR_MULTIPLE_ENUM_VARINT({5, 5}); + const auto result = + decoder.FLOOR_MULTIPLE_ENUM_VARINT({.minimum = 5, .multiplier = 5}); const sourcemeta::core::JSON expected{10}; EXPECT_EQ(result, expected); } @@ -72,7 +80,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__10_5_5) { TEST(FLOOR_MULTIPLE_ENUM_VARINT__10_2_5) { sourcemeta::core::InputByteStream stream{0x01}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.FLOOR_MULTIPLE_ENUM_VARINT({2, 5}); + const auto result = + decoder.FLOOR_MULTIPLE_ENUM_VARINT({.minimum = 2, .multiplier = 5}); const sourcemeta::core::JSON expected{10}; EXPECT_EQ(result, expected); } @@ -80,7 +89,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__10_2_5) { TEST(FLOOR_MULTIPLE_ENUM_VARINT__1000_minus_2_4) { sourcemeta::core::InputByteStream stream{0xfa, 0x01}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.FLOOR_MULTIPLE_ENUM_VARINT({-2, 4}); + const auto result = + decoder.FLOOR_MULTIPLE_ENUM_VARINT({.minimum = -2, .multiplier = 4}); const sourcemeta::core::JSON expected{1000}; EXPECT_EQ(result, expected); } @@ -88,7 +98,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__1000_minus_2_4) { TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__minus_3_minus_2_1) { sourcemeta::core::InputByteStream stream{0x01}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT({-2, 1}); + const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT( + {.maximum = -2, .multiplier = 1}); const sourcemeta::core::JSON expected{-3}; EXPECT_EQ(result, expected); } @@ -96,7 +107,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__minus_3_minus_2_1) { TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__8_10_1) { sourcemeta::core::InputByteStream stream{0x02}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT({10, 1}); + const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT( + {.maximum = 10, .multiplier = 1}); const sourcemeta::core::JSON expected{8}; EXPECT_EQ(result, expected); } @@ -104,7 +116,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__8_10_1) { TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__5_16_5) { sourcemeta::core::InputByteStream stream{0x02}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT({16, 5}); + const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT( + {.maximum = 16, .multiplier = 5}); const sourcemeta::core::JSON expected{5}; EXPECT_EQ(result, expected); } @@ -112,7 +125,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__5_16_5) { TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__10_15_5) { sourcemeta::core::InputByteStream stream{0x01}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT({15, 5}); + const auto result = decoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT( + {.maximum = 15, .multiplier = 5}); const sourcemeta::core::JSON expected{10}; EXPECT_EQ(result, expected); } diff --git a/test/runtime/decode_object_test.cc b/test/runtime/decode_object_test.cc index d6e59528..319bb4e5 100644 --- a/test/runtime/decode_object_test.cc +++ b/test/runtime/decode_object_test.cc @@ -14,9 +14,10 @@ TEST(FIXED_TYPED_ARBITRARY_OBJECT__no_length_string__integer) { }; Decoder decoder{stream}; const auto result = decoder.FIXED_TYPED_ARBITRARY_OBJECT( - {2, std::make_shared(UTF8_STRING_NO_LENGTH{3}), - std::make_shared( - BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1})}); + {.size = 2, + .key_encoding = std::make_shared(UTF8_STRING_NO_LENGTH{3}), + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1})}); EXPECT_TRUE(result.is_object()); EXPECT_EQ(result.size(), 2); EXPECT_TRUE(result.defines("foo")); @@ -40,9 +41,9 @@ TEST(VARINT_TYPED_ARBITRARY_OBJECT__no_length_string__integer) { }; Decoder decoder{stream}; const auto result = decoder.VARINT_TYPED_ARBITRARY_OBJECT( - {std::make_shared(UTF8_STRING_NO_LENGTH{3}), - std::make_shared( - BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1})}); + {.key_encoding = std::make_shared(UTF8_STRING_NO_LENGTH{3}), + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1})}); EXPECT_TRUE(result.is_object()); EXPECT_EQ(result.size(), 2); EXPECT_TRUE(result.defines("foo")); diff --git a/test/runtime/decode_string_test.cc b/test/runtime/decode_string_test.cc index ab2c80c3..c158a530 100644 --- a/test/runtime/decode_string_test.cc +++ b/test/runtime/decode_string_test.cc @@ -81,7 +81,8 @@ TEST(ROOF_VARINT_PREFIX_UTF8_STRING_SHARED_unicode_4) { TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_3_5) { sourcemeta::core::InputByteStream stream{0x01, 0x66, 0x6f, 0x6f}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED({3, 5}); + const auto result = decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( + {.minimum = 3, .maximum = 5}); const sourcemeta::core::JSON expected{"foo"}; EXPECT_EQ(result, expected); } @@ -89,7 +90,8 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_3_5) { TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_3_3) { sourcemeta::core::InputByteStream stream{0x01, 0x66, 0x6f, 0x6f}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED({3, 3}); + const auto result = decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( + {.minimum = 3, .maximum = 3}); const sourcemeta::core::JSON expected{"foo"}; EXPECT_EQ(result, expected); } @@ -99,7 +101,8 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_0_6_foo_3_100) { 0x00, 0x01, 0x05}; sourcemeta::jsonbinpack::Decoder decoder{stream}; const sourcemeta::core::JSON result1 = - decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED({0, 6}); + decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( + {.minimum = 0, .maximum = 6}); const sourcemeta::core::JSON expected{"foo"}; EXPECT_EQ(result1, expected); @@ -107,14 +110,16 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_0_6_foo_3_100) { EXPECT_EQ(stream.tellg(), 4); const sourcemeta::core::JSON result2 = - decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED({3, 100}); + decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( + {.minimum = 3, .maximum = 100}); EXPECT_EQ(result2, expected); } TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_unicode_0_6) { sourcemeta::core::InputByteStream stream{0x05, 0x66, 0x6f, 0xc3, 0xb8}; sourcemeta::jsonbinpack::Decoder decoder{stream}; - const auto result = decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED({0, 6}); + const auto result = decoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( + {.minimum = 0, .maximum = 6}); const sourcemeta::core::JSON expected{"foø"}; EXPECT_EQ(result, expected); } diff --git a/test/runtime/decode_test.cc b/test/runtime/decode_test.cc index 18edb3f0..df417f7f 100644 --- a/test/runtime/decode_test.cc +++ b/test/runtime/decode_test.cc @@ -7,7 +7,8 @@ TEST(generic_decode_BOUNDED_MULTIPLE_8BITS_ENUM_FIXED) { using namespace sourcemeta::jsonbinpack; sourcemeta::core::InputByteStream stream{0x00}; Decoder decoder{stream}; - BOUNDED_MULTIPLE_8BITS_ENUM_FIXED options{-5, -1, 1}; + BOUNDED_MULTIPLE_8BITS_ENUM_FIXED options{ + .minimum = -5, .maximum = -1, .multiplier = 1}; const auto result = decoder.read(options); const sourcemeta::core::JSON expected{-5}; EXPECT_EQ(result, expected); diff --git a/test/runtime/encode_any_test.cc b/test/runtime/encode_any_test.cc index cc74dea9..9a41c487 100644 --- a/test/runtime/encode_any_test.cc +++ b/test/runtime/encode_any_test.cc @@ -13,9 +13,9 @@ TEST(BYTE_CHOICE_INDEX_1__1_0_0) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{1}); - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{0}); + choices.emplace_back(1); + choices.emplace_back(0); + choices.emplace_back(0); encoder.BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } @@ -25,9 +25,9 @@ TEST(BYTE_CHOICE_INDEX_1__0_1_0) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{1}); - choices.push_back(sourcemeta::core::JSON{0}); + choices.emplace_back(0); + choices.emplace_back(1); + choices.emplace_back(0); encoder.BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -37,9 +37,9 @@ TEST(BYTE_CHOICE_INDEX_1__0_0_1) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{1}); + choices.emplace_back(0); + choices.emplace_back(0); + choices.emplace_back(1); encoder.BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}})); } @@ -49,9 +49,9 @@ TEST(BYTE_CHOICE_INDEX_bar__foo_bar_bar) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{"foo"}); - choices.push_back(sourcemeta::core::JSON{"bar"}); - choices.push_back(sourcemeta::core::JSON{"bar"}); + choices.emplace_back("foo"); + choices.emplace_back("bar"); + choices.emplace_back("bar"); encoder.BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -78,9 +78,9 @@ TEST(LARGE_CHOICE_INDEX_1__1_0_0) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{1}); - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{0}); + choices.emplace_back(1); + choices.emplace_back(0); + choices.emplace_back(0); encoder.LARGE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } @@ -90,9 +90,9 @@ TEST(LARGE_CHOICE_INDEX_1__0_1_0) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{1}); - choices.push_back(sourcemeta::core::JSON{0}); + choices.emplace_back(0); + choices.emplace_back(1); + choices.emplace_back(0); encoder.LARGE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -102,9 +102,9 @@ TEST(LARGE_CHOICE_INDEX_1__0_0_1) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{1}); + choices.emplace_back(0); + choices.emplace_back(0); + choices.emplace_back(1); encoder.LARGE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}})); } @@ -114,9 +114,9 @@ TEST(LARGE_CHOICE_INDEX_bar__foo_bar_bar) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{"foo"}); - choices.push_back(sourcemeta::core::JSON{"bar"}); - choices.push_back(sourcemeta::core::JSON{"bar"}); + choices.emplace_back("foo"); + choices.emplace_back("bar"); + choices.emplace_back("bar"); encoder.LARGE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -143,8 +143,9 @@ TEST(LARGE_CHOICE_INDEX_enum_250) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - for (std::int64_t x = 0; x < 255; x++) { - choices.push_back(sourcemeta::core::JSON{x}); + choices.reserve(255); + for (std::int64_t value = 0; value < 255; value++) { + choices.emplace_back(value); } encoder.LARGE_CHOICE_INDEX(document, {std::move(choices)}); @@ -157,9 +158,9 @@ TEST(TOP_LEVEL_BYTE_CHOICE_INDEX_1__1_0_0) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{1}); - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{0}); + choices.emplace_back(1); + choices.emplace_back(0); + choices.emplace_back(0); encoder.TOP_LEVEL_BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{})); } @@ -169,9 +170,9 @@ TEST(TOP_LEVEL_BYTE_CHOICE_INDEX_1__0_1_0) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{1}); - choices.push_back(sourcemeta::core::JSON{0}); + choices.emplace_back(0); + choices.emplace_back(1); + choices.emplace_back(0); encoder.TOP_LEVEL_BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } @@ -181,9 +182,9 @@ TEST(TOP_LEVEL_BYTE_CHOICE_INDEX_1__0_0_1) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{0}); - choices.push_back(sourcemeta::core::JSON{1}); + choices.emplace_back(0); + choices.emplace_back(0); + choices.emplace_back(1); encoder.TOP_LEVEL_BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -193,9 +194,9 @@ TEST(TOP_LEVEL_BYTE_CHOICE_INDEX_bar__foo_bar_bar) { sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; std::vector choices; - choices.push_back(sourcemeta::core::JSON{"foo"}); - choices.push_back(sourcemeta::core::JSON{"bar"}); - choices.push_back(sourcemeta::core::JSON{"bar"}); + choices.emplace_back("foo"); + choices.emplace_back("bar"); + choices.emplace_back("bar"); encoder.TOP_LEVEL_BYTE_CHOICE_INDEX(document, {std::move(choices)}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } @@ -664,7 +665,7 @@ TEST(ANY_PACKED_TYPE_TAG_BYTE_PREFIX__array_32) { TEST(ANY_PACKED_TYPE_TAG_BYTE_PREFIX__object_foo_bar_baz_1) { using namespace sourcemeta::jsonbinpack; const sourcemeta::core::JSON document = - sourcemeta::core::parse_json("{ \"foo\": \"bar\", \"baz\": 1 }"); + sourcemeta::core::parse_json(R"JSON({ "foo": "bar", "baz": 1 })JSON"); sourcemeta::core::OutputByteStream stream{}; Encoder encoder{stream}; diff --git a/test/runtime/encode_array_test.cc b/test/runtime/encode_array_test.cc index 7876c02b..7240a44b 100644 --- a/test/runtime/encode_array_test.cc +++ b/test/runtime/encode_array_test.cc @@ -14,9 +14,10 @@ TEST(FIXED_TYPED_ARRAY_0_1_2__no_prefix_encodings) { Encoder encoder{stream}; encoder.FIXED_TYPED_ARRAY( document, - {3, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}), - {}}); + {.size = 3, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}), + .prefix_encodings = {}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}, std::byte{0x01}, std::byte{0x02}})); @@ -29,18 +30,20 @@ TEST(FIXED_TYPED_ARRAY_0_1_true__semityped) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); - Encoding first{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}}; - Encoding second{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}}; + Encoding first{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}}; + Encoding second{BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}}; Encoder encoder{stream}; encoder.FIXED_TYPED_ARRAY( - document, - {3, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {std::move(first), std::move(second)}}); + document, {.size = 3, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {std::move(first), std::move(second)}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}, std::byte{0x01}, std::byte{0x01}})); @@ -54,9 +57,10 @@ TEST(FIXED_TYPED_ARRAY_empty__no_prefix_encodings) { Encoder encoder{stream}; encoder.FIXED_TYPED_ARRAY( document, - {0, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1}), - {}}); + {.size = 0, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1}), + .prefix_encodings = {}}); EXPECT_EQ(stream.bytes(), (std::vector{})); } @@ -67,16 +71,16 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_true_false_true__no_prefix_encodings) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; - encoder.BOUNDED_8BITS_TYPED_ARRAY( - document, - {0, - 3, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + encoder.BOUNDED_8BITS_TYPED_ARRAY(document, + {.minimum = 0, + .maximum = 3, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x03}, std::byte{0x01}, std::byte{0x00}, std::byte{0x01}})); @@ -89,16 +93,16 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_true_false_true__same_max_min) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; - encoder.BOUNDED_8BITS_TYPED_ARRAY( - document, - {3, - 3, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + encoder.BOUNDED_8BITS_TYPED_ARRAY(document, + {.minimum = 3, + .maximum = 3, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}, std::byte{0x01}, std::byte{0x00}, std::byte{0x01}})); @@ -111,16 +115,18 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_true_false_5__1_3) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; encoder.BOUNDED_8BITS_TYPED_ARRAY( document, - {1, - 3, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 255, 1}), - {BYTE_CHOICE_INDEX{choices}, BYTE_CHOICE_INDEX{choices}}}); + {.minimum = 1, + .maximum = 3, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 255, .multiplier = 1}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + BYTE_CHOICE_INDEX{choices}}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}, std::byte{0x01}, std::byte{0x00}, std::byte{0x05}})); @@ -133,16 +139,18 @@ TEST(BOUNDED_8BITS_TYPED_ARRAY_complex) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; encoder.BOUNDED_8BITS_TYPED_ARRAY( - document, {0, - 10, - std::make_shared(FLOOR_MULTIPLE_ENUM_VARINT{-2, 4}), - {BYTE_CHOICE_INDEX{choices}, - FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); + document, + {.minimum = 0, + .maximum = 10, + .encoding = std::make_shared( + FLOOR_MULTIPLE_ENUM_VARINT{.minimum = -2, .multiplier = 4}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); EXPECT_EQ( stream.bytes(), (std::vector{std::byte{0x03}, std::byte{0x01}, std::byte{0x01}, @@ -157,15 +165,15 @@ TEST(FLOOR_TYPED_ARRAY_true_false_true__no_prefix_encodings) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; - encoder.FLOOR_TYPED_ARRAY( - document, - {0, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + encoder.FLOOR_TYPED_ARRAY(document, + {.minimum = 0, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x03}, std::byte{0x01}, std::byte{0x00}, std::byte{0x01}})); @@ -178,15 +186,17 @@ TEST(FLOOR_TYPED_ARRAY_true_false_5__1_3) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; encoder.FLOOR_TYPED_ARRAY( document, - {1, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 255, 1}), - {BYTE_CHOICE_INDEX{choices}, BYTE_CHOICE_INDEX{choices}}}); + {.minimum = 1, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 255, .multiplier = 1}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + BYTE_CHOICE_INDEX{choices}}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}, std::byte{0x01}, std::byte{0x00}, std::byte{0x05}})); @@ -199,15 +209,17 @@ TEST(FLOOR_TYPED_ARRAY_complex) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; encoder.FLOOR_TYPED_ARRAY( - document, {0, - std::make_shared(FLOOR_MULTIPLE_ENUM_VARINT{-2, 4}), - {BYTE_CHOICE_INDEX{choices}, - FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); + document, + {.minimum = 0, + .encoding = std::make_shared( + FLOOR_MULTIPLE_ENUM_VARINT{.minimum = -2, .multiplier = 4}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + FLOOR_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); EXPECT_EQ( stream.bytes(), (std::vector{std::byte{0x03}, std::byte{0x01}, std::byte{0x01}, @@ -222,15 +234,15 @@ TEST(ROOF_TYPED_ARRAY_true_false_true__no_prefix_encodings) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; - encoder.ROOF_TYPED_ARRAY( - document, - {6, - std::make_shared(BYTE_CHOICE_INDEX{std::move(choices)}), - {}}); + encoder.ROOF_TYPED_ARRAY(document, + {.maximum = 6, + .encoding = std::make_shared( + BYTE_CHOICE_INDEX{std::move(choices)}), + .prefix_encodings = {}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x03}, std::byte{0x01}, std::byte{0x00}, std::byte{0x01}})); @@ -243,15 +255,17 @@ TEST(ROOF_TYPED_ARRAY_true_false_5__1_3) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; encoder.ROOF_TYPED_ARRAY( document, - {5, - std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 255, 1}), - {BYTE_CHOICE_INDEX{choices}, BYTE_CHOICE_INDEX{choices}}}); + {.maximum = 5, + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 255, .multiplier = 1}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + BYTE_CHOICE_INDEX{choices}}}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}, std::byte{0x01}, std::byte{0x00}, std::byte{0x05}})); @@ -264,15 +278,17 @@ TEST(ROOF_TYPED_ARRAY_complex) { sourcemeta::core::OutputByteStream stream{}; std::vector choices; - choices.push_back(sourcemeta::core::JSON(false)); - choices.push_back(sourcemeta::core::JSON(true)); + choices.emplace_back(false); + choices.emplace_back(true); Encoder encoder{stream}; encoder.ROOF_TYPED_ARRAY( document, - {6, - std::make_shared(FLOOR_MULTIPLE_ENUM_VARINT{-2, 4}), - {BYTE_CHOICE_INDEX{choices}, ROOF_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); + {.maximum = 6, + .encoding = std::make_shared( + FLOOR_MULTIPLE_ENUM_VARINT{.minimum = -2, .multiplier = 4}), + .prefix_encodings = {BYTE_CHOICE_INDEX{choices}, + ROOF_VARINT_PREFIX_UTF8_STRING_SHARED{3}}}); EXPECT_EQ( stream.bytes(), (std::vector{std::byte{0x03}, std::byte{0x01}, std::byte{0x01}, diff --git a/test/runtime/encode_cache_test.cc b/test/runtime/encode_cache_test.cc index 841eb8c2..cc93dac1 100644 --- a/test/runtime/encode_cache_test.cc +++ b/test/runtime/encode_cache_test.cc @@ -109,7 +109,7 @@ TEST(cache_remove_oldest) { } TEST(cache_is_a_circular_buffer) { - const auto length{5000000}; + const std::uint64_t length{5000000}; const std::string string_1(length, 'u'); const std::string string_2(length, 'v'); const std::string string_3(length, 'w'); diff --git a/test/runtime/encode_integer_test.cc b/test/runtime/encode_integer_test.cc index 7c23835a..cb877939 100644 --- a/test/runtime/encode_integer_test.cc +++ b/test/runtime/encode_integer_test.cc @@ -10,7 +10,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__minus_5_minus_5_minus_1_1) { const sourcemeta::core::JSON document{-5}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(document, {-5, -1, 1}); + encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + document, {.minimum = -5, .maximum = -1, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } @@ -18,7 +19,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__2_minus_5_5_1) { const sourcemeta::core::JSON document{2}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(document, {-5, 5, 1}); + encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + document, {.minimum = -5, .maximum = 5, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x07}})); } @@ -26,7 +28,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__5_2_8_1) { const sourcemeta::core::JSON document{5}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(document, {2, 8, 1}); + encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + document, {.minimum = 2, .maximum = 8, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x03}})); } @@ -34,7 +37,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__5_1_19_5) { const sourcemeta::core::JSON document{5}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(document, {1, 19, 5}); + encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + document, {.minimum = 1, .maximum = 19, .multiplier = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } @@ -42,7 +46,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__15_1_19_5) { const sourcemeta::core::JSON document{15}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(document, {1, 19, 5}); + encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + document, {.minimum = 1, .maximum = 19, .multiplier = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}})); } @@ -50,7 +55,8 @@ TEST(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED__255_0_255_1) { const sourcemeta::core::JSON document{255}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED(document, {0, 255, 1}); + encoder.BOUNDED_MULTIPLE_8BITS_ENUM_FIXED( + document, {.minimum = 0, .maximum = 255, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0xff}})); } @@ -58,7 +64,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__minus_3_minus_10_1) { const sourcemeta::core::JSON document{-3}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {-10, 1}); + encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, + {.minimum = -10, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x07}})); } @@ -66,7 +73,7 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__5_2_1) { const sourcemeta::core::JSON document{5}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {2, 1}); + encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {.minimum = 2, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x03}})); } @@ -74,7 +81,7 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__10_5_5) { const sourcemeta::core::JSON document{10}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {5, 5}); + encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {.minimum = 5, .multiplier = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -82,7 +89,7 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__10_2_5) { const sourcemeta::core::JSON document{10}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {2, 5}); + encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {.minimum = 2, .multiplier = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -90,7 +97,8 @@ TEST(FLOOR_MULTIPLE_ENUM_VARINT__1000_minus_2_4) { const sourcemeta::core::JSON document{1000}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, {-2, 4}); + encoder.FLOOR_MULTIPLE_ENUM_VARINT(document, + {.minimum = -2, .multiplier = 4}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0xfa}, std::byte{0x01}})); } @@ -99,7 +107,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__minus_3_minus_2_1) { const sourcemeta::core::JSON document{-3}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, {-2, 1}); + encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, + {.maximum = -2, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } @@ -107,7 +116,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__8_10_1) { const sourcemeta::core::JSON document{8}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, {10, 1}); + encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, + {.maximum = 10, .multiplier = 1}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}})); } @@ -115,7 +125,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__5_16_5) { const sourcemeta::core::JSON document{5}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, {15, 5}); + encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, + {.maximum = 15, .multiplier = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x02}})); } @@ -123,7 +134,8 @@ TEST(ROOF_MULTIPLE_MIRROR_ENUM_VARINT__10_15_5) { const sourcemeta::core::JSON document{10}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, {15, 5}); + encoder.ROOF_MULTIPLE_MIRROR_ENUM_VARINT(document, + {.maximum = 15, .multiplier = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}})); } diff --git a/test/runtime/encode_object_test.cc b/test/runtime/encode_object_test.cc index 9d9a56cf..3377547b 100644 --- a/test/runtime/encode_object_test.cc +++ b/test/runtime/encode_object_test.cc @@ -9,14 +9,16 @@ TEST(FIXED_TYPED_ARBITRARY_OBJECT__no_length_string__integer) { using namespace sourcemeta::jsonbinpack; const sourcemeta::core::JSON document = - sourcemeta::core::parse_json("{\"foo\":1,\"bar\":2}"); + sourcemeta::core::parse_json(R"JSON({"foo":1,"bar":2})JSON"); sourcemeta::core::OutputByteStream stream{}; Encoder encoder{stream}; encoder.FIXED_TYPED_ARBITRARY_OBJECT( - document, {2, std::make_shared(UTF8_STRING_NO_LENGTH{3}), - std::make_shared( - BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1})}); + document, + {.size = 2, + .key_encoding = std::make_shared(UTF8_STRING_NO_LENGTH{3}), + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1})}); // Deal with object property non-determinism if (document.as_object().cbegin()->first == "foo") { @@ -37,14 +39,15 @@ TEST(FIXED_TYPED_ARBITRARY_OBJECT__no_length_string__integer) { TEST(VARINT_TYPED_ARBITRARY_OBJECT__no_length_string__integer) { using namespace sourcemeta::jsonbinpack; const sourcemeta::core::JSON document = - sourcemeta::core::parse_json("{\"foo\":1,\"bar\":2}"); + sourcemeta::core::parse_json(R"JSON({"foo":1,"bar":2})JSON"); sourcemeta::core::OutputByteStream stream{}; Encoder encoder{stream}; encoder.VARINT_TYPED_ARBITRARY_OBJECT( - document, {std::make_shared(UTF8_STRING_NO_LENGTH{3}), - std::make_shared( - BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{0, 10, 1})}); + document, + {.key_encoding = std::make_shared(UTF8_STRING_NO_LENGTH{3}), + .encoding = std::make_shared(BOUNDED_MULTIPLE_8BITS_ENUM_FIXED{ + .minimum = 0, .maximum = 10, .multiplier = 1})}); // Deal with object property non-determinism if (document.as_object().cbegin()->first == "foo") { diff --git a/test/runtime/encode_string_test.cc b/test/runtime/encode_string_test.cc index 1b65776d..9f9a0a16 100644 --- a/test/runtime/encode_string_test.cc +++ b/test/runtime/encode_string_test.cc @@ -89,7 +89,8 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_3_5) { const sourcemeta::core::JSON document{"foo"}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, {3, 5}); + encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, + {.minimum = 3, .maximum = 5}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}, std::byte{0x66}, std::byte{0x6f}, std::byte{0x6f}})); @@ -99,7 +100,8 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_3_3) { const sourcemeta::core::JSON document{"foo"}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, {3, 3}); + encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, + {.minimum = 3, .maximum = 3}); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x01}, std::byte{0x66}, std::byte{0x6f}, std::byte{0x6f}})); @@ -109,8 +111,10 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_foo_0_6_foo_3_100) { const sourcemeta::core::JSON document{"foo"}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, {0, 6}); - encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, {3, 100}); + encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, + {.minimum = 0, .maximum = 6}); + encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED( + document, {.minimum = 3, .maximum = 100}); EXPECT_EQ( stream.bytes(), (std::vector{std::byte{0x04}, std::byte{0x66}, std::byte{0x6f}, @@ -122,7 +126,8 @@ TEST(BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED_unicode_0_6) { const sourcemeta::core::JSON document{"foø"}; sourcemeta::core::OutputByteStream stream{}; sourcemeta::jsonbinpack::Encoder encoder{stream}; - encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, {0, 6}); + encoder.BOUNDED_8BIT_PREFIX_UTF8_STRING_SHARED(document, + {.minimum = 0, .maximum = 6}); EXPECT_EQ( stream.bytes(), (std::vector{std::byte{0x05}, std::byte{0x66}, std::byte{0x6f}, diff --git a/test/runtime/encode_test.cc b/test/runtime/encode_test.cc index bcf71b6d..4c4c8330 100644 --- a/test/runtime/encode_test.cc +++ b/test/runtime/encode_test.cc @@ -10,7 +10,8 @@ TEST(generic_encode_BOUNDED_MULTIPLE_8BITS_ENUM_FIXED) { const sourcemeta::core::JSON document{-5}; sourcemeta::core::OutputByteStream stream{}; Encoder encoder{stream}; - BOUNDED_MULTIPLE_8BITS_ENUM_FIXED options{-5, -1, 1}; + BOUNDED_MULTIPLE_8BITS_ENUM_FIXED options{ + .minimum = -5, .maximum = -1, .multiplier = 1}; encoder.write(document, options); EXPECT_EQ(stream.bytes(), (std::vector{std::byte{0x00}})); } diff --git a/vendor/blaze/CMakeLists.txt b/vendor/blaze/CMakeLists.txt index c94b8e93..4b563709 100644 --- a/vendor/blaze/CMakeLists.txt +++ b/vendor/blaze/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.24) project(blaze VERSION 0.0.1 LANGUAGES CXX DESCRIPTION "The ultra high-performance JSON Schema evaluator" HOMEPAGE_URL "https://github.com/sourcemeta/blaze") diff --git a/vendor/blaze/DEPENDENCIES b/vendor/blaze/DEPENDENCIES index 95d8a9b3..e6f828d8 100644 --- a/vendor/blaze/DEPENDENCIES +++ b/vendor/blaze/DEPENDENCIES @@ -1,5 +1,5 @@ vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02 -core https://github.com/sourcemeta/core 389a44f98aa246050ddd1c78c4369e278cf8c22b +core https://github.com/sourcemeta/core c9b8470f64cc359da4e3d1cb1c1524de76dc3c2a jsonschema-test-suite https://github.com/json-schema-org/JSON-Schema-Test-Suite 6648e8194c69697b2e1a15fe76a06a480b183a51 jsonschema-2020-12 https://github.com/json-schema-org/json-schema-spec 769daad75a9553562333a8937a187741cb708c72 jsonschema-2019-09 https://github.com/json-schema-org/json-schema-spec 41014ea723120ce70b314d72f863c6929d9f3cfd diff --git a/vendor/blaze/ports/javascript/describe.mjs b/vendor/blaze/ports/javascript/describe.mjs index 1716fb27..00609784 100644 --- a/vendor/blaze/ports/javascript/describe.mjs +++ b/vendor/blaze/ports/javascript/describe.mjs @@ -24,7 +24,7 @@ import { ASSERTION_PROPERTY_TYPE_STRICT_ANY, ASSERTION_PROPERTY_TYPE_STRICT_ANY_EVALUATE, ASSERTION_ARRAY_PREFIX, ASSERTION_ARRAY_PREFIX_EVALUATE, ASSERTION_OBJECT_PROPERTIES_SIMPLE, - ANNOTATION_EMIT, ANNOTATION_TO_PARENT, ANNOTATION_BASENAME_TO_PARENT, + ANNOTATION_EMIT, ANNOTATION_EMIT_WRAPPED, ANNOTATION_TO_PARENT, ANNOTATION_BASENAME_TO_PARENT, EVALUATE, LOGICAL_NOT, LOGICAL_NOT_EVALUATE, LOGICAL_OR, LOGICAL_AND, LOGICAL_XOR, LOGICAL_CONDITION, @@ -546,7 +546,7 @@ export function describe(valid, instruction, evaluatePath, 'in scope that declared a recursive anchor'; } - if (opcode === ANNOTATION_EMIT) { + if (opcode === ANNOTATION_EMIT || opcode === ANNOTATION_EMIT_WRAPPED) { if (keyword === 'properties') { return 'The object property ' + escapeString(annotation) + ' successfully validated against its property subschema'; diff --git a/vendor/blaze/ports/javascript/index.d.mts b/vendor/blaze/ports/javascript/index.d.mts index bcb7f112..41cb5f0f 100644 --- a/vendor/blaze/ports/javascript/index.d.mts +++ b/vendor/blaze/ports/javascript/index.d.mts @@ -22,7 +22,7 @@ export interface StandardOutputAnnotationEntry { keywordLocation: string; absoluteKeywordLocation: string; instanceLocation: string; - annotation: unknown[]; + annotation: unknown; } export type StandardOutputFlagResult = { valid: boolean }; diff --git a/vendor/blaze/ports/javascript/index.mjs b/vendor/blaze/ports/javascript/index.mjs index 1d497209..bd76d551 100644 --- a/vendor/blaze/ports/javascript/index.mjs +++ b/vendor/blaze/ports/javascript/index.mjs @@ -1,12 +1,13 @@ import { - ANNOTATION_EMIT, ANNOTATION_TO_PARENT, ANNOTATION_BASENAME_TO_PARENT, + ANNOTATION_EMIT, ANNOTATION_EMIT_WRAPPED, ANNOTATION_TO_PARENT, ANNOTATION_BASENAME_TO_PARENT, + isWrappedAnnotationOpcode, ASSERTION_EQUALS_ANY, CONTROL_GROUP as CONTROL_GROUP_START, CONTROL_EVALUATE as CONTROL_EVALUATE_END, CONTROL_JUMP, CONTROL_DYNAMIC_ANCHOR_JUMP } from './opcodes.mjs'; -const JSON_VERSION = 6; +const JSON_VERSION = 7; const DEPTH_LIMIT = 300; const URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/; @@ -306,38 +307,40 @@ function compileInstructionToCode(instruction, captures, visited, budget) { case 45: { var r=R('t'); return r?IO+r+'if(t===void 0)return true;return('+value+'&(1<<_es(t)))!==0;':null; } case 46: return fb(46); case 47: return fb(47); case 48: return fb(48); case 49: return fb(49); - case 50: return 'return true;'; case 51: return 'return true;'; case 52: return 'return true;'; case 53: return 'return true;'; - case 54: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return 'return false;'; var c=r; for(var j=0;j0)c+=seq(children,'t'); return c+'return true;'; } - case 61: { var r=R('t'); if(!r)return null; var c=r+TO+'return true;if(!Object.hasOwn(t,'+JSON.stringify(value)+'))return true;'; if(children&&children.length>0)c+=seq(children,'t'); return c+'return true;'; } - case 62: { var r=R('t'); if(!r)return null; var c=r+'if(!Array.isArray(t)||t.length<='+value+')return true;'; if(children&&children.length>0)c+=seq(children,'t'); return c+'return true;'; } - case 63: return fb(63); case 64: return fb(64); - case 65: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; var mi=captures.length; captures.push(value); var gf=''; for(var gi=0;gi0){gf+='function(i,d,_t,_v){'+lb(gc,'i')+'return true;},';}else{gf+='null,';}} return r+TO+'return true;var __cg=['+gf+'];for(var k in t){var __mi=_c['+mi+'][k];if(__mi!==void 0){var __cf=__cg[__mi];if(__cf&&!__cf(t,d,_t,_v))return false;}}return true;'; } - case 66: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; var mi=captures.length; captures.push(value); var gf=''; for(var gi=0;gi0){gf+='function(i,d,_t,_v){'+lb(gc,'i')+'return true;},';}else{gf+='null,';}} return r+TO+'return true;var __cg=['+gf+'];for(var k in t){var __mi=_c['+mi+'][k];if(__mi===void 0)return false;var __cf=__cg[__mi];if(__cf&&!__cf(t,d,_t,_v))return false;}return true;'; } - case 67: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; return r+TO+'return true;for(var k in t){'+lb(children,'t[k]')+'}return true;'; } - case 68: return fb(68); case 69: return fb(69); case 70: return fb(70); case 71: return fb(71); case 72: return fb(72); - case 73: return fb(73); case 74: return fb(74); case 75: return fb(75); case 76: return fb(76); + case 50: case 51: case 52: case 53: case 54: return 'return true;'; + case 55: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return 'return false;'; var c=r; for(var j=0;j0)c+=seq(children,'t'); return c+'return true;'; } + case 62: { var r=R('t'); if(!r)return null; var c=r+TO+'return true;if(!Object.hasOwn(t,'+JSON.stringify(value)+'))return true;'; if(children&&children.length>0)c+=seq(children,'t'); return c+'return true;'; } + case 63: { var r=R('t'); if(!r)return null; var c=r+'if(!Array.isArray(t)||t.length<='+value+')return true;'; if(children&&children.length>0)c+=seq(children,'t'); return c+'return true;'; } + case 64: return fb(64); case 65: return fb(65); + case 66: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; var mi=captures.length; captures.push(value); var gf=''; for(var gi=0;gi0){gf+='function(i,d,_t,_v){'+lb(gc,'i')+'return true;},';}else{gf+='null,';}} return r+TO+'return true;var __cg=['+gf+'];for(var k in t){var __mi=_c['+mi+'][k];if(__mi!==void 0){var __cf=__cg[__mi];if(__cf&&!__cf(t,d,_t,_v))return false;}}return true;'; } + case 67: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; var mi=captures.length; captures.push(value); var gf=''; for(var gi=0;gi0){gf+='function(i,d,_t,_v){'+lb(gc,'i')+'return true;},';}else{gf+='null,';}} return r+TO+'return true;var __cg=['+gf+'];for(var k in t){var __mi=_c['+mi+'][k];if(__mi===void 0)return false;var __cf=__cg[__mi];if(__cf&&!__cf(t,d,_t,_v))return false;}return true;'; } + case 68: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; return r+TO+'return true;for(var k in t){'+lb(children,'t[k]')+'}return true;'; } + case 69: return fb(69); case 70: return fb(70); case 71: return fb(71); case 72: return fb(72); case 73: return fb(73); + case 74: return fb(74); case 75: return fb(75); case 76: return fb(76); case 77: { var r=R('t'); return r?r+TO+'return true;for(var k in t){if(_es(t[k])!=='+value+')return false;}return true;':null; } case 78: return fb(78); case 79: return fb(79); case 80: return fb(80); case 81: return fb(81); - case 82: { var r=R('t'); if(!r)return null; if(!children||children.length===0)return r+'return true;'; return r+'if(!Array.isArray(t))return true;for(var j=0;j=t.length)return true;for(var j='+value+';j0)c+=seq(children,'i'); return c+'return true;'; } - case 95: { var c=IO+'if(!Object.hasOwn(i,'+JSON.stringify(value)+'))return true;'; if(children&&children.length>0)c+=seq(children,'i'); return c+'return true;'; } - case 96: { var c='if(_jt(i)!=='+value+')return true;'; if(children&&children.length>0)c+=seq(children,'i'); return c+'return true;'; } - case 97: return 'return true;'; - case 98: return fb(98); - case 99: { if(!value)return 'return true;'; if(visited&&visited.has(instruction))return fb(99); if(!visited)visited=new Set(); visited.add(instruction); var r=R('t'); if(!r)return fb(99); var c=r; for(var j=0;j=t.length)return true;for(var j='+value+';j0)c+=seq(children,'i'); return c+'return true;'; } + case 96: { var c=IO+'if(!Object.hasOwn(i,'+JSON.stringify(value)+'))return true;'; if(children&&children.length>0)c+=seq(children,'i'); return c+'return true;'; } + case 97: { var c='if(_jt(i)!=='+value+')return true;'; if(children&&children.length>0)c+=seq(children,'i'); return c+'return true;'; } + case 98: return 'return true;'; + case 99: return fb(99); + case 100: { if(!value)return 'return true;'; if(visited&&visited.has(instruction))return fb(100); if(!visited)visited=new Set(); visited.add(instruction); var r=R('t'); if(!r)return fb(100); var c=r; for(var j=0;j 0 ? this.instanceLocationLength - 1 : 0; @@ -1589,6 +1592,10 @@ function AnnotationEmit(instruction, instance, depth, template, evaluator) { if (evaluator.callbackMode) evaluator.callbackAnnotation(instruction); return true; } +function AnnotationEmitWrapped(instruction, instance, depth, template, evaluator) { + if (evaluator.callbackMode) evaluator.callbackAnnotation(instruction); + return true; +} function AnnotationToParent(instruction, instance, depth, template, evaluator) { if (evaluator.callbackMode) evaluator.callbackAnnotation(instruction); return true; @@ -2705,55 +2712,56 @@ const handlers = [ AssertionArrayPrefixEvaluate, // 48 AssertionObjectPropertiesSimple, // 49 AnnotationEmit, // 50 - AnnotationToParent, // 51 - AnnotationBasenameToParent, // 52 - Evaluate, // 53 - LogicalNot, // 54 - LogicalNotEvaluate, // 55 - LogicalOr, // 56 - LogicalAnd, // 57 - LogicalXor, // 58 - LogicalCondition, // 59 - LogicalWhenType, // 60 - LogicalWhenDefines, // 61 - LogicalWhenArraySizeGreater, // 62 - LoopPropertiesUnevaluated, // 63 - LoopPropertiesUnevaluatedExcept, // 64 - LoopPropertiesMatch, // 65 - LoopPropertiesMatchClosed, // 66 - LoopProperties, // 67 - LoopPropertiesEvaluate, // 68 - LoopPropertiesRegex, // 69 - LoopPropertiesRegexClosed, // 70 - LoopPropertiesStartsWith, // 71 - LoopPropertiesExcept, // 72 - LoopPropertiesType, // 73 - LoopPropertiesTypeEvaluate, // 74 - LoopPropertiesExactlyTypeStrict, // 75 - LoopPropertiesExactlyTypeStrictHash, // 76 - LoopPropertiesTypeStrict, // 77 - LoopPropertiesTypeStrictEvaluate, // 78 - LoopPropertiesTypeStrictAny, // 79 - LoopPropertiesTypeStrictAnyEvaluate, // 80 - LoopKeys, // 81 - LoopItems, // 82 - LoopItemsFrom, // 83 - LoopItemsUnevaluated, // 84 - LoopItemsType, // 85 - LoopItemsTypeStrict, // 86 - LoopItemsTypeStrictAny, // 87 - LoopItemsPropertiesExactlyTypeStrictHash, // 88 + AnnotationEmitWrapped, // 51 + AnnotationToParent, // 52 + AnnotationBasenameToParent, // 53 + Evaluate, // 54 + LogicalNot, // 55 + LogicalNotEvaluate, // 56 + LogicalOr, // 57 + LogicalAnd, // 58 + LogicalXor, // 59 + LogicalCondition, // 60 + LogicalWhenType, // 61 + LogicalWhenDefines, // 62 + LogicalWhenArraySizeGreater, // 63 + LoopPropertiesUnevaluated, // 64 + LoopPropertiesUnevaluatedExcept, // 65 + LoopPropertiesMatch, // 66 + LoopPropertiesMatchClosed, // 67 + LoopProperties, // 68 + LoopPropertiesEvaluate, // 69 + LoopPropertiesRegex, // 70 + LoopPropertiesRegexClosed, // 71 + LoopPropertiesStartsWith, // 72 + LoopPropertiesExcept, // 73 + LoopPropertiesType, // 74 + LoopPropertiesTypeEvaluate, // 75 + LoopPropertiesExactlyTypeStrict, // 76 + LoopPropertiesExactlyTypeStrictHash, // 77 + LoopPropertiesTypeStrict, // 78 + LoopPropertiesTypeStrictEvaluate, // 79 + LoopPropertiesTypeStrictAny, // 80 + LoopPropertiesTypeStrictAnyEvaluate, // 81 + LoopKeys, // 82 + LoopItems, // 83 + LoopItemsFrom, // 84 + LoopItemsUnevaluated, // 85 + LoopItemsType, // 86 + LoopItemsTypeStrict, // 87 + LoopItemsTypeStrictAny, // 88 LoopItemsPropertiesExactlyTypeStrictHash, // 89 - LoopItemsIntegerBounded, // 90 - LoopItemsIntegerBoundedSized, // 91 - LoopContains, // 92 - ControlGroup, // 93 - ControlGroupWhenDefines, // 94 - ControlGroupWhenDefinesDirect, // 95 - ControlGroupWhenType, // 96 - ControlEvaluate, // 97 - ControlDynamicAnchorJump, // 98 - ControlJump // 99 + LoopItemsPropertiesExactlyTypeStrictHash, // 90 + LoopItemsIntegerBounded, // 91 + LoopItemsIntegerBoundedSized, // 92 + LoopContains, // 93 + ControlGroup, // 94 + ControlGroupWhenDefines, // 95 + ControlGroupWhenDefinesDirect, // 96 + ControlGroupWhenType, // 97 + ControlEvaluate, // 98 + ControlDynamicAnchorJump, // 99 + ControlJump // 100 ]; function AssertionTypeArrayBounded_fast(instruction, instance, depth, template, evaluator) { @@ -3517,6 +3525,7 @@ function AssertionObjectPropertiesSimple_fast(instruction, instance, depth, temp } function AnnotationEmit_fast() { return true; } +function AnnotationEmitWrapped_fast() { return true; } function AnnotationToParent_fast() { return true; } function AnnotationBasenameToParent_fast() { return true; } @@ -3956,35 +3965,35 @@ function AssertionTypeIntegerLowerBoundStrict_fast(instruction, instance, depth, const fastHandlers = handlers.slice(); fastHandlers[16] = AssertionTypeArrayBounded_fast; -fastHandlers[87] = LoopItemsTypeStrictAny_fast; +fastHandlers[88] = LoopItemsTypeStrictAny_fast; fastHandlers[43] = AssertionPropertyTypeStrict_fast; fastHandlers[11] = AssertionTypeStrict_fast; fastHandlers[4] = AssertionDefinesAllStrict_fast; fastHandlers[27] = AssertionEqual_fast; -fastHandlers[65] = LoopPropertiesMatch_fast; -fastHandlers[56] = LogicalOr_fast; -fastHandlers[99] = ControlJump_fast; +fastHandlers[66] = LoopPropertiesMatch_fast; +fastHandlers[57] = LogicalOr_fast; +fastHandlers[100] = ControlJump_fast; fastHandlers[29] = AssertionEqualsAnyStringHash_fast; -fastHandlers[58] = LogicalXor_fast; +fastHandlers[59] = LogicalXor_fast; fastHandlers[2] = AssertionDefinesStrict_fast; -fastHandlers[82] = LoopItems_fast; -fastHandlers[66] = LoopPropertiesMatchClosed_fast; +fastHandlers[83] = LoopItems_fast; +fastHandlers[67] = LoopPropertiesMatchClosed_fast; fastHandlers[14] = AssertionTypeStringBounded_fast; -fastHandlers[57] = LogicalAnd_fast; +fastHandlers[58] = LogicalAnd_fast; fastHandlers[8] = AssertionPropertyDependencies_fast; fastHandlers[10] = AssertionTypeAny_fast; -fastHandlers[59] = LogicalCondition_fast; -fastHandlers[72] = LoopPropertiesExcept_fast; +fastHandlers[60] = LogicalCondition_fast; +fastHandlers[73] = LoopPropertiesExcept_fast; fastHandlers[20] = AssertionRegex_fast; -fastHandlers[67] = LoopProperties_fast; +fastHandlers[68] = LoopProperties_fast; fastHandlers[1] = AssertionDefines_fast; -fastHandlers[60] = LogicalWhenType_fast; -fastHandlers[61] = LogicalWhenDefines_fast; +fastHandlers[61] = LogicalWhenType_fast; +fastHandlers[62] = LogicalWhenDefines_fast; fastHandlers[0] = AssertionFail_fast; -fastHandlers[92] = LoopContains_fast; -fastHandlers[54] = LogicalNot_fast; -fastHandlers[85] = LoopItemsType_fast; -fastHandlers[86] = LoopItemsTypeStrict_fast; +fastHandlers[93] = LoopContains_fast; +fastHandlers[55] = LogicalNot_fast; +fastHandlers[86] = LoopItemsType_fast; +fastHandlers[87] = LoopItemsTypeStrict_fast; fastHandlers[28] = AssertionEqualsAny_fast; fastHandlers[3] = AssertionDefinesAll_fast; fastHandlers[5] = AssertionDefinesExactly_fast; @@ -4023,33 +4032,34 @@ fastHandlers[47] = AssertionArrayPrefix_fast; fastHandlers[48] = AssertionArrayPrefixEvaluate_fast; fastHandlers[49] = AssertionObjectPropertiesSimple_fast; fastHandlers[50] = AnnotationEmit_fast; -fastHandlers[51] = AnnotationToParent_fast; -fastHandlers[52] = AnnotationBasenameToParent_fast; -fastHandlers[53] = Evaluate_fast; -fastHandlers[55] = LogicalNotEvaluate_fast; -fastHandlers[62] = LogicalWhenArraySizeGreater_fast; -fastHandlers[63] = LoopPropertiesUnevaluated_fast; -fastHandlers[64] = LoopPropertiesUnevaluatedExcept_fast; -fastHandlers[68] = LoopPropertiesEvaluate_fast; -fastHandlers[69] = LoopPropertiesRegex_fast; -fastHandlers[70] = LoopPropertiesRegexClosed_fast; -fastHandlers[71] = LoopPropertiesStartsWith_fast; -fastHandlers[73] = LoopPropertiesType_fast; -fastHandlers[74] = LoopPropertiesTypeEvaluate_fast; -fastHandlers[75] = LoopPropertiesExactlyTypeStrict_fast; -fastHandlers[76] = LoopPropertiesExactlyTypeStrictHash_fast; -fastHandlers[77] = LoopPropertiesTypeStrict_fast; -fastHandlers[78] = LoopPropertiesTypeStrictEvaluate_fast; -fastHandlers[79] = LoopPropertiesTypeStrictAny_fast; -fastHandlers[80] = LoopPropertiesTypeStrictAnyEvaluate_fast; -fastHandlers[81] = LoopKeys_fast; -fastHandlers[83] = LoopItemsFrom_fast; -fastHandlers[84] = LoopItemsUnevaluated_fast; -fastHandlers[88] = LoopItemsPropertiesExactlyTypeStrictHash_fast; +fastHandlers[51] = AnnotationEmitWrapped_fast; +fastHandlers[52] = AnnotationToParent_fast; +fastHandlers[53] = AnnotationBasenameToParent_fast; +fastHandlers[54] = Evaluate_fast; +fastHandlers[56] = LogicalNotEvaluate_fast; +fastHandlers[63] = LogicalWhenArraySizeGreater_fast; +fastHandlers[64] = LoopPropertiesUnevaluated_fast; +fastHandlers[65] = LoopPropertiesUnevaluatedExcept_fast; +fastHandlers[69] = LoopPropertiesEvaluate_fast; +fastHandlers[70] = LoopPropertiesRegex_fast; +fastHandlers[71] = LoopPropertiesRegexClosed_fast; +fastHandlers[72] = LoopPropertiesStartsWith_fast; +fastHandlers[74] = LoopPropertiesType_fast; +fastHandlers[75] = LoopPropertiesTypeEvaluate_fast; +fastHandlers[76] = LoopPropertiesExactlyTypeStrict_fast; +fastHandlers[77] = LoopPropertiesExactlyTypeStrictHash_fast; +fastHandlers[78] = LoopPropertiesTypeStrict_fast; +fastHandlers[79] = LoopPropertiesTypeStrictEvaluate_fast; +fastHandlers[80] = LoopPropertiesTypeStrictAny_fast; +fastHandlers[81] = LoopPropertiesTypeStrictAnyEvaluate_fast; +fastHandlers[82] = LoopKeys_fast; +fastHandlers[84] = LoopItemsFrom_fast; +fastHandlers[85] = LoopItemsUnevaluated_fast; fastHandlers[89] = LoopItemsPropertiesExactlyTypeStrictHash_fast; -fastHandlers[90] = LoopItemsIntegerBounded_fast; -fastHandlers[91] = LoopItemsIntegerBoundedSized_fast; -fastHandlers[98] = ControlDynamicAnchorJump_fast; +fastHandlers[90] = LoopItemsPropertiesExactlyTypeStrictHash_fast; +fastHandlers[91] = LoopItemsIntegerBounded_fast; +fastHandlers[92] = LoopItemsIntegerBoundedSized_fast; +fastHandlers[99] = ControlDynamicAnchorJump_fast; import { describe } from './describe.mjs'; @@ -4118,17 +4128,18 @@ class SimpleOutput { keywordLocation: evaluatePath, absoluteKeywordLocation: instruction[3], instanceLocation, - annotation: [ annotation ] + values: [ annotation ], + isWrapped: isWrappedAnnotationOpcode(instruction[0]) }; this.annotations.set(annotationKey, bucket); } else { - const last = bucket.annotation[bucket.annotation.length - 1]; + const last = bucket.values[bucket.values.length - 1]; let isSame = last === annotation; if (!isSame && Array.isArray(last) && Array.isArray(annotation) && last.length === annotation.length) { isSame = last.every((value, index) => value === annotation[index]); } - if (!isSame) bucket.annotation.push(annotation); + if (!isSame) bucket.values.push(annotation); } return; } @@ -4201,7 +4212,14 @@ class SimpleOutput { if (valid) { const result = { valid: true }; if (this.annotations.size > 0) { - result.annotations = [ ...this.annotations.values() ]; + result.annotations = [ ...this.annotations.values() ].map(entry => ({ + keywordLocation: entry.keywordLocation, + absoluteKeywordLocation: entry.absoluteKeywordLocation, + instanceLocation: entry.instanceLocation, + annotation: entry.isWrapped + ? entry.values + : entry.values[entry.values.length - 1] + })); } return result; } diff --git a/vendor/blaze/ports/javascript/opcodes.mjs b/vendor/blaze/ports/javascript/opcodes.mjs index 95838297..9fdfa858 100644 --- a/vendor/blaze/ports/javascript/opcodes.mjs +++ b/vendor/blaze/ports/javascript/opcodes.mjs @@ -49,55 +49,56 @@ export const ASSERTION_ARRAY_PREFIX = 47; export const ASSERTION_ARRAY_PREFIX_EVALUATE = 48; export const ASSERTION_OBJECT_PROPERTIES_SIMPLE = 49; export const ANNOTATION_EMIT = 50; -export const ANNOTATION_TO_PARENT = 51; -export const ANNOTATION_BASENAME_TO_PARENT = 52; -export const EVALUATE = 53; -export const LOGICAL_NOT = 54; -export const LOGICAL_NOT_EVALUATE = 55; -export const LOGICAL_OR = 56; -export const LOGICAL_AND = 57; -export const LOGICAL_XOR = 58; -export const LOGICAL_CONDITION = 59; -export const LOGICAL_WHEN_TYPE = 60; -export const LOGICAL_WHEN_DEFINES = 61; -export const LOGICAL_WHEN_ARRAY_SIZE_GREATER = 62; -export const LOOP_PROPERTIES_UNEVALUATED = 63; -export const LOOP_PROPERTIES_UNEVALUATED_EXCEPT = 64; -export const LOOP_PROPERTIES_MATCH = 65; -export const LOOP_PROPERTIES_MATCH_CLOSED = 66; -export const LOOP_PROPERTIES = 67; -export const LOOP_PROPERTIES_EVALUATE = 68; -export const LOOP_PROPERTIES_REGEX = 69; -export const LOOP_PROPERTIES_REGEX_CLOSED = 70; -export const LOOP_PROPERTIES_STARTS_WITH = 71; -export const LOOP_PROPERTIES_EXCEPT = 72; -export const LOOP_PROPERTIES_TYPE = 73; -export const LOOP_PROPERTIES_TYPE_EVALUATE = 74; -export const LOOP_PROPERTIES_EXACTLY_TYPE_STRICT = 75; -export const LOOP_PROPERTIES_EXACTLY_TYPE_STRICT_HASH = 76; -export const LOOP_PROPERTIES_TYPE_STRICT = 77; -export const LOOP_PROPERTIES_TYPE_STRICT_EVALUATE = 78; -export const LOOP_PROPERTIES_TYPE_STRICT_ANY = 79; -export const LOOP_PROPERTIES_TYPE_STRICT_ANY_EVALUATE = 80; -export const LOOP_KEYS = 81; -export const LOOP_ITEMS = 82; -export const LOOP_ITEMS_FROM = 83; -export const LOOP_ITEMS_UNEVALUATED = 84; -export const LOOP_ITEMS_TYPE = 85; -export const LOOP_ITEMS_TYPE_STRICT = 86; -export const LOOP_ITEMS_TYPE_STRICT_ANY = 87; -export const LOOP_ITEMS_PROPERTIES_EXACTLY_TYPE_STRICT_HASH = 88; -export const LOOP_ITEMS_PROPERTIES_EXACTLY_TYPE_STRICT_HASH3 = 89; -export const LOOP_ITEMS_INTEGER_BOUNDED = 90; -export const LOOP_ITEMS_INTEGER_BOUNDED_SIZED = 91; -export const LOOP_CONTAINS = 92; -export const CONTROL_GROUP = 93; -export const CONTROL_GROUP_WHEN_DEFINES = 94; -export const CONTROL_GROUP_WHEN_DEFINES_DIRECT = 95; -export const CONTROL_GROUP_WHEN_TYPE = 96; -export const CONTROL_EVALUATE = 97; -export const CONTROL_DYNAMIC_ANCHOR_JUMP = 98; -export const CONTROL_JUMP = 99; +export const ANNOTATION_EMIT_WRAPPED = 51; +export const ANNOTATION_TO_PARENT = 52; +export const ANNOTATION_BASENAME_TO_PARENT = 53; +export const EVALUATE = 54; +export const LOGICAL_NOT = 55; +export const LOGICAL_NOT_EVALUATE = 56; +export const LOGICAL_OR = 57; +export const LOGICAL_AND = 58; +export const LOGICAL_XOR = 59; +export const LOGICAL_CONDITION = 60; +export const LOGICAL_WHEN_TYPE = 61; +export const LOGICAL_WHEN_DEFINES = 62; +export const LOGICAL_WHEN_ARRAY_SIZE_GREATER = 63; +export const LOOP_PROPERTIES_UNEVALUATED = 64; +export const LOOP_PROPERTIES_UNEVALUATED_EXCEPT = 65; +export const LOOP_PROPERTIES_MATCH = 66; +export const LOOP_PROPERTIES_MATCH_CLOSED = 67; +export const LOOP_PROPERTIES = 68; +export const LOOP_PROPERTIES_EVALUATE = 69; +export const LOOP_PROPERTIES_REGEX = 70; +export const LOOP_PROPERTIES_REGEX_CLOSED = 71; +export const LOOP_PROPERTIES_STARTS_WITH = 72; +export const LOOP_PROPERTIES_EXCEPT = 73; +export const LOOP_PROPERTIES_TYPE = 74; +export const LOOP_PROPERTIES_TYPE_EVALUATE = 75; +export const LOOP_PROPERTIES_EXACTLY_TYPE_STRICT = 76; +export const LOOP_PROPERTIES_EXACTLY_TYPE_STRICT_HASH = 77; +export const LOOP_PROPERTIES_TYPE_STRICT = 78; +export const LOOP_PROPERTIES_TYPE_STRICT_EVALUATE = 79; +export const LOOP_PROPERTIES_TYPE_STRICT_ANY = 80; +export const LOOP_PROPERTIES_TYPE_STRICT_ANY_EVALUATE = 81; +export const LOOP_KEYS = 82; +export const LOOP_ITEMS = 83; +export const LOOP_ITEMS_FROM = 84; +export const LOOP_ITEMS_UNEVALUATED = 85; +export const LOOP_ITEMS_TYPE = 86; +export const LOOP_ITEMS_TYPE_STRICT = 87; +export const LOOP_ITEMS_TYPE_STRICT_ANY = 88; +export const LOOP_ITEMS_PROPERTIES_EXACTLY_TYPE_STRICT_HASH = 89; +export const LOOP_ITEMS_PROPERTIES_EXACTLY_TYPE_STRICT_HASH3 = 90; +export const LOOP_ITEMS_INTEGER_BOUNDED = 91; +export const LOOP_ITEMS_INTEGER_BOUNDED_SIZED = 92; +export const LOOP_CONTAINS = 93; +export const CONTROL_GROUP = 94; +export const CONTROL_GROUP_WHEN_DEFINES = 95; +export const CONTROL_GROUP_WHEN_DEFINES_DIRECT = 96; +export const CONTROL_GROUP_WHEN_TYPE = 97; +export const CONTROL_EVALUATE = 98; +export const CONTROL_DYNAMIC_ANCHOR_JUMP = 99; +export const CONTROL_JUMP = 100; export const INSTRUCTION_NAMES = { "AssertionFail": ASSERTION_FAIL, @@ -151,6 +152,7 @@ export const INSTRUCTION_NAMES = { "AssertionArrayPrefixEvaluate": ASSERTION_ARRAY_PREFIX_EVALUATE, "AssertionObjectPropertiesSimple": ASSERTION_OBJECT_PROPERTIES_SIMPLE, "AnnotationEmit": ANNOTATION_EMIT, + "AnnotationEmitWrapped": ANNOTATION_EMIT_WRAPPED, "AnnotationToParent": ANNOTATION_TO_PARENT, "AnnotationBasenameToParent": ANNOTATION_BASENAME_TO_PARENT, "Evaluate": EVALUATE, @@ -204,5 +206,9 @@ export const INSTRUCTION_NAMES = { }; export const ANNOTATION_OPCODES = new Set([ - ANNOTATION_EMIT, ANNOTATION_TO_PARENT, ANNOTATION_BASENAME_TO_PARENT + ANNOTATION_EMIT, ANNOTATION_EMIT_WRAPPED, ANNOTATION_TO_PARENT, ANNOTATION_BASENAME_TO_PARENT ]); + +export function isWrappedAnnotationOpcode(opcode) { + return opcode === ANNOTATION_EMIT_WRAPPED || opcode === ANNOTATION_BASENAME_TO_PARENT; +} diff --git a/vendor/blaze/src/alterschema/alterschema.cc b/vendor/blaze/src/alterschema/alterschema.cc index 25db0d59..5eb14253 100644 --- a/vendor/blaze/src/alterschema/alterschema.cc +++ b/vendor/blaze/src/alterschema/alterschema.cc @@ -102,7 +102,7 @@ auto WALK_UP(const JSON &root, const SchemaFrame &frame, const auto &parent_pointer{current_parent.value()}; const auto relative_pointer{current_pointer.resolve_from(parent_pointer)}; assert(!relative_pointer.empty() && relative_pointer.at(0).is_property()); - const auto parent{frame.traverse(frame.uri(parent_pointer).value().get())}; + const auto parent{frame.traverse(parent_pointer)}; assert(parent.has_value()); const auto &parent_vocabularies{ frame.vocabularies(parent.value().get(), resolver)}; diff --git a/vendor/blaze/src/alterschema/include/sourcemeta/blaze/alterschema.h b/vendor/blaze/src/alterschema/include/sourcemeta/blaze/alterschema.h index 1070e0e4..6c2cb728 100644 --- a/vendor/blaze/src/alterschema/include/sourcemeta/blaze/alterschema.h +++ b/vendor/blaze/src/alterschema/include/sourcemeta/blaze/alterschema.h @@ -79,8 +79,16 @@ enum class AlterSchemaMode : std::uint8_t { /// } /// })JSON"); /// -/// bundle.apply(schema, sourcemeta::blaze::schema_walker, -/// sourcemeta::blaze::schema_resolver); +/// const auto result{bundle.apply(schema, +/// sourcemeta::blaze::schema_walker, +/// sourcemeta::blaze::schema_resolver, +/// [](const auto &pointer, +/// const auto &name, +/// const auto &message, +/// const auto &outcome, +/// const auto dismissed) { +/// // Do something with the information +/// })}; /// ``` SOURCEMETA_BLAZE_ALTERSCHEMA_EXPORT auto add(SchemaTransformer &bundle, const AlterSchemaMode mode) -> void; @@ -142,6 +150,7 @@ class SOURCEMETA_BLAZE_ALTERSCHEMA_EXPORT SchemaRule final /// /// ```cpp /// #include +/// #include /// #include /// #include /// #include @@ -156,8 +165,9 @@ class SOURCEMETA_BLAZE_ALTERSCHEMA_EXPORT SchemaRule final /// sourcemeta::blaze::SchemaFrame::Mode::References, document, /// sourcemeta::blaze::schema_walker, sourcemeta::blaze::schema_resolver}; /// +/// const sourcemeta::core::Pointer pointer{"items"}; /// const auto location{frame.traverse( -/// sourcemeta::core::WeakPointer{"items"}, +/// sourcemeta::core::to_weak_pointer(pointer), /// sourcemeta::blaze::SchemaFrame::LocationType::Subschema)}; /// /// sourcemeta::core::WeakPointer base; diff --git a/vendor/blaze/src/alterschema/linter/invalid_external_ref.h b/vendor/blaze/src/alterschema/linter/invalid_external_ref.h index 1c60832b..f950396f 100644 --- a/vendor/blaze/src/alterschema/linter/invalid_external_ref.h +++ b/vendor/blaze/src/alterschema/linter/invalid_external_ref.h @@ -104,6 +104,20 @@ class InvalidExternalRef final : public SchemaTransformRule { const JSON::String &base_key, const SchemaWalker &walker, const SchemaResolver &resolver, const SchemaFrame::Location &location) const -> bool { + // A pointer fragment names a place of the document, and the document can + // answer for that on its own without paying to frame it + const auto fragment_pointer{sourcemeta::core::fragment_to_pointer( + sourcemeta::core::URI{reference_entry.destination})}; + if (fragment_pointer.has_value() && + sourcemeta::core::try_get(remote.value(), fragment_pointer.value()) != + nullptr) { + return false; + } + + // An anchor is not a place of the document, and the drafts that spell + // identifiers as `id` let one look just like a pointer, so a miss above + // still has to ask the frame. Only the anchors of the remote matter here, + // rather than every pointer of it auto frame_iterator{this->frame_cache_.find(base_key)}; if (frame_iterator == this->frame_cache_.end()) { auto remote_frame{std::make_unique( diff --git a/vendor/blaze/src/bundle/bundle.cc b/vendor/blaze/src/bundle/bundle.cc index 200020e3..9811976c 100644 --- a/vendor/blaze/src/bundle/bundle.cc +++ b/vendor/blaze/src/bundle/bundle.cc @@ -420,16 +420,30 @@ auto bundle_schema(sourcemeta::core::JSON &root, // If the reference has a fragment, verify it exists in the remote // schema if (reference.fragment.has_value()) { - // TODO: The fact that we have to re-frame on each loop pass to check - // for this is probably insanely slow - sourcemeta::blaze::SchemaFrame remote_frame{ - sourcemeta::blaze::SchemaFrame::Mode::Locations, - remote, - walker, - resolver, - default_dialect, - identifier}; - if (!remote_frame.traverse(reference.destination).has_value()) { + // A pointer fragment names a place of the document, and the document can + // answer for that on its own without paying to frame it + const auto fragment_pointer{sourcemeta::core::fragment_to_pointer( + sourcemeta::core::URI{reference.destination})}; + bool exists{fragment_pointer.has_value() && + sourcemeta::core::try_get(remote, fragment_pointer.value()) != + nullptr}; + + // An anchor is not a place of the document, and the drafts that spell + // identifiers as `id` let one look just like a pointer, so a miss above + // still has to ask the frame. Only the anchors of the remote matter + // here, rather than every pointer of it + if (!exists) { + const sourcemeta::blaze::SchemaFrame remote_frame{ + sourcemeta::blaze::SchemaFrame::Mode::Locations, + remote, + walker, + resolver, + default_dialect, + identifier}; + exists = remote_frame.traverse(reference.destination).has_value(); + } + + if (!exists) { throw sourcemeta::blaze::SchemaReferenceError( reference.destination, sourcemeta::core::to_pointer(pointer), "Could not resolve schema reference"); diff --git a/vendor/blaze/src/bundle/include/sourcemeta/blaze/bundle.h b/vendor/blaze/src/bundle/include/sourcemeta/blaze/bundle.h index f413e03e..f682c1cd 100644 --- a/vendor/blaze/src/bundle/include/sourcemeta/blaze/bundle.h +++ b/vendor/blaze/src/bundle/include/sourcemeta/blaze/bundle.h @@ -61,7 +61,7 @@ enum class BundleMode : std::uint8_t { /// /// // A custom resolver that knows about an additional schema /// static auto test_resolver(std::string_view identifier) -/// -> std::optional { +/// -> sourcemeta::blaze::SchemaResolverResult { /// if (identifier == "https://www.example.com/test") { /// return sourcemeta::core::parse_json(R"JSON({ /// "$id": "https://www.example.com/test", @@ -111,7 +111,7 @@ auto dependencies(const sourcemeta::core::JSON &schema, /// /// // A custom resolver that knows about an additional schema /// static auto test_resolver(std::string_view identifier) -/// -> std::optional { +/// -> sourcemeta::blaze::SchemaResolverResult { /// if (identifier == "https://www.example.com/test") { /// return sourcemeta::core::parse_json(R"JSON({ /// "$id": "https://www.example.com/test", @@ -173,7 +173,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker, /// /// // A custom resolver that knows about an additional schema /// static auto test_resolver(std::string_view identifier) -/// -> std::optional { +/// -> sourcemeta::blaze::SchemaResolverResult { /// if (identifier == "https://www.example.com/test") { /// return sourcemeta::core::parse_json(R"JSON({ /// "$id": "https://www.example.com/test", diff --git a/vendor/blaze/src/canonicalizer/canonicalize.cc b/vendor/blaze/src/canonicalizer/canonicalize.cc index 7842f5a8..ec1cc7ad 100644 --- a/vendor/blaze/src/canonicalizer/canonicalize.cc +++ b/vendor/blaze/src/canonicalizer/canonicalize.cc @@ -366,6 +366,7 @@ auto apply(const std::vector &rules, sourcemeta::core::JSON &schema, #include "rules/unnecessary_allof_ref_wrapper_draft.h" #include "rules/unnecessary_extends_ref_wrapper.h" #include "rules/unsatisfiable_drop_validation.h" +#include "rules/unsatisfiable_empty_enum.h" #include "rules/unsatisfiable_exclusive_equal_bounds.h" #include "rules/unsatisfiable_in_place_applicator_type.h" #include "rules/unsatisfiable_type_and_enum.h" @@ -380,7 +381,7 @@ auto canonicalize(sourcemeta::core::JSON &schema, const std::string_view default_dialect, const std::string_view default_id) -> void { std::vector rules; - rules.reserve(125); + rules.reserve(128); rules.push_back(make_rule()); rules.push_back(make_rule()); rules.push_back(make_rule()); @@ -477,6 +478,7 @@ auto canonicalize(sourcemeta::core::JSON &schema, rules.push_back(make_rule()); rules.push_back(make_rule()); rules.push_back(make_rule()); + rules.push_back(make_rule()); rules.push_back(make_rule()); rules.push_back(make_rule()); rules.push_back(make_rule()); diff --git a/vendor/blaze/src/canonicalizer/helpers.h b/vendor/blaze/src/canonicalizer/helpers.h index 45afcb64..aac2a8e0 100644 --- a/vendor/blaze/src/canonicalizer/helpers.h +++ b/vendor/blaze/src/canonicalizer/helpers.h @@ -70,6 +70,23 @@ inline auto UNSATISFIABLE_SCHEMA(const SchemaVocabularies &vocabularies) return result; } + // Draft 2 and earlier have no boolean schemas either, and their negation + // keyword takes type names rather than schemas, so the name to rule out is + // the wildcard that every instance answers to + if (vocabularies.contains_any( + {SchemaVocabularies::Known::JSON_Schema_Draft_0, + SchemaVocabularies::Known::JSON_Schema_Draft_0_Hyper, + SchemaVocabularies::Known::JSON_Schema_Draft_1, + SchemaVocabularies::Known::JSON_Schema_Draft_1_Hyper, + SchemaVocabularies::Known::JSON_Schema_Draft_2, + SchemaVocabularies::Known::JSON_Schema_Draft_2_Hyper})) { + auto types{sourcemeta::core::JSON::make_array()}; + types.push_back(sourcemeta::core::JSON{"any"}); + auto result{sourcemeta::core::JSON::make_object()}; + result.assign("disallow", std::move(types)); + return result; + } + return sourcemeta::core::JSON{false}; } @@ -117,7 +134,7 @@ auto WALK_UP(const sourcemeta::core::JSON &root, const SchemaFrame &frame, const auto &parent_pointer{current_parent.value()}; const auto relative_pointer{current_pointer.resolve_from(parent_pointer)}; assert(!relative_pointer.empty() && relative_pointer.at(0).is_property()); - const auto parent{frame.traverse(frame.uri(parent_pointer).value().get())}; + const auto parent{frame.traverse(parent_pointer)}; assert(parent.has_value()); const auto &parent_vocabularies{ frame.vocabularies(parent.value().get(), resolver)}; diff --git a/vendor/blaze/src/canonicalizer/rules/type_inherit_in_place.h b/vendor/blaze/src/canonicalizer/rules/type_inherit_in_place.h index be681920..f0acd7f1 100644 --- a/vendor/blaze/src/canonicalizer/rules/type_inherit_in_place.h +++ b/vendor/blaze/src/canonicalizer/rules/type_inherit_in_place.h @@ -77,7 +77,7 @@ class TypeInheritInPlace final : public SchemaTransformRule { if (walk_relative.empty() || !walk_relative.at(0).is_property()) { break; } - const auto walk_entry{frame.traverse(frame.uri(wp).value().get())}; + const auto walk_entry{frame.traverse(wp)}; if (!walk_entry.has_value()) { break; } diff --git a/vendor/blaze/src/canonicalizer/rules/type_union_implicit.h b/vendor/blaze/src/canonicalizer/rules/type_union_implicit.h index 2492d87d..fb7aa68c 100644 --- a/vendor/blaze/src/canonicalizer/rules/type_union_implicit.h +++ b/vendor/blaze/src/canonicalizer/rules/type_union_implicit.h @@ -86,7 +86,7 @@ class TypeUnionImplicit final : public SchemaTransformRule { if (walk_relative.empty() || !walk_relative.at(0).is_property()) { break; } - const auto walk_entry{frame.traverse(frame.uri(wp).value().get())}; + const auto walk_entry{frame.traverse(wp)}; if (!walk_entry.has_value()) { break; } diff --git a/vendor/blaze/src/canonicalizer/rules/unsatisfiable_empty_enum.h b/vendor/blaze/src/canonicalizer/rules/unsatisfiable_empty_enum.h new file mode 100644 index 00000000..7859d982 --- /dev/null +++ b/vendor/blaze/src/canonicalizer/rules/unsatisfiable_empty_enum.h @@ -0,0 +1,40 @@ +class UnsatisfiableEmptyEnum final : public SchemaTransformRule { +public: + using reframe_after_transform = std::false_type; + UnsatisfiableEmptyEnum() : SchemaTransformRule{"unsatisfiable_empty_enum"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON &, + const sourcemeta::blaze::SchemaVocabularies &vocabularies, + const sourcemeta::blaze::SchemaFrame &, + const sourcemeta::blaze::SchemaFrame::Location &, + const sourcemeta::blaze::SchemaWalker &, + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + ONLY_CONTINUE_IF( + vocabularies.contains_any( + {SchemaVocabularies::Known::JSON_Schema_Draft_0, + SchemaVocabularies::Known::JSON_Schema_Draft_1, + SchemaVocabularies::Known::JSON_Schema_Draft_2, + SchemaVocabularies::Known::JSON_Schema_Draft_3, + SchemaVocabularies::Known::JSON_Schema_Draft_4, + SchemaVocabularies::Known::JSON_Schema_Draft_6, + SchemaVocabularies::Known::JSON_Schema_Draft_7, + SchemaVocabularies::Known::JSON_Schema_2019_09_Validation, + SchemaVocabularies::Known::JSON_Schema_2020_12_Validation}) && + schema.is_object()); + + const auto *enum_value{schema.try_at("enum")}; + ONLY_CONTINUE_IF(enum_value && enum_value->is_array() && + enum_value->empty()); + this->unsatisfiable_ = UNSATISFIABLE_SCHEMA(vocabularies); + return true; + } + + auto transform(sourcemeta::core::JSON &schema) const -> void override { + INTO_UNSATISFIABLE(schema, this->unsatisfiable_); + } + +private: + mutable sourcemeta::core::JSON unsatisfiable_{false}; +}; diff --git a/vendor/blaze/src/codegen/codegen.cc b/vendor/blaze/src/codegen/codegen.cc index b096a93b..0dba1b10 100644 --- a/vendor/blaze/src/codegen/codegen.cc +++ b/vendor/blaze/src/codegen/codegen.cc @@ -48,6 +48,22 @@ auto is_validation_subschema( resolver); } +// The dialect a schema declares, falling back to the given default. Unlike the +// equivalent helper in bundling, this one hands back a copy rather than a view, +// as canonicalisation goes on to rewrite the very document it reads from +auto declared_dialect(const sourcemeta::core::JSON &schema, + const std::string_view default_dialect) + -> sourcemeta::core::JSON::String { + if (!schema.is_object()) { + return sourcemeta::core::JSON::String{default_dialect}; + } + + const auto *dialect{schema.try_at("$schema")}; + return (dialect != nullptr && dialect->is_string()) + ? dialect->to_string() + : sourcemeta::core::JSON::String{default_dialect}; +} + } // anonymous namespace namespace sourcemeta::blaze { @@ -70,7 +86,12 @@ auto compile(const sourcemeta::core::JSON &input, // (2) Canonicalize the schema for easier analysis // -------------------------------------------------------------------------- - sourcemeta::blaze::canonicalize(schema, walker, resolver, default_dialect, + // Canonicalisation can collapse an unsatisfiable schema into a boolean, + // which has no room for the dialect the document declares, so hold on to + // that dialect for the framing that follows + const auto dialect{declared_dialect(schema, default_dialect)}; + + sourcemeta::blaze::canonicalize(schema, walker, resolver, dialect, default_id); // -------------------------------------------------------------------------- @@ -82,7 +103,7 @@ auto compile(const sourcemeta::core::JSON &input, schema, walker, resolver, - default_dialect, + dialect, default_id}; // -------------------------------------------------------------------------- diff --git a/vendor/blaze/src/codegen/codegen_default_compiler.h b/vendor/blaze/src/codegen/codegen_default_compiler.h index bd0f117e..e6fbd8e1 100644 --- a/vendor/blaze/src/codegen/codegen_default_compiler.h +++ b/vendor/blaze/src/codegen/codegen_default_compiler.h @@ -109,13 +109,34 @@ auto handle_object(const sourcemeta::core::JSON &schema, assert(subschema.defines("properties")); const auto &properties{subschema.at("properties")}; + if (!properties.is_object()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "properties", "Expected an object value"); + } std::unordered_set required_set; if (subschema.defines("required")) { const auto &required{subschema.at("required")}; + if (!required.is_array()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "required", "Expected an array value"); + } + for (const auto &item : required.as_array()) { - // Guaranteed by canonicalisation - assert(properties.defines(item.to_string())); + if (!item.is_string()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "required", + "Expected an array of string values"); + } + + // Canonicalisation adds a required property that the schema leaves + // unconstrained, but it cannot do so for an object that forbids it + if (!properties.defines(item.to_string())) { + throw CodegenUnexpectedSchemaError( + schema, location.pointer, + "This schema requires a property that it does not allow"); + } + required_set.insert(item.to_string()); } } @@ -160,6 +181,12 @@ auto handle_object(const sourcemeta::core::JSON &schema, std::vector pattern; if (subschema.defines("patternProperties")) { const auto &pattern_props{subschema.at("patternProperties")}; + if (!pattern_props.is_object()) { + throw CodegenUnsupportedKeywordValueError(schema, location.pointer, + "patternProperties", + "Expected an object value"); + } + for (const auto &entry : pattern_props.as_object()) { auto pattern_pointer{sourcemeta::core::to_pointer(location.pointer)}; pattern_pointer.push_back("patternProperties"); @@ -249,7 +276,10 @@ auto handle_array(const sourcemeta::core::JSON &schema, SchemaVocabularies::Known::JSON_Schema_2020_12_Applicator) && subschema.defines("prefixItems")) { const auto &prefix_items{subschema.at("prefixItems")}; - assert(prefix_items.is_array()); + if (!prefix_items.is_array()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "prefixItems", "Expected an array value"); + } std::vector tuple_items; for (std::size_t index = 0; index < prefix_items.size(); ++index) { @@ -364,6 +394,10 @@ auto handle_enum(const sourcemeta::core::JSON &schema, "description", "default", "deprecated", "readOnly", "writeOnly", "examples"}); const auto &enum_json{subschema.at("enum")}; + if (!enum_json.is_array()) { + throw CodegenUnsupportedKeywordValueError(schema, location.pointer, "enum", + "Expected an array value"); + } // Boolean and null special cases if (enum_json.size() == 1 && enum_json.at(0).is_null()) { @@ -404,7 +438,12 @@ auto handle_anyof(const sourcemeta::core::JSON &schema, "writeOnly", "examples", "unevaluatedProperties", "unevaluatedItems"}); const auto &any_of{subschema.at("anyOf")}; - assert(any_of.is_array()); + if (!any_of.is_array() || any_of.empty()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "anyOf", "Expected a non-empty array value"); + } + + // Canonicalisation merges a single branch into its parent assert(any_of.size() >= 2); std::vector branches; @@ -441,7 +480,12 @@ auto handle_oneof(const sourcemeta::core::JSON &schema, "writeOnly", "examples", "unevaluatedProperties", "unevaluatedItems"}); const auto &one_of{subschema.at("oneOf")}; - assert(one_of.is_array()); + if (!one_of.is_array() || one_of.empty()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "oneOf", "Expected a non-empty array value"); + } + + // Canonicalisation merges a single branch into its parent assert(one_of.size() >= 2); std::vector branches; @@ -585,7 +629,10 @@ auto handle_allof(const sourcemeta::core::JSON &schema, "writeOnly", "examples", "unevaluatedProperties", "unevaluatedItems"}); const auto &all_of{subschema.at("allOf")}; - assert(all_of.is_array()); + if (!all_of.is_array() || all_of.empty()) { + throw CodegenUnsupportedKeywordValueError( + schema, location.pointer, "allOf", "Expected a non-empty array value"); + } if (all_of.size() == 1) { auto target_pointer{sourcemeta::core::to_pointer(location.pointer)}; diff --git a/vendor/blaze/src/compiler/compile.cc b/vendor/blaze/src/compiler/compile.cc index c7aaefa0..2c8e73d3 100644 --- a/vendor/blaze/src/compiler/compile.cc +++ b/vendor/blaze/src/compiler/compile.cc @@ -215,7 +215,7 @@ auto compile_subschema(const sourcemeta::blaze::Context &context, schema_context.relative_pointer.empty() && !booleans_are_schemas(schema_context.vocabularies)) [[unlikely]] { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), "This dialect does not support boolean schemas"); } @@ -266,16 +266,20 @@ auto compile_subschema(const sourcemeta::blaze::Context &context, !schema_context.schema.defines(KEYWORD_MAXIMUM)))) [[unlikely]] { throw sourcemeta::blaze::CompilerError( schema_context.base, - to_pointer(schema_context.relative_pointer.concat( - sourcemeta::blaze::make_weak_pointer(keyword))), + absolute_schema_location( + context, schema_context.base, + schema_context.relative_pointer.concat( + sourcemeta::blaze::make_weak_pointer(keyword))), "This keyword was expected to accompany the bound it applies to"); } if (shape_error) [[unlikely]] { throw sourcemeta::blaze::CompilerError( schema_context.base, - to_pointer(schema_context.relative_pointer.concat( - sourcemeta::blaze::make_weak_pointer(keyword))), + absolute_schema_location( + context, schema_context.base, + schema_context.relative_pointer.concat( + sourcemeta::blaze::make_weak_pointer(keyword))), shape_error); } @@ -294,10 +298,9 @@ auto compile_subschema(const sourcemeta::blaze::Context &context, .base_instance_location = dynamic_context.base_instance_location}, steps)) { // Just a sanity check to ensure every keyword location is indeed valid - assert(context.frame - .location(sourcemeta::blaze::SchemaReferenceType::Static, - context.extra[step.extra_index].keyword_location) - .has_value()); + assert(sourcemeta::core::try_get( + context.root, + absolute_schema_pointer(context, schema_context)) != nullptr); steps.push_back(std::move(step)); } } @@ -356,7 +359,9 @@ auto schema_frame_populate_target_types( return; } - const auto reference_location{frame.traverse(origin)}; + // A reference is always a keyword of the subschema that declares it, + // so that subschema is what the origin sits directly inside of + const auto reference_location{frame.traverse(origin.initial())}; assert(reference_location.has_value()); auto &context{target_types[reference.destination]}; if (reference_location->get().property_name) { @@ -423,6 +428,43 @@ auto schema_frame_populate_target_types( namespace sourcemeta::blaze { +// Whether an entry point that the frame could not locate nonetheless names a +// place that the document has, which means it is a keyword rather than a +// schema. Only reachable when the entry point carries a pointer fragment, as +// anything else can only ever name a schema +auto entrypoint_names_non_schema(const sourcemeta::core::JSON &schema, + const sourcemeta::blaze::SchemaFrame &frame, + const std::string_view entrypoint) -> bool { + std::optional uri; + try { + uri.emplace(sourcemeta::core::JSON::String{entrypoint}); + } catch (const sourcemeta::core::URIParseError &) { + // A URI that does not even parse names nothing at all, so leave the + // caller to report it as the invalid entry point that it is + return false; + } + + const auto relative{sourcemeta::core::fragment_to_pointer(uri.value())}; + if (!relative.has_value()) { + return false; + } + + const auto base{uri.value().recompose_without_fragment().value_or( + sourcemeta::core::JSON::String{})}; + const auto base_location{frame.traverse(base)}; + if (!base_location.has_value()) { + // A base that framing does not know names some other document, which this + // one has nothing to say about + return base.empty() && + sourcemeta::core::try_get(schema, relative.value()) != nullptr; + } + + return sourcemeta::core::try_get( + schema, + sourcemeta::core::to_pointer(base_location.value().get().pointer) + .concat(relative.value())) != nullptr; +} + auto compile(const sourcemeta::core::JSON &schema, const sourcemeta::blaze::SchemaWalker &walker, const sourcemeta::blaze::SchemaResolver &resolver, @@ -435,8 +477,14 @@ auto compile(const sourcemeta::core::JSON &schema, const auto maybe_entrypoint_location{frame.traverse(entrypoint)}; if (!maybe_entrypoint_location.has_value()) [[unlikely]] { + // A frame that only locates schemas has nothing to say about an entry + // point that names a plain keyword, so tell the two apart by asking the + // document rather than reporting a place that does exist as missing throw CompilerInvalidEntryPoint{ - entrypoint, "The given entry point URI does not exist in the schema"}; + entrypoint, + entrypoint_names_non_schema(schema, frame, entrypoint) + ? "The given entry point URI is not a valid subschema" + : "The given entry point URI does not exist in the schema"}; } const auto &entrypoint_location{maybe_entrypoint_location->get()}; @@ -455,8 +503,7 @@ auto compile(const sourcemeta::core::JSON &schema, !booleans_are_schemas(frame.vocabularies(entrypoint_location, resolver))) [[unlikely]] { throw CompilerError(sourcemeta::core::URI{entrypoint_location.base}, - to_pointer(entrypoint_location.pointer.slice( - entrypoint_location.relative_pointer)), + to_pointer(entrypoint_location.pointer), "This dialect does not support boolean schemas"); } @@ -519,20 +566,11 @@ auto compile(const sourcemeta::core::JSON &schema, return; } - auto reference_origin{frame.traverse(origin)}; + const auto reference_origin{frame.traverse(origin.initial())}; assert(reference_origin.has_value()); - while (reference_origin->get().type == - sourcemeta::blaze::SchemaFrame::LocationType::Pointer && - reference_origin->get().parent.has_value()) { - reference_origin = - frame.traverse(reference_origin->get().parent.value()); - assert(reference_origin.has_value()); - } // Skip unreachable targets - if (reference_origin->get().type != - sourcemeta::blaze::SchemaFrame::LocationType::Pointer && - !frame.is_reachable(entrypoint_location, reference_origin->get(), + if (!frame.is_reachable(entrypoint_location, reference_origin->get(), walker, resolver)) { return; } @@ -756,31 +794,49 @@ auto compile(const Context &context, const SchemaContext &schema_context, const sourcemeta::core::WeakPointer &schema_suffix, const sourcemeta::core::WeakPointer &instance_suffix, const std::optional uri) -> Instructions { - // Determine URI of the destination after recursion - const std::string destination{ - uri.has_value() - ? sourcemeta::core::URI::canonicalize(uri.value()) - : to_uri(schema_context.relative_pointer.concat(schema_suffix), - schema_context.base) - .canonicalize() - .recompose()}; - - // Otherwise the recursion attempt is non-sense - if (!context.frame - .location(sourcemeta::blaze::SchemaReferenceType::Static, - destination) - .has_value()) [[unlikely]] { - throw sourcemeta::blaze::SchemaReferenceError( - destination, to_pointer(schema_context.relative_pointer), - "The target of the reference does not exist in the schema"); + // An explicit URI is a jump elsewhere in the schema, which only the frame + // can resolve. Without one we are recursing within the subschema we are + // already at, so where we land follows from the pointer we came in with + std::optional< + std::reference_wrapper> + entry; + sourcemeta::core::WeakPointer target; + if (uri.has_value()) { + const auto destination{sourcemeta::core::URI::canonicalize(uri.value())}; + entry = context.frame.location( + sourcemeta::blaze::SchemaReferenceType::Static, destination); + // Otherwise the recursion attempt is non-sense + if (!entry.has_value()) [[unlikely]] { + throw sourcemeta::blaze::SchemaReferenceError( + destination, absolute_schema_location(context, schema_context), + "The target of the reference does not exist in the schema"); + } + + target = entry.value().get().pointer; + } else { + target = + absolute_schema_pointer(context, schema_context).concat(schema_suffix); + // Otherwise the recursion attempt is non-sense + if (sourcemeta::core::try_get(context.root, target) == nullptr) + [[unlikely]] { + throw sourcemeta::blaze::SchemaReferenceError( + to_uri(schema_context.relative_pointer.concat(schema_suffix), + schema_context.base) + .canonicalize() + .recompose(), + absolute_schema_location(context, schema_context), + "The target of the reference does not exist in the schema"); + } + + // A pointer that sits under more than one base is framed once per base, so + // this may be any of those entries. They are interchangeable here, as + // framing resolves the base, the dialect and the depth of a location from + // the resource nearest to it rather than from the URI it got keyed under, + // so every entry of a given pointer reports the same ones + entry = context.frame.traverse(target); } - const auto &entry{ - context.frame - .location(sourcemeta::blaze::SchemaReferenceType::Static, destination) - .value() - .get()}; - const auto &new_schema{get(context.root, entry.pointer)}; + const auto &new_schema{get(context.root, target)}; // An invalid schema may set an applicator to a value that is not a schema // at all, in which case we consider it to impose no constraints @@ -795,16 +851,28 @@ auto compile(const Context &context, const SchemaContext &schema_context, .concat(make_weak_pointer(dynamic_context.keyword)) .concat(schema_suffix)}; - const auto new_relative_pointer{entry.pointer.slice(entry.relative_pointer)}; + // A schema that the walker never descended into has no location of its own, + // in which case it inherits the resource and the dialect of what encloses it + const auto new_relative_pointer{ + entry.has_value() + ? entry.value().get().pointer.slice( + entry.value().get().relative_pointer) + : schema_context.relative_pointer.concat(schema_suffix)}; const sourcemeta::core::URI new_base{ - sourcemeta::core::URI{entry.base}.recompose_without_fragment().value_or( - "")}; + entry.has_value() + ? sourcemeta::core::URI{entry.value().get().base} + .recompose_without_fragment() + .value_or("") + : schema_context.base.recompose_without_fragment().value_or("")}; return compile_subschema( context, {.relative_pointer = new_relative_pointer, .schema = new_schema, - .vocabularies = context.frame.vocabularies(entry, context.resolver), + .vocabularies = entry.has_value() + ? context.frame.vocabularies(entry.value().get(), + context.resolver) + : schema_context.vocabularies, .base = new_base, .is_property_name = schema_context.is_property_name}, {.keyword = dynamic_context.keyword, diff --git a/vendor/blaze/src/compiler/compile_helpers.h b/vendor/blaze/src/compiler/compile_helpers.h index 3b91fb79..358cd87f 100644 --- a/vendor/blaze/src/compiler/compile_helpers.h +++ b/vendor/blaze/src/compiler/compile_helpers.h @@ -328,14 +328,58 @@ unsigned_integer_property(const sourcemeta::core::JSON &document, return unsigned_integer_property(document, property).value_or(otherwise); } -inline auto static_frame_entry(const Context &context, - const SchemaContext &schema_context) - -> const sourcemeta::blaze::SchemaFrame::Location & { - const auto current{ - to_uri(schema_context.relative_pointer, schema_context.base).recompose()}; - const auto type{sourcemeta::blaze::SchemaReferenceType::Static}; - assert(context.frame.location(type, current).has_value()); - return context.frame.location(type, current).value().get(); +// A schema context only knows where it sits within the schema resource that +// encloses it, while an error must report where the problem is within the +// document that the schema came from. Prepending the pointer of that resource +// bridges the two, so that a consumer can resolve the location against the +// document it parsed without keeping a frame of its own +inline auto +absolute_schema_location(const Context &context, + const sourcemeta::core::URI &base, + const sourcemeta::core::WeakPointer &relative_pointer) + -> sourcemeta::core::Pointer { + const auto resource{context.frame.location( + sourcemeta::blaze::SchemaReferenceType::Static, base.recompose())}; + // Framing is where this base came from, so the resource it names is there. + // Were that to stop holding, the relative pointer is all we could report, + // and it would silently mean something else, so catch the drift here + assert(resource.has_value()); + if (!resource.has_value()) [[unlikely]] { + return to_pointer(relative_pointer); + } + + return to_pointer(resource.value().get().pointer.concat(relative_pointer)); +} + +inline auto absolute_schema_location(const Context &context, + const SchemaContext &schema_context) + -> sourcemeta::core::Pointer { + return absolute_schema_location(context, schema_context.base, + schema_context.relative_pointer); +} + +// Same bridging as above, but keeping the pointer weak, as every caller only +// wants to address the frame with it rather than to hand it out +inline auto +absolute_schema_pointer(const Context &context, + const sourcemeta::core::URI &base, + const sourcemeta::core::WeakPointer &relative_pointer) + -> sourcemeta::core::WeakPointer { + const auto resource{context.frame.location( + sourcemeta::blaze::SchemaReferenceType::Static, base.recompose())}; + assert(resource.has_value()); + if (!resource.has_value()) [[unlikely]] { + return relative_pointer; + } + + return resource.value().get().pointer.concat(relative_pointer); +} + +inline auto absolute_schema_pointer(const Context &context, + const SchemaContext &schema_context) + -> sourcemeta::core::WeakPointer { + return absolute_schema_pointer(context, schema_context.base, + schema_context.relative_pointer); } // Whether the current keyword value, as a schema, contains any nested @@ -346,9 +390,8 @@ inline auto static_frame_entry(const Context &context, inline auto defines_nested_subschemas(const Context &context, const SchemaContext &schema_context) -> bool { - const auto &entry{static_frame_entry(context, schema_context)}; return context.frame.any_subschema_under( - entry.pointer, + absolute_schema_pointer(context, schema_context), [](const sourcemeta::blaze::SchemaFrame::Location &) -> bool { return true; }); @@ -371,12 +414,15 @@ inline auto find_adjacent(const Context &context, const std::set &vocabularies, const std::string &keyword, const sourcemeta::core::JSON::Type type) -> auto { - std::vector possible_keyword_uris; - possible_keyword_uris.push_back( - to_uri(schema_context.relative_pointer.initial().concat( - make_weak_pointer(keyword)), - schema_context.base) - .recompose()); + // A candidate is the subschema that may declare the keyword, paired with the + // vocabularies in force there, as following a reference can land the search + // in a resource that speaks a different dialect than the one we started from + std::vector>> + candidates; + const auto current{ + absolute_schema_pointer(context, schema_context).initial()}; + candidates.emplace_back(current, std::cref(schema_context.vocabularies)); // TODO: Do something similar with `allOf` @@ -384,62 +430,40 @@ inline auto find_adjacent(const Context &context, static const std::string ref_keyword{"$ref"}; if (schema_context.schema.defines("$ref")) { const auto reference_type{sourcemeta::blaze::SchemaReferenceType::Static}; - const auto destination_uri{ - to_uri(schema_context.relative_pointer.initial().concat( - make_weak_pointer(ref_keyword)), - schema_context.base) - .recompose()}; - assert(context.frame.location(reference_type, destination_uri).has_value()); - const auto &destination{ - context.frame.location(reference_type, destination_uri).value().get()}; - assert(context.frame.reference(reference_type, destination.pointer) - .has_value()); + const auto origin{current.concat(make_weak_pointer(ref_keyword))}; + assert(context.frame.reference(reference_type, origin).has_value()); const auto &reference{ - context.frame.reference(reference_type, destination.pointer) - .value() - .get()}; - const auto keyword_uri{ - sourcemeta::core::to_uri( - sourcemeta::core::to_pointer( - std::string{reference.fragment.value_or("")}) - .concat(keyword)) - .resolve_from(sourcemeta::core::URI{reference.base})}; + context.frame.reference(reference_type, origin).value().get()}; + const auto destination{context.frame.traverse(reference.destination)}; // TODO: When this logic is used by // `unevaluatedProperties`/`unevaluatedItems`, how can we let the // applicators we detect here know that they have already been taken into // consideration and thus do not have to track evaluation? - possible_keyword_uris.push_back(keyword_uri.recompose()); + if (destination.has_value()) { + candidates.emplace_back( + destination.value().get().pointer, + std::cref(context.frame.vocabularies(destination.value().get(), + context.resolver))); + } } std::vector> result; - for (const auto &possible_keyword_uri : possible_keyword_uris) { - if (!context.frame - .location(sourcemeta::blaze::SchemaReferenceType::Static, - possible_keyword_uri) - .has_value()) { + for (const auto &[subschema, subschema_vocabularies] : candidates) { + const auto *value{sourcemeta::core::try_get( + context.root, subschema.concat(make_weak_pointer(keyword)))}; + if (value == nullptr) { continue; } - const auto &frame_entry{ - context.frame - .location(sourcemeta::blaze::SchemaReferenceType::Static, - possible_keyword_uri) - .value() - .get()}; - const auto &subschema{ - sourcemeta::core::get(context.root, frame_entry.pointer)}; - const auto subschema_vocabularies{ - context.frame.vocabularies(frame_entry, context.resolver)}; - if (std::ranges::any_of( vocabularies, [&subschema_vocabularies](const auto &vocabulary) -> auto { - return subschema_vocabularies.contains(vocabulary); + return subschema_vocabularies.get().contains(vocabulary); }) && - subschema.type() == type) { - result.emplace_back(subschema); + value->type() == type) { + result.emplace_back(*value); } } @@ -481,8 +505,8 @@ inline auto requires_evaluation(const Context &context, inline auto requires_evaluation(const Context &context, const SchemaContext &schema_context) -> bool { - const auto &entry{static_frame_entry(context, schema_context)}; - return requires_evaluation(context, entry.pointer); + return requires_evaluation(context, + absolute_schema_pointer(context, schema_context)); } inline auto annotations_enabled(const Context &context, diff --git a/vendor/blaze/src/compiler/default_compiler_2019_09.h b/vendor/blaze/src/compiler/default_compiler_2019_09.h index e55822e9..e1e36a7e 100644 --- a/vendor/blaze/src/compiler/default_compiler_2019_09.h +++ b/vendor/blaze/src/compiler/default_compiler_2019_09.h @@ -15,7 +15,7 @@ auto compiler_2019_09_applicator_dependentschemas( -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_object()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_OBJECT); } @@ -26,7 +26,7 @@ auto compiler_2019_09_applicator_dependentschemas( return is_schema(entry.second, allow_boolean); })) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_SCHEMA_OBJECT); } @@ -78,7 +78,7 @@ auto compiler_2019_09_validation_dependentrequired( -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_object()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_OBJECT); } @@ -88,7 +88,7 @@ auto compiler_2019_09_validation_dependentrequired( return is_string_array(entry.second); })) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_DEPENDENCIES); } @@ -395,7 +395,7 @@ auto compiler_2019_09_applicator_unevaluatedproperties( "patternProperties"}; filter_regexes.push_back( {.first = parse_regex( - property.first, schema_context.base, + property.first, context, schema_context.base, schema_context.relative_pointer.initial().concat( sourcemeta::blaze::make_weak_pointer( pattern_properties_keyword))), @@ -456,11 +456,11 @@ auto compiler_2019_09_core_recursiveref(const Context &context, const DynamicContext &dynamic_context, const Instructions ¤t) -> Instructions { - const auto &entry{static_frame_entry(context, schema_context)}; + const auto entry_pointer{absolute_schema_pointer(context, schema_context)}; // In this case, just behave as a normal static reference if (!context.frame .reference(sourcemeta::blaze::SchemaReferenceType::Dynamic, - entry.pointer) + entry_pointer) .has_value()) { return compiler_draft3_core_ref(context, schema_context, dynamic_context, current); diff --git a/vendor/blaze/src/compiler/default_compiler_2020_12.h b/vendor/blaze/src/compiler/default_compiler_2020_12.h index 1bae92b5..2cd45fff 100644 --- a/vendor/blaze/src/compiler/default_compiler_2020_12.h +++ b/vendor/blaze/src/compiler/default_compiler_2020_12.h @@ -70,11 +70,11 @@ auto compiler_2020_12_core_dynamicref(const Context &context, const DynamicContext &dynamic_context, const Instructions ¤t) -> Instructions { - const auto &entry{static_frame_entry(context, schema_context)}; + const auto entry_pointer{absolute_schema_pointer(context, schema_context)}; // In this case, just behave as a normal static reference if (!context.frame .reference(sourcemeta::blaze::SchemaReferenceType::Dynamic, - entry.pointer) + entry_pointer) .has_value()) { return compiler_draft3_core_ref(context, schema_context, dynamic_context, current); diff --git a/vendor/blaze/src/compiler/default_compiler_draft3.h b/vendor/blaze/src/compiler/default_compiler_draft3.h index 43c13948..1c4e2971 100644 --- a/vendor/blaze/src/compiler/default_compiler_draft3.h +++ b/vendor/blaze/src/compiler/default_compiler_draft3.h @@ -14,13 +14,15 @@ #include "compile_helpers.h" static auto parse_regex(const std::string &pattern, + const sourcemeta::blaze::Context &context, const sourcemeta::core::URI &base, const sourcemeta::core::WeakPointer &schema_location) -> sourcemeta::core::Regex { const auto result{sourcemeta::core::to_regex(pattern)}; if (!result.has_value()) [[unlikely]] { throw sourcemeta::blaze::CompilerInvalidRegexError( - base, to_pointer(schema_location), pattern); + base, absolute_schema_location(context, base, schema_location), + pattern); } return result.value(); @@ -399,14 +401,13 @@ auto compiler_draft3_core_ref(const Context &context, const SchemaContext &schema_context, const DynamicContext &dynamic_context, const Instructions &) -> Instructions { - const auto &entry{static_frame_entry(context, schema_context)}; + const auto entry_pointer{absolute_schema_pointer(context, schema_context)}; const auto type{sourcemeta::blaze::SchemaReferenceType::Static}; - const auto reference{context.frame.reference(type, entry.pointer)}; + const auto reference{context.frame.reference(type, entry_pointer)}; if (!reference.has_value()) [[unlikely]] { throw sourcemeta::blaze::SchemaReferenceError( schema_context.schema.at(dynamic_context.keyword).to_string(), - to_pointer(schema_context.relative_pointer), - "Could not resolve schema reference"); + to_pointer(entry_pointer), "Could not resolve schema reference"); } const auto key{std::make_tuple(type, @@ -454,12 +455,13 @@ auto properties_as_loop(const Context &context, } } - const auto ¤t_entry{static_frame_entry(context, schema_context)}; + const auto current_entry_pointer{ + absolute_schema_pointer(context, schema_context)}; const auto inside_disjunctor{ is_inside_disjunctor(schema_context.relative_pointer) || // Check if any reference from `anyOf` or `oneOf` points to us context.frame.any_reference( - [&context, ¤t_entry]( + [&context, ¤t_entry_pointer]( const sourcemeta::blaze::SchemaReferenceType, const sourcemeta::core::WeakPointer &origin, const sourcemeta::blaze::SchemaFrame::Reference &reference) @@ -472,7 +474,7 @@ auto properties_as_loop(const Context &context, } return is_inside_disjunctor(origin) && - current_entry.pointer.initial() == + current_entry_pointer.initial() == destination.value().get().pointer; })}; @@ -645,7 +647,7 @@ auto compiler_draft3_applicator_properties_with_options( if (!schema_context.schema.at(dynamic_context.keyword).is_object()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_OBJECT); } @@ -680,8 +682,8 @@ auto compiler_draft3_applicator_properties_with_options( if (emit_annotation) { substeps.push_back( - make(sourcemeta::blaze::InstructionIndex::AnnotationEmit, context, - schema_context, relative_dynamic_context(), + make(sourcemeta::blaze::InstructionIndex::AnnotationEmitWrapped, + context, schema_context, relative_dynamic_context(), sourcemeta::core::JSON{name})); } @@ -839,8 +841,8 @@ auto compiler_draft3_applicator_properties_with_options( for (auto &&[name, substeps] : properties) { if (emit_annotation) { substeps.push_back( - make(sourcemeta::blaze::InstructionIndex::AnnotationEmit, context, - schema_context, effective_dynamic_context, + make(sourcemeta::blaze::InstructionIndex::AnnotationEmitWrapped, + context, schema_context, effective_dynamic_context, sourcemeta::core::JSON{name})); } @@ -1166,7 +1168,7 @@ auto compiler_draft3_applicator_patternproperties_with_options( const bool track_evaluation) -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_object()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_OBJECT); } @@ -1216,13 +1218,13 @@ auto compiler_draft3_applicator_patternproperties_with_options( schema_context.schema.defines("additionalProperties") && schema_context.schema.at("additionalProperties").is_boolean() && !schema_context.schema.at("additionalProperties").to_boolean()) { - children.push_back( - make(sourcemeta::blaze::InstructionIndex::LoopPropertiesRegexClosed, - context, schema_context, dynamic_context, - ValueRegex{.first = parse_regex(pattern, schema_context.base, - schema_context.relative_pointer), - .second = pattern}, - std::move(substeps))); + children.push_back(make( + sourcemeta::blaze::InstructionIndex::LoopPropertiesRegexClosed, + context, schema_context, dynamic_context, + ValueRegex{.first = parse_regex(pattern, context, schema_context.base, + schema_context.relative_pointer), + .second = pattern}, + std::move(substeps))); // If the `patternProperties` subschema for the given pattern does // nothing, then we can avoid generating an entire loop for it @@ -1234,13 +1236,14 @@ auto compiler_draft3_applicator_patternproperties_with_options( context, schema_context, dynamic_context, ValueString{maybe_prefix.value()}, std::move(substeps))); } else { - children.push_back(make( - sourcemeta::blaze::InstructionIndex::LoopPropertiesRegex, context, - schema_context, dynamic_context, - ValueRegex{.first = parse_regex(pattern, schema_context.base, - schema_context.relative_pointer), - .second = pattern}, - std::move(substeps))); + children.push_back( + make(sourcemeta::blaze::InstructionIndex::LoopPropertiesRegex, + context, schema_context, dynamic_context, + ValueRegex{ + .first = parse_regex(pattern, context, schema_context.base, + schema_context.relative_pointer), + .second = pattern}, + std::move(substeps))); } } } @@ -1351,7 +1354,7 @@ auto compiler_draft3_applicator_additionalproperties_with_options( "patternProperties"}; filter_regexes.push_back( {.first = - parse_regex(entry.first, schema_context.base, + parse_regex(entry.first, context, schema_context.base, schema_context.relative_pointer.initial().concat( sourcemeta::blaze::make_weak_pointer( pattern_properties_keyword))), @@ -1473,7 +1476,7 @@ auto compiler_draft3_validation_pattern(const Context &context, const Instructions &) -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_string()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_STRING); } @@ -1485,12 +1488,12 @@ auto compiler_draft3_validation_pattern(const Context &context, const auto ®ex_string{ schema_context.schema.at(dynamic_context.keyword).to_string()}; - return { - make(sourcemeta::blaze::InstructionIndex::AssertionRegex, context, - schema_context, dynamic_context, - ValueRegex{.first = parse_regex(regex_string, schema_context.base, - schema_context.relative_pointer), - .second = regex_string})}; + return {make(sourcemeta::blaze::InstructionIndex::AssertionRegex, context, + schema_context, dynamic_context, + ValueRegex{.first = parse_regex(regex_string, context, + schema_context.base, + schema_context.relative_pointer), + .second = regex_string})}; } auto compiler_draft3_applicator_items_array( @@ -1503,7 +1506,7 @@ auto compiler_draft3_applicator_items_array( if (!schema_context.schema.at(dynamic_context.keyword).is_array()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_ARRAY); } @@ -1517,7 +1520,7 @@ auto compiler_draft3_applicator_items_array( !all_are_schemas(items, booleans_are_schemas(schema_context.vocabularies))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), allows_empty ? EXPECTED_SCHEMA_ARRAY_ANY_SIZE : EXPECTED_SCHEMA_ARRAY); } @@ -1661,7 +1664,8 @@ auto compiler_draft3_applicator_items_with_options( !all_are_schemas(entries, booleans_are_schemas(schema_context.vocabularies))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), allows_empty ? EXPECTED_SCHEMA_ARRAY_ANY_SIZE : EXPECTED_SCHEMA_ARRAY); } @@ -1903,7 +1907,7 @@ auto compiler_draft3_validation_enum(const Context &context, const Instructions &) -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_array()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_ARRAY); } @@ -1916,7 +1920,7 @@ auto compiler_draft3_validation_enum(const Context &context, (schema_context.schema.at(dynamic_context.keyword).empty() || !schema_context.schema.at(dynamic_context.keyword).unique())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_UNIQUE_VALUES); } @@ -1992,7 +1996,7 @@ auto compiler_draft3_validation_maxlength(const Context &context, (!integral_reals_are_integers(schema_context.vocabularies) && !schema_context.schema.at(dynamic_context.keyword).is_integer())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_INTEGER); } @@ -2003,7 +2007,7 @@ auto compiler_draft3_validation_maxlength(const Context &context, {Known::JSON_Schema_Draft_3, Known::JSON_Schema_Draft_3_Hyper}) && !schema_context.schema.at(dynamic_context.keyword).is_positive()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NON_NEGATIVE); } @@ -2053,13 +2057,13 @@ auto compiler_draft3_validation_minlength(const Context &context, (!integral_reals_are_integers(schema_context.vocabularies) && !schema_context.schema.at(dynamic_context.keyword).is_integer())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_INTEGER); } if (!schema_context.schema.at(dynamic_context.keyword).is_positive()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NON_NEGATIVE); } @@ -2099,13 +2103,13 @@ auto compiler_draft3_validation_maxitems(const Context &context, (!integral_reals_are_integers(schema_context.vocabularies) && !schema_context.schema.at(dynamic_context.keyword).is_integer())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_INTEGER); } if (!schema_context.schema.at(dynamic_context.keyword).is_positive()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NON_NEGATIVE); } @@ -2140,13 +2144,13 @@ auto compiler_draft3_validation_minitems(const Context &context, (!integral_reals_are_integers(schema_context.vocabularies) && !schema_context.schema.at(dynamic_context.keyword).is_integer())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_INTEGER); } if (!schema_context.schema.at(dynamic_context.keyword).is_positive()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NON_NEGATIVE); } @@ -2181,7 +2185,7 @@ auto compiler_draft3_validation_maximum(const Context &context, const Instructions &) -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_number()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NUMBER); } @@ -2217,7 +2221,7 @@ auto compiler_draft3_validation_minimum(const Context &context, const Instructions &) -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_number()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NUMBER); } @@ -2267,7 +2271,8 @@ auto compiler_draft3_validation_type(const Context &context, if (value.is_array()) { if (!is_draft3_type_union(value)) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -2554,7 +2559,8 @@ auto compiler_draft3_validation_type(const Context &context, return {}; } else { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } } else if (value.is_array() && value.size() == 1 && @@ -2597,7 +2603,8 @@ auto compiler_draft3_validation_type(const Context &context, return {}; } else { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } } else if (value.is_array()) { @@ -2609,7 +2616,8 @@ auto compiler_draft3_validation_type(const Context &context, return element.is_string() || (is_draft3 && element.is_object()); })) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -2638,7 +2646,8 @@ auto compiler_draft3_validation_type(const Context &context, types.set(std::to_underlying(sourcemeta::core::JSON::Type::String)); } else if (!is_draft3) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } } @@ -2662,7 +2671,7 @@ auto compiler_draft3_validation_type(const Context &context, // Every dialect asks that `type` be a type name or an array of them throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -2677,7 +2686,7 @@ auto compiler_draft3_validation_disallow(const Context &context, if (!value.is_string() && (!value.is_array() || !is_draft3_type_union(value))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -2766,7 +2775,7 @@ auto compiler_draft3_applicator_extends(const Context &context, !all_are_schemas(value, booleans_are_schemas(schema_context.vocabularies))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_SCHEMA_ARRAY_ANY_SIZE); } @@ -2840,7 +2849,7 @@ auto compiler_draft3_applicator_dependencies( -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_object()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_OBJECT); } @@ -2867,7 +2876,7 @@ auto compiler_draft3_applicator_dependencies( (is_draft3 && entry.second.is_string()); })) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_DEPENDENCIES); } @@ -2927,7 +2936,7 @@ auto compiler_draft3_validation_divisibleby( -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_number()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NUMBER); } @@ -2937,7 +2946,7 @@ auto compiler_draft3_validation_divisibleby( schema_context.schema.at(dynamic_context.keyword) == sourcemeta::core::JSON{0}) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_POSITIVE); } @@ -3169,7 +3178,8 @@ auto compiler_draft3_validation_format(const Context &context, // TODO: Support this old format, even though not even the official test // suite covers it throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), "The \"utc-millisec\" format is not supported in assertion mode yet"); } else if (name == "regex") { type = ValueStringType::Regex; @@ -3179,20 +3189,22 @@ auto compiler_draft3_validation_format(const Context &context, // TODO: Support this old format, even though not even the official test // suite covers it throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), "The \"style\" format is not supported in assertion mode yet"); } else if (name == "phone") { // TODO: Support this old format, even though not even the official test // suite covers it throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), "The \"phone\" format is not supported in assertion mode yet"); } else { return {}; } } else { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), unsupported_dialect_message); } diff --git a/vendor/blaze/src/compiler/default_compiler_draft4.h b/vendor/blaze/src/compiler/default_compiler_draft4.h index 1bb9bdb5..8ca81637 100644 --- a/vendor/blaze/src/compiler/default_compiler_draft4.h +++ b/vendor/blaze/src/compiler/default_compiler_draft4.h @@ -28,7 +28,7 @@ auto compiler_draft4_validation_required(const Context &context, (!allows_empty && schema_context.schema.at(dynamic_context.keyword).empty())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_PROPERTY_NAME_ARRAY); } @@ -45,7 +45,7 @@ auto compiler_draft4_applicator_allof(const Context &context, if (!is_schema_array(schema_context.schema.at(dynamic_context.keyword), booleans_are_schemas(schema_context.vocabularies))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_SCHEMA_ARRAY); } @@ -94,7 +94,7 @@ auto compiler_draft4_applicator_anyof(const Context &context, if (!is_schema_array(schema_context.schema.at(dynamic_context.keyword), booleans_are_schemas(schema_context.vocabularies))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_SCHEMA_ARRAY); } @@ -171,7 +171,7 @@ auto compiler_draft4_applicator_oneof(const Context &context, if (!is_schema_array(schema_context.schema.at(dynamic_context.keyword), booleans_are_schemas(schema_context.vocabularies))) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_SCHEMA_ARRAY); } @@ -238,13 +238,13 @@ auto compiler_draft4_validation_maxproperties( (!integral_reals_are_integers(schema_context.vocabularies) && !schema_context.schema.at(dynamic_context.keyword).is_integer())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_INTEGER); } if (!schema_context.schema.at(dynamic_context.keyword).is_positive()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NON_NEGATIVE); } @@ -279,13 +279,13 @@ auto compiler_draft4_validation_minproperties( (!integral_reals_are_integers(schema_context.vocabularies) && !schema_context.schema.at(dynamic_context.keyword).is_integer())) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_INTEGER); } if (!schema_context.schema.at(dynamic_context.keyword).is_positive()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NON_NEGATIVE); } diff --git a/vendor/blaze/src/compiler/default_compiler_draft6.h b/vendor/blaze/src/compiler/default_compiler_draft6.h index 4758e3ff..3de9f42e 100644 --- a/vendor/blaze/src/compiler/default_compiler_draft6.h +++ b/vendor/blaze/src/compiler/default_compiler_draft6.h @@ -41,7 +41,7 @@ auto compiler_draft6_validation_type(const Context &context, // No known type was named at all, which the meta-schema rejects throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -289,7 +289,8 @@ auto compiler_draft6_validation_type(const Context &context, sourcemeta::core::JSON::Type::String)}; } else { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } } else if (schema_context.schema.at(dynamic_context.keyword).is_array() && @@ -332,7 +333,8 @@ auto compiler_draft6_validation_type(const Context &context, sourcemeta::core::JSON::Type::String)}; } else { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } } else if (schema_context.schema.at(dynamic_context.keyword).is_array()) { @@ -341,7 +343,8 @@ auto compiler_draft6_validation_type(const Context &context, if (schema_context.schema.at(dynamic_context.keyword).empty() || !schema_context.schema.at(dynamic_context.keyword).unique()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -350,7 +353,8 @@ auto compiler_draft6_validation_type(const Context &context, schema_context.schema.at(dynamic_context.keyword).as_array()) { if (!type.is_string()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -373,7 +377,8 @@ auto compiler_draft6_validation_type(const Context &context, types.set(std::to_underlying(sourcemeta::core::JSON::Type::String)); } else { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, + absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } } @@ -385,7 +390,7 @@ auto compiler_draft6_validation_type(const Context &context, // Neither a type name nor a union of them, which the meta-schema rejects throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_TYPE_NAMES); } @@ -405,7 +410,7 @@ auto compiler_draft6_validation_exclusivemaximum( -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_number()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NUMBER); } @@ -428,7 +433,7 @@ auto compiler_draft6_validation_exclusiveminimum( -> Instructions { if (!schema_context.schema.at(dynamic_context.keyword).is_number()) { throw sourcemeta::blaze::CompilerError( - schema_context.base, to_pointer(schema_context.relative_pointer), + schema_context.base, absolute_schema_location(context, schema_context), EXPECTED_NUMBER); } diff --git a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h index 389a520e..dff7087b 100644 --- a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h +++ b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h @@ -47,6 +47,8 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerError : public std::exception { return this->base_; } + /// Where the problem is, as a pointer from the root of the document + /// that the schema came from [[nodiscard]] auto location() const noexcept -> const sourcemeta::core::Pointer & { return this->schema_location_; @@ -76,6 +78,8 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerInvalidRegexError return this->base_; } + /// Where the problem is, as a pointer from the root of the document + /// that the schema came from [[nodiscard]] auto location() const noexcept -> const sourcemeta::core::Pointer & { return this->schema_location_; @@ -110,6 +114,8 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerReferenceTargetNotSchemaError return this->identifier_; } + /// Where the problem is, as a pointer from the root of the document + /// that the schema came from [[nodiscard]] auto location() const noexcept -> const sourcemeta::core::Pointer & { return this->schema_location_; diff --git a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_unevaluated.h b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_unevaluated.h index 26e6c6d4..c16eefcb 100644 --- a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_unevaluated.h +++ b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_unevaluated.h @@ -38,7 +38,6 @@ using SchemaUnevaluatedEntries = /// /// This function performs a static analysis pass on `unevaluatedProperties` and /// `unevaluatedItems` occurences throughout the entire schema (if any). -/// ``` auto SOURCEMETA_BLAZE_COMPILER_EXPORT unevaluated(const sourcemeta::core::JSON &schema, const sourcemeta::blaze::SchemaFrame &frame, diff --git a/vendor/blaze/src/editor/editor.cc b/vendor/blaze/src/editor/editor.cc index 9fcc1dca..cd7a7bde 100644 --- a/vendor/blaze/src/editor/editor.cc +++ b/vendor/blaze/src/editor/editor.cc @@ -6,7 +6,6 @@ #include // assert #include // std::format -#include // std::map namespace { @@ -22,9 +21,7 @@ auto top_dynamic_anchor_location( -> std::optional< std::reference_wrapper> { // Get the location object of where we are at the moment - const auto uri{frame.uri(current)}; - assert(uri.has_value()); - const auto match{frame.traverse(uri.value().get())}; + const auto match{frame.traverse(current)}; assert(match.has_value()); const auto &location{match.value().get()}; @@ -93,17 +90,6 @@ auto for_editor(sourcemeta::core::JSON &schema, // Otherwise the input is not bundled assert(frame.standalone()); - // Note that `std::unordered_map` is slower here due to high collision rates - // from the simple pointer hashes - std::map pointer_to_uri; - frame.for_each_location( - [&pointer_to_uri]( - const sourcemeta::blaze::SchemaReferenceType, - const std::string_view uri, - const sourcemeta::blaze::SchemaFrame::Location &location) -> void { - pointer_to_uri.emplace(location.pointer, uri); - }); - // Collect reference changes frame.for_each_reference( [&](const sourcemeta::blaze::SchemaReferenceType type, @@ -116,8 +102,10 @@ auto for_editor(sourcemeta::core::JSON &schema, if (type == sourcemeta::blaze::SchemaReferenceType::Dynamic) { if (reference.fragment.has_value()) { + // A reference is a keyword of the subschema that declares it, + // which is the resource scope the search has to start from const auto destination{top_dynamic_anchor_location( - frame, origin, reference.fragment.value(), + frame, origin.initial(), reference.fragment.value(), reference.destination)}; if (!destination.has_value()) { return; @@ -139,10 +127,10 @@ auto for_editor(sourcemeta::core::JSON &schema, } } else { if (keyword == "$schema") { - // Use pre-built index instead of O(n) frame.uri() scan - const auto uri_it{pointer_to_uri.find(origin)}; - assert(uri_it != pointer_to_uri.end()); - const auto location{frame.traverse(uri_it->second)}; + // A meta-schema reference is a keyword of the subschema that + // declares it, so the base dialect to report is the one in force + // at that subschema + const auto location{frame.traverse(origin.initial())}; assert(location.has_value()); reference_changes.push_back( {.pointer = sourcemeta::core::to_pointer(origin), diff --git a/vendor/blaze/src/editor/include/sourcemeta/blaze/editor.h b/vendor/blaze/src/editor/include/sourcemeta/blaze/editor.h index 3754894d..bdee5460 100644 --- a/vendor/blaze/src/editor/include/sourcemeta/blaze/editor.h +++ b/vendor/blaze/src/editor/include/sourcemeta/blaze/editor.h @@ -39,6 +39,20 @@ namespace sourcemeta::blaze { /// #include /// #include /// +/// // A custom resolver that knows about the referenced schema +/// static auto test_resolver(std::string_view identifier) +/// -> sourcemeta::blaze::SchemaResolverResult { +/// if (identifier == "https://www.example.com/another") { +/// return sourcemeta::core::parse_json(R"JSON({ +/// "$id": "https://www.example.com/another", +/// "$schema": "https://json-schema.org/draft/2020-12/schema", +/// "type": "string" +/// })JSON"); +/// } else { +/// return sourcemeta::blaze::schema_resolver(identifier); +/// } +/// } +/// /// auto schema = sourcemeta::core::parse_json(R"JSON({ /// "$id": "https://www.example.com/schema", /// "$schema": "https://json-schema.org/draft/2020-12/schema", @@ -46,12 +60,10 @@ namespace sourcemeta::blaze { /// })JSON"); /// /// sourcemeta::blaze::bundle(schema, -/// sourcemeta::blaze::schema_walker, -/// sourcemeta::blaze::schema_resolver, +/// sourcemeta::blaze::schema_walker, test_resolver, /// sourcemeta::blaze::BundleMode::NonOfficialMetaschemas); /// sourcemeta::blaze::for_editor(schema, -/// sourcemeta::blaze::schema_walker, -/// sourcemeta::blaze::schema_resolver); +/// sourcemeta::blaze::schema_walker, test_resolver); /// ``` SOURCEMETA_BLAZE_EDITOR_EXPORT auto for_editor(sourcemeta::core::JSON &schema, diff --git a/vendor/blaze/src/evaluator/evaluator_describe.cc b/vendor/blaze/src/evaluator/evaluator_describe.cc index 2544241a..dc5b8843 100644 --- a/vendor/blaze/src/evaluator/evaluator_describe.cc +++ b/vendor/blaze/src/evaluator/evaluator_describe.cc @@ -483,7 +483,8 @@ auto describe(const bool valid, const Instruction &step, return message.str(); } - if (step.type == sourcemeta::blaze::InstructionIndex::AnnotationEmit) { + if (step.type == sourcemeta::blaze::InstructionIndex::AnnotationEmit || + step.type == sourcemeta::blaze::InstructionIndex::AnnotationEmitWrapped) { if (keyword == "properties") { assert(annotation.is_string()); std::ostringstream message; diff --git a/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator.h b/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator.h index 4be5a3aa..95737f68 100644 --- a/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator.h +++ b/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator.h @@ -46,7 +46,7 @@ struct Template { }; /// @ingroup evaluator -constexpr std::size_t JSON_VERSION{6}; +constexpr std::size_t JSON_VERSION{7}; /// @ingroup evaluator /// Parse a template from JSON @@ -136,9 +136,11 @@ class SOURCEMETA_BLAZE_EVALUATOR_EXPORT Evaluator { /// #include /// /// #include + /// #include /// #include /// /// #include + /// #include /// #include /// /// const sourcemeta::core::JSON schema = @@ -153,21 +155,28 @@ class SOURCEMETA_BLAZE_EVALUATOR_EXPORT Evaluator { /// sourcemeta::blaze::default_schema_compiler)}; /// /// static auto callback( - /// bool result, + /// const sourcemeta::blaze::EvaluationType type, + /// const bool result, /// const sourcemeta::blaze::Instruction &instruction, - /// const sourcemeta::core::Pointer &evaluate_path, - /// const sourcemeta::core::Pointer &instance_location, - /// const sourcemeta::core::JSON &document, + /// const sourcemeta::blaze::InstructionExtra &extra, + /// const sourcemeta::core::WeakPointer &evaluate_path, + /// const sourcemeta::core::WeakPointer &instance_location, /// const sourcemeta::core::JSON &annotation) -> void { - /// std::cout << "TYPE: " << (result ? "Success" : "Failure") << "\n"; - /// std::cout << "INSTRUCTION:\n"; - /// sourcemeta::core::prettify(sourcemeta::blaze::to_json({instruction}), - /// std::cout); - /// std::cout << "\nEVALUATE PATH:"; + /// if (type == sourcemeta::blaze::EvaluationType::Pre) { + /// return; + /// } + /// + /// std::cout << "RESULT: " << (result ? "Success" : "Failure") << "\n"; + /// std::cout << "INSTRUCTION: " + /// << sourcemeta::blaze::InstructionNames[ + /// static_cast(instruction.type)] + /// << "\n"; + /// std::cout << "KEYWORD LOCATION: " << extra.keyword_location << "\n"; + /// std::cout << "EVALUATE PATH: "; /// sourcemeta::core::stringify(evaluate_path, std::cout); - /// std::cout << "\nINSTANCE LOCATION:"; + /// std::cout << "\nINSTANCE LOCATION: "; /// sourcemeta::core::stringify(instance_location, std::cout); - /// std::cout << "\nANNOTATION:\n"; + /// std::cout << "\nANNOTATION: "; /// sourcemeta::core::prettify(annotation, std::cout); /// std::cout << "\n"; /// } diff --git a/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_dispatch.h b/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_dispatch.h index b68013c2..bfcb5277 100644 --- a/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_dispatch.h +++ b/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_dispatch.h @@ -1579,6 +1579,12 @@ INSTRUCTION_HANDLER(AnnotationEmit) { value); } +INSTRUCTION_HANDLER(AnnotationEmitWrapped) { + const auto &value{assume_value(instruction.value)}; + EVALUATE_ANNOTATION(AnnotationEmitWrapped, + context.evaluator->instance_location, value); +} + INSTRUCTION_HANDLER(AnnotationToParent) { const auto &value{assume_value(instruction.value)}; EVALUATE_ANNOTATION( @@ -2816,7 +2822,7 @@ using DispatchHandler = bool (*)( template // Must have same order as InstructionIndex // NOLINTNEXTLINE(modernize-avoid-c-arrays) -static constexpr DispatchHandler handlers[100] = { +static constexpr DispatchHandler handlers[101] = { AssertionFail, AssertionDefines, AssertionDefinesStrict, @@ -2868,6 +2874,7 @@ static constexpr DispatchHandler handlers[100] = { AssertionArrayPrefixEvaluate, AssertionObjectPropertiesSimple, AnnotationEmit, + AnnotationEmitWrapped, AnnotationToParent, AnnotationBasenameToParent, Evaluate, diff --git a/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_instruction.h b/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_instruction.h index 952ce521..f23dad3a 100644 --- a/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_instruction.h +++ b/vendor/blaze/src/evaluator/include/sourcemeta/blaze/evaluator_instruction.h @@ -71,6 +71,7 @@ enum class InstructionIndex : std::uint8_t { AssertionArrayPrefixEvaluate, AssertionObjectPropertiesSimple, AnnotationEmit, + AnnotationEmitWrapped, AnnotationToParent, AnnotationBasenameToParent, Evaluate, @@ -176,6 +177,7 @@ constexpr std::string_view InstructionNames[] = { "AssertionArrayPrefixEvaluate", "AssertionObjectPropertiesSimple", "AnnotationEmit", + "AnnotationEmitWrapped", "AnnotationToParent", "AnnotationBasenameToParent", "Evaluate", @@ -237,6 +239,21 @@ inline auto is_annotation(const InstructionIndex type) noexcept -> bool { return true; case InstructionIndex::AnnotationEmit: return true; + case InstructionIndex::AnnotationEmitWrapped: + return true; + default: + return false; + } +} + +/// @ingroup evaluator +/// Check if a given instruction type corresponds to a wrapped annotation +inline auto is_wrapped_annotation(const InstructionIndex type) noexcept + -> bool { + switch (type) { + case InstructionIndex::AnnotationBasenameToParent: + case InstructionIndex::AnnotationEmitWrapped: + return true; default: return false; } diff --git a/vendor/blaze/src/format/include/sourcemeta/blaze/format.h b/vendor/blaze/src/format/include/sourcemeta/blaze/format.h index e81b6e9a..02e58e65 100644 --- a/vendor/blaze/src/format/include/sourcemeta/blaze/format.h +++ b/vendor/blaze/src/format/include/sourcemeta/blaze/format.h @@ -38,8 +38,11 @@ namespace sourcemeta::blaze { /// #include /// /// sourcemeta::core::JSON schema = -/// sourcemeta::core::parse_json( -/// "{ \"type\": \"string\", \"minLength\": 3 }"); +/// sourcemeta::core::parse_json(R"JSON({ +/// "type": "string", +/// "minLength": 3, +/// "$schema": "https://json-schema.org/draft/2020-12/schema" +/// })JSON"); /// sourcemeta::blaze::format(schema, sourcemeta::blaze::schema_walker, /// sourcemeta::blaze::schema_resolver); /// std::ostringstream stream; diff --git a/vendor/blaze/src/foundation/frame.cc b/vendor/blaze/src/foundation/frame.cc index 88baee4a..dfff1620 100644 --- a/vendor/blaze/src/foundation/frame.cc +++ b/vendor/blaze/src/foundation/frame.cc @@ -520,6 +520,9 @@ auto SchemaFrame::to_json( case SchemaFrame::Mode::References: root.assign_assume_new("mode", sourcemeta::core::JSON{"references"}); break; + case SchemaFrame::Mode::Pointers: + root.assign_assume_new("mode", sourcemeta::core::JSON{"pointers"}); + break; } const auto destinations{ @@ -720,6 +723,10 @@ struct SchemaFrame::Cache { canonical_pointer_; std::unordered_map location_to_canonical_; + // The key that a location is stored under, so that reporting the URI of a + // pointer does not have to search the locations for the entry it already has + std::unordered_map + location_to_uri_; bool standalone_{false}; bool has_dynamic_references_{false}; @@ -1049,7 +1056,7 @@ SchemaFrame::SchemaFrame(const Mode mode, const sourcemeta::core::JSON &root, } } - if (this->mode_ == SchemaFrame::Mode::References) { + if (this->mode_ >= SchemaFrame::Mode::References) { // Handle metaschema references const auto maybe_metaschema{sourcemeta::blaze::dialect( entry.common.subschema.get(), {}, false)}; @@ -1201,6 +1208,11 @@ SchemaFrame::SchemaFrame(const Mode mode, const sourcemeta::core::JSON &root, for (const auto &relative_pointer : pointers) { const auto pointer_weak{path.concat(relative_pointer)}; + if (this->mode_ != SchemaFrame::Mode::Pointers && + !subschemas.contains(pointer_weak)) { + continue; + } + const auto combined{ find_dialect_and_all_bases(base_dialects, base_uris, pointer_weak)}; const auto &dialect_for_pointer{ @@ -1319,7 +1331,7 @@ SchemaFrame::SchemaFrame(const Mode mode, const sourcemeta::core::JSON &root, } } - if (this->mode_ != SchemaFrame::Mode::References) { + if (this->mode_ < SchemaFrame::Mode::References) { return; } @@ -1472,6 +1484,93 @@ SchemaFrame::SchemaFrame(const Mode mode, const sourcemeta::core::JSON &root, } } + // A reference may target a place that the walker never descends into, like + // a keyword value or a container that a top-level `$ref` overrides. Those + // have no location of their own outside of + // sourcemeta::blaze::SchemaFrame::Mode::Pointers, so materialise one for + // each, which costs an entry per reference rather than one per pointer of + // the analysed document + if (this->mode_ < SchemaFrame::Mode::Pointers) { + for (const auto &reference : this->references_) { + const auto &fragment{reference.second.fragment}; + if (!fragment.has_value() || !fragment.value().starts_with('/')) { + continue; + } + + if (this->locations_.contains( + {SchemaReferenceType::Static, reference.second.destination})) { + continue; + } + + const auto base_entry{this->locations_.find( + {SchemaReferenceType::Static, + sourcemeta::core::JSON::String{reference.second.base}})}; + if (base_entry == this->locations_.cend()) { + continue; + } + + // The fragment of a reference is URI-encoded, so it has to be decoded + // rather than read as-is, else an escape like `a%20b` would stand for a + // property of that literal name + const auto relative{sourcemeta::core::fragment_to_pointer( + sourcemeta::core::URI{reference.second.destination})}; + if (!relative.has_value()) { + continue; + } + + auto absolute{sourcemeta::core::to_pointer(base_entry->second.pointer) + .concat(relative.value())}; + if (sourcemeta::core::try_get(root, absolute) == nullptr) { + continue; + } + + this->reference_pointers_.push_back(std::move(absolute)); + const auto pointer_weak{ + sourcemeta::core::to_weak_pointer(this->reference_pointers_.back())}; + const auto combined{ + find_dialect_and_all_bases(base_dialects, base_uris, pointer_weak)}; + + std::size_t nearest_base_depth{base_entry->second.pointer.size()}; + std::string_view nearest_base_view{base_entry->first.second}; + for (const auto &candidate : combined.every_base) { + if (candidate.first.empty()) { + continue; + } + + nearest_base_depth = candidate.second.size(); + const auto candidate_entry{this->locations_.find( + {SchemaReferenceType::Static, + sourcemeta::core::JSON::String{candidate.first}})}; + if (candidate_entry != this->locations_.cend()) { + nearest_base_view = candidate_entry->first.second; + } + + break; + } + + const auto parent{combined.dialect_match.has_value() + ? combined.dialect_match->second + : base_entry->second.pointer}; + const auto parent_subschema{subschemas.find(parent)}; + store(this->locations_, SchemaReferenceType::Static, + SchemaFrame::LocationType::Pointer, + sourcemeta::core::JSON::String{reference.second.destination}, + nearest_base_view, pointer_weak, nearest_base_depth, + combined.dialect_match.has_value() + ? combined.dialect_match->first.get().dialects.front() + : base_entry->second.dialect, + combined.dialect_match.has_value() + ? combined.dialect_match->first.get().base_dialect + : base_entry->second.base_dialect, + parent, + parent_subschema != subschemas.cend() && + parent_subschema->second.property_name, + parent_subschema != subschemas.cend() && + parent_subschema->second.orphan, + true); + } + } + // A schema is standalone if all references can be resolved within itself this->cache_->standalone_ = std::ranges::all_of( this->references_, [&](const auto &reference) -> bool { @@ -1772,10 +1871,9 @@ auto SchemaFrame::uri(const sourcemeta::core::WeakPointer &pointer) const } if (best != nullptr) { - for (const auto &entry : this->locations_) { - if (&entry.second == best) { - return entry.first.second; - } + const auto match{this->cache_->location_to_uri_.find(best)}; + if (match != this->cache_->location_to_uri_.cend()) { + return *(match->second); } } @@ -1916,9 +2014,11 @@ auto SchemaFrame::Cache::populate_pointer_to_location(const SchemaFrame &frame) } this->pointer_to_location_.reserve(frame.locations_.size()); + this->location_to_uri_.reserve(frame.locations_.size()); for (const auto &entry : frame.locations_) { this->pointer_to_location_[std::cref(entry.second.pointer)].push_back( &entry.second); + this->location_to_uri_.emplace(&entry.second, &entry.first.second); } } @@ -2027,14 +2127,17 @@ auto SchemaFrame::Cache::populate_reachability_graph( this->populate_location_members(frame, walker, resolver); this->populate_reference_graph(frame); + // Containment edges go from the enclosing subschema straight to what it + // encloses, rather than hopping through the location of every keyword in + // between. Both reach the same set, but this one holds even when the frame + // did not register a location for each of those intermediate keywords for (const auto &entry : frame.locations_) { - if (entry.second.pointer.empty()) { + if (!entry.second.parent.has_value()) { continue; } - const auto parent_pointer{entry.second.pointer.initial()}; - auto parent_iterator = - this->pointer_to_location_.find(std::cref(parent_pointer)); + const auto parent_iterator{this->pointer_to_location_.find( + std::cref(entry.second.parent.value()))}; if (parent_iterator == this->pointer_to_location_.end()) { continue; } diff --git a/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation.h b/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation.h index f914d249..9ebaba7c 100644 --- a/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation.h +++ b/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation.h @@ -73,10 +73,8 @@ auto schema_walker(const std::string_view keyword, /// "https://example.com/my-new-id", /// sourcemeta::blaze::schema_resolver); /// -/// const auto id{sourcemeta::blaze::identify( -/// document, sourcemeta::blaze::schema_resolver)}; -/// assert(!id.empty()); -/// assert(id == "https://example.com/my-new-id"); +/// assert(document.at("$id").to_string() == +/// "https://example.com/my-new-id"); /// ``` SOURCEMETA_BLAZE_FOUNDATION_EXPORT auto schema_reidentify(sourcemeta::core::JSON &schema, diff --git a/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_error.h b/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_error.h index ec11de6c..a96d4b70 100644 --- a/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_error.h +++ b/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_error.h @@ -111,6 +111,8 @@ class SOURCEMETA_BLAZE_FOUNDATION_EXPORT SchemaReferenceError return this->identifier_; } + /// Where the problem is, as a pointer from the root of the document + /// that the schema came from [[nodiscard]] auto location() const noexcept -> const sourcemeta::core::Pointer & { return this->schema_location_; @@ -238,6 +240,8 @@ class SOURCEMETA_BLAZE_FOUNDATION_EXPORT SchemaAnchorCollisionError return this->identifier_; } + /// Where the problem is, as a pointer from the root of the document + /// that the schema came from [[nodiscard]] auto location() const noexcept -> const sourcemeta::core::Pointer & { return this->location_; diff --git a/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_frame.h b/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_frame.h index 04265236..420ff238 100644 --- a/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_frame.h +++ b/vendor/blaze/src/foundation/include/sourcemeta/blaze/foundation_frame.h @@ -15,6 +15,7 @@ #include // std::invocable #include // std::uint8_t +#include // std::deque #include // std::reference_wrapper #include // std::map #include // std::unique_ptr @@ -58,7 +59,15 @@ class SOURCEMETA_BLAZE_FOUNDATION_EXPORT SchemaFrame { /// intensive. Each mode is a superset of the previous one. Note that /// sourcemeta::blaze::SchemaFrame::Mode::Root reports on a single schema, /// so framing a wrapper that holds more than one yields no locations - enum class Mode : std::uint8_t { Root, Locations, References }; + /// + /// sourcemeta::blaze::SchemaFrame::Mode::Locations and + /// sourcemeta::blaze::SchemaFrame::Mode::References locate the schemas of + /// the document rather than each of its JSON Pointers, and the latter also + /// locates whatever place a reference names. Reach for + /// sourcemeta::blaze::SchemaFrame::Mode::Pointers only to address a keyword + /// or a value of the document by URI, as computing those locations tends to + /// dominate the cost of framing + enum class Mode : std::uint8_t { Root, Locations, References, Pointers }; /// How a caller-provided default identifier relates to the one that the /// schema declares, if any @@ -529,6 +538,11 @@ class SOURCEMETA_BLAZE_FOUNDATION_EXPORT SchemaFrame { #pragma warning(disable : 4251 4275) #endif sourcemeta::core::JSON::String root_; + // A reference may target a place that no schema location covers, in which + // case framing materialises one for it. Unlike every other location, the + // tokens of those pointers are not borrowed from the analysed document, so + // they have to be declared here to outlive the locations that borrow them + std::deque reference_pointers_; Locations locations_; References references_; // What the frame derives rather than is, kept out of line so that this diff --git a/vendor/blaze/src/output/include/sourcemeta/blaze/output_simple.h b/vendor/blaze/src/output/include/sourcemeta/blaze/output_simple.h index 344ec98e..0fdf3d32 100644 --- a/vendor/blaze/src/output/include/sourcemeta/blaze/output_simple.h +++ b/vendor/blaze/src/output/include/sourcemeta/blaze/output_simple.h @@ -88,6 +88,7 @@ class SOURCEMETA_BLAZE_OUTPUT_EXPORT SimpleOutput { sourcemeta::core::WeakPointer evaluate_path; std::reference_wrapper schema_location; sourcemeta::core::JSON value; + bool is_wrapped; }; auto operator()(const EvaluationType type, const bool result, diff --git a/vendor/blaze/src/output/include/sourcemeta/blaze/output_standard.h b/vendor/blaze/src/output/include/sourcemeta/blaze/output_standard.h index 543c3ce7..a7d02dc1 100644 --- a/vendor/blaze/src/output/include/sourcemeta/blaze/output_standard.h +++ b/vendor/blaze/src/output/include/sourcemeta/blaze/output_standard.h @@ -67,8 +67,7 @@ enum class StandardOutput : std::uint8_t { /// assert(result.at("valid").is_boolean()); /// assert(result.at("valid").to_boolean()); /// -/// sourcemeta::core::prettify(result, -/// std::cout, sourcemeta::blaze::standard_output_compare); +/// sourcemeta::core::prettify(result, std::cout); /// std::cout << "\n"; /// ``` /// diff --git a/vendor/blaze/src/output/include/sourcemeta/blaze/output_trace.h b/vendor/blaze/src/output/include/sourcemeta/blaze/output_trace.h index 47501145..3b80521d 100644 --- a/vendor/blaze/src/output/include/sourcemeta/blaze/output_trace.h +++ b/vendor/blaze/src/output/include/sourcemeta/blaze/output_trace.h @@ -48,9 +48,7 @@ namespace sourcemeta::blaze { /// /// const sourcemeta::core::JSON instance{5}; /// -/// sourcemeta::blaze::TraceOutput output{ -/// sourcemeta::blaze::schema_walker, -/// sourcemeta::blaze::schema_resolver, +/// sourcemeta::blaze::TraceOutput output{schema_template, /// [](const sourcemeta::blaze::TraceOutput::Entry &entry) { /// std::cerr << entry.name << "\n"; /// }}; diff --git a/vendor/blaze/src/output/output_simple.cc b/vendor/blaze/src/output/output_simple.cc index 30e51c2e..d21f0522 100644 --- a/vendor/blaze/src/output/output_simple.cc +++ b/vendor/blaze/src/output/output_simple.cc @@ -86,7 +86,8 @@ auto SimpleOutput::operator()( {.instance_location = instance_location, .evaluate_path = std::move(effective_evaluate_path), .schema_location = step_metadata.keyword_location, - .value = annotation}); + .value = annotation, + .is_wrapped = is_wrapped_annotation(step.type)}); } return; diff --git a/vendor/blaze/src/output/output_standard.cc b/vendor/blaze/src/output/output_standard.cc index a27751ef..a0900e72 100644 --- a/vendor/blaze/src/output/output_standard.cc +++ b/vendor/blaze/src/output/output_standard.cc @@ -29,15 +29,21 @@ struct AnnotationLocation { std::reference_wrapper schema_location; }; +struct AnnotationGroup { + std::vector values; + bool is_wrapped{false}; +}; + auto group_annotations(const SimpleOutput &output) - -> std::map> { - std::map> result; + -> std::map { + std::map result; for (const auto &entry : output.annotations()) { - auto &values{result[{.instance_location = entry.instance_location, - .evaluate_path = entry.evaluate_path, - .schema_location = entry.schema_location}]}; - if (values.empty() || values.back() != entry.value) { - values.push_back(entry.value); + auto &group{result[{.instance_location = entry.instance_location, + .evaluate_path = entry.evaluate_path, + .schema_location = entry.schema_location}]}; + group.is_wrapped = entry.is_wrapped; + if (group.values.empty() || group.values.back() != entry.value) { + group.values.push_back(entry.value); } } @@ -87,8 +93,15 @@ auto handle_standard(Evaluator &evaluator, const Template &schema, } } - unit.assign_assume_new("annotation", - sourcemeta::core::to_json(annotation.second)); + if (annotation.second.is_wrapped) { + unit.assign_assume_new("annotation", sourcemeta::core::to_json( + annotation.second.values)); + } else { + assert(!annotation.second.values.empty()); + unit.assign_assume_new( + "annotation", + sourcemeta::core::JSON{annotation.second.values.back()}); + } annotations.push_back(std::move(unit)); } diff --git a/vendor/blaze/src/test/include/sourcemeta/blaze/test.h b/vendor/blaze/src/test/include/sourcemeta/blaze/test.h index de024109..2bcdd811 100644 --- a/vendor/blaze/src/test/include/sourcemeta/blaze/test.h +++ b/vendor/blaze/src/test/include/sourcemeta/blaze/test.h @@ -150,6 +150,8 @@ struct SOURCEMETA_BLAZE_TEST_EXPORT TestSuite { /// #include /// #include /// + /// #include + /// #include /// #include /// /// const auto input{R"JSON({ @@ -166,8 +168,8 @@ struct SOURCEMETA_BLAZE_TEST_EXPORT TestSuite { /// })JSON"}; /// /// sourcemeta::core::PointerPositionTracker tracker; - /// const auto document{ - /// sourcemeta::core::parse_json(input, std::ref(tracker))}; + /// sourcemeta::core::JSON document{nullptr}; + /// sourcemeta::core::parse_json(input, document, std::ref(tracker)); /// /// auto suite{sourcemeta::blaze::TestSuite::parse( /// document, tracker, std::filesystem::current_path(), @@ -203,6 +205,8 @@ struct SOURCEMETA_BLAZE_TEST_EXPORT TestSuite { /// #include /// /// #include + /// #include + /// #include /// /// const auto input{R"JSON({ /// "target": "https://json-schema.org/draft/2020-12/schema", @@ -213,8 +217,8 @@ struct SOURCEMETA_BLAZE_TEST_EXPORT TestSuite { /// })JSON"}; /// /// sourcemeta::core::PointerPositionTracker tracker; - /// const auto document{ - /// sourcemeta::core::parse_json(input, std::ref(tracker))}; + /// sourcemeta::core::JSON document{nullptr}; + /// sourcemeta::core::parse_json(input, document, std::ref(tracker)); /// /// const auto suite{sourcemeta::blaze::TestSuite::parse( /// document, tracker, std::filesystem::current_path(), diff --git a/vendor/core/CMakeLists.txt b/vendor/core/CMakeLists.txt index af73da73..d2623fcb 100644 --- a/vendor/core/CMakeLists.txt +++ b/vendor/core/CMakeLists.txt @@ -50,6 +50,7 @@ option(SOURCEMETA_CORE_TESTS "Build the Sourcemeta Core tests" OFF) option(SOURCEMETA_CORE_TESTS_CI "Build the Sourcemeta Core CI tests" OFF) option(SOURCEMETA_CORE_BENCHMARK "Build the Sourcemeta Core benchmarks" OFF) option(SOURCEMETA_CORE_DOCS "Build the Sourcemeta Core docs" OFF) +option(SOURCEMETA_CORE_CLANG_TIDY_ANALYZER "Run the Clang static analyzer alongside ClangTidy" OFF) option(SOURCEMETA_CORE_INSTALL "Install the Sourcemeta Core library" ON) option(SOURCEMETA_CORE_ADDRESS_SANITIZER "Build Sourcemeta Core with an address sanitizer" OFF) option(SOURCEMETA_CORE_UNDEFINED_SANITIZER "Build Sourcemeta Core with an undefined behavior sanitizer" OFF) diff --git a/vendor/core/cmake/FindMimalloc.cmake b/vendor/core/cmake/FindMimalloc.cmake index 9ac939c4..f6f14f93 100644 --- a/vendor/core/cmake/FindMimalloc.cmake +++ b/vendor/core/cmake/FindMimalloc.cmake @@ -40,8 +40,18 @@ if(NOT Mimalloc_FOUND) add_library(mimalloc ${MIMALLOC_SOURCES}) sourcemeta_add_default_options(PRIVATE mimalloc) + # Link the resolved thread library rather than the imported target, as the + # latter obliges every consumer of the exported package to run FindThreads, + # whose try_compile cannot run inside build systems that read the export by + # tracing CMake instead of calling it. The imported target also carries a + # compile option on the platforms whose threads need one, which we set here find_package(Threads REQUIRED) - target_link_libraries(mimalloc PRIVATE Threads::Threads) + if(THREADS_HAVE_PTHREAD_ARG) + target_compile_options(mimalloc PRIVATE -pthread) + endif() + if(CMAKE_THREAD_LIBS_INIT) + target_link_libraries(mimalloc PRIVATE "${CMAKE_THREAD_LIBS_INIT}") + endif() target_include_directories(mimalloc PUBLIC "$" @@ -145,8 +155,6 @@ if(NOT Mimalloc_FOUND) COMPONENT sourcemeta_core_dev) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/mimalloc-config.cmake - "include(CMakeFindDependencyMacro)\n" - "find_dependency(Threads)\n" "include(\"\${CMAKE_CURRENT_LIST_DIR}/mimalloc.cmake\")\n" "check_required_components(\"mimalloc\")\n") install(FILES diff --git a/vendor/core/cmake/FindPCRE2.cmake b/vendor/core/cmake/FindPCRE2.cmake index 21756978..ad73b552 100644 --- a/vendor/core/cmake/FindPCRE2.cmake +++ b/vendor/core/cmake/FindPCRE2.cmake @@ -201,6 +201,7 @@ if(NOT PCRE2_FOUND) NAMELINK_COMPONENT sourcemeta_core_dev ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT sourcemeta_core_dev) + sourcemeta_library_export_flatten(pcre2) install(EXPORT pcre2 DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/pcre2" NAMESPACE PCRE2:: diff --git a/vendor/core/cmake/common/clang-tidy.cmake b/vendor/core/cmake/common/clang-tidy.cmake index f9d78a73..44680928 100644 --- a/vendor/core/cmake/common/clang-tidy.cmake +++ b/vendor/core/cmake/common/clang-tidy.cmake @@ -111,6 +111,7 @@ function(sourcemeta_clang_tidy_attempt_enable) set(CLANG_TIDY_CONFIG "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/clang-tidy.json") execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE MACOSX_SDK_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + set(SOURCEMETA_CXX_CLANG_TIDY "${CLANG_TIDY_BIN};--config-file=${CLANG_TIDY_CONFIG};-header-filter=${PROJECT_SOURCE_DIR}/src/*" "--extra-arg=-isysroot" @@ -118,6 +119,17 @@ function(sourcemeta_clang_tidy_attempt_enable) CACHE STRING "CXX_CLANG_TIDY") endif() + # The static analyzer roughly triples ClangTidy time per translation unit, so + # it stays out of the local edit loop. This sits outside the cache guard above + # so that toggling the option takes effect on an existing build tree. The + # `--checks` argument is appended to the `Checks` option of the configuration + # file rather than replacing it, so the group composes with whatever the file + # enables + set(TARGET_CLANG_TIDY "${SOURCEMETA_CXX_CLANG_TIDY}") + if(SOURCEMETA_CORE_CLANG_TIDY_ANALYZER) + list(APPEND TARGET_CLANG_TIDY "--checks=clang-analyzer-*") + endif() + set_target_properties("${SOURCEMETA_TARGET_CLANG_TIDY_ATTEMPT_ENABLE_TARGET}" - PROPERTIES CXX_CLANG_TIDY "${SOURCEMETA_CXX_CLANG_TIDY}") + PROPERTIES CXX_CLANG_TIDY "${TARGET_CLANG_TIDY}") endfunction() diff --git a/vendor/core/cmake/common/clang-tidy.json b/vendor/core/cmake/common/clang-tidy.json index c9e314e3..62bb89d3 100644 --- a/vendor/core/cmake/common/clang-tidy.json +++ b/vendor/core/cmake/common/clang-tidy.json @@ -1,7 +1,41 @@ { - "Checks": "-*, bugprone-*, -bugprone-easily-swappable-parameters,-bugprone-unchecked-optional-access, concurrency-*,cppcoreguidelines-missing-std-forward, - cppcoreguidelines-avoid-const-or-ref-data-members, modernize-*, performance-*, portability-*", + "Checks": "-*,bugprone-*,cert-*,concurrency-*,cppcoreguidelines-*,google-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,llvm-namespace-comment,-readability-avoid-const-params-in-decls,-llvm-prefer-static-over-anonymous-namespace,-hicpp-multiway-paths-covered,-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-macro-usage,-misc-no-recursion,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-cppcoreguidelines-owning-memory,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-non-private-member-variables-in-classes,-llvm-header-guard,-readability-use-anyofallof,-readability-use-concise-preprocessor-directives,-hicpp-signed-bitwise,-bugprone-easily-swappable-parameters,-google-objc-*,-google-readability-todo,-google-readability-avoid-underscore-in-googletest-name,-misc-include-cleaner,-modernize-use-std-numbers,-bugprone-exception-escape,-bugprone-macro-parentheses,-bugprone-unchecked-optional-access,-cert-dcl59-cpp,-cert-err33-c,-concurrency-mt-unsafe,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-init-variables,-cppcoreguidelines-no-malloc,-cppcoreguidelines-prefer-member-initializer,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-member-init,-cppcoreguidelines-rvalue-reference-param-not-moved,-cppcoreguidelines-special-member-functions,-google-build-namespaces,-google-build-using-namespace,-google-explicit-constructor,-google-runtime-int,-hicpp-avoid-c-arrays,-hicpp-exception-baseclass,-hicpp-explicit-conversions,-hicpp-invalid-access-moved,-hicpp-member-init,-hicpp-no-malloc,-hicpp-special-member-functions,-hicpp-uppercase-literal-suffix,-misc-anonymous-namespace-in-header,-misc-const-correctness,-misc-definitions-in-headers,-misc-misplaced-const,-misc-multiple-inheritance,-misc-redundant-expression,-misc-use-anonymous-namespace,-misc-use-internal-linkage,-modernize-use-ranges,-modernize-use-trailing-return-type,-performance-no-automatic-move,-readability-avoid-nested-conditional-operator,-readability-container-contains,-readability-convert-member-functions-to-static,-readability-function-cognitive-complexity,-readability-redundant-casting,-readability-redundant-member-init,-readability-redundant-string-init,-readability-simplify-boolean-expr,-readability-static-accessed-through-instance,-readability-suspicious-call-argument,-readability-uppercase-literal-suffix", "WarningsAsErrors": "*", "FormatStyle": "none", - "UseColor": true + "UseColor": true, + "CheckOptions": { + "bugprone-empty-catch.IgnoreCatchWithKeywords": "@TODO;@FIXME;expected", + "portability-restrict-system-includes.Includes": "*,-expected", + "readability-identifier-length.IgnoredVariableNames": "^([a-h]|[x-z]|r|s|iv|IV)$", + "readability-identifier-length.IgnoredParameterNames": "^(iv|n|x|y)$", + "readability-identifier-naming.NamespaceCase": "lower_case", + "readability-identifier-naming.ClassCase": "CamelCase", + "readability-identifier-naming.ClassIgnoredRegexp": "^const_iterator$", + "readability-identifier-naming.StructCase": "CamelCase", + "readability-identifier-naming.UnionCase": "CamelCase", + "readability-identifier-naming.EnumCase": "CamelCase", + "readability-identifier-naming.EnumConstantCase": "CamelCase", + "readability-identifier-naming.EnumConstantIgnoredRegexp": "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$", + "readability-identifier-naming.TypeAliasCase": "CamelCase", + "readability-identifier-naming.TypeAliasIgnoredRegexp": "^[a-z][a-z0-9_]*$", + "readability-identifier-naming.TypedefCase": "CamelCase", + "readability-identifier-naming.TypeTemplateParameterCase": "CamelCase", + "readability-identifier-naming.ValueTemplateParameterCase": "CamelCase", + "readability-identifier-naming.FunctionCase": "lower_case", + "readability-identifier-naming.VariableCase": "lower_case", + "readability-identifier-naming.ParameterCase": "lower_case", + "readability-identifier-naming.PublicMemberCase": "lower_case", + "readability-identifier-naming.PrivateMemberCase": "lower_case", + "readability-identifier-naming.PrivateMemberSuffix": "_", + "readability-identifier-naming.ProtectedMemberCase": "lower_case", + "readability-identifier-naming.ProtectedMemberSuffix": "_", + "readability-identifier-naming.GlobalConstantCase": "UPPER_CASE", + "readability-identifier-naming.StaticConstantCase": "UPPER_CASE", + "readability-identifier-naming.ClassConstantCase": "UPPER_CASE", + "readability-identifier-naming.ConstexprVariableCase": "UPPER_CASE", + "readability-identifier-naming.LocalConstantCase": "lower_case", + "readability-identifier-naming.LocalVariableCase": "lower_case", + "readability-identifier-naming.MacroDefinitionCase": "UPPER_CASE", + "readability-identifier-naming.MacroDefinitionIgnoredRegexp": "^[A-Z][A-Z0-9_]*_$" + } } diff --git a/vendor/core/cmake/common/targets/executable.cmake b/vendor/core/cmake/common/targets/executable.cmake index 84814a5b..1015cbde 100644 --- a/vendor/core/cmake/common/targets/executable.cmake +++ b/vendor/core/cmake/common/targets/executable.cmake @@ -71,4 +71,9 @@ function(sourcemeta_executable) endif() set_target_properties("${TARGET_NAME}" PROPERTIES FOLDER "${FOLDER_NAME}") + + # We don't want consumers to be bothered with this + if(PROJECT_IS_TOP_LEVEL) + sourcemeta_clang_tidy_attempt_enable(TARGET "${TARGET_NAME}") + endif() endfunction() diff --git a/vendor/core/cmake/common/targets/library.cmake b/vendor/core/cmake/common/targets/library.cmake index 8085dee0..94a81717 100644 --- a/vendor/core/cmake/common/targets/library.cmake +++ b/vendor/core/cmake/common/targets/library.cmake @@ -133,6 +133,32 @@ function(sourcemeta_library) endif() endfunction() +# A static library records its private dependencies as $ in the +# exported link interface. Build systems that read the export without evaluating +# generator expressions drop those entries and lose the transitive link closure, +# so unwrap them for the installed interface. The build interface keeps the +# wrapper, so that consumers within this project do not start inheriting the +# usage requirements that a private dependency is not meant to hand them +function(sourcemeta_library_export_flatten TARGET_NAME) + get_target_property(SOURCEMETA_LIBRARY_INTERFACE + ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + if(SOURCEMETA_LIBRARY_INTERFACE) + set(SOURCEMETA_LIBRARY_FLATTENED) + foreach(entry IN LISTS SOURCEMETA_LIBRARY_INTERFACE) + string(REGEX REPLACE "^\\$$" "\\1" unwrapped "${entry}") + if(unwrapped STREQUAL entry) + list(APPEND SOURCEMETA_LIBRARY_FLATTENED "${entry}") + else() + list(APPEND SOURCEMETA_LIBRARY_FLATTENED + "$" + "$") + endif() + endforeach() + set_property(TARGET ${TARGET_NAME} + PROPERTY INTERFACE_LINK_LIBRARIES ${SOURCEMETA_LIBRARY_FLATTENED}) + endif() +endfunction() + function(sourcemeta_library_install) cmake_parse_arguments(SOURCEMETA_LIBRARY "" "NAMESPACE;PROJECT;NAME;VARIANT" "" ${ARGN}) @@ -173,6 +199,12 @@ function(sourcemeta_library_install) NAMELINK_COMPONENT ${COMPONENT_NAME}_dev ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT ${COMPONENT_NAME}_dev) + # Deferred, as callers link their dependencies after installing the target. + # The target name is expanded into the deferred call, as its arguments are + # not evaluated until the call runs, by which point the variable is gone + cmake_language(EVAL CODE + "cmake_language(DEFER CALL sourcemeta_library_export_flatten ${TARGET_NAME})") + install(EXPORT ${TARGET_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${SOURCEMETA_LIBRARY_PROJECT}" NAMESPACE ${NAMESPACE_PREFIX} diff --git a/vendor/core/src/core/crypto/CMakeLists.txt b/vendor/core/src/core/crypto/CMakeLists.txt index d5170a05..03d0d327 100644 --- a/vendor/core/src/core/crypto/CMakeLists.txt +++ b/vendor/core/src/core/crypto/CMakeLists.txt @@ -129,19 +129,34 @@ elseif(APPLE) target_include_directories(sourcemeta_core_crypto PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") - target_link_libraries(sourcemeta_core_crypto PRIVATE "-framework Security") + # Resolve the frameworks to absolute bundle paths rather than passing raw + # linker flags, as the exported interface is also read by build systems that + # only understand a path to a library + find_library(CRYPTOKIT_SECURITY_FRAMEWORK Security REQUIRED) + find_library(CRYPTOKIT_CORE_FOUNDATION_FRAMEWORK CoreFoundation REQUIRED) + find_library(CRYPTOKIT_CRYPTOKIT_FRAMEWORK CryptoKit REQUIRED) + find_library(CRYPTOKIT_FOUNDATION_FRAMEWORK Foundation REQUIRED) target_link_libraries(sourcemeta_core_crypto - PRIVATE "-framework CoreFoundation") - target_link_libraries(sourcemeta_core_crypto PRIVATE "-framework CryptoKit") - target_link_libraries(sourcemeta_core_crypto PRIVATE "-framework Foundation") + PRIVATE "${CRYPTOKIT_SECURITY_FRAMEWORK}") + target_link_libraries(sourcemeta_core_crypto + PRIVATE "${CRYPTOKIT_CORE_FOUNDATION_FRAMEWORK}") + target_link_libraries(sourcemeta_core_crypto + PRIVATE "${CRYPTOKIT_CRYPTOKIT_FRAMEWORK}") + target_link_libraries(sourcemeta_core_crypto + PRIVATE "${CRYPTOKIT_FOUNDATION_FRAMEWORK}") # Resolve the Swift runtime that the shim autolinks, both at link and at load. # PUBLIC rather than INTERFACE so that a shared build of this library, which - # has its own link step pulling in the Swift object, also gets the flags + # has its own link step pulling in the Swift object, also gets the flags. + # Every option is a single token, as the multi-token spellings need a SHELL: + # prefix that only CMake knows how to strip back out of the exported + # interface, and every one of them addresses the linker directly, as these + # paths serve libraries that no command line asks for by name and a build + # system that resolves the named ones itself would drop a plain search path target_link_options(sourcemeta_core_crypto PUBLIC - "SHELL:-L ${CRYPTOKIT_SDK}/usr/lib/swift" - "SHELL:-L ${CRYPTOKIT_RUNTIME_LIB}" - "SHELL:-Xlinker -rpath -Xlinker /usr/lib/swift") + "-Wl,-L${CRYPTOKIT_SDK}/usr/lib/swift" + "-Wl,-L${CRYPTOKIT_RUNTIME_LIB}" + "-Wl,-rpath,/usr/lib/swift") elseif(WIN32) target_sources(sourcemeta_core_crypto PRIVATE crypto_sha1_windows.cc crypto_sha256_windows.cc diff --git a/vendor/core/src/core/http/CMakeLists.txt b/vendor/core/src/core/http/CMakeLists.txt index b1008acd..ba553b92 100644 --- a/vendor/core/src/core/http/CMakeLists.txt +++ b/vendor/core/src/core/http/CMakeLists.txt @@ -38,7 +38,12 @@ if(SOURCEMETA_CORE_HTTP_USE_SYSTEM_CURL) PRIVATE SOURCEMETA_CORE_HTTP_USE_SYSTEM_CURL) target_link_libraries(sourcemeta_core_http PRIVATE CURL::libcurl) elseif(APPLE) - target_link_libraries(sourcemeta_core_http PRIVATE "-framework Foundation") + # Resolve the framework to an absolute bundle path rather than passing a raw + # linker flag, as the exported interface is also read by build systems that + # only understand a path to a library + find_library(HTTP_FOUNDATION_FRAMEWORK Foundation REQUIRED) + target_link_libraries(sourcemeta_core_http + PRIVATE "${HTTP_FOUNDATION_FRAMEWORK}") elseif(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "MSYS") target_link_libraries(sourcemeta_core_http PRIVATE winhttp) target_link_libraries(sourcemeta_core_http PRIVATE sourcemeta::core::unicode) diff --git a/vendor/core/src/core/regex/include/sourcemeta/core/regex.h b/vendor/core/src/core/regex/include/sourcemeta/core/regex.h index 4b0de557..18b0aea0 100644 --- a/vendor/core/src/core/regex/include/sourcemeta/core/regex.h +++ b/vendor/core/src/core/regex/include/sourcemeta/core/regex.h @@ -181,19 +181,38 @@ auto replace_all(const Regex ®ex, const std::string_view subject, /// readings of the standard, meaning the one that JavaScript selects with the /// `u` flag or the one it selects with the `v` flag. The latter is what makes /// set notation, such as nested classes, set operations and string -/// disjunctions, come out valid. -/// -/// The legacy reading of Annex B, which JavaScript selects when no flag is -/// given, is deliberately not accepted. That reading treats a great deal of -/// otherwise malformed input as literal text, so a pattern written for another -/// flavour would pass without meaning what its author intended. The official -/// JSON Schema test suite agrees, as it requires an alarm escape to be -/// rejected even though the legacy reading accepts it as a literal. -/// -/// In practice this means that a syntax character standing on its own, such as -/// an unescaped brace or closing bracket, makes a pattern invalid, and that -/// property escapes only resolve against the property names and values that -/// the standard permits. For example: +/// disjunctions, come out valid. JSON Schema recommends the former for the +/// sake of Unicode support. +/// +/// The reading that JavaScript selects when neither flag is given is +/// deliberately not accepted. That is the reading on which Annex B of the +/// standard applies, and the standard is explicit about who that annex is +/// for: "The ECMAScript language syntax and semantics defined in this annex +/// are required when the ECMAScript host is a web browser. The content of this +/// annex is normative but optional if the ECMAScript host is not a web +/// browser." It is equally explicit about who should stay away from it: +/// "ECMAScript implementations are discouraged from implementing these +/// features unless the implementation is part of a web browser or is required +/// to run the same legacy ECMAScript code that web browsers encounter", and of +/// the features themselves it says that they "are not considered part of the +/// core ECMAScript language". Neither condition holds for reading a schema. +/// Both Unicode-aware readings turn the annex off in any case, as "none of +/// these extensions change the syntax of Unicode patterns recognized when +/// parsing with the [UnicodeMode] parameter present on the goal symbol". See +/// https://tc39.es/ecma262/#sec-additional-ecmascript-features-for-web-browsers +/// and https://tc39.es/ecma262/#sec-regular-expressions-patterns +/// +/// The practical effect of that annex is to turn a great deal of otherwise +/// malformed input into literal text, so a pattern written for another flavour +/// would pass without meaning what its author intended. Leaving it aside, a +/// syntax character standing on its own, such as an unescaped brace or closing +/// bracket, makes a pattern invalid, an escape of a letter that the standard +/// leaves undefined makes a pattern invalid, and property escapes only resolve +/// against the property names and values that the standard permits. The +/// discarded reading is also the only one that allows escaping a character +/// that cannot continue an identifier, so escaped punctuation outside a +/// character class is turned down as well. A web browser accepts all of these, +/// and this is where the two answers part company. For example: /// /// ```cpp /// #include @@ -205,12 +224,16 @@ auto replace_all(const Regex ®ex, const std::string_view subject, /// assert(!sourcemeta::core::is_regex_ecma("^(abc]")); /// assert(!sourcemeta::core::is_regex_ecma("\\a")); /// assert(!sourcemeta::core::is_regex_ecma("^{.*}$")); +/// assert(!sourcemeta::core::is_regex_ecma("a]")); +/// assert(!sourcemeta::core::is_regex_ecma("foo\\Kbar")); /// ``` /// /// Note that a pattern being valid does not mean this project can compile it, -/// as the standard places no bound on how much a quantifier may repeat while -/// the underlying engine does. Use `to_regex` to find out whether a pattern -/// can also be matched with. +/// as the standard places no bound on how much a quantifier may repeat nor on +/// how deeply groups and classes may nest, while this reader stops at 255 +/// levels and the underlying engine has limits of its own. Use `to_regex` to +/// find out whether a pattern can also be matched with, bearing in mind that +/// the dialects it offers are not the reading described here. SOURCEMETA_CORE_REGEX_EXPORT auto is_regex_ecma(const std::string_view pattern) -> bool; diff --git a/vendor/core/src/lang/memory/include/sourcemeta/core/memory_owned_or_reference.h b/vendor/core/src/lang/memory/include/sourcemeta/core/memory_owned_or_reference.h index 543afe43..f17ab39a 100644 --- a/vendor/core/src/lang/memory/include/sourcemeta/core/memory_owned_or_reference.h +++ b/vendor/core/src/lang/memory/include/sourcemeta/core/memory_owned_or_reference.h @@ -52,7 +52,7 @@ template class OwnedOrReference { /// Hold nothing // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) - OwnedOrReference(std::nullopt_t) {} + OwnedOrReference([[maybe_unused]] const std::nullopt_t value) {} /// Take ownership of a value that may or may not be there // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) diff --git a/vendor/core/src/lang/parallel/include/sourcemeta/core/parallel_for_each.h b/vendor/core/src/lang/parallel/include/sourcemeta/core/parallel_for_each.h index a7730c17..3316138f 100644 --- a/vendor/core/src/lang/parallel/include/sourcemeta/core/parallel_for_each.h +++ b/vendor/core/src/lang/parallel/include/sourcemeta/core/parallel_for_each.h @@ -7,7 +7,7 @@ #include // std::exception_ptr, std::current_exception, std::rethrow_exception #include // std::function #include // std::input_iterator, std::iter_reference_t -#include // std::mutex, std::lock_guard +#include // std::mutex, std::scoped_lock #include // std::queue #include // std::runtime_error #include // std::thread @@ -48,7 +48,7 @@ inline auto parallel_for_each_drain_and_join(std::queue &tasks, std::vector &workers) -> void { { - std::lock_guard lock{queue_mutex}; + std::scoped_lock lock{queue_mutex}; std::queue empty; tasks.swap(empty); } @@ -84,7 +84,7 @@ inline auto parallel_for_each_drain_and_join(std::queue &tasks, /// [&mutex, &result](const auto value, /// const auto parallelism, /// const auto cursor) { -/// std::lock_guard lock{mutex}; +/// std::scoped_lock lock{mutex}; /// result.push_back(value); /// std::cerr << "Processing " << cursor /// << " with parallelism " << parallelism << "\n"; @@ -128,8 +128,8 @@ auto parallel_for_each( std::exception_ptr exception = nullptr; auto handle_exception = [&exception_mutex, - &exception](std::exception_ptr pointer) { - std::lock_guard lock{exception_mutex}; + &exception](const std::exception_ptr &pointer) { + std::scoped_lock lock{exception_mutex}; if (!exception) { exception = pointer; } @@ -150,7 +150,7 @@ auto parallel_for_each( Iterator iterator; std::size_t cursor{0}; { - std::lock_guard lock{queue_mutex}; + std::scoped_lock lock{queue_mutex}; if (tasks.empty()) { return; } diff --git a/vendor/core/src/lang/process/usage.cc b/vendor/core/src/lang/process/usage.cc index e1860930..f5b68952 100644 --- a/vendor/core/src/lang/process/usage.cc +++ b/vendor/core/src/lang/process/usage.cc @@ -267,7 +267,7 @@ auto process_start_time() noexcept const std::chrono::duration since_epoch{ static_cast(information.pbi_start_tvsec) + - static_cast(information.pbi_start_tvusec) / 1000000.0}; + (static_cast(information.pbi_start_tvusec) / 1000000.0)}; return std::chrono::system_clock::time_point{ std::chrono::duration_cast( since_epoch)}; diff --git a/vendor/core/src/lang/test/include/sourcemeta/core/test.h b/vendor/core/src/lang/test/include/sourcemeta/core/test.h index 5f4d98ed..cf24caad 100644 --- a/vendor/core/src/lang/test/include/sourcemeta/core/test.h +++ b/vendor/core/src/lang/test/include/sourcemeta/core/test.h @@ -99,6 +99,9 @@ auto test_compare_equal(const Left &left, const Right &right) -> bool { test_comparable_integer) { return std::cmp_equal(left, right); } else { + // Character types reach this branch, and comparing whatever the caller + // passed is the whole point of the helper + // NOLINTNEXTLINE(bugprone-signed-char-misuse) return left == right; } } @@ -249,6 +252,10 @@ auto test_expect_comparison(std::string_view file, int line, } // namespace sourcemeta::core +// The registration symbol is a namespace-scope object whose initializer runs +// the registry call, which no static initialization check can prove +// non-throwing +// NOLINTBEGIN(cert-err58-cpp,bugprone-throwing-static-initialization) #define SOURCEMETA_CORE_TEST_REGISTER(name) \ static auto sourcemeta_test_body_##name()->void; \ [[maybe_unused]] static const int sourcemeta_test_registration_##name = \ @@ -282,6 +289,7 @@ auto test_expect_comparison(std::string_view file, int line, #define TEST_F(fixture, name) \ SOURCEMETA_CORE_TEST_REGISTER_FIXTURE(fixture, name) +// NOLINTEND(cert-err58-cpp,bugprone-throwing-static-initialization) #define SOURCEMETA_CORE_TEST_COMPARE(actual, expected, comparator, operation) \ ::sourcemeta::core::test_expect_comparison( \ @@ -307,6 +315,9 @@ auto test_expect_comparison(std::string_view file, int line, SOURCEMETA_CORE_TEST_COMPARE(actual, expected, test_compare_greater_equal, \ ">=") +// The assertion macros wrap their body in a loop so that they expand into a +// single statement that still requires a trailing semicolon at the call site +// NOLINTBEGIN(cppcoreguidelines-avoid-do-while) #define SOURCEMETA_CORE_TEST_COMPARE_FLOATING(actual, expected, type) \ do { \ const type sourcemeta_test_actual{static_cast(actual)}; \ @@ -358,6 +369,8 @@ auto test_expect_comparison(std::string_view file, int line, } \ } while (false) +// NOLINTEND(cppcoreguidelines-avoid-do-while) + #define FAIL() \ ::sourcemeta::core::test_report_failure(__FILE__, __LINE__, \ "explicit failure") diff --git a/vendor/core/src/lang/test/test.cc b/vendor/core/src/lang/test/test.cc index ad46d968..45a0966c 100644 --- a/vendor/core/src/lang/test/test.cc +++ b/vendor/core/src/lang/test/test.cc @@ -158,6 +158,19 @@ auto test_run(int argc, char **argv) -> int { std::cout << "TAP version 14\n"; std::cout << "1.." << selected.size() << "\n"; + // A test binary exists to run tests, so selecting none exits with failure on + // purpose. An empty run means either broken registration or a filter that + // matches nothing, neither of which may pass as a green suite + if (selected.empty()) { + if (needle.empty()) { + print_diagnostic("no tests were registered"); + } else { + print_diagnostic("no tests matched the filter: " + std::string{needle}); + } + + return EXIT_FAILURE; + } + std::size_t number{0}; std::size_t passed{0}; std::size_t failed{0};