diff --git a/src/CBot/CBotCall.cpp b/src/CBot/CBotCall.cpp index 2d1ffe78..a141d552 100644 --- a/src/CBot/CBotCall.cpp +++ b/src/CBot/CBotCall.cpp @@ -17,7 +17,6 @@ * along with this program. If not, see http://gnu.org/licenses */ -// Modules inlcude #include "CBot/CBotCall.h" #include "CBot/CBotToken.h" @@ -28,279 +27,153 @@ #include "CBot/CBotVar/CBotVar.h" -// Local include +std::map> CBotCall::m_list = std::map>(); +void* CBotCall::m_user = nullptr; -// Global include - - - -//////////////////////////////////////////////////////////////////////////////// - -CBotCall* CBotCall::m_ListCalls = nullptr; -void* CBotCall::m_pUser = nullptr; - -//////////////////////////////////////////////////////////////////////////////// -CBotCall::CBotCall(const std::string& name, - bool rExec(CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), - CBotTypResult rCompile(CBotVar*& pVar, void* pUser)) +CBotCall::CBotCall(const std::string& name, RuntimeFunc rExec, CompileFunc rCompile) { - m_name = name; - m_rExec = rExec; - m_rComp = rCompile; - m_nFuncIdent = CBotVar::NextUniqNum(); + m_name = name; + m_rExec = rExec; + m_rComp = rCompile; + m_ident = CBotVar::NextUniqNum(); } -//////////////////////////////////////////////////////////////////////////////// CBotCall::~CBotCall() { } -//////////////////////////////////////////////////////////////////////////////// -void CBotCall::Free() +void CBotCall::Clear() { - delete CBotCall::m_ListCalls; - m_ListCalls = nullptr; + m_list.clear(); } -//////////////////////////////////////////////////////////////////////////////// -bool CBotCall::AddFunction(const std::string& name, - bool rExec(CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), - CBotTypResult rCompile(CBotVar*& pVar, void* pUser)) +bool CBotCall::AddFunction(const std::string& name, RuntimeFunc rExec, CompileFunc rCompile) { - CBotCall* p = m_ListCalls; - CBotCall* pp = nullptr; - - if ( p != nullptr ) while ( p->m_next != nullptr ) - { - if ( p->GetName() == name ) - { - // frees redefined function - if ( pp ) pp->m_next = p->m_next; - else m_ListCalls = p->m_next; - pp = p; - p = p->m_next; - pp->m_next = nullptr; // not to destroy the following list - delete pp; - continue; - } - pp = p; // previous pointer - p = p->m_next; - } - - pp = new CBotCall(name, rExec, rCompile); - - if (p) p->m_next = pp; - else m_ListCalls = pp; - + m_list[name] = std::unique_ptr(new CBotCall(name, rExec, rCompile)); return true; } -//////////////////////////////////////////////////////////////////////////////// CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent) { nIdent = 0; - CBotCall* pt = m_ListCalls; - std::string name = p->GetString(); + if (m_list.count(p->GetString()) == 0) + return -1; - while ( pt != nullptr ) + CBotCall* pt = m_list[p->GetString()].get(); + nIdent = pt->m_ident; + + std::unique_ptr args = std::unique_ptr(MakeListVars(ppVar)); + CBotVar* var = args.get(); // TODO: This shouldn't be a reference + CBotTypResult r = pt->m_rComp(var, m_user); + + // if a class is returned, it is actually a pointer + if (r.GetType() == CBotTypClass) r.SetType(CBotTypPointer); + + if (r.GetType() > 20) // error? { - if ( pt->m_name == name ) - { - CBotVar* pVar = MakeListVars(ppVar); - CBotVar* pVar2 = pVar; - CBotTypResult r = pt->m_rComp(pVar2, m_pUser); - int ret = r.GetType(); - - // if a class is returned, it is actually a pointer - if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer ); - - if ( ret > 20 ) - { - if (pVar2) pStack->SetError(static_cast(ret), p /*pVar2->GetToken()*/ ); - } - delete pVar; - nIdent = pt->m_nFuncIdent; - return r; - } - pt = pt->m_next; + pStack->SetError(static_cast(r.GetType()), p); } - return -1; + + return r; } -//////////////////////////////////////////////////////////////////////////////// -void CBotCall::SetPUser(void* pUser) +void CBotCall::SetUserPtr(void* pUser) { - m_pUser = pUser; + m_user = pUser; } -//////////////////////////////////////////////////////////////////////////////// bool CBotCall::CheckCall(const std::string& name) { - CBotCall* p = m_ListCalls; - - while ( p != nullptr ) - { - if ( name == p->GetName() ) return true; - p = p->m_next; - } - return false; + return m_list.count(name) > 0; } -//////////////////////////////////////////////////////////////////////////////// -std::string CBotCall::GetName() -{ - return m_name; -} - -//////////////////////////////////////////////////////////////////////////////// int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype) { - CBotCall* pt = m_ListCalls; + CBotCall* pt = nullptr; - if ( nIdent ) while ( pt != nullptr ) + if (nIdent > 0) { - if ( pt->m_nFuncIdent == nIdent ) + for (const auto& it : m_list) { - goto fund; - } - pt = pt->m_next; - } - - pt = m_ListCalls; - - if ( token != nullptr ) - { - std::string name = token->GetString(); - while ( pt != nullptr ) - { - if ( pt->m_name == name ) + if (it.second->m_ident == nIdent) { - nIdent = pt->m_nFuncIdent; - goto fund; + pt = it.second.get(); } - pt = pt->m_next; } } - return -1; - -fund: -#if !STACKRUN - // lists the parameters depending on the contents of the stack (pStackVar) - - CBotVar* pVar = MakeListVars(ppVar, true); - CBotVar* pVarToDelete = pVar; - - // creates a variable to the result - CBotVar* pResult = rettype.Eq(0) ? nullptr : CBotVar::Create("", rettype); - - CBotVar* pRes = pResult; - int Exception = 0; - int res = pt->m_rExec(pVar, pResult, Exception, pStack->GetPUser()); - - if ( pResult != pRes ) delete pRes; // different result if made - delete pVarToDelete; - - if (res == false) + if (pt == nullptr) { - if (Exception!=0) + if (token != nullptr) { - pStack->SetError(Exception, token); + if (m_list.count(token->GetString()) > 0) + { + pt = m_list[token->GetString()].get(); + nIdent = pt->m_ident; + } } - delete pResult; - return false; } - pStack->SetVar(pResult); - if ( rettype.GetType() > 0 && pResult == nullptr ) - { - pStack->SetError(CBotErrNoRetVal, token); - } - nIdent = pt->m_nFuncIdent; - return true; - -#else + if (pt == nullptr) + return -1; CBotStack* pile = pStack->AddStackEOX(pt); - if ( pile == EOX ) return true; + if (pile == EOX) return true; // lists the parameters depending on the contents of the stack (pStackVar) - CBotVar* pVar = MakeListVars(ppVar, true); -// CBotVar* pVarToDelete = pVar; // creates a variable to the result - CBotVar* pResult = rettype.Eq(0) ? nullptr : CBotVar::Create("", rettype); + CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype); - pile->SetVar( pVar ); + pile->SetVar(pVar); CBotStack* pile2 = pile->AddStack(); - pile2->SetVar( pResult ); + pile2->SetVar(pResult); - pile->SetError(CBotNoErr, token); // for the position on error + away - return pt->Run( pStack ); - -#endif + pile->SetError(CBotNoErr, token); // save token for the position in case of error + return pt->Run(pStack); } -#if STACKRUN - -//////////////////////////////////////////////////////////////////////////////// bool CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack) { - CBotCall* pt = m_ListCalls; + if (m_list.count(token->GetString()) == 0) + return false; - { - std::string name = token->GetString(); - while ( pt != nullptr ) - { - if ( pt->m_name == name ) - { - nIdent = pt->m_nFuncIdent; + CBotCall* pt = m_list[token->GetString()].get(); + nIdent = pt->m_ident; - CBotStack* pile = pStack->RestoreStackEOX(pt); - if ( pile == nullptr ) return true; + CBotStack* pile = pStack->RestoreStackEOX(pt); + if ( pile == nullptr ) return true; - // CBotStack* pile2 = pile->RestoreStack(); - pile->RestoreStack(); - return true; - } - pt = pt->m_next; - } - } - - return false; + pile->RestoreStack(); + return true; } -//////////////////////////////////////////////////////////////////////////////// bool CBotCall::Run(CBotStack* pStack) { CBotStack* pile = pStack->AddStackEOX(this); if ( pile == EOX ) return true; - CBotVar* pVar = pile->GetVar(); + CBotVar* args = pile->GetVar(); - CBotStack* pile2 = pile->AddStack(); - CBotVar* pResult = pile2->GetVar(); - CBotVar* pRes = pResult; + CBotStack* pile2 = pile->AddStack(); - int Exception = 0; // TODO: change this to CBotError - int res = m_rExec(pVar, pResult, Exception, pStack->GetPUser()); + CBotVar* result = pile2->GetVar(); - if (res == false) + int exception = CBotNoErr; // TODO: Change to CBotError + bool res = m_rExec(args, result, exception, pStack->GetPUser()); + + if (!res) { - if (Exception!=0) + if (exception != CBotNoErr) { - pStack->SetError(static_cast(Exception)); + pStack->SetError(static_cast(exception)); } - if ( pResult != pRes ) delete pResult; // different result if made return false; } - if ( pResult != nullptr ) pStack->SetCopyVar( pResult ); - if ( pResult != pRes ) delete pResult; // different result if made + if (result != nullptr) pStack->SetCopyVar(result); return true; } - -#endif diff --git a/src/CBot/CBotCall.h b/src/CBot/CBotCall.h index 26789aae..122a17ed 100644 --- a/src/CBot/CBotCall.h +++ b/src/CBot/CBotCall.h @@ -20,8 +20,12 @@ #pragma once #include "CBot/CBotUtils.h" +#include "CBot/CBotEnums.h" +#include "CBot/CBotDefines.h" #include +#include +#include class CBotStack; class CBotCStack; @@ -29,114 +33,92 @@ class CBotVar; class CBotTypResult; class CBotToken; -#define STACKRUN 1 //! \def return execution directly on a suspended routine - -/*! - * \brief The CBotCall class. Class for routine calls (external). +/** + * \brief Class used for external calls + * + * \see CBotProgram::AddFunction() for information on how to add your functions to this list */ class CBotCall : public CBotLinkedList { public: + typedef bool (*RuntimeFunc)(CBotVar* args, CBotVar* result, int& exception, void* user); + typedef CBotTypResult (*CompileFunc)(CBotVar*& args, void* user); - /*! - * \brief CBotCall - * \param name - * \param rExec - * \param rCompile + /** + * \brief Constructor + * \param name Function name + * \param rExec Runtime function + * \param rCompile Compilation function + * \see CBotProgram::AddFunction() */ - CBotCall(const std::string& name, - bool rExec(CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), - CBotTypResult rCompile(CBotVar*& pVar, void* pUser)); + CBotCall(const std::string& name, RuntimeFunc rExec, CompileFunc rCompile); - /*! - * \brief ~CBotCall + /** + * \brief Destructor */ ~CBotCall(); - /*! - * \brief AddFunction - * \param name - * \param rExec - * \param rCompile - * \return + /** + * \brief Add a new function to the list + * \param name Function name + * \param rExec Runtime function + * \param rCompile Compilation function + * \return true */ - static bool AddFunction(const std::string& name, - bool rExec(CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), - CBotTypResult rCompile(CBotVar*& pVar, void* pUser)); + static bool AddFunction(const std::string& name, RuntimeFunc rExec, CompileFunc rCompile); - /*! - * \brief CompileCall Is acceptable by a call procedure name and given - * parameters. - * \param p - * \param ppVars - * \param pStack - * \param nIdent - * \return + /** + * \brief Find and call compile function + * + * \todo Document */ static CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent); - /*! - * \brief CheckCall - * \param name - * \return + /** + * \brief Check if function with given name has been defined + * \param name Name to check + * \return true if function was defined */ static bool CheckCall(const std::string& name); - /*! - * \brief DoCall - * \param nIdent - * \param token - * \param ppVars - * \param pStack - * \param rettype - * \return + /** + * \brief Find and call runtime function + * + * \todo Document */ static int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype); -#if STACKRUN - - /*! - * \brief Run - * \param pStack - * \return + /** + * \brief Execute the runtime function + * \param pStack Stack to execute the function on + * \return false if function requested interruption, true otherwise */ bool Run(CBotStack* pStack); - /*! - * \brief RestoreCall - * \param nIdent - * \param token - * \param ppVar - * \param pStack - * \return + /** + * \brief Restore execution status after loading saved state + * + * \todo Document */ static bool RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack); -#endif - /*! - * \brief GetName - * \return + /** + * \brief Set user pointer to pass to compile/runtime functions + * \param pUser User pointer */ - std::string GetName(); + static void SetUserPtr(void* pUser); - /*! - * \brief SetPUser - * \param pUser + /** + * \brief Reset the list of registered functions */ - static void SetPUser(void* pUser); - - /*! - * \brief Free - */ - static void Free(); - + static void Clear(); private: - static CBotCall* m_ListCalls; - static void* m_pUser; - long m_nFuncIdent; + static std::map> m_list; + static void* m_user; + long m_ident; std::string m_name; - bool (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser); - CBotTypResult (*m_rComp) (CBotVar* &pVar, void* pUser); + RuntimeFunc m_rExec; + CompileFunc m_rComp; }; diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index 6569a936..e453ee32 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -186,7 +186,7 @@ enum TokenType { * * Also note that these can't overlap with CBotType, see CBotTypResult for explanation */ -enum CBotError +enum CBotError : int { CBotNoErr = 0, diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index a15108d1..8961d9e6 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -77,7 +77,7 @@ bool CBotProgram::Compile(const std::string& program, std::vector& CBotToken* p = tokens.get()->GetNext(); // skips the first token (separator) pStack->SetProgram(this); // defined used routines - CBotCall::SetPUser(pUser); + CBotCall::SetUserPtr(pUser); // Step 2. Find all function and class definitions while ( pStack->IsOk() && p != nullptr && p->GetType() != 0) @@ -209,7 +209,6 @@ bool CBotProgram::Run(void* pUser, int timer) m_pStack->SetBotCall(this); // bases for routines -#if STACKRUN // resumes execution on the top of the stack ok = m_pStack->Execute(); if ( ok ) @@ -217,9 +216,6 @@ bool CBotProgram::Run(void* pUser, int timer) // returns to normal execution ok = m_entryPoint->Execute(nullptr, m_pStack, m_thisVar); } -#else - ok = m_pRun->Execute(nullptr, m_pStack, m_thisVar); -#endif // completed on a mistake? if (!ok && !m_pStack->IsOk()) @@ -440,6 +436,6 @@ void CBotProgram::Init() void CBotProgram::Free() { CBotToken::ClearDefineNum() ; - CBotCall ::Free() ; + CBotCall::Clear() ; CBotClass::Free() ; } \ No newline at end of file