// SPDX-License-Identifier: LGPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // The conditions `crafter-debug wait` and `pause --when` take: comparisons of // watch paths with literals and with each other, combined with && || ! and // parentheses. // // fort1.core.hp <= 0 // scene == "Game" && !debug.paused // bodies[3].pos.y < -10 || (lives == 0 && score > highScore) // // A lone operand tests truthiness: true, a nonzero number, a non-empty // string, array or object. Numbers compare by value, strings in byte order; // == and != work on any two values, and ordering a string against a number // is an error rather than false, so a typo in a condition is reported // instead of waiting forever. Parsed once when it arrives, evaluated on the // Pump thread every frame. export module Crafter.Debug:Condition; import std; import Crafter.Debug.Core; export namespace Crafter::Debug { class ConditionError : public std::runtime_error { public: std::size_t offset; ConditionError(std::size_t offset, std::string_view what); }; class Condition { public: // Throws ConditionError, with the offset of the problem. static Condition Parse(std::string_view text); // Looks a path up: a value, or why there is none. using Resolver = std::function(std::string_view path)>; // True or false, or why it cannot be decided (an unknown path, or // operands that cannot be ordered). std::expected Evaluate(const Resolver& resolve) const; const std::string& Text() const { return text; } // The paths the condition reads, in order of appearance. std::span Paths() const { return paths; } struct Node; private: std::string text; std::shared_ptr root; std::vector paths; }; }