#pragma once #include "dtcore/inc/dtscript.h" namespace dt { class ScriptStatementCompoundImpl; // Base class for compound statement that can contain nested // statements within a block surrounded by { }. A compound // statement will first execute like a ScriptStatementLeaf // statement and with the Initialize() method called repeatedly until SetCompleted() // is called. Then Run() method will follow the same process. // Then, Monitor() will be called repeatedly while nested statements // are being executed. The Monitor() method is called before any nested // statements Run(). This can be used to validate that a prerequisite is // maintained during the evaluation of its children. Monitor can call // the DT_FAIL macros as needed. class ScriptStatementCompound : public ScriptStatement { public: // Constructor. When runChildrenInParallel is true, the nest // statements are executed in parallel, otherwise they are // executed one after the other DT_CORE_DLL_ENTRY ScriptStatementCompound(bool runChildrenInParallel); DT_CORE_DLL_ENTRY ~ScriptStatementCompound(); // The monitor function is to be overridden as needed. It is // called when the Run() step is completed, before the // execution of nested statement. DT_CORE_DLL_ENTRY virtual void Monitor() {} // This method is called when all children are completed, // before this statement gets destroyed. If the method is // overridden and restart is set to true, the statement will // be restarted another time. This includes the Initialize(), // Run(), Monitor() and Cleanup() steps with also the execution of all // children. NOTE that new instances of children statement // will be created. DT_CORE_DLL_ENTRY virtual void EndQuery(bool& restart) { restart = false; } DT_CORE_DLL_ENTRY virtual void SetCompleted() override; DT_CORE_DLL_ENTRY virtual void Skip() override; DT_CORE_DLL_ENTRY virtual bool InternalUpdate() override; enum class State { Pending, Synchronize, Initialize, Run, Monitor, Cleanup, Done }; DT_CORE_DLL_ENTRY const State GetState() const; private: friend class ScriptParserState; friend class ScriptStatementCompoundImpl; friend class ServiceScript; void PushBack(ScriptStatement* stm); void MoveChildrenTo(ScriptStatementCompound* stm); const ScriptStatements& GetChildren() const; void InitWaitInteractionMode(); virtual bool IsCompound() const override { return true; } // because of friends DT_CORE_DLL_ENTRY virtual void SetScriptState(ScriptState* state) override; DT_CORE_DLL_ENTRY virtual void InternalTimeout() override; DT_CORE_DLL_ENTRY virtual bool IsRunningChildrenInParallel() const override; virtual void CacheFunctionParameterVariablesIn() {}; virtual void CreateFunctionParameterVariables() {}; virtual void CacheFunctionParameterVariablesOut() {}; virtual void UpdateFunctionParameterVariablesOut() {}; ScriptStatementCompoundImpl* m_Impl; }; ////////////////////////////////////////////////////////////////////////// /* \name Run in sequence \description Compound statement which runs its child statements in sequence (a child statement is started after the previous finishes). This is the implicit mode for compound statements (when nothing is specified). \example // Prints "3", "4" and then "5". Even if the second statement has a // delay, the third will wait until it's done. GIVEN in sequence { THEN print "3" AND delay print "4" in 4000 ms AND print "5" } THEN expect progress: "3" AND expect progress: "4" AND expect progress: "5" \example // Does the same thing as the first example, as the // "in sequence" sequence is implicit. GIVEN { THEN print "3" AND delay print "4" in 4000 ms AND print "5" } THEN expect progress: "3" AND expect progress: "4" AND expect progress: "5" \category Generic */ DT_DECLARE_SCRIPT_STATEMENT(ScriptStatementInSequence, "in sequence") : public ScriptStatementCompound { public: DT_CORE_DLL_ENTRY ScriptStatementInSequence(); }; ////////////////////////////////////////////////////////////////////////// /* \name Run in parallel \description Compound statement which runs its child statements in parallel (all child statements are started at the same time). \example // Starts 3 delay prints at the same time. The prints with the // smallest delay will appear first in the progression. GIVEN in parallel { THEN delay print "0" in 1000 ms AND delay print "1" in 3000 ms AND delay print "2" in 2000 ms } THEN expect progress: "0" AND expect progress: "2" AND expect progress: "1" \category Generic */ DT_DECLARE_SCRIPT_STATEMENT(ScriptStatementInParallel, "in parallel") : public ScriptStatementCompound { public: DT_CORE_DLL_ENTRY ScriptStatementInParallel(); }; }