Skip to content

Commit c4c2107

Browse files
committed
Prototype a new LoopItemsIntegerBounded instruction
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 58aee71 commit c4c2107

10 files changed

Lines changed: 25523 additions & 4256 deletions

src/compiler/default_compiler_draft4.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,71 @@ auto compiler_draft4_applicator_items_array(
14741474
}
14751475
}
14761476

1477+
auto is_number_type_check(const Instruction &instruction) -> bool {
1478+
if (instruction.type == InstructionIndex::AssertionTypeStrictAny) {
1479+
const auto &value{std::get<ValueTypes>(instruction.value)};
1480+
return value.test(
1481+
std::to_underlying(sourcemeta::core::JSON::Type::Integer)) &&
1482+
value.test(std::to_underlying(sourcemeta::core::JSON::Type::Real));
1483+
}
1484+
1485+
if (instruction.type == InstructionIndex::AssertionTypeStrict) {
1486+
const auto &value{std::get<ValueType>(instruction.value)};
1487+
return value == sourcemeta::core::JSON::Type::Integer ||
1488+
value == sourcemeta::core::JSON::Type::Real;
1489+
}
1490+
1491+
if (instruction.type == InstructionIndex::AssertionType) {
1492+
const auto &value{std::get<ValueType>(instruction.value)};
1493+
return value == sourcemeta::core::JSON::Type::Integer ||
1494+
value == sourcemeta::core::JSON::Type::Real;
1495+
}
1496+
1497+
return false;
1498+
}
1499+
1500+
auto is_integer_bounded_pattern(const Instructions &children) -> bool {
1501+
if (children.size() != 3) {
1502+
return false;
1503+
}
1504+
1505+
bool has_type{false};
1506+
bool has_min{false};
1507+
bool has_max{false};
1508+
for (const auto &child : children) {
1509+
if (is_number_type_check(child)) {
1510+
has_type = true;
1511+
} else if (child.type == InstructionIndex::AssertionGreaterEqual) {
1512+
if (!std::get<ValueJSON>(child.value).is_integer()) {
1513+
return false;
1514+
}
1515+
has_min = true;
1516+
} else if (child.type == InstructionIndex::AssertionLessEqual) {
1517+
if (!std::get<ValueJSON>(child.value).is_integer()) {
1518+
return false;
1519+
}
1520+
has_max = true;
1521+
}
1522+
}
1523+
1524+
return has_type && has_min && has_max;
1525+
}
1526+
1527+
auto extract_integer_bounds(const Instructions &children)
1528+
-> ValueIntegerBounds {
1529+
std::int64_t minimum{0};
1530+
std::int64_t maximum{0};
1531+
for (const auto &child : children) {
1532+
if (child.type == InstructionIndex::AssertionGreaterEqual) {
1533+
minimum = std::get<ValueJSON>(child.value).to_integer();
1534+
} else if (child.type == InstructionIndex::AssertionLessEqual) {
1535+
maximum = std::get<ValueJSON>(child.value).to_integer();
1536+
}
1537+
}
1538+
1539+
return {minimum, maximum};
1540+
}
1541+
14771542
auto compiler_draft4_applicator_items_with_options(
14781543
const Context &context, const SchemaContext &schema_context,
14791544
const DynamicContext &dynamic_context, const bool annotate,
@@ -1539,6 +1604,13 @@ auto compiler_draft4_applicator_items_with_options(
15391604
return {};
15401605
}
15411606

1607+
if (context.mode == Mode::FastValidation && children.size() == 3 &&
1608+
is_integer_bounded_pattern(children)) {
1609+
return {make(sourcemeta::blaze::InstructionIndex::LoopItemsIntegerBounded,
1610+
context, schema_context, dynamic_context,
1611+
extract_integer_bounds(children))};
1612+
}
1613+
15421614
if (context.mode == Mode::FastValidation && children.size() == 1) {
15431615
if (children.front().type == InstructionIndex::AssertionTypeStrict) {
15441616
return {make(sourcemeta::blaze::InstructionIndex::LoopItemsTypeStrict,
@@ -1614,6 +1686,15 @@ auto compiler_draft4_applicator_additionalitems_from_cursor(
16141686
Instructions children;
16151687

16161688
if (!subchildren.empty()) {
1689+
if (context.mode == Mode::FastValidation && cursor == 0 && !annotate &&
1690+
!track_evaluation && is_integer_bounded_pattern(subchildren)) {
1691+
children.push_back(
1692+
make(sourcemeta::blaze::InstructionIndex::LoopItemsIntegerBounded,
1693+
context, schema_context, dynamic_context,
1694+
extract_integer_bounds(subchildren)));
1695+
return children;
1696+
}
1697+
16171698
children.push_back(make(sourcemeta::blaze::InstructionIndex::LoopItemsFrom,
16181699
context, schema_context, dynamic_context,
16191700
ValueUnsignedInteger{cursor},

src/compiler/default_compiler_draft6.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ auto compiler_draft6_validation_type(const Context &context,
107107
LoopItemsPropertiesExactlyTypeStrictHash ||
108108
current.back().type ==
109109
sourcemeta::blaze::InstructionIndex::
110-
LoopItemsPropertiesExactlyTypeStrictHash3) &&
110+
LoopItemsPropertiesExactlyTypeStrictHash3 ||
111+
current.back().type ==
112+
sourcemeta::blaze::InstructionIndex::LoopItemsIntegerBounded) &&
111113
current.back().relative_instance_location ==
112114
to_pointer(dynamic_context.base_instance_location)) {
113115
return {};

src/evaluator/evaluator_describe.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,12 @@ auto describe(const bool valid, const Instruction &step,
775775
return message.str();
776776
}
777777

778+
if (step.type ==
779+
sourcemeta::blaze::InstructionIndex::LoopItemsIntegerBounded) {
780+
return "Every item in the array was expected to be a number within the "
781+
"given range";
782+
}
783+
778784
if (step.type == sourcemeta::blaze::InstructionIndex::LoopPropertiesType) {
779785
std::ostringstream message;
780786
message << "The object properties were expected to be of type "

src/evaluator/evaluator_json.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ auto value_from_json(const sourcemeta::core::JSON &wrapper)
4040
case 19: return sourcemeta::core::from_json<ValueTypedProperties>(value);
4141
case 20: return sourcemeta::core::from_json<ValueStringHashes>(value);
4242
case 21: return sourcemeta::core::from_json<ValueTypedHashes>(value);
43+
case 22:
44+
if (value.is_array() && value.array_size() == 2 &&
45+
value.at(0).is_integer() && value.at(1).is_integer()) {
46+
return ValueIntegerBounds{value.at(0).to_integer(),
47+
value.at(1).to_integer()};
48+
}
49+
return std::nullopt;
4350
// clang-format on
4451
default:
4552
std::unreachable();

src/evaluator/include/sourcemeta/blaze/evaluator_dispatch.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,35 @@ INSTRUCTION_HANDLER(LoopItemsPropertiesExactlyTypeStrictHash3) {
22072207
EVALUATE_END(LoopItemsPropertiesExactlyTypeStrictHash3);
22082208
}
22092209

2210+
INSTRUCTION_HANDLER(LoopItemsIntegerBounded) {
2211+
EVALUATE_BEGIN_NON_STRING(LoopItemsIntegerBounded, target.is_array());
2212+
const auto value{assume_value_copy<ValueIntegerBounds>(instruction.value)};
2213+
result = true;
2214+
for (const auto &element : target.as_array()) {
2215+
if (!element.is_number()) [[unlikely]] {
2216+
result = false;
2217+
break;
2218+
}
2219+
2220+
if (element.is_integer()) {
2221+
const auto integer{element.to_integer()};
2222+
if (integer < value.first || integer > value.second) [[unlikely]] {
2223+
result = false;
2224+
break;
2225+
}
2226+
} else {
2227+
const auto real{element.as_real()};
2228+
if (real < static_cast<double>(value.first) ||
2229+
real > static_cast<double>(value.second)) [[unlikely]] {
2230+
result = false;
2231+
break;
2232+
}
2233+
}
2234+
}
2235+
2236+
EVALUATE_END(LoopItemsIntegerBounded);
2237+
}
2238+
22102239
INSTRUCTION_HANDLER(LoopContains) {
22112240
EVALUATE_BEGIN_NON_STRING(LoopContains, target.is_array());
22122241
assert(!instruction.children.empty());
@@ -2277,7 +2306,7 @@ using DispatchHandler = bool (*)(
22772306
template <bool Track, bool Dynamic, bool HasCallback>
22782307
// Must have same order as InstructionIndex
22792308
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
2280-
static constexpr DispatchHandler<Track, Dynamic, HasCallback> handlers[95] = {
2309+
static constexpr DispatchHandler<Track, Dynamic, HasCallback> handlers[93] = {
22812310
AssertionFail,
22822311
AssertionDefines,
22832312
AssertionDefinesStrict,
@@ -2362,6 +2391,7 @@ static constexpr DispatchHandler<Track, Dynamic, HasCallback> handlers[95] = {
23622391
LoopItemsTypeStrictAny,
23632392
LoopItemsPropertiesExactlyTypeStrictHash,
23642393
LoopItemsPropertiesExactlyTypeStrictHash3,
2394+
LoopItemsIntegerBounded,
23652395
LoopContains,
23662396
ControlGroup,
23672397
ControlGroupWhenDefines,

src/evaluator/include/sourcemeta/blaze/evaluator_instruction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ enum class InstructionIndex : std::uint8_t {
104104
LoopItemsTypeStrictAny,
105105
LoopItemsPropertiesExactlyTypeStrictHash,
106106
LoopItemsPropertiesExactlyTypeStrictHash3,
107+
LoopItemsIntegerBounded,
107108
LoopContains,
108109
ControlGroup,
109110
ControlGroupWhenDefines,
@@ -201,6 +202,7 @@ constexpr std::string_view InstructionNames[] = {
201202
"LoopItemsTypeStrictAny",
202203
"LoopItemsPropertiesExactlyTypeStrictHash",
203204
"LoopItemsPropertiesExactlyTypeStrictHash3",
205+
"LoopItemsIntegerBounded",
204206
"LoopContains",
205207
"ControlGroup",
206208
"ControlGroupWhenDefines",

src/evaluator/include/sourcemeta/blaze/evaluator_value.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,19 @@ using ValueStringHashes =
155155
/// Represents a compiler step types property hashes value
156156
using ValueTypedHashes = std::pair<ValueType, ValueStringHashes>;
157157

158+
/// @ingroup evaluator
159+
/// Represents integer bounds with minimum and maximum
160+
using ValueIntegerBounds = std::pair<std::int64_t, std::int64_t>;
161+
158162
/// @ingroup evaluator
159163
using Value =
160164
std::variant<ValueNone, ValueJSON, ValueSet, ValueString, ValueProperty,
161165
ValueStrings, ValueStringSet, ValueTypes, ValueType,
162166
ValueRegex, ValueUnsignedInteger, ValueRange, ValueBoolean,
163167
ValueNamedIndexes, ValueStringType, ValueStringMap,
164168
ValuePropertyFilter, ValueIndexPair, ValuePointer,
165-
ValueTypedProperties, ValueStringHashes, ValueTypedHashes>;
169+
ValueTypedProperties, ValueStringHashes, ValueTypedHashes,
170+
ValueIntegerBounds>;
166171

167172
} // namespace sourcemeta::blaze
168173

0 commit comments

Comments
 (0)