16 char value, std::vector<char>& expected_closers,
int line_num) {
18 expected_closers.push_back(closer);
22 if (expected_closers.empty() || expected_closers.back() !=
value) {
23 throw std::invalid_argument(
24 "Line " + std::to_string(line_num) +
25 ": mismatched expression delimiter");
27 expected_closers.pop_back();
32 const std::string& text, std::size_t position,
33 std::string_view token) {
34 if (position == 0 || position + token.size() >= text.size()) {
38 static_cast<unsigned char>(text[position - 1])) != 0 &&
39 std::isspace(
static_cast<unsigned char>(
40 text[position + token.size()])) != 0;
44 const std::string& text, std::size_t position,
45 const std::vector<std::string_view>& tokens) {
46 for (
const auto token : tokens) {
47 if (position + token.size() <= text.size() &&
49 position, token.size(), token.data(), token.size()) == 0 &&
58 const std::string& text,
59 const std::vector<std::string_view>& tokens,
61 std::vector<char> expected_closers;
62 std::vector<TopLevelToken> matches;
63 for (std::size_t i = 0; i < text.size(); ++i) {
65 !expected_closers.empty()) {
72 matches.push_back({i, token});
73 i += token.size() - 1;
75 if (!expected_closers.empty()) {
76 throw std::invalid_argument(
77 "Line " + std::to_string(line_num) +
78 ": unclosed expression delimiter");
83std::string
trim_copy(
const std::string& text,
int line_num) {
85 if (trimmed.empty()) {
86 throw std::invalid_argument(
87 "Line " + std::to_string(line_num) +
": empty expression");
89 return std::string(trimmed);
93 const std::string& text,
int line_num,
const char* role) {
94 const std::string trimmed =
trim_copy(text, line_num);
95 if (trimmed.size() < 2 || trimmed.front() !=
'(' ||
96 trimmed.back() !=
')') {
97 throw std::invalid_argument(
98 "Line " + std::to_string(line_num) +
99 ": CONDITIONAL " + role +
" must be parenthesized");
102 for (std::size_t i = 0; i < trimmed.size(); ++i) {
103 if (trimmed[i] ==
'(') {
105 }
else if (trimmed[i] ==
')') {
107 if (
depth == 0 && i + 1 != trimmed.size()) {
108 throw std::invalid_argument(
109 "Line " + std::to_string(line_num) +
110 ": CONDITIONAL has text outside " + role);
114 return trimmed.substr(1, trimmed.size() - 2);
118 const std::string& text,
int line_num,
130 const std::string& text,
int line_num,
bool conditional,
132 static const std::vector<std::string_view> operators = {
133 "GEQ",
"LEQ",
"NEQ",
"GT",
"LT",
"EQ",
134 ">=",
"<=",
"!=",
"==",
">",
"<"};
136 find_top_level_tokens(text, operators, line_num);
137 if (matches.size() != 1) {
138 const std::string message = conditional
139 ?
"CONDITIONAL cannot parse expression '" + text +
"'"
140 :
"RELATION requires exactly one top-level operator";
141 throw std::invalid_argument(
142 "Line " + std::to_string(line_num) +
": " + message);
145 const auto match = matches.front();
146 const std::string lhs_text =
147 trim_copy(text.substr(0, match.position), line_num);
148 const std::string rhs_text = trim_copy(
149 text.substr(match.position + match.token.size()), line_num);
157 std::istringstream& input,
const std::string& keyword) {
159 std::getline(input, text);
161 if (trimmed.empty()) {
162 throw std::invalid_argument(
163 "Line " + std::to_string(
line_num) +
164 ": RELATION requires lhs, op, and rhs");
169 ctx.current_relations().add_relation_checked(
171 ctx.current_properties()),
176 std::istringstream& input,
const std::string& keyword) {
178 std::getline(input, text);
180 if (trimmed.empty()) {
181 throw std::invalid_argument(
182 "Line " + std::to_string(
line_num) +
183 ": CONDITIONAL requires condition and conclusion");
187 find_top_level_tokens(text, {
"=>"},
line_num);
188 if (arrows.size() != 1) {
189 throw std::invalid_argument(
190 "Line " + std::to_string(
line_num) +
191 ": CONDITIONAL requires one top-level '=>'");
194 const auto arrow = arrows.front();
195 const std::string condition_text = unwrap_parenthesized(
196 text.substr(0, arrow.position),
line_num,
"condition");
197 const std::string conclusion_text = unwrap_parenthesized(
198 text.substr(arrow.position + arrow.token.size()),
200 SymbolicExpr condition = parse_conditional_relation(
202 SymbolicExpr conclusion = parse_conditional_relation(
205 ctx.assume_conditional_checked(condition, conclusion),
void parse_relation(std::istringstream &ls, const std::string &keyword)
ComputationContext & computation
void parse_conditional(std::istringstream &ls, const std::string &keyword)
bool consume_delimiter(char value, std::vector< char > &expected_closers, int line_num)
std::string_view top_level_token_at(const std::string &text, std::size_t position, const std::vector< std::string_view > &tokens)
SymbolicExpr parse_conditional_relation(const std::string &text, int line_num, ComputationContext &context)
std::vector< TopLevelToken > find_top_level_tokens(const std::string &text, const std::vector< std::string_view > &tokens, int line_num)
bool token_is_separated(const std::string &text, std::size_t position, std::string_view token)
std::string trim_copy(const std::string &text, int line_num)
std::string unwrap_parenthesized(const std::string &text, int line_num, const char *role)
RelationOp parse_relop(const std::string &s, int line_num)
Relation parse_relation(const std::string &text, int line_num, bool conditional, ComputationContext &context)
std::string_view trim_ascii_whitespace(std::string_view text) noexcept
void require_deserialization_update(const Result< void > &result, int line, const std::string &keyword)
SymbolicExpr parse_serialized_expression(const std::string &text, int line_num, ComputationContext &context)
bool is_closing_delimiter(char value) noexcept
char matching_closer(char opener) noexcept
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
std::shared_ptr< const Node > make_node(Args &&... args)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
std::size_t std::size_t depth
ExprResult relation(const ExprPtr &lhs, const ExprPtr &rhs, RelationOp op)
const std::string const ExprPtr & value
A stored relational constraint between two symbolic expressions.