{
public:
PredicateWaitInterface(BatchExecutor *executor, std::chrono::milliseconds timeout)
- : self(executor), timeout(std::chrono::high_resolution_clock::now() + timeout)
+ : self(executor), delay(timeout)
{}
void join() override
{
- if (success) return;
-
- success = predicate();
+ timeout = std::chrono::high_resolution_clock::now() + delay;
+ joinImpl();
}
protected:
- virtual bool predicate() = 0;
+ virtual void joinImpl() = 0;
BatchExecutor *self;
std::chrono::high_resolution_clock::time_point timeout;
- bool success = false;
+ std::chrono::milliseconds delay;
};
class WaitDlog : public PredicateWaitInterface
WaitDlog(BatchExecutor *executor, std::chrono::milliseconds timeout, std::string pattern)
: PredicateWaitInterface(executor, timeout)
{
- {
- auto h = self->dlogInfo.lock();
- h->searchLine = std::move(pattern);
- h->mode = BatchExecutor::DLogInfo::Mode::search;
- }
}
private:
- bool predicate() override
+ void prepare() override
+ {
+ auto h = self->dlogInfo.lock();
+ h->stack.push_back({ std::move(pattern) });
+ h->stack.back().found = &found;
+ }
+ void joinImpl() override
{
auto h = self->dlogInfo.lock();
+ CallOnExit _tmp{
+ [&]()
+ {
+ if (!found) {
+ assert(!h->stack.empty());
+ assert(h->stack.back().found == &found);
+ h->stack.pop_back();
+ }
+ }
+ };
auto res = h.waitForCondition(timeout, [&]() {
- return h->mode == BatchExecutor::DLogInfo::Mode::found;
+ return found;
});
- h->mode = BatchExecutor::DLogInfo::Mode::ignore;
if (!res)
throw EvaluationFailure{} << "wait for dlog ('" << pattern << "'): operation timeouted";
-
- return res;
}
std::string pattern;
+ bool found = false;
};
class WaitTTS : public PredicateWaitInterface
{
public:
WaitTTS(BatchExecutor *executor, std::chrono::milliseconds timeout, std::string pattern, bool exact)
- : PredicateWaitInterface(executor, timeout)
+ : PredicateWaitInterface(executor, timeout), exact(exact)
{
this->pattern = pattern;
- {
- auto h = self->ttsInfo.lock();
- if (!pattern.empty())
- h->searchLine = std::move(pattern);
- else
- h->searchLine = {};
- h->exact = exact;
- h->mode = BatchExecutor::TTSInfo::Mode::search;
- }
}
private:
- bool predicate() override
+ void prepare() override
{
auto h = self->ttsInfo.lock();
+ h->stack.push_back({});
+ auto &w = h->stack.back();
+ if (!pattern.empty())
+ w.searchLine = pattern;
+ w.exact = exact;
+ w.found = &found;
+ }
+ void joinImpl() override
+ {
+ auto h = self->ttsInfo.lock();
+ CallOnExit _tmp{
+ [&]()
+ {
+ if (!found) {
+ assert(!h->stack.empty());
+ assert(h->stack.back().found == &found);
+ h->stack.pop_back();
+ }
+ }
+ };
auto res = h.waitForCondition(timeout, [&]() {
- return h->mode == BatchExecutor::TTSInfo::Mode::found;
+ return found;
});
- h->mode = BatchExecutor::TTSInfo::Mode::ignore;
if (!res)
throw EvaluationFailure{} << "wait for tts ('" << pattern << "'): operation timeouted";
-
- return res;
}
std::string pattern;
+ bool exact = false, found = false;
};
class WaitGui : public PredicateWaitInterface
{
public:
WaitGui(BatchExecutor *executor, std::chrono::milliseconds timeout, std::string name)
- : PredicateWaitInterface(executor, timeout)
+ : PredicateWaitInterface(executor, timeout), name(std::move(name))
{
- {
- auto h = self->contextInfo.lock();
- this->currentContextName = h->rootName;
- }
- if (name.empty()) {
- this->name = this->currentContextName;
- searchForAnyChange = true;
- } else {
- this->name = std::move(name);
- }
+ searchForAnyChange = this->name.empty();
}
-
private:
- bool predicate() override
+ void prepare() override
+ {
+ auto h = self->contextInfo.lock();
+ currentContextName = h->rootName;
+ }
+ void joinImpl() override
{
auto h = self->contextInfo.lock();
auto pred = [&]() {
}
return (searchForAnyChange && name != h->rootName) || (!searchForAnyChange && name == h->rootName);
};
- if (pred()) return true;
auto res = h.waitForCondition(timeout, pred);
if (!res) {
if (searchForAnyChange)
throw EvaluationFailure{} << "wait for gui ('" << name << "'): operation timeouted, " <<
"current root name is '" << h->rootName << "'";
}
-
- return res;
}
std::string name, currentContextName;
if (hasContext) {
auto ttsDlogHandler = dlog.registerCallback([&exec](const std::string & txt) {
auto h = exec->ttsInfo.lock();
- if (h->mode == BatchExecutor::TTSInfo::Mode::search) {
- if (!h->searchLine) {
- h->mode = BatchExecutor::TTSInfo::Mode::found;
+ if (!h->stack.empty()) {
+ auto &w = h->stack.back();
+ if (!w.searchLine) {
+ *w.found = true;
} else {
if (txt.find("(tts_speak_customized)") != std::string::npos) {
static const auto prefix = std::string{ "TTS reading text '" };
if (z2 != std::string::npos && z2 > z) {
auto sub = txt.substr(z, z2 - z);
exec->outputStream() << "TTS: '" << sub << "'\n";
- if ((h->exact && sub == *h->searchLine) || (!h->exact && sub.find(*h->searchLine) != std::string::npos)) {
- h->mode = BatchExecutor::TTSInfo::Mode::found;
+ if ((w.exact && sub == *w.searchLine) || (!w.exact && sub.find(*w.searchLine) != std::string::npos)) {
+ *w.found = true;
}
}
}
}
}
+ if (*w.found)
+ h->stack.pop_back();
}
});
auto dlogHandler = dlog.registerCallback([&exec](const std::string & txt) {
auto h = exec->dlogInfo.lock();
- if (h->mode == BatchExecutor::DLogInfo::Mode::search) {
- if (txt.find(h->searchLine) != std::string::npos) {
- h->mode = BatchExecutor::DLogInfo::Mode::found;
+ if (!h->stack.empty()) {
+ auto &w = h->stack.back();
+ if (txt.find(w.searchLine) != std::string::npos) {
+ *w.found = true;
+ h->stack.pop_back();
}
}
});
template <typename F> static auto evaluateHelper(std::string debugId, TokenLocation loc, F &&f)
{
- struct CallOnExit {
- std::function<void()> func;
- CallOnExit(std::function<void()> func) : func(std::move(func)) { }
- ~CallOnExit()
- {
- func();
- }
- };
EvaluationDepthCountManager countManager;
std::string indent(static_cast<size_t>(evaluationDepth * 2), ' ');
try {
EvaluationValue OperatorEvaluator::evaluateImpl() const
{
std::vector<EvaluationValue> vals;
- for (auto &a : args)
- vals.push_back(a->evaluate());
+ if (kind == Kind::LOG_AND) {
+ vals.push_back(args[0]->evaluate());
+ vals.push_back(vals[0] ? args[1]->evaluate() : EvaluationValue{});
+ } else if (kind == Kind::LOG_OR) {
+ vals.push_back(!vals[0] ? args[1]->evaluate() : EvaluationValue{});
+ } else {
+ for (auto &a : args)
+ vals.push_back(a->evaluate());
+ }
switch (kind) {
case Kind::IN:
auto r = w->evaluate();
waitsValues.push_back(r.convertToWait());
}
+ for (auto it = waitsValues.rbegin(); it != waitsValues.rend(); ++it)
+ it->asWait()->prepare();
+
DebugEvaluator{} << getDebugId() << ": executing main block of wait clause";
exec->evaluate();
DebugEvaluator{} << getDebugId() << ": joining waiters (" << waits.size() << ")";