diff --git a/src/CBot/CBotCStack.cpp b/src/CBot/CBotCStack.cpp index c8bf4575..a024bb34 100644 --- a/src/CBot/CBotCStack.cpp +++ b/src/CBot/CBotCStack.cpp @@ -351,7 +351,7 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId nIdent = 0; CBotTypResult val(-1); - val = m_prog->GetExternalCalls()->CompileCall(p, ppVars, this); + val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this); if (val.GetType() < 0) { val = m_prog->GetFunctions()->CompileCall(p->GetString(), ppVars, nIdent); diff --git a/src/CBot/CBotExternalCall.cpp b/src/CBot/CBotExternalCall.cpp index 1d88c3b6..46ccf3e6 100644 --- a/src/CBot/CBotExternalCall.cpp +++ b/src/CBot/CBotExternalCall.cpp @@ -37,7 +37,7 @@ bool CBotExternalCallList::AddFunction(const std::string& name, std::unique_ptr< return true; } -CBotTypResult CBotExternalCallList::CompileCall(CBotToken*& p, CBotVar** ppVar, CBotCStack* pStack) +CBotTypResult CBotExternalCallList::CompileCall(CBotToken*& p, CBotVar* thisVar, CBotVar** ppVar, CBotCStack* pStack) { if (m_list.count(p->GetString()) == 0) return -1; @@ -45,7 +45,7 @@ CBotTypResult CBotExternalCallList::CompileCall(CBotToken*& p, CBotVar** ppVar, CBotExternalCall* pt = m_list[p->GetString()].get(); std::unique_ptr args = std::unique_ptr(MakeListVars(ppVar)); - CBotTypResult r = pt->Compile(args.get(), m_user); + CBotTypResult r = pt->Compile(thisVar, args.get(), m_user); // if a class is returned, it is actually a pointer if (r.GetType() == CBotTypClass) r.SetType(CBotTypPointer); @@ -68,7 +68,7 @@ bool CBotExternalCallList::CheckCall(const std::string& name) return m_list.count(name) > 0; } -int CBotExternalCallList::DoCall(CBotToken* token, CBotVar** ppVar, CBotStack* pStack, const CBotTypResult& rettype) +int CBotExternalCallList::DoCall(CBotToken* token, CBotVar* thisVar, CBotVar** ppVar, CBotStack* pStack, const CBotTypResult& rettype) { if (token == nullptr) return -1; @@ -93,10 +93,10 @@ int CBotExternalCallList::DoCall(CBotToken* token, CBotVar** ppVar, CBotStack* p pile2->SetVar(pResult); pile->SetError(CBotNoErr, token); // save token for the position in case of error - return pt->Run(pStack); + return pt->Run(thisVar, pStack); } -bool CBotExternalCallList::RestoreCall(CBotToken* token, CBotVar** ppVar, CBotStack* pStack) +bool CBotExternalCallList::RestoreCall(CBotToken* token, CBotVar* thisVar, CBotVar** ppVar, CBotStack* pStack) { if (m_list.count(token->GetString()) == 0) return false; @@ -123,7 +123,6 @@ CBotExternalCall::~CBotExternalCall() //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CBotExternalCallDefault::CBotExternalCallDefault(RuntimeFunc rExec, CompileFunc rCompile) -: CBotExternalCall() { m_rExec = rExec; m_rComp = rCompile; @@ -133,12 +132,12 @@ CBotExternalCallDefault::~CBotExternalCallDefault() { } -CBotTypResult CBotExternalCallDefault::Compile(CBotVar* args, void* user) +CBotTypResult CBotExternalCallDefault::Compile(CBotVar* thisVar, CBotVar* args, void* user) { return m_rComp(args, user); } -bool CBotExternalCallDefault::Run(CBotStack* pStack) +bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack) { CBotStack* pile = pStack->AddStackEOX(this); if ( pile == EOX ) return true; @@ -164,3 +163,47 @@ bool CBotExternalCallDefault::Run(CBotStack* pStack) return true; } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CBotExternalCallDefaultClass::CBotExternalCallDefaultClass(RuntimeFunc rExec, CompileFunc rCompile) +{ + m_rExec = rExec; + m_rComp = rCompile; +} + +CBotExternalCallDefaultClass::~CBotExternalCallDefaultClass() +{ +} + +CBotTypResult CBotExternalCallDefaultClass::Compile(CBotVar* thisVar, CBotVar* args, void* user) +{ + return m_rComp(nullptr, args); +} + +// TODO: Figure out why classes do pStack->SetVar while normal calls do pStack->SetCopyVar +bool CBotExternalCallDefaultClass::Run(CBotVar* thisVar, CBotStack* pStack) +{ + CBotStack* pile = pStack->AddStackEOX(this); + if ( pile == EOX ) return true; + CBotVar* args = pile->GetVar(); + + CBotStack* pile2 = pile->AddStack(); + + CBotVar* result = pile2->GetVar(); + + int exception = CBotNoErr; // TODO: Change to CBotError + bool res = m_rExec(thisVar, args, result, exception, pStack->GetPUser()); + pStack->SetVar(result); + + if (!res) + { + if (exception != CBotNoErr) + { + pStack->SetError(static_cast(exception)); + } + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/CBot/CBotExternalCall.h b/src/CBot/CBotExternalCall.h index 95ff4b6c..12b768bd 100644 --- a/src/CBot/CBotExternalCall.h +++ b/src/CBot/CBotExternalCall.h @@ -56,18 +56,20 @@ public: /** * \brief Compile the function * + * \param "this" variable for class calls, nullptr for normal calls * \param Arguments (only types!) passed to the function * \param User pointer provided to CBotProgram::Compile() */ - virtual CBotTypResult Compile(CBotVar* args, void* user) = 0; + virtual CBotTypResult Compile(CBotVar* thisVar, CBotVar* args, void* user) = 0; /** * \brief Execute the function * + * \param thisVar "this" variable for class calls, nullptr for normal calls * \param pStack Stack to execute the function on * \return false to request program interruption, true otherwise */ - virtual bool Run(CBotStack* pStack) = 0; + virtual bool Run(CBotVar* thisVar, CBotStack* pStack) = 0; }; /** @@ -92,8 +94,38 @@ public: */ virtual ~CBotExternalCallDefault(); - virtual CBotTypResult Compile(CBotVar* args, void* user); - virtual bool Run(CBotStack* pStack); + virtual CBotTypResult Compile(CBotVar* thisVar, CBotVar* args, void* user); + virtual bool Run(CBotVar* thisVar, CBotStack* pStack); + +private: + RuntimeFunc m_rExec; + CompileFunc m_rComp; +}; + +/** + * \brief Default implementation of CBot external class call, using compilation and runtime functions + */ +class CBotExternalCallDefaultClass : public CBotExternalCall +{ +public: + typedef bool (*RuntimeFunc)(CBotVar* thisVar, CBotVar* args, CBotVar* result, int& exception, void* user); + typedef CBotTypResult (*CompileFunc)(CBotVar* thisVar, CBotVar*& args); // TODO: Add user pointer + + /** + * \brief Constructor + * \param rExec Runtime function + * \param rCompile Compilation function + * \see CBotClass::AddFunction() + */ + CBotExternalCallDefaultClass(RuntimeFunc rExec, CompileFunc rCompile); + + /** + * \brief Destructor + */ + virtual ~CBotExternalCallDefaultClass(); + + virtual CBotTypResult Compile(CBotVar* thisVar, CBotVar* args, void* user); + virtual bool Run(CBotVar* thisVar, CBotStack* pStack); private: RuntimeFunc m_rExec; @@ -124,10 +156,11 @@ public: * * \param p Token representing the function name * \param ppVars List of arguments (only types!) + * \param thisVar "this" variable for class calls, nullptr for normal calls * \param pStack Compilation stack * \return CBotTypResult representing the return type of the function (::CBotTypVar), or an error (::CBotError) */ - CBotTypResult CompileCall(CBotToken*& p, CBotVar** ppVars, CBotCStack* pStack); + CBotTypResult CompileCall(CBotToken*& p, CBotVar* thisVar, CBotVar** ppVars, CBotCStack* pStack); /** * \brief Check if function with given name has been defined @@ -142,22 +175,24 @@ public: * This function sets an error in runtime stack in case of failure * * \param token Token representing the function name + * \param thisVar "this" variable for class calls, nullptr for normal calls * \param ppVars List of arguments * \param pStack Runtime stack * \param rettype Return type of the function, as returned by CompileCall() * \return -1 if call failed (no such function), 0 if function requested interruption, 1 on success */ - int DoCall(CBotToken* token, CBotVar** ppVars, CBotStack* pStack, const CBotTypResult& rettype); + int DoCall(CBotToken* token, CBotVar* thisVar, CBotVar** ppVars, CBotStack* pStack, const CBotTypResult& rettype); /** * \brief Restore execution status after loading saved state * * \param token Token representing the function name - * \param ppVar List of arguments (TODO: unused) + * \param "this" variable for class calls, nullptr for normal calls + * \param ppVar List of arguments * \param pStack Runtime stack * \return false on failure (e.g. function doesn't exist) */ - bool RestoreCall(CBotToken* token, CBotVar** ppVar, CBotStack* pStack); + bool RestoreCall(CBotToken* token, CBotVar* thisVar, CBotVar** ppVar, CBotStack* pStack); /** * \brief Set user pointer to pass to compile functions diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 2b2672bf..67641775 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -637,7 +637,7 @@ bool CBotStack::Execute() if ( instr == nullptr ) return true; // normal execution request - if (!instr->Run(pile)) return false; // \TODO exécution à partir de là + if (!instr->Run(nullptr, pile)) return false; // \TODO exécution à partir de là #if STACKMEM pile->m_next->Delete(); @@ -744,7 +744,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBo // first looks by the identifier - res = m_prog->GetExternalCalls()->DoCall(nullptr, ppVar, this, rettype); + res = m_prog->GetExternalCalls()->DoCall(nullptr, nullptr, ppVar, this, rettype); if (res.GetType() >= 0) return res.GetType(); res = m_prog->GetFunctions()->DoCall(nIdent, "", ppVar, this, token ); @@ -753,7 +753,7 @@ bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBo // if not found (recompile?) seeks by name nIdent = 0; - res = m_prog->GetExternalCalls()->DoCall(token, ppVar, this, rettype); + res = m_prog->GetExternalCalls()->DoCall(token, nullptr, ppVar, this, rettype); if (res.GetType() >= 0) return res.GetType(); res = m_prog->GetFunctions()->DoCall(nIdent, token->GetString(), ppVar, this, token ); @@ -768,7 +768,7 @@ void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar) { if (m_next == nullptr) return; - if (m_prog->GetExternalCalls()->RestoreCall(token, ppVar, this)) + if (m_prog->GetExternalCalls()->RestoreCall(token, nullptr, ppVar, this)) return; m_prog->GetFunctions()->RestoreCall(nIdent, token->GetString(), ppVar, this);