LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
assumption_parse_relations.cpp
浏览该文件的文档.
2#include <cctype>
3#include <string_view>
4#include <vector>
5
7namespace {
8
10 std::size_t position;
11 std::string_view token;
12};
13
14
16 char value, std::vector<char>& expected_closers, int line_num) {
17 if (const char closer = matching_closer(value)) {
18 expected_closers.push_back(closer);
19 return true;
20 }
21 if (!is_closing_delimiter(value)) return false;
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");
26 }
27 expected_closers.pop_back();
28 return true;
29}
30
32 const std::string& text, std::size_t position,
33 std::string_view token) {
34 if (position == 0 || position + token.size() >= text.size()) {
35 return false;
36 }
37 return std::isspace(
38 static_cast<unsigned char>(text[position - 1])) != 0 &&
39 std::isspace(static_cast<unsigned char>(
40 text[position + token.size()])) != 0;
41}
42
43std::string_view top_level_token_at(
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() &&
48 text.compare(
49 position, token.size(), token.data(), token.size()) == 0 &&
50 token_is_separated(text, position, token)) {
51 return token;
52 }
53 }
54 return {};
55}
56
57std::vector<TopLevelToken> find_top_level_tokens(
58 const std::string& text,
59 const std::vector<std::string_view>& tokens,
60 int line_num) {
61 std::vector<char> expected_closers;
62 std::vector<TopLevelToken> matches;
63 for (std::size_t i = 0; i < text.size(); ++i) {
64 if (consume_delimiter(text[i], expected_closers, line_num) ||
65 !expected_closers.empty()) {
66 continue;
67 }
68 const auto token = top_level_token_at(text, i, tokens);
69 if (token.empty()) {
70 continue;
71 }
72 matches.push_back({i, token});
73 i += token.size() - 1;
74 }
75 if (!expected_closers.empty()) {
76 throw std::invalid_argument(
77 "Line " + std::to_string(line_num) +
78 ": unclosed expression delimiter");
79 }
80 return matches;
81}
82
83std::string trim_copy(const std::string& text, int line_num) {
84 const auto trimmed = trim_ascii_whitespace(text);
85 if (trimmed.empty()) {
86 throw std::invalid_argument(
87 "Line " + std::to_string(line_num) + ": empty expression");
88 }
89 return std::string(trimmed);
90}
91
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");
100 }
101 int depth = 0;
102 for (std::size_t i = 0; i < trimmed.size(); ++i) {
103 if (trimmed[i] == '(') {
104 ++depth;
105 } else if (trimmed[i] == ')') {
106 --depth;
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);
111 }
112 }
113 }
114 return trimmed.substr(1, trimmed.size() - 2);
115}
116
118 const std::string& text, int line_num,
120 auto relation = parse_relation(text, line_num, true, context);
125}
126
127}
128
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 ">=", "<=", "!=", "==", ">", "<"};
135 const auto matches =
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);
143 }
144
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);
150 return {
151 parse_serialized_expression(lhs_text, line_num, context),
152 parse_serialized_expression(rhs_text, line_num, context),
153 parse_relop(std::string(match.token), line_num)};
154}
155
157 std::istringstream& input, const std::string& keyword) {
158 std::string text;
159 std::getline(input, text);
160 const auto trimmed = trim_ascii_whitespace(text);
161 if (trimmed.empty()) {
162 throw std::invalid_argument(
163 "Line " + std::to_string(line_num) +
164 ": RELATION requires lhs, op, and rhs");
165 }
167 std::string(trimmed), line_num, false, computation);
169 ctx.current_relations().add_relation_checked(
170 relation.lhs, relation.rhs, relation.op,
171 ctx.current_properties()),
172 line_num, keyword);
173}
174
176 std::istringstream& input, const std::string& keyword) {
177 std::string text;
178 std::getline(input, text);
179 const auto trimmed = trim_ascii_whitespace(text);
180 if (trimmed.empty()) {
181 throw std::invalid_argument(
182 "Line " + std::to_string(line_num) +
183 ": CONDITIONAL requires condition and conclusion");
184 }
185 text = trimmed;
186 const auto arrows =
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 '=>'");
192 }
193
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()),
199 line_num, "conclusion");
200 SymbolicExpr condition = parse_conditional_relation(
201 condition_text, line_num, computation);
202 SymbolicExpr conclusion = parse_conditional_relation(
203 conclusion_text, line_num, computation);
205 ctx.assume_conditional_checked(condition, conclusion),
206 line_num, keyword);
207}
208
209}
void parse_relation(std::istringstream &ls, const std::string &keyword)
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 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.