Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions src/compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
noa_library(NAMESPACE sourcemeta PROJECT jsonbinpack NAME compiler
FOLDER "JSON BinPack/Compiler"
SOURCES
states.h compiler.cc
mapper_rules/enum_8_bit.h
mapper_rules/enum_8_bit_top_level.h
mapper_rules/enum_arbitrary.h
mapper_rules/enum_singleton.h
mapper_rules/integer_bounded_8_bit.h
mapper_rules/integer_bounded_greater_than_8_bit.h
mapper_rules/integer_bounded_multiplier_8_bit.h
mapper_rules/integer_bounded_multiplier_greater_than_8_bit.h
mapper_rules/integer_lower_bound.h
mapper_rules/integer_lower_bound_multiplier.h
mapper_rules/integer_unbound.h
mapper_rules/integer_unbound_multiplier.h
mapper_rules/integer_upper_bound.h
mapper_rules/integer_upper_bound_multiplier.h
mapper_rules/number_arbitrary.h)
states.h encoding.h compiler.cc
mapper/enum_8_bit.h
mapper/enum_8_bit_top_level.h
mapper/enum_arbitrary.h
mapper/enum_singleton.h
mapper/integer_bounded_8_bit.h
mapper/integer_bounded_greater_than_8_bit.h
mapper/integer_bounded_multiplier_8_bit.h
mapper/integer_bounded_multiplier_greater_than_8_bit.h
mapper/integer_lower_bound.h
mapper/integer_lower_bound_multiplier.h
mapper/integer_unbound.h
mapper/integer_unbound_multiplier.h
mapper/integer_upper_bound.h
mapper/integer_upper_bound_multiplier.h
mapper/number_arbitrary.h)

if(JSONBINPACK_INSTALL)
noa_library_install(NAMESPACE sourcemeta PROJECT jsonbinpack NAME compiler)
Expand Down
88 changes: 27 additions & 61 deletions src/compiler/compiler.cc
Original file line number Diff line number Diff line change
@@ -1,64 +1,31 @@
#include <sourcemeta/jsonbinpack/compiler.h>

#include <sourcemeta/alterschema/engine.h>
#include <sourcemeta/alterschema/linter.h>
#include <sourcemeta/jsonbinpack/compiler.h>
#include <sourcemeta/jsontoolkit/jsonschema.h>

#include <cassert> // assert
#include <future> // std::future
#include <limits> // std::numeric_limits

#include "encoding.h"
#include "states.h"

namespace {
constexpr auto ENCODING_V1{"tag:sourcemeta.com,2024:jsonbinpack/encoding/v1"};
auto make_resolver(const sourcemeta::jsontoolkit::SchemaResolver &fallback)
-> auto {
return [&fallback](std::string_view identifier)
-> std::future<std::optional<sourcemeta::jsontoolkit::JSON>> {
std::promise<std::optional<sourcemeta::jsontoolkit::JSON>> promise;
if (identifier == ENCODING_V1) {
promise.set_value(sourcemeta::jsontoolkit::parse(R"JSON({
"$id": "tag:sourcemeta.com,2024:jsonbinpack/encoding/v1",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true }
})JSON"));
} else {
promise.set_value(fallback(identifier).get());
}

return promise.get_future();
};
}
} // namespace

namespace sourcemeta::jsonbinpack {

auto canonicalize(sourcemeta::jsontoolkit::JSON &schema,
const sourcemeta::jsontoolkit::SchemaWalker &walker,
const sourcemeta::jsontoolkit::SchemaResolver &resolver,
const std::optional<std::string> &default_dialect) -> void {
sourcemeta::alterschema::Bundle canonicalizer;
sourcemeta::alterschema::add(
canonicalizer, sourcemeta::alterschema::LinterCategory::AntiPattern);
sourcemeta::alterschema::add(
canonicalizer, sourcemeta::alterschema::LinterCategory::Simplify);
sourcemeta::alterschema::add(
canonicalizer, sourcemeta::alterschema::LinterCategory::Desugar);
sourcemeta::alterschema::add(
canonicalizer, sourcemeta::alterschema::LinterCategory::Implicit);
sourcemeta::alterschema::add(
canonicalizer, sourcemeta::alterschema::LinterCategory::Superfluous);
namespace alterschema = sourcemeta::alterschema;
alterschema::Bundle canonicalizer;
alterschema::add(canonicalizer, alterschema::LinterCategory::AntiPattern);
alterschema::add(canonicalizer, alterschema::LinterCategory::Simplify);
alterschema::add(canonicalizer, alterschema::LinterCategory::Desugar);
alterschema::add(canonicalizer, alterschema::LinterCategory::Implicit);
alterschema::add(canonicalizer, alterschema::LinterCategory::Superfluous);
canonicalizer.apply(schema, walker, make_resolver(resolver),
sourcemeta::jsontoolkit::empty_pointer, default_dialect);
}

auto is_encoding(const sourcemeta::jsontoolkit::JSON &document) -> bool {
const std::optional<std::string> dialect{
sourcemeta::jsontoolkit::dialect(document)};
return dialect.has_value() && document.defines("name") &&
document.defines("options") && dialect.value() == ENCODING_V1;
}

auto make_encoding(sourcemeta::alterschema::Transformer &document,
const std::string &encoding,
const sourcemeta::jsontoolkit::JSON &options) -> void {
Expand All @@ -73,21 +40,21 @@ template <typename T> constexpr auto is_byte(const T value) noexcept -> bool {
return value <= std::numeric_limits<std::uint8_t>::max();
}

#include "mapper_rules/enum_8_bit.h"
#include "mapper_rules/enum_8_bit_top_level.h"
#include "mapper_rules/enum_arbitrary.h"
#include "mapper_rules/enum_singleton.h"
#include "mapper_rules/integer_bounded_8_bit.h"
#include "mapper_rules/integer_bounded_greater_than_8_bit.h"
#include "mapper_rules/integer_bounded_multiplier_8_bit.h"
#include "mapper_rules/integer_bounded_multiplier_greater_than_8_bit.h"
#include "mapper_rules/integer_lower_bound.h"
#include "mapper_rules/integer_lower_bound_multiplier.h"
#include "mapper_rules/integer_unbound.h"
#include "mapper_rules/integer_unbound_multiplier.h"
#include "mapper_rules/integer_upper_bound.h"
#include "mapper_rules/integer_upper_bound_multiplier.h"
#include "mapper_rules/number_arbitrary.h"
#include "mapper/enum_8_bit.h"
#include "mapper/enum_8_bit_top_level.h"
#include "mapper/enum_arbitrary.h"
#include "mapper/enum_singleton.h"
#include "mapper/integer_bounded_8_bit.h"
#include "mapper/integer_bounded_greater_than_8_bit.h"
#include "mapper/integer_bounded_multiplier_8_bit.h"
#include "mapper/integer_bounded_multiplier_greater_than_8_bit.h"
#include "mapper/integer_lower_bound.h"
#include "mapper/integer_lower_bound_multiplier.h"
#include "mapper/integer_unbound.h"
#include "mapper/integer_unbound_multiplier.h"
#include "mapper/integer_upper_bound.h"
#include "mapper/integer_upper_bound_multiplier.h"
#include "mapper/number_arbitrary.h"

auto compile(sourcemeta::jsontoolkit::JSON &schema,
const sourcemeta::jsontoolkit::SchemaWalker &walker,
Expand Down Expand Up @@ -122,13 +89,12 @@ auto compile(sourcemeta::jsontoolkit::JSON &schema,
sourcemeta::jsontoolkit::empty_pointer, default_dialect);

// The "any" encoding is always the last resort
if (!is_encoding(schema)) {
const auto dialect{sourcemeta::jsontoolkit::dialect(schema)};
if (!dialect.has_value() || dialect.value() != ENCODING_V1) {
sourcemeta::alterschema::Transformer transformer{schema};
make_encoding(transformer, "ANY_PACKED_TYPE_TAG_BYTE_PREFIX",
sourcemeta::jsontoolkit::JSON::make_object());
}

assert(is_encoding(schema));
}

} // namespace sourcemeta::jsonbinpack
34 changes: 34 additions & 0 deletions src/compiler/encoding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef SOURCEMETA_JSONBINPACK_COMPILER_ENCODING_H_
#define SOURCEMETA_JSONBINPACK_COMPILER_ENCODING_H_

#include <sourcemeta/jsontoolkit/json.h>
#include <sourcemeta/jsontoolkit/jsonschema.h>

#include <future> // std::future

namespace sourcemeta::jsonbinpack {

constexpr auto ENCODING_V1{"tag:sourcemeta.com,2024:jsonbinpack/encoding/v1"};

inline auto
make_resolver(const sourcemeta::jsontoolkit::SchemaResolver &fallback) -> auto {
return [&fallback](std::string_view identifier)
-> std::future<std::optional<sourcemeta::jsontoolkit::JSON>> {
std::promise<std::optional<sourcemeta::jsontoolkit::JSON>> promise;
if (identifier == ENCODING_V1) {
promise.set_value(sourcemeta::jsontoolkit::parse(R"JSON({
"$id": "tag:sourcemeta.com,2024:jsonbinpack/encoding/v1",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true }
})JSON"));
} else {
promise.set_value(fallback(identifier).get());
}

return promise.get_future();
};
}

} // namespace sourcemeta::jsonbinpack

#endif
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// TODO: Unit test this mapping once we have container encodings
class Enum8Bit final : public sourcemeta::alterschema::Rule {
public:
Enum8Bit() : sourcemeta::alterschema::Rule("enum_8_bit", "TODO") {};
Enum8Bit() : sourcemeta::alterschema::Rule{"enum_8_bit", ""} {};

[[nodiscard]] auto condition(
const sourcemeta::jsontoolkit::JSON &schema, const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &pointer) const -> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("enum") && schema.at("enum").is_array() &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
class Enum8BitTopLevel final : public sourcemeta::alterschema::Rule {
public:
Enum8BitTopLevel()
: sourcemeta::alterschema::Rule("enum_8_bit_top_level", "TODO") {};
: sourcemeta::alterschema::Rule{"enum_8_bit_top_level", ""} {};

[[nodiscard]] auto condition(
const sourcemeta::jsontoolkit::JSON &schema, const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &pointer) const -> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("enum") && schema.at("enum").is_array() &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// TODO: Unit test this mapping once we have container encodings
class EnumArbitrary final : public sourcemeta::alterschema::Rule {
public:
EnumArbitrary() : sourcemeta::alterschema::Rule("enum_arbitrary", "TODO") {};
EnumArbitrary() : sourcemeta::alterschema::Rule{"enum_arbitrary", ""} {};

[[nodiscard]] auto condition(
const sourcemeta::jsontoolkit::JSON &schema, const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &pointer) const -> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("enum") && schema.at("enum").is_array() &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
class EnumSingleton final : public sourcemeta::alterschema::Rule {
public:
EnumSingleton() : sourcemeta::alterschema::Rule("enum_singleton", "TODO") {};
EnumSingleton() : sourcemeta::alterschema::Rule{"enum_singleton", ""} {};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("enum") && schema.at("enum").is_array() &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
class IntegerBounded8Bit final : public sourcemeta::alterschema::Rule {
public:
IntegerBounded8Bit()
: sourcemeta::alterschema::Rule("integer_bounded_8_bit", "TODO") {};
: sourcemeta::alterschema::Rule{"integer_bounded_8_bit", ""} {};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("type") &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ class IntegerBoundedGreaterThan8Bit final
: public sourcemeta::alterschema::Rule {
public:
IntegerBoundedGreaterThan8Bit()
: sourcemeta::alterschema::Rule("integer_bounded_greater_than_8_bit",
"TODO") {};
: sourcemeta::alterschema::Rule{"integer_bounded_greater_than_8_bit",
""} {};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("type") &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ class IntegerBoundedMultiplier8Bit final
: public sourcemeta::alterschema::Rule {
public:
IntegerBoundedMultiplier8Bit()
: sourcemeta::alterschema::Rule("integer_bounded_multiplier_8_bit",
"TODO") {};
: sourcemeta::alterschema::Rule{"integer_bounded_multiplier_8_bit", ""} {
};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
if (is_encoding(schema) ||
dialect != "https://json-schema.org/draft/2020-12/schema" ||
if (dialect != "https://json-schema.org/draft/2020-12/schema" ||
!vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") ||
!schema.defines("type") || schema.at("type").to_string() != "integer" ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ class IntegerBoundedMultiplierGreaterThan8Bit final
: public sourcemeta::alterschema::Rule {
public:
IntegerBoundedMultiplierGreaterThan8Bit()
: sourcemeta::alterschema::Rule(
"integer_bounded_multiplier_greater_than_8_bit", "TODO") {};
: sourcemeta::alterschema::Rule{
"integer_bounded_multiplier_greater_than_8_bit", ""} {};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
if (is_encoding(schema) ||
dialect != "https://json-schema.org/draft/2020-12/schema" ||
if (dialect != "https://json-schema.org/draft/2020-12/schema" ||
!vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") ||
!schema.defines("type") || schema.at("type").to_string() != "integer" ||
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
class IntegerLowerBound final : public sourcemeta::alterschema::Rule {
public:
IntegerLowerBound()
: sourcemeta::alterschema::Rule("integer_lower_bound", "TODO") {};
: sourcemeta::alterschema::Rule{"integer_lower_bound", ""} {};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("type") &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
class IntegerLowerBoundMultiplier final : public sourcemeta::alterschema::Rule {
public:
IntegerLowerBoundMultiplier()
: sourcemeta::alterschema::Rule("integer_lower_bound_multiplier",
"TODO") {};
: sourcemeta::alterschema::Rule{"integer_lower_bound_multiplier", ""} {};

[[nodiscard]] auto condition(const sourcemeta::jsontoolkit::JSON &schema,
const std::string &dialect,
const std::set<std::string> &vocabularies,
const sourcemeta::jsontoolkit::Pointer &) const
-> bool override {
return !is_encoding(schema) &&
dialect == "https://json-schema.org/draft/2020-12/schema" &&
return dialect == "https://json-schema.org/draft/2020-12/schema" &&
vocabularies.contains(
"https://json-schema.org/draft/2020-12/vocab/validation") &&
schema.defines("type") &&
Expand Down
Loading