72 [[nodiscard]]
virtual std::string
ToString()
const = 0;
81 : lhs_(std::move(lhs)), op_(op), rhs_(std::move(rhs)) {}
84 double lhs_val = GetValue(registry, lhs_);
85 double rhs_val = std::holds_alternative<double>(rhs_)
86 ? std::get<double>(rhs_)
87 : GetValue(registry, std::get<std::string>(rhs_));
91 return lhs_val < rhs_val;
93 return lhs_val <= rhs_val;
95 return lhs_val > rhs_val;
97 return lhs_val >= rhs_val;
99 return lhs_val == rhs_val;
101 return lhs_val != rhs_val;
106 [[nodiscard]] std::string
ToString()
const override {
128 std::string rhs_str = std::holds_alternative<double>(rhs_)
129 ? std::to_string(std::get<double>(rhs_))
130 : std::get<std::string>(rhs_);
131 return lhs_ +
" " + op_str +
" " + rhs_str;
137 std::variant<double, std::string> rhs_;
140 const std::string &name) {
142 if constexpr (std::is_same_v<Scalar, double>) {
147 throw ConditionError(
"Cannot evaluate symbolic signals in conditions: " + name);
157 : left_(std::move(left)), right_(std::move(right)) {}
160 return left_->Evaluate(registry) && right_->Evaluate(registry);
163 [[nodiscard]] std::string
ToString()
const override {
164 return "(" + left_->ToString() +
" AND " + right_->ToString() +
")";
168 std::unique_ptr<ConditionNode<Scalar>> left_;
169 std::unique_ptr<ConditionNode<Scalar>> right_;
177 : left_(std::move(left)), right_(std::move(right)) {}
180 return left_->Evaluate(registry) || right_->Evaluate(registry);
183 [[nodiscard]] std::string
ToString()
const override {
184 return "(" + left_->ToString() +
" OR " + right_->ToString() +
")";
188 std::unique_ptr<ConditionNode<Scalar>> left_;
189 std::unique_ptr<ConditionNode<Scalar>> right_;
196 : operand_(std::move(operand)) {}
199 return !operand_->Evaluate(registry);
202 [[nodiscard]] std::string
ToString()
const override {
return "NOT " + operand_->ToString(); }
205 std::unique_ptr<ConditionNode<Scalar>> operand_;
214 explicit Tokenizer(std::string_view input) : input_(input), pos_(0) {}
217 std::vector<Token> tokens;
224 std::size_t start = pos_;
228 if (c ==
'<' && PeekNext() ==
'=') {
232 }
else if (c ==
'>' && PeekNext() ==
'=') {
236 }
else if (c ==
'=' && PeekNext() ==
'=') {
240 }
else if (c ==
'!' && PeekNext() ==
'=') {
244 }
else if (c ==
'&' && PeekNext() ==
'&') {
248 }
else if (c ==
'|' && PeekNext() ==
'|') {
257 }
else if (c ==
'>') {
260 }
else if (c ==
'!') {
263 }
else if (c ==
'(') {
266 }
else if (c ==
')') {
271 else if (std::isdigit(c) || (c ==
'-' && std::isdigit(PeekNext()))) {
272 tokens.push_back(ScanNumber());
275 else if (std::isalpha(c) || c ==
'_') {
276 tokens.push_back(ScanIdentifier());
278 throw ConditionError(
"Unexpected character '" + std::string(1, c) +
279 "' at position " + std::to_string(pos_));
288 std::string_view input_;
291 [[nodiscard]]
bool AtEnd()
const {
return pos_ >= input_.size(); }
293 [[nodiscard]]
char Peek()
const {
return AtEnd() ?
'\0' : input_[pos_]; }
295 [[nodiscard]]
char PeekNext()
const {
296 return (pos_ + 1 >= input_.size()) ?
'\0' : input_[pos_ + 1];
299 char Advance() {
return input_[pos_++]; }
301 void SkipWhitespace() {
302 while (!AtEnd() && std::isspace(Peek())) {
307 [[nodiscard]] Token ScanNumber() {
308 std::size_t start = pos_;
317 while (!AtEnd() && std::isdigit(Peek())) {
322 if (Peek() ==
'.' && std::isdigit(PeekNext())) {
324 while (!AtEnd() && std::isdigit(Peek())) {
330 if (Peek() ==
'e' || Peek() ==
'E') {
332 if (Peek() ==
'+' || Peek() ==
'-') {
335 while (!AtEnd() && std::isdigit(Peek())) {
343 [[nodiscard]] Token ScanIdentifier() {
344 std::size_t start = pos_;
348 while (!AtEnd() && (std::isalnum(Peek()) || Peek() ==
'_' || Peek() ==
'.')) {
353 if (value ==
"AND" || value ==
"and") {
356 if (value ==
"OR" || value ==
"or") {
359 if (value ==
"NOT" || value ==
"not") {
380 : root_(std::move(root)) {}
387 return root_->Evaluate(registry);
391 [[nodiscard]]
bool IsValid()
const {
return root_ !=
nullptr; }
394 [[nodiscard]] std::string
ToString()
const {
return root_ ? root_->ToString() :
"<empty>"; }
397 std::unique_ptr<ConditionNode<Scalar>> root_;
425 auto root = ParseOrExpr();
428 throw ConditionError(
"Unexpected token '" + Peek().value +
"' at position " +
429 std::to_string(Peek().position));
436 std::vector<Token> tokens_;
437 std::size_t current_ = 0;
439 [[nodiscard]]
const Token &Peek()
const {
return tokens_[current_]; }
441 [[nodiscard]]
const Token &Previous()
const {
return tokens_[current_ - 1]; }
451 [[nodiscard]]
bool Check(
TokenType type)
const {
454 return Peek().type == type;
465 Token Consume(
TokenType type,
const std::string &message) {
468 throw ConditionError(message +
" at position " + std::to_string(Peek().position));
472 [[nodiscard]] std::unique_ptr<ConditionNode<Scalar>> ParseOrExpr() {
473 auto left = ParseAndExpr();
476 auto right = ParseAndExpr();
477 left = std::make_unique<OrNode<Scalar>>(std::move(left), std::move(right));
484 [[nodiscard]] std::unique_ptr<ConditionNode<Scalar>> ParseAndExpr() {
485 auto left = ParseNotExpr();
488 auto right = ParseNotExpr();
489 left = std::make_unique<AndNode<Scalar>>(std::move(left), std::move(right));
496 [[nodiscard]] std::unique_ptr<ConditionNode<Scalar>> ParseNotExpr() {
498 auto operand = ParseNotExpr();
499 return std::make_unique<NotNode<Scalar>>(std::move(operand));
501 return ParsePrimary();
505 [[nodiscard]] std::unique_ptr<ConditionNode<Scalar>> ParsePrimary() {
507 auto expr = ParseOrExpr();
512 return ParseComparison();
516 [[nodiscard]] std::unique_ptr<ConditionNode<Scalar>> ParseComparison() {
533 throw ConditionError(
"Expected comparison operator at position " +
534 std::to_string(Peek().position));
537 std::variant<double, std::string> rhs;
539 rhs = std::stod(Previous().value);
541 rhs = Previous().value;
543 throw ConditionError(
"Expected number or signal name at position " +
544 std::to_string(Peek().position));
547 return std::make_unique<ComparisonNode<Scalar>>(lhs.value, op, std::move(rhs));
Consolidated error handling for Icarus.
Signal Registry (Backplane) for Icarus.
AndNode(std::unique_ptr< ConditionNode< Scalar > > left, std::unique_ptr< ConditionNode< Scalar > > right)
Definition ConditionParser.hpp:155
std::string ToString() const override
Definition ConditionParser.hpp:163
bool Evaluate(const SignalRegistry< Scalar > ®istry) const override
Definition ConditionParser.hpp:159
ComparisonNode(std::string lhs, Op op, std::variant< double, std::string > rhs)
Definition ConditionParser.hpp:80
Op
Definition ConditionParser.hpp:78
@ NotEqual
Definition ConditionParser.hpp:78
@ Less
Definition ConditionParser.hpp:78
@ GreaterEqual
Definition ConditionParser.hpp:78
@ Greater
Definition ConditionParser.hpp:78
@ LessEqual
Definition ConditionParser.hpp:78
@ Equal
Definition ConditionParser.hpp:78
bool Evaluate(const SignalRegistry< Scalar > ®istry) const override
Definition ConditionParser.hpp:83
std::string ToString() const override
Definition ConditionParser.hpp:106
Compiled condition ready for evaluation.
Definition ConditionParser.hpp:376
std::string ToString() const
Get string representation.
Definition ConditionParser.hpp:394
CompiledCondition()=default
CompiledCondition(std::unique_ptr< ConditionNode< Scalar > > root)
Definition ConditionParser.hpp:379
bool Evaluate(const SignalRegistry< Scalar > ®istry) const
Evaluate the condition against the registry.
Definition ConditionParser.hpp:383
bool IsValid() const
Check if condition is valid (has been parsed).
Definition ConditionParser.hpp:391
Condition parsing and evaluation errors.
Definition Error.hpp:377
Definition ConditionParser.hpp:68
virtual bool Evaluate(const SignalRegistry< Scalar > ®istry) const =0
virtual std::string ToString() const =0
virtual ~ConditionNode()=default
Parser for condition expressions.
Definition ConditionParser.hpp:411
CompiledCondition< Scalar > Parse(const std::string &condition)
Parse a condition string.
Definition ConditionParser.hpp:420
NotNode(std::unique_ptr< ConditionNode< Scalar > > operand)
Definition ConditionParser.hpp:195
std::string ToString() const override
Definition ConditionParser.hpp:202
bool Evaluate(const SignalRegistry< Scalar > ®istry) const override
Definition ConditionParser.hpp:198
OrNode(std::unique_ptr< ConditionNode< Scalar > > left, std::unique_ptr< ConditionNode< Scalar > > right)
Definition ConditionParser.hpp:175
bool Evaluate(const SignalRegistry< Scalar > ®istry) const override
Definition ConditionParser.hpp:179
std::string ToString() const override
Definition ConditionParser.hpp:183
Central registry for all simulation signals.
Definition Registry.hpp:37
const Scalar & GetByName(const std::string &name) const
Get signal value by name (slow path, for debugging).
Definition Registry.hpp:434
Definition ConditionParser.hpp:212
std::vector< Token > Tokenize()
Definition ConditionParser.hpp:216
Tokenizer(std::string_view input)
Definition ConditionParser.hpp:214
Definition AggregationTypes.hpp:13
TokenType
Definition ConditionParser.hpp:29
@ NotEqual
Definition ConditionParser.hpp:40
@ Less
Definition ConditionParser.hpp:35
@ Identifier
Definition ConditionParser.hpp:32
@ RightParen
Definition ConditionParser.hpp:49
@ Or
Definition ConditionParser.hpp:44
@ Eof
Definition ConditionParser.hpp:52
@ GreaterEqual
Definition ConditionParser.hpp:38
@ Greater
Definition ConditionParser.hpp:37
@ Not
Definition ConditionParser.hpp:45
@ Number
Definition ConditionParser.hpp:31
@ And
Definition ConditionParser.hpp:43
@ LessEqual
Definition ConditionParser.hpp:36
@ LeftParen
Definition ConditionParser.hpp:48
@ Equal
Definition ConditionParser.hpp:39
Definition ConditionParser.hpp:55
Token(TokenType t, std::string v, std::size_t pos=0)
Definition ConditionParser.hpp:60
std::size_t position
Definition ConditionParser.hpp:58
TokenType type
Definition ConditionParser.hpp:56
std::string value
Definition ConditionParser.hpp:57