json: min + max integer constraints
This commit is contained in:
parent
d69ccb06a4
commit
c37c484029
2 changed files with 210 additions and 30 deletions
|
@ -161,40 +161,109 @@ static std::string format_literal(const std::string & literal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _generate_min_max_int(int min_value, int max_value, std::stringstream & out, int decimals_left = 16, bool top_level = true) {
|
static void _generate_min_max_int(int min_value, int max_value, std::stringstream & out, int decimals_left = 16, bool top_level = true) {
|
||||||
auto has_max = max_value != std::numeric_limits<int>::max();
|
|
||||||
auto has_min = min_value != std::numeric_limits<int>::min();
|
auto has_min = min_value != std::numeric_limits<int>::min();
|
||||||
|
auto has_max = max_value != std::numeric_limits<int>::max();
|
||||||
|
|
||||||
if (has_min && has_max && min_value > max_value) {
|
auto digit_range = [&](char from, char to) {
|
||||||
throw std::invalid_argument("min value must be less than or equal to max value");
|
out << "[";
|
||||||
}
|
if (from == to) {
|
||||||
if (has_min && has_max && min_value == max_value) {
|
out << from;
|
||||||
out << "\"" << min_value << "\"";
|
} else {
|
||||||
} else if (has_min && has_max) {
|
out << from << "-" << to;
|
||||||
throw std::invalid_argument("min and max values not supported yet");
|
|
||||||
} else if (has_min) {
|
|
||||||
if (min_value < 0) {
|
|
||||||
throw std::invalid_argument("negative min values not supported yet");
|
|
||||||
// out << "\"-\" ";
|
|
||||||
// _generate_min_max_int(std::nullopt, -min_value, out);
|
|
||||||
// ...
|
|
||||||
}
|
}
|
||||||
auto less_decimals = std::max(decimals_left - 1, 1);
|
out << "]";
|
||||||
auto more_digits = [&](int min_digits, int decimals) {
|
};
|
||||||
out << "[0-9]{" << min_digits << "," << decimals << "}";
|
auto more_digits = [&](int min_digits, int max_digits) {//} = std::numeric_limits<int>::max()) {
|
||||||
};
|
out << "[0-9]";
|
||||||
auto digit_range = [&](char from, char to) {
|
if (min_digits == max_digits && min_digits == 1) {
|
||||||
out << "[";
|
return;
|
||||||
if (from == to) {
|
}
|
||||||
out << from;
|
out << "{";
|
||||||
} else {
|
out << min_digits;
|
||||||
out << from << "-" << to;
|
if (max_digits != min_digits) {
|
||||||
|
out << ",";
|
||||||
|
if (max_digits != std::numeric_limits<int>::max()) {
|
||||||
|
out << max_digits;
|
||||||
}
|
}
|
||||||
out << "]";
|
}
|
||||||
};
|
out << "}";
|
||||||
|
};
|
||||||
|
std::function<void(const std::string_view &, const std::string_view &)> uniform_range = [&](const std::string_view & from, const std::string_view & to) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (from[i] == to[i]) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i > 0) {
|
||||||
|
out << "\"" << from.substr(0, i) << "\"";
|
||||||
|
}
|
||||||
|
if (i < from.length()) {
|
||||||
|
if (i > 0) {
|
||||||
|
out << " ";
|
||||||
|
}
|
||||||
|
auto sub_len = from.length() - i - 1;
|
||||||
|
if (sub_len > 0) {
|
||||||
|
auto from_sub = from.substr(i + 1);
|
||||||
|
auto to_sub = to.substr(i + 1);
|
||||||
|
auto sub_zeros = repeat("0", sub_len);
|
||||||
|
auto sub_nines = repeat("9", sub_len);
|
||||||
|
|
||||||
if (min_value == 0) {
|
auto to_reached = false;
|
||||||
|
if (from_sub == sub_zeros) {
|
||||||
|
digit_range(from[i], to[i] - 1);
|
||||||
|
out << " ";
|
||||||
|
more_digits(sub_len, sub_len);
|
||||||
|
} else {
|
||||||
|
out << "[" << from[i] << "] ";
|
||||||
|
uniform_range(from_sub, sub_nines);
|
||||||
|
if (from[i] < to[i] - 1) {
|
||||||
|
out << " | ";
|
||||||
|
if (to_sub == sub_nines) {
|
||||||
|
digit_range(from[i] + 1, to[i]);
|
||||||
|
to_reached = true;
|
||||||
|
} else {
|
||||||
|
digit_range(from[i] + 1, to[i] - 1);
|
||||||
|
}
|
||||||
|
out << " ";
|
||||||
|
more_digits(sub_len, sub_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!to_reached) {
|
||||||
|
out << " | ";
|
||||||
|
digit_range(to[i], to[i]);
|
||||||
|
out << " ";
|
||||||
|
uniform_range(sub_zeros, to_sub);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out << "[" << from[i] << "-" << to[i] << "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (has_min && has_max) {
|
||||||
|
auto min_s = std::to_string(min_value);
|
||||||
|
auto max_s = std::to_string(max_value);
|
||||||
|
auto min_digits = min_s.length();
|
||||||
|
auto max_digits = max_s.length();
|
||||||
|
|
||||||
|
for (auto digits = min_digits; digits < max_digits; digits++) {
|
||||||
|
uniform_range(min_s, repeat("9", digits));
|
||||||
|
min_s = "1" + repeat("0", digits);
|
||||||
|
out << " | ";
|
||||||
|
}
|
||||||
|
uniform_range(min_s, max_s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto less_decimals = std::max(decimals_left - 1, 1);
|
||||||
|
|
||||||
|
if (has_min) {
|
||||||
|
if (min_value < 0) {
|
||||||
|
out << "\"-\" ";
|
||||||
|
_generate_min_max_int(std::numeric_limits<int>::min(), -min_value, out, decimals_left, /* top_level= */ false);
|
||||||
|
out << " | [0] | [1-9] ";
|
||||||
|
more_digits(0, decimals_left - 1);
|
||||||
|
} else if (min_value == 0) {
|
||||||
if (top_level) {
|
if (top_level) {
|
||||||
out << "[1-9] ";
|
|
||||||
out << "[0] | [1-9] ";
|
out << "[0] | [1-9] ";
|
||||||
more_digits(0, less_decimals);
|
more_digits(0, less_decimals);
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,9 +302,26 @@ static void _generate_min_max_int(int min_value, int max_value, std::stringstrea
|
||||||
more_digits(len - 1, less_decimals);
|
more_digits(len - 1, less_decimals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
return;
|
||||||
throw std::invalid_argument("max values not supported yet");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (has_max) {
|
||||||
|
if (max_value >= 0) {
|
||||||
|
if (top_level) {
|
||||||
|
out << "\"-\" [1-9] ";
|
||||||
|
more_digits(0, less_decimals);
|
||||||
|
out << " | ";
|
||||||
|
}
|
||||||
|
_generate_min_max_int(0, max_value, out, decimals_left, /* top_level= */ true);
|
||||||
|
} else {
|
||||||
|
out << "\"-\" (";
|
||||||
|
_generate_min_max_int(std::numeric_limits<int>::min(), -max_value, out, decimals_left, /* top_level= */ false);
|
||||||
|
out << ")";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SchemaConverter {
|
class SchemaConverter {
|
||||||
|
|
|
@ -158,6 +158,100 @@ static void test_all(const std::string & lang, std::function<void(const TestCase
|
||||||
)"""
|
)"""
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"max 30",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 30
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ("-" [1-9] [0-9]{0,15} | [0-9] | [1-2] [0-9] | [3] "0") space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"min -5",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": -5
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ("-" [0-5] | [0] | [1-9] [0-9]{0,15}) space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"max 1",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 1
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ("-" [1-9] [0-9]{0,15} | [0-1]) space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"max 100",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 100
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ("-" [1-9] [0-9]{0,15} | [0-9] | [1-8] [0-9] | [9] [0-9] | "100") space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"min 0 max 23",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 23
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ([0-9] | [1] [0-9] | [2] [0-3]) space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"min 15 max 300",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 15,
|
||||||
|
"maximum": 300
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ([1] [5-9] | [2-9] [0-9] | [1-2] [0-9]{2} | [3] "00") space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
|
test({
|
||||||
|
SUCCESS,
|
||||||
|
"min 5 max 30",
|
||||||
|
R"""({
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 5,
|
||||||
|
"maximum": 30
|
||||||
|
})""",
|
||||||
|
R"""(
|
||||||
|
root ::= ([5-9] | [1-2] [0-9] | [3] "0") space
|
||||||
|
space ::= " "?
|
||||||
|
)"""
|
||||||
|
});
|
||||||
|
|
||||||
test({
|
test({
|
||||||
FAILURE,
|
FAILURE,
|
||||||
"unknown type",
|
"unknown type",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue