CBotCall refactoring

dev-time-step
krzys-h 2015-12-24 00:41:33 +01:00
parent 00221c9a3f
commit 3170395576
4 changed files with 129 additions and 278 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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,

View File

@ -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() ;
}