CBotCall refactoring
parent
00221c9a3f
commit
3170395576
|
@ -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<std::string, std::unique_ptr<CBotCall>> CBotCall::m_list = std::map<std::string, std::unique_ptr<CBotCall>>();
|
||||
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<CBotCall>(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<CBotVar> args = std::unique_ptr<CBotVar>(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<CBotError>(ret), p /*pVar2->GetToken()*/ );
|
||||
}
|
||||
delete pVar;
|
||||
nIdent = pt->m_nFuncIdent;
|
||||
return r;
|
||||
}
|
||||
pt = pt->m_next;
|
||||
pStack->SetError(static_cast<CBotError>(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<CBotError>(Exception));
|
||||
pStack->SetError(static_cast<CBotError>(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
|
||||
|
|
|
@ -20,8 +20,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "CBot/CBotUtils.h"
|
||||
#include "CBot/CBotEnums.h"
|
||||
#include "CBot/CBotDefines.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
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<CBotCall>
|
||||
{
|
||||
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<std::string, std::unique_ptr<CBotCall>> 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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
|
|||
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() ;
|
||||
}
|
Loading…
Reference in New Issue